diff --git a/include/ntfs-3g/inode.h b/include/ntfs-3g/inode.h index b9467463..1fc4d79f 100644 --- a/include/ntfs-3g/inode.h +++ b/include/ntfs-3g/inode.h @@ -48,8 +48,6 @@ typedef enum { mft record and then to disk. */ NI_FileNameDirty, /* 1: FILE_NAME attributes need to be updated in the index. */ - NI_NoMtimeUpdate, /* 1: Don't update modifiction time. */ - NI_NoParentMtimeUpdate, /* 1: Don't update parent dir's mtime. */ NI_v3_Extensions, /* 1: JPA v3.x extensions present. */ } ntfs_inode_state_bits; @@ -99,16 +97,6 @@ typedef enum { #define NInoFileNameTestAndClearDirty(ni) \ test_and_clear_nino_flag(ni, FileNameDirty) -#define NInoNoMtimeUpdate(ni) test_nino_flag(ni, NoMtimeUpdate) -#define NInoSetNoMtimeUpdate(ni) set_nino_flag(ni, NoMtimeUpdate) -#define NInoClearNoMtimeUpdate(ni) clear_nino_flag(ni, NoMtimeUpdate) -#define NInoMtimeUpdate(ni) (!NInoNoMtimeUpdate(ni)) - -#define NInoNoParentMtimeUpdate(ni) test_nino_flag(ni, NoMtimeUpdate) -#define NInoSetNoParentMtimeUpdate(ni) set_nino_flag(ni, NoMtimeUpdate) -#define NInoClearNoParentMtimeUpdate(ni) clear_nino_flag(ni, NoMtimeUpdate) -#define NInoParentMtimeUpdate(ni) (!NInoNoParentMtimeUpdate(ni)) - /** * struct _ntfs_inode - The NTFS in-memory inode structure. * @@ -168,6 +156,15 @@ struct _ntfs_inode { le32 usn; }; +typedef enum { + NTFS_UPDATE_ATIME = 1 << 0, + NTFS_UPDATE_MTIME = 1 << 1, + NTFS_UPDATE_CTIME = 1 << 2, +} ntfs_time_update_flags; + +#define NTFS_UPDATE_MCTIME (NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME) +#define NTFS_UPDATE_AMCTIME (NTFS_UPDATE_ATIME | NTFS_UPDATE_MCTIME) + extern ntfs_inode *ntfs_inode_base(ntfs_inode *ni); extern ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol); @@ -183,8 +180,7 @@ extern int ntfs_inode_attach_all_extents(ntfs_inode *ni); extern void ntfs_inode_mark_dirty(ntfs_inode *ni); -extern void ntfs_inode_update_atime(ntfs_inode *ni); -extern void ntfs_inode_update_time(ntfs_inode *ni); +extern void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask); extern int ntfs_inode_sync(ntfs_inode *ni); diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index c9bf1ec8..b0927b04 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -815,10 +815,7 @@ s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b) return -1; } vol = na->ni->vol; - /* Update access time if needed. */ - if (na->type == AT_DATA || na->type == AT_INDEX_ROOT || - na->type == AT_INDEX_ALLOCATION) - ntfs_inode_update_atime(na->ni); + if (!count) return 0; /* Truncate reads beyond end of attribute. */ @@ -1168,10 +1165,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) errno = EOPNOTSUPP; goto errno_set; } - /* Update access and change times if needed. */ - if (na->type == AT_DATA || na->type == AT_INDEX_ROOT || - na->type == AT_INDEX_ALLOCATION) - ntfs_inode_update_time(na->ni); + if (!count) goto out; /* If the write reaches beyond the end, extend the attribute. */ @@ -4936,10 +4930,6 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) ret = ntfs_non_resident_attr_shrink(na, newsize); } else ret = ntfs_resident_attr_resize(na, newsize); - /* Update access and change times if needed. */ - if (na->type == AT_DATA || na->type == AT_INDEX_ROOT || - na->type == AT_INDEX_ALLOCATION) - ntfs_inode_update_time(na->ni); ntfs_log_trace("Return status %d\n", ret); return ret; diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index 01da272e..c14c3fbc 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -1500,8 +1500,10 @@ search: * case there are no reference to this inode left, so we should free all * non-resident attributes and mark all MFT record as not in use. */ - if (ni->mrec->link_count) + if (ni->mrec->link_count) { + ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME); goto out; + } ntfs_attr_reinit_search_ctx(actx); while (!ntfs_attrs_walk(actx)) { if (actx->attr->non_resident) { diff --git a/libntfs-3g/inode.c b/libntfs-3g/inode.c index 1fe64027..65bdc0d8 100644 --- a/libntfs-3g/inode.c +++ b/libntfs-3g/inode.c @@ -712,7 +712,6 @@ int ntfs_inode_sync(ntfs_inode *ni) /* Update FILE_NAME's in the index. */ if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && NInoFileNameTestAndClearDirty(ni) && - NInoParentMtimeUpdate(ni) && ntfs_inode_sync_file_name(ni)) { if (!err || errno == EIO) { err = errno; @@ -1122,42 +1121,36 @@ put_err_out: } /** - * ntfs_inode_update_atime - update access time for ntfs inode - * @ni: ntfs inode for which update access time + * ntfs_inode_update_times - update selected time fields for ntfs inode + * @ni: ntfs inode for which update time fields + * @mask: select which time fields should be updated * - * This function usually get called when user read not metadata from inode. - * Do not update time for system files. + * This function updates time fields to current time. Fields to update are + * selected using @mask (see enum @ntfs_time_update_flags for posssible values). */ -void ntfs_inode_update_atime(ntfs_inode *ni) +void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) { - if (!NVolReadOnly(ni->vol) && !NVolNoATime(ni->vol) && (ni->mft_no >= - FILE_first_user || ni->mft_no == FILE_root)) { - ni->last_access_time = time(NULL); - NInoFileNameSetDirty(ni); - NInoSetDirty(ni); + time_t now; + + if (!ni) { + ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__); + return; } -} -/** - * ntfs_inode_update_time - update all times for ntfs inode - * @ni: ntfs inode for which update times - * - * This function updates last access, mft and data change times. Usually - * get called when user write not metadata to inode. Do not update time for - * system files. - */ -void ntfs_inode_update_time(ntfs_inode *ni) -{ - if (!NVolReadOnly(ni->vol) && NInoMtimeUpdate(ni) && - (ni->mft_no >= FILE_first_user || ni->mft_no == FILE_root)) { - time_t now; + if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) || + NVolReadOnly(ni->vol) || !mask) + return; - now = time(NULL); + now = time(NULL); + if (mask & NTFS_UPDATE_ATIME) + ni->last_access_time = now; + if (mask & NTFS_UPDATE_MTIME) ni->last_data_change_time = now; + if (mask & NTFS_UPDATE_CTIME) ni->last_mft_change_time = now; - NInoFileNameSetDirty(ni); - NInoSetDirty(ni); - } + + NInoFileNameSetDirty(ni); + NInoSetDirty(ni); } /** diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index ab037ad4..dcc763f4 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -175,6 +175,13 @@ static int ntfs_fuse_is_named_data_stream(const char *path) return 0; } +static void ntfs_fuse_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) +{ + if (ctx->noatime) + mask &= ~NTFS_UPDATE_ATIME; + ntfs_inode_update_times(ni, mask); +} + static s64 ntfs_get_nr_free_mft_records(ntfs_volume *vol) { ntfs_attr *na = vol->mftbmp_na; @@ -592,6 +599,7 @@ static int ntfs_fuse_readdir(const char *path, void *buf, if (ntfs_readdir(ni, &pos, &fill_ctx, (ntfs_filldir_t)ntfs_fuse_filler)) err = -errno; + ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME); if (ntfs_inode_close(ni)) set_fuse_error(&err); return err; @@ -653,7 +661,6 @@ static int ntfs_fuse_open(const char *org_path, static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi __attribute__((unused))) { - ntfs_volume *vol; ntfs_inode *ni = NULL; ntfs_attr *na = NULL; char *path = NULL; @@ -661,11 +668,13 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, int stream_name_len, res; s64 total = 0; + if (!size) + return 0; + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; - vol = ctx->vol; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) { res = -errno; goto exit; @@ -695,6 +704,7 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, total += ret; } ok: + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME); res = total; exit: if (na) @@ -748,6 +758,8 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, total += res; } res = total; + if (res > 0) + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); exit: if (na) ntfs_attr_close(na); @@ -804,6 +816,7 @@ static int ntfs_fuse_trunc(const char *org_path, off_t size, BOOL chkwrite) /* JPA strange : no ntfs_attr_close(na) ? */ goto exit; + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); ntfs_attr_close(na); errno = 0; exit: @@ -837,7 +850,6 @@ static int ntfs_fuse_chmod(const char *path, int res = 0; ntfs_inode *ni; struct SECURITY_CONTEXT security; - time_t now; if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; /* n/a for named data streams. */ @@ -862,8 +874,7 @@ static int ntfs_fuse_chmod(const char *path, ni->flags &= ~FILE_ATTR_READONLY; else ni->flags |= FILE_ATTR_READONLY; - now = time(NULL); - ni->last_mft_change_time = now; + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); } NInoSetDirty(ni); if (ntfs_inode_close(ni)) @@ -879,7 +890,6 @@ static int ntfs_fuse_chown(const char *path, uid_t uid, gid_t gid) { ntfs_inode *ni; int res; - time_t now; struct SECURITY_CONTEXT security; if (ntfs_fuse_is_named_data_stream(path)) @@ -904,10 +914,8 @@ static int ntfs_fuse_chown(const char *path, uid_t uid, gid_t gid) if (ntfs_set_owner(&security, path,ni,uid,gid)) res = -errno; - else { - now = time(NULL); - ni->last_mft_change_time = now; - } + else + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); if (ntfs_inode_close(ni)) set_fuse_error(&res); } @@ -1066,6 +1074,7 @@ static int ntfs_fuse_create(const char *org_path, dev_t typemode, dev_t dev, NInoSetDirty(ni); if (ntfs_inode_close(ni)) set_fuse_error(&res); + ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME); } else res = -errno; @@ -1168,13 +1177,7 @@ static int ntfs_fuse_symlink(const char *to, const char *from) return ntfs_fuse_create(from, S_IFLNK, 0, to); } -/** - * NOTE: About the role of mtime: during rename(3), which is currently - * implemented by the help of link() operations, modification time mustn't - * be updated, so we NInoSetNoMtimeUpdate() such inodes after they are opened. - * This is not very nice itself but it may be eliminated, in time. - */ -static int ntfs_fuse_ln(const char *old_path, const char *new_path, int mtime) +static int ntfs_fuse_link(const char *old_path, const char *new_path) { char *name; ntfschar *uname = NULL; @@ -1197,9 +1200,6 @@ static int ntfs_fuse_ln(const char *old_path, const char *new_path, int mtime) goto exit; } - if (!mtime) - NInoSetNoMtimeUpdate(ni); - /* Generate unicode filename. */ name = strrchr(path, '/'); name++; @@ -1223,9 +1223,14 @@ static int ntfs_fuse_ln(const char *old_path, const char *new_path, int mtime) res = -EACCES; else { - /* Create hard link. */ - if (ntfs_link(ni, dir_ni, uname, uname_len)) + + if (ntfs_link(ni, dir_ni, uname, uname_len)) { res = -errno; + goto exit; + } + + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME); } exit: /* @@ -1241,11 +1246,6 @@ exit: return res; } -static int ntfs_fuse_link(const char *old_path, const char *new_path) -{ - return ntfs_fuse_ln(old_path, new_path, 1); -} - static int ntfs_fuse_rm(const char *org_path) { char *name; @@ -1284,8 +1284,13 @@ static int ntfs_fuse_rm(const char *org_path) || ntfs_allowed_access(&security, path, dir_ni, S_IEXEC + S_IWRITE + S_ISVTX)) { /* Delete object. */ - if (ntfs_delete(ni, dir_ni, uname, uname_len)) + if (ntfs_delete(ni, dir_ni, uname, uname_len)) { res = -errno; + } else { + /* Inode ctime is updated in ntfs_delete() for hard links. */ + ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME); + } + /* ntfs_delete() always closes ni */ } else res = -EACCES; ni = NULL; @@ -1356,14 +1361,14 @@ static int ntfs_fuse_safe_rename(const char *old_path, ntfs_log_trace("Entering\n"); - ret = ntfs_fuse_ln(new_path, tmp, 0); + ret = ntfs_fuse_link(new_path, tmp); if (ret) return ret; ret = ntfs_fuse_unlink(new_path); if (!ret) { - ret = ntfs_fuse_ln(old_path, new_path, 0); + ret = ntfs_fuse_link(old_path, new_path); if (ret) goto restore; @@ -1377,7 +1382,7 @@ static int ntfs_fuse_safe_rename(const char *old_path, goto cleanup; restore: - if (ntfs_fuse_ln(tmp, new_path, 0)) { + if (ntfs_fuse_link(tmp, new_path)) { err: ntfs_log_perror("Rename failed. Existing file '%s' was renamed " "to '%s'", new_path, tmp); @@ -1446,7 +1451,7 @@ static int ntfs_fuse_rename(const char *old_path, const char *new_path) goto out; } - ret = ntfs_fuse_ln(old_path, new_path, 0); + ret = ntfs_fuse_link(old_path, new_path); if (ret) goto out; @@ -1478,7 +1483,6 @@ static int ntfs_fuse_rmdir(const char *path) static int ntfs_fuse_utime(const char *path, struct utimbuf *buf) { ntfs_inode *ni; - time_t now; int res = 0; if (ntfs_fuse_is_named_data_stream(path)) @@ -1487,20 +1491,13 @@ static int ntfs_fuse_utime(const char *path, struct utimbuf *buf) if (!ni) return -errno; - NInoSetNoParentMtimeUpdate(ni); - - now = time(NULL); - ni->last_mft_change_time = now; - if (buf) { ni->last_access_time = buf->actime; ni->last_data_change_time = buf->modtime; - } else { - ni->last_access_time = now; - ni->last_data_change_time = now; - } - NInoFileNameSetDirty(ni); - NInoSetDirty(ni); + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + } else + ntfs_fuse_update_times(ni, NTFS_UPDATE_AMCTIME); + if (ntfs_inode_close(ni)) set_fuse_error(&res); return res;