Product:binutils
Tool:ar
Version:2.37
Here is a simple example on a openEuler-22.03-LTS machine running binutils/2.37:
-------
[root@19fe3bb99663 ~]# rpm -qa | grep binutils
binutils-2.37-6.oe2203.x86_64
[root@19fe3bb99663 ~]# touch 1.txt
[root@19fe3bb99663 ~]# ar -rvU 1.a 1.txt
ar: creating 1.a
a - 1.txt
[root@19fe3bb99663 ~]# rm -f 1.txt
[root@19fe3bb99663 ~]# ar -xo 1.a
ar: 1.txt: cannot set time: Invalid argument
----
gdb message:
Breakpoint 2, set_times (destination=0x555555573680 "1.txt", statbuf=0x7fffffffe900) at rename.c:168
168 {
(gdb)
Continuing.
Breakpoint 3, 0x00007ffff7d76940 in utimensat () from /usr/lib64/libc.so.6
(gdb) l
163 /* Set the times of the file DESTINATION to be the same as those in
164 STATBUF. */
165
166 void
167 set_times (const char *destination, const struct stat *statbuf)
168 {
169 int result
170 #if defined HAVE_UTIMENSAT
171 struct timespec times[2]
172 times[0] = get_stat_atime (statbuf)
(gdb)
173 times[1] = get_stat_mtime (statbuf)
174 result = utimensat (AT_FDCWD, destination, times, 0)
175 #elif defined HAVE_UTIMES
176 struct timeval tv[2]
177
178 tv[0].tv_sec = statbuf->st_atime
179 tv[0].tv_usec = get_stat_atime_ns (statbuf) / 1000
180 tv[1].tv_sec = statbuf->st_mtime
181 tv[1].tv_usec = get_stat_mtime_ns (statbuf) / 1000
182 result = utimes (destination, tv)
(gdb) disassemble
Dump of assembler code for function utimensat:
=> 0x00007ffff7d76940 <+0>: endbr64
0x00007ffff7d76944 <+4>: mov %ecx,%r10d
0x00007ffff7d76947 <+7>: test %rsi,%rsi
0x00007ffff7d7694a <+10>: je 0x7ffff7d76972 <utimensat+50>
0x00007ffff7d7694c <+12>: mov $0x118,%eax
0x00007ffff7d76951 <+17>: syscall
0x00007ffff7d76953 <+19>: cmp $0xfffffffffffff000,%rax
0x00007ffff7d76959 <+25>: ja 0x7ffff7d76960 <utimensat+32>
0x00007ffff7d7695b <+27>: ret
0x00007ffff7d7695c <+28>: nopl 0x0(%rax)
0x00007ffff7d76960 <+32>: mov 0xeb491(%rip),%rdx # 0x7ffff7e61df8
0x00007ffff7d76967 <+39>: neg %eax
0x00007ffff7d76969 <+41>: mov %eax,%fs:(%rdx)
0x00007ffff7d7696c <+44>: mov $0xffffffff,%eax
0x00007ffff7d76971 <+49>: ret
0x00007ffff7d76972 <+50>: mov 0xeb47f(%rip),%rax # 0x7ffff7e61df8
0x00007ffff7d76979 <+57>: movl $0x16,%fs:(%rax)
0x00007ffff7d76980 <+64>: mov $0xffffffff,%eax
0x00007ffff7d76985 <+69>: ret
End of assembler dump.
(gdb) n
Single stepping until exit from function utimensat,
which has no line number information.
set_times (destination=0x555555573680 "1.txt", statbuf=<optimized out>) at rename.c:197
197 if (result != 0)
(gdb) p result
$1 = -1
(gdb) p *(int *)__errno_location()
$2 = 22
The tv_nsec outside range 0 to 999,999,999:
EINVAL Invalid value in one of the tv_nsec fields (value outside
range 0 to 999,999,999, and not UTIME_NOW or UTIME_OMIT);
or an invalid value in one of the tv_sec fields.
Breakpoint 2, set_times (destination=0x555555573680 "1.txt", statbuf=0x7fffffffe900) at rename.c:168
168 {
(gdb) n
172 times[0] = get_stat_atime (statbuf);
(gdb)
173 times[1] = get_stat_mtime (statbuf);
(gdb)
174 result = utimensat (AT_FDCWD, destination, times, 0);
(gdb) p times
$3 = {{tv_sec = 1659577707, tv_nsec = 93824992314928}, {tv_sec = 1659577707, tv_nsec = 93824992314592}}
(gdb)
In glibc 2.34, utimes and utimensat call the same interface __utimensat64_helper, so both interfaces are bound by tv_nsec:
void
set_times (const char *destination, const struct stat *statbuf)
{
int result;
#if defined HAVE_UTIMENSAT
struct timespec times[2];
times[0] = get_stat_atime (statbuf);
times[1] = get_stat_mtime (statbuf);
result = utimensat (AT_FDCWD, destination, times, 0);
#elif defined HAVE_UTIMES
struct timeval tv[2];
tv[0].tv_sec = statbuf->st_atime;
tv[0].tv_usec = get_stat_atime_ns (statbuf) / 1000;
tv[1].tv_sec = statbuf->st_mtime;
tv[1].tv_usec = get_stat_mtime_ns (statbuf) / 1000;
result = utimes (destination, tv);
#elif defined HAVE_GOOD_UTIME_H
struct utimbuf tb;
tb.actime = statbuf->st_atime;
tb.modtime = statbuf->st_mtime;
result = utime (destination, &tb);
#else
long tb[2];
tb[0] = statbuf->st_atime;
tb[1] = statbuf->st_mtime;
result = utime (destination, tb);
#endif
if (result != 0)
non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
}
I provide a patch bound tv_nsec:
diff --git a/binutils/rename.c b/binutils/rename.c
index 8826917c..248952cf 100644
--- a/binutils/rename.c
+++ b/binutils/rename.c
@@ -160,6 +160,24 @@ get_stat_mtime (struct stat const *st)
}
+
+static void
+nsec_bound(long *nsec)
+{
+ long ns = *nsec;
+ if (ns == UTIME_OMIT || ns == UTIME_NOW)
+ return;
+
+ if (ns < 0)
+ {
+ *nsec = 0;
+ }
+ else if (ns > 999999999)
+ {
+ *nsec = 999999999;
+ }
+}
+
@@ -170,7 +188,9 @@ set_times (const char *destination, const struct stat *statbuf)
#if defined HAVE_UTIMENSAT
struct timespec times[2];
times[0] = get_stat_atime (statbuf);
+ nsec_bound(×[0].tv_nsec);
times[1] = get_stat_mtime (statbuf);
+ nsec_bound(×[1].tv_nsec);
result = utimensat (AT_FDCWD, destination, times, 0);
#elif defined HAVE_UTIMES
struct timeval tv[2];
Tested:(tv_nsec was reset to 999999999
[root@19fe3bb99663 ~]# touch 1.txt
[root@19fe3bb99663 ~]# stat 1.txt
File: 1.txt
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 0,41 Inode: 1703945 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-08-04 20:00:48.658963408 +0800
Modify: 2022-08-04 20:00:48.658963408 +0800
Change: 2022-08-04 20:00:48.658963408 +0800
Birth: 2022-08-04 20:00:48.658963408 +0800
[root@19fe3bb99663 ~]# ar -rvU 1.a 1.txt
r - 1.txt
[root@19fe3bb99663 ~]# rm -f 1.txt
[root@19fe3bb99663 ~]# ar -xo 1.a
[root@19fe3bb99663 ~]# stat 1.txt
File: 1.txt
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 0,41 Inode: 1703945 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-08-04 20:00:48.999999999 +0800
Modify: 2022-08-04 20:00:48.999999999 +0800
Change: 2022-08-04 20:01:13.541931099 +0800
Birth: 2022-08-04 20:01:13.541931099 +0800
[root@19fe3bb99663 ~]# rpm -qa | grep binutils
binutils-2.37-8.oe2203.x86_64
[root@19fe3bb99663 ~]#
|
canpool
|
canpool@163.com
|
签名由
网易邮箱大师
定制