📄 ntfsresize.c
字号:
{ err_printf(resize, "ntfs_rl_truncate failed"); return (-1); } return (0);}/** * bitmap_file_data_fixup * * $Bitmap can overlap the end of the volume. Any bits in this region * must be set. This region also encompasses the backup boot sector. */static void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm){ for (; cluster < bm->size << 3; cluster++) ntfs_bit_set(bm->bm, (u64)cluster, 1);}/** * truncate_badclust_bad_attr * * The metadata file $BadClus needs to be shrunk. * * FIXME: this function should go away and instead using a generalized * "truncate_bitmap_data_attr()" */static int truncate_badclust_bad_attr(ntfs_resize_t *resize){ ATTR_RECORD *a; runlist *rl_bad; s64 nr_clusters = resize->new_volume_size; ntfs_volume *vol = resize->vol; a = resize->ctx->attr; if (!a->non_resident) { /* FIXME: handle resident attribute value */ err_printf(resize, "Resident attribute in $BadClust isn't supported!"); return (-1); } if (!(rl_bad = ntfs_mapping_pairs_decompress(vol, a, NULL))) { err_printf(resize, "ntfs_mapping_pairs_decompress failed"); return (-1); } if (rl_truncate(resize, &rl_bad, nr_clusters) < 0) return (-1); a->highest_vcn = cpu_to_le64(nr_clusters - 1LL); a->allocated_size = cpu_to_le64(nr_clusters * vol->cluster_size); a->data_size = cpu_to_le64(nr_clusters * vol->cluster_size); if (replace_attribute_runlist(resize, vol, resize->ctx, rl_bad) < 0) return (-1); free(rl_bad); return (0);}/** * realloc_bitmap_data_attr * * Reallocate the metadata file $Bitmap. It must be large enough for one bit * per cluster of the shrunken volume. Also it must be a of 8 bytes in size. */static int realloc_bitmap_data_attr(ntfs_resize_t *resize, runlist **rl, s64 nr_bm_clusters){ s64 i; ntfs_volume *vol = resize->vol; ATTR_RECORD *a = resize->ctx->attr; s64 new_size = resize->new_volume_size; struct bitmap *bm = &resize->lcn_bitmap; if (!(*rl = ntfs_mapping_pairs_decompress(vol, a, NULL))) { err_printf(resize, "ntfs_mapping_pairs_decompress failed"); return (-1); } release_bitmap_clusters(bm, *rl); free(*rl); for (i = vol->nr_clusters; i < new_size; i++) ntfs_bit_set(bm->bm, i, 0); if (!(*rl = alloc_cluster(resize, bm, nr_bm_clusters, new_size, 0))) { err_printf(resize, "Couldn't allocate $Bitmap clusters"); return (-1); } return (0);}static int realloc_lcn_bitmap(ntfs_resize_t *resize, s64 bm_bsize){ u8 *tmp; if (!(tmp = realloc(resize->lcn_bitmap.bm, bm_bsize))) { err_printf(resize, "realloc failed"); return (-1); } resize->lcn_bitmap.bm = tmp; resize->lcn_bitmap.size = bm_bsize; bitmap_file_data_fixup(resize->new_volume_size, &resize->lcn_bitmap); return (0);}/** * truncate_bitmap_data_attr */static int truncate_bitmap_data_attr(ntfs_resize_t *resize){ ATTR_RECORD *a; runlist *rl; s64 bm_bsize, size; s64 nr_bm_clusters; ntfs_volume *vol = resize->vol; a = resize->ctx->attr; if (!a->non_resident) { /* FIXME: handle resident attribute value */ err_printf(resize, "Resident attribute in $Bitmap isn't supported!"); return (-1); } bm_bsize = nr_clusters_to_bitmap_byte_size(resize->new_volume_size); nr_bm_clusters = rounded_up_division(bm_bsize, vol->cluster_size); if (resize->shrink) { if (realloc_bitmap_data_attr(resize, &rl, nr_bm_clusters) < 0) return (-1); if (realloc_lcn_bitmap(resize, bm_bsize) < 0) return (-1); } else { if (realloc_lcn_bitmap(resize, bm_bsize) < 0) return (-1); if (realloc_bitmap_data_attr(resize, &rl, nr_bm_clusters) < 0) return (-1); } a->highest_vcn = cpu_to_le64(nr_bm_clusters - 1LL); a->allocated_size = cpu_to_le64(nr_bm_clusters * vol->cluster_size); a->data_size = cpu_to_le64(bm_bsize); a->initialized_size = cpu_to_le64(bm_bsize); if (replace_attribute_runlist(resize, vol, resize->ctx, rl) < 0) return (-1); /* * FIXME: update allocated/data sizes and timestamps in $FILE_NAME * attribute too, for now chkdsk will do this for us. */ size = ntfs_rl_pwrite(vol, rl, 0, bm_bsize, resize->lcn_bitmap.bm); if (bm_bsize != size) { if (size == -1) err_printf(resize, "Couldn't write $Bitmap"); else err_printf(resize, "Couldn't write full $Bitmap file (%lld from %lld)", (long long)size, (long long)bm_bsize); return (-1); } free(rl); return (0);}/** * lookup_data_attr * * Find the $DATA attribute (with or without a name) for the given MFT reference * (inode number). */static int lookup_data_attr(ntfs_resize_t *resize, ntfs_volume *vol, MFT_REF mref, const char *aname, ntfs_attr_search_ctx **ctx){ ntfs_inode *ni; ntfschar *ustr = NULL; int len = 0; if (!(ni = ntfs_inode_open(vol, mref))) { err_printf(resize, "ntfs_open_inode failed"); return (-1); } if (!(*ctx = attr_get_search_ctx(resize, ni, NULL))) { return (-1); } if ((ustr = ntfs_str2ucs(aname, &len)) == NULL) { err_printf(resize, "Couldn't convert '%s' to Unicode", aname); return (-1); } if (ntfs_attr_lookup(AT_DATA, ustr, len, 0, 0, NULL, 0, *ctx)) { err_printf(resize, "ntfs_lookup_attr failed"); return (-1); } ntfs_ucsfree(ustr); return (0);}static int check_bad_sectors(ntfs_resize_t *resize, ntfs_volume *vol){ ntfs_attr_search_ctx *ctx; ntfs_inode *base_ni; runlist *rl; s64 i, badclusters = 0; progress_message(resize, "Checking for bad sectors"); if (lookup_data_attr(resize, vol, FILE_BadClus, "$Bad", &ctx) != 0) return (-1); base_ni = ctx->base_ntfs_ino; if (!base_ni) base_ni = ctx->ntfs_ino; if (NInoAttrList(base_ni)) { err_printf(resize, "Hopelessly many bad sectors has been detected!"); err_printf(resize, "%s", many_bad_sectors_msg); return (-1); } if (!ctx->attr->non_resident) { err_printf(resize, "Resident attribute in $BadClust! Please report to " "%s", NTFS_DEV_LIST); return (-1); } /* * FIXME: The below would be partial for non-base records in the * not yet supported multi-record case. Alternatively use audited * ntfs_attr_truncate after an umount & mount. */ if (!(rl = ntfs_mapping_pairs_decompress(vol, ctx->attr, NULL))) { err_printf(resize, "Decompressing $BadClust:$Bad mapping pairs failed"); return (-1); } for (i = 0; rl[i].length; i++) { /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */ if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED) continue; badclusters += rl[i].length; err_printf(resize, "Bad cluster: %llx - %llx (%lld)\n", rl[i].lcn, rl[i].lcn + rl[i].length - 1, rl[i].length); } if (badclusters) { err_printf(resize, "This software has detected that the\n" "disk has at least %lld bad sector%s.", badclusters, badclusters - 1 ? "s" : ""); if (!opt.badsectors) { err_printf(resize, "%s", bad_sectors_warning_msg); return (-1); } else err_printf(resize, "Bad sectors can cause reliability\n" "problems and massive data loss!!!"); } free(rl); ntfs_attr_put_search_ctx(ctx); return badclusters;}/** * truncate_badclust_file * * Shrink the $BadClus file to match the new volume size. */static int truncate_badclust_file(ntfs_resize_t *resize){ progress_message(resize, "Updating $BadClust file"); if (lookup_data_attr(resize, resize->vol, FILE_BadClus, "$Bad", &resize->ctx) != 0) return (-1); /* FIXME: sanity_check_attr(ctx->attr); */ if (truncate_badclust_bad_attr(resize) < 0) return (-1); if (write_mft_record(resize, resize->vol, resize->ctx->ntfs_ino->mft_no, resize->ctx->mrec)) { err_printf(resize, "Couldn't update $BadClust"); return (-1); } ntfs_attr_put_search_ctx(resize->ctx); return (0);}/** * truncate_bitmap_file * * Shrink the $Bitmap file to match the new volume size. */static int truncate_bitmap_file(ntfs_resize_t *resize){ progress_message(resize, "Updating $Bitmap file"); if (lookup_data_attr(resize, resize->vol, FILE_Bitmap, NULL, &resize->ctx) != 0) return (-1); if (truncate_bitmap_data_attr(resize) < 0) return (-1); if (write_mft_record(resize, resize->vol, resize->ctx->ntfs_ino->mft_no, resize->ctx->mrec)) { err_printf(resize, "Couldn't update $Bitmap"); return (-1); } ntfs_attr_put_search_ctx(resize->ctx); return (0);}/** * setup_lcn_bitmap * * Allocate a block of memory with one bit for each cluster of the disk. * All the bits are set to 0, except those representing the region beyond the * end of the disk. */static int setup_lcn_bitmap(ntfs_resize_t *resize, struct bitmap *bm, s64 nr_clusters){ progress_message(resize, "Set up LCN bitmap"); /* Determine lcn bitmap byte size and allocate it. */ bm->size = rounded_up_division(nr_clusters, 8); if (!(bm->bm = (unsigned char *)calloc(1, bm->size))) return -1; bitmap_file_data_fixup(nr_clusters, bm); return 0;}/** * update_bootsector * * FIXME: should be done using ntfs_* functions */static int update_bootsector(ntfs_resize_t *r){ NTFS_BOOT_SECTOR bs; s64 bs_size = sizeof(NTFS_BOOT_SECTOR); ntfs_volume *vol = r->vol; progress_message(r, "Updating Boot record"); if (vol->dev->d_ops->seek(vol->dev, 0, SEEK_SET) == (off_t)-1) { err_printf(r, "lseek failed"); return (-1); } if (vol->dev->d_ops->read(vol->dev, &bs, bs_size) == -1) { err_printf(r, "read() error"); return (-1); } bs.number_of_sectors = cpu_to_sle64(r->new_volume_size * bs.bpb.sectors_per_cluster); if (r->mftmir_old) { if (copy_clusters(r, r->mftmir_rl.lcn, r->mftmir_old, r->mftmir_rl.length) < 0) return (-1); bs.mftmirr_lcn = cpu_to_le64(r->mftmir_rl.lcn); } if (vol->dev->d_ops->seek(vol->dev, 0, SEEK_SET) == (off_t)-1) { err_printf(r, "lseek failed"); return (-1); }// if (!opt.ro_flag) if (vol->dev->d_ops->write(vol->dev, &bs, bs_size) == -1) { err_printf(r, "write() error"); return (-1); } return (0);}#ifndef __VISOPSYS__/** * vol_size */static s64 vol_size(ntfs_volume *v, s64 nr_clusters){ /* add one sector_size for the backup boot sector */ return nr_clusters * v->cluster_size + v->sector_size;}/** * print_vol_size * * Print the volume size in bytes and decimal megabytes. */static void print_vol_size(const char *str, s64 bytes){ printf("%s: %lld bytes (%lld MB)\n", str, (long long)bytes, (long long)rounded_up_division(bytes, NTFS_MBYTE));}/** * print_disk_usage * * Display the amount of disk space in use. */static void print_disk_usage(ntfs_volume *vol, s64 nr_used_clusters){ s64 total, used; total = vol->nr_clusters * vol->cluster_size; used = nr_used_clusters * vol->cluster_size; /* WARNING: don't modify the text, external tools grep for it */ printf("Space in use : %lld MB (%.1f%%)\n", (long long)rounded_up_division(used, NTFS_MBYTE), 100.0 * ((float)used / total));}static void print_num_of_relocations(ntfs_resize_t *resize){ s64 relocations = resize->relocations * resize->vol->cluster_size; printf("Needed relocations : %lld (%lld MB)\n", (long long)resize->relocations, (long long) rounded_up_division(relocations, NTFS_MBYTE));}#endif /* __VISOPSYS__ *//** * mount_volume * * First perform some checks to determine if the volume is already mounted, or * is dirty (Windows wasn't shutdown properly). If everything is OK, then mount * the volume (load the metadata into memory). */static ntfs_volume *mount_volume(ntfs_resize_t *resize){ unsigned long mntflag; ntfs_volume *vol = NULL; progress_message(resize, "Mounting volume"); if (ntfs_check_if_mounted(opt.volume, &mntflag)) { err_printf(resize, "Failed to check '%s' mount state", opt.volume); return (NULL); } if (mntflag & NTFS_MF_MOUNTED) { if (!(mntflag & NTFS_MF_READONLY)) err_printf(resize, "Device '%s' is mounted read-write. " "You must unmount it first.", opt.volume); else err_printf(resize, "Device '%s' is mounted. " "You must unmount it first.", opt.volume); return (NULL); } if (!(vol = ntfs_mount(opt.volume, MS_NOATIME))) { int err = errno; static char *ERRMESS = "Opening '%s' as NTFS failed. %s"; if (err == EINVAL) err_printf(resize, ERRMESS, opt.volume, invalid_ntfs_msg); else if (err == EIO) err_printf(resize, ERRMESS, opt.volume, corrupt_volume_msg); else if (err == EPERM) err_printf(resize, ERRMESS, opt.volume, hibernated_volume_msg); else if (err == EOPNOTSUPP) err_printf(resize, ERRMESS, opt.volume, unclean_journal_msg); else if (err == EBUSY) err_printf(resize, ERRMESS, opt.volume, opened_volume_msg); else err_printf(resize, ERRMESS, opt.volume, "Unknown error."); return (NULL); } if (vol->flags & VOLUME_IS_DIRTY) if (opt.force-- <= 0) { err_printf(resize, "Volume is scheduled for check. Run chkdsk /f" " and please try again, or see option -f."); return (NULL); } if (NTFS_MAX_CLUSTER_SIZE < vol->cluster_size) { err_printf(resize, "Cluster size %u is too large!", (unsigned int)vol->cluster_size); return (NULL); } progress_message(resize, "Device name: %s", opt.volume); progress_message(resize, "NTFS volume version: %d.%d", vol->major_ver, vol->minor_ver); if (ntfs_versio
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -