posix file time updates (Yura Pakhuchiy, Szabolcs Szakacsits)

N2009_11_14_FIXES
szaka 2007-11-13 00:11:51 +00:00
parent eb0713793e
commit 906637db9e
5 changed files with 79 additions and 101 deletions

View File

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

View File

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

View File

@ -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) {

View File

@ -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);
}
/**

View File

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