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 fileedge.strict_endians
parent
a1124ce7f4
commit
82df6c1fea
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue