Recent

Author Topic: [CLOSED] Get datetime of creation and of modification, for a file, under Linux  (Read 5511 times)

devEric69

  • Hero Member
  • *****
  • Posts: 648
Hello,

I would like to port this feature to Linux (it works on Windows):

Code: Pascal  [Select][+][-]
  1. TenumFileDateProperty = (eCreation, eAccess, eModification);
  2.  
  3. {$If defined (Window)}
  4. uses ...;
  5. {$If defined(UNIX)}
  6. uses BaseUnix;
  7. {$EndIf}
  8.  
  9.  
  10. function TFileUtils.FileGetDatePropertyDateTime(const sPathFile: string; iDateProperty: TenumFileDateProperty): TDateTime;
  11. {^explanation: returns a TDateTime of a property of the file passed as a parameter.
  12. - param. sPathFile: the full path to the file; e.g. /home/.../testFile.txt
  13. - iDateProperty parameter: the type of time-stamped property you want to know about
  14. ^^}
  15. var
  16. {$If defined(Windows)}
  17.   SR: TSearchRec;
  18.   LocalFTime,
  19.   WichProperty: TFileTime;
  20.   STime: TSystemTime;
  21. {$ElseIf defined (UNIX)}
  22.   fAge: Longint;
  23.   aDateTime: TDateTime;
  24.   recInfo: stat;
  25.   hFile: LongInt;
  26.   SR: TSearchRec;
  27. {$EndIf}
  28.  
  29. begin
  30.     case iDateProperty of
  31. {$If defined(Windows)}
  32.         try
  33.                 (*Windows code*)
  34.                 eCreation: WichProperty:= SR.FindData.ftCreationTime;
  35.                 eAccess: WichProperty:= SR.FindData.ftLastAccessTime;
  36.                 eModification: WichProperty:= SR.FindData.ftLastWriteTime;
  37.                 if FindFirst(sPathFile, faAnyFile, SR) = 0 then begin
  38.                         FileTimeToLocalFileTime(WichProperty, LocalFTime);
  39.                         FileTimeToSystemTime(LocalFTime, STime);
  40.                         result:= SystemTimeToDateTime(STime);
  41.                 end
  42.                 result:= -1;
  43.                 Raise EFilesUtils.Create('');
  44.         finally
  45.                 System.SysUtils.FindClose(SR);
  46.         end;
  47. {$ElseIf defined (UNIX)}
  48.                 (*Linux code*)
  49.                 eCreation: begin
  50.                         (* //test 1:
  51.                         if FpStat(sPathFile, recInfo)<>0 then begin
  52.                                 result:= -1;
  53.                                 Raise EFilesUtils.Create('');
  54.                         end
  55.                         else begin
  56.                                 aDateTime:= FileDateToDateTime(recInfo.ctime);
  57.                                 result:= aDateTime;     // last *c*reation time
  58.                         *)
  59.                         (* //test 2:
  60.                         fAge:= FileAge(sPathFile);
  61.                         if (fAge<>-1) then begin
  62.                                 aDateTime:= FileDateToDateTime(fAge);
  63.                         result:= aDateTime;
  64.                         end;
  65.                         *)
  66.                         (* //test 3:
  67.                         hFile:= FileOpen(sPathFile, fmOpenRead);
  68.                         fAge:= FileGetDate(hFile);
  69.                         aDateTime:= FileDateToDateTime(fAge);
  70.                         result:= aDateTime;
  71.                         FileClose(hFile);
  72.                         *)
  73.                         //test 4:
  74.                         if FpStat(sPathFile, recInfo)<>0 then begin
  75.                                 result:= -1;
  76.                                 Raise EFilesUtils.Create('');
  77.                         end
  78.                         else begin
  79.                                 aDateTime:= FileDateToDateTime(recInfo.ctime);
  80.                                 result:= aDateTime;     // last *c*reation time
  81.                         end;
  82.                 end;
  83.  
  84.                 eAccess: begin
  85.                         if FpStat(sPathFile, recInfo)<>0 then begin
  86.                                 result:= -1;
  87.                                 Raise EFilesUtils.Create('');
  88.                         end
  89.                         else begin
  90.                                 aDateTime:= FileDateToDateTime(recInfo.atime);
  91.                                 result:= aDateTime;     // last *a*cces time
  92.                         end;
  93.                 end;
  94. {$EndIf}
  95.     end;
  96. end;
  97.  

