static void before_open(const char *path, int oflag, struct backup_info *info) { int srcfd = -1, dstfd = -1, success = 0; struct stat st; memset(info, 0, sizeof(*info)); // bail out if not write if ((oflag & (O_WRONLY | O_RDWR)) == 0) return; // FIXME better blacklisting if (strncmp(path, "/dev/", 5) == 0) return; // not implemented if ((oflag & O_NOFOLLOW) != 0) { uncolog_set_error(&ufp, 0, "unco:unsupported operation: open with O_NOFOLLOW against file:%s", path); return; } // open source if ((srcfd = default_open(path, O_RDONLY)) == -1) { info->errnum = errno; goto Exit; } fstat(srcfd, &st); // TODO need to check error? // create backup and copy, update the times, and return if ((info->backup = uncolog_get_linkname(&ufp)) == NULL) { // errror reported by caller goto Exit; } if ((dstfd = default_open(info->backup, O_WRONLY | O_CREAT | O_EXCL)) == -1) { info->errnum = errno; goto Exit; } if (kcopyfd(srcfd, dstfd) != 0) { info->errnum = errno; goto Exit; } if (unco_utimes(dstfd, &st, default_futimes) != 0) { info->errnum = errno; goto Exit; } success = 1; Exit: if (! success) { if (srcfd != -1) close(srcfd); free(info->backup); info->backup = NULL; if (dstfd != -1) close(dstfd); } }
int my_open(const char* path) { default_open(path); check_device(drv.device); set_rc_protocol(drv.device); return 0; }
extern void _setup_unco_preload() { char *logfn, *env, *dir = NULL, *fnbuf = NULL; long long log_index; int dirlock_fd = -1; // load default handlers default_open = (int (*)(const char*, int, ...))dlsym(RTLD_NEXT, "open"); default_mkdir = (int (*)(const char *, mode_t))dlsym(RTLD_NEXT, "mkdir"); default_futimes = (int (*)(int, const struct timeval[2]))dlsym(RTLD_NEXT, "futimes"); default_link = (int (*)(const char *, const char *))dlsym(RTLD_NEXT, "link"); default_symlink = (int (*)(const char *, const char *))dlsym(RTLD_NEXT, "symlink"); default_unlink = (int (*)(const char *))dlsym(RTLD_NEXT, "unlink"); default_rmdir = (int (*)(const char *))dlsym(RTLD_NEXT, "rmdir"); default_chown = (int (*)(const char *, uid_t, gid_t))dlsym(RTLD_NEXT, "chown"); // open the log file if ((env = getenv("UNCO_LOG")) != NULL) { if (env[0] == '/') { logfn = env; } else { if ((dir = getcwd(NULL, 0)) == NULL) { perror("unco:could not obtain cwd"); goto Error; } if ((fnbuf = ksprintf("%s/%s", dir, env)) == NULL) { perror("unco"); goto Error; } logfn = fnbuf; } uncolog_open(&ufp, logfn, 'a', default_open, default_mkdir); } else { // no path given; create a new entry in the default dir if ((dir = unco_get_default_dir(default_mkdir)) == NULL) goto Error; // lock the directory if ((fnbuf = ksprintf("%s/lock", dir)) == NULL) { perror("unco"); goto Error; } if ((dirlock_fd = default_open(fnbuf, O_WRONLY | O_CREAT | O_TRUNC | O_EXLOCK, 0600)) == -1) { kerr_printf("failed to open file:%s", fnbuf); goto Error; } free(fnbuf); fnbuf = NULL; // obtain logindex if ((log_index = unco_get_next_logindex(dir)) == -1) goto Error; if ((fnbuf = ksprintf("%s/%lld", dir, log_index)) == NULL) { perror("unco"); goto Error; } logfn = fnbuf; // set UNCO_LOG, so that child processes would write to the same file #if 1 if (set_uncolog_osx(logfn) != 0) goto Error; #else setenv("UNCO_LOG", logfn, 1); #endif // open the log uncolog_open(&ufp, logfn, 'w', default_open, default_mkdir); // unlock the directory close(dirlock_fd); dirlock_fd = -1; // append meta if (uncolog_get_fd(&ufp) != -1) { // setup procedures for a new log log_meta(); spawn_finalizer(); } } free(dir); free(fnbuf); return; Error: if (dirlock_fd != -1) close(dirlock_fd); free(dir); free(fnbuf); uncolog_init_fp(&ufp); }