📄 inode.c
字号:
* not covered by mft records, this implies that the * next records are all free, so we already have found * a free record. */ bit = nr_mft_records; if (bit < 24UL) bit = 24UL; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Found free " "record bit (#1) = 0x%lx.\n", bit); goto found_free_rec; } ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Done pass 2.\n"); ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before: " "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, " "bmp->initialized = 0x%Lx.\n", bmp->allocated, bmp->size, bmp->initialized); /* Need to extend the mft bitmap. */ if (bmp->initialized + 8LL > bmp->allocated) { ntfs_io io2; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Initialized " "> allocated.\n"); /* Need to extend bitmap by one more cluster. */ rl = bmp->d.r.runlist; rlen = bmp->d.r.len - 1; lcn = rl[rlen].lcn + rl[rlen].len; io2.fn_put = ntfs_put; io2.fn_get = ntfs_get; io2.param = &b; io2.size = 1; io2.do_read = 1; err = ntfs_readwrite_attr(vol->bitmap, data, lcn >> 3, &io2); if (err) goto err_ret; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Read %lu " "bytes.\n", (unsigned long)io2.size); if (io2.size == 1 && b != 0xff) { __u8 tb = 1 << (lcn & (ntfs_cluster_t)7); if (!(b & tb)) { /* Next cluster is free. Allocate it. */ b |= tb; io2.param = &b; io2.do_read = 0; err = ntfs_readwrite_attr(vol->bitmap, data, lcn >> 3, &io2); if (err || io.size != 1) { if (!err) err = -EIO; goto err_ret; }append_mftbmp_simple: rl[rlen].len++; have_allocated_mftbmp |= 1; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Appending one " "cluster to mftbmp.\n"); } } if (!have_allocated_mftbmp) { /* Allocate a cluster from the DATA_ZONE. */ ntfs_cluster_t lcn2 = lcn; ntfs_cluster_t count = 1; err = ntfs_allocate_clusters(vol, &lcn2, &count, &rl2, &r2len, DATA_ZONE); if (err) goto err_ret; if (count != 1 || lcn2 <= 0) { if (count > 0) {rl2_dealloc_err_out: if (ntfs_deallocate_clusters( vol, rl2, r2len)) ntfs_error(__FUNCTION__ "(): Cluster " "deallocation in error " "code path failed! You " "should run chkdsk.\n"); } ntfs_vfree(rl2); if (!err) err = -EINVAL; goto err_ret; } if (lcn2 == lcn) { ntfs_vfree(rl2); goto append_mftbmp_simple; } /* We need to append a new run. */ rl_size = (rlen * sizeof(ntfs_runlist) + PAGE_SIZE - 1) & PAGE_MASK; /* Reallocate memory if necessary. */ if ((rlen + 2) * sizeof(ntfs_runlist) >= rl_size) { ntfs_runlist *rlt; rl_size += PAGE_SIZE; rlt = ntfs_vmalloc(rl_size); if (!rlt) { err = -ENOMEM; goto rl2_dealloc_err_out; } ntfs_memcpy(rlt, rl, rl_size - PAGE_SIZE); ntfs_vfree(rl); bmp->d.r.runlist = rl = rlt; } ntfs_vfree(rl2); rl[rlen].lcn = lcn = lcn2; rl[rlen].len = count; bmp->d.r.len = ++rlen; have_allocated_mftbmp |= 2; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): " "Adding run to mftbmp. " "LCN = %i, len = %i\n", lcn, count); } /* * We now have extended the mft bitmap allocated size * by one cluster. Reflect this in the attribute. */ bmp->allocated += (__s64)vol->cluster_size; } ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After: " "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, " "bmp->initialized = 0x%Lx.\n", bmp->allocated, bmp->size, bmp->initialized); /* We now have sufficient allocated space. */ ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Now have sufficient " "allocated space in mftbmp.\n"); ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before: " "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, " "bmp->initialized = 0x%Lx.\n", bmp->allocated, bmp->size, bmp->initialized); buf_pos = bmp->initialized; bmp->initialized += 8LL; if (bmp->initialized > bmp->size) bmp->size = bmp->initialized; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After: " "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, " "bmp->initialized = 0x%Lx.\n", bmp->allocated, bmp->size, bmp->initialized); have_allocated_mftbmp |= 4; /* Update the mft bitmap attribute value. */ memset(buf, 0, 8); io.param = buf; io.size = 8; io.do_read = 0; err = ntfs_readwrite_attr(vol->mft_ino, bmp, buf_pos, &io); if (err || io.size != 8) { if (!err) err = -EIO; goto shrink_mftbmp_err_ret; } ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote extended " "mftbmp bytes %lu.\n", (unsigned long)io.size); ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After write: " "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, " "bmp->initialized = 0x%Lx.\n", bmp->allocated, bmp->size, bmp->initialized); bit = buf_pos << 3; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Found free record " "bit (#2) = 0x%lx.\n", bit); goto found_free_rec; }found_free_rec: /* bit is the found free mft record. Allocate it in the mft bitmap. */ vol->mft_data_pos = bit; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At found_free_rec.\n"); io.param = buf; io.size = 1; io.do_read = 1; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before update: " "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, " "bmp->initialized = 0x%Lx.\n", bmp->allocated, bmp->size, bmp->initialized); err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io); if (err || io.size != 1) { if (!err) err = -EIO; goto shrink_mftbmp_err_ret; } ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Read %lu bytes.\n", (unsigned long)io.size);#ifdef DEBUG /* Check our bit is really zero! */ if (*buf & (1 << (bit & 7))) BUG();#endif *buf |= 1 << (bit & 7); io.param = buf; io.do_read = 0; err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io); if (err || io.size != 1) { if (!err) err = -EIO; goto shrink_mftbmp_err_ret; } ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote %lu bytes.\n", (unsigned long)io.size); ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After update: " "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, " "bmp->initialized = 0x%Lx.\n", bmp->allocated, bmp->size, bmp->initialized); /* The mft bitmap is now uptodate. Deal with mft data attribute now. */ ll = (__s64)(bit + 1) << vol->mft_record_size_bits; if (ll <= data->initialized) { /* The allocated record is already initialized. We are done! */ ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated mft record " "already initialized!\n"); goto done_ret; } ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated mft record needs " "to be initialized.\n"); /* The mft record is outside the initialized data. */ mft_rec_size = (unsigned long)vol->mft_record_size; /* Preserve old values for undo purposes. */ old_data_allocated = data->allocated; old_data_rlen = data->d.r.len - 1; old_data_len = data->d.r.runlist[old_data_rlen].len; /* * If necessary, extend the mft until it covers the allocated record. * The loop is only actually used when a freshly formatted volume is * first written to. But it optimizes away nicely in the common case. */ while (ll > data->allocated) { ntfs_cluster_t lcn2, nr_lcn2, nr, min_nr; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Extending mft " "data allocation, data->allocated = 0x%Lx, " "data->size = 0x%Lx, data->initialized = " "0x%Lx.\n", data->allocated, data->size, data->initialized); /* Minimum allocation is one mft record worth of clusters. */ if (mft_rec_size <= vol->cluster_size) min_nr = (ntfs_cluster_t)1; else min_nr = mft_rec_size >> vol->cluster_size_bits; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): min_nr = %i.\n", min_nr); /* Allocate 16 mft records worth of clusters. */ nr = mft_rec_size << 4 >> vol->cluster_size_bits; if (!nr) nr = (ntfs_cluster_t)1; /* Determine the preferred allocation location. */ ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): nr = %i.\n", nr); rl2 = data->d.r.runlist; r2len = data->d.r.len; lcn2 = rl2[r2len - 1].lcn + rl2[r2len - 1].len; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): rl2[r2len - 1].lcn " "= %i, .len = %i.\n", rl2[r2len - 1].lcn, rl2[r2len - 1].len); ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): lcn2 = %i, r2len = " "%i.\n", lcn2, r2len);retry_mft_data_allocation: nr_lcn2 = nr; err = ntfs_allocate_clusters(vol, &lcn2, &nr_lcn2, &rl2, &r2len, MFT_ZONE);#ifdef DEBUG if (!err && nr_lcn2 < min_nr) /* Allocated less than minimum needed. Weird! */ BUG();#endif if (err) { /* * If there isn't enough space to do the wanted * allocation, but there is enough space to do a * minimal allocation, then try that, unless the wanted * allocation was already the minimal allocation. */ if (err == -ENOSPC && nr > min_nr && nr_lcn2 >= min_nr) { nr = min_nr; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): " "Retrying mft data " "allocation, nr = min_nr = %i" ".\n", nr); goto retry_mft_data_allocation; } goto undo_mftbmp_alloc_err_ret; } ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated %i " "clusters starting at LCN %i.\n", nr_lcn2, lcn2); ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated " "runlist:\n"); dump_runlist(rl2, r2len); /* Append rl2 to the mft data attribute's run list. */ err = splice_runlists(&data->d.r.runlist, (int*)&data->d.r.len, rl2, r2len); if (err) { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): " "splice_runlists failed with error " "code %i.\n", -err); goto undo_partial_data_alloc_err_ret; } /* Reflect the allocated clusters in the mft allocated data. */ data->allocated += nr_lcn2 << vol->cluster_size_bits; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After extending mft " "data allocation, data->allocated = 0x%Lx, " "data->size = 0x%Lx, data->initialized = " "0x%Lx.\n", data->allocated, data->size, data->initialized); } /* Prepare a formatted (empty) mft record. */ memset(buf, 0, mft_rec_size); ntfs_fill_mft_header(buf, mft_rec_size, 0, 0, 0); err = ntfs_insert_fixups(buf, mft_rec_size); if (err) goto undo_data_alloc_err_ret; /* * Extend mft data initialized size to reach the allocated mft record * and write the formatted mft record buffer to each mft record being * initialized. Note, that ntfs_readwrite_attr extends both * data->initialized and data->size, so no need for us to touch them. */ old_data_initialized = data->initialized; old_data_size = data->size; while (ll > data->initialized) { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Initializing mft " "record 0x%Lx.\n", data->initialized >> vol->mft_record_size_bits); io.param = buf; io.size = mft_rec_size; io.do_read = 0; err = ntfs_readwrite_attr(vol->mft_ino, data, data->initialized, &io); if (err || io.size != mft_rec_size) { if (!err) err = -EIO; goto undo_data_init_err_ret; } ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote %i bytes to " "mft data.\n", io.size); } /* Update the VFS inode size as well. */ VFS_I(vol->mft_ino)->i_size = data->size;#ifdef DEBUG ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After mft record " "initialization: data->allocated = 0x%Lx, data->size " "= 0x%Lx, data->initialized = 0x%Lx.\n", data->allocated, data->size, data->initialized); /* Sanity checks. */ if (data->size > data->allocated || data->size < data->initialized || data->initialized > data->allocated) BUG();#endifdone_ret: /* Return the number of the allocated mft record. */ ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At done_ret. *result = bit = " "0x%lx.\n", bit); *result = bit; vol->mft_data_pos = bit + 1;err_ret: unlock_kernel(); free_page((unsigned long)buf); ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Syncing inode $MFT.\n"); if (ntfs_update_inode(vol->mft_ino)) ntfs_error(__FUNCTION__ "(): Failed to sync inode $MFT. " "Continuing anyway.\n"); if (!err) { ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): Done. Allocated mft " "record number *result = 0x%lx.\n", *result); return 0; } if (err != -ENOSPC) ntfs_error(__FUNCTION__ "(): Failed to allocate an mft " "record. Returning error code %i.\n", -err); else ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): Failed to allocate " "an mft record due to lack of free space.\n"); return err;undo_data_init_err_ret: ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At " "undo_data_init_err_ret.\n"); data->initialized = old_data_initialized; data->size = old_data_size;undo_data_alloc_err_ret: ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At undo_data_alloc_err_ret." "\n"); data->allocated = old_data_allocated;undo_partial_data_alloc_err_ret: ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At " "undo_partial_data_alloc_err_ret.\n"); /* Deallocate the clusters. */ if (ntfs_deallocate_clusters(vol, rl2, r2len)) ntfs_error(__FUNCTION__ "(): Error deallocating clusters in " "error code path. You should run chkdsk.\n"); ntfs_vfree(rl2); /* Revert the run list back to what it was before. */ r2len = data->d.r.len; rl2 = data->d.r.runlist; rl2[old_data_rlen++].len = old_data_len; rl2[old_data_rlen].lcn = (ntfs_cluster_t)-1; rl2[old_data_rlen].len = (ntfs_cluster_t)0; data->d.r.len = old_data_rlen; rl2_size = ((old_data_rlen + 1) * sizeof(ntfs_runlist) + PAGE_SIZE - 1) & PAGE_MASK; /* Reallocate memory freeing any extra memory allocated. */ if (rl2_size < ((r2len * sizeof(ntfs_runlist) + PAGE_SIZE - 1) & PAGE_MASK)) { rl2 = ntfs_vmalloc(rl2_size); if (rl2) { ntfs_memcpy(rl2, data->d.r.runlist, rl2_size); ntfs_vfree(data->d.r.runlist); data->d.r.runlist = rl2; } else ntfs_error(__FUNCTION__ "(): Error reallocating " "memory in error code path. This " "should be harmless.\n"); } undo_mft
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -