--- ntfs-3g-2009.11.14AC.2/configure.ac 2009-12-16 08:33:26.000000000 +0100 +++ ntfslow/configure.ac 2009-12-23 10:24:29.000000000 +0100 @@ -314,7 +314,7 @@ atexit basename daemon dup2 fdatasync ffs getopt_long hasmntopt \ mbsinit memmove memset realpath regcomp setlocale setxattr \ strcasecmp strchr strdup strerror strnlen strsep strtol strtoul \ - sysconf utime fork \ + sysconf utime utimensat fork \ ]) AC_SYS_LARGEFILE --- ntfs-3g-2009.11.14AC.2/src/lowntfs-3g.c 2009-12-19 09:58:22.000000000 +0100 +++ ntfslow/src/lowntfs-3g.c 2009-12-23 15:06:14.000000000 +0100 @@ -1527,8 +1527,54 @@ return res; } +#ifdef HAVE_UTIMENSAT + +static int ntfs_fuse_utimens(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, + struct stat *stin, struct stat *stbuf, int to_set) +{ + ntfs_inode *ni; + int res = 0; + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) + return -errno; + + /* no check or update if both UTIME_OMIT */ + if (to_set & (FUSE_SET_ATTR_ATIME + FUSE_SET_ATTR_MTIME)) { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + if (ntfs_allowed_access(scx, ni, S_IWRITE) + || ((to_set & FUSE_SET_ATTR_ATIME_NOW) + && (to_set & FUSE_SET_ATTR_MTIME_NOW) + && ntfs_allowed_as_owner(scx, ni))) { +#endif + ntfs_time_update_flags mask = NTFS_UPDATE_CTIME; + + if (to_set & FUSE_SET_ATTR_ATIME_NOW) + mask |= NTFS_UPDATE_ATIME; + else + if (to_set & FUSE_SET_ATTR_ATIME) + ni->last_access_time = stin->st_atime; + if (to_set & FUSE_SET_ATTR_MTIME_NOW) + mask |= NTFS_UPDATE_MTIME; + else + if (to_set & FUSE_SET_ATTR_MTIME) + ni->last_data_change_time = stin->st_mtime;; + ntfs_inode_update_times(ni, mask); +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + } else + res = -errno; +#endif + } + res = ntfs_fuse_getstat(scx, ni, stbuf); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +#else /* HAVE_UTIMENSAT */ + static int ntfs_fuse_utime(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, - struct stat *stin, struct stat *stbuf) + struct stat *stin, struct stat *stbuf, int to_set) { ntfs_inode *ni; int res = 0; @@ -1586,6 +1632,8 @@ return res; } +#endif /* HAVE_UTIMENSAT */ + static void ntfs_fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi __attribute__((unused))) { @@ -1594,13 +1642,14 @@ int res; struct SECURITY_CONTEXT security; + res = 0; ntfs_fuse_fill_security_context(req, &security); - switch (to_set + /* no flags */ + if (!(to_set & (FUSE_SET_ATTR_MODE | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID | FUSE_SET_ATTR_SIZE - | FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) { - case 0 : + | FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) { ni = ntfs_inode_open(ctx->vol, INODE(ino)); if (!ni) res = -errno; @@ -1609,46 +1658,60 @@ if (ntfs_inode_close(ni)) set_fuse_error(&res); } - break; - case FUSE_SET_ATTR_MODE : - res = ntfs_fuse_chmod(&security, ino, attr->st_mode & 07777, - &stbuf); - break; - case FUSE_SET_ATTR_UID : - res = ntfs_fuse_chown(&security, ino, attr->st_uid, - (gid_t)-1, &stbuf); - break; - case FUSE_SET_ATTR_GID : - res = ntfs_fuse_chown(&security, ino, (uid_t)-1, - attr->st_gid, &stbuf); - break; - case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_GID : - res = ntfs_fuse_chown(&security, ino, attr->st_uid, - attr->st_gid, &stbuf); - break; - case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_MODE: - res = ntfs_fuse_chownmod(&security, ino, attr->st_uid, - (gid_t)-1,attr->st_mode, &stbuf); - break; - case FUSE_SET_ATTR_GID + FUSE_SET_ATTR_MODE: - res = ntfs_fuse_chownmod(&security, ino, (uid_t)-1, - attr->st_gid,attr->st_mode, &stbuf); - break; - case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_GID + FUSE_SET_ATTR_MODE: - res = ntfs_fuse_chownmod(&security, ino, attr->st_uid, + } + /* some set of uid/gid/mode */ + if (to_set + & (FUSE_SET_ATTR_MODE + | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) { + switch (to_set + & (FUSE_SET_ATTR_MODE + | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) { + case FUSE_SET_ATTR_MODE : + res = ntfs_fuse_chmod(&security, ino, + attr->st_mode & 07777, &stbuf); + break; + case FUSE_SET_ATTR_UID : + res = ntfs_fuse_chown(&security, ino, attr->st_uid, + (gid_t)-1, &stbuf); + break; + case FUSE_SET_ATTR_GID : + res = ntfs_fuse_chown(&security, ino, (uid_t)-1, + attr->st_gid, &stbuf); + break; + case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_GID : + res = ntfs_fuse_chown(&security, ino, attr->st_uid, + attr->st_gid, &stbuf); + break; + case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_MODE: + res = ntfs_fuse_chownmod(&security, ino, attr->st_uid, + (gid_t)-1,attr->st_mode, + &stbuf); + break; + case FUSE_SET_ATTR_GID + FUSE_SET_ATTR_MODE: + res = ntfs_fuse_chownmod(&security, ino, (uid_t)-1, + attr->st_gid,attr->st_mode, + &stbuf); + break; + case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_GID + FUSE_SET_ATTR_MODE: + res = ntfs_fuse_chownmod(&security, ino, attr->st_uid, attr->st_gid,attr->st_mode, &stbuf); - break; - case FUSE_SET_ATTR_SIZE : + break; + default : + break; + } + } + /* size */ + if (!res && (to_set & FUSE_SET_ATTR_SIZE)) { res = ntfs_fuse_trunc(&security, ino, attr->st_size, !fi, &stbuf); - break; - case FUSE_SET_ATTR_ATIME + FUSE_SET_ATTR_MTIME : + } + /* some set of atime/mtime */ + if (!res && (to_set & (FUSE_SET_ATTR_ATIME + FUSE_SET_ATTR_MTIME))) { +#ifdef HAVE_UTIMENSAT + res = ntfs_fuse_utimens(&security, ino, attr, &stbuf, to_set); +#else /* HAVE_UTIMENSAT */ res = ntfs_fuse_utime(&security, ino, attr, &stbuf); - break; - default: - ntfs_log_error("Unsupported setattr mode 0x%x\n",(int)to_set); - res = -EOPNOTSUPP; - break; +#endif /* HAVE_UTIMENSAT */ } if (res) fuse_reply_err(req, -res);