Factor ntfs_attr_fill_hole() out of ntfs_attr_pwrite(). (Szaka)

edge.strict_endians
uvman 2006-11-01 20:20:18 +00:00
parent 1598a68d67
commit be6b5ce977
2 changed files with 161 additions and 164 deletions

View File

@ -62,6 +62,7 @@ xx/xx/2006 - x.xx.x - .
- Move ntfs_index_entry_mark_dirty() to index.c. (Szaka)
- Introduce misc.c. Move ntfs_[mc]alloc there. (Szaka)
- Change malloc() calls to ntfs_malloc(). (Szaka)
- Factor ntfs_attr_fill_hole() out of ntfs_attr_pwrite(). (Szaka)
21/06/2006 - 1.13.1 - Various fixes.

View File

@ -921,6 +921,154 @@ rl_err_out:
return -1;
}
static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs,
runlist_element **rl, VCN *update_from)
{
s64 to_write;
ntfs_volume *vol = na->ni->vol;
int eo, ret = -1;
runlist *rlc;
LCN lcn_seek_from = -1;
VCN cur_vcn, from_vcn;
to_write = min(count, ((*rl)->length << vol->cluster_size_bits) - *ofs);
/* Instantiate the hole. */
cur_vcn = (*rl)->vcn;
from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits);
ntfs_log_trace("Instantiate the hole with vcn 0x%llx.\n", cur_vcn);
/*
* Map whole runlist to be able update mapping pairs
* later.
*/
if (ntfs_attr_map_whole_runlist(na))
goto err_out;
/*
* Restore @*rl, it probably get lost during runlist
* mapping.
*/
*rl = ntfs_attr_find_vcn(na, cur_vcn);
if (!*rl) {
ntfs_log_error("Failed to find run after mapping runlist. "
"Please report to %s.\n", NTFS_DEV_LIST);
errno = EIO;
goto err_out;
}
/*
* Search backwards to find the best lcn to start
* seek from.
*/
rlc = *rl;
while (rlc->vcn) {
rlc--;
if (rlc->lcn >= 0) {
lcn_seek_from = rlc->lcn + (from_vcn - rlc->vcn);
break;
}
}
if (lcn_seek_from == -1) {
/* Backwards search failed, search forwards. */
rlc = *rl;
while (rlc->length) {
rlc++;
if (rlc->lcn >= 0) {
lcn_seek_from = rlc->lcn -
(rlc->vcn - from_vcn);
break;
}
}
}
/* Allocate clusters to instantiate the hole. */
rlc = ntfs_cluster_alloc(vol, from_vcn,
((*ofs + to_write - 1) >>
vol->cluster_size_bits) + 1 +
(*rl)->vcn - from_vcn,
lcn_seek_from, DATA_ZONE);
if (!rlc) {
ntfs_log_perror("Hole filling cluster allocation failed");
goto err_out;
}
/* Merge runlists. */
*rl = ntfs_runlists_merge(na->rl, rlc);
if (!*rl) {
eo = errno;
ntfs_log_trace("Failed to merge runlists.\n");
if (ntfs_cluster_free_from_rl(vol, rlc)) {
ntfs_log_trace("Failed to free just "
"allocated clusters. Leaving "
"inconsistent metadata. "
"Run chkdsk\n");
}
errno = eo;
goto err_out;
}
na->rl = *rl;
if (*update_from == -1)
*update_from = from_vcn;
*rl = ntfs_attr_find_vcn(na, cur_vcn);
if (!*rl) {
/*
* It's definitely a BUG, if we failed to find @cur_vcn, because
* we missed it during instantiating of the hole.
*/
ntfs_log_error("BUG! Failed to find run after hole "
"instantiating. Please report to the %s.\n",
NTFS_DEV_LIST);
errno = EIO;
goto err_out;
}
/* If leaved part of the hole go to the next run. */
if ((*rl)->lcn < 0)
(*rl)++;
/* Now LCN shoudn't be less than 0. */
if ((*rl)->lcn < 0) {
ntfs_log_error("BUG! LCN is lesser than 0. "
"Please report to the %s.\n", NTFS_DEV_LIST);
errno = EIO;
goto err_out;
}
if (*ofs) {
/*
* Need to clear region between start of
* @cur_vcn cluster and @*ofs.
*/
char *buf;
buf = ntfs_malloc(*ofs);
if (!buf) {
errno = ENOMEM;
goto err_out;
}
memset(buf, 0, *ofs);
if (ntfs_rl_pwrite(vol, na->rl, cur_vcn <<
vol->cluster_size_bits, *ofs, buf) < 0) {
eo = errno;
ntfs_log_perror("Failed to zero area");
free(buf);
errno = eo;
goto err_out;
}
free(buf);
}
if ((*rl)->vcn < cur_vcn) {
/*
* Clusters that replaced hole are merged with
* previous run, so we need to update offset.
*/
*ofs += (cur_vcn - (*rl)->vcn) << vol->cluster_size_bits;
}
if ((*rl)->vcn > cur_vcn) {
/*
* We left part of the hole, so we need to update the offset.
*/
*ofs -= ((*rl)->vcn - cur_vcn) << vol->cluster_size_bits;
}
ret = 0;
err_out:
return ret;
}
/**
* ntfs_attr_pwrite - positioned write to an ntfs attribute
* @na: ntfs attribute to write to
@ -942,7 +1090,8 @@ rl_err_out:
*/
s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
{
s64 written, to_write, ofs, total, old_initialized_size, old_data_size;
s64 written, to_write, ofs, old_initialized_size, old_data_size;
s64 total = 0;
VCN update_from = -1;
ntfs_volume *vol;
ntfs_attr_search_ctx *ctx = NULL;
@ -951,8 +1100,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
struct {
unsigned int undo_initialized_size : 1;
unsigned int undo_data_size : 1;
unsigned int update_mapping_pairs : 1;
} need_to = { 0, 0, 0 };
} need_to = { 0, 0 };
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count "
"0x%llx.\n", na->ni->mft_no, na->type, (long long)pos,
@ -1028,7 +1176,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
ntfs_attr_put_search_ctx(ctx);
return count;
}
total = 0;
/* Handle writes beyond initialized_size. */
if (pos + count > na->initialized_size) {
if (ntfs_attr_map_whole_runlist(na))
@ -1125,174 +1273,22 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
goto rl_err_out;
}
if (rl->lcn < (LCN)0) {
LCN lcn_seek_from = -1;
runlist *rlc;
VCN cur_vcn, from_vcn;
if (rl->lcn != (LCN)LCN_HOLE) {
errno = EIO;
goto rl_err_out;
}
to_write = min(count, (rl->length <<
vol->cluster_size_bits) - ofs);
/* Instantiate the hole. */
cur_vcn = rl->vcn;
from_vcn = rl->vcn + (ofs >> vol->cluster_size_bits);
ntfs_log_trace("Instantiate hole with vcn 0x%llx.\n",
cur_vcn);
/*
* Map whole runlist to be able update mapping pairs
* later.
*/
if (ntfs_attr_map_whole_runlist(na))
goto err_out;
/*
* Restore @rl, it probably get lost during runlist
* mapping.
*/
rl = ntfs_attr_find_vcn(na, cur_vcn);
if (!rl) {
ntfs_log_error("BUG! Failed to find run after "
"mapping whole runlist. Please "
"report to the %s.\n",
NTFS_DEV_LIST);
errno = EIO;
goto err_out;
}
/*
* Search backwards to find the best lcn to start
* seek from.
*/
rlc = rl;
while (rlc->vcn) {
rlc--;
if (rlc->lcn >= 0) {
lcn_seek_from = rlc->lcn +
(from_vcn - rlc->vcn);
break;
}
}
if (lcn_seek_from == -1) {
/* Backwards search failed, search forwards. */
rlc = rl;
while (rlc->length) {
rlc++;
if (rlc->lcn >= 0) {
lcn_seek_from = rlc->lcn -
(rlc->vcn - from_vcn);
break;
}
}
}
/* Allocate clusters to instantiate the hole. */
rlc = ntfs_cluster_alloc(vol, from_vcn,
((ofs + to_write - 1) >>
vol->cluster_size_bits) + 1 +
rl->vcn - from_vcn,
lcn_seek_from, DATA_ZONE);
if (!rlc) {
eo = errno;
ntfs_log_trace("Failed to allocate clusters "
"for hole instantiating.\n");
errno = eo;
goto err_out;
}
/* Merge runlists. */
rl = ntfs_runlists_merge(na->rl, rlc);
if (!rl) {
eo = errno;
ntfs_log_trace("Failed to merge runlists.\n");
if (ntfs_cluster_free_from_rl(vol, rlc)) {
ntfs_log_trace("Failed to free just "
"allocated clusters. Leaving "
"inconsistent metadata. "
"Run chkdsk\n");
}
errno = eo;
goto err_out;
}
na->rl = rl;
need_to.update_mapping_pairs = 1;
if (update_from == -1)
update_from = from_vcn;
rl = ntfs_attr_find_vcn(na, cur_vcn);
if (!rl) {
/*
* It's definitely a BUG, if we failed to find
* @cur_vcn, because we missed it during
* instantiating of the hole.
*/
ntfs_log_error("BUG! Failed to find run after "
"instantiating. Please report "
"to the %s.\n", NTFS_DEV_LIST);
errno = EIO;
goto err_out;
}
/* If leaved part of the hole go to the next run. */
if (rl->lcn < 0)
rl++;
/* Now LCN shoudn't be less than 0. */
if (rl->lcn < 0) {
ntfs_log_error("BUG! LCN is lesser than 0. "
"Please report to the %s.\n",
NTFS_DEV_LIST);
errno = EIO;
goto err_out;
}
if (ofs) {
/*
* Need to clear region between start of
* @cur_vcn cluster and @ofs.
*/
char *buf;
buf = malloc(ofs);
if (!buf) {
ntfs_log_trace("Not enough memory to "
"allocate %lld "
"bytes.\n", ofs);
errno = ENOMEM;
goto err_out;
}
memset(buf, 0, ofs);
if (ntfs_rl_pwrite(vol, na->rl, cur_vcn <<
vol->cluster_size_bits,
ofs, buf) < 0) {
eo = errno;
ntfs_log_trace("Failed to zero "
"area.\n");
free(buf);
errno = eo;
goto err_out;
}
free(buf);
}
if (rl->vcn < cur_vcn) {
/*
* Clusters that replaced hole are merged with
* previous run, so we need to update offset.
*/
ofs += (cur_vcn - rl->vcn) <<
vol->cluster_size_bits;
}
if (rl->vcn > cur_vcn) {
/*
* We left part of the hole, so update we need
* to update offset
*/
ofs -= (rl->vcn - cur_vcn) <<
vol->cluster_size_bits;
}
if (ntfs_attr_fill_hole(na, count, &ofs, &rl,
&update_from))
goto err_out;
}
/* It is a real lcn, write it to the volume. */
to_write = min(count, (rl->length << vol->cluster_size_bits) -
ofs);
retry:
ntfs_log_trace("Writing 0x%llx bytes to vcn 0x%llx, lcn 0x%llx,"
" ofs 0x%llx.\n", to_write, rl->vcn, rl->lcn,
ofs);
ntfs_log_trace("Writing %lld bytes to vcn %lld, lcn %lld, ofs "
"%lld.\n", to_write, rl->vcn, rl->lcn, ofs);
if (!NVolReadOnly(vol))
written = ntfs_pwrite(vol->dev, (rl->lcn <<
vol->cluster_size_bits) + ofs,
@ -1317,7 +1313,7 @@ done:
if (ctx)
ntfs_attr_put_search_ctx(ctx);
/* Update mapping pairs if needed. */
if (need_to.update_mapping_pairs)
if (update_from != -1)
ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/);
/* Finally, return the number of bytes written. */
return total;
@ -1375,7 +1371,7 @@ err_out:
if (ctx)
ntfs_attr_put_search_ctx(ctx);
/* Update mapping pairs if needed. */
if (need_to.update_mapping_pairs)
if (update_from != -1)
ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/);
/* Restore original data_size if needed. */
if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size))