Skip to content

Instantly share code, notes, and snippets.

@tbussmann
Created November 14, 2022 11:33
Copy/Set the 'Date Added' of files and folders in macOS
//Simple tool to copy the 'Date Added' on macOS.
//based on code witten by Andrew Neitsch <andrew@neitsch.ca> and an hint of Ken Thomases
//<https://stackoverflow.com/q/39685113/>
//compile using "cc -o cpda cpda.c"
//tested on macOS 10.13 and 12 on APFS
//test with "mdls -name kMDItemDateAdded ..." <https://stackoverflow.com/a/71264110/394431>
//use with "cp -a ..." and "find -exec ..."
#include <stdlib.h>
#include <string.h>
#include <sys/attr.h>
#include <unistd.h>
/*
* 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) {
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) {
return 1;
}
return 0;
}
#include <stdio.h>
/*
*
* Make it possible to call the code above from a simple cmd line tool
* to copy the 'Date Added' from one file to another.
*
*/
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage:\n%s source_path target_path\n\nCopy the kMDItemDateAdded from source_path to target_path.\n", argv[0]);
return 64;
}
struct timespec t;
int err;
err = get_date_added(argv[1], &t);
if (err != 0) {
return err;
}
err = set_date_added(argv[2], t);
if (err != 0) {
return err;
}
return 0;
}
@ukushu
Copy link

ukushu commented Apr 22, 2024

Can you help me transfer "set_date_added" func to swift code?

All I have at the moment is:

import Darwin

func setDateAdded(path: String, toDate date: Date) -> Bool {
    guard FileManager.default.fileExists(atPath: path) else { return false }
    
    var request = attrlist()
    request.bitmapcount = UInt16(ATTR_BIT_MAP_COUNT)
    request.commonattr  = attrgroup_t(ATTR_CMN_ADDEDTIME)
    
    struct request_buf_t {
        var added: timespec
    }
    
    var request_buf = request_buf_t(added: timespec(tv_sec: Int(date.timeIntervalSince1970), tv_nsec: 0) )
    
    let err = setattrlist(path, &request, &request_buf, MemoryLayout.size(ofValue: request_buf), 0)
    
    return err == 0
}

But it allways falls

Here in comments or by the URL:
https://stackoverflow.com/questions/78366352/change-kmditemdateadded-date-added-files-metadata-attribute-via-swift-cod

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment