posix file time updates (Yura Pakhuchiy, Szabolcs Szakacsits)
parent
698ab031c2
commit
d4b91d350c
|
@ -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. */
|
||||
} ntfs_inode_state_bits;
|
||||
|
||||
#define test_nino_flag(ni, flag) test_bit(NI_##flag, (ni)->state)
|
||||
|
@ -98,16 +96,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.
|
||||
*
|
||||
|
@ -161,6 +149,15 @@ struct _ntfs_inode {
|
|||
time_t last_access_time;
|
||||
};
|
||||
|
||||
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);
|
||||
|
@ -176,8 +173,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);
|
||||
|
||||
|
|
|
@ -809,10 +809,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. */
|
||||
|
@ -1162,10 +1159,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. */
|
||||
|
@ -4930,10 +4924,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;
|
||||
|
|
|
@ -1485,8 +1485,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) {
|
||||
|
|
|
@ -686,7 +686,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;
|
||||
|
@ -1096,42 +1095,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -168,6 +168,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;
|
||||
|
@ -552,6 +559,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;
|
||||
|
@ -594,7 +602,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;
|
||||
|
@ -602,11 +609,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;
|
||||
|
@ -636,6 +645,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)
|
||||
|
@ -688,6 +698,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);
|
||||
|
@ -725,6 +737,7 @@ static int ntfs_fuse_truncate(const char *org_path, off_t size)
|
|||
if (ntfs_attr_truncate(na, size))
|
||||
goto exit;
|
||||
|
||||
ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
|
||||
ntfs_attr_close(na);
|
||||
errno = 0;
|
||||
exit:
|
||||
|
@ -808,6 +821,7 @@ static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev,
|
|||
if (ni) {
|
||||
if (ntfs_inode_close(ni))
|
||||
set_fuse_error(&res);
|
||||
ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME);
|
||||
} else
|
||||
res = -errno;
|
||||
exit:
|
||||
|
@ -905,13 +919,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;
|
||||
|
@ -933,9 +941,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++;
|
||||
|
@ -951,9 +956,14 @@ static int ntfs_fuse_ln(const char *old_path, const char *new_path, int mtime)
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
/* 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:
|
||||
/*
|
||||
* Must close dir_ni first otherwise ntfs_inode_sync_file_name(ni)
|
||||
|
@ -968,11 +978,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;
|
||||
|
@ -1006,8 +1011,13 @@ static int ntfs_fuse_rm(const char *org_path)
|
|||
goto exit;
|
||||
}
|
||||
/* 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 */
|
||||
ni = NULL;
|
||||
exit:
|
||||
if (ni && ntfs_inode_close(ni))
|
||||
|
@ -1065,14 +1075,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;
|
||||
|
||||
|
@ -1086,7 +1096,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);
|
||||
|
@ -1155,7 +1165,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;
|
||||
|
||||
|
@ -1187,7 +1197,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))
|
||||
|
@ -1196,20 +1205,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;
|
||||
|
|
Loading…
Reference in New Issue