- 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
parent
7cd9b6b22d
commit
4b000b3d13
|
@ -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.
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
129
libntfs/inode.c
129
libntfs/inode.c
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue