Rework time updates

- Library no longer perform time updates, only provide API for this
- Remove ntfs_inode_update_{a,}time() and introduce ntfs_inode_update_times()
- Make ntfsmount properly update times
- ntfs_delete() now takes pointer to pointer to ntfs_inode for while to delete and closes inode only in cases no more hard links left to file
edge.strict_endians
Yura Pakhuchiy 2007-09-06 18:34:38 +03:00
parent a1124ce7f4
commit 82df6c1fea
11 changed files with 92 additions and 82 deletions

View File

@ -77,7 +77,7 @@ extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni,
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni,
ntfschar *name, u8 name_len, ntfschar *target, u8 target_len);
extern int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
extern int ntfs_delete(ntfs_inode **pni, ntfs_inode *dir_ni, ntfschar *name,
u8 name_len);
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,

View File

@ -130,7 +130,7 @@ struct _ntfs_inode {
};
/* Below fields are valid only for base inode. */
s64 data_size; /* Data size stored in the filename index. */
s64 data_size; /* Data size of unnamed DATA attribute. */
s64 allocated_size; /* Allocated size stored in the filename
index. (NOTE: Equal to allocated size of
the unnamed data attribute for normal or
@ -172,8 +172,14 @@ static __inline__ void ntfs_inode_mark_dirty(ntfs_inode *ni)
NInoSetDirty(ni->base_ni);
}
extern void ntfs_inode_update_atime(ntfs_inode *ni);
extern void ntfs_inode_update_time(ntfs_inode *ni);
typedef enum {
NTFS_UPDATE_ATIME = 1 << 0,
NTFS_UPDATE_MTIME = 1 << 1,
NTFS_UPDATE_CTIME = 1 << 2,
} ntfs_time_update_flags;
extern void ntfs_inode_update_times(ntfs_inode *ni,
ntfs_time_update_flags mask);
extern int ntfs_inode_sync(ntfs_inode *ni);

View File

@ -57,10 +57,9 @@ typedef struct _ntfs_volume ntfs_volume;
*/
typedef enum {
NTFS_MNT_RDONLY = 1,
NTFS_MNT_NOATIME = 2,
NTFS_MNT_FORENSIC = 2,
NTFS_MNT_CASE_SENSITIVE = 4,
NTFS_MNT_NOT_EXCLUSIVE = 8,
NTFS_MNT_FORENSIC = 16,
} ntfs_mount_flags;
/**
@ -108,10 +107,6 @@ typedef enum {
#define NVolSetLogFileEmpty(nv) set_nvol_flag(nv, LogFileEmpty)
#define NVolClearLogFileEmpty(nv) clear_nvol_flag(nv, LogFileEmpty)
#define NVolNoATime(nv) test_nvol_flag(nv, NoATime)
#define NVolSetNoATime(nv) set_nvol_flag(nv, NoATime)
#define NVolClearNoATime(nv) clear_nvol_flag(nv, NoATime)
#define NVolWasDirty(nv) test_nvol_flag(nv, WasDirty)
#define NVolSetWasDirty(nv) set_nvol_flag(nv, WasDirty)
#define NVolClearWasDirty(nv) clear_nvol_flag(nv, WasDirty)

View File

@ -864,10 +864,6 @@ s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b)
return ntfs_crypto_attr_pread(na, pos, count, b);
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. */
@ -1050,10 +1046,6 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
errno = EOPNOTSUPP;
return -1;
}
/* 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)
return 0;
/* If the write reaches beyond the end, extend the attribute. */
@ -5092,10 +5084,6 @@ int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse)
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);
if (!ret)
ntfs_log_trace("Done!\n");
else

View File

@ -487,7 +487,7 @@ close_err_out:
u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent,
const char *pathname)
{
u64 inum, result;
u64 inum, result;
int len, err = 0;
char *p, *q;
ntfs_inode *ni = NULL;
@ -1430,20 +1430,24 @@ ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
/**
* ntfs_delete - delete file or directory from ntfs volume
* @ni: ntfs inode for object to delete
* @pni: ntfs inode for object to delete
* @dir_ni: ntfs inode for directory in which delete object
* @name: unicode name of the object to delete
* @name_len: length of the name in unicode characters
*
* @ni is always closed after the call to this function (even if it failed),
* user does not need to call ntfs_inode_close himself.
* @pni is pointer to pointer to ntfs_inode structure. Upon successful
* completion and if inode is really deleted (there are no more links left to
* it) this function will close @*pni and set it to NULL, in the other cases
* @*pni will stay opened.
*
* Return 0 on success or -1 on error with errno set to the error code.
*/
int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
int ntfs_delete(ntfs_inode **pni, ntfs_inode *dir_ni, ntfschar *name,
u8 name_len)
{
ntfs_attr_search_ctx *actx = NULL;
ntfs_index_context *ictx = NULL;
ntfs_inode *ni;
FILE_NAME_ATTR *fn = NULL;
BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE;
BOOL case_sensitive_match = TRUE;
@ -1451,15 +1455,12 @@ int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
ntfs_log_trace("Entering.\n");
if (!ni || !dir_ni || !name || !name_len) {
if (!pni || !(ni = *pni) || !dir_ni || !name || !name_len ||
ni->nr_extents == -1 || dir_ni->nr_extents == -1) {
ntfs_log_error("Invalid arguments.\n");
errno = EINVAL;
goto err_out;
}
if (ni->nr_extents == -1)
ni = ni->base_ni;
if (dir_ni->nr_extents == -1)
dir_ni = dir_ni->base_ni;
/*
* Search for FILE_NAME attribute with such name. If it's in POSIX or
* WIN32_AND_DOS namespace, then simply remove it from index and inode.
@ -1642,14 +1643,12 @@ search:
ntfs_log_error("Failed to free base MFT record. "
"Leaving inconsistent metadata.\n");
}
ni = NULL;
*pni = NULL;
out:
if (actx)
ntfs_attr_put_search_ctx(actx);
if (ictx)
ntfs_index_ctx_put(ictx);
if (ni)
ntfs_inode_close(ni);
if (err) {
ntfs_log_error("%s(): Failed.\n", __FUNCTION__);
errno = err;

View File

@ -1069,43 +1069,34 @@ 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;
}
}
if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) ||
NVolReadOnly(ni->vol) || !mask)
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) && !NVolNoATime(ni->vol) && (ni->mft_no >=
FILE_first_user || ni->mft_no == FILE_root)) {
time_t now;
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

@ -440,8 +440,6 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
vol->upcase_len * sizeof(ntfschar));
if (flags & NTFS_MNT_RDONLY)
NVolSetReadOnly(vol);
if (flags & NTFS_MNT_NOATIME)
NVolSetNoATime(vol);
if (flags & NTFS_MNT_CASE_SENSITIVE)
NVolSetCaseSensitive(vol);
ntfs_log_debug("Reading bootsector... ");
@ -758,7 +756,6 @@ out:
* as for the mount system call (man 2 mount). Currently the following flags
* are implemented:
* NTFS_MNT_RDONLY - mount volume read-only
* NTFS_MNT_NOATIME - do not update access time
* NTFS_MNT_CASE_SENSITIVE - treat filenames as case sensitive even if
* they are not in POSIX namespace
* NTFS_MNT_NOT_EXCLUSIVE - (unix only) do not open volume exclusively

View File

@ -833,7 +833,7 @@ int main(int argc, char **argv)
// at this point we know that the volume is valid enough for mounting.
/* Call ntfs_device_mount() to do the actual mount. */
vol = ntfs_device_mount(dev, NTFS_MNT_NOATIME | NTFS_MNT_RDONLY);
vol = ntfs_device_mount(dev, NTFS_MNT_RDONLY);
if (!vol) {
ntfs_device_free(dev);
return 2;

View File

@ -1841,7 +1841,7 @@ int main(int argc, char **argv)
/* 'force' again mount for dirty volumes (e.g. after resize).
FIXME: use mount flags to avoid potential side-effects in future */
opt.force++;
mount_volume(NTFS_MNT_NOATIME);
mount_volume(0);
free(lcn_bitmap.bm);
setup_lcn_bitmap();

View File

@ -107,6 +107,7 @@ typedef struct {
BOOL verbose;
BOOL no_def_opts;
BOOL case_insensitive;
BOOL noatime;
} ntfs_fuse_context_t;
typedef enum {
@ -138,6 +139,7 @@ static const struct fuse_opt ntfs_fuse_opts[] = {
NTFS_FUSE_OPT("no_detach", no_detach),
NTFS_FUSE_OPT("no_def_opts", no_def_opts),
NTFS_FUSE_OPT("case_insensitive", case_insensitive),
NTFS_FUSE_OPT("noatime", noatime),
NTFS_FUSE_OPT("fmask=%o", fmask),
NTFS_FUSE_OPT("dmask=%o", dmask),
NTFS_FUSE_OPT("umask=%o", fmask),
@ -160,6 +162,7 @@ static const struct fuse_opt ntfs_fuse_opts[] = {
FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("ro", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("rw", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("noatime", FUSE_OPT_KEY_KEEP),
FUSE_OPT_END
};
@ -190,6 +193,14 @@ static __inline__ int ntfs_fuse_is_named_data_stream(const char *path)
return 0;
}
static __inline__ 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 long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol, long nr_free)
{
u8 *buf;
@ -589,6 +600,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);
ntfs_inode_close(ni);
return err;
}
@ -633,6 +645,8 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size,
ntfschar *stream_name;
int stream_name_len, res, 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;
@ -662,6 +676,7 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size,
total += res;
}
res = total;
ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME);
exit:
if (na)
ntfs_attr_close(na);
@ -711,6 +726,9 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size,
res = total;
exit:
ntfs_fuse_mark_free_space_outdated();
if (res > 0)
ntfs_fuse_update_times(ni, NTFS_UPDATE_MTIME |
NTFS_UPDATE_CTIME);
if (na)
ntfs_attr_close(na);
if (ni && ntfs_inode_close(ni))
@ -738,6 +756,10 @@ static int ntfs_fuse_truncate(const char *org_path, off_t size)
res = -errno;
goto exit;
}
if (ni->data_size == size) {
res = 0;
goto exit;
}
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
if (!na) {
res = -errno;
@ -745,8 +767,11 @@ static int ntfs_fuse_truncate(const char *org_path, off_t size)
}
if (ntfs_attr_truncate(na, size))
res = -errno;
else
else {
ntfs_fuse_update_times(ni, NTFS_UPDATE_MTIME |
NTFS_UPDATE_CTIME);
res = 0;
}
ntfs_fuse_mark_free_space_outdated();
ntfs_attr_close(na);
exit:
@ -827,9 +852,11 @@ static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev,
ni = ntfs_create(dir_ni, uname, uname_len, type);
break;
}
if (ni)
if (ni) {
ntfs_inode_close(ni);
else
ntfs_fuse_update_times(dir_ni,
NTFS_UPDATE_CTIME | NTFS_UPDATE_MTIME);
} else
res = -errno;
exit:
free(uname);
@ -948,6 +975,11 @@ static int ntfs_fuse_link(const char *old_path, const char *new_path)
/* Create hard link. */
if (ntfs_link(ni, dir_ni, uname, uname_len))
res = -errno;
else {
ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_CTIME |
NTFS_UPDATE_MTIME);
}
exit:
if (ni)
ntfs_inode_close(ni);
@ -993,9 +1025,14 @@ 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;
ni = NULL;
else {
if (ni)
ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_CTIME |
NTFS_UPDATE_MTIME);
}
exit:
if (ni)
ntfs_inode_close(ni);
@ -1110,23 +1147,21 @@ static int ntfs_fuse_rmdir(const char *path)
static int ntfs_fuse_utimens(const char *path, const struct timespec ts[2])
{
ntfs_inode *ni;
time_t now;
if (ntfs_fuse_is_named_data_stream(path))
return -EINVAL; /* n/a for named data streams. */
ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
if (!ni)
return -errno;
now = time(NULL);
ni->last_mft_change_time = now;
if (ts) {
ni->last_access_time = ts[0].tv_sec;
ni->last_data_change_time = ts[1].tv_sec;
ni->last_mft_change_time = ts[1].tv_sec;
} else {
time_t now;
now = time(NULL);
ni->last_access_time = now;
ni->last_data_change_time = now;
ni->last_mft_change_time = now;
}
NInoFileNameSetDirty(ni);
NInoSetDirty(ni);
@ -1599,7 +1634,7 @@ static int ntfs_fuse_mount(void)
{
ntfs_volume *vol;
vol = utils_mount_volume(ctx->device, NTFS_MNT_NOATIME |
vol = utils_mount_volume(ctx->device,
((ctx->ro) ? NTFS_MNT_RDONLY : 0) |
((ctx->case_insensitive) ? 0 :
NTFS_MNT_CASE_SENSITIVE) |

View File

@ -2243,8 +2243,7 @@ static ntfs_volume *mount_volume(void)
* volume at all. We will do the logfile emptying and dirty setting
* later if needed.
*/
if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_NOATIME |
NTFS_MNT_FORENSIC))) {
if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_FORENSIC))) {
int err = errno;
perr_printf("Opening '%s' as NTFS failed", opt.volume);