1

On Mac OS X, using C and/or C++, I want to change the creation time of a file to an arbitrary date/time. I have found a number of solutions, notably this StackOverflow answer, that allow to set the creation time to an older date, but this is not sufficient for me - I also want to be able to set a newer date. Using the utimes() function therefore is not the solution I am looking for.

I know that setting a newer creation time must be possible somehow, because the SetFile utility from Apple's developer command line tools can do it, but so far my search-fu has failed to uncover any hints that bring me closer to a solution.

Does anyone know of a way how I can achieve my goal?

Why do I want to do this myself, why can't I use SetFile?

  • The SetFile command line utility is deprecated (see man SetFile), so it's bound to go away some time in the future
  • I want to create a utility that allows me to specify a time delta to add to/subtract from the current creation time. The SetFile utility does not have any convenient command line arguments to do this.
  • Last but not least: Curiosity!
Community
  • 1
  • 1
herzbube
  • 13,158
  • 9
  • 45
  • 87
  • Using [`utime`](https://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man3/utime.3.html) wouldn't work anyway, as you can only set the access and modification times with it, not the creation time. To change the creation time the only way is to create a new file, copy the contents, and rename it as the new file. Then the creation time will be "now". You can't, in user-space, change the creation time once it has been set. – Some programmer dude Aug 10 '16 at 09:31
  • @JoachimPileborg If you read the answer that I have referenced you will see that `utimes()` adjusts the creation time under some circumstances. [Here's a direct link](https://www.freebsd.org/cgi/man.cgi?query=utimes&sektion=2) to the BSD man page of `utimes()` that specifies the behaviour. I admit that I have not tested the behaviour myself, but its operation is in evidence if you run `touch -t` on the command line and set a modification time that is older than the file's current creation time. – herzbube Aug 10 '16 at 09:38
  • Most Unix file systems don't even store creation time. – Keith Thompson Aug 10 '16 at 15:57

2 Answers2

2

Haven't tried it, but according to the docs, the NSURL resource value under the key NSURLCreationDateKey is read-write. Since you specified C or C++, you'd use the corresponding CFURL API. So, you'd call:

CFURLRef url = /* ... */
CFDateRef date = /* ... */
CFErrorRef error;
if (!CFURLSetResourcePropertyForKey(url, kCFURLCreationDateKey, date, &error))
    /* handle error */;

EDIT: A minimal example

const char* fileName = "/path/to/file";
size_t fileNameStringLength = strlen(fileName);
Boolean isDirectory = false;
CFURLRef url = CFURLCreateFromFileSystemRepresentation(
   kCFAllocatorDefault,
   (const UInt8*)fileName,
   fileNameStringLength,
   isDirectory);

// Seconds since 1 January, 2001 00:00:00 GMT
CFAbsoluteTime absTime = CFAbsoluteTimeGetCurrent();
CFAbsoluteTime adjustedCreationTime = absTime - 3600;
CFDateRef date = CFDateCreate(
    kCFAllocatorDefault,
    adjustedCreationTime);

CFErrorRef error;
if (!CFURLSetResourcePropertyForKey(url, kCFURLCreationDateKey, date, &error))
{
  fprintf(stderr, "an error occurred\n");
  exit(1);
}

CFRelease(url);
CFRelease(date);
herzbube
  • 13,158
  • 9
  • 45
  • 87
Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • I tested this with a minimal example, and it does work, indeed! Just putting together the example has been a hassle, though, because I am not familiar with Core Foundation. In the meantime, I have found an alternative that also works and that uses Objective-C / Cocoa ([link to the SO answer](http://stackoverflow.com/a/16302660/1054378)). I will go for that solution because C/C++ can easily be mixed with Objective-C, and life is so much easier with Cocoa's higher-level APIs. – herzbube Aug 11 '16 at 12:21
0

BTW, I have no idea if this is safe, secure, whatever. So, do this at your own risk.

On OS X, you can sort of do this by setting the time of the day to the future and then copying the file (and renaming it back). It is not the same file with its creation time modified; it is a copy with the creation time you set.

Some code (I got the code to set the time of the day from here):

#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <copyfile.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  struct timeval tv_now, tv_set;
  copyfile_state_t s;
  struct stat st;
  // retrieve original stat
  if (stat(argv[2], &st) < 0)
    perror("stat");
  // get current time of day
  if (gettimeofday(&tv_now, 0) == -1)
    perror("gettimeofday");
  // set time of day to +argv[1] days
  tv_set = tv_now;
  tv_set.tv_sec += 86400 * atoi(argv[1]);
  if (settimeofday(&tv_set, 0) == -1)
    perror("settimeofday to future");
  // copy the file to a temporary, copy everythig except stat
  s = copyfile_state_alloc();
  if (copyfile(argv[2], ".eighty_eight_miles_per_hour", s, COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_DATA) < 0)
    perror("copy file");
  copyfile_state_free(s);
  // rename it back to original name
  if (rename(".eighty_eight_miles_per_hour", argv[2]) < 0)
    perror("rename file");
  // restore file owner, group, and mode
  if (chown(argv[2], st.st_uid, st.st_gid) < 0)
    perror("chown");
  if (chmod(argv[2], st.st_mode) < 0)
    perror("chmod");
  // reset current time of day
  if (settimeofday(&tv_now, 0) == -1)
    perror("settimeofday back to now");

  return 0;
}

I call this program the flux_capacitor. The first command line argument is the number of days forward to set the file's creation date, and the second argument is the file name. You have to run this program as root to set the time.

Observe, as I send the delorean forward in time by 2 days.

[ronin:~/Documents/CPP] aichao% touch delorean
[ronin:~/Documents/CPP] aichao% ls -l delorean
-rw-r--r--  1 aichao  staff  0 Aug 10 11:43 delorean
[ronin:~/Documents/CPP] aichao% su
Password:
sh-3.2# ./flux_capacitor 2 delorean
sh-3.2# exit
exit
[ronin:~/Documents/CPP] aichao% ls -l delorean
-rw-r--r--  1 aichao  staff  0 Aug 12  2016 delorean
[ronin:~/Documents/CPP] aichao% date
Wed Aug 10 11:43:47 EDT 2016

and in the Finder:

Delorean

Note that I only restore the original owner, group, and mode from the stat for the file. I don't think you can or want to do more than that, but I don't know. Obviously, links to the file will be broken.

Community
  • 1
  • 1
aichao
  • 7,375
  • 3
  • 16
  • 18
  • Thanks for taking the time to put this together. The humour is much appreciated :-) but as you note yourself, this solution is less than ideal. – herzbube Aug 11 '16 at 12:36
  • Thanks for asking the question. This was the most fun I had in my 40 days on SO :-) – aichao Aug 11 '16 at 12:39
  • Reminds me of a program written in High School, shrank all system fonts to 1, making it near impossible to control anything with the mouse (gag app). Changing the system time a lot and often... that could be even worse. -- Calendars, log files, emails, expiry dates, renewal prompts, oh my! – Able Mac Jul 04 '19 at 01:01