3

I was copying Asterisk call recordings from our main server to a samba share and the creation date and times were changed to the current date and time.

The file format is: in-xxxxxxxxxx-xxxxxxxxxx-20211020-162749-1634761669.7921917.wav

The bold part is in EPOCH time. I have hundreds of these files and I need to change the creation date of the file based on that EPOCH time stamp in the file's name. Can anyone help me?

3
  • 2
    By creation date, do you mean the last modification time of the file (the one reported by ls -l)? Jan 20 at 17:05
  • yes, thanks for the reply Jan 20 at 17:56
  • I suspect that timestamp in the asterisk file name corresponds to the start of the recording. If that's the case, it may make more sense to have the birth time correspond to the start of the call and the last modification time to the end of the call. Jan 20 at 18:39

1 Answer 1

6

With GNU touch, you can use touch -d @1634761669.7921917 file to set the last modification time of a file to the specified epoch time (even with subsecond precision as here).

So you could do in zsh:

#! /bin/zsh -
ret=0
for file in *-<->.<->.wav; do
  t=${file:r} t=${t##*-}
  touch -d @$t -- $file || ret=$?
done
exit $ret

If it's really the creation time, often called birth time, as reported by ls -l --time=birth with recent versions of GNU ls for instance that you want to change, AFAIK that is not possible on Linux other than changing the clock back to that time and create the file again.

If on Linux (a recent version¹), you could however only change the clock in a new time namespace so as not to affect the system's clock globally.

For instance, with:

sudo unshare --time sh -c 'date -s @1634761669.7921917 && exec cp -a file file.new'

You would create a file.new copy of file with a birth time close to @1634761669.7921917

$ sudo unshare --time sh -c 'date -s @1634761669.7921917 && exec cp -a file file.new'
$ ls -l --time=birth --time-style=+%s.%N file file.new
-rw-r--r-- 1 stephane stephane 0 1642699170.474916807 file
-rw-r--r-- 1 stephane stephane 0 1634761669.792191700 file.new

The zsh script above could then be written:

#! /bin/zsh -
ret=0
for file in *-<->.<->.wav; do
  t=${file:r} t=${t##*-}
  
  unshare --time sh -c '
    date -s "@$1" && exec cp -aTn -- "$2" "$2.new"' sh "$t" "$file" &&
    mv -f -- "$file.new" "$file" || ret=$?
done
exit $ret

(and would need to be run as root).

Some second thought while revising this:

I just realised that causes a potential problem: that unshare --time hack allows the birth time to be set to some arbitrary time in the past but that also causes the change status time (the one reported by ls -lc for instance) to be set in the past, to the specified time, plus the time it took to make the copy).

That ctime is not meant to be settable arbitrarily either. By setting it in the past like that, it may break the assumptions that some software may make about those file. For instance a backup software may decide to disregard it because it has a ctime that predates the last backup time.

So it may be better to make sure the ctime is not set in that namespace with a faked clock time, for instance, by only creating the file in the past, but copying its contents in the present:

unshare --time sh -Cc '
  umask 77 && date -s "@$1" && : > "$2.new"' sh "$t" "$file" &&
  cp -aT -- "$file" "$file.new" &&
  mv -f -- "$file.new" "$file"

¹ you need a Linux kernel 5.6 or above and CONFIG_TIME_NS to be enabled in the kernel and util-linux 2.36 or above.

2
  • my version of unshare doesnt have the --time option. unshare from util-linux 2.33.1. I get the following message when trying to run that command. unshare: unrecognized option '--time' Try 'unshare --help' for more information. Jan 20 at 17:53
  • I was able to use the zsh and touch option you post above, Thank you for your help! Jan 20 at 18:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.