I'm testing the function with this call:
Code: Pascal  [Select][+][-]
  1. procedure TfrmMain.Button1Click(Sender: TObject);
  2. begin
  3.   ShowMessage('Creation date: '+DateTimeToStr(
  4.         {TFileUtils.}FileGetCreationDateTime('/home/.../.../fileTested.pas')
  5.               ));
  6. end;


In fact, I only get the true creation date with test 2: "fAge:= FileAge(...". But, as soon as I've modified the file to see if the creation date remained the same, then 'test 2' returned me the modification date. Does anyone know how to retrieve the creation and modification date under Linux?

The "dev"ice partition of my Linux filesystem is formatted in ext4 (command in the terminal: df -Th | grep "^dev").

ps: I use the Cinnamon desktop (in addition to the Nautilus desktop). When I modify a file, the Cinnamon desktop always shows me the same creation date (Cf. image).

Regards.
« Last Edit: January 02, 2020, 10:42:46 am by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #1 on: December 31, 2019, 01:54:46 pm »
You can use fpStat() (in unit BaseUnix). In the resulting record Stat the parts you're looking for are:
  • Last access time: st_atime
  • Last modification time: st_mtime
  • Creation time: st_ctime

ETA: Remember that those are Unix timestamps so you need to use TimeStampToDateTime to convert them. Or, yeah, FileDateToDateTime, as you're doing :-[
« Last Edit: December 31, 2019, 02:13:16 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6686
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #2 on: December 31, 2019, 02:45:50 pm »
Also make sure that the appropriate variants of the  ls  command show you the dates you expect, and be aware of  lsattr  etc. even if not directly relevant.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

devEric69

  • Hero Member
  • *****
  • Posts: 648
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #3 on: December 31, 2019, 02:49:45 pm »
I've tested with this code (using the other variant part of the record; those with st_*), and a new created file (with same modification datetime, too):
Code: Pascal  [Select][+][-]
  1. FpStat(sPathFile, recInfo)<>0 then begin
  2. aDateTime:= FileDateToDateTime(recInfo.st_ctime);
  3. result:= aDateTime;     // last *c*reation time

So, indeed, it works... but only the first time (on my computer, at least): I get the correct creation date. But, if I modify the same file, then this same code gives me the modification date (with st_ctime, st_mtime, or st_atime)??!
Does anyone else observe the same behaviour under *nix?

Quote
Also make sure that the appropriate variants of the  ls  command show you the dates you expect, and be aware of  lsattr  etc. even if not directly relevant.

Okay, I'll check with terminal commands.
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #4 on: December 31, 2019, 03:21:35 pm »
Hi!

You are looking for the wrong result of FpStat.
0 means: everything ok, <> 0 means error.

Runs without a problem:

Code: Pascal  [Select][+][-]
  1. if FpStat('/tmp/st-test.txt', recInfo)=0 then begin
  2.    s := DateTimeToStr(FileDateToDateTime(recInfo.st_ctime)) + LineEnding +
  3.         DateTimeToStr(FileDateToDateTime(recInfo.st_mtime)) +LineEnding+
  4.         DateTimeToStr(FileDateToDateTime(recInfo.st_atime)) ;
  5.    ShowMessage (s);
  6.    end else showMessage ('Nada');      
  7.  

Winni

MarkMLl

  • Hero Member
  • *****
  • Posts: 6686
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #5 on: December 31, 2019, 03:26:18 pm »
Some of the semantics might be filesystem-specific, hence my suggestion that you familiarise yourself with lsattr etc. There's definitely at least one attribute in there that changed how some of the timestamps work, and I think that can also be changed on a per-filesystem basis although the detail escapes me.

