- Implement FILE_NAME attributes update in index during inode sync and enable code that set/clean sparse bit. Also add new inode state bit FileNameDirty to indicate that FILE_NAME attributes need update. At least after attribute resize we leave absolutely consist volume.

- Bugfixes to collate.c and index.c.
- Minor formating fixed to ntfscp and ntfsinfo.
edge.strict_endians
cha0smaster 2005-06-05 14:55:08 +00:00
parent 7cd9b6b22d
commit 4b000b3d13
8 changed files with 201 additions and 29 deletions

View File

@ -153,6 +153,11 @@ xx/xx/2005 - 2.0.0-WIP
ntfs_is_collation_rule_supported. (Yura)
- Port index.[ch] from kernel to library. New API's: ntfs_index_lookup,
ntfs_index_ctx_{get,put}, ntfs_index_entry_mark_dirty. (Yura)
- Implement FILE_NAME attributes update in index during inode sync and
enable code that set/clean sparse bit. Also add new inode state bit
FileNameDirty to indicate that FILE_NAME attributes need update.
At least after attribute resize we leave absolutely consist
volume. (Yura)
04/09/2004 - 1.9.4 - Urgent bug fixes.

View File

@ -45,6 +45,8 @@ typedef enum {
NI_Compressed, /* 1: Inode is compressed. */
NI_Encrypted, /* 1: Inode is encrypted. */
NI_Sparse, /* 1: Inode is sparse. */
NI_FileNameDirty, /* 1: FILE_NAME attributes need to be updated
in the index. */
} ntfs_inode_state_bits;
#define test_nino_flag(ni, flag) test_bit(NI_##flag, (ni)->state)
@ -94,6 +96,17 @@ typedef enum {
#define NInoSetSparse(ni) set_nino_flag(ni, Sparse)
#define NInoClearSparse(ni) clear_nino_flag(ni, Sparse)
#define NInoFileNameDirty(ni) \
test_nino_flag(ni, FileNameDirty)
#define NInoFileNameSetDirty(ni) \
set_nino_flag(ni, FileNameDirty)
#define NInoFileNameClearDirty(ni) \
clear_nino_flag(ni, FileNameDirty)
#define NInoFileNameTestAndSetDirty(ni) \
test_and_set_nino_flag(ni, FileNameDirty)
#define NInoFileNameTestAndClearDirty(ni) \
test_and_clear_nino_flag(ni, FileNameDirty)
/*
* The NTFS in-memory inode structure. It is just used as an extension to the
* fields already provided in the VFS inode.
@ -126,6 +139,9 @@ struct _ntfs_inode {
void *private_data; /* Temp: for directory handling */
int ref_count;
/* Belows fields needed to update indexes. They valid if != -1. */
s64 data_size;
s64 allocated_size;
};
extern ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol);

View File

@ -3976,12 +3976,6 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
* function updates sparse bit and allocates/frees space for compressed_size,
* but doesn't change it, so caller should update it manually.
*
* NOTE: Code that set/clean sparse bit currently disabled, because chkdsk
* complain if we don't update index entry's for inode to which we set sparse
* bit. But it doesn't if attribute's runlist has lcn holes and sparse bit
* isn't set. So until we have no API for updating index entries it's the best
* choice.
*
* On success return 0 and on error return -1 with errno set to the error code.
* The following error codes are defined:
* ENOMEM - Not enough memory to complete operation.
@ -4064,7 +4058,6 @@ retry:
goto put_err_out;
}
}
#if 0
/* If we in the first extent, then set/clean sparse bit. */
if (!a->lowest_vcn) {
int sparse;
@ -4130,6 +4123,13 @@ retry:
a->mapping_pairs_offset =
cpu_to_le16(le16_to_cpu(
a->mapping_pairs_offset) + 8);
/*
* Set FILE_NAME dirty flag, to update
* sparse bit in the index.
*/
if (na->type == AT_DATA &&
na->name == AT_UNNAMED)
NInoFileNameSetDirty(na->ni);
}
if (!sparse && (a->flags & ATTR_IS_SPARSE) &&
!(a->flags & ATTR_IS_COMPRESSED)) {
@ -4144,9 +4144,15 @@ retry:
a->mapping_pairs_offset =
cpu_to_le16(le16_to_cpu(
a->mapping_pairs_offset) - 8);
/*
* Set FILE_NAME dirty flag, to update
* sparse bit in the index.
*/
if (na->type == AT_DATA &&
na->name == AT_UNNAMED)
NInoFileNameSetDirty(na->ni);
}
}
#endif
/* Get the size for the rest of mapping pairs array. */
mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, na->rl,
stop_vcn);
@ -4811,6 +4817,8 @@ put_err_out:
*/
int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
{
int ret;
if (!na || newsize < 0 ||
(na->ni->mft_no == FILE_MFT && na->type == AT_DATA)) {
Dprintf("%s(): Invalid aruments passed.\n", __FUNCTION__);
@ -4837,9 +4845,24 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
}
if (NAttrNonResident(na)) {
if (newsize > na->data_size)
return ntfs_non_resident_attr_expand(na, newsize);
ret = ntfs_non_resident_attr_expand(na, newsize);
else
return ntfs_non_resident_attr_shrink(na, newsize);
ret = ntfs_non_resident_attr_shrink(na, newsize);
} else
ret = ntfs_resident_attr_resize(na, newsize);
/* Set FILE_NAME dirty flag, to update file length in the index. */
if (na->type == AT_DATA && na->name == AT_UNNAMED) {
NInoFileNameSetDirty(na->ni);
na->ni->data_size = na->data_size;
/*
* If attribute sparse or commpreseed then allocated size in
* index should be euqal to compressed size, not to allocated
* size.
*/
if (NAttrCompressed(na) || NAttrSparse(na))
na->ni->allocated_size = na->compressed_size;
else
na->ni->allocated_size = na->allocated_size;
}
return ntfs_resident_attr_resize(na, newsize);
return ret;
}

