static int ghost_apply_metadata(const char *path, GhostFileEntry *gfe) { struct timeval tv[2]; int ret = -1; if (chown(path, gfe->uid, gfe->gid) < 0) { pr_perror("Can't reset user/group on ghost %s", path); goto err; } if (chmod(path, gfe->mode)) { pr_perror("Can't set perms %o on ghost %s", gfe->mode, path); goto err; } if (gfe->atim) { tv[0].tv_sec = gfe->atim->tv_sec; tv[0].tv_usec = gfe->atim->tv_usec; tv[1].tv_sec = gfe->mtim->tv_sec; tv[1].tv_usec = gfe->mtim->tv_usec; if (lutimes(path, tv)) { pr_perror("Can't set access and modufication times on ghost %s", path); goto err; } } ret = 0; err: return ret; }
void set_ftime(char *fnm, time_t mtime, time_t atime, int frc) { static struct timeval tv[2] = {{0L, 0L}, {0L, 0L}}; struct stat sb; tv[0].tv_sec = atime; tv[1].tv_sec = mtime; if (!frc && (!patime || !pmtime)) { /* * if we are not forcing, only set those times the user wants * set. We get the current values of the times if we need them. */ if (lstat(fnm, &sb) == 0) { if (!patime) tv[0].tv_sec = sb.st_atime; if (!pmtime) tv[1].tv_sec = sb.st_mtime; } else syswarn(0,errno,"Unable to obtain file stats %s", fnm); } /* * set the times */ if (lutimes(fnm, tv) < 0) syswarn(1, errno, "Access/modification time set failed on: %s", fnm); return; }
void DCOPY_copy_timestamps( bayer_flist flist, uint64_t idx, const char* dest_path) { /* get atime seconds and nsecs */ uint64_t atime = bayer_flist_file_get_atime(flist, idx); uint64_t atime_nsec = bayer_flist_file_get_atime_nsec(flist, idx); /* get mtime seconds and nsecs */ uint64_t mtime = bayer_flist_file_get_mtime(flist, idx); uint64_t mtime_nsec = bayer_flist_file_get_mtime_nsec(flist, idx); /* fill in time structures */ struct timespec times[2]; times[0].tv_sec = (time_t) atime; times[0].tv_nsec = (long) atime_nsec; times[1].tv_sec = (time_t) mtime; times[1].tv_nsec = (long) mtime_nsec; /* set times with nanosecond precision using utimensat, * assume path is relative to current working directory, * if it's not absolute, and set times on link (not target file) * if dest_path refers to a link */ if(utimensat(AT_FDCWD, dest_path, times, AT_SYMLINK_NOFOLLOW) != 0) { BAYER_LOG(BAYER_LOG_ERR, "Failed to change timestamps on %s utime() errno=%d %s", dest_path, errno, strerror(errno) ); } #if 0 /* TODO: see stat-time.h and get_stat_atime/mtime/ctime to read sub-second times, * and use utimensat to set sub-second times */ /* as last step, change timestamps */ if(! S_ISLNK(statbuf->st_mode)) { struct utimbuf times; times.actime = statbuf->st_atime; times.modtime = statbuf->st_mtime; if(utime(dest_path, ×) != 0) { BAYER_LOG(BAYER_LOG_ERR, "Failed to change timestamps on %s utime() errno=%d %s", dest_path, errno, strerror(errno) ); } } else { struct timeval tv[2]; tv[0].tv_sec = statbuf->st_atime; tv[0].tv_usec = 0; tv[1].tv_sec = statbuf->st_mtime; tv[1].tv_usec = 0; if(lutimes(dest_path, tv) != 0) { BAYER_LOG(BAYER_LOG_ERR, "Failed to change timestamps on %s utime() errno=%d %s", dest_path, errno, strerror(errno) ); } } #endif return; }
static bool copy_entry(const char *source, const char *destination, uid_t uid, gid_t gid) { struct stat sb; if (lstat(source, &sb) != 0) return false; struct timeval tv[2]; tv[0].tv_sec = sb.st_atime; tv[0].tv_usec = 0; tv[1].tv_sec = sb.st_mtime; tv[1].tv_usec = 0; if (S_ISDIR(sb.st_mode)) { if (!copy_dir(source, destination, uid, gid, &sb)) return false; } else if (S_ISLNK(sb.st_mode)) { if (!copy_symlink(source, destination, uid, gid, &sb)) return false; } else if (S_ISREG(sb.st_mode)) { if (!copy_file(source, destination, uid, gid, &sb)) return false; } else { if (!copy_special(source, destination, uid, gid, &sb)) return false; } if (lutimes(destination, tv) != 0) return false; return true; }
/* * set attributes to what is specified. XXX: no rollback in case of failure */ static int processvattr(const char *path, const struct vattr *va, int regular) { struct timeval tv[2]; /* XXX: -1 == PUFFS_VNOVAL, but shouldn't trust that */ if (va->va_uid != (unsigned)-1 || va->va_gid != (unsigned)-1) if (lchown(path, va->va_uid, va->va_gid) == -1) return errno; if (va->va_mode != (u_short)PUFFS_VNOVAL) if (lchmod(path, va->va_mode) == -1) return errno; /* sloppy */ if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL || va->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) { TIMESPEC_TO_TIMEVAL(&tv[0], &va->va_atime); TIMESPEC_TO_TIMEVAL(&tv[1], &va->va_mtime); if (lutimes(path, tv) == -1) return errno; } if (regular && va->va_size != (u_quad_t)PUFFS_VNOVAL) if (truncate(path, (off_t)va->va_size) == -1) return errno; return 0; }
// .utimens static int mhdd_utimens(const char *path, const struct timespec ts[2]) { mhdd_debug(MHDD_MSG, "mhdd_utimens: %s\n", path); int i, res, flag_found; for (i = flag_found = 0; i<mhdd.cdirs; i++) { char *object = create_path(mhdd.dirs[i], path); struct stat st; if (lstat(object, &st) != 0) { free(object); continue; } flag_found = 1; struct timeval tv[2]; tv[0].tv_sec = ts[0].tv_sec; tv[0].tv_usec = ts[0].tv_nsec / 1000; tv[1].tv_sec = ts[1].tv_sec; tv[1].tv_usec = ts[1].tv_nsec / 1000; res = lutimes(object, tv); free(object); if (res == -1) return -errno; } if (flag_found) return 0; errno = ENOENT; return -errno; }
void psync_utimes(const char *fn, const struct pfl_timespec *pts, int flags) { #ifdef HAVE_FUTIMENS struct timespec ts[2]; ts[0].tv_sec = pts[0].tv_sec; ts[0].tv_nsec = pts[0].tv_nsec; ts[1].tv_sec = pts[1].tv_sec; ts[1].tv_nsec = pts[1].tv_nsec; if (utimensat(AT_FDCWD, fn, ts, flags) == -1) psynclog_warn("utimes %s", fn); #else struct timeval tv[2]; (void)flags; tv[0].tv_sec = pts[0].tv_sec; tv[0].tv_usec = pts[0].tv_nsec / 1000; tv[1].tv_sec = pts[1].tv_sec; tv[1].tv_usec = pts[1].tv_nsec / 1000; if (lutimes(fn, tv) == -1) psynclog_warn("utimes %s", fn); #endif }
int set_utimes(const char *file, struct stat *fs) { static struct timeval tv[2]; #ifndef BSD tv[0].tv_sec = fs->st_atime; tv[0].tv_usec = 0; tv[1].tv_sec = fs->st_mtime; tv[1].tv_usec = 0; if (utimes(file, tv)) { warn("utimes: %s", file); return 1; } #else TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); if (lutimes(file, tv)) { warn("lutimes: %s", file); return (1); } #endif return (0); }
bool CFile::SetTimestamp(long timestamp) { #ifdef WIN32 FILETIME ftime; HANDLE h; bool close = false; if (handle==NULL) { h = CreateFile(s2ws(filename).c_str() , GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); close = true; } else { h = (HANDLE)_get_osfhandle(fileno(handle)); } if (h == NULL) { return false; } fileSystem->TimestampToFiletime(timestamp, ftime); bool ret = SetFileTime(h, NULL, NULL, &ftime); if (close) { //close opened file CloseHandle(h); } return ret; #else struct timeval tv = {0, 0}; tv.tv_sec = timestamp; if (handle==NULL) { return lutimes(filename.c_str(), &tv) == 0; } else { return futimes(fileno(handle), &tv) == 0; } #endif }
static int do_lutimes(const char *path, struct stat *statp) { struct timeval t[2]; t[0].tv_sec = statp->st_atime; t[0].tv_usec = 0; t[1].tv_sec = statp->st_mtime; t[1].tv_usec = 0; return lutimes(path, t); }
gint32 Mono_Posix_Syscall_lutimes(const char *filename, struct Mono_Posix_Timeval *tv) { struct timeval _tv[2]; struct timeval *ptv; ptv = copy_utimes (_tv, tv); return lutimes (filename, ptv); }
static int restore_time(struct cpio *cpio, struct archive_entry *entry, const char *name, int fd) { #ifndef HAVE_UTIMES static int warned = 0; (void)cpio; /* UNUSED */ (void)entry; /* UNUSED */ (void)name; /* UNUSED */ if (!warned) lafe_warnc(0, "Can't restore access times on this platform"); warned = 1; return (fd); #else #if defined(_WIN32) && !defined(__CYGWIN__) struct __timeval times[2]; #else struct timeval times[2]; #endif if (!cpio->option_atime_restore) return (fd); times[1].tv_sec = archive_entry_mtime(entry); times[1].tv_usec = archive_entry_mtime_nsec(entry) / 1000; times[0].tv_sec = archive_entry_atime(entry); times[0].tv_usec = archive_entry_atime_nsec(entry) / 1000; #if defined(HAVE_FUTIMES) && !defined(__CYGWIN__) if (fd >= 0 && futimes(fd, times) == 0) return (fd); #endif /* * Some platform cannot restore access times if the file descriptor * is still opened. */ if (fd >= 0) { close(fd); fd = -1; } #ifdef HAVE_LUTIMES if (lutimes(name, times) != 0) #else if ((AE_IFLNK != archive_entry_filetype(entry)) && utimes(name, times) != 0) #endif lafe_warnc(errno, "Can't update time for %s", name); #endif return (fd); }
void MyDirEntry::setMetadata(const QString& path) const{ QFile file(path); file.setPermissions(permissions); struct timeval tv[2]; tv[0].tv_sec=lastModified.toTime_t(); tv[0].tv_usec=0; tv[1].tv_sec=lastModified.toTime_t(); tv[1].tv_usec=0; lutimes(QFile::encodeName(file.fileName()), tv); lchown(QFile::encodeName(file.fileName()), uid(), gid()); }
void hh_lutimes(value filename_v) { CAMLparam1(filename_v); #ifdef _WIN32 /* Not implemented */ CAMLreturn0; #else char* filename = String_val(filename_v); int success = lutimes(filename, NULL); if (success != 0) { caml_failwith("lutimes failed"); } #endif CAMLreturn0; }
int set_utimes(const char *file, struct stat *fs) { static struct timeval tv[2]; TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); if (lutimes(file, tv)) { warn("lutimes: %s", file); return (1); } return (0); }
int _do_utimens(EncFS_Context *, const string &cyName, const struct timespec ts[2]) { #ifdef HAVE_UTIMENSAT int res = utimensat(AT_FDCWD, cyName.c_str(), ts, AT_SYMLINK_NOFOLLOW); #else struct timeval tv[2]; tv[0].tv_sec = ts[0].tv_sec; tv[0].tv_usec = ts[0].tv_nsec / 1000; tv[1].tv_sec = ts[1].tv_sec; tv[1].tv_usec = ts[1].tv_nsec / 1000; int res = lutimes(cyName.c_str(), tv); #endif return (res == -1) ? -errno : ESUCCESS; }
void set_ftime(char *fnm, time_t mtime, time_t atime, int frc, int slk) { struct timeval tv[2]; struct stat sb; tv[0].tv_sec = atime; tv[0].tv_usec = 0; tv[1].tv_sec = mtime; tv[1].tv_usec = 0; if (!frc && (!patime || !pmtime)) { /* * if we are not forcing, only set those times the user wants * set. We get the current values of the times if we need them. */ if (lstat(fnm, &sb) == 0) { #if BSD4_4 && !HAVE_NBTOOL_CONFIG_H if (!patime) TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec); if (!pmtime) TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec); #else if (!patime) tv[0].tv_sec = sb.st_atime; if (!pmtime) tv[1].tv_sec = sb.st_mtime; #endif } else syswarn(0, errno, "Cannot obtain file stats %s", fnm); } /* * set the times */ #if HAVE_LUTIMES if (lutimes(fnm, tv) == 0) return; if (errno != ENOSYS) /* XXX linux: lutimes is per-FS */ goto bad; #endif if (slk) return; if (utimes(fnm, tv) == -1) goto bad; return; bad: syswarn(1, errno, "Access/modification time set failed on: %s", fnm); }
int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { int rc; struct timeval tv[2]; tv[0].tv_sec = times[0].tv_sec; tv[0].tv_usec = times[0].tv_nsec / 1000; tv[1].tv_sec = times[1].tv_sec; tv[1].tv_usec = times[1].tv_nsec / 1000; dir_mutex_lock(dirfd); if(flags & AT_SYMLINK_NOFOLLOW) { rc = lutimes(pathname, tv); } else { rc = utimes(pathname, tv); } dir_mutex_unlock(); return rc; }
int setfile(struct stat *fs, int fd) { static struct timeval tv[2]; struct stat ts; int rval, gotstat, islink, fdval; rval = 0; fdval = fd != -1; islink = !fdval && S_ISLNK(fs->st_mode); fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim); if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { warn("%sutimes: %s", islink ? "l" : "", to.p_path); rval = 1; } if (fdval ? fstat(fd, &ts) : (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) gotstat = 0; else { gotstat = 1; ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; } if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) : chown(to.p_path, fs->st_uid, fs->st_gid))) { if (errno != EPERM) { warn("chown: %s", to.p_path); rval = 1; } fs->st_mode &= ~(S_ISUID | S_ISGID); } if (!gotstat || fs->st_mode != ts.st_mode) if (fdval ? fchmod(fd, fs->st_mode) : (islink ? lchmod(to.p_path, fs->st_mode) : chmod(to.p_path, fs->st_mode))) { warn("chmod: %s", to.p_path); rval = 1; } if (!gotstat || fs->st_flags != ts.st_flags) if (fdval ? fchflags(fd, fs->st_flags) : (islink ? lchflags(to.p_path, fs->st_flags) : chflags(to.p_path, fs->st_flags))) { warn("chflags: %s", to.p_path); rval = 1; } return (rval); }
int set_utime(const char *filename, __u32 yst_atime, __u32 yst_mtime) { #ifdef HAS_LUTIMES struct timeval ftime[2]; ftime[0].tv_sec = yst_atime; ftime[0].tv_usec = 0; ftime[1].tv_sec = yst_mtime; ftime[1].tv_usec = 0; return lutimes(filename, ftime); #else struct utimbuf ftime; ftime.actime = yst_atime; ftime.modtime = yst_mtime; return utime(filename, &ftime); #endif }
static int _single_p(Copy * copy, char const * dst, struct stat const * st) { struct timeval tv[2]; if(lchown(dst, st->st_uid, st->st_gid) != 0) { _copy_filename_error(copy, dst, 0); if(lchmod(dst, st->st_mode & ~(S_ISUID | S_ISGID)) != 0) _copy_filename_error(copy, dst, 0); } else if(lchmod(dst, st->st_mode) != 0) _copy_filename_error(copy, dst, 0); tv[0].tv_sec = st->st_atime; tv[0].tv_usec = 0; tv[1].tv_sec = st->st_mtime; tv[1].tv_usec = 0; if(lutimes(dst, tv) != 0) _copy_filename_error(copy, dst, 0); return 0; }
int set_utimes(const char *file, struct stat *fs) { static struct timeval tv[2]; #ifndef HAVE_STRUCT_STAT_ST_ATIMESPEC tv[0].tv_sec = fs->st_atime; tv[0].tv_usec = 0; tv[1].tv_sec = fs->st_mtime; tv[1].tv_usec = 0; #else TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); #endif if (lutimes(file, tv)) { warn("lutimes: %s", file); return (1); } return (0); }
static PyObject * oe_lutimes(PyObject *self, PyObject *args) { // (str) filename, (tuple) (atime, mtime) char *path; PyObject *ftimes; if (!PyArg_ParseTuple( args, "etO:utime", Py_FileSystemDefaultEncoding, &path, &ftimes )) return NULL; struct timeval tv[2]; if (PyTuple_Check(ftimes) && PyTuple_Size(ftimes) == 2) { int i; for (i=0; i<2; i++) { if ( extract_time(PyTuple_GET_ITEM(ftimes, i), &tv[i].tv_sec, &tv[i].tv_usec) == -1 ) { PyMem_Free(path); return NULL; } } Py_BEGIN_ALLOW_THREADS i = lutimes(path, tv); Py_END_ALLOW_THREADS if (i < 0) return posix_error_with_allocated_filename(path); }
int cow_utimens(const char *path, const struct timespec ts[2]) { int res; LOG("%s",path); char *fqpath = create_path(cow_getConfig()->srcdir, path); if(fqpath==NULL){ return -errno; } struct timeval tv[2]; tv[0].tv_sec = ts[0].tv_sec; tv[0].tv_usec = ts[0].tv_nsec / 1000; tv[1].tv_sec = ts[1].tv_sec; tv[1].tv_usec = ts[1].tv_nsec / 1000; res = lutimes(fqpath, tv); free(fqpath); if (res == -1) return -errno; return 0; }
static PyObject * utimensat_wrapper(PyObject *self, PyObject *args) { int ret; const char *filename; long atime_sec, atime_nsec; long mtime_sec, mtime_nsec; #if NO_NANOSECONDS struct timeval tv[2]; #else struct timespec tv[2]; #endif if (!PyArg_ParseTuple(args, "sllll", &filename, &atime_sec, &atime_nsec, &mtime_sec, &mtime_nsec)) return NULL; #if NO_NANOSECONDS tv[0].tv_sec = atime_sec; tv[0].tv_usec = atime_nsec / 1000; tv[1].tv_sec = mtime_sec; tv[1].tv_usec = mtime_nsec / 1000; ret = lutimes(filename, tv); #else tv[0].tv_sec = atime_sec; tv[0].tv_nsec = atime_nsec; tv[1].tv_sec = mtime_sec; tv[1].tv_nsec = mtime_nsec; ret = utimensat(AT_FDCWD, filename, tv, AT_SYMLINK_NOFOLLOW); #endif if (ret == -1) ret = errno; return Py_BuildValue("i", ret); }
int extractfile(char *name) { int flags; uid_t uid; gid_t gid; mode_t mode; int extsize; struct timeval mtimep[2], ctimep[2]; struct entry *ep; char *buf; curfile.name = name; curfile.action = USING; mtimep[0].tv_sec = curfile.atime_sec; mtimep[0].tv_usec = curfile.atime_nsec / 1000; mtimep[1].tv_sec = curfile.mtime_sec; mtimep[1].tv_usec = curfile.mtime_nsec / 1000; ctimep[0].tv_sec = curfile.atime_sec; ctimep[0].tv_usec = curfile.atime_nsec / 1000; ctimep[1].tv_sec = curfile.birthtime_sec; ctimep[1].tv_usec = curfile.birthtime_nsec / 1000; extsize = curfile.extsize; uid = getuid(); if (uid == 0) uid = curfile.uid; gid = curfile.gid; mode = curfile.mode; flags = curfile.file_flags; switch (mode & IFMT) { default: fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); skipfile(); return (FAIL); case IFSOCK: vprintf(stdout, "skipped socket %s\n", name); skipfile(); return (GOOD); case IFDIR: if (mflag) { ep = lookupname(name); if (ep == NULL || ep->e_flags & EXTRACT) panic("unextracted directory %s\n", name); skipfile(); return (GOOD); } vprintf(stdout, "extract file %s\n", name); return (genliteraldir(name, curfile.ino)); case IFLNK: lnkbuf[0] = '\0'; pathlen = 0; buf = setupextattr(extsize); getfile(xtrlnkfile, xtrattr, xtrlnkskip); if (pathlen == 0) { vprintf(stdout, "%s: zero length symbolic link (ignored)\n", name); return (GOOD); } if (linkit(lnkbuf, name, SYMLINK) == GOOD) { if (extsize > 0) set_extattr_link(name, buf, extsize); (void) lchown(name, uid, gid); (void) lchmod(name, mode); (void) lutimes(name, ctimep); (void) lutimes(name, mtimep); (void) lchflags(name, flags); return (GOOD); } return (FAIL); case IFIFO: vprintf(stdout, "extract fifo %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag) (void) unlink(name); if (mkfifo(name, 0600) < 0) { fprintf(stderr, "%s: cannot create fifo: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } if (extsize == 0) { skipfile(); } else { buf = setupextattr(extsize); getfile(xtrnull, xtrattr, xtrnull); set_extattr_file(name, buf, extsize); } (void) chown(name, uid, gid); (void) chmod(name, mode); (void) utimes(name, ctimep); (void) utimes(name, mtimep); (void) chflags(name, flags); return (GOOD); case IFCHR: case IFBLK: vprintf(stdout, "extract special file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag) (void) unlink(name); if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600, (int)curfile.rdev) < 0) { fprintf(stderr, "%s: cannot create special file: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } if (extsize == 0) { skipfile(); } else { buf = setupextattr(extsize); getfile(xtrnull, xtrattr, xtrnull); set_extattr_file(name, buf, extsize); } (void) chown(name, uid, gid); (void) chmod(name, mode); (void) utimes(name, ctimep); (void) utimes(name, mtimep); (void) chflags(name, flags); return (GOOD); case IFREG: vprintf(stdout, "extract file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag) (void) unlink(name); if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { fprintf(stderr, "%s: cannot create file: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } buf = setupextattr(extsize); getfile(xtrfile, xtrattr, xtrskip); if (extsize > 0) set_extattr_fd(ofile, name, buf, extsize); (void) fchown(ofile, uid, gid); (void) fchmod(ofile, mode); (void) futimes(ofile, ctimep); (void) futimes(ofile, mtimep); (void) fchflags(ofile, flags); (void) close(ofile); return (GOOD); } /* NOTREACHED */ }
/* Set the access and modification time stamps of FILE to be TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing symlinks. Fail with ENOSYS if the platform does not support changing symlink timestamps, but FILE was a symlink. */ int lutimens (char const *file, struct timespec const timespec[2]) { struct timespec adjusted_timespec[2]; struct timespec *ts = timespec ? adjusted_timespec : NULL; int adjustment_needed = 0; struct stat st; if (ts) { adjusted_timespec[0] = timespec[0]; adjusted_timespec[1] = timespec[1]; adjustment_needed = validate_timespec (ts); } if (adjustment_needed < 0) return -1; /* The Linux kernel did not support symlink timestamps until utimensat, in version 2.6.22, so we don't need to mimic fdutimens' worry about buggy NFS clients. But we do have to worry about bogus return values. */ #if HAVE_UTIMENSAT if (0 <= lutimensat_works_really) { int result; # if __linux__ /* As recently as Linux kernel 2.6.32 (Dec 2009), several file systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT, but work if both times are either explicitly specified or UTIME_NOW. Work around it with a preparatory lstat prior to calling utimensat; fortunately, there is not much timing impact due to the extra syscall even on file systems where UTIME_OMIT would have worked. FIXME: Simplify this in 2012, when file system bugs are no longer common. */ if (adjustment_needed == 2) { if (lstat (file, &st)) return -1; if (ts[0].tv_nsec == UTIME_OMIT) ts[0] = get_stat_atime (&st); else if (ts[1].tv_nsec == UTIME_OMIT) ts[1] = get_stat_mtime (&st); /* Note that st is good, in case utimensat gives ENOSYS. */ adjustment_needed++; } # endif /* __linux__ */ result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW); # ifdef __linux__ /* Work around a kernel bug: http://bugzilla.redhat.com/442352 http://bugzilla.redhat.com/449910 It appears that utimensat can mistakenly return 280 rather than -1 upon ENOSYS failure. FIXME: remove in 2010 or whenever the offending kernels are no longer in common use. */ if (0 < result) errno = ENOSYS; # endif if (result == 0 || errno != ENOSYS) { utimensat_works_really = 1; lutimensat_works_really = 1; return result; } } lutimensat_works_really = -1; #endif /* HAVE_UTIMENSAT */ /* The platform lacks an interface to set file timestamps with nanosecond resolution, so do the best we can, discarding any fractional part of the timestamp. */ if (adjustment_needed || REPLACE_FUNC_STAT_FILE) { if (adjustment_needed != 3 && lstat (file, &st)) return -1; if (ts && update_timespec (&st, &ts)) return 0; } /* On Linux, lutimes is a thin wrapper around utimensat, so there is no point trying lutimes if utimensat failed with ENOSYS. */ #if HAVE_LUTIMES && !HAVE_UTIMENSAT { struct timeval timeval[2]; struct timeval *t; int result; if (ts) { timeval[0].tv_sec = ts[0].tv_sec; timeval[0].tv_usec = ts[0].tv_nsec / 1000; timeval[1].tv_sec = ts[1].tv_sec; timeval[1].tv_usec = ts[1].tv_nsec / 1000; t = timeval; } else t = NULL; result = lutimes (file, t); if (result == 0 || errno != ENOSYS) return result; } #endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */ /* Out of luck for symlinks, but we still handle regular files. */ if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st)) return -1; if (!S_ISLNK (st.st_mode)) return fdutimens (-1, file, ts); errno = ENOSYS; return -1; }
int setfile(struct stat *fs, int fd) { static struct timeval tv[2]; struct stat ts; int rval, gotstat, islink, fdval; rval = 0; fdval = fd != -1; islink = !fdval && S_ISLNK(fs->st_mode); fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { warn("%sutimes: %s", islink ? "l" : "", to.p_path); rval = 1; } if (fdval ? fstat(fd, &ts) : (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) gotstat = 0; else { gotstat = 1; ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; } /* * Changing the ownership probably won't succeed, unless we're root * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting * the mode; current BSD behavior is to remove all setuid bits on * chown. If chown fails, lose setuid/setgid bits. */ if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) : chown(to.p_path, fs->st_uid, fs->st_gid))) { if (errno != EPERM) { warn("chown: %s", to.p_path); rval = 1; } fs->st_mode &= ~(S_ISUID | S_ISGID); } if (!gotstat || fs->st_mode != ts.st_mode) if (fdval ? fchmod(fd, fs->st_mode) : (islink ? lchmod(to.p_path, fs->st_mode) : chmod(to.p_path, fs->st_mode))) { warn("chmod: %s", to.p_path); rval = 1; } if (!gotstat || fs->st_flags != ts.st_flags) if (fdval ? fchflags(fd, fs->st_flags) : (islink ? lchflags(to.p_path, fs->st_flags) : chflags(to.p_path, fs->st_flags))) { warn("chflags: %s", to.p_path); rval = 1; } return (rval); }
RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER); AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); /* * Convert the paths. */ char const *pszNativePath; int rc = rtPathToNative(&pszNativePath, pszPath, NULL); if (RT_SUCCESS(rc)) { RTFSOBJINFO ObjInfo; /* * If it's a no-op, we'll only verify the existance of the file. */ if (!pAccessTime && !pModificationTime) rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, fFlags); else { /* * Convert the input to timeval, getting the missing one if necessary, * and call the API which does the change. */ struct timeval aTimevals[2]; if (pAccessTime && pModificationTime) { RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]); RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]); } else { rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags); if (RT_SUCCESS(rc)) { RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]); RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]); } else Log(("RTPathSetTimes('%s',%p,%p,,): RTPathQueryInfo failed with %Rrc\n", pszPath, pAccessTime, pModificationTime, rc)); } if (RT_SUCCESS(rc)) { if (fFlags & RTPATH_F_FOLLOW_LINK) { if (utimes(pszNativePath, aTimevals)) rc = RTErrConvertFromErrno(errno); } #if (defined(RT_OS_DARWIN) && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) \ || defined(RT_OS_FREEBSD) \ || defined(RT_OS_LINUX) \ || defined(RT_OS_OS2) /** @todo who really has lutimes? */ else { if (lutimes(pszNativePath, aTimevals)) rc = RTErrConvertFromErrno(errno); } #else else { if (pAccessTime && pModificationTime) rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags); if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)) rc = VERR_NS_SYMLINK_SET_TIME; else if (RT_SUCCESS(rc)) { if (utimes(pszNativePath, aTimevals)) rc = RTErrConvertFromErrno(errno); } } #endif if (RT_FAILURE(rc)) Log(("RTPathSetTimes('%s',%p,%p,,): failed with %Rrc and errno=%d\n", pszPath, pAccessTime, pModificationTime, rc, errno)); } } rtPathFreeNative(pszNativePath, pszPath); }
/* * copy_symlink - copy a symlink * * Copy a symlink from src to dst. * * statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set * the access and modification and the access rights. * * Return 0 on success, -1 on error. */ static int copy_symlink (const char *src, const char *dst, unused bool reset_selinux, const struct stat *statp, const struct timeval mt[], uid_t old_uid, uid_t new_uid, gid_t old_gid, gid_t new_gid) { char *oldlink; /* copy_tree () must be the entry point */ assert (NULL != src_orig); assert (NULL != dst_orig); /* * Get the name of the file which the link points * to. If that name begins with the original * source directory name, that part of the link * name will be replaced with the original * destination directory name. */ oldlink = readlink_malloc (src); if (NULL == oldlink) { return -1; } /* If src was a link to an entry of the src_orig directory itself, * create a link to the corresponding entry in the dst_orig * directory. */ if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) { size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1; char *dummy = (char *) xmalloc (len); (void) snprintf (dummy, len, "%s%s", dst_orig, oldlink + strlen (src_orig)); free (oldlink); oldlink = dummy; } #ifdef WITH_SELINUX if (set_selinux_file_context (dst) != 0) { free (oldlink); return -1; } #endif /* WITH_SELINUX */ if ( (symlink (oldlink, dst) != 0) || (lchown_if_needed (dst, statp, old_uid, new_uid, old_gid, new_gid) != 0)) { /* FIXME: there are no modes on symlinks, right? * ACL could be copied, but this would be much more * complex than calling perm_copy_file. * Ditto for Extended Attributes. * We currently only document that ACL and Extended * Attributes are not copied. */ free (oldlink); return -1; } free (oldlink); #ifdef HAVE_LUTIMES /* 2007-10-18: We don't care about * exit status of lutimes because * it returns ENOSYS on many system * - not implemented */ (void) lutimes (dst, mt); #endif /* HAVE_LUTIMES */ return 0; }