diff options
author | Nick Clifton <nickc@redhat.com> | 2023-09-26 14:07:23 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2023-09-26 14:07:23 +0100 |
commit | 6f56739807051e82a6327ff184b01be67be37670 (patch) | |
tree | de68ace335c036865cc3dda48f599baf25cc9383 /binutils | |
parent | 0128542673364609a0b2e1d8a3f1896fc89584d2 (diff) | |
download | gdb-6f56739807051e82a6327ff184b01be67be37670.zip gdb-6f56739807051e82a6327ff184b01be67be37670.tar.gz gdb-6f56739807051e82a6327ff184b01be67be37670.tar.bz2 |
Allow the use of SOURCE_DATE_EPOCH in the timestamps for members of static archives.
(For some reason this commit was not applied at the time that the patch was approved).
Diffstat (limited to 'binutils')
-rw-r--r-- | binutils/ar.c | 24 | ||||
-rw-r--r-- | binutils/doc/binutils.texi | 4 | ||||
-rw-r--r-- | binutils/testsuite/binutils-all/ar.exp | 222 |
3 files changed, 249 insertions, 1 deletions
diff --git a/binutils/ar.c b/binutils/ar.c index fe2d971..b09a3e0 100644 --- a/binutils/ar.c +++ b/binutils/ar.c @@ -807,7 +807,7 @@ main (int argc, char **argv) fatal (_("`u' is only meaningful with the `r' option.")); if (newer_only && deterministic > 0) - fatal (_("`u' is not meaningful with the `D' option.")); + non_fatal (_("`u' is not meaningful with the `D' option - replacement will always happen.")); if (newer_only && deterministic < 0 && DEFAULT_AR_DETERMINISTIC) non_fatal (_("\ @@ -1482,6 +1482,7 @@ replace_members (bfd *arch, char **files_to_move, bool quick) && current->arelt_data != NULL) { bool replaced; + if (newer_only) { struct stat fsbuf, asbuf; @@ -1492,12 +1493,33 @@ replace_members (bfd *arch, char **files_to_move, bool quick) bfd_fatal (*files_to_move); goto next_file; } + if (bfd_stat_arch_elt (current, &asbuf) != 0) /* xgettext:c-format */ fatal (_("internal stat error on %s"), bfd_get_filename (current)); if (fsbuf.st_mtime <= asbuf.st_mtime) + /* A note about deterministic timestamps: In an + archive created in a determistic manner the + individual elements will either have a timestamp + of 0 or SOURCE_DATE_EPOCH, depending upon the + method used. This will be the value retrieved + by bfd_stat_arch_elt(). + + The timestamp in fsbuf.st_mtime however will + definitely be greater than 0, and it is unlikely + to be less than SOURCE_DATE_EPOCH. (FIXME: + should we test for this case case and issue an + error message ?) + + So in either case fsbuf.st_mtime > asbuf.st_time + and hence the incoming file will replace the + current file. Which is what should be expected to + happen. Deterministic archives have no real sense + of the time/date when their elements were created, + and so any updates to the archive should always + result in replaced files. */ goto next_file; } diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 56394b2..0d46119 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -521,6 +521,10 @@ operation @samp{r} (replace). In particular, the combination @samp{qu} is not allowed, since checking the timestamps would lose any speed advantage from the operation @samp{q}. +Note - if an archive has been created in a deterministic manner, eg +via the use of the @option{D} modifier, then replacement will always +happen and the @option{u} modifier will be ineffective. + @item U @cindex deterministic archives @kindex --enable-deterministic-archives diff --git a/binutils/testsuite/binutils-all/ar.exp b/binutils/testsuite/binutils-all/ar.exp index b9a325c..a0fa54d 100644 --- a/binutils/testsuite/binutils-all/ar.exp +++ b/binutils/testsuite/binutils-all/ar.exp @@ -467,6 +467,225 @@ proc deterministic_archive { } { pass $testname } +# Test replacing a member of a deterministic archive. + +proc replacing_deterministic_member { } { + global AR + global AS + global NM + global srcdir + global subdir + global obj + + set testname "replacing deterministic member" + + if [is_remote host] { + # The kind of filename trickery that we are about to + # play is hard to do if we have to operate remotely. + unsupported $testname + return + } + + file mkdir tmpdir/ar + + if ![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.${obj}] { + unsupported $testname + return + } + + # Wait a second and then build a second object file - with the same name + # as the first, but in a different directory. + sleep 1 + if ![binutils_assemble $srcdir/$subdir/copytest.s tmpdir/ar/bintest.${obj}] { + unsupported $testname + return + } + + set archive tmpdir/artest.a + set older_objfile tmpdir/bintest.${obj} + set newer_objfile tmpdir/ar/bintest.${obj} + set older_length [file size $older_objfile] + # set newer_length [file size $newer_objfile] + + remote_file build delete tmpdir/artest.a + + # Build the archive with the *newer* object file. + + set got [binutils_run $AR "rcD $archive ${newer_objfile}"] + if ![string match "" $got] { + fail "$testname: (could not build archive)" + return + } + + # Now replace the newer file with the older one. On a normal + # archive this will not work, but one created to be deterministic + # should always replace its members. + + set got [binutils_run $AR "ruD $archive $older_objfile"] + # The archiver will warn that 'u' and 'D' do not work together + if ![string match "*not meaningful*" $got] { + fail "$testname: (failed to replace file)" + return + } + + set got [binutils_run $AR "tvO $archive"] + if ![string match "rw-r--r-- 0/0 *${older_length} *bintest.${obj} 0x*" $got] { + fail "$testname (wrong size, expected: $older_length)" + return + } + + pass $testname +} + +# Test replacing a member of a non-deterministic archive. + +proc replacing_non_deterministic_member { } { + global AR + global AS + global NM + global srcdir + global subdir + global obj + + set testname "replacing non-deterministic member" + + if [is_remote host] { + # The kind of filename trickery that we are about to + # play is hard to do if we have to operate remotely. + unsupported $testname + return + } + + file mkdir tmpdir/ar + + if ![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.${obj}] { + unsupported $testname + return + } + + # Wait a second and then build a second object file - with the same name + # as the first, but in a different directory. + sleep 1 + if ![binutils_assemble $srcdir/$subdir/copytest.s tmpdir/ar/bintest.${obj}] { + unsupported $testname + return + } + + set archive tmpdir/artest.a + set older_objfile tmpdir/bintest.${obj} + set newer_objfile tmpdir/ar/bintest.${obj} + # set older_length [file size $older_objfile] + set newer_length [file size $newer_objfile] + + remote_file build delete tmpdir/artest.a + + # Build the archive with the *newer* object file. + + set got [binutils_run $AR "rc $archive ${newer_objfile}"] + if ![string match "" $got] { + fail "$testname: (could not build archive)" + return + } + + # Now try to replace the newer file with the older one. This should not work. + + set got [binutils_run $AR "ru $archive $older_objfile"] + if ![string match "" $got] { + fail "$testname: (failed to replace file)" + return + } + + # Since this archive is non-deterministic, we do not know what the + # user or group ids will be, so we have to use */* to match them. + set got [binutils_run $AR "tvO $archive"] + if ![string match "rw-r--r-- */* *${newer_length} *bintest.${obj} 0x*" $got] { + fail "$testname (wrong size, expected: $newer_length)" + return + } + + pass $testname +} + +# Test replacing a member of deterministic archive created by using SOURCE_DATE_EPOCH. + +proc replacing_sde_deterministic_member { } { + global AR + global AS + global NM + global srcdir + global subdir + global obj + + set testname "replacing SOURCE_DATE_EPOCH deterministic member" + + if [is_remote host] { + # The kind of filename trickery that we are about to + # play is hard to do if we have to operate remotely. + unsupported $testname + return + } + + file mkdir tmpdir/ar + + if ![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.${obj}] { + unsupported $testname + return + } + + # Wait a second and then build a second object file - with the same name + # as the first, but in a different directory. + sleep 1 + if ![binutils_assemble $srcdir/$subdir/copytest.s tmpdir/ar/bintest.${obj}] { + unsupported $testname + return + } + + set archive tmpdir/artest.a + set older_objfile tmpdir/bintest.${obj} + set newer_objfile tmpdir/ar/bintest.${obj} + set older_length [file size $older_objfile] + # set newer_length [file size $newer_objfile] + + remote_file build delete tmpdir/artest.a + + # Build the archive with the *newer* object file. + setenv SOURCE_DATE_EPOCH "1000" + + set got [binutils_run $AR "rc $archive ${newer_objfile}"] + if ![string match "" $got] { + fail "$testname: (could not build archive)" + unsetenv SOURCE_DATE_EPOCH + return + } + + # Now replace the newer file with the older one. On a normal + # archive this will not work, but one created to be deterministic + # should always replace its members. + + set got [binutils_run $AR "ru $archive $older_objfile"] + if ![string match "" $got] { + fail "$testname: (failed to replace file)" + unsetenv SOURCE_DATE_EPOCH + return + } + + # Since this archive has fixed source dates, but non-deterministic + # uid and gid values we have to use */* to match them. + set got [binutils_run $AR "tvO $archive"] + if ![string match "rw-r--r-- */* *${older_length} *bintest.${obj} 0x*" $got] { + fail "$testname (wrong size, expected: $older_length)" + unsetenv SOURCE_DATE_EPOCH + return + } + + # FIXME - it would be nice if we could check to see that the time & date + # in the archive listing matches SOURCE_DATE_EPOCH. + + unsetenv SOURCE_DATE_EPOCH + pass $testname +} + + proc unique_symbol { } { global AR global AS @@ -797,6 +1016,9 @@ if { [file exists $base_dir/bfdtest1] && [file exists $base_dir/bfdtest2] } { symbol_table argument_parsing deterministic_archive +replacing_deterministic_member +replacing_non_deterministic_member +replacing_sde_deterministic_member delete_an_element move_an_element empty_archive |