Re: [fuse-devel] utimensat fails to update ctime

From: Jean-Pierre André
Date: Wed Dec 23 2009 - 09:29:10 EST


Hi,

OGAWA Hirofumi wrote:
I suggest I port Miklos patch to fuse-lite soon,
and delay the low-level case (and microsecond
precision) until January. Does that suit your needs ?
Thanks. Sounds good. I'm not using ntfs-3g actually, I just bridged the
bug report on lkml to others. Eric?

As my Christmas present to any real non-bridging
user, here is, ahead of schedule, the patch for the
low level fuse interface of ntfs-3g.

The good news is that for this interface, no update
of fuse is needed. So there is no compilation issue with
unpatched versions of fuse, and the attached patch
is independent of the one for the high-level interface
posted previously, except for the configuration.ac file
for which I duplicate the patch.

Regards

Jean-Pierre



--- 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);