gparted/include/GParted_Core.h

218 lines
10 KiB
C
Raw Normal View History

/* Copyright (C) 2004 Bart
* Copyright (C) 2008, 2009, 2010, 2011, 2012 Curtis Gedak
*
* 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; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GPARTED_GPARTED_CORE_H
#define GPARTED_GPARTED_CORE_H
Add BlockSpecial into mount_info and fstab_info (#767842) On some distributions having btrfs on top of LUKS encrypted partitions, adding a second device and removing the first device used to mount the file system causes GParted to no longer be able to report the file system as busy or the mount points themselves. For example, on CentOS 7, create a single btrfs file system and mount it. The provided /dev/mapper/sdb1_crypt name is reported, via /proc/mounts, as the mounting device: # cryptsetup luksFormat --force-password /dev/sdb1 # cryptsetup luksOpen /dev/sdb1 sdb1_crypt # mkfs.btrfs -L encrypted-btrfs /dev/mapper/sdb1_crypt # mount /dev/mapper/sdb1_crypt /mnt/1 # ls -l /dev/mapper total 0 lrwxrwxrwx. 1 root root 7 Jul 2 14:15 centos-root -> ../dm-1 lrwxrwxrwx. 1 root root 7 Jul 2 14:15 centos-swap -> ../dm-0 crw-------. 1 root root 10, 236 Jul 2 14:15 control lrwxrwxrwx. 1 root root 7 Jul 2 15:14 sdb1_crypt -> ../dm-2 # fgrep btrfs /proc/mounts /dev/mapper/sdb1_crypt /mnt/1 btrfs rw,seclabel,relatime,space_cache 0 0 Add a second device to the btrfs file system: # cryptsetup luksFormat --force-password /dev/sdb2 # cryptsetup luksOpen /dev/sdb2 sdb2_crypt # btrfs device add /dev/mapper/sdb2_crypt /mnt/1 # ls -l /dev/mapper ... lrwxrwxrwx. 1 root root 7 Jul 2 15:12 sdb2_crypt -> ../dm-3 # btrfs filesystem show /dev/mapper/sdb1_crypt Label: 'encrypted-btrfs' uuid: 45d7b1ef-820c-4ef8-8abd-c70d928afb49 Total devices 2 FS bytes used 32.00KiB devid 1 size 1022.00MiB used 12.00MiB path /dev/mapper/sdb1_crypt devid 2 size 1022.00MiB used 0.00B path /dev/mapper/sdb2_crypt Remove the first mounting device from the btrfs file system. Now the non-canonical name /dev/dm-3 is reported, via /proc/mounts, as the mounting device: # btrfs device delete /dev/mapper/sdb1_crypt /mnt/1 # btrfs filesystem show /dev/mapper/sdb2_crypt Label: 'encrypted-btrfs' uuid: 45d7b1ef-820c-4ef8-8abd-c70d928afb49 Total devices 1 FS bytes used 96.00KiB devid 2 size 1022.00MiB used 144.00MiB path /dev/mapper/sdb2_crypt # fgrep btrfs /proc/mounts /dev/dm-3 /mnt/1 btrfs rw,seclabel,relatime,space_cache 0 0 # ls -l /dev/dm-3 brw-rw----. 1 root disk 253, 3 Jul 2 15:12 /dev/dm-3 GParted loads the mount_info mapping from /proc/mounts and with it the /dev/dm-3 name. When GParted is determining if the encrypted btrfs file system is mounted or getting the mount points it is using the /dev/mapper/sdb2_crypt name. Therefore no information is found and the file system is incorrectly reported as unmounted. Fix by changing mount_info and fstab_info to use BlockSpecial objects instead of strings so that matching is performed by major, minor device numbers rather than by string compare. Note that as BlockSpecial objects are used as the key of std::map [1] mappings operator<() [2] needs to be provided to order the key values. [1] std::map http://www.cplusplus.com/reference/map/map/ [2] std::map::key_comp http://www.cplusplus.com/reference/map/map/key_comp/ Bug 767842 - File system usage missing when tools report alternate block device names
2016-06-25 01:29:17 -06:00
#include "../include/BlockSpecial.h"
#include "../include/FileSystem.h"
#include "../include/Operation.h"
#include "../include/Partition.h"
#include "../include/PartitionLUKS.h"
#include "../include/PartitionVector.h"
#include <parted/parted.h>
#include <vector>
#include <fstream>
namespace GParted
{
class GParted_Core
{
public:
static Glib::Thread *mainthread;
GParted_Core() ;
~GParted_Core() ;
static void find_supported_core();
void find_supported_filesystems() ;
void set_user_devices( const std::vector<Glib::ustring> & user_devices ) ;
void set_devices( std::vector<Device> & devices ) ;
void set_devices_thread( std::vector<Device> * pdevices );
void guess_partition_table(const Device & device, Glib::ustring &buff);
bool snap_to_cylinder( const Device & device, Partition & partition, Glib::ustring & error ) ;
bool snap_to_mebibyte( const Device & device, Partition & partition, Glib::ustring & error ) ;
bool snap_to_alignment( const Device & device, Partition & partition, Glib::ustring & error ) ;
bool apply_operation_to_disk( Operation * operation );
bool set_disklabel( const Device & device, const Glib::ustring & disklabel );
Fix failure to recognise whole disk file systems in certain cases (#743181) When the following conditions were met GParted would fail to recognise a newly created whole disk device file system, and instead show an unknown file system filling the disk: 1) Disk was previously partitioned and contained at least one partition. 2) Using libparted version 2.0 to 3.0 inclusive. Initial status: # blkid | fgrep sdc # fgrep sdc /proc/partitions 8 32 976762584 sdc 8 33 104857600 sdc1 # parted /dev/sdc GNU Parted 2.4 Using /dev/sdc Welcome to GNU Parted! Type 'help' to view a list of commands. (parted) print Model: ATA ST1000LM024 HN-M (scsi) Disk /dev/sdc: 1000GB Sector size (logical/physical): 512B/4096B Partition Table: msdos Number Start End Size Type File system Flags 1 1049kB 107GB 107GB primary When creating the loop partition table libparted would not inform the kernel to delete the old partitions. /proc/partitions still contained the details of the old partitions. (parted) mktable loop Warning: The existing disk label on /dev/sdc will be destroyed and all data on this disk will be lost. Do you want to continue? Yes/No? Yes (parted) print Model: ATA ST1000LM024 HN-M (scsi) Disk /dev/sdc: 1000GB Sector size (logical/physical): 512B/4096B Partition Table: loop Number Start End Size File system Flags (parted) quit # fgrep sdc /proc/partitions 8 32 976762584 sdc 8 33 104857600 sdc1 Creation of the whole disk device file system goes unnoticed by blkid because the kernel and therefore blkid's cache have stale partition information. # mkfs.xfs -f /dev/sdc # blkid | fgrep sdc NOTE: On a Linux Software RAID array, as opposed to a hard disk, blkid does notice creation of the whole disk device file system. However the kernel still has old partition details. This was fixed in libparted 3.1 by commit: http://git.savannah.gnu.org/cgit/parted.git/commit/?id=f5c909c0cd50ed52a48dae6d35907dc08b137e88 libparted: remove has_partitions check to allow loopback partitions Fix by deleting old partitions before creating the loop table when compiled with a broken version of libparted. The GParted UI provides no feedback while a new partition table is created, and with some versions of GTK the UI become unresponsive too, so it is important to be as fast as possible. Evaluated three different methods, deleting 15 and 22 MSDOS partitions on a physical 5400 RPM hard drive using libparted 2.4: M1) Delete and commit one partition at a time. Takes up to 24 seconds to delete 15 partitions. With 22 partitions libparted always reports finding some of the partitions busy and unable to inform the kernel about the modifications. Too slow and doesn't work. M2) Delete all partitions in one go and commit once. Takes up to 1.4 seconds to delete either 15 or 22 partitions. Never removes partitions 17 and higher from the kernel. Doesn't work. M3) Write GPT table (letting libparted delete any old partitions). Takes up to 0.8 seconds to delete either 15 or 22 partitions. Fast and works. Use method 3 - write a GPT table thus using libparted code to inform the kernel of the old partition deletions. Bug 743181 - Add unpartitioned drive read-write support
2015-02-21 09:43:42 -07:00
bool new_disklabel( const Glib::ustring & device_path, const Glib::ustring & disklabel,
bool recreate_dmraid_devs = true );
bool toggle_flag( const Partition & partition, const Glib::ustring & flag, bool state ) ;
const std::vector<FS> & get_filesystems() const ;
const FS & get_fs( GParted::FILESYSTEM filesystem ) const ;
static std::vector<Glib::ustring> get_disklabeltypes() ;
std::map<Glib::ustring, bool> get_available_flags( const Partition & partition ) ;
Glib::ustring get_libparted_version() ;
Glib::ustring get_thread_status_message() ;
static FileSystem * get_filesystem_object( FILESYSTEM filesystem );
static bool supported_filesystem( FILESYSTEM fstype );
static bool filesystem_resize_disallowed( const Partition & partition ) ;
static void insert_unallocated( const Glib::ustring & device_path,
PartitionVector & partitions,
Sector start,
Sector end,
Byte_Value sector_size,
bool inside_extended );
private:
//detectionstuff..
void set_thread_status_message( Glib::ustring msg ) ;
static Glib::ustring get_partition_path( PedPartition * lp_partition );
void set_device_serial_number( Device & device );
void set_device_partitions( Device & device, PedDevice* lp_device, PedDisk* lp_disk ) ;
void set_device_one_partition( Device & device, PedDevice * lp_device, FILESYSTEM fstype,
std::vector<Glib::ustring> & messages );
void set_luks_partition( PartitionLUKS & partition );
void set_partition_label_and_uuid( Partition & partition );
static FILESYSTEM detect_filesystem_internal( PedDevice * lp_device, PedPartition * lp_partition );
static FILESYSTEM detect_filesystem( PedDevice * lp_device, PedPartition * lp_partition,
std::vector<Glib::ustring> & messages );
void read_label( Partition & partition ) ;
void read_uuid( Partition & partition ) ;
void set_mountpoints( Partition & partition );
bool set_mountpoints_helper( Partition & partition, const Glib::ustring & path );
bool is_busy( FILESYSTEM fstype, const Glib::ustring & path ) ;
void set_used_sectors( Partition & partition, PedDisk* lp_disk );
void mounted_set_used_sectors( Partition & partition ) ;
#ifdef HAVE_LIBPARTED_FS_RESIZE
void LP_set_used_sectors( Partition & partition, PedDisk* lp_disk ) ;
#endif
void set_flags( Partition & partition, PedPartition* lp_partition ) ;
//operationstuff...
bool create( Partition & new_partition, OperationDetail & operationdetail );
bool create_partition( Partition & new_partition, OperationDetail & operationdetail, Sector min_size = 0 ) ;
bool create_filesystem( const Partition & partition, OperationDetail & operationdetail ) ;
bool format( const Partition & partition, OperationDetail & operationdetail ) ;
bool delete_partition( const Partition & partition, OperationDetail & operationdetail );
bool remove_filesystem( const Partition & partition, OperationDetail & operationdetail ) ;
bool label_filesystem( const Partition & partition, OperationDetail & operationdetail );
bool name_partition( const Partition & partition, OperationDetail & operationdetail );
bool change_filesystem_uuid( const Partition & partition, OperationDetail & operation_detail );
bool resize_move( const Partition & partition_old,
Partition & partition_new,
OperationDetail & operationdetail );
bool move( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail );
bool move_filesystem( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail ) ;
#ifdef HAVE_LIBPARTED_FS_RESIZE
bool resize_move_filesystem_using_libparted( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail ) ;
void thread_lp_ped_file_system_resize( PedFileSystem * fs,
PedGeometry * lp_geom,
bool * return_value );
#endif
bool resize( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail ) ;
bool resize_move_partition( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail ) ;
bool resize_filesystem( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail,
bool fill_partition = false ) ;
bool maximize_filesystem( const Partition & partition, OperationDetail & operationdetail ) ;
bool copy( const Partition & partition_src,
Partition & partition_dst,
OperationDetail & operationdetail );
bool copy_filesystem( const Partition & partition_src,
Partition & partition_dst,
OperationDetail & operationdetail );
bool copy_filesystem_internal( const Partition & partition_src,
const Partition & partition_dst,
OperationDetail & operationdetail,
bool cancel_safe );
bool copy_filesystem_internal( const Partition & partition_src,
const Partition & partition_dst,
OperationDetail & operationdetail,
Byte_Value & total_done,
bool cancel_safe );
bool copy_blocks( const Glib::ustring & src_device,
const Glib::ustring & dst_device,
Sector src_start,
Sector dst_start,
Byte_Value src_sector_size,
Byte_Value dst_sector_size,
Byte_Value src_length,
OperationDetail & operationdetail,
Byte_Value & total_done,
bool cancel_safe );
void rollback_transaction( const Partition & partition_src,
const Partition & partition_dst,
OperationDetail & operationdetail,
Byte_Value total_done ) ;
bool check_repair_filesystem( const Partition & partition, OperationDetail & operationdetail ) ;
bool set_partition_type( const Partition & partition, OperationDetail & operationdetail ) ;
bool calibrate_partition( Partition & partition, OperationDetail & operationdetail ) ;
bool calculate_exact_geom( const Partition & partition_old,
Partition & partition_new,
OperationDetail & operationdetail ) ;
Use wipefs to clear old signatures before creating new file systems (#688882) Previously the function erase_filesystem_signatures() was used to clear file system signatures when a new partition was created and when an existing partition was formatted with a file system. However this was only available with libparted <= 2.4 and then only for the file systems which libparted supports. Having multiple different file system signatures on a partition leads to misidentification of file system. For example creating a nilfs2 over the top of a fat32 file system is detected as a fat32, not nilfs2. This shows that old file system signatures must be cleared before a new file system is created. Fix by always using "wipefs -a /dev/PARTITION" command to clear all old file system signatures rather than libparted API calls. Failure from wipefs is only considered a warning so doesn't fail the file system creation. (This doesn't yet fully meet the "MUST be cleared" requirement above. Will be fully met later in this patchset). Output from the wipefs command is displayed as a new sub-step which looks like this: v Format /dev/sda7 as xfs 00:00:05 > calibrate /dev/sda14 00:00:01 v clear old file system signatures in /dev/sda7 00:00:01 [NEW] > wipefs -a /dev/sda7 [NEW] > set partition type on /dev/sda7 00:00:02 v create new xfs file system 00:00:01 > mkfs.xfs -f -L "" /dev/sda7 Also signatures are only cleared immediately before a new file system is written and not when an unformatted partition is created. This allows recovery from accidental partition deletion by re-creating the deleted partition as unformatted. Bug #688882 - Improve clearing of file system signatures
2012-12-01 05:49:29 -07:00
bool erase_filesystem_signatures( const Partition & partition, OperationDetail & operationdetail ) ;
bool update_bootsector( const Partition & partition, OperationDetail & operationdetail ) ;
//general..
static void init_filesystems();
static void fini_filesystems();
static bool flush_device( PedDevice * lp_device );
static bool get_device( const Glib::ustring & device_path, PedDevice *& lp_device, bool flush = false );
static bool get_disk( PedDevice *& lp_device, PedDisk *& lp_disk, bool strict = true );
static bool get_device_and_disk( const Glib::ustring & device_path,
PedDevice*& lp_device, PedDisk*& lp_disk, bool strict = true, bool flush = false );
static void destroy_device_and_disk( PedDevice*& lp_device, PedDisk*& lp_disk );
static bool commit( PedDisk* lp_disk );
static bool commit_to_os( PedDisk* lp_disk, std::time_t timeout );
static void settle_device( std::time_t timeout );
static bool useable_device( PedDevice * lp_device );
static PedExceptionOption ped_exception_handler( PedException * e ) ;
std::vector<FS> FILESYSTEMS ;
static std::map< FILESYSTEM, FileSystem * > FILESYSTEM_MAP ;
std::vector<PedPartitionFlag> flags;
std::vector<Glib::ustring> device_paths ;
bool probe_devices ;
Glib::ustring thread_status_message; //Used to pass data to show_pulsebar method
Glib::RefPtr<Glib::IOChannel> iocInput, iocOutput; // Used to send data to gpart command
};
} //GParted
#endif /* GPARTED_GPARTED_CORE_H */