So, I've further messed with the code kindly offered by andrew and Stefan Schmidt, and here's a bit of C code that you can run after you copy your folders. Just write the path to the folder where the Date Added order is the way God intended (or just drag the folder itself into the Terminal window), press Enter, and then write the path to the folder copy, and that folder copy will receive the dates of the original!
(Once again, folder with the right dates first! Or the wrong dates will overwrite the right ones!)
Code works in my test, but hey, if there's issues with it, don't be surprised, all I knew about C two days ago was it existed
EDIT: updated the code to make it more user-friendly and give more informational warnings. Remember to assert admin privileges, run it as root, sudo that sucker, lest it fail a bunch of files for no clear reason, and to for your sake only point it to folders whose dates you actually care about, lest it run for half an hour filling your logs with Application Support garbage you don't care about.
#include <stdlib.h>
#include <string.h>
#include <sys/attr.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/errno.h>
/* Code goes through all the files in the source folder and its subfolders
* gets their Date Added
* and sets it to the corresponding files in the destination folder
* Neat, eh?
*/
/* List, finds all files and sub-directories of a given
* directory in tree structure.
* @param basePath Base path to traverse directory
*/
int ok=0;
int nok=0;
int logs=1;
void list(char *basePathSource, char *basePathDest){
char path[9000];
char pathd[9000];
struct dirent *dp;
DIR *dir = opendir(basePathSource);
if (!dir) return;
while ((dp = readdir(dir)) != NULL){
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0){
strcpy(path, basePathSource); //these three lines are
strcat(path, "/"); //equivalent to the Processing line
strcat(path, dp->d_name); //path=basePathSource+'/'+dp->d_name
strcpy(pathd, basePathDest); //these three lines are
strcat(pathd, "/"); //equivalent to the Processing line
strcat(pathd, dp->d_name); //path=basePath+'/'+dp->d_name
int terr = date_added_transfer(path, pathd);
if(terr==0){
ok++;
if(logs>=2)printf("Successfully transferred Date Added to %s! :D\n", pathd);
}else nok++;
if (terr==2) if(logs<=2)printf("Failed to get Date Added from %s :c\n", path);
list(path, pathd);
}
}
closedir(dir);
}
/* Get kMDItemDateAdded of path.
* Returns:
* • 0 on success
* • 1 if a system call failed: check errno
* • 2 if something else went wrong
*/
int get_date_added(const char* path, struct timespec * out) {
attrgroup_t request_attrs = ATTR_CMN_RETURNED_ATTRS | ATTR_CMN_ADDEDTIME;
struct attrlist request;
memset(&request, 0, sizeof(request));
request.bitmapcount = ATTR_BIT_MAP_COUNT;
request.commonattr = request_attrs;
typedef struct {
u_int32_t length;
attribute_set_t returned;
struct timespec added;
} __attribute__((aligned(4), packed)) response_buf_t;
response_buf_t response;
int err = getattrlist(path, &request, &response, sizeof(response), 0);
if (err != 0) {
if(logs<=2)printf("Failed to get Date Added from %s: '%s' :c \n", path,strerror(errno));
return 1;
}
if (response.length != sizeof(response)) {
// Need a different-sized buffer; but provided one of exactly required
// size?!
return 2;
}
if (response.returned.commonattr != request_attrs) {
// Didn’t get back all requested common attributes
return 2;
}
out->tv_sec = response.added.tv_sec;
out->tv_nsec = response.added.tv_nsec;
return 0;
}
/* Set kMDItemDateAdded of path.
* Returns:
* • 0 on success
* • 1 if a system call failed: check errno
*/
int set_date_added(const char* path, struct timespec in) {
attrgroup_t request_attrs = ATTR_CMN_ADDEDTIME;
struct attrlist request;
memset(&request, 0, sizeof(request));
request.bitmapcount = ATTR_BIT_MAP_COUNT;
request.commonattr = request_attrs;
typedef struct {
struct timespec added;
} __attribute__((aligned(4), packed)) request_buf_t;
request_buf_t request_buf;
request_buf.added.tv_sec = in.tv_sec;
request_buf.added.tv_nsec = in.tv_nsec;
int err = setattrlist(path, &request, &request_buf, sizeof(request_buf), 0);
if (err != 0) {
if(logs<=2)printf("Failed to set Date Added to %s: '%s' :c \n", path,strerror(errno));
return 1;
}
return 0;
}
/* Set kMDItemDateAdded of path to kMDItemFSContentChangeDate
* Returns:
* • 0 on success
* • 1 if a path doesn't exist
* • 2 if a function call failed
*/
int date_added_transfer(char* paths, char* pathd) {
int err;
if(access(paths, F_OK) != 0) {
if(logs<=2)printf("Can't reach source path %s :c\n", paths);
return 1;
}
if(access(pathd, F_OK) != 0) {
if(logs<=2)printf("Can't reach destination path %s - it's probably not there\n", pathd);
return 1;
}
struct timespec out;
err = get_date_added(paths, &out);
if (err != 0) {
return 2;
}
struct timespec in;
in.tv_sec = out.tv_sec;
in.tv_nsec = out.tv_nsec;
err = set_date_added(pathd, in);
if (err != 0) {
return 3;
}
return 0;
}
/* Modify paths given as command line arguments
* Returns:
* • 0 on success
* • 1 if a path doesn't exist
* • 2 if something else went wrong
*/
int main(){
char srcpath[100];
char dstpath[100];
int logset;
int loopn=1;
// Input paths from user
while(loopn==1){
ok=0;
nok=0;
printf("Enter folder you wish to copy Date Added info from: ");
scanf("%s", srcpath);
printf("Enter the corresponding folder in the destination to copy the info to: ");
scanf("%s", dstpath);
printf("You'll be told how many successful and failed transfers occurred, In addition, type the number of the option you prefer:\n");
printf("1. Failure messages only, 2. Failure and success messages, or 3. Success messages only\n");
scanf("%d", &logset);
logs=logset;
printf("Righty then, let's go!\n");
list(srcpath, dstpath);
printf("%d transfers successful, %d transfers failed\n",ok,nok);
printf("Wanna go again? 1. Yep! 2. Nah that's it!\n");
scanf("%d", &loopn);
}
return 0;
}