My recollection is that the creation time (ctime) is basically the inode creation timestamp, with other timestamps stored (and updated) inside the inode. Check before you trust that statement :-) You might find it worth zeroing recInfo before the FpStat() so that you know that it's being updated.

> You are looking for the wrong result of FpStat.
> 0 means: everything ok, <> 0 means error.

That as well :-)

MarkMLl
« Last Edit: December 31, 2019, 03:27:49 pm by MarkMLl »
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #6 on: December 31, 2019, 03:43:00 pm »
Does anyone else observe the same behaviour under *nix?

No, sorry. This q&d test:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. {$IFNDEF UNIX}{$Error Unix only!!!}{$ENDIF}
  6.  
  7. uses
  8.   SysUtils, BaseUnix;
  9.  
  10. var
  11.   st: Stat;
  12.   err: cint;
  13.  
  14. begin
  15.   if (ParamCount > 0) and FileExists(ParamStr(1)) then begin
  16.     err := FpStat(ParamStr(1), st);
  17.     if err <> 0 then
  18.       WriteLn('Stat error: ', err)
  19.     else begin;
  20.       writeln('Creation    : ', DateTimeToStr(FileDateToDateTime(st.st_ctime)));
  21.       writeln('Modification: ', DateTimeToStr(FileDateToDateTime(st.st_mtime)));
  22.       writeln('Last Access : ', DateTimeToStr(FileDateToDateTime(st.st_atime)));
  23.     end;
  24.   end else
  25.     WriteLn('Need some file to test its dates!');
  26. end.

gives this output with some (arbitrarily selected) file:

Code: [Select]
Creation    : 03-07-2019 00:54:09
Modification: 12-12-2017 13:05:56
Last Access : 05-12-2019 20:57:29

which AFAICT is quite correct: the file is an MP3 I copied over from an older disk in Summer and I played it last early this month.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

devEric69

  • Hero Member
  • *****
  • Posts: 648
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #7 on: December 31, 2019, 05:05:31 pm »
Quote
0 means: everything ok, <> 0 means error.
Sorry about that reverse test :-[ .

Quote
which AFAICT is quite correct: the file is an MP3 I copied over from an older disk in Summer and I played it last early this month.
Good music, then :) . Thanks for the test.

In a paranoid reflex, I copied and pasted *your* code (I just replaced the Writeln with a ShowMessage, and tested it without the error test (assuming it works), and with the error test (paranoid reflex, always):
- I created a new empty file ("$ touch") at 16:10. I ran the code: the creation time is Ok, like the 2 others. They are identical to 1 second accuracy near.
- I've waited 7 minutes, I've added a line "blabla" in this same text file, and I've started the code again: unfortunately for me, the 3 dates are all identical: 16:17 (modification date).

But the Cinnamon desktop - fortunately, it's there - indicates that the file was really created at 16:10, and was then modified at 16:17.

==> I'll install the cross-compiler for Linux 32bits, and re-test on a netbook LUbuntu 32bits (ext4, too).

ps: aftermath of my failed test: I did a search on the internet. Several sites say that the creation date (or birthday date) since ext4 would be stored in a new field named "crtime: Shows file creation time" field (the article: https://www.tecmint.com/debugfs-command-show-file-creation-time-in-linux/ ).

@lucamar: is your test on ext3 or ext4, please (command in the terminal: df -Th)?
« Last Edit: December 31, 2019, 05:08:42 pm by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6686
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #8 on: December 31, 2019, 05:35:42 pm »
Remember I said something about checking using the  ls  command?

These command issued roughly a minute apart:

Code: [Select]
$ date && touch veeblefetzer
Tue 31 Dec 16:30:03 GMT 2019
$ ls -l ve* && ls -l --time=ctime ve* && ls -l --time=atime ve*
-rw-r--r-- 1 markMLl markMLl 0 Dec 31 16:30 veeblefetzer
-rw-r--r-- 1 markMLl markMLl 0 Dec 31 16:30 veeblefetzer
-rw-r--r-- 1 markMLl markMLl 0 Dec 31 16:30 veeblefetzer
$ cat ve*
$ ls -l ve* && ls -l --time=ctime ve* && ls -l --time=atime ve*
-rw-r--r-- 1 markMLl markMLl 0 Dec 31 16:30 veeblefetzer
-rw-r--r-- 1 markMLl markMLl 0 Dec 31 16:30 veeblefetzer
-rw-r--r-- 1 markMLl markMLl 0 Dec 31 16:31 veeblefetzer
$ echo x >> ve*
0 1>markMLl@desktop:~$ ls -l ve* && ls -l --time=ctime ve* && ls -l --time=atime ve*
-rw-r--r-- 1 markMLl markMLl 2 Dec 31 16:32 veeblefetzer
-rw-r--r-- 1 markMLl markMLl 2 Dec 31 16:32 veeblefetzer
-rw-r--r-- 1 markMLl markMLl 2 Dec 31 16:31 veeblefetzer

So mtime and ctime on ext4 seem to track each other, but atime can be modified (in the inode) without anything else changing.

Oy vey"! This is hardly the first time I've done tech support on New Year's Eve :-)

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #9 on: December 31, 2019, 05:56:39 pm »
- I've waited 7 minutes, I've added a line "blabla" in this same text file, and I've started the code again: unfortunately for me, the 3 dates are all identical: 16:17 (modification date).

That quite depends on how you edit the file. If the program renames the old file, creates a new one and saves the old/new data to it then all three dates are (quite logically) the same.

Quote
But the Cinnamon desktop - fortunately, it's there - indicates that the file was really created at 16:10, and was then modified at 16:17.

Then something is wrong with fpstat, though I can't see what: it just calls the system's stat, IIRC

Quote
is your test on ext3 or ext4, please

Ext3; I never use ext4 on (semi-)critical boxes. Now that I think about it, I never use it if I can avoid it: too easy to break.

I see your point, though: you were talking about ext4 partitions and my tests were in ext3 (and 32 bits, moreover) Sorry about that  :-[
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #10 on: December 31, 2019, 06:10:46 pm »
Hi!

Before any checking of file dates you have to do a

Code: Bash  [Select][+][-]
  1. sync

to force the buffers to be written onto disk.
after that you can check the dates!

Winni

MarkMLl

  • Hero Member
  • *****
  • Posts: 6686
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #11 on: December 31, 2019, 06:21:00 pm »
Hi!

Before any checking of file dates you have to do a

Code: Bash  [Select][+][-]
  1. sync

to force the buffers to be written onto disk.
after that you can check the dates!

Winni

Well I certainly didn't. The buffered directory entries etc. in memory should be checked before disc, that's what "primary storage" is for.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

devEric69

  • Hero Member
  • *****
  • Posts: 648
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #12 on: December 31, 2019, 06:42:38 pm »
Quote
So mtime and ctime on ext4 seem to track each other, but atime can be modified (in the inode) without anything else changing.

==> Bingo????!
I'll only going to test - tomorrow - on another Ubuntu (same version 18.04 LTS, ext4, 64bits) and a 32bits Linux, but ext4 too. Amho, if someone would have a virtual box  with several different *nix, it would be interesting, to corroborate, or to invalidate, the ext4 versus ext3 hypothesis ("mtime and ctime on ext4 seem to track each other")...

Quote
I see your point, though: you were talking about ext4 partitions and my tests were in ext3 (and 32 bits, moreover) Sorry about that.

It's no problem: it was impossible to know, from where it came; on the contrary, your test on ext3 increases the probability of the hypothesis, that ext4 manages the creation date differently from ext3 (MarkMLl also observes it under ext4).
I prefer to end the year with an "almost" certitude :) .

Quote
Before any checking of file dates you have to do a sync
@winni: I'm sorry. But this idea doesn't seem to be working:
- I've created an empty file at 18:16.
- I've waited, and modified it at 18:32.
- I've ran the cmd "sync", as user and as admin "sudo -i" (ie root)
- I've asked for the dates: the 3 indicate 18:32 (the Cinnamon office, refreshed, continues to distinguish the creation at 18:16 and the modification at 18:32.

I must quit this discussion's thread for today.
Happy New Year to you, to the other administrators, and to the Lazarus support people  :D  ;) !!!
==> I'm ending this discussion for today.
« Last Edit: December 31, 2019, 06:45:35 pm by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6686
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #13 on: December 31, 2019, 06:55:25 pm »
> - I've waited, and modified it at 18:32.

How, /exactly/ did you modify it? if you used any sort of text editor then you might actually be looking at a new file, check that the inode is the same (I think ls has an option for this- possibly -i).

Oh, and what makes you think that Crinoline Office is giving you the right result? There could be more bugs in that that in your code that you're trying to debug... there really are very good reasons that my example used the  ls  and  echo  commands.

I think I might have an ext3 system on Qemu, I'll try to take a look but it won't be immediate.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

MarkMLl

  • Hero Member
  • *****
  • Posts: 6686
Re: Get datetime of creation and of modification, for a file, under Linux
« Reply #14 on: December 31, 2019, 07:55:19 pm »
Here's a test script:

Code: [Select]
#!/bin/bash

V=veeblefetzer

rm $V
date && touch $V
ls -il $V
ls -il --time=ctime $V
ls -il --time=atime $V

sleep 90
date && cat $V
ls -il $V
ls -il --time=ctime $V
ls -il --time=atime $V

sleep 90
date && echo x >> $V
ls -il $V
ls -il --time=ctime $V
ls -il --time=atime $V

rm $V

Here's the result on ext4:

Code: [Select]
Tue 31 Dec 18:44:55 GMT 2019
3017024 -rw-r--r-- 1 markMLl markMLl 0 Dec 31 18:44 veeblefetzer
3017024 -rw-r--r-- 1 markMLl markMLl 0 Dec 31 18:44 veeblefetzer
3017024 -rw-r--r-- 1 markMLl markMLl 0 Dec 31 18:44 veeblefetzer
Tue 31 Dec 18:46:25 GMT 2019
3017024 -rw-r--r-- 1 markMLl markMLl 0 Dec 31 18:44 veeblefetzer
3017024 -rw-r--r-- 1 markMLl markMLl 0 Dec 31 18:44 veeblefetzer
3017024 -rw-r--r-- 1 markMLl markMLl 0 Dec 31 18:46 veeblefetzer
Tue 31 Dec 18:47:55 GMT 2019
3017024 -rw-r--r-- 1 markMLl markMLl 2 Dec 31 18:47 veeblefetzer
3017024 -rw-r--r-- 1 markMLl markMLl 2 Dec 31 18:47 veeblefetzer
3017024 -rw-r--r-- 1 markMLl markMLl 2 Dec 31 18:46 veeblefetzer

Here's the result on ext3:

Code: [Select]
Tue Dec 31 18:45:02 GMT 2019
3797947 -rw-r--r--    1 markMLl  users           0 Dec 31 18:45 veeblefetzer
3797947 -rw-r--r--    1 markMLl  users           0 Dec 31 18:45 veeblefetzer
3797947 -rw-r--r--    1 markMLl  users           0 Dec 31 18:45 veeblefetzer
Tue Dec 31 18:46:32 GMT 2019
3797947 -rw-r--r--    1 markMLl  users           0 Dec 31 18:45 veeblefetzer
3797947 -rw-r--r--    1 markMLl  users           0 Dec 31 18:45 veeblefetzer
3797947 -rw-r--r--    1 markMLl  users           0 Dec 31 18:46 veeblefetzer
Tue Dec 31 18:48:02 GMT 2019
3797947 -rw-r--r--    1 markMLl  users           2 Dec 31 18:48 veeblefetzer
3797947 -rw-r--r--    1 markMLl  users           2 Dec 31 18:48 veeblefetzer
3797947 -rw-r--r--    1 markMLl  users           2 Dec 31 18:46 veeblefetzer

Note how I'm writing to the file, and note that the inode number remains consistent.

The bottom line appears to be that with those commands mtime == ctime. I suggest that it might be worth researching the output from the  stat  command.

MarkMLl





« Last Edit: January 01, 2020, 03:22:50 pm by MarkMLl »
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018