📄 ntfsresize.c
字号:
/** * ntfsresize - Part of the Linux-NTFS project. * * Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2002-2003 Richard Russon * * This utility will resize an NTFS volume without data loss. * * WARNING FOR DEVELOPERS!!! Several external tools grep for text messages * to control execution thus if you would like to change any message * then PLEASE think twice before doing so then don't modify it. Thanks! * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the main directory of the Linux-NTFS * distribution in the file COPYING); if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Heavily modified 01/2007 by Andy McLaughlin for Visopsys port. */#include "config.h"#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_STDIO_H#include <stdio.h>#endif#ifdef HAVE_STDARG_H#include <stdarg.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#ifdef HAVE_GETOPT_H#include <getopt.h>#endif#include <sys/ntfs.h>#include <sys/api.h>#include "debug.h"#include "types.h"#include "support.h"#include "endians.h"#include "bootsect.h"#include "device.h"#include "attrib.h"#include "volume.h"#include "mft.h"#include "bitmap.h"#include "inode.h"#include "runlist.h"#ifndef __VISOPSYS__#include "utils.h"#include "version.h"static const char *EXEC_NAME = "ntfsresize";static const char *resize_warning_msg ="WARNING: Every sanity check passed and only the dangerous operations left.\n""Make sure that important data has been backed up! Power outage or computer\n""crash may result major data loss!\n";static const char *resize_important_msg ="You can go on to shrink the device for example with Linux fdisk.\n""IMPORTANT: When recreating the partition, make sure that you\n"" 1) create it at the same disk sector (use sector as the unit!)\n"" 2) create it with the same partition type (usually 7, HPFS/NTFS)\n"" 3) do not make it smaller than the new NTFS filesystem size\n"" 4) set the bootable flag for the partition if it existed before\n""Otherwise you won't be able to access NTFS or can't boot from the disk!\n""If you make a mistake and don't have a partition table backup then you\n""can recover the partition table by TestDisk or Parted's rescue mode.\n";static const char *invalid_ntfs_msg ="The device '%s' doesn't have a valid NTFS.\n""Maybe you selected the wrong partition? Or the whole disk instead of a\n""partition (e.g. /dev/hda, not /dev/hda1)? This error might also occur\n""if the disk was incorrectly repartitioned (see the ntfsresize FAQ).\n";static const char *corrupt_volume_msg ="NTFS is inconsistent. Run chkdsk /f on Windows then reboot it TWICE!\n""The usage of the /f parameter is very IMPORTANT! No modification was\n""and will be made to NTFS by this software until it gets repaired.\n";static const char *hibernated_volume_msg ="The NTFS partition is hibernated. Windows must be resumed and turned off\n""properly, so resizing could be done safely.\n";static const char *unclean_journal_msg ="The NTFS journal file is unclean. Please shutdown Windows properly before\n""using this software! Note, if you have run chkdsk previously then boot\n""Windows again which will automatically initialize the journal correctly.\n";static const char *opened_volume_msg ="This software has detected that the NTFS volume is already opened by another\n""software thus it refuses to progress to preserve data consistency.\n";static const char *bad_sectors_warning_msg ="****************************************************************************\n""* WARNING: The disk has bad sector. This means physical damage on the disk *\n""* surface caused by deterioration, manufacturing faults or other reason. *\n""* The reliability of the disk may stay stable or degrade fast. We suggest *\n""* making a full backup urgently by running 'ntfsclone --rescue ...' then *\n""* run 'chkdsk /f /r' on Windows and rebooot it TWICE! Then you can resize *\n""* NTFS safely by additionally using the --bad-sectors option of ntfsresize.*\n""****************************************************************************\n";static const char *many_bad_sectors_msg ="***************************************************************************\n""* WARNING: The disk has many bad sectors. This means physical damage *\n""* on the disk surface caused by deterioration, manufacturing faults or *\n""* other reason. We suggest to get a replacement disk as soon as possible. *\n""***************************************************************************\n";#endif /* __VISOPSYS__ */static const char *invalid_ntfs_msg ="The device or partition doesn't have a valid NTFS volume.";static const char *corrupt_volume_msg ="This software has detected that your NTFS is corrupted.\n""No modifications were made.";static const char *hibernated_volume_msg ="The NTFS volume is hibernated. Windows must be resumed and\n""shut down properly so that resizing can be done safely.";static const char *unclean_journal_msg ="The NTFS journal file is unclean. Please run chkdsk and\n""then boot windows again, and shut down properly.";static const char *opened_volume_msg ="The NTFS volume is already opened by another process.\n""Refusing to continue for the sake of data consistency.";static const char *bad_sectors_warning_msg ="The device or partition has bad sectors.";static const char *many_bad_sectors_msg ="The device or partition has many bad sectors. This\n""means physical damage on the disk surface caused by\n""defects or deterioration. Replace as soon as possible.";struct { int force; int info; int badsectors; s64 bytes; char *volume;} opt;struct bitmap { s64 size; u8 *bm; u8 padding[4]; /* Unused: padding to 64 bit. */};#ifndef __VISOPSYS__#define NTFS_PROGBAR 0x0001#define NTFS_PROGBAR_SUPPRESS 0x0002struct progress_bar { u64 start; u64 stop; int resolution; int flags; float unit; u8 padding[4]; /* Unused: padding to 64 bit. */};#endif /* __VISOPSYS__ */struct llcn_t { s64 lcn; /* last used LCN for a "special" file/attr type */ s64 inode; /* inode using it */};#define NTFSCK_PROGBAR 0x0001typedef struct { ntfs_inode *ni; /* inode being processed */ ntfs_attr_search_ctx *ctx; /* inode attribute being processed */ s64 inuse; /* num of clusters in use */ int multi_ref; /* num of clusters referenced many times */ int outsider; /* num of clusters outside the volume */ int show_outsider; /* controls showing the above information */ int flags; struct bitmap lcn_bitmap;} ntfsck_t;typedef struct { ntfs_volume *vol; ntfs_inode *ni; /* inode being processed */ s64 new_volume_size; /* in clusters; 0 = --info w/o --size */ MFT_REF mref; /* mft reference */ MFT_RECORD *mrec; /* mft record */ ntfs_attr_search_ctx *ctx; /* inode attribute being processed */ u64 relocations; /* num of clusters to relocate */ s64 inuse; /* num of clusters in use */ runlist mftmir_rl; /* $MFTMirr AT_DATA's new position */ s64 mftmir_old; /* $MFTMirr AT_DATA's old LCN */ int dirty_inode; /* some inode data got relocated */ int shrink; /* shrink = 1, enlarge = 0 */ s64 badclusters; /* num of physically dead clusters */ VCN mft_highest_vcn; /* used for relocating the $MFT */ progress *prog; struct bitmap lcn_bitmap; /* Temporary statistics until all case is supported */ struct llcn_t last_mft; struct llcn_t last_mftmir; struct llcn_t last_multi_mft; struct llcn_t last_sparse; struct llcn_t last_compressed; struct llcn_t last_lcn; s64 last_unsupp; /* last unsupported cluster */} ntfs_resize_t;/* FIXME: This, lcn_bitmap and pos from find_free_cluster() will make a cluster allocation related structure, attached to ntfs_resize_t */s64 max_free_cluster_range = 0;#define NTFS_MBYTE (1000 * 1000)/* WARNING: don't modify the text, external tools grep for it */#define ERR_PREFIX "ERROR: "#define DIRTY_NONE (0)#define DIRTY_INODE (1)#define DIRTY_ATTRIB (2)#define NTFS_MAX_CLUSTER_SIZE (65536)static int progressPercentages[] = { 18, // RSZPCNT_CHECK 1, // RSZPCNT_ACCOUNTING 17, // RSZPCNT_SETRSZCONST 60, // RSZPCNT_VOLFIXUP 1, // RSZPCNT_RELOCATIONS 1, // RSZPCNT_BADCLUST 1, // RSZPCNT_TRUNCBMP 1, // RSZPCNT_UPDBOOTSECT};#define RSZPCNT_CHECK 0#define RSZPCNT_ACCOUNTING 1#define RSZPCNT_SETRSZCONST 2#define RSZPCNT_VOLFIXUP 3#define RSZPCNT_RELOCATIONS 4#define RSZPCNT_BADCLUST 5#define RSZPCNT_TRUNCBMP 6#define RSZPCNT_UPDBOOTSECT 7#define CHECK_CANCEL() do { \ if (resize->prog && resize->prog->cancel) \ { free(resize); return (ERR_CANCELLED); } \} while (0)static s64 rounded_up_division(s64 numer, s64 denom){ return (numer + (denom - 1)) / denom;}#ifndef __VISOPSYS__/** * perr_printf * * Print an error message. */__attribute__((format(printf, 1, 2)))static void perr_printf(const char *fmt, ...){ va_list ap; int eo = errno; fprintf(stdout, PERR_PREFIX, eo); va_start(ap, fmt); vfprintf(stdout, fmt, ap); va_end(ap); fprintf(stdout, ": %s\n", strerror(eo)); fflush(stdout); fflush(stderr);}__attribute__((format(printf, 1, 2)))static void err_printf(const char *fmt, ...){ va_list ap; fprintf(stdout, NERR_PREFIX); va_start(ap, fmt); vfprintf(stdout, fmt, ap); va_end(ap); fflush(stdout); fflush(stderr);}/** * err_exit * * Print and error message and exit the program. */__attribute__((noreturn))__attribute__((format(printf, 1, 2)))static int err_exit(const char *fmt, ...){ va_list ap; fprintf(stdout, NERR_PREFIX); va_start(ap, fmt); vfprintf(stdout, fmt, ap); va_end(ap); fflush(stdout); fflush(stderr); exit(1);}/** * perr_exit * * Print and error message and exit the program */__attribute__((noreturn))__attribute__((format(printf, 1, 2)))static int perr_exit(const char *fmt, ...){ va_list ap; int eo = errno; fprintf(stdout, PERR_PREFIX, eo); va_start(ap, fmt); vfprintf(stdout, fmt, ap); va_end(ap); printf(": %s\n", strerror(eo)); fflush(stdout); fflush(stderr); exit(1);}/** * usage - Print a list of the parameters to the program * * Print a list of the parameters and options for the program. * * Return: none */__attribute__((noreturn))static void usage(void){ printf("\nUsage: %s [OPTIONS] DEVICE\n" " Resize an NTFS volume non-destructively, safely move any data if needed.\n" "\n" " -i, --info Estimate the smallest shrunken size possible\n" " -s, --size SIZE Resize volume to SIZE[k|M|G] bytes\n" "\n" " -n, --no-action Do not write to disk\n" " -b, --bad-sectors Support disks having bad sectors\n" " -f, --force Force to progress\n" " -P, --no-progress-bar Don't show progress bar\n" " -v, --verbose More output\n" " -V, --version Display version information\n" " -h, --help Display this help\n"#ifdef DEBUG " -d, --debug Show debug information\n"#endif "\n" " The options -i and -s are mutually exclusive. If both options are\n" " omitted then the NTFS volume will be enlarged to the DEVICE size.\n" "\n", EXEC_NAME); printf("%s%s", ntfs_bugs, ntfs_home); printf("Ntfsresize FAQ: http://linux-ntfs.sourceforge.net/info/ntfsresize.html\n"); exit(1);}/** * proceed_question * * Force the user to confirm an action before performing it. * Copy-paste from e2fsprogs */static void proceed_question(void){ char buf[256]; const char *short_yes = "yY"; fflush(stdout); fflush(stderr); printf("Are you sure you want to proceed (y/[n])? "); buf[0] = 0; fgets(buf, sizeof(buf), stdin); if (strchr(short_yes, buf[0]) == 0) { printf("OK quitting. NO CHANGES have been made to your " "NTFS volume.\n"); exit(1); }}/** * version - Print version information about the program * * Print a copyright statement and a brief description of the program. * * Return: none */static void version(void){ printf("\nResize an NTFS Volume, without data loss.\n\n"); printf("Copyright (c) 2002-2006 Szabolcs Szakacsits\n"); printf("Copyright (c) 2002-2005 Anton Altaparmakov\n"); printf("Copyright (c) 2002-2003 Richard Russon\n"); printf("\n%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);}/** * get_new_volume_size * * Convert a user-supplied string into a size. Without any suffix the number * will be assumed to be in bytes. If the number has a suffix of k, M or G it * will be scaled up by 1000, 1000000, or 1000000000. */static s64 get_new_volume_size(char *s){ s64 size; char *suffix; int prefix_kind = 1000; size = strtoll(s, &suffix, 10); if (size <= 0 || errno == ERANGE) err_exit("Illegal new volume size\n"); if (!*suffix) return size; if (strlen(suffix) == 2 && suffix[1] == 'i') prefix_kind = 1024; else if (strlen(suffix) > 1) usage(); /* We follow the SI prefixes: http://physics.nist.gov/cuu/Units/prefixes.html http://physics.nist.gov/cuu/Units/binary.html Disk partitioning tools use prefixes as, k M G fdisk 2.11x- 2^10 2^20 10^3*2^20 fdisk 2.11y+ 10^3 10^6 10^9 cfdisk 10^3 10^6 10^9 sfdisk 2^10 2^20 parted 2^10 2^20 (may change) fdisk (DOS) 2^10 2^20 */ /* FIXME: check for overflow */ switch (*suffix) { case 'G': size *= prefix_kind; case 'M': size *= prefix_kind; case 'k': size *= prefix_kind; break; default: usage(); } return size;}/** * parse_options - Read and validate the programs command line * * Read the command line, verify the syntax and parse the options. * This function is very long, but quite simple. * * Return: 1 Success * 0 Error, one or more problems */static int parse_options(int argc, char **argv){ static const char *sopt = "-bdfhinPs:vV"; static const struct option lopt[] = { { "bad-sectors",no_argument, NULL, 'b' },#ifdef DEBUG { "debug", no_argument, NULL, 'd' },#endif { "force", no_argument, NULL, 'f' }, { "help", no_argument, NULL, 'h' }, { "info", no_argument, NULL, 'i' }, { "no-action", no_argument, NULL, 'n' }, { "no-progress-bar", no_argument, NULL, 'P' }, { "size", required_argument, NULL, 's' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; int c; int err = 0; int ver = 0; int help = 0; memset(&opt, 0, sizeof(opt)); opt.show_progress = 1; while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { switch (c) { case 1: /* A non-option argument */ if (!err && !opt.volume) opt.volume = argv[optind-1]; else err++; break; case 'b': opt.badsectors++; break; case 'd':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -