parent
09ec84d205
commit
19fcf9b688
|
@ -1,3 +1,6 @@
|
|||
03/12/2003 - 1.x.x - WIP
|
||||
- Add new API function attrib.[hc]:ntfs_attr_map_whole_runlist().
|
||||
|
||||
19/11/2003 - 1.8.0 - Final fixes and tidy ups.
|
||||
- Cleanup build system wrt CFLAGS handling placing it all in one place
|
||||
in configure.ac and removing everything related from the Makefile.am
|
||||
|
|
|
@ -253,6 +253,7 @@ extern s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos,
|
|||
s64 bk_cnt, const u32 bk_size, void *src);
|
||||
|
||||
extern int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn);
|
||||
extern int ntfs_attr_map_whole_runlist(ntfs_attr *na);
|
||||
|
||||
extern LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn);
|
||||
extern runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn);
|
||||
|
|
128
libntfs/attrib.c
128
libntfs/attrib.c
|
@ -438,6 +438,114 @@ int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute
|
||||
* @na: ntfs attribute for which to map the runlist
|
||||
*
|
||||
* Map the whole runlist of an the ntfs attribute @na. For an attribute made
|
||||
* up of only one attribute extent this is the same as calling
|
||||
* ntfs_attr_map_runlist(na, 0) but for an attribute with multiple extents this
|
||||
* will map the runlist fragments from each of the extents thus giving access
|
||||
* to the entirety of the disk allocation of an attribute.
|
||||
*
|
||||
* Return 0 on success and -1 on error with errno set to the error code.
|
||||
*/
|
||||
int ntfs_attr_map_whole_runlist(ntfs_attr *na)
|
||||
{
|
||||
VCN next_vcn, last_vcn, highest_vcn;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ntfs_volume *vol = na->ni->vol;
|
||||
ATTR_RECORD *a;
|
||||
int err;
|
||||
|
||||
Dprintf("%s(): Entering for inode 0x%Lx, attr 0x%x.\n", __FUNCTION__,
|
||||
(unsigned long long)na->ni->mft_no, na->type);
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||
if (!ctx)
|
||||
return -1;
|
||||
|
||||
/* Map all attribute extents one by one. */
|
||||
next_vcn = last_vcn = highest_vcn = 0;
|
||||
a = NULL;
|
||||
while (!ntfs_attr_lookup(na->type, na->name, na->name_len,
|
||||
CASE_SENSITIVE, next_vcn, NULL, 0, ctx)) {
|
||||
runlist_element *rl;
|
||||
|
||||
a = ctx->attr;
|
||||
|
||||
/* Decode the runlist. */
|
||||
rl = ntfs_mapping_pairs_decompress(na->ni->vol, a, na->rl);
|
||||
if (!rl)
|
||||
goto err_out;
|
||||
na->rl = rl;
|
||||
|
||||
/* Are we in the first extent? */
|
||||
if (!next_vcn) {
|
||||
if (a->lowest_vcn) {
|
||||
Dprintf("%s(): First extent of attribute "
|
||||
"has non zero lowest_vcn. "
|
||||
"Inode is corrupt.\n",
|
||||
__FUNCTION__);
|
||||
errno = EIO;
|
||||
goto err_out;
|
||||
}
|
||||
/* Get the last vcn in the attribute. */
|
||||
last_vcn = sle64_to_cpu(a->allocated_size) >>
|
||||
vol->cluster_size_bits;
|
||||
}
|
||||
|
||||
/* Get the lowest vcn for the next extent. */
|
||||
highest_vcn = sle64_to_cpu(a->highest_vcn);
|
||||
next_vcn = highest_vcn + 1;
|
||||
|
||||
/* Only one extent or error, which we catch below. */
|
||||
if (next_vcn <= 0) {
|
||||
errno = ENOENT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Avoid endless loops due to corruption. */
|
||||
if (next_vcn < sle64_to_cpu(a->lowest_vcn)) {
|
||||
Dprintf("%s(): Inode has corrupt attribute list "
|
||||
"attribute.\n", __FUNCTION__);
|
||||
errno = EIO;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
if (!a) {
|
||||
err = errno;
|
||||
if (err == ENOENT)
|
||||
Dprintf("%s(): Attribute not found. Inode is "
|
||||
"corrupt.\n", __FUNCTION__);
|
||||
else
|
||||
Dprintf("%s(): Inode is corrupt.\n", __FUNCTION__);
|
||||
errno = err;
|
||||
goto err_out;
|
||||
}
|
||||
if (highest_vcn && highest_vcn != last_vcn - 1) {
|
||||
Dprintf("%s(): Failed to load the complete run list for the "
|
||||
"attribute. Bug or corrupt inode.\n",
|
||||
__FUNCTION__);
|
||||
Dprintf("%s(): highest_vcn = 0x%Lx, last_vcn - 1 = 0x%Lx\n",
|
||||
__FUNCTION__, (long long)highest_vcn,
|
||||
(long long)last_vcn - 1);
|
||||
errno = EIO;
|
||||
goto err_out;
|
||||
}
|
||||
err = errno;
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
if (err == ENOENT)
|
||||
return 0;
|
||||
out_now:
|
||||
errno = err;
|
||||
return -1;
|
||||
err_out:
|
||||
err = errno;
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
goto out_now;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_attr_vcn_to_lcn - convert a vcn into a lcn given an ntfs attribute
|
||||
* @na: ntfs attribute whose runlist to use for conversion
|
||||
|
@ -2527,6 +2635,8 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
|
|||
{
|
||||
ntfs_volume *vol = na->ni->vol;
|
||||
ATTR_REC *a = ctx->attr;
|
||||
int name_ofs, val_ofs;
|
||||
s64 arec_size;
|
||||
|
||||
/* Some preliminary sanity checking. */
|
||||
if (!NAttrNonResident(na)) {
|
||||
|
@ -2569,10 +2679,22 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Is there enough space for the attribute to be resident?
|
||||
// If not: errno = ENOSPC; return -1;
|
||||
/* Work out offsets into and size of the resident attribute. */
|
||||
name_ofs = 24; /* = sizeof(resident_ATTR_REC); */
|
||||
val_ofs = (name_ofs + a->name_length + 7) & ~7;
|
||||
arec_size = (val_ofs + na->data_size + 7) & ~7;
|
||||
|
||||
/* Read and cache the whole runlist if not already done. */
|
||||
if (ntfs_attr_map_whole_runlist(na))
|
||||
return -1;
|
||||
|
||||
// Can be done by ntfs_attr_record_resize() itself!
|
||||
if (ctx->mrec->bytes_in_use - le32_to_cpu(a->length) + arec_size >
|
||||
ctx->mrec->bytes_allocated) {
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read and cache runlist if not already done.
|
||||
|
||||
// Convert to resident attribute & resize attribute record.
|
||||
|
||||
|
|
Loading…
Reference in New Issue