resize.c revision 7e7bd3dccbfe8f79e25e5c1554b5bc3a9aaca321
/*
libparted
Copyright (C) 1998, 1999, 2000, 2007 Free Software Foundation, Inc.
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 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. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "fat.h"
#include "traverse.h"
#include "count.h"
#include "fatio.h"
#include "calc.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#ifndef DISCOVER_ONLY
/* Recursively builds (i.e. makes consistent) the duplicated directory tree
* (leaving the original directory tree in tact)
*/
static int
{
break;
continue;
if (!sub_dir_info)
return 0;
return 0;
}
}
/* remove "stale" entries at the end */
}
return 1;
}
static int
{
== new_fs_info->root_dir_sector_count, return 0);
return 0;
return 0;
return 1;
}
/*
Constructs the new directory tree for legacy (FAT16) file systems.
*/
static int
{
if (!duplicate_legacy_root_dir (ctx))
return 0;
}
/*
Constructs the new directory tree for new (FAT32) file systems.
*/
static int
{
"\\");
return 1;
}
/* Converts the root directory between FAT16 and FAT32. NOTE: this code
* can also do no conversion. I'm leaving fat_construct_directory(), because
* it's really pretty :-) It also leaves a higher chance of deleted file
* recovery, because it doesn't remove redundant entries. (We do this here,
* because brain-damaged FAT16 has an arbitary limit on root directory entries,
* so we save room)
*/
static int
{
break;
if (!fat_dir_entry_is_active (old_dir_entry))
continue;
if (!new_dir_entry) {
return ped_exception_throw (PED_EXCEPTION_ERROR,
_("There's not enough room in the root "
"directory for all of the files. Either "
"cancel, or ignore to lose the files."))
}
continue;
if (!sub_old_dir_trav || !sub_new_dir_trav)
return 0;
return 0;
}
}
/* remove "stale" entries at the end, just in case there is some
* overlap
*/
}
return 1;
}
static void
{
}
/* This MUST be called BEFORE the fat_construct_new_fat(), because cluster
* allocation depend on the old FAT. The reason is, old clusters may
* still be needed during the resize, (particularly clusters in the directory
* tree) even if they will be discarded later.
*/
static int
{
FatCluster i;
for (i = 0; i < cluster_count; i++) {
if (!cluster)
return 0;
}
ctx->new_root_dir [i] = 0;
return 1;
}
/* when converting FAT32 -> FAT16
* fat_duplicate clusters() duplicated the root directory unnecessarily.
* Let's free it.
*
* This must be called AFTER fat_construct_new_fat(). (otherwise, our
* changes just get overwritten)
*/
static int
{
FatFragment i;
for (i = 0; i < new_fs_info->cluster_frags; i++) {
old_frag + i);
return 0;
}
}
return 1;
}
static int
{
int i;
for (i = 0; i < fs_info->root_dir_sector_count; i++) {
_("Error writing to the root directory."))
return 0;
}
}
return 1;
}
static int
{
"\\");
} else {
"\\");
}
if (!new_trav_info || !old_trav_info)
return 0;
return 0;
return 1;
}
/*
Constructs the new directory tree to match the new file locations.
*/
static int
{
switch (old_fs_info->fat_type) {
case FAT_TYPE_FAT12:
PED_ASSERT (0, (void) 0);
break;
case FAT_TYPE_FAT16:
return fat_construct_legacy_root (ctx);
case FAT_TYPE_FAT32:
return fat_construct_root (ctx);
}
} else {
return fat_construct_converted_tree (ctx);
}
return 0;
}
static FatFragment
{
return frag + 1;
else
return -1;
} else {
return -1;
else
}
}
/*
Constructs the new fat for the resized file system.
*/
static int
{
int i;
return 0;
if (flag == FAT_FLAG_FREE)
continue;
if (flag == FAT_FLAG_BAD) {
if (new_frag == -1)
continue;
new_frag);
continue;
}
if (old_next_frag == -1) {
continue;
}
}
#if 0
#ifdef PED_VERBOSE
old_cluster++) {
continue;
printf ("%d->%d\t(next: %d->%d)\n",
}
#endif /* PED_VERBOSE */
#endif
}
ctx->new_root_dir[i],
}
}
return 1;
}
static int
{
char* fat16_msg;
char* fat32_msg;
fat16_msg = _("If you leave your file system as FAT16, "
"then you will have no problems.");
else
fat16_msg = _("If you convert to FAT16, and MS Windows "
"is installed on this partition, then "
"you must re-install the MS Windows boot "
"loader. If you want to do this, you "
"should consult the Parted manual (or "
"your distribution's manual).");
fat32_msg = _("If you leave your file system as FAT32, "
"then you will not introduce any new "
"problems.");
else
fat32_msg = _("If you convert to FAT32, and MS Windows "
"is installed on this partition, then "
"you must re-install the MS Windows boot "
"loader. If you want to do this, you "
"should consult the Parted manual (or "
"your distribution's manual). Also, "
"converting to FAT32 will make the file "
"system unreadable by MS DOS, MS Windows "
"95a, and MS Windows NT.");
_("%s %s %s"),
_("Would you like to use FAT32?"),
switch (status) {
case PED_EXCEPTION_YES:
return 1;
case PED_EXCEPTION_NO:
return 1;
case PED_EXCEPTION_UNHANDLED:
return 1;
case PED_EXCEPTION_CANCEL:
return 0;
default:
PED_ASSERT (0, (void) 0);
break;
}
}
if (fat16_ok) {
_("%s %s"),
_("The file system can only be resized to this "
"size by converting to FAT16."),
if (status == PED_EXCEPTION_CANCEL)
return 0;
}
return 1;
}
if (fat32_ok) {
_("%s %s"),
_("The file system can only be resized to this "
"size by converting to FAT32."),
if (status == PED_EXCEPTION_CANCEL)
return 0;
}
return 1;
}
_("GNU Parted cannot resize this partition to this size. "
"We're working on it!"));
return 0;
}
/* For resize operations: determine if the file system must be FAT16 or FAT32,
* or either. If the new file system must be FAT32, then query for
* confirmation. If either file system can be used, query for which one.
*/
static int
{
int fat16_ok;
int fat32_ok;
}
/* Creates the PedFileSystem struct for the new resized file system, and
sticks it in a FatOpContext. At the end of the process, the original
(ctx->old_fs) is destroyed, and replaced with the new one (ctx->new_fs).
*/
static FatOpContext*
{
/* hypothetical number of root dir sectors, if we end up using
* FAT16
*/
if (fs_info->root_dir_sector_count)
else
* sizeof (FatDirEntry) / 512;
return 0;
goto error;
if (!new_fs)
goto error;
if (!new_fs_info)
goto error_free_new_fs;
/* preserve boot code, etc. */
sizeof (FatBootSector));
sizeof (FatInfoSector));
/* what about copying? */
new_fs_info->root_dir_offset = 0;
/* we add calc_align_sectors to push the cluster_offset
forward, to keep the clusters aligned between the new
and old file systems
*/
} else {
}
if (!context)
goto error_free_new_fs_info;
goto error_free_context;
if (!fat_alloc_buffers (new_fs))
goto error_free_fat;
return context;
return NULL;
}
static int
{
? &fat16_type
: &fat32_type;
return 1;
}
static int
{
return 1;
}
/* copies the "hidden" sectors, between the boot sector and the FAT. Required,
* for the Windows 98 FAT32 boot loader
*/
int
{
/* nothing to copy for FAT16 */
return 1;
return 0;
return 0;
return 1;
}
int
{
if (!ctx)
goto error;
goto error_abort_ctx;
if (!alloc_root_dir (ctx))
goto error_abort_ctx;
}
if (!fat_construct_new_fat (ctx))
goto error_abort_ctx;
if (!free_root_dir (ctx))
goto error_abort_ctx;
}
if (!fat_construct_dir_tree (ctx))
goto error_abort_ctx;
goto error_abort_ctx;
}
if (!resize_context_assimilate (ctx))
goto error;
return 1;
return 0;
}
#endif /* !DISCOVER_ONLY */