📄 attrib.c
字号:
ofs = pos - (rl->vcn << vol->cluster_size_bits); for (; count; rl++, ofs = 0) { if (rl->lcn == LCN_RL_NOT_MAPPED) { rl = ntfs_attr_find_vcn(na, rl->vcn); if (!rl) { if (errno == ENOENT) { errno = EIO; ntfs_log_perror("%s: Failed to find VCN #2", __FUNCTION__); } goto rl_err_out; } /* Needed for case when runs merged. */ ofs = pos + total - (rl->vcn << vol->cluster_size_bits); } if (!rl->length) { errno = EIO; ntfs_log_perror("%s: Zero run length", __FUNCTION__); goto rl_err_out; } if (rl->lcn < (LCN)0) { if (rl->lcn != (LCN)LCN_HOLE) { ntfs_log_perror("%s: Bad run (%lld)", __FUNCTION__, (long long)rl->lcn); goto rl_err_out; } /* It is a hole, just zero the matching @b range. */ to_read = min(count, (rl->length << vol->cluster_size_bits) - ofs); memset(b, 0, to_read); /* Update progress counters. */ total += to_read; count -= to_read; b = (u8*)b + to_read; continue; } /* It is a real lcn, read it into @dst. */ to_read = min(count, (rl->length << vol->cluster_size_bits) - ofs);retry: ntfs_log_trace("Reading 0x%llx bytes from vcn 0x%llx, lcn 0x%llx, " "ofs 0x%llx.\n", to_read, rl->vcn, rl->lcn, ofs); br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) + ofs, to_read, b); /* If everything ok, update progress counters and continue. */ if (br > 0) { total += br; count -= br; b = (u8*)b + br; continue; } /* If the syscall was interrupted, try again. */ if (br == (s64)-1 && errno == EINTR) goto retry; if (total) return total; if (!br) errno = EIO; ntfs_log_perror("%s: ntfs_pread failed", __FUNCTION__); return -1; } /* Finally, return the number of bytes read. */ return total + total2;rl_err_out: if (total) return total; errno = EIO; return -1;}/** * ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure * @na: ntfs attribute to read from * @pos: byte position in the attribute to begin reading from * @count: number of bytes to read * @b: output data buffer * * This function will read @count bytes starting at offset @pos from the ntfs * attribute @na into the data buffer @b. * * On success, return the number of successfully read bytes. If this number is * lower than @count this means that the read reached end of file or that an * error was encountered during the read so that the read is partial. 0 means * end of file or nothing was read (also return 0 when @count is 0). * * On error and nothing has been read, return -1 with errno set appropriately * to the return code of ntfs_pread(), or to EINVAL in case of invalid * arguments. */s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b){ int ret; if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { errno = EINVAL; ntfs_log_perror("%s: na=%p b=%p pos=%lld count=%lld", __FUNCTION__, na, b, (long long)pos, (long long)count); return -1; } ntfs_log_enter("Entering for inode %lld attr 0x%x pos %lld count " "%lld\n", (unsigned long long)na->ni->mft_no, na->type, (long long)pos, (long long)count); ret = ntfs_attr_pread_i(na, pos, count, b); ntfs_log_leave("\n"); return ret;}static int ntfs_attr_fill_zero(ntfs_attr *na, s64 pos, s64 count){ char *buf; s64 written, size, end = pos + count; int ret = -1; ntfs_log_trace("pos %lld, count %lld\n", (long long)pos, (long long)count); if (!na || pos < 0 || count < 0) { errno = EINVAL; goto err_out; } buf = ntfs_calloc(NTFS_BUF_SIZE); if (!buf) goto err_out; while (pos < end) { size = min(end - pos, NTFS_BUF_SIZE); written = ntfs_rl_pwrite(na->ni->vol, na->rl, pos, size, buf); if (written <= 0) { ntfs_log_perror("Failed to zero space"); goto err_free; } pos += written; } ret = 0;err_free: free(buf);err_out: return ret; }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); cur_vcn = (*rl)->vcn; from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits); ntfs_log_trace("count: %lld, cur_vcn: %lld, from: %lld, to: %lld, ofs: " "%lld\n", count, cur_vcn, from_vcn, to_write, *ofs); /* 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); if (lcn_seek_from < -1) lcn_seek_from = -1; break; } } } 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) goto err_out; *rl = ntfs_runlists_merge(na->rl, rlc); if (!*rl) { eo = errno; ntfs_log_perror("Failed to merge runlists"); if (ntfs_cluster_free_from_rl(vol, rlc)) { ntfs_log_perror("Failed to free hot clusters. " "Please run chkdsk /f"); } 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("Failed to find run after hole instantiation. " "Please report to %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) { /* Clear non-sparse region from @cur_vcn to @*ofs. */ if (ntfs_attr_fill_zero(na, cur_vcn << vol->cluster_size_bits, *ofs)) goto err_out; } 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 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 * @pos: position in the attribute to write to * @count: number of bytes to write * @b: data buffer to write to disk * * This function will write @count bytes from data buffer @b to ntfs attribute * @na at position @pos. * * On success, return the number of successfully written bytes. If this number * is lower than @count this means that an error was encountered during the * write so that the write is partial. 0 means nothing was written (also return * 0 when @count is 0). * * On error and nothing has been written, return -1 with errno set * appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of * invalid arguments. */s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b){ 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; runlist_element *rl; s64 eo, hole; struct { unsigned int undo_initialized_size : 1; unsigned int undo_data_size : 1; } need_to = { 0, 0 }; ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count " "0x%llx.\n", na->ni->mft_no, na->type, (long long)pos, (long long)count); if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { errno = EINVAL; ntfs_log_perror("%s", __FUNCTION__); goto errno_set; } vol = na->ni->vol; /* * Encrypted non-resident attributes are not supported. We return * access denied, which is what Windows NT4 does, too. */ if (NAttrEncrypted(na) && NAttrNonResident(na)) { errno = EACCES; goto errno_set; } /* If this is a compressed attribute it needs special treatment. */ if (NAttrCompressed(na)) { // TODO: Implement writing compressed attributes! (AIA) // return ntfs_attr_pwrite_compressed(ntfs_attr *na, // const s64 pos, s64 count, void *b); errno = EOPNOTSUPP; goto errno_set; } if (!count) goto out; /* If the write reaches beyond the end, extend the attribute. */ old_data_size = na->data_size; if (pos + count > na->data_size) { if (ntfs_attr_truncate(na, pos + count)) { ntfs_log_perror("Failed to enlarge attribute"); goto errno_set; } need_to.undo_data_size = 1; } old_initialized_size = na->initialized_size; /* If it is a resident attribute, write the data to the mft record. */ if (!NAttrNonResident(na)) { char *val; ctx = ntfs_attr_get_search_ctx(na->ni, NULL); if (!ctx) goto err_out; if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0, NULL, 0, ctx)) { ntfs_log_perror("%s: lookup failed", __FUNCTION__); goto err_out; } val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset); if (val < (char*)ctx->attr || val + le32_to_cpu(ctx->attr->value_length) > (char*)ctx->mrec + vol->mft_record_size) { errno = EIO; ntfs_log_perror("%s: Sanity check failed", __FUNCTION__); goto err_out; } memcpy(val + pos, b, count); if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, ctx->mrec)) { /* * NOTE: We are in a bad state at this moment. We have * dirtied the mft record but we failed to commit it to * disk. Since we have read the mft record ok before, * it is unlikely to fail writing it, so is ok to just * return error here... (AIA) */ ntfs_log_perror("%s: failed to write mft record", __FUNCTION__); goto err_out; } ntfs_attr_put_search_ctx(ctx); total = count; goto out; } /* Handle writes beyond initialized_size. */ if (pos + count > na->initialized_size) { if (ntfs_attr_map_whole_runlist(na)) goto err_out; /* Set initialized_size to @pos + @count. */ ctx = ntfs_attr_get_search_ctx(na->ni, NULL); if (!ctx) goto err_out; if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0, NULL, 0, ctx)) goto err_out; /* If write starts beyond initialized_size, zero the gap. */ if (pos > na->initialized_size) if (ntfs_attr_fill_zero(na, na->initialized_size, pos - na->initialized_size)) goto err_out; ctx->attr->initialized_size = cpu_to_sle64(pos + count); if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, ctx->mrec)) { /* * Undo the change in the in-memory copy and send it * back for writing. */ ctx->attr->initialized_size = cpu_to_sle64(old_initialized_size); ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, ctx->mrec); goto err_out; } na->initialized_size = pos + count; ntfs_attr_put_search_ctx(ctx); ctx = NULL; /* * NOTE: At this point the initialized_size in the mft record * has been updated BUT there is random data on disk thus if * we decide to abort, we MUST change the initialized_size * again. */ need_to.undo_initialized_size = 1; } /* Find the runlist element containing the vcn. */ rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits); if (!rl) { /* * If the vcn is not present it is an out of bounds write. * However, we already extended the size of the attribute, * so getting this here must be an error of some kind. */ if (errno == ENOENT) { errno = EIO; ntfs_log_perror("%s: Failed to find VCN #1", __FUNCTION__); } goto err_out;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -