From 6072a9559137cd1e3c1bee119a4c180caa2891f8 Mon Sep 17 00:00:00 2001 From: jpandre Date: Fri, 18 Dec 2009 08:27:05 +0000 Subject: [PATCH] Cached looked-up inodes for subsequent use --- include/ntfs-3g/dir.h | 3 + include/ntfs-3g/param.h | 3 + include/ntfs-3g/volume.h | 3 + libntfs-3g/cache.c | 10 +++ libntfs-3g/dir.c | 163 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 180 insertions(+), 2 deletions(-) diff --git a/include/ntfs-3g/dir.h b/include/ntfs-3g/dir.h index c23171e9..56e76fe7 100644 --- a/include/ntfs-3g/dir.h +++ b/include/ntfs-3g/dir.h @@ -61,6 +61,9 @@ extern ntfschar NTFS_INDEX_R[3]; extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname, const int uname_len); +extern u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name); +extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name, + u64 inum); extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, const char *pathname); diff --git a/include/ntfs-3g/param.h b/include/ntfs-3g/param.h index 8d2b989f..07bc7a80 100644 --- a/include/ntfs-3g/param.h +++ b/include/ntfs-3g/param.h @@ -24,10 +24,13 @@ #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_LOOKUP_SIZE 64 /* lookup 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 */ #define FORCE_FORMAT_v1x 0 /* Insert security data as in NTFS v1.x */ #define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */ +#define FULLCOLLATE 1 + #endif /* defined _NTFS_PARAM_H */ diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h index 2e11c022..253e482b 100644 --- a/include/ntfs-3g/volume.h +++ b/include/ntfs-3g/volume.h @@ -235,6 +235,9 @@ struct _ntfs_volume { #if CACHE_NIDATA_SIZE struct CACHE_HEADER *nidata_cache; #endif +#if CACHE_LOOKUP_SIZE + struct CACHE_HEADER *lookup_cache; +#endif #if CACHE_SECURID_SIZE struct CACHE_HEADER *securid_cache; #endif diff --git a/libntfs-3g/cache.c b/libntfs-3g/cache.c index 5e15fc0c..dd147672 100644 --- a/libntfs-3g/cache.c +++ b/libntfs-3g/cache.c @@ -571,6 +571,13 @@ void ntfs_create_lru_caches(ntfs_volume *vol) ntfs_inode_nidata_free, ntfs_inode_nidata_hash, sizeof(struct CACHED_NIDATA), CACHE_NIDATA_SIZE, 2*CACHE_NIDATA_SIZE); +#endif +#if CACHE_LOOKUP_SIZE + /* lookup cache */ + vol->lookup_cache = ntfs_create_cache("lookup", + (cache_free)NULL, ntfs_dir_lookup_hash, + sizeof(struct CACHED_LOOKUP), + CACHE_LOOKUP_SIZE, 2*CACHE_LOOKUP_SIZE); #endif vol->securid_cache = ntfs_create_cache("securid",(cache_free)NULL, (cache_hash)NULL,sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0); @@ -591,6 +598,9 @@ void ntfs_free_lru_caches(ntfs_volume *vol) #endif #if CACHE_NIDATA_SIZE ntfs_free_cache(vol->nidata_cache); +#endif +#if CACHE_LOOKUP_SIZE + ntfs_free_cache(vol->lookup_cache); #endif ntfs_free_cache(vol->securid_cache); #if CACHE_LEGACY_SIZE diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index 196e7d41..e629ed0f 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -158,6 +158,65 @@ static int inode_cache_inv_compare(const struct CACHED_GENERIC *cached, #endif +#if CACHE_LOOKUP_SIZE + +/* + * File name comparing for entering/fetching from lookup cache + */ + +static int lookup_cache_compare(const struct CACHED_GENERIC *cached, + const struct CACHED_GENERIC *wanted) +{ + const struct CACHED_LOOKUP *c = (const struct CACHED_LOOKUP*) cached; + const struct CACHED_LOOKUP *w = (const struct CACHED_LOOKUP*) wanted; + return (!c->name + || (c->parent != w->parent) + || (c->namesize != w->namesize) + || memcmp(c->name, w->name, c->namesize)); +} + +/* + * Inode number comparing for invalidating lookup cache + * + * All entries with designated inode number are invalidated + * + * Only use associated with a CACHE_NOHASH flag + */ + +static int lookup_cache_inv_compare(const struct CACHED_GENERIC *cached, + const struct CACHED_GENERIC *wanted) +{ + const struct CACHED_LOOKUP *c = (const struct CACHED_LOOKUP*) cached; + const struct CACHED_LOOKUP *w = (const struct CACHED_LOOKUP*) wanted; + return (!c->name + || (c->parent != w->parent) + || (MREF(c->inum) != MREF(w->inum))); +} + +/* + * Lookup hashing + * + * Based on first, second and and last char + */ + +int ntfs_dir_lookup_hash(const struct CACHED_GENERIC *cached) +{ + const unsigned char *name; + int count; + unsigned int val; + + name = (const unsigned char*)cached->variable; + count = cached->varsize; + if (!name || !count) { + ntfs_log_error("Bad lookup cache entry\n"); + return (-1); + } + val = (name[0] << 2) + (name[1] << 1) + name[count - 1] + count; + return (val % (2*CACHE_LOOKUP_SIZE)); +} + +#endif + /** * ntfs_inode_lookup_by_name - find an inode in a directory given its name * @dir_ni: ntfs inode of the directory in which to search for the name @@ -183,8 +242,8 @@ static int inode_cache_inv_compare(const struct CACHED_GENERIC *cached, * If the volume is mounted with the case sensitive flag set, then we only * allow exact matches. */ -u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname, - const int uname_len) +u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, + const ntfschar *uname, const int uname_len) { VCN vcn; u64 mref = 0; @@ -472,6 +531,94 @@ close_err_out: goto eo_put_err_out; } +/* + * Lookup a file in a directory from its UTF-8 name + * + * The name is first fetched from cache if one is defined + * + * Returns the inode number + * or -1 if not possible (errno tells why) + */ + +u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name) +{ + int uname_len; + ntfschar *uname = (ntfschar*)NULL; + u64 inum; +#if CACHE_LOOKUP_SIZE + struct CACHED_LOOKUP item; + struct CACHED_LOOKUP *cached; + + /* + * fetch inode from cache + */ + + if (dir_ni->vol->lookup_cache) { + item.name = name; + item.namesize = strlen(name) + 1; + item.parent = dir_ni->mft_no; + cached = (struct CACHED_LOOKUP*)ntfs_fetch_cache( + dir_ni->vol->lookup_cache, GENERIC(&item), + lookup_cache_compare); + if (cached) { + inum = cached->inum; + if (inum == (u64)-1) + errno = ENOENT; + } else { + /* Generate unicode name. */ + uname_len = ntfs_mbstoucs(name, &uname); + if (uname_len >= 0) { + inum = ntfs_inode_lookup_by_name(dir_ni, + uname, uname_len); + item.inum = inum; + /* enter into cache, even if not found */ + ntfs_enter_cache(dir_ni->vol->lookup_cache, + GENERIC(&item), + lookup_cache_compare); + free(uname); + } else + inum = (s64)-1; + } + } else +#endif + { + /* Generate unicode name. */ + uname_len = ntfs_mbstoucs(name, &uname); + if (uname_len >= 0) + inum = ntfs_inode_lookup_by_name(dir_ni, + uname, uname_len); + else + inum = (s64)-1; + } + return (inum); +} + +/* + * Update a cache lookup record when a name has been defined + * + * The UTF-8 name is required + */ + +void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name, u64 inum) +{ +#if CACHE_LOOKUP_SIZE + struct CACHED_LOOKUP item; + struct CACHED_LOOKUP *cached; + + if (dir_ni->vol->lookup_cache) { + item.name = name; + item.namesize = strlen(name) + 1; + item.parent = dir_ni->mft_no; + item.inum = inum; + cached = (struct CACHED_LOOKUP*)ntfs_enter_cache( + dir_ni->vol->lookup_cache, + GENERIC(&item), lookup_cache_compare); + if (cached) + cached->inum = inum; + } +#endif +} + /** * ntfs_pathname_to_inode - Find the inode which represents the given pathname * @vol: An ntfs volume obtained from ntfs_mount @@ -1557,6 +1704,9 @@ int ntfs_delete(ntfs_volume *vol, const char *pathname, u64 inum = (u64)-1; int count; #endif +#if CACHE_LOOKUP_SIZE + struct CACHED_LOOKUP lkitem; +#endif ntfs_log_trace("Entering.\n"); @@ -1670,6 +1820,15 @@ 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 CACHE_LOOKUP_SIZE + /* invalidate entry in lookup cache */ + lkitem.name = (const char*)NULL; + lkitem.namesize = 0; + lkitem.inum = ni->mft_no; + lkitem.parent = dir_ni->mft_no; + ntfs_invalidate_cache(vol->lookup_cache, GENERIC(&lkitem), + lookup_cache_inv_compare, CACHE_NOHASH); +#endif #if CACHE_INODE_SIZE inum = ni->mft_no; if (pathname) {