Cached inode data for subsequent use
parent
41a371f4a7
commit
d75f69d80e
|
@ -50,6 +50,7 @@ typedef enum {
|
|||
in the index. */
|
||||
NI_v3_Extensions, /* 1: JPA v3.x extensions present. */
|
||||
NI_TimesSet, /* 1: Use times which were set */
|
||||
NI_KnownSize, /* 1: Set if sizes are meaningful */
|
||||
} ntfs_inode_state_bits;
|
||||
|
||||
#define test_nino_flag(ni, flag) test_bit(NI_##flag, (ni)->state)
|
||||
|
@ -135,8 +136,11 @@ struct _ntfs_inode {
|
|||
* These two fields are used to sync filename index and guaranteed to be
|
||||
* correct, however value in index itself maybe wrong (windows itself
|
||||
* do not update them properly).
|
||||
* For directories, they hold the index size, provided the
|
||||
* flag KnownSize is set.
|
||||
*/
|
||||
s64 data_size; /* Data size of unnamed DATA attribute. */
|
||||
s64 data_size; /* Data size of unnamed DATA attribute
|
||||
(or INDEX_ROOT for directories) */
|
||||
s64 allocated_size; /* Allocated size stored in the filename
|
||||
index. (NOTE: Equal to allocated size of
|
||||
the unnamed data attribute for normal or
|
||||
|
@ -179,6 +183,18 @@ extern ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref);
|
|||
extern int ntfs_inode_close(ntfs_inode *ni);
|
||||
extern int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||
|
||||
#if CACHE_NIDATA_SIZE
|
||||
|
||||
struct CACHED_GENERIC;
|
||||
|
||||
extern int ntfs_inode_real_close(ntfs_inode *ni);
|
||||
extern void ntfs_inode_invalidate(ntfs_volume *vol, const MFT_REF mref);
|
||||
extern void ntfs_inode_nidata_free(const struct CACHED_GENERIC *cached);
|
||||
extern int ntfs_inode_nidata_hash(const struct CACHED_GENERIC *item);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
extern ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni,
|
||||
const MFT_REF mref);
|
||||
|
||||
|
@ -201,4 +217,8 @@ extern int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size);
|
|||
extern int ntfs_inode_set_times(ntfs_inode *ni, const char *value,
|
||||
size_t size, int flags);
|
||||
|
||||
/* debugging */
|
||||
#define debug_double_inode(num, type)
|
||||
#define debug_cached_inode(ni)
|
||||
|
||||
#endif /* defined _NTFS_INODE_H */
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#define _NTFS_PARAM_H
|
||||
|
||||
#define CACHE_INODE_SIZE 32 /* inode cache, zero or >= 3 and not too big */
|
||||
#define CACHE_NIDATA_SIZE 64 /* idata cache, zero or >= 3 and not too big */
|
||||
#define CACHE_SECURID_SIZE 16 /* securid cache, zero or >= 3 and not too big */
|
||||
#define CACHE_LEGACY_SIZE 8 /* legacy cache size, zero or >= 3 and not too big */
|
||||
|
||||
|
|
|
@ -232,6 +232,9 @@ struct _ntfs_volume {
|
|||
#if CACHE_INODE_SIZE
|
||||
struct CACHE_HEADER *xinode_cache;
|
||||
#endif
|
||||
#if CACHE_NIDATA_SIZE
|
||||
struct CACHE_HEADER *nidata_cache;
|
||||
#endif
|
||||
#if CACHE_SECURID_SIZE
|
||||
struct CACHE_HEADER *securid_cache;
|
||||
#endif
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#include "param.h"
|
||||
#include "compat.h"
|
||||
#include "attrib.h"
|
||||
#include "attrlist.h"
|
||||
|
@ -1463,6 +1464,15 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
|
|||
goto err_out;
|
||||
}
|
||||
na->initialized_size = pos + count;
|
||||
#if CACHE_NIDATA_SIZE
|
||||
if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY
|
||||
? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30
|
||||
: na->type == AT_DATA && na->name == AT_UNNAMED) {
|
||||
na->ni->data_size = na->data_size;
|
||||
na->ni->allocated_size = na->allocated_size;
|
||||
set_nino_flag(na->ni,KnownSize);
|
||||
}
|
||||
#endif
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx = NULL;
|
||||
/*
|
||||
|
@ -1876,6 +1886,15 @@ retry:
|
|||
if (!NVolReadOnly(vol)) {
|
||||
|
||||
written = ntfs_compressed_close(na, rl, ofs);
|
||||
#if CACHE_NIDATA_SIZE
|
||||
if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY
|
||||
? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30
|
||||
: na->type == AT_DATA && na->name == AT_UNNAMED) {
|
||||
na->ni->data_size = na->data_size;
|
||||
na->ni->allocated_size = na->allocated_size;
|
||||
set_nino_flag(na->ni,KnownSize);
|
||||
}
|
||||
#endif
|
||||
/* If everything ok, update progress counters and continue. */
|
||||
if (!written)
|
||||
goto done;
|
||||
|
@ -3217,9 +3236,12 @@ int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
|||
goto put_err_out;
|
||||
}
|
||||
}
|
||||
if (type == AT_DATA && name == AT_UNNAMED) {
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY
|
||||
? type == AT_INDEX_ROOT && name == NTFS_INDEX_I30
|
||||
: type == AT_DATA && name == AT_UNNAMED) {
|
||||
ni->data_size = size;
|
||||
ni->allocated_size = (size + 7) & ~7;
|
||||
set_nino_flag(ni,KnownSize);
|
||||
}
|
||||
ntfs_inode_mark_dirty(ni);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
|
@ -4341,10 +4363,14 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize)
|
|||
if ((na->data_flags & ATTR_COMPRESSION_MASK)
|
||||
|| NAttrSparse(na))
|
||||
na->compressed_size = na->allocated_size;
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED) {
|
||||
if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY
|
||||
? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30
|
||||
: na->type == AT_DATA && na->name == AT_UNNAMED) {
|
||||
na->ni->data_size = na->data_size;
|
||||
na->ni->allocated_size = na->allocated_size;
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
set_nino_flag(na->ni,KnownSize);
|
||||
if (na->type == AT_DATA)
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
}
|
||||
goto resize_done;
|
||||
}
|
||||
|
@ -5244,9 +5270,17 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize)
|
|||
ctx->attr->initialized_size = cpu_to_sle64(newsize);
|
||||
}
|
||||
/* Update data size in the index. */
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED) {
|
||||
na->ni->data_size = na->data_size;
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
|
||||
if (na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30) {
|
||||
na->ni->data_size = na->data_size;
|
||||
na->ni->allocated_size = na->allocated_size;
|
||||
set_nino_flag(na->ni,KnownSize);
|
||||
}
|
||||
} else {
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED) {
|
||||
na->ni->data_size = na->data_size;
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the attribute now has zero size, make it resident. */
|
||||
|
@ -5435,9 +5469,17 @@ static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize)
|
|||
na->data_size = newsize;
|
||||
ctx->attr->data_size = cpu_to_sle64(newsize);
|
||||
/* Update data size in the index. */
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED) {
|
||||
na->ni->data_size = na->data_size;
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
|
||||
if (na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30) {
|
||||
na->ni->data_size = na->data_size;
|
||||
na->ni->allocated_size = na->allocated_size;
|
||||
set_nino_flag(na->ni,KnownSize);
|
||||
}
|
||||
} else {
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED) {
|
||||
na->ni->data_size = na->data_size;
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
}
|
||||
}
|
||||
/* Set the inode dirty so it is written out later. */
|
||||
ntfs_inode_mark_dirty(ctx->ntfs_ino);
|
||||
|
|
|
@ -564,6 +564,13 @@ void ntfs_create_lru_caches(ntfs_volume *vol)
|
|||
vol->xinode_cache = ntfs_create_cache("inode",(cache_free)NULL,
|
||||
ntfs_dir_inode_hash, sizeof(struct CACHED_INODE),
|
||||
CACHE_INODE_SIZE, 2*CACHE_INODE_SIZE);
|
||||
#endif
|
||||
#if CACHE_NIDATA_SIZE
|
||||
/* idata cache */
|
||||
vol->nidata_cache = ntfs_create_cache("nidata",
|
||||
ntfs_inode_nidata_free, ntfs_inode_nidata_hash,
|
||||
sizeof(struct CACHED_NIDATA),
|
||||
CACHE_NIDATA_SIZE, 2*CACHE_NIDATA_SIZE);
|
||||
#endif
|
||||
vol->securid_cache = ntfs_create_cache("securid",(cache_free)NULL,
|
||||
(cache_hash)NULL,sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0);
|
||||
|
@ -581,6 +588,9 @@ void ntfs_free_lru_caches(ntfs_volume *vol)
|
|||
{
|
||||
#if CACHE_INODE_SIZE
|
||||
ntfs_free_cache(vol->xinode_cache);
|
||||
#endif
|
||||
#if CACHE_NIDATA_SIZE
|
||||
ntfs_free_cache(vol->nidata_cache);
|
||||
#endif
|
||||
ntfs_free_cache(vol->securid_cache);
|
||||
#if CACHE_LEGACY_SIZE
|
||||
|
|
|
@ -1216,6 +1216,9 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
|||
ni = ntfs_mft_record_alloc(dir_ni->vol, NULL);
|
||||
if (!ni)
|
||||
return NULL;
|
||||
#if CACHE_NIDATA_SIZE
|
||||
ntfs_inode_invalidate(dir_ni->vol, ni->mft_no);
|
||||
#endif
|
||||
/*
|
||||
* Create STANDARD_INFORMATION attribute.
|
||||
* JPA Depending on available inherited security descriptor,
|
||||
|
@ -1379,8 +1382,12 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
|||
fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
|
||||
fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
|
||||
fn->last_access_time = utc2ntfs(ni->last_access_time);
|
||||
fn->data_size = cpu_to_sle64(ni->data_size);
|
||||
fn->allocated_size = cpu_to_sle64(ni->allocated_size);
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||
fn->data_size = fn->allocated_size = const_cpu_to_le64(0);
|
||||
else {
|
||||
fn->data_size = cpu_to_sle64(ni->data_size);
|
||||
fn->allocated_size = cpu_to_sle64(ni->allocated_size);
|
||||
}
|
||||
memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
|
||||
/* Add FILE_NAME attribute to inode. */
|
||||
if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) {
|
||||
|
@ -1541,6 +1548,9 @@ int ntfs_delete(ntfs_volume *vol, const char *pathname,
|
|||
BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE;
|
||||
BOOL case_sensitive_match = TRUE;
|
||||
int err = 0;
|
||||
#if CACHE_NIDATA_SIZE
|
||||
int i;
|
||||
#endif
|
||||
#if CACHE_INODE_SIZE
|
||||
struct CACHED_INODE item;
|
||||
const char *p;
|
||||
|
@ -1731,12 +1741,31 @@ search:
|
|||
"Probably leaving inconsistent metadata.\n");
|
||||
}
|
||||
/* All extents should be attached after attribute walk. */
|
||||
#if CACHE_NIDATA_SIZE
|
||||
/*
|
||||
* Disconnect extents before deleting them, so they are
|
||||
* not wrongly moved to cache through the chainings
|
||||
*/
|
||||
for (i=ni->nr_extents-1; i>=0; i--) {
|
||||
ni->extent_nis[i]->base_ni = (ntfs_inode*)NULL;
|
||||
ni->extent_nis[i]->nr_extents = 0;
|
||||
if (ntfs_mft_record_free(ni->vol, ni->extent_nis[i])) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to free extent MFT record. "
|
||||
"Leaving inconsistent metadata.\n");
|
||||
}
|
||||
}
|
||||
free(ni->extent_nis);
|
||||
ni->nr_extents = 0;
|
||||
ni->extent_nis = (ntfs_inode**)NULL;
|
||||
#else
|
||||
while (ni->nr_extents)
|
||||
if (ntfs_mft_record_free(ni->vol, *(ni->extent_nis))) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to free extent MFT record. "
|
||||
"Leaving inconsistent metadata.\n");
|
||||
}
|
||||
#endif
|
||||
if (ntfs_mft_record_free(ni->vol, ni)) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to free base MFT record. "
|
||||
|
@ -1812,10 +1841,13 @@ static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
|||
fn->file_name_length = name_len;
|
||||
fn->file_name_type = nametype;
|
||||
fn->file_attributes = ni->flags;
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
|
||||
fn->file_attributes |= FILE_ATTR_I30_INDEX_PRESENT;
|
||||
fn->allocated_size = cpu_to_sle64(ni->allocated_size);
|
||||
fn->data_size = cpu_to_sle64(ni->data_size);
|
||||
fn->data_size = fn->allocated_size = const_cpu_to_le64(0);
|
||||
} else {
|
||||
fn->allocated_size = cpu_to_sle64(ni->allocated_size);
|
||||
fn->data_size = cpu_to_sle64(ni->data_size);
|
||||
}
|
||||
fn->creation_time = utc2ntfs(ni->creation_time);
|
||||
fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
|
||||
fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
|
||||
|
|
|
@ -43,8 +43,10 @@
|
|||
#include "param.h"
|
||||
#include "compat.h"
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
#include "volume.h"
|
||||
#include "cache.h"
|
||||
#include "inode.h"
|
||||
#include "attrib.h"
|
||||
#include "debug.h"
|
||||
#include "mft.h"
|
||||
#include "attrlist.h"
|
||||
|
@ -154,7 +156,7 @@ static void __ntfs_inode_release(ntfs_inode *ni)
|
|||
* Return a pointer to the ntfs_inode structure on success or NULL on error,
|
||||
* with errno set to the error code.
|
||||
*/
|
||||
ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
|
||||
static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
|
||||
{
|
||||
s64 l;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
@ -207,13 +209,13 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
|
|||
ni->usn = std_info->usn;
|
||||
} else {
|
||||
clear_nino_flag(ni, v3_Extensions);
|
||||
ni->owner_id = 0;
|
||||
ni->security_id = 0;
|
||||
ni->owner_id = const_cpu_to_le32(0);
|
||||
ni->security_id = const_cpu_to_le32(0);
|
||||
}
|
||||
/* Set attribute list information. */
|
||||
olderrno = errno;
|
||||
if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
|
||||
ctx)) {
|
||||
if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
if (errno != ENOENT)
|
||||
goto put_err_out;
|
||||
/* Attribute list attribute does not present. */
|
||||
|
@ -268,6 +270,7 @@ get_size:
|
|||
ni->data_size = le32_to_cpu(ctx->attr->value_length);
|
||||
ni->allocated_size = (ni->data_size + 7) & ~7;
|
||||
}
|
||||
set_nino_flag(ni,KnownSize);
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
out:
|
||||
|
@ -306,7 +309,8 @@ err_out:
|
|||
* EINVAL @ni is invalid (probably it is an extent inode).
|
||||
* EIO I/O error while trying to write inode to disk.
|
||||
*/
|
||||
int ntfs_inode_close(ntfs_inode *ni)
|
||||
|
||||
int ntfs_inode_real_close(ntfs_inode *ni)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
|
@ -326,7 +330,7 @@ int ntfs_inode_close(ntfs_inode *ni)
|
|||
/* Is this a base inode with mapped extent inodes? */
|
||||
if (ni->nr_extents > 0) {
|
||||
while (ni->nr_extents > 0) {
|
||||
if (ntfs_inode_close(ni->extent_nis[0])) {
|
||||
if (ntfs_inode_real_close(ni->extent_nis[0])) {
|
||||
if (errno != EIO)
|
||||
errno = EBUSY;
|
||||
goto err;
|
||||
|
@ -366,8 +370,10 @@ int ntfs_inode_close(ntfs_inode *ni)
|
|||
/* Ignore errors, they don't really matter. */
|
||||
if (tmp_nis)
|
||||
base_ni->extent_nis = tmp_nis;
|
||||
} else if (tmp_nis)
|
||||
} else if (tmp_nis) {
|
||||
free(tmp_nis);
|
||||
base_ni->extent_nis = (ntfs_inode**)NULL;
|
||||
}
|
||||
/* Allow for error checking. */
|
||||
i = -1;
|
||||
break;
|
||||
|
@ -389,6 +395,154 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if CACHE_NIDATA_SIZE
|
||||
|
||||
/*
|
||||
* Free an inode structure when there is not more space
|
||||
* in the cache
|
||||
*/
|
||||
|
||||
void ntfs_inode_nidata_free(const struct CACHED_GENERIC *cached)
|
||||
{
|
||||
ntfs_inode_real_close(((const struct CACHED_NIDATA*)cached)->ni);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute a hash value for an inode entry
|
||||
*/
|
||||
|
||||
int ntfs_inode_nidata_hash(const struct CACHED_GENERIC *item)
|
||||
{
|
||||
return (((const struct CACHED_NIDATA*)item)->inum
|
||||
% (2*CACHE_NIDATA_SIZE));
|
||||
}
|
||||
|
||||
/*
|
||||
* inum comparing for entering/fetching from cache
|
||||
*/
|
||||
|
||||
static int idata_cache_compare(const struct CACHED_GENERIC *cached,
|
||||
const struct CACHED_GENERIC *wanted)
|
||||
{
|
||||
return (((const struct CACHED_NIDATA*)cached)->inum
|
||||
!= ((const struct CACHED_NIDATA*)wanted)->inum);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate an inode entry when not needed anymore.
|
||||
* The entry should have been synced, it may be reused later,
|
||||
* if it is requested before it is dropped from cache.
|
||||
*/
|
||||
|
||||
void ntfs_inode_invalidate(ntfs_volume *vol, const MFT_REF mref)
|
||||
{
|
||||
struct CACHED_NIDATA item;
|
||||
int count;
|
||||
|
||||
item.inum = MREF(mref);
|
||||
item.ni = (ntfs_inode*)NULL;
|
||||
item.pathname = (const char*)NULL;
|
||||
item.varsize = 0;
|
||||
count = ntfs_invalidate_cache(vol->nidata_cache,
|
||||
GENERIC(&item),idata_cache_compare,CACHE_FREE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Open an inode
|
||||
*
|
||||
* When possible, an entry recorded in the cache is reused
|
||||
*
|
||||
* **NEVER REOPEN** an inode, this can lead to a duplicated
|
||||
* cache entry (hard to detect), and to an obsolete one being
|
||||
* reused. System files are however protected from being cached.
|
||||
*/
|
||||
|
||||
ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
#if CACHE_NIDATA_SIZE
|
||||
struct CACHED_NIDATA item;
|
||||
struct CACHED_NIDATA *cached;
|
||||
|
||||
/* fetch idata from cache */
|
||||
item.inum = MREF(mref);
|
||||
debug_double_inode(item.inum,1);
|
||||
item.pathname = (const char*)NULL;
|
||||
item.varsize = 0;
|
||||
cached = (struct CACHED_NIDATA*)ntfs_fetch_cache(vol->nidata_cache,
|
||||
GENERIC(&item),idata_cache_compare);
|
||||
if (cached) {
|
||||
ni = cached->ni;
|
||||
/* do not keep open entries in cache */
|
||||
ntfs_remove_cache(vol->nidata_cache,
|
||||
(struct CACHED_GENERIC*)cached,0);
|
||||
} else {
|
||||
ni = ntfs_inode_real_open(vol, mref);
|
||||
}
|
||||
#else
|
||||
ni = ntfs_inode_real_open(vol, mref);
|
||||
#endif
|
||||
return (ni);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close an inode entry
|
||||
*
|
||||
* If cacheing is in use, the entry is synced and kept available
|
||||
* in cache for further use.
|
||||
*
|
||||
* System files (inode < 16 or having the IS_4 flag) are protected
|
||||
* against being cached.
|
||||
*/
|
||||
|
||||
int ntfs_inode_close(ntfs_inode *ni)
|
||||
{
|
||||
int res;
|
||||
#if CACHE_NIDATA_SIZE
|
||||
BOOL dirty;
|
||||
struct CACHED_NIDATA item;
|
||||
|
||||
if (ni) {
|
||||
debug_double_inode(ni->mft_no,0);
|
||||
/* do not cache system files : could lead to double entries */
|
||||
if (ni->vol && ni->vol->nidata_cache
|
||||
&& ((ni->mft_no == FILE_root)
|
||||
|| ((ni->mft_no >= FILE_first_user)
|
||||
&& !(ni->mrec->flags & MFT_RECORD_IS_4)))) {
|
||||
/* If we have dirty metadata, write it out. */
|
||||
dirty = NInoDirty(ni) || NInoAttrListDirty(ni);
|
||||
if (dirty) {
|
||||
res = ntfs_inode_sync(ni);
|
||||
/* do a real close if sync failed */
|
||||
if (res)
|
||||
ntfs_inode_real_close(ni);
|
||||
} else
|
||||
res = 0;
|
||||
|
||||
if (!res) {
|
||||
/* feed idata into cache */
|
||||
item.inum = ni->mft_no;
|
||||
item.ni = ni;
|
||||
item.pathname = (const char*)NULL;
|
||||
item.varsize = 0;
|
||||
debug_cached_inode(ni);
|
||||
ntfs_enter_cache(ni->vol->nidata_cache,
|
||||
GENERIC(&item), idata_cache_compare);
|
||||
}
|
||||
} else {
|
||||
/* cache not ready or system file, really close */
|
||||
res = ntfs_inode_real_close(ni);
|
||||
}
|
||||
} else
|
||||
res = 0;
|
||||
#else
|
||||
res = ntfs_inode_real_close(ni);
|
||||
#endif
|
||||
return (res);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_extent_inode_open - load an extent inode and attach it to its base
|
||||
* @base_ni: base ntfs inode
|
||||
|
@ -669,8 +823,13 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||
fnx->file_attributes =
|
||||
(fnx->file_attributes & ~FILE_ATTR_VALID_FLAGS) |
|
||||
(ni->flags & FILE_ATTR_VALID_FLAGS);
|
||||
fnx->allocated_size = cpu_to_sle64(ni->allocated_size);
|
||||
fnx->data_size = cpu_to_sle64(ni->data_size);
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||
fnx->data_size = fnx->allocated_size
|
||||
= const_cpu_to_le64(0);
|
||||
else {
|
||||
fnx->allocated_size = cpu_to_sle64(ni->allocated_size);
|
||||
fnx->data_size = cpu_to_sle64(ni->data_size);
|
||||
}
|
||||
if (!test_nino_flag(ni, TimesSet)) {
|
||||
fnx->creation_time = utc2ntfs(ni->creation_time);
|
||||
fnx->last_data_change_time = utc2ntfs(ni->last_data_change_time);
|
||||
|
@ -1327,14 +1486,27 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
|||
/*
|
||||
* Mark times set to avoid overwriting
|
||||
* them when the inode is closed.
|
||||
* The inode structure must also be updated
|
||||
* (with loss of precision) because of cacheing.
|
||||
* TODO : use NTFS precision in inode, and
|
||||
* return sub-second times in getattr()
|
||||
*/
|
||||
set_nino_flag(ni, TimesSet);
|
||||
std_info->creation_time = cpu_to_le64(times[0]);
|
||||
if (size >= 16)
|
||||
ni->creation_time
|
||||
= ntfs2utc(std_info->creation_time);
|
||||
if (size >= 16) {
|
||||
std_info->last_data_change_time = cpu_to_le64(times[1]);
|
||||
if (size >= 24)
|
||||
ni->last_data_change_time
|
||||
= ntfs2utc(std_info->last_data_change_time);
|
||||
}
|
||||
if (size >= 24) {
|
||||
std_info->last_access_time = cpu_to_le64(times[2]);
|
||||
ni->last_access_time
|
||||
= ntfs2utc(std_info->last_access_time);
|
||||
}
|
||||
std_info->last_mft_change_time = now;
|
||||
ni->last_mft_change_time = ntfs2utc(now);
|
||||
ntfs_inode_mark_dirty(ctx->ntfs_ino);
|
||||
NInoFileNameSetDirty(ni);
|
||||
|
||||
|
@ -1365,7 +1537,7 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
|||
}
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (size < 8)
|
||||
errno = ERANGE;
|
||||
|
|
|
@ -1860,7 +1860,11 @@ int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni)
|
|||
}
|
||||
|
||||
/* Throw away the now freed inode. */
|
||||
#if CACHE_NIDATA_SIZE
|
||||
if (!ntfs_inode_real_close(ni)) {
|
||||
#else
|
||||
if (!ntfs_inode_close(ni)) {
|
||||
#endif
|
||||
vol->free_mft_records++;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -714,12 +714,18 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
|||
} else {
|
||||
/* Directory. */
|
||||
stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask);
|
||||
na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
|
||||
if (na) {
|
||||
stbuf->st_size = na->data_size;
|
||||
stbuf->st_blocks = na->allocated_size >> 9;
|
||||
ntfs_attr_close(na);
|
||||
/* get index size, if not known */
|
||||
if (!test_nino_flag(ni, KnownSize)) {
|
||||
na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
|
||||
if (na) {
|
||||
ni->data_size = na->data_size;
|
||||
ni->allocated_size = na->allocated_size;
|
||||
set_nino_flag(ni, KnownSize);
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
}
|
||||
stbuf->st_size = ni->data_size;
|
||||
stbuf->st_blocks = ni->allocated_size >> 9;
|
||||
stbuf->st_nlink = 1; /* Make find(1) work */
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue