Browse Source

+ futimens syscall
* make use of futimens syscall in sysutils unit
+ tests

git-svn-id: trunk@48472 -

florian 4 years ago
parent
commit
b8ab06aae7

+ 1 - 0
.gitattributes

@@ -16110,6 +16110,7 @@ tests/test/units/fpwidestring/twide6fpwidestring.pp svneol=native#text/pascal
 tests/test/units/fpwidestring/twide7fpwidestring.pp svneol=native#text/pascal
 tests/test/units/lineinfo/tlininfo.pp svneol=native#text/plain
 tests/test/units/linux/tepoll1.pp svneol=native#text/pascal
+tests/test/units/linux/tfutimesen.pp svneol=native#text/pascal
 tests/test/units/linux/tstatx.pp svneol=native#text/pascal
 tests/test/units/linux/tutimensat.pp svneol=native#text/pascal
 tests/test/units/math/tcmpnan.pp svneol=native#text/plain

+ 23 - 1
rtl/linux/linux.pp

@@ -555,7 +555,8 @@ Type
 
    tkernel_timespecs = array[0..1] of kernel_timespec;
 
-  Function fputimensat(dfd: cint; path:pchar;const times:tkernel_timespecs;flags:cint):cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'statx'; {$ENDIF}
+Function fputimensat(dfd: cint; path:pchar;const times:tkernel_timespecs;flags:cint):cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'statx'; {$ENDIF}
+Function fpfutimens(fd: cint; const times:tkernel_timespecs):cint; {$ifdef FPC_USE_LIBC} cdecl; external name 'futimens'; {$ENDIF}
 
 implementation
 
@@ -893,4 +894,25 @@ begin
 {$endif sizeof(clong)<=4}
 end;
 
+
+Function fpfutimens(fd: cint; const times:tkernel_timespecs):cint;
+var
+  tsa: Array[0..1] of timespec;
+begin
+{$if sizeof(clong)<=4}
+  fpfutimens:=do_syscall(syscall_nr_utimensat_time64,fd,TSysParam(nil),TSysParam(@times),0);
+  if (fpfutimens>=0) or (fpgeterrno<>ESysENOSYS) then
+    exit;
+  { try 32 bit fall back }
+  tsa[0].tv_sec := times[0].tv_sec;
+  tsa[0].tv_nsec := times[0].tv_nsec;
+  tsa[1].tv_sec := times[1].tv_sec;
+  tsa[1].tv_nsec := times[1].tv_nsec;
+  fpfutimens:=do_syscall(syscall_nr_utimensat,fd,TSysParam(nil),TSysParam(@tsa),0);
+{$else sizeof(clong)<=4}
+  fpfutimens:=do_syscall(syscall_nr_utimensat,fd,TSysParam(nil),TSysParam(@times),0);
+{$endif sizeof(clong)<=4}
+end;
+
 end.
+

+ 15 - 2
rtl/unix/sysutils.pp

@@ -58,6 +58,7 @@ uses
 {$if defined(LINUX)}
 {$DEFINE USE_STATX}
 {$DEFINE USE_UTIMENSAT}
+{$DEFINE USE_FUTIMES}
 {$endif}
 
 { Include platform independent interface part }
@@ -1027,10 +1028,22 @@ end;
 
 
 Function FileSetDate (Handle : Longint;Age : Int64) : Longint;
-
+{$ifdef USE_UTIMENSAT}
+var
+  times : tkernel_timespecs;
+{$endif USE_UTIMENSAT}
 begin
-  // Impossible under Linux from FileHandle !!
+  Result:=0;
+{$ifdef USE_FUTIMES}
+  times[0].tv_sec:=Age;
+  times[0].tv_nsec:=0;
+  times[1].tv_sec:=Age;
+  times[1].tv_nsec:=0;
+  if fpfutimens(Handle,times) = -1 then
+    Result:=fpgeterrno;
+{$else USE_FUTIMES}
   FileSetDate:=-1;
