herzbube
herzbube

Reputation: 13378

How do I change the creation time of a file to a newer date in Mac OS X?

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?

Upvotes: 1

Views: 1991

Answers (2)

Ken Thomases
Ken Thomases

Reputation: 90531

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);

Upvotes: 2

aichao
aichao

Reputation: 7435

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.

Upvotes: 0

Related Questions