A user reported that GParted was slow to refresh on FAT32 file systems:
"can take very long, up to several minutes; can be reproduced by running
dosfsck manually". This is because the file system was large and almost
full, and GParted performs a file system check just to to report the
file system usage.
Created a 4 GiB FAT32 file system and almost filled it with 4 KiB files,
just over 970,000 files.
# df -k /mnt/2
Filesystem 1K-blocks Used Available Used% Mounted on
/dev/sdb2 4186108 39155384 270724 94% /mnt/2
# df -i /mnt/2
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sdb2 0 0 0 - /mnt/2
# find /mnt/2 -type f -print | wc -l
971059
# find /mnt/2 -type d -print | wc -l
1949
Testing performance of the current fsck.fat:
# time fsck.fat -n -v /dev/sdb2 | \
> egrep 'bytes per logical sector|bytes per cluster|sectors total|clusters$'
512 bytes per logical sector
4096 bytes per cluster
8388608 sectors total
/dev/sdb2: 973008 files, 978846/1046527 clusters
real 0m11.552s
user 0m2.183s
sys 0m7.547s
Free sectors in the file system according to fsck.fat:
(1046527 - 978846) * 4096 / 512 = 541448 sectors
Repeating this test while also using 'blktrace /dev/sdb2' and Ctrl-C
around the test in a separate terminal, reports these numbers of I/Os
being performed:
Read requests Read bytes
15,563 165 MiB
Prior to this commit [1] from 0.0.9, GParted used libparted's
ped_file_system_get_resize_constraint() to report the minimum size to
which a FAT* file system can be resized. Use this test program [2] to
performance test this method:
# time ./fscons /dev/sdb2
dev=/dev/sdb2
sector_size=512
min_size=7909522
max_size=8388608
real 0m2.673s
user 0m0.070s
sys 0m1.834s
Free sectors in the file system according to libparted
ped_file_system_get_resize_constraint():
8388608 - 7909522 = 479086 sectors
blktrace reports these numbers of I/Os being performed:
Read requests Read bytes
7,821 71 MiB
So using libparted resize constraint is a bit faster but is still
reading too much data and is really too slow. Also when testing GParted
using this libparted method against a corrupted FAT32 file system, on
every refresh, one popup dialog is displayed for each error libparted
detects with the file system, each of which needs acknowledgement.
Example popup:
Libparted Error
\DIRNAME\FILENAME.EXT is 107724k, but is has 1920
clusters (122880k).
[ Cancel ][ Ignore ]
There could be a huge number of such errors in a corrupted file system.
Not really suitable for use by GParted.
Test the performance of mtools' minfo command to report the file system
figures:
# time minfo -i /dev/sdb2 :: | \
> egrep 'sector size:|cluster size:|small size:|big size:|free clusters='
sector size: 512 bytes
cluster size: 8 sectors
small size: 0 sectors
big size: 8388608 sectors
free clusters=67681
real 0m0.013s
user 0m0.004s
sys 0m0.019s
Free sectors in the file system according to minfo:
67681 * 8 = 541448 sectors
blktrace reports these numbers of I/Os being performed by minfo:
Read requests Read bytes
1 16 KiB
This matches with minfo just reading information from the BPB (BIOS
Parameter Block) [3] from sector 0 and the FS Information Sector [4]
usually in sector 1. Note that the free cluster figure reported by
minfo comes from the FS Information Sector because it only reports it
for FAT32 file systems, not for FAT16 file systems. Scanning the File
Allocation Table (FAT) [5] to count free clusters is exactly what mdir,
without the '-f' (fast) flag, does. Test the performance of mdir:
# export MTOOLS_SKIP_CHECK=1
# time mdir -i /dev/sdb2 ::/ | fgrep 'bytes free'
277 221 376 bytes free
real 0m0.023s
user 0m0.011s
sys 0m0.023s
Free sectors in the file system according to mdir:
277221376 / 512 = 541448 sectors
blktrace reports these number of I/Os being performed by mdir:
Read requests Read bytes
5 448 KiB
So minfo and mdir together provide the needed information and are 2 to 3
orders of magnitude faster because they only read the needed BPB and FAT
data from the drive. Use these together to read the file system usage.
[1] 61cd0ce778
lots of stuff and cleanups, including fixing getting used/unused
space of hfs/hfs+/fat16/fat32
[2] fscons.c
/* FILE: fscons.c
* SYNOPSIS: Report libparted's FS resize limits.
* BUILD: gcc -o fscons fscons.c -lparted -lparted-fs-resize
*/
int main(int argc, const char *argv[])
{
PedDevice* dev = NULL;
PedDisk* tab = NULL;
PedPartition* ptn = NULL;
PedFileSystem* fs = NULL;
PedConstraint* cons = NULL;
if (argc != 2)
{
fprintf(stderr, "Usage: fscons BLOCKDEV\n");
exit(1);
}
dev = ped_device_get(argv[1]);
if (dev == NULL)
{
fprintf(stderr, "ped_device_get(\"%s\") failed\n", argv[1]);
exit(1);
}
printf("dev=%s\n", dev->path);
printf("sector_size=%ld\n", dev->sector_size);
tab = ped_disk_new(dev);
if (tab == NULL)
{
fprintf(stderr, "ped_disk_new(dev) failed\n");
exit(1);
}
ptn = ped_disk_get_partition_by_sector(tab, 0);
if (ptn == NULL)
{
fprintf(stderr, "ped_disk_get_partition(tab, 0) failed\n");
exit(1);
}
fs = ped_file_system_open(&ptn->geom);
if (fs == NULL)
{
fprintf(stderr, "ped_file_system_open(&ptn->geom) failed\n");
exit(1);
}
cons = ped_file_system_get_resize_constraint(fs);
if (cons == NULL)
{
fprintf(stderr, "ped_file_system_get_resize_constraint(fs) failed\n");
exit(1);
}
printf("min_size=%ld\n", cons->min_size);
printf("max_size=%ld\n", cons->max_size);
ped_constraint_destroy(cons);
ped_file_system_close(fs);
ped_disk_destroy(tab);
ped_device_destroy(dev);
return 0;
}
[3] Design of the FAT file system, BIOS Parameter Block
https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#BIOS_Parameter_Block
[4] Design of the FAT file system, FS Information Sector
https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#FS_Information_Sector
[5] Design of the FAT file system, File Allocation Table
https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#File_Allocation_Table
Bug 569921 - dosfsck -n delays device scan
The Change_UUID_Warning vectors were fat16 and ntfs class member
variables, but are only ever accessed in the get_custom_text() method.
Make them local variables in get_custom_text() instead. Static so that
references to them can be returned.
Replace return by value of const strings from
FileSystem::get_custom_text() and get_generic_text() because that
implies duplication of those strings. Return a reference to constant
strings instead.
There are too many different types of things named "filesystem" in the
GParted code with the potential to cause confusion. Namely:
std::vector<FS> FILESYSTEMS
Vector of file system capabilities.
class FileSystem Base class interfacing to file system
specific executables for querying and
modification.
enum FILESYSTEM Symbolic constants representing each file
system type.
Many recent written or re-written functions already used a variable
named fstype. Rename enum FILESYSTEM to enum FSType to clearly
distinguish it from the other things with very similar names. Only
changing the name of the enumeration, not the name of variables of that
type too because that is a lot more lines of code and those can be
changed when the relevant code is re-written.
It made the code look a little messy, is easily resolved in the build
system and made the dependencies more complicated than needed. Each
GParted header was tracked via multiple different names (different
numbers of "../include/" prefixes). For example just looking at how
DialogFeatures.o depends on Utils.h:
$ cd src
$ make DialogFeatures.o
$ egrep ' [^ ]*Utils.h' .deps/DialogFeatures.Po
../include/DialogFeatures.h ../include/../include/Utils.h \
../include/../include/../include/../include/../include/../include/Utils.h \
../include/../include/../include/Utils.h \
After removing "../include/" from the GParted header #includes, just
need to add "-I../include" to the compile command via the AM_CPPFLAGS in
src/Makefile.am. Now the dependencies on GParted header files are
tracked under a single name (with a single "../include/" prefix). Now
DialogFeatures.o only depends on a single name to Utils.h:
$ make DialogFeatures.o
$ egrep ' [^ ]*Utils.h' .deps/DialogFeatures.Po
../include/DialogFeatures.h ../include/Utils.h ../include/i18n.h \
Lots of files which use the Partition class relied on the declaration
being included via other header files. This is bad practice.
Add #include "Partition.h" into every file which uses the Partition
class which doesn't already include it. Header file #include guards are
specifically to allow this.
GParted waits forever when attempting to set a FAT16/32 file system
label which contains prohibited characters [1][2]. This is because
mlabel asks a question and is waiting for input. Force cancelling the
operation doesn't work either as GParted sends signal 2 (interrupt i.e.
[Ctrl-C]) but mtools commands specifically ignores this and a number of
other signals. Have to kill mlabel with signal 9 (kill) to regain
control of GParted.
Mlabel command with prohibited characters in the label:
# export MTOOLS_SKIP_CHECK=1
# mlabel ::"MYLABEL/ " -i /dev/sdb10
Long file name "MYLABEL/ " contains illegal character(s).
a)utorename A)utorename-all r)ename R)ename-all
s)kip S)kip-all q)uit (aArRsSq):
Remove prohibited characters from FAT16/32 file systems labels when
creating and labelling them. Also upper case the label to meet label
requirements [1][2]. This silently corrects the label and the actual
label applied will be displayed when GParted refreshes after applying
the operation.
[1] Microsoft TechNet: Label
https://technet.microsoft.com/en-us/library/bb490925.aspx
[2] Replicated in Wikikedia: label (command)
https://en.wikipedia.org/wiki/Label_%28command%29
Bug 755608 - Labeling fat16/fat32 partitions hangs if certain characters
included in label
The function never modifies any member variables so make it a const
member function.
(FileSystem::get_custom_text() is a virtual function so can't be made
static).
This is part of parent bug:
Bug #721455 - Obsolete info in license text on multiple modules
and GNOME Goal:
https://wiki.gnome.org/Initiatives/GnomeGoals/Proposals
* verify all source files to make sure they have a license and a
copyright, and that both are up-to-date
Bug #721565 - License text contains obsolete FSF postal address
Dosfstools >= 3.0.18, released June 2013, renamed the programs thus:
dosfslabel becomes fatlabel,
dosfsck becomes fsck.fat,
and mkdosfs becomes mkfs.fat.
Dosfstools creates symbolic links for the old names for backward
compatibility, but unfortunately the Debian dosfstools-3.0.22-1
(experimental) package doesn't include those symbolic links. This
causes create, check and read unmounted FAT16/32 file systems to not be
supported.
Make GParted look for the new names first and the old names second.
Closes Bug #704629 - Program name changes in dosfstools 3.0.18+ break
FAT16/32 support
Include guards need to be unique within GParted code and all included
library header files.
http://en.wikipedia.org/wiki/Include_guard#Difficulties
Use this model for all include guards:
#ifndef GPARTED_FILE_NAME_H
#define GPARTED_FILE_NAME_H
...
#endif /* GPARTED_FILE_NAME_H */
Closes Bug #539297 - Make include guards unique
Mlabel sometimes writes uninitialised memory at the end of the label.
This causes mlabel, and therefore GParted, to display extra junk at the
end of the label. Depending on the bytes written GParted may also show
the following error on stdout:
(gpartedbin:18116): glibmm-CRITICAL **:
unhandled exception (type Glib::Error) in signal handler:
domain: g_convert_error
code : 1
what : Invalid byte sequence in conversion input
This is caused by a bug in mlabel, believed fixed in mtools 4.0.14.
Effects at least Fedora 14, RHEL/CentOS 6.x and Debian 6. (Use label
"1234567890" on Debian 6 to reproduce). Reproduction steps:
# mkdosfs -F16 /dev/sda7
mkdosfs 3.0.9 (31 Jan 2010)
# export MTOOLS_SKIP_CHECK=1
# mlabel ::123456 -i /dev/sda7
# mlabel -s :: -i /dev/sda7
Volume label is 123456~1t
It is not possible to detect which characters are junk so they can't be
trimmed. Instead just space pad labels so that at least newly written
labels aren't effected. (Fat labels are space padded on the disk by
definition anyway).
Bug #700228 - FAT16/32 labels are sometimes shown corrupted
There was virtually no difference between the separate modules for fat16
and fat32. Remove module fat32 and patch fat16 to serve both file
system subtypes. This is equivalent to what was previously done for
ext[234] by commit:
38dc55d49c
Combine duplicate code for ext[234]
Many filesystems do not implement some of their methods, but had to provide
dummy implementations. Remove all of the dummy implementations and instead
just provide one in the base FileSystem class.
This commit only adds a remove() method to every file system and an
optional call to it in the relevant operations. All remove() methods
are no operations and not enabled.
The remove() method provides explicit controlled removal of a file
system before the partition is deleted or overwritten by being formatted
or pasted into. When implemented, it appears as an extra step in the
relevant operation. The file system specific remove() method is
explicitly allowed to fail and stop the operations currently being
applied.
This is different to the existing erase_filesystem_signatures() which
wipes any previous file system signatures immediately before a new file
system is written to ensure there is no possibility of the partition
containing two or more different file system signatures. It never fails
or reports anything to the user.
NOTE:
Most file systems should NOT implement a remove() method as it will
prevent recovery from accidental partition deletion.
Bug #670171 - Add LVM PV read-write support
Add the ability to set a new random UUID on file systems that provide
the appropriate tools to perform this action.
Update the help manual to include this new functionality. Also add
reference links to "setting a partition label" and "changing a
partition UUID" in the "copying and pasting a partition" section.
This patch does not include setting the UUID on an NTFS file system.
Bug #667278 - Add support for setting UUID
Bug #608308 - fix documentation - Copying and Pasting a Partition
Restore copyright entries by original author to those of his last
known repository commit titled "released gparted-0.3.4 on
LarryT's request." on Feb 25, 2007.
Add my own copyright entries for files in which I changed source
code. Files in which I only made spelling changes do not have my
copyright entry added.
* added support for reading volumelabels. Atm we only read ext2/3, but
the infrastructure for adding the other filesystems is in place.
It's simply a matter of finding the right commands and parsing the
output. (see #338528 for more info)
* added detailed progressfeedback. It still needs some polishing, but
is already far better then the old situation. And what's more, it's
finally threadsafe :p
* The Filesystemclasses: Changed 'bool Create( const Glib::ustring & device_path, const Partition & new_partition )'
to 'bool Create( const Partition & new_partition )'. Since i now use external tools for all filesystems, the partitionpath will suffice.
* Again way too many chances to create a detailed entry (i'm glad i'm the only dev atm :P ).
Resizing of ext2/3 works perfect now. I've even tested it on the partition holding my SG seasons =)
Implemented checking of filesystems (only internally used atm).
Done some overall tweaking, finetuning etc.. release 0.0.7 is getting shape.
* Rewrote a large part of gparteds internal code. Filesystemssupport is now much more separated from the rest of gparted and
adding support for other filesystems should be a piece of cake now (hope that's true :P)
It still needs a lot of love, but the foundations are laid =)