aboutsummaryrefslogtreecommitdiff
path: root/binutils
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2023-09-26 14:07:23 +0100
committerNick Clifton <nickc@redhat.com>2023-09-26 14:07:23 +0100
commit6f56739807051e82a6327ff184b01be67be37670 (patch)
treede68ace335c036865cc3dda48f599baf25cc9383 /binutils
parent0128542673364609a0b2e1d8a3f1896fc89584d2 (diff)
downloadgdb-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.c24
-rw-r--r--binutils/doc/binutils.texi4
-rw-r--r--binutils/testsuite/binutils-all/ar.exp222
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