mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 10:04:00 +08:00
Developed selective timestamp setting for utimensat(2)
This commit is contained in:
parent
b8a83add46
commit
17a629229d
@ -313,7 +313,7 @@ AC_CHECK_FUNCS([ \
|
||||
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
|
||||
|
||||
|
@ -67,7 +67,23 @@ typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
|
||||
* Changed in fuse 2.8.0 (regardless of API version)
|
||||
* Previously, paths were limited to a length of PATH_MAX.
|
||||
*/
|
||||
|
||||
#define HAS_UTIME_OMIT_OK 1
|
||||
|
||||
struct fuse_operations {
|
||||
unsigned int flag_nullpath_ok : 1;
|
||||
|
||||
/**
|
||||
* Flag indicating that the filesystem accepts special
|
||||
* UTIME_NOW and UTIME_OMIT values in its utimens operation.
|
||||
*/
|
||||
unsigned int flag_utime_omit_ok : 1;
|
||||
|
||||
/**
|
||||
* Reserved flags, don't set
|
||||
*/
|
||||
unsigned int flag_reserved : 30;
|
||||
|
||||
/** Get file attributes.
|
||||
*
|
||||
* Similar to stat(). The 'st_dev' and 'st_blksize' fields are
|
||||
|
@ -114,6 +114,8 @@ struct fuse_ctx {
|
||||
#define FUSE_SET_ATTR_SIZE (1 << 3)
|
||||
#define FUSE_SET_ATTR_ATIME (1 << 4)
|
||||
#define FUSE_SET_ATTR_MTIME (1 << 5)
|
||||
#define FUSE_SET_ATTR_ATIME_NOW (1 << 7)
|
||||
#define FUSE_SET_ATTR_MTIME_NOW (1 << 8)
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* Request methods and replies *
|
||||
|
@ -75,6 +75,7 @@ struct fuse {
|
||||
struct fuse_config conf;
|
||||
int intr_installed;
|
||||
struct fuse_fs *fs;
|
||||
int utime_omit_ok;
|
||||
};
|
||||
|
||||
struct lock {
|
||||
@ -1187,6 +1188,29 @@ static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
|
||||
else
|
||||
err = fuse_fs_truncate(f->fs, path, attr->st_size);
|
||||
}
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
if (!err && f->utime_omit_ok &&
|
||||
(valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) {
|
||||
struct timespec tv[2];
|
||||
|
||||
tv[0].tv_sec = 0;
|
||||
tv[1].tv_sec = 0;
|
||||
tv[0].tv_nsec = UTIME_OMIT;
|
||||
tv[1].tv_nsec = UTIME_OMIT;
|
||||
|
||||
if (valid & FUSE_SET_ATTR_ATIME_NOW)
|
||||
tv[0].tv_nsec = UTIME_NOW;
|
||||
else if (valid & FUSE_SET_ATTR_ATIME)
|
||||
tv[0] = attr->st_atim;
|
||||
|
||||
if (valid & FUSE_SET_ATTR_MTIME_NOW)
|
||||
tv[1].tv_nsec = UTIME_NOW;
|
||||
else if (valid & FUSE_SET_ATTR_MTIME)
|
||||
tv[1] = attr->st_mtim;
|
||||
|
||||
err = fuse_fs_utimens(f->fs, path, tv);
|
||||
} else
|
||||
#endif
|
||||
if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
|
||||
(FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
|
||||
struct timespec tv[2];
|
||||
@ -2606,6 +2630,7 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
|
||||
goto out_free;
|
||||
|
||||
f->fs = fs;
|
||||
f->utime_omit_ok = fs->op.flag_utime_omit_ok;
|
||||
|
||||
/* Oh f**k, this is ugly! */
|
||||
if (!fs->op.lock) {
|
||||
@ -2639,6 +2664,8 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
|
||||
|
||||
fuse_session_add_chan(f->se, ch);
|
||||
|
||||
if (f->conf.debug)
|
||||
fprintf(stderr, "utime_omit_ok: %i\n", f->utime_omit_ok);
|
||||
f->ctr = 0;
|
||||
f->generation = 0;
|
||||
/* FIXME: Dynamic hash table */
|
||||
|
@ -2185,6 +2185,63 @@ static int ntfs_fuse_rmdir(const char *path)
|
||||
return ntfs_fuse_rm(path);
|
||||
}
|
||||
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
|
||||
static int ntfs_fuse_utimens(const char *path, const struct timespec tv[2])
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
int res = 0;
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
struct SECURITY_CONTEXT security;
|
||||
#endif
|
||||
|
||||
if (ntfs_fuse_is_named_data_stream(path))
|
||||
return -EINVAL; /* n/a for named data streams. */
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
/* parent directory must be executable */
|
||||
if (ntfs_fuse_fill_security_context(&security)
|
||||
&& !ntfs_allowed_dir_access(&security,path,
|
||||
(ntfs_inode*)NULL,(ntfs_inode*)NULL,S_IEXEC)) {
|
||||
return (-errno);
|
||||
}
|
||||
#endif
|
||||
ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
|
||||
if (!ni)
|
||||
return -errno;
|
||||
|
||||
/* no check or update if both UTIME_OMIT */
|
||||
if ((tv[0].tv_nsec != UTIME_OMIT) || (tv[1].tv_nsec != UTIME_OMIT)) {
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
if (ntfs_allowed_access(&security, ni, S_IWRITE)
|
||||
|| ((tv[0].tv_nsec == UTIME_NOW)
|
||||
&& (tv[0].tv_nsec == UTIME_NOW)
|
||||
&& ntfs_allowed_as_owner(&security, ni))) {
|
||||
#endif
|
||||
ntfs_time_update_flags mask = NTFS_UPDATE_CTIME;
|
||||
|
||||
if (tv[0].tv_nsec == UTIME_NOW)
|
||||
mask |= NTFS_UPDATE_ATIME;
|
||||
else
|
||||
if (tv[0].tv_nsec != UTIME_OMIT)
|
||||
ni->last_access_time = tv[0].tv_sec;
|
||||
if (tv[1].tv_nsec == UTIME_NOW)
|
||||
mask |= NTFS_UPDATE_MTIME;
|
||||
else
|
||||
if (tv[1].tv_nsec != UTIME_OMIT)
|
||||
ni->last_data_change_time = tv[1].tv_sec;
|
||||
ntfs_inode_update_times(ni, mask);
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
} else
|
||||
res = -errno;
|
||||
#endif
|
||||
}
|
||||
if (ntfs_inode_close(ni))
|
||||
set_fuse_error(&res);
|
||||
return res;
|
||||
}
|
||||
|
||||
#else /* HAVE_UTIMENSAT */
|
||||
|
||||
static int ntfs_fuse_utime(const char *path, struct utimbuf *buf)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
@ -2252,6 +2309,8 @@ static int ntfs_fuse_utime(const char *path, struct utimbuf *buf)
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* HAVE_UTIMENSAT */
|
||||
|
||||
static int ntfs_fuse_bmap(const char *path, size_t blocksize, uint64_t *idx)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
@ -3386,6 +3445,9 @@ static void ntfs_fuse_destroy2(void *unused __attribute__((unused)))
|
||||
}
|
||||
|
||||
static struct fuse_operations ntfs_3g_ops = {
|
||||
#if defined(HAVE_UTIMENSAT) && defined(HAS_UTIME_OMIT_OK)
|
||||
.flag_utime_omit_ok = 1, /* accept UTIME_NOW and UTIME_OMIT in utimens */
|
||||
#endif
|
||||
.getattr = ntfs_fuse_getattr,
|
||||
.readlink = ntfs_fuse_readlink,
|
||||
.readdir = ntfs_fuse_readdir,
|
||||
@ -3406,7 +3468,11 @@ static struct fuse_operations ntfs_3g_ops = {
|
||||
.rename = ntfs_fuse_rename,
|
||||
.mkdir = ntfs_fuse_mkdir,
|
||||
.rmdir = ntfs_fuse_rmdir,
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
.utimens = ntfs_fuse_utimens,
|
||||
#else
|
||||
.utime = ntfs_fuse_utime,
|
||||
#endif
|
||||
.bmap = ntfs_fuse_bmap,
|
||||
.destroy = ntfs_fuse_destroy2,
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
|
Loading…
Reference in New Issue
Block a user