+{$endif USE_FUTIMES}
 end;
 
 

+ 84 - 0
tests/test/units/linux/tfutimesen.pp

@@ -0,0 +1,84 @@
+{ %target=linux }
+uses
+  ctypes,baseunix,linux;
+
+var
+  un : utsname;
+  res : cint;
+  f1,f2 : text;
+  err : word;
+  mystatx1,mystatx2 : statx;
+  times : tkernel_timespecs;
+  st,major,minor : string;
+  i,p,e : longint;
+  major_release, minor_release : longint;
+begin
+  fpuname(un);
+  st:=un.release;
+  for i:=1 to UTSNAME_LENGTH do
+    if st[i]='.' then
+      begin
+        p:=i;
+        major:=system.copy(st,1,p-1);
+        system.val(major,major_release,err);
+        if err<>0 then
+          begin
+            writeln('Unable to parse first part of linux version ',st,'(',major,') correctly');
+            halt(2);
+          end;
+        break;
+      end;
+
+  for i:=p+1 to UTSNAME_LENGTH do
+    if st[i]='.' then
+      begin
+        e:=i;
+        minor:=system.copy(st,p+1,e-p-1);
+        system.val(minor,minor_release,err);
+        if err<>0 then
+          begin
+            writeln('Unable to second part of parse linux version ',st,'i(',minor,') correctly');
+            halt(2);
+          end;
+        break;
+      end;
+  if (major_release<4) or ((major_release=4) and (minor_release<11)) then
+    begin
+      writeln('This version of Linux: ',st,' does not have fstatx syscall');
+      halt(0);
+    end
+  else
+    writeln('This linux version ',st,' should support statx syscall');
+
+  assign(f1,'tutimensat1.txt');
+  rewrite(f1);
+  write(f1,'ccccc');
+  assign(f2,'tutimensat2.txt');
+  rewrite(f2);
+  write(f2,'ccccc');
+
+  res:=fpstatx(AT_FDCWD,'tutimensat1.txt',AT_SYMLINK_NOFOLLOW,STATX_ALL,mystatx1);
+  if res<>0 then
+    halt(1);
+  times[0].tv_sec:=mystatx1.stx_atime.tv_sec;
+  times[0].tv_nsec:=mystatx1.stx_atime.tv_nsec;
+  times[1].tv_sec:=mystatx1.stx_mtime.tv_sec;
+  times[1].tv_nsec:=mystatx1.stx_mtime.tv_nsec;
+  res:=fpfutimens(textrec(f2).handle,times);
+  if res<>0 then
+    halt(1);
+  res:=fpstatx(AT_FDCWD,'tutimensat2.txt',AT_SYMLINK_NOFOLLOW,STATX_ALL,mystatx2);
+  if res<>0 then
+    halt(1);
+
+  close(f1);
+  close(f2);
+
+  erase(f1);
+  erase(f2);
+
+  if (mystatx1.stx_atime.tv_sec<>mystatx2.stx_atime.tv_sec) or (mystatx1.stx_atime.tv_nsec<>mystatx2.stx_atime.tv_nsec) or
+    (mystatx1.stx_mtime.tv_sec<>mystatx2.stx_mtime.tv_sec) or (mystatx1.stx_mtime.tv_nsec<>mystatx2.stx_mtime.tv_nsec) then
+    halt(1);
+  writeln('ok');
+end.

+ 7 - 0
tests/test/units/sysutils/tfile1.pp

@@ -32,6 +32,13 @@ BEGIN
   if FileSetDate('datetest.dat', DateTimeToFileDate(dateTime))<>0 then
     do_error(1002);
 
+  dateTime := IncMonth(Now, -1);
+  Assign(f,'datetest.dat');
+  Rewrite(f);
+  if FileSetDate(filerec(f).handle, DateTimeToFileDate(dateTime))<>0 then
+    do_error(1003);
+  Close(f);
+
   if FileExists('datetest.dat') then
     begin
       Assign(f,'datetest.dat');