1N/A/*
1N/A libparted - a library for manipulating disk partitions
1N/A Copyright (C) 2000, 2007, 2009-2010 Free Software Foundation, Inc.
1N/A
1N/A This program is free software; you can redistribute it and/or modify
1N/A it under the terms of the GNU General Public License as published by
1N/A the Free Software Foundation; either version 3 of the License, or
1N/A (at your option) any later version.
1N/A
1N/A This program is distributed in the hope that it will be useful,
1N/A but WITHOUT ANY WARRANTY; without even the implied warranty of
1N/A MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A GNU General Public License for more details.
1N/A
1N/A You should have received a copy of the GNU General Public License
1N/A along with this program. If not, see <http://www.gnu.org/licenses/>.
1N/A*/
1N/A
1N/A#include <config.h>
1N/A
1N/A#include <parted/parted.h>
1N/A#include <parted/endian.h>
1N/A#include <parted/debug.h>
1N/A
1N/A#if ENABLE_NLS
1N/A# include <libintl.h>
1N/A# define _(String) dgettext (PACKAGE, String)
1N/A#else
1N/A# define _(String) (String)
1N/A#endif /* ENABLE_NLS */
1N/A
1N/A#include <unistd.h>
1N/A#include <string.h>
1N/A#include <limits.h> /* for PATH_MAX */
1N/A
1N/A#define NTFS_BLOCK_SIZES ((int[2]){512, 0})
1N/A
1N/A#define NTFS_SIGNATURE "NTFS"
1N/A
1N/A#define NTFSRESIZE_CMD_PATH "ntfsresize"
1N/A#define NTFSCREATE_CMD_PATH "mkntfs"
1N/A#define NTFSFIX_CMD_PATH "ntfsfix"
1N/A#define NTFSCLONE_CMD_PATH "ntfsclone"
1N/A
1N/Astatic PedFileSystemType ntfs_type;
1N/A
1N/Astatic char bigbuf[128*1024]; /* for command output storage */
1N/A
1N/Astatic PedGeometry*
1N/Antfs_probe (PedGeometry* geom)
1N/A{
1N/A char buf[512];
1N/A
1N/A PED_ASSERT(geom != NULL, return 0);
1N/A
1N/A if (!ped_geometry_read (geom, buf, 0, 1))
1N/A return 0;
1N/A
1N/A if (strncmp (NTFS_SIGNATURE, buf + 3, strlen (NTFS_SIGNATURE)) == 0)
1N/A return ped_geometry_new (geom->dev, geom->start,
1N/A PED_LE64_TO_CPU (*(uint64_t*)
1N/A (buf + 0x28)));
1N/A else
1N/A return NULL;
1N/A}
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/Astatic int
1N/Antfs_clobber (PedGeometry* geom)
1N/A{
1N/A char buf[512];
1N/A
1N/A PED_ASSERT(geom != NULL, return 0);
1N/A
1N/A memset (buf, 0, sizeof(buf));
1N/A return ped_geometry_write (geom, buf, 0, 1);
1N/A}
1N/A
1N/Astatic PedFileSystem*
1N/Antfs_open (PedGeometry* geom)
1N/A{
1N/A PedFileSystem* fs;
1N/A
1N/A PED_ASSERT(geom != NULL, return 0);
1N/A
1N/A fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
1N/A if (!fs)
1N/A return NULL;
1N/A
1N/A fs->type = &ntfs_type;
1N/A fs->geom = ped_geometry_duplicate (geom);
1N/A fs->checked = 1; /* XXX */
1N/A fs->type_specific = NULL;
1N/A
1N/A return fs;
1N/A}
1N/A
1N/A/*
1N/A * Returns partition number (1..4) that contains geom, 0 otherwise.
1N/A */
1N/Astatic int
1N/A_get_partition_num_by_geom(const PedGeometry* geom)
1N/A{
1N/A PedDisk *disk;
1N/A PedPartition *part;
1N/A int partnum = 0;
1N/A
1N/A PED_ASSERT(geom != NULL, return 0);
1N/A
1N/A disk = ped_disk_new (geom->dev);
1N/A if (!disk) {
1N/A printf("_get_partition_num_by_geom: ped_disk_new failed!\n");
1N/A }
1N/A else {
1N/A part = ped_disk_get_partition_by_sector (disk, geom->start);
1N/A if (part == NULL) {
1N/A printf("_get_partition_num_by_geom: "
1N/A "ped_disk_get_partition_by_sector failed!\n");
1N/A }
1N/A else {
1N/A if (part->num > 0)
1N/A partnum = part->num;
1N/A }
1N/A ped_disk_destroy (disk);
1N/A }
1N/A return partnum;
1N/A}
1N/A
1N/A/*
1N/A * return the partition device name for geom in partpath.
1N/A * return 1 on success, 0 on failure.
1N/A */
1N/Astatic int
1N/A_get_part_device_path(const PedGeometry* geom, char *partpath, const int len)
1N/A{
1N/A int partnum;
1N/A
1N/A PED_ASSERT(geom != NULL, return 0);
1N/A PED_ASSERT(partpath != NULL, return 0);
1N/A
1N/A partnum = _get_partition_num_by_geom(geom);
1N/A if (!partnum)
1N/A return 0;
1N/A
1N/A strncpy(partpath, geom->dev->path, len);
1N/A /*
1N/A * XXX Solaris specific
1N/A * Create the path name to the *pn device, where n is the partition #
1N/A * geom->dev->path looks like this: "/devices/.../cmdk@0,0:q"
1N/A * or like this: "/dev/dsk/...p0"
1N/A * ":q" is the "/dev/dsk/...p0" device
1N/A * :r is p1, :s is p2, :t is p3, :u is p4
1N/A * 'q' + 1 == 'r'
1N/A * '0' + 1 == '1'
1N/A */
1N/A partpath[strlen(partpath) -1] += partnum;
1N/A
1N/A return 1;
1N/A}
1N/A
1N/A/*
1N/A * Executes cmd in a pipe.
1N/A * Returns -1 on popen failure or the return value from pclose.
1N/A * Saves the output from cmd in bigbuf for later display.
1N/A */
1N/Astatic int
1N/A_execute(const char *cmd)
1N/A{
1N/A FILE *fp;
1N/A char buf[512];
1N/A int szbigbuf;
1N/A
1N/A PED_ASSERT(cmd != NULL, return 0);
1N/A
1N/A fp = popen(cmd, "r");
1N/A if (fp == NULL)
1N/A return -1;
1N/A
1N/A strcpy(bigbuf, "");
1N/A szbigbuf = sizeof(bigbuf) -1;
1N/A
1N/A while (fgets(buf, sizeof(buf), fp) != NULL) {
1N/A if (szbigbuf > 0) {
1N/A strncat(bigbuf, buf, szbigbuf);
1N/A szbigbuf -= strlen(buf);
1N/A }
1N/A }
1N/A
1N/A return pclose(fp);
1N/A}
1N/A
1N/A/*
1N/A * ./mkntfs -f -s 512 -S 63 -H 255 -p 0 /dev/dsk/c0d0p1
1N/A * Returns new fs on success, NULL on failure.
1N/A */
1N/APedFileSystem*
1N/Antfs_create (PedGeometry* geom, PedTimer* timer)
1N/A{
1N/A int x;
1N/A PedFileSystem* fs = NULL;
1N/A char partpath[PATH_MAX];
1N/A char cmd[PATH_MAX];
1N/A
1N/A PED_ASSERT(geom != NULL, return 0);
1N/A PED_ASSERT(timer != NULL, return 0);
1N/A
1N/A ped_timer_reset (timer);
1N/A ped_timer_update (timer, 0.0);
1N/A ped_timer_set_state_name(timer, _("creating"));
1N/A
1N/A if (_get_part_device_path(geom, partpath, sizeof(partpath)) == 0)
1N/A goto error;
1N/A
1N/A snprintf(cmd, sizeof(cmd), "%s -f -s %lld -S %d -H %d -p %lld %s",
1N/A NTFSCREATE_CMD_PATH,
1N/A geom->dev->sector_size,
1N/A geom->dev->hw_geom.sectors,
1N/A geom->dev->hw_geom.heads,
1N/A (PedSector) 0, /* partition start sector */
1N/A partpath);
1N/A printf("%s\n", cmd);
1N/A
1N/A /*
1N/A * Use system() so the output that shows progress is displayed.
1N/A */
1N/A ped_device_begin_external_access(geom->dev);
1N/A x = system(cmd);
1N/A ped_device_end_external_access(geom->dev);
1N/A
1N/A if (x != 0) {
1N/A goto error;
1N/A }
1N/A
1N/A fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
1N/A if (!fs)
1N/A goto error;
1N/A fs->type = &ntfs_type;
1N/A fs->geom = ped_geometry_duplicate (geom);
1N/A fs->checked = 1; /* XXX */
1N/A fs->type_specific = NULL;
1N/A
1N/Aerror:
1N/A ped_timer_update (timer, 1.0);
1N/A return fs;
1N/A}
1N/A
1N/A/*
1N/A * Returns 1 on success, 0 on failure.
1N/A */
1N/Astatic int
1N/Antfs_close (PedFileSystem *fs)
1N/A{
1N/A PED_ASSERT(fs != NULL, return 0);
1N/A
1N/A ped_geometry_destroy (fs->geom);
1N/A free (fs);
1N/A
1N/A return 1;
1N/A}
1N/A
1N/A/*
1N/A * ntfsfix /dev/dsk/c0d0p1
1N/A * Returns 1 on success, 0 on failure.
1N/A */
1N/Astatic int
1N/Antfs_check(PedFileSystem *fs, PedTimer *timer)
1N/A{
1N/A int x;
1N/A int ret = 0;
1N/A char partpath[PATH_MAX];
1N/A char cmd[PATH_MAX];
1N/A
1N/A PED_ASSERT(fs != NULL, return 0);
1N/A PED_ASSERT(timer != NULL, return 0);
1N/A
1N/A ped_timer_reset(timer);
1N/A ped_timer_set_state_name(timer, _("checking"));
1N/A ped_timer_update(timer, 0.0);
1N/A
1N/A if (_get_part_device_path(fs->geom, partpath, sizeof(partpath)) == 0)
1N/A goto error;
1N/A
1N/A snprintf(cmd, sizeof(cmd), "%s %s",
1N/A NTFSFIX_CMD_PATH, partpath);
1N/A printf("%s\n", cmd);
1N/A
1N/A /*
1N/A * Use system() so the output that shows progress is displayed.
1N/A */
1N/A ped_device_begin_external_access(fs->geom->dev);
1N/A x = system(cmd);
1N/A ped_device_end_external_access(fs->geom->dev);
1N/A
1N/A if (x == 0) {
1N/A ret = 1; /* return success to the upper layer */
1N/A }
1N/A else {
1N/A goto error;
1N/A }
1N/A
1N/Aerror:
1N/A ped_timer_update(timer, 1.0);
1N/A return ret;
1N/A}
1N/A
1N/A/*
1N/A * Copy from source fs to destination geom.
1N/A * The destination partition must alreay exist.
1N/A * ntfsclone --overwrite destination-device source-device
1N/A * Returns new fs on success, NULL on failure.
1N/A */
1N/Astatic PedFileSystem*
1N/Antfs_copy(const PedFileSystem *fs, PedGeometry *geom, PedTimer *timer)
1N/A{
1N/A int x;
1N/A char spartpath[PATH_MAX];
1N/A char dpartpath[PATH_MAX];
1N/A char cmd[PATH_MAX];
1N/A PedFileSystem *new_fs = NULL;
1N/A
1N/A PED_ASSERT(fs != NULL, return 0);
1N/A PED_ASSERT(geom != NULL, return 0);
1N/A PED_ASSERT(timer != NULL, return 0);
1N/A
1N/A ped_timer_reset(timer);
1N/A ped_timer_set_state_name(timer, _("copying"));
1N/A ped_timer_update(timer, 0.0);
1N/A
1N/A if (_get_part_device_path(fs->geom, spartpath, sizeof(spartpath)) == 0)
1N/A goto error;
1N/A
1N/A if (_get_part_device_path(geom, dpartpath, sizeof(dpartpath)) == 0)
1N/A goto error;
1N/A
1N/A snprintf(cmd, sizeof(cmd), "%s --overwrite %s %s",
1N/A NTFSCLONE_CMD_PATH, dpartpath, spartpath);
1N/A printf("%s\n", cmd);
1N/A
1N/A /*
1N/A * Use system() so the output that shows progress is displayed.
1N/A */
1N/A ped_device_begin_external_access(geom->dev);
1N/A x = system(cmd);
1N/A ped_device_end_external_access(geom->dev);
1N/A
1N/A if (x != 0) {
1N/A goto error;
1N/A }
1N/A
1N/A if (!(new_fs = (PedFileSystem *) ped_malloc(sizeof(PedFileSystem))))
1N/A goto error;
1N/A
1N/A new_fs->type = &ntfs_type;
1N/A new_fs->geom = ped_geometry_duplicate(geom);
1N/A new_fs->checked = 0;
1N/A new_fs->type_specific = NULL;
1N/A
1N/Aerror:
1N/A ped_timer_update(timer, 1.0);
1N/A return new_fs;
1N/A}
1N/A
1N/A/*
1N/A * fs->geom has the current filesystem size in sectors.
1N/A * geom has the new, requested filesystem size in sectors.
1N/A *
1N/A * fs->geom->dev is the same object as geom->dev.
1N/A * geom->dev->path looks like this:
1N/A * /dev/dsk/...p0
1N/A * or this:
1N/A * /devices/.../cmdk@0,0:q
1N/A *
1N/A * The ntfsresize cmd wants the block disk device, not the raw one.
1N/A * It also wants the partition device, not the whole disk.
1N/A *
1N/A * Returns 1 on success, 0 on failure.
1N/A */
1N/Astatic int
1N/Antfs_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
1N/A{
1N/A int x;
1N/A int ret = 0; /* this tells the upper layer NOT to resize partition */
1N/A char partpath[PATH_MAX];
1N/A char cmd[PATH_MAX];
1N/A
1N/A PED_ASSERT(fs != NULL, return 0);
1N/A PED_ASSERT(geom != NULL, return 0);
1N/A PED_ASSERT(timer != NULL, return 0);
1N/A
1N/A if (fs->geom->start != geom->start) {
1N/A ped_exception_throw(PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("Sorry, can't move the start of "
1N/A "ntfs partitions yet."));
1N/A return 0;
1N/A }
1N/A
1N/A ped_timer_reset (timer);
1N/A ped_timer_update (timer, 0.0);
1N/A
1N/A if (fs->geom->length > geom->length) {
1N/A ped_timer_set_state_name(timer, _("shrinking"));
1N/A }
1N/A else if (fs->geom->length < geom->length) {
1N/A ped_timer_set_state_name(timer, _("enlarging"));
1N/A }
1N/A else {
1N/A ped_timer_set_state_name(timer, _("no change"));
1N/A }
1N/A
1N/A if (_get_part_device_path(fs->geom, partpath, sizeof(partpath)) == 0)
1N/A goto error1;
1N/A
1N/A ped_device_begin_external_access(geom->dev);
1N/A
1N/A /*
1N/A * ntfsresize -f says don't worry about consistency flag
1N/A */
1N/A snprintf(cmd, sizeof(cmd), "%s -f -i %s",
1N/A NTFSRESIZE_CMD_PATH, partpath);
1N/A printf("%s\n", cmd);
1N/A x = _execute(cmd);
1N/A if (x != 0) {
1N/A printf("ntfsresize had this message:\n%s\n", bigbuf);
1N/A goto error2;
1N/A }
1N/A
1N/A snprintf(cmd, sizeof(cmd), "%s -f -n -s %lld %s",
1N/A NTFSRESIZE_CMD_PATH,
1N/A geom->length * geom->dev->sector_size, partpath);
1N/A printf("%s\n", cmd);
1N/A x = _execute(cmd);
1N/A if (x != 0) {
1N/A printf("ntfsresize had this message:\n%s\n", bigbuf);
1N/A goto error2;
1N/A }
1N/A
1N/A /*
1N/A * ntfsresize -f -f means don't ask "Are you sure?"
1N/A * Use system() so the output that shows progress is displayed.
1N/A */
1N/A snprintf(cmd, sizeof(cmd), "%s -f -f -s %lld %s",
1N/A NTFSRESIZE_CMD_PATH,
1N/A geom->length * geom->dev->sector_size, partpath);
1N/A printf("%s\n", cmd);
1N/A x = system(cmd);
1N/A if (x == 0) {
1N/A ret = 1; /* this tells upper layer to resize the partition */
1N/A }
1N/A else {
1N/A goto error2;
1N/A }
1N/A
1N/Aerror2:
1N/A ped_device_end_external_access(geom->dev);
1N/Aerror1:
1N/A ped_timer_update (timer, 1.0);
1N/A return ret;
1N/A}
1N/A
1N/A/*
1N/A * return the minimum resize size from the ntfsresize external cmd
1N/A * in blocks, 0 on error.
1N/A * Saves the output from cmd in bigbuf for later display.
1N/A */
1N/Astatic PedSector
1N/A_get_min_from_ntfsresize(const char *cmd)
1N/A{
1N/A FILE *fp;
1N/A char buf[512];
1N/A PedSector size = 0;
1N/A int x;
1N/A int szbigbuf;
1N/A
1N/A PED_ASSERT(cmd != NULL, return 0);
1N/A
1N/A fp = popen(cmd, "r");
1N/A if (fp == NULL)
1N/A return 0;
1N/A
1N/A strcpy(bigbuf, "");
1N/A szbigbuf = sizeof(bigbuf) -1;
1N/A
1N/A while (fgets(buf, sizeof(buf), fp) != NULL) {
1N/A if (szbigbuf > 0) {
1N/A strncat(bigbuf, buf, szbigbuf);
1N/A szbigbuf -= strlen(buf);
1N/A }
1N/A x = sscanf(buf, "You might resize at %lld", &size);
1N/A if (x > 0)
1N/A break;
1N/A }
1N/A
1N/A pclose(fp);
1N/A return size;
1N/A}
1N/A
1N/A/*
1N/A * return the minimum resize size in blocks, fs->geom->length on error.
1N/A */
1N/Astatic PedSector
1N/A_get_min_resize_size (const PedFileSystem* fs)
1N/A{
1N/A PedSector max_length = fs->geom->length;
1N/A PedSector length;
1N/A char partpath[PATH_MAX];
1N/A char cmd[PATH_MAX];
1N/A
1N/A PED_ASSERT(fs != NULL, return 0);
1N/A
1N/A if (_get_part_device_path(fs->geom, partpath, sizeof(partpath)) == 0)
1N/A return max_length;
1N/A
1N/A snprintf(cmd, sizeof(cmd), "%s -f -i %s",
1N/A NTFSRESIZE_CMD_PATH, partpath);
1N/A
1N/A length = _get_min_from_ntfsresize(cmd);
1N/A if (length == 0) {
1N/A printf("ntfsresize had this message:\n%s\n", bigbuf);
1N/A return max_length;
1N/A }
1N/A
1N/A return (length / fs->geom->dev->sector_size);
1N/A}
1N/A
1N/APedConstraint*
1N/Antfs_get_copy_constraint (const PedFileSystem* fs, const PedDevice* dev)
1N/A{
1N/A PedGeometry full_dev;
1N/A
1N/A PED_ASSERT(fs != NULL, return 0);
1N/A PED_ASSERT(dev != NULL, return 0);
1N/A
1N/A if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
1N/A return NULL;
1N/A
1N/A return ped_constraint_new (ped_alignment_any, ped_alignment_any,
1N/A &full_dev, &full_dev,
1N/A _get_min_resize_size (fs),
1N/A dev->length);
1N/A}
1N/A
1N/APedConstraint*
1N/Antfs_get_resize_constraint (const PedFileSystem* fs)
1N/A{
1N/A PED_ASSERT(fs != NULL, return 0);
1N/A
1N/A return ntfs_get_copy_constraint (fs, fs->geom->dev);
1N/A}
1N/A
1N/A#endif /* !DISCOVER_ONLY */
1N/A
1N/Astatic PedFileSystemOps ntfs_ops = {
1N/A .probe = ntfs_probe,
1N/A#ifndef DISCOVER_ONLY
1N/A .clobber = ntfs_clobber,
1N/A .open = ntfs_open,
1N/A .create = ntfs_create,
1N/A .close = ntfs_close,
1N/A .check = ntfs_check,
1N/A .copy = ntfs_copy,
1N/A .resize = ntfs_resize,
1N/A .get_create_constraint = NULL,
1N/A .get_resize_constraint = ntfs_get_resize_constraint,
1N/A .get_copy_constraint = ntfs_get_copy_constraint
1N/A#else
1N/A .clobber = NULL,
1N/A .open = NULL,
1N/A .create = NULL,
1N/A .close = NULL,
1N/A .check = NULL,
1N/A .copy = NULL,
1N/A .resize = NULL,
1N/A .get_create_constraint = NULL,
1N/A .get_resize_constraint = NULL,
1N/A .get_copy_constraint = NULL
1N/A#endif
1N/A};
1N/A
1N/Astatic PedFileSystemType ntfs_type = {
1N/A .next = NULL,
1N/A .ops = &ntfs_ops,
1N/A .name = "ntfs",
1N/A .block_sizes = NTFS_BLOCK_SIZES
1N/A};
1N/A
1N/Avoid
1N/Aped_file_system_ntfs_init ()
1N/A{
1N/A ped_file_system_type_register (&ntfs_type);
1N/A}
1N/A
1N/Avoid
1N/Aped_file_system_ntfs_done ()
1N/A{
1N/A ped_file_system_type_unregister (&ntfs_type);
1N/A}
1N/A
1N/A