View File

@ -79,7 +79,7 @@ static int ntfs_collate_file_name(ntfs_volume *vol,
fn2 = (const FILE_NAME_ATTR *)data2;
rc = ntfs_names_collate(fn1->file_name, fn1->file_name_length,
fn2->file_name, fn2->file_name_length,
NTFS_COLLATION_ERROR, CASE_SENSITIVE, vol->upcase,
NTFS_COLLATION_ERROR, IGNORE_CASE, vol->upcase,
vol->upcase_len);
ntfs_debug("Done, returning %i.", rc);
return rc;

View File

@ -26,6 +26,7 @@
#include "collate.h"
#include "debug.h"
#include "index.h"
#include "mst.h"
/**
* ntfs_index_ctx_get - allocate and initialize a new index context
@ -71,14 +72,15 @@ void ntfs_index_ctx_put(ntfs_index_context *ictx)
ntfs_attr_put_search_ctx(ictx->actx);
} else {
/* Write out index block it it's dirty. */
if (ictx->ia_dirty)
if (ntfs_attr_pwrite(ictx->ia_na,
if (ictx->ia_dirty) {
if (ntfs_attr_mst_pwrite(ictx->ia_na,
ictx->ia_vcn <<
ictx->ni->vol->cluster_size,
ictx->ni->vol->cluster_size, 1,
ictx->block_size, ictx->ia) !=
ictx->block_size)
1)
ntfs_error(, "Failed to write out "
"index block.");
}
/* Free resources. */
free(ictx->ia);
ntfs_attr_close(ictx->ia_na);
@ -264,12 +266,13 @@ done:
goto err_out;
}
descend_into_child_node:
ntfs_debug("Descend into node with VCN %lld.", vcn);
/* Read index allocation block. */
if (ntfs_attr_pread(na, vcn << vol->cluster_size_bits, ictx->block_size,
ia) != ictx->block_size) {
if (ntfs_attr_mst_pread(na, vcn << vol->cluster_size_bits, 1,
ictx->block_size, ia) != 1) {
ntfs_error(, "Failed to read index allocation.");
goto err_out;
}
}
/* Catch multi sector transfer fixup errors. */
if (!ntfs_is_indx_record(ia->magic)) {
ntfs_error(sb, "Index record with vcn 0x%llx is corrupt. "
@ -392,3 +395,4 @@ idx_err_out:
ntfs_error(sb, "Corrupt index. Aborting lookup.");
goto err_out;
}

View File

@ -36,6 +36,8 @@
#include "attrlist.h"
#include "runlist.h"
#include "lcnalloc.h"
#include "index.h"
#include "dir.h"
/**
* Internal:
@ -123,6 +125,8 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
if (!(ni->mrec->flags & MFT_RECORD_IN_USE))
goto err_out;
ni->mft_no = MREF(mref);
ni->data_size = -1;
ni->allocated_size = -1;
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx)
goto err_out;
@ -453,6 +457,113 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni) {
return 0;
}
/**
* ntfs_inode_sync_standard_information - update FILE_NAME attribute's
* @ni: ntfs inode to update FILE_NAME attribute's
*
* Update all FILE_NAME attribute's for inode @ni in the index.
*
* Return 0 on success or -1 on error with errno set to the error code.
*/
static int ntfs_inode_sync_file_name(ntfs_inode *ni) {
ntfs_attr_search_ctx *ctx = NULL;
ntfs_index_context *ictx;
ntfs_inode *index_ni;
FILE_NAME_ATTR *fn;
int err = 0;
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx) {
err = errno;
Dprintf("%s(): Failed to get attribute search context.\n",
__FUNCTION__);
goto err_out;
}
/* Walk through all FILE_NAME attributes and update them. */
while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) {
fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr +
le16_to_cpu(ctx->attr->value_offset));
if (MREF_LE(fn->parent_directory) == ni->mft_no) {
/*
* WARNING: We cheater here and obtain 2 attribute
* search contextes for one inode (first we obtained
* above, second will be obtained inside
* ntfs_index_lookup), it's acceptable for library,
* but will lock kernel.
*/
index_ni = ni;
} else
index_ni = ntfs_inode_open(ni->vol,
le64_to_cpu(fn->parent_directory));
if (!index_ni) {
if (!err)
err = errno;
Dprintf("%s(): Failed to open inode with index.\n",
__FUNCTION__);
continue;
}
ictx = ntfs_index_ctx_get(index_ni, I30, 4);
if (!ictx) {
if (!err)
err = errno;
Dprintf("%s(): Failed to get index context.\n",
__FUNCTION__);
ntfs_inode_close(index_ni);
continue;
}
if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) {
if (!err) {
if (errno == ENOENT)
err = EIO;
else
err = errno;
}
Dprintf("%s(): Index lookup failed.\n", __FUNCTION__);
ntfs_index_ctx_put(ictx);
ntfs_inode_close(index_ni);
continue;
}
/* Update flags and file size. */
fn = (FILE_NAME_ATTR *)ictx->data;
if (NInoCompressed(ni))
fn->file_attributes |= FILE_ATTR_COMPRESSED;
else
fn->file_attributes &= ~FILE_ATTR_COMPRESSED;
if (NInoEncrypted(ni))
fn->file_attributes |= FILE_ATTR_ENCRYPTED;
else
fn->file_attributes &= ~FILE_ATTR_ENCRYPTED;
if (NInoSparse(ni))
fn->file_attributes |= FILE_ATTR_SPARSE_FILE;
else
fn->file_attributes &= ~FILE_ATTR_SPARSE_FILE;
if (ni->allocated_size != -1)
fn->allocated_size = cpu_to_sle64(ni->allocated_size);
if (ni->data_size != -1)
fn->data_size = cpu_to_sle64(ni->data_size);
ntfs_index_entry_mark_dirty(ictx);
ntfs_index_ctx_put(ictx);
ntfs_inode_close(index_ni);
}
/* Check for real error occured. */
if (errno != ENOENT) {
err = errno;
Dprintf("%s(): Attribute lookup failed.\n", __FUNCTION__);
goto err_out;
}
ntfs_attr_put_search_ctx(ctx);
if (err) {
errno = err;
return -1;
}
return 0;
err_out:
if (ctx)
ntfs_attr_put_search_ctx(ctx);
errno = err;
return -1;
}
/**
* ntfs_inode_sync - write the inode (and its dirty extents) to disk
* @ni: ntfs inode to write
@ -480,7 +591,7 @@ int ntfs_inode_sync(ntfs_inode *ni)
errno = EINVAL;
return -1;
}
Dprintf("%s(): Entering for inode 0x%llx.\n",
__FUNCTION__, (long long) ni->mft_no);
@ -495,6 +606,19 @@ int ntfs_inode_sync(ntfs_inode *ni)
__FUNCTION__);
}
/* Update FILE_NAME's in the index. */
if (ni->nr_extents != -1 && NInoFileNameTestAndClearDirty(ni) &&
ntfs_inode_sync_file_name(ni)) {
if (!err || errno == EIO) {
err = errno;
if (err != EIO)
err = EBUSY;
}
Dprintf("%s(): Failed to sync FILE_NAME attributes.\n",
__FUNCTION__);
NInoFileNameSetDirty(ni);
}
/* Write out attribute list from cache to disk. */
if (ni->nr_extents != -1 && NInoAttrList(ni) &&
NInoAttrListTestAndClearDirty(ni)) {
@ -522,7 +646,6 @@ int ntfs_inode_sync(ntfs_inode *ni)
Dprintf("%s(): Attribute list "
"sync failed (write failed).\n",
__FUNCTION__);
}
NInoAttrListSetDirty(ni);
}
@ -574,8 +697,6 @@ int ntfs_inode_sync(ntfs_inode *ni)
}
}
// TODO: Update FILE_NAME attribute in the index.
if (!err)
return 0;
errno = err;

View File

@ -273,7 +273,7 @@ int main (int argc, char *argv[])
return 1;
utils_set_locale();
/* Set SIGINT handler. */
if (signal(SIGINT, sigint_handler) == SIG_ERR) {
perror("Failed to set SIGINT handler");
@ -288,7 +288,7 @@ int main (int argc, char *argv[])
perror("ERROR: couldn't mount volume");
return 1;
}
if ((vol->flags & VOLUME_IS_DIRTY) && (!opts.force))
goto umount;
@ -382,7 +382,7 @@ int main (int argc, char *argv[])
goto close_dst;
}
}
Vprintf("Old file size: %lld\n", na->data_size);
if (na->data_size != new_size) {
if (ntfs_attr_truncate(na, new_size)) {

View File

@ -1390,9 +1390,12 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni)
printf("\tIndex name:\t\t '%s'\n",index_name);
free(index_name);
} else {
/* an error occured, errno holds the reason - notify the user */
fprintf(stderr, "ntfsinfo error: could not parse index name: %s\n",
strerror(errno));
/*
* An error occured, errno holds the reason -
* notify the user
*/
fprintf(stderr, "ntfsinfo error: could not parse "
"index name: %s\n", strerror(errno));
}
} else {
printf("\tIndex name:\t\t unnamed\n");