static void setfile(const char *name, struct stat *fs) { static struct timespec tspec[2]; fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO; tspec[0] = fs->st_atim; tspec[1] = fs->st_mtim; if (utimensat(AT_FDCWD, name, tspec, 0)) cwarn("utimensat: %s", name); /* * 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 (chown(name, fs->st_uid, fs->st_gid)) { if (errno != EPERM) cwarn("chown: %s", name); fs->st_mode &= ~(S_ISUID|S_ISGID); } if (chmod(name, fs->st_mode) && errno != EOPNOTSUPP) cwarn("chmod: %s", name); if (chflags(name, fs->st_flags) && errno != EOPNOTSUPP) cwarn("chflags: %s", name); }
static int process_utimes(const char *path, struct timespec *at, struct timespec *mt, struct timespec *ct, void *user) { int ret = 0; struct btrfs_receive *r = user; char full_path[PATH_MAX]; struct timespec tv[2]; ret = path_cat_out(full_path, r->full_subvol_path, path); if (ret < 0) { error("utimes: path invalid: %s", path); goto out; } if (g_verbose >= 2) fprintf(stderr, "utimes %s\n", path); tv[0] = *at; tv[1] = *mt; ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW); if (ret < 0) { ret = -errno; error("utimes %s failed: %s", path, strerror(-ret)); goto out; } out: return ret; }
int serv_touch(char *arg) { char corr[40]; if (!arg || !arg[0]) return serv_list(NULL); if (!strstr(arg, ".conf")) { snprintf(corr, sizeof(corr), "%s.conf", arg); arg = corr; } pushd(FINIT_RCSD); if (!fexist(arg)) { popd(); if (!strstr(arg, "finit.conf")) errx(1, "Service %s is not enabled", arg); arg = FINIT_CONF; } /* libite:touch() follows symlinks */ if (utimensat(AT_FDCWD, arg, NULL, AT_SYMLINK_NOFOLLOW)) err(1, "Failed marking %s for reload", arg); return 0; }
void sys_stat_check_functions() { (void)chmod((const char *)1234, (mode_t)0); (void)fchmod(0, (mode_t)0); #if HAVE_XXXAT (void)fchmodat(0, (const char *)1234, (mode_t)0, 0); #endif (void)fstat(0, (struct stat *)1234); #if HAVE_XXXAT (void)fstatat(0, (const char *)1234, (struct stat *)1234, 0); #endif (void)futimens(0, (const struct timespec *)1234); (void)lstat((const char *)1234, (struct stat *)1234); (void)mkdir((const char *)1234, (mode_t)0); #if HAVE_XXXAT (void)mkdirat(0, (const char *)1234, (mode_t)0); #endif (void)mkfifo((const char *)1234, (mode_t)0); (void)mkfifoat(0, (const char *)1234, (mode_t)0); (void)mknod((const char *)1234, (mode_t)0, (dev_t)0); (void)mknodat(0, (const char *)1234, (mode_t)0, (dev_t)0); (void)stat((const char *)1234, (struct stat *)1234); (void)umask((mode_t)0); (void)utimensat(0, (const char *)1234, (const struct timespec *)1234, 0); }
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 int apply_timestamp(const char *path, struct timespec *ts) { struct timespec twice[2] = { *ts, *ts }; struct stat st; assert(path); assert(ts); if (stat(path, &st) >= 0) { /* Is the timestamp file already newer than the OS? If * so, there's nothing to do. We ignore the nanosecond * component of the timestamp, since some file systems * do not support any better accuracy than 1s and we * have no way to identify the accuracy * available. Most notably ext4 on small disks (where * 128 byte inodes are used) does not support better * accuracy than 1s. */ if (st.st_mtim.tv_sec > ts->tv_sec) return 0; /* It is older? Then let's update it */ if (utimensat(AT_FDCWD, path, twice, AT_SYMLINK_NOFOLLOW) < 0) { if (errno == EROFS) return log_debug("Can't update timestamp file %s, file system is read-only.", path); return log_error_errno(errno, "Failed to update timestamp on %s: %m", path); } } else if (errno == ENOENT) { _cleanup_close_ int fd = -1; int r; /* The timestamp file doesn't exist yet? Then let's create it. */ r = mac_selinux_create_file_prepare(path, S_IFREG); if (r < 0) return log_error_errno(r, "Failed to set SELinux context for %s: %m", path); fd = open(path, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644); mac_selinux_create_file_clear(); if (fd < 0) { if (errno == EROFS) return log_debug("Can't create timestamp file %s, file system is read-only.", path); return log_error_errno(errno, "Failed to create timestamp file %s: %m", path); } (void) loop_write(fd, MESSAGE, strlen(MESSAGE), false); if (futimens(fd, twice) < 0) return log_error_errno(errno, "Failed to update timestamp on %s: %m", path); } else log_error_errno(errno, "Failed to stat() timestamp file %s: %m", path); return 0; }
/* * Check if @path is on read-only filesystem independently on file permissions. */ int mnt_is_readonly(const char *path) { if (access(path, W_OK) == 0) return 0; if (errno == EROFS) return 1; if (errno != EACCES) return 0; #ifdef HAVE_FUTIMENS /* * access(2) returns EACCES on read-only FS: * * - for set-uid application if one component of the path is not * accessible for the current rUID. (Note that euidaccess(2) does not * check for EROFS at all). * * - for read-write filesystem with read-only VFS node (aka -o remount,ro,bind) */ { struct timespec times[2]; times[0].tv_nsec = UTIME_NOW; /* atime */ times[1].tv_nsec = UTIME_OMIT; /* mtime */ if (utimensat(AT_FDCWD, path, times, 0) == -1) return errno == EROFS; } #endif return 0; }
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 }
/* SELinux uses PCRE pre-compiled regexps for binary caches, which can * fail if the version of PCRE on the host differs from the version * which generated the cache (in the target root). * * Note also this function is probably already broken in Fedora * 23+ from https://bugzilla.redhat.com/show_bug.cgi?id=1265406 */ static gboolean workaround_selinux_cross_labeling_recurse (int dfd, const char *path, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; if (!glnx_dirfd_iterator_init_at (dfd, path, TRUE, &dfd_iter, error)) goto out; while (TRUE) { struct dirent *dent = NULL; const char *name; if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) goto out; if (!dent) break; name = dent->d_name; if (dent->d_type == DT_DIR) { if (!workaround_selinux_cross_labeling_recurse (dfd_iter.fd, name, cancellable, error)) goto out; } else if (g_str_has_suffix (name, ".bin")) { struct stat stbuf; const char *lastdot; gs_free char *nonbin_name = NULL; if (TEMP_FAILURE_RETRY (fstatat (dfd_iter.fd, name, &stbuf, AT_SYMLINK_NOFOLLOW)) != 0) { glnx_set_error_from_errno (error); goto out; } lastdot = strrchr (name, '.'); g_assert (lastdot); nonbin_name = g_strndup (name, lastdot - name); g_print ("Setting mtime of '%s' to newer than '%s'\n", nonbin_name, name); if (TEMP_FAILURE_RETRY (utimensat (dfd_iter.fd, nonbin_name, NULL, 0)) == -1) { glnx_set_error_from_errno (error); goto out; } } } ret = TRUE; out: return ret; }
static void touch(const char *file) { int fd; struct stat st; int r; if ((r = stat(file, &st)) < 0) { if (errno != ENOENT) eprintf("stat %s:", file); if (cflag) return; } else if (!r) { if (!aflag) times[0] = st.st_atim; if (!mflag) times[1] = st.st_mtim; if (utimensat(AT_FDCWD, file, times, 0) < 0) eprintf("utimensat %s:", file); return; } if ((fd = open(file, O_CREAT | O_EXCL, 0644)) < 0) eprintf("open %s:", file); close(fd); touch(file); }
static int process_utimes(const char *path, struct timespec *at, struct timespec *mt, struct timespec *ct, void *user) { int ret = 0; struct btrfs_receive *r = user; char *full_path = path_cat(r->full_subvol_path, path); struct timespec tv[2]; if (g_verbose >= 2) fprintf(stderr, "utimes %s\n", path); tv[0] = *at; tv[1] = *mt; ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW); if (ret < 0) { ret = -errno; fprintf(stderr, "ERROR: utimes %s failed. %s\n", path, strerror(-ret)); goto out; } out: free(full_path); return ret; }
void set_ftime(char *fnm, time_t mtime, time_t atime, int frc) { struct timespec tv[2]; tv[0].tv_sec = atime; tv[0].tv_nsec = 0L; tv[1].tv_sec = mtime; tv[1].tv_nsec = 0L; if (!frc) { /* * if we are not forcing, only set those times the user wants * set. */ if (!patime) tv[0].tv_nsec = UTIME_OMIT; if (!pmtime) tv[1].tv_nsec = UTIME_OMIT; } /* * set the times */ if (utimensat(AT_FDCWD, fnm, tv, AT_SYMLINK_NOFOLLOW) < 0) syswarn(1, errno, "Access/modification time set failed on: %s", fnm); }
/** * mbox_path_probe - Is this an mbox mailbox? - Implements MxOps::path_probe() */ enum MailboxType mbox_path_probe(const char *path, const struct stat *st) { if (!path || !st) return MUTT_UNKNOWN; if (S_ISDIR(st->st_mode)) return MUTT_UNKNOWN; if (st->st_size == 0) return MUTT_MBOX; FILE *fp = fopen(path, "r"); if (!fp) return MUTT_UNKNOWN; int ch; while ((ch = fgetc(fp)) != EOF) { /* Some mailbox creation tools erroneously append a blank line to * a file before appending a mail message. This allows neomutt to * detect magic for and thus open those files. */ if ((ch != '\n') && (ch != '\r')) { ungetc(ch, fp); break; } } enum MailboxType magic = MUTT_UNKNOWN; char tmp[256]; if (fgets(tmp, sizeof(tmp), fp)) { if (mutt_str_startswith(tmp, "From ", CASE_MATCH)) magic = MUTT_MBOX; else if (mutt_str_strcmp(tmp, MMDF_SEP) == 0) magic = MUTT_MMDF; } mutt_file_fclose(&fp); if (!C_CheckMboxSize) { /* need to restore the times here, the file was not really accessed, * only the type was accessed. This is important, because detection * of "new mail" depends on those times set correctly. */ #ifdef HAVE_UTIMENSAT struct timespec ts[2]; mutt_file_get_stat_timespec(&ts[0], &st, MUTT_STAT_ATIME); mutt_file_get_stat_timespec(&ts[1], &st, MUTT_STAT_MTIME); utimensat(0, path, ts, 0); #else struct utimbuf times; times.actime = st->st_atime; times.modtime = st->st_mtime; utime(path, ×); #endif } return magic; }
int stream_utimens(const char *path, const struct timespec tv[2]) { int rc; drop_privilege(); rc = (utimensat(-1, fixpath(path), tv, 0)) ? -errno : 0; regain_privilege(); return rc; }
int main(void) { static const char fname[] = "utimensat\nfilename"; assert(utimensat(AT_FDCWD, fname, NULL, 0) == -1); if (ENOENT != errno) error_msg_and_skip("utimensat"); #define PREFIX "utimensat(AT_FDCWD, \"utimensat\\nfilename\", " printf(PREFIX "NULL, 0) = -1 ENOENT (%m)\n"); struct timeval tv; struct timespec ts[2]; if (gettimeofday(&tv, NULL)) perror_msg_and_skip("gettimeofday"); ts[0].tv_sec = tv.tv_sec; ts[0].tv_nsec = tv.tv_usec; ts[1].tv_sec = tv.tv_sec - 1; ts[1].tv_nsec = tv.tv_usec + 1; printf(PREFIX "["); print_ts(&ts[0]); printf(", "); print_ts(&ts[1]); printf("], AT_SYMLINK_NOFOLLOW) = -1 ENOENT "); assert(utimensat(AT_FDCWD, fname, ts, AT_SYMLINK_NOFOLLOW) == -1); if (ENOENT != errno) error_msg_and_skip("utimensat"); printf("(%m)\n"); ts[0].tv_nsec = UTIME_NOW; ts[1].tv_nsec = UTIME_OMIT; assert(utimensat(AT_FDCWD, fname, ts, AT_SYMLINK_NOFOLLOW) == -1); if (ENOENT != errno) error_msg_and_skip("utimensat"); printf(PREFIX "[UTIME_NOW, UTIME_OMIT], AT_SYMLINK_NOFOLLOW)" " = -1 ENOENT (%m)\n"); puts("+++ exited with 0 +++"); return 0; }
static int xmp_utimens(const char *path, const struct timespec ts[2]) { int res; /* don't use utime/utimes since they follow symlinks */ res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); if (res == -1) return -errno; return 0; }
int lutimes(const char *filename, const struct timeval tv[2]) { struct timespec times[2]; times[0].tv_sec = tv[0].tv_sec; times[0].tv_nsec = tv[0].tv_usec * 1000; times[1].tv_sec = tv[1].tv_sec; times[1].tv_nsec = tv[1].tv_usec * 1000; return utimensat(AT_FDCWD, filename, times, AT_SYMLINK_NOFOLLOW); }
ATF_TC_BODY(utimensat_fderr1, tc) { int dfd; ATF_REQUIRE(mkdir(DIR, 0755) == 0); ATF_REQUIRE((dfd = open(DIR, O_RDONLY, 0)) != -1); ATF_REQUIRE(utimensat(dfd, FILEERR, tptr, 0) == -1); ATF_REQUIRE(close(dfd) == 0); }
static int apply_timestamp(const char *path, struct timespec *ts) { struct timespec twice[2]; struct stat st; assert(path); assert(ts); if (stat(path, &st) >= 0) { /* Is the timestamp file already newer than the OS? If so, there's nothing to do. */ if (st.st_mtim.tv_sec > ts->tv_sec || (st.st_mtim.tv_sec == ts->tv_sec && st.st_mtim.tv_nsec >= ts->tv_nsec)) return 0; /* It is older? Then let's update it */ twice[0] = *ts; twice[1] = *ts; if (utimensat(AT_FDCWD, path, twice, AT_SYMLINK_NOFOLLOW) < 0) { if (errno == EROFS) return log_debug("Can't update timestamp file %s, file system is read-only.", path); return log_error_errno(errno, "Failed to update timestamp on %s: %m", path); } } else if (errno == ENOENT) { _cleanup_close_ int fd = -1; int r; /* The timestamp file doesn't exist yet? Then let's create it. */ r = mac_selinux_create_file_prepare(path, S_IFREG); if (r < 0) return log_error_errno(r, "Failed to set SELinux context for %s: %m", path); fd = open(path, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644); mac_selinux_create_file_clear(); if (fd < 0) { if (errno == EROFS) return log_debug("Can't create timestamp file %s, file system is read-only.", path); return log_error_errno(errno, "Failed to create timestamp file %s: %m", path); } (void) loop_write(fd, MESSAGE, strlen(MESSAGE), false); twice[0] = *ts; twice[1] = *ts; if (futimens(fd, twice) < 0) return log_error_errno(errno, "Failed to update timestamp on %s: %m", path); } else log_error_errno(errno, "Failed to stat() timestamp file %s: %m", path); return 0; }
static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler, const struct fuse_in_header *hdr, const struct fuse_setattr_in *req) { struct node* node; char path[PATH_MAX]; struct timespec times[2]; pthread_mutex_lock(&fuse->lock); node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path)); TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token, req->fh, req->valid, hdr->nodeid, node ? node->name : "?"); pthread_mutex_unlock(&fuse->lock); if (!node) { return -ENOENT; } /* XXX: incomplete implementation on purpose. * chmod/chown should NEVER be implemented.*/ if ((req->valid & FATTR_SIZE) && truncate(path, req->size) < 0) { return -errno; } /* Handle changing atime and mtime. If FATTR_ATIME_and FATTR_ATIME_NOW * are both set, then set it to the current time. Else, set it to the * time specified in the request. Same goes for mtime. Use utimensat(2) * as it allows ATIME and MTIME to be changed independently, and has * nanosecond resolution which fuse also has. */ if (req->valid & (FATTR_ATIME | FATTR_MTIME)) { times[0].tv_nsec = UTIME_OMIT; times[1].tv_nsec = UTIME_OMIT; if (req->valid & FATTR_ATIME) { if (req->valid & FATTR_ATIME_NOW) { times[0].tv_nsec = UTIME_NOW; } else { times[0].tv_sec = req->atime; times[0].tv_nsec = req->atimensec; } } if (req->valid & FATTR_MTIME) { if (req->valid & FATTR_MTIME_NOW) { times[1].tv_nsec = UTIME_NOW; } else { times[1].tv_sec = req->mtime; times[1].tv_nsec = req->mtimensec; } } TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n", handler->token, path, times[0].tv_sec, times[1].tv_sec); if (utimensat(-1, path, times, 0) < 0) { return -errno; } } return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path); }
ATF_TC_BODY(utimensat_fderr3, tc) { int fd; ATF_REQUIRE(mkdir(DIR, 0755) == 0); ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); ATF_REQUIRE(close(fd) == 0); ATF_REQUIRE(utimensat(-1, FILE, tptr, 0) == -1); }
static int pifs_utimens(const char *path, const struct timespec times[2]) { DIR *dir = opendir(options.mdd); if (!dir) { return -errno; } int ret = utimensat(dirfd(dir), basename((char *) path), times, 0); closedir(dir); return ret == -1 ? -errno : ret; }
/* * TODO: To simplify things, we're mandating absolute paths. We should * probably properly handle relative paths for this later and remove this * restriction. Given this, the first argument to utimensat() is ignored. */ static int bru_utimens(const char *path, const struct timespec *times) { SET_CALLER_UID(); REDIR_PATH(path, new_path); int ret = utimensat(0, new_path, times, AT_SYMLINK_NOFOLLOW); SET_RET_ERRNO(); return ret; }
static int xmp_utimens(const char *path, const struct timespec ts[2]) { fprintf(f, "utimes path: %s\n", path); int res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); if (res == -1){ fprintf(f, "operation failed\n"); return -errno; } fprintf(f, "operation succeeded\n"); return 0; }
static int copyat(int olddirfd, const char* oldpath, int newdirfd, const char* newpath) { int err; int oldfd = openat(olddirfd, oldpath, O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NOATIME); if (oldfd == -1 && errno == EPERM) { oldfd = openat(olddirfd, oldpath, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); } if (oldfd == -1 && errno == ELOOP) { char oldtarget[PATH_MAX]; ssize_t oldlen = readlinkat(olddirfd, oldpath, oldtarget, sizeof(oldtarget)); if (oldlen == -1) { return -1; } oldtarget[oldlen] = '\0'; return symlinkat(oldtarget, newdirfd, newpath); } if (oldfd == -1) { return -1; } struct stat oldstat; if (fstat(oldfd, &oldstat) == -1) { err = errno; close(oldfd); errno = err; return -1; } int newfd = openat(newdirfd, newpath, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC | O_NOATIME, oldstat.st_mode); if (newfd == -1 && errno == EPERM) { newfd = openat(newdirfd, newpath, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC, oldstat.st_mode); } if (newfd == -1) { err = errno; close(oldfd); errno = err; return -1; } if (fchown(newfd, oldstat.st_uid, oldstat.st_gid) == -1) { // ignore error } if (copyfile_sparse(oldfd, newfd) == -1) { err = errno; close(newfd); close(oldfd); errno = err; return -1; } close(newfd); close(oldfd); struct timespec times[2]; times[0] = oldstat.st_atim; times[1] = oldstat.st_mtim; utimensat(newdirfd, newpath, times, 0); // ignore error return 0; }
int utimes(const char* path, const struct timeval tv[2]) { struct timespec ts[2]; struct timespec* ts_ptr = NULL; if (tv != NULL) { if (!timespec_from_timeval(&ts[0], &tv[0]) || !timespec_from_timeval(&ts[1], &tv[1])) { errno = EINVAL; return -1; } ts_ptr = ts; } return utimensat(AT_FDCWD, path, ts_ptr, 0); }
int setfile(struct stat *fs, int fd) { struct timespec ts[2]; int rval; rval = 0; fs->st_mode &= S_ISTXT | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; ts[0] = fs->st_atim; ts[1] = fs->st_mtim; if (fd >= 0 ? futimens(fd, ts) : utimensat(AT_FDCWD, to.p_path, ts, AT_SYMLINK_NOFOLLOW)) { warn("update times: %s", to.p_path); rval = 1; } /* * 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 (fd >= 0 ? fchown(fd, fs->st_uid, fs->st_gid) : lchown(to.p_path, fs->st_uid, fs->st_gid)) { if (errno != EPERM) { warn("chown: %s", to.p_path); rval = 1; } fs->st_mode &= ~(S_ISTXT | S_ISUID | S_ISGID); } if (fd >= 0 ? fchmod(fd, fs->st_mode) : fchmodat(AT_FDCWD, to.p_path, fs->st_mode, AT_SYMLINK_NOFOLLOW)) { warn("chmod: %s", to.p_path); rval = 1; } /* * XXX * NFS doesn't support chflags; ignore errors unless there's reason * to believe we're losing bits. (Note, this still won't be right * if the server supports flags and we were trying to *remove* flags * on a file that we copied, i.e., that we didn't create.) */ errno = 0; if (fd >= 0 ? fchflags(fd, fs->st_flags) : chflagsat(AT_FDCWD, to.p_path, fs->st_flags, AT_SYMLINK_NOFOLLOW)) if (errno != EOPNOTSUPP || fs->st_flags != 0) { warn("chflags: %s", to.p_path); rval = 1; } return (rval); }
int main (void) { #if defined(HAVE_SIGNALFD) && defined(HAVE_EVENTFD) \ && defined(HAVE_EVENTFD_READ) && defined(HAVE_PPOLL) { sigset_t mask; int fd, fd2; eventfd_t ev; struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; struct pollfd pfd[2]; sigemptyset (&mask); sigaddset (&mask, SIGUSR1); fd = signalfd (-1, &mask, 0); sigaddset (&mask, SIGUSR2); fd = signalfd (fd, &mask, 0); fd2 = eventfd (5, 0); eventfd_read (fd2, &ev); pfd[0].fd = fd; pfd[0].events = POLLIN|POLLOUT; pfd[1].fd = fd2; pfd[1].events = POLLIN|POLLOUT; ppoll (pfd, 2, &ts, &mask); } #endif #if defined(HAVE_UTIMENSAT) unlink("/tmp/valgrind-utimensat-test"); close (creat ("/tmp/valgrind-utimensat-test", S_IRUSR | S_IWUSR)); { struct timespec ts2[2] = { [0].tv_sec = 10000000, [1].tv_sec = 20000000 }; utimensat (AT_FDCWD, "/tmp/valgrind-utimensat-test", ts2, 0); } unlink("/tmp/valgrind-utimensat-test"); #endif #if defined(HAVE_EPOLL_CREATE) && defined(HAVE_EPOLL_PWAIT) { int fd3; struct epoll_event evs[10]; sigset_t mask; sigemptyset (&mask); sigaddset (&mask, SIGUSR1); sigaddset (&mask, SIGUSR2); fd3 = epoll_create (10); epoll_pwait (fd3, evs, 10, 0, &mask); } #endif return 0; }
ATF_TC_BODY(utimensat_fdlink, tc) { int dfd; struct stat st; ATF_REQUIRE(mkdir(DIR, 0755) == 0); ATF_REQUIRE(symlink(FILE, LINK) == 0); /* NB: FILE does not exists */ ATF_REQUIRE((dfd = open(DIR, O_RDONLY, 0)) != -1); ATF_REQUIRE(utimensat(dfd, BASELINK, tptr, 0) == -1); ATF_REQUIRE(errno = ENOENT); ATF_REQUIRE(utimensat(dfd, BASELINK, tptr, AT_SYMLINK_NOFOLLOW) == 0); ATF_REQUIRE(close(dfd) == 0); ATF_REQUIRE(lstat(LINK, &st) == 0); ATF_REQUIRE(st.st_atimespec.tv_sec == tptr[0].tv_sec); ATF_REQUIRE(st.st_atimespec.tv_nsec == tptr[0].tv_nsec); ATF_REQUIRE(st.st_mtimespec.tv_sec == tptr[1].tv_sec); ATF_REQUIRE(st.st_mtimespec.tv_nsec == tptr[1].tv_nsec); }
int utimesys(int code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) { switch (code) { case 0: return (futimens((int)arg1, (timespec_t *)arg2)); case 1: return (utimensat((int)arg1, (char *)arg2, (timespec_t *)arg3, (int)arg4)); default: return (set_errno(EINVAL)); } }