summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJinWang An <jinwang.an@samsung.com>2022-12-26 13:14:07 +0900
committerJinWang An <jinwang.an@samsung.com>2022-12-26 13:14:07 +0900
commit9a7966555cb8146da9a47e2270b3e45bda06ea1c (patch)
tree4722e160acc621183e9a3ad4601a1a6d45518b36
parentf2f0e690db008447a230628762679108d1d9e72b (diff)
downloaddosfstools-9a7966555cb8146da9a47e2270b3e45bda06ea1c.tar.gz
dosfstools-9a7966555cb8146da9a47e2270b3e45bda06ea1c.tar.bz2
dosfstools-9a7966555cb8146da9a47e2270b3e45bda06ea1c.zip
Imported Upstream version 4.0upstream/4.0
-rw-r--r--.gitignore27
-rw-r--r--ChangeLog765
-rw-r--r--Makefile170
-rw-r--r--Makefile.am10
-rw-r--r--NEWS76
-rw-r--r--README39
-rw-r--r--README.md42
-rw-r--r--VERSION1
-rw-r--r--configure.ac67
-rw-r--r--manpages/Makefile50
-rw-r--r--manpages/Makefile.am38
-rwxr-xr-xmanpages/bin/update-version.sh55
-rw-r--r--manpages/fatlabel.8.in (renamed from manpages/en/fatlabel.8)2
-rw-r--r--manpages/fsck.fat.8.in (renamed from manpages/en/fsck.fat.8)5
-rw-r--r--manpages/mkfs.fat.8.in (renamed from manpages/en/mkfs.fat.8)5
-rw-r--r--src/Makefile.am63
-rw-r--r--src/blkdev/README3
-rw-r--r--src/blkdev/blkdev.c376
-rw-r--r--src/blkdev/blkdev.h149
-rw-r--r--src/blkdev/linux_version.c25
-rw-r--r--src/blkdev/linux_version.h14
-rw-r--r--src/boot.c77
-rw-r--r--src/boot.h2
-rw-r--r--src/check.c82
-rw-r--r--src/check.h2
-rw-r--r--src/device_info.c332
-rw-r--r--src/device_info.h56
-rw-r--r--src/endian_compat.h29
-rw-r--r--src/fat.c56
-rw-r--r--src/fat.h2
-rw-r--r--src/fatlabel.c5
-rw-r--r--src/fsck.fat.c3
-rw-r--r--src/fsck.fat.h24
-rw-r--r--src/io.c70
-rw-r--r--src/io.h16
-rw-r--r--src/lfn.c23
-rw-r--r--src/lfn.h6
-rw-r--r--src/mkfs.fat.c540
-rw-r--r--src/msdos_fs.h2
-rw-r--r--src/testdevinfo.c125
-rw-r--r--src/version.h.in (renamed from src/version.h)6
41 files changed, 2650 insertions, 790 deletions
diff --git a/.gitignore b/.gitignore
index 2dc4ca9..99908a7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,32 @@
*.o
-/fatlabel
-/fsck.fat
-/mkfs.fat
+src/fatlabel
+src/fsck.fat
+src/mkfs.fat
+src/testdevinfo
tags
+TAGS
*~
.*.sw[a-p]
*.orig
*.rej
*.DS_Store
+
+aclocal.m4
+autom4te.cache
+config.log
+config.status
+configure
+compile
+depcomp
+install-sh
+missing
+.deps
+.dirstamp
+
+Makefile
+Makefile.in
+src/version.h
+manpages/fatlabel.8
+manpages/mkfs.fat.8
+manpages/fsck.fat.8
diff --git a/ChangeLog b/ChangeLog
index f6a1e3d..4e9f763 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,768 @@
+commit a79ff90
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri May 6 02:34:42 2016 +0200
+
+ src/Makefile.am: Fix CPPFLAGS for VPATH builds
+
+ The -I flag to add the blkdev subdir to the include search path is now
+ relative to $(srcdir) to allow VPATH builds to work. Additionally move
+ the -I flag from the mkfs_fat and testdevinfo CFLAGS to CPPFLAGS where
+ it actually belongs.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit e8eff14
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Apr 27 21:38:37 2016 +0200
+
+ read_boot(): Handle excessive FAT size specifications
+
+ The variable used for storing the FAT size (in bytes) was an unsigned
+ int. Since the size in sectors read from the BPB was not sufficiently
+ checked, this could end up being zero after multiplying it with the
+ sector size while some offsets still stayed excessive. Ultimately it
+ would cause segfaults when accessing FAT entries for which no memory
+ was allocated.
+
+ Make it more robust by changing the types used to store FAT size to
+ off_t and abort if there is no room for data clusters. Additionally
+ check that FAT size is not specified as zero.
+
+ Fixes #25 and fixes #26.
+
+ Reported-by: Hanno Böck
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 016800e
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Apr 27 14:16:53 2016 +0200
+
+ Use variable total_fat_entries in read_boot() for readability
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit a6478d8
+Author: Álvaro Fernández Rojas <noltari@gmail.com>
+Date: Fri Apr 8 12:20:46 2016 +0200
+
+ Add missing iconv library for OS X
+
+ Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit ce67dc6
+Author: Álvaro Fernández Rojas <noltari@gmail.com>
+Date: Fri Apr 8 12:20:27 2016 +0200
+
+ Add endian support for OS X
+
+ Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 08f3869
+Author: Joel Holdsworth <joel.holdsworth@vcatechnology.com>
+Date: Thu Mar 10 00:53:07 2016 +0000
+
+ Configure option to disable building with libudev
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit ed4e47b
+Author: Andreas Bombe <aeb@debian.org>
+Date: Mon Feb 22 03:47:14 2016 +0100
+
+ Remove use of PATH_MAX in path_name()
+
+ The length of a file path on the checked filesystem has no relation to
+ the maximum path length of the system fsck is running on. So replace it
+ with a constant of our own.
+
+ As a bonus this will not fail compilation on a system without PATH_MAX.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit b1a38ab
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 17 21:04:35 2016 +0100
+
+ Add preliminary entry for release 4.0 to NEWS
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 4ad3e9e
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 17 21:02:06 2016 +0100
+
+ Adjust ridiculous source indentation in io.c
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit b96acb2
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 17 20:51:53 2016 +0100
+
+ Document ./configure --enable-compat-symlinks in README
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit de39c5c
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 17 15:16:27 2016 +0100
+
+ Add include paths.h in the HAVE_DECL_GETMNTENT case
+
+ _PATH_MOUNTED is now used for getmntent() in place of MOUNTED because
+ the latter was marked as a deprecated alias in glibc's mntent.h. The
+ mntent.h of musl libc does not include the _PATH_MOUNTED however. Fix
+ this by including paths.h alongside mntent.h
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 86c7acd
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 17 15:06:56 2016 +0100
+
+ man fsck: Document the -c option
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit ef9a73c
+Author: Andreas Bombe <aeb@debian.org>
+Date: Mon Feb 15 02:10:57 2016 +0100
+
+ Add NEWS file with changes of the last two releases
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit bda6551
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Feb 12 03:56:16 2016 +0100
+
+ Make filesystem mounted check portable
+
+ A new function is_device_mounted() in device_info.c is now used by
+ check_mount() in mkfs.fat.c. It contains the getmntent() using code
+ used before in check_mount() and now an alternative using getmntinfo()
+ as found on the BSDs.
+
+ In case neither function is available, is_device_mounted() defaults to
+ reporting that the device isn't mounted.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 4b8c9cc
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Feb 12 01:57:33 2016 +0100
+
+ Make use of endian.h portable to BSD
+
+ The endian.h found on Linux and the BSDs appear to be compatible, but
+ they are found in different locations. Add tests in configure.ac and a
+ new endian_compat.h file that has the logic to include the correct
+ files.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit d7665f2
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 10 21:30:06 2016 +0100
+
+ Fix format string in check_file() (%lu → %llu)
+
+ The cluster chain length printing needs a 64 bit calculation, so we can
+ just use unsigned long long instead of uint64_t and use the format
+ string %llu.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 6225e59
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Feb 5 14:39:00 2016 +0100
+
+ blkdev.c: Prevent unused parameter warnings in fallback code
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 34cdded
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Feb 5 14:36:14 2016 +0100
+
+ blkdev_get_size(): Remove unused variable ch
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 5571d29
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 10 03:22:19 2016 +0100
+
+ Reinstate alignment of FAT32 structures to cluster size
+
+ This reverts commits 17c956cb9 and d63e0d627 where the alignment was
+ removed because it created problems with a device that refused to read
+ the aligned filesystem. The option -a is already provided to disable
+ alignment in order to handle such cases.
+
+ This change brings it back in line with FAT12/16 where alignment wasn't
+ disabled and brings consistency with the current command line options,
+ where only the option to disable alignment exists but no opposite option
+ to enable it.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 2c71ace
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 3 03:38:33 2016 +0100
+
+ Makefile.am: Add historic documentation to distribution
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit bcbae63
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 3 02:38:24 2016 +0100
+
+ src/Makefile.am: Add forgotten msdos_fs.h to mkfs_fat_SOURCES
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 19d1a13
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 3 02:34:51 2016 +0100
+
+ Remove sys/ioctl.h and linux/fd.h include from io.c
+
+ These weren't used anymore and the linux/fd.h include would
+ gratuitously cause compilation to fail on non-Linux environments.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit f691660
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Feb 3 02:31:00 2016 +0100
+
+ Reinstate some #include <sys/types.h>
+
+ These shouldn't have been removed in commit 245d0cce5. Put them back for
+ correctness even though the definitions were pulled in implicitly.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 51afd41
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Jan 27 21:38:29 2016 +0100
+
+ src/Makefile.am: Put all header files in appropriate _SOURCES variables
+
+ With the headers missing the dist targets of the automake generated
+ Makefiles would not include them and make the resulting dist
+ unbuildable.
+
+ Also combine sources collections into common variables for
+ deduplication.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit bf6f142
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Jan 27 15:28:42 2016 +0100
+
+ mkfs man: Note that sector sizes > 4096 are non-standard
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit ea96c32
+Author: Andreas Bombe <aeb@debian.org>
+Date: Mon Jan 25 21:30:23 2016 +0100
+
+ mkfs: Improve parsing of bad blocks file
+
+ The bad blocks file that can be given to mkfs via the -l option had a
+ very simplistic design. It failed to notice it was parsing an empty
+ line and would report errors for that.
+
+ Replace it with a more robust version that ignores empty lines as well
+ as leading and trailing white space. Additionally it produces meaningful
+ error messages.
+
+ GitHub: Fixes #17
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit dfb5bea
+Author: Andreas Bombe <aeb@debian.org>
+Date: Mon Jan 25 02:47:12 2016 +0100
+
+ mkfs: Limit filesystem size on targets that are too large
+
+ For FAT filesystems, the number of sectors has to fit into a 32 bit
+ variable. Previously this was not checked possibly causing invalid
+ filesystems to be generated.
+
+ Now there is a check for that case which will limit the number of
+ sectors if needed and print a warning that disk space will be left
+ unused in that case.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit fc0343f
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Jan 22 21:29:20 2016 +0100
+
+ mkfs: Improved bounds checking in mark_FAT_sector()/mark_FAT_cluster()
+
+ In mark_FAT_sector() the sector number itself is now checked against
+ limits instead of the computed cluster number. Even with sector number
+ before the start of the data area, the cluster number may be valid for
+ the first cluster due to dividing by the cluster size.
+
+ Both functions now check for upper limits and should prevent writing
+ past the valid end of the FAT.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 9211c8a
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Jan 15 02:17:16 2016 +0100
+
+ mkfs: Fix offset error in FAT12/16 bad cluster marking
+
+ The root directory wasn't factored in to the calculation of the data
+ area start sector. On FAT32 the root directory is in the data area, but
+ for FAT12 and FAT16 it is a reserved space before the start of the data
+ area.
+
+ On FAT12 and FAT16, this resulted in the wrong clusters being marked
+ during bad blocks mapping, whether from check_blocks() or from reading
+ the user supplied bad blocks file.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 0627a62
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Jan 15 01:59:59 2016 +0100
+
+ mkfs: Fix off-by-2 error in bad cluster marking
+
+ mark_FAT_sector(), which has the mark_sector_bad() macro as its sole
+ user, computed the cluster number corresponding to the sector by taking
+ its offset from the first data sector and dividing by sectors per
+ cluster.
+
+ What it missed was that the first data cluster is number 2 and not 0.
+ This meant all marks were off by 2 and when the first two clusters are
+ supposed to be marked, it would overwrite the reserved cluster values
+ and create an invalid filesystem.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 2dca9aa
+Author: Andreas Bombe <aeb@debian.org>
+Date: Thu Jan 14 14:43:00 2016 +0100
+
+ .gitignore: Add .dirstamp
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 6a966fb
+Author: Andreas Bombe <aeb@debian.org>
+Date: Thu Jan 14 14:38:53 2016 +0100
+
+ mkfs: Reword non-standard sector size warning
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit bebc9ac
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Dec 30 15:10:35 2015 +0100
+
+ Clean up includes in mkfs.fat.c
+
+ Moving the device probing out into device_info.c removed the need for a
+ number of includes in mkfs.fat.c. Remove them and add a define for
+ BLOCK_SIZE, which was the only thing used from linux/fs.h.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 12a1d46
+Author: Andreas Bombe <aeb@debian.org>
+Date: Sun Nov 29 01:59:10 2015 +0100
+
+ Don't use pointer to first member when more of the struct gets copied
+
+ Where a fs_write() of "first 13 bytes of directory entry" is intended,
+ actually use pointer to directory entry structure instead of the 11
+ byte name field at the beginning.
+
+ This does not change how the code works, it is just a clean up.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit d38bd2d
+Author: Andreas Bombe <aeb@debian.org>
+Date: Sun Nov 29 00:44:48 2015 +0100
+
+ Remove name/extension split in directory entry structures
+
+ Both the DIR_ENT structure in fsck.fat.h and the msdos_dir_entry in
+ msdos_fs.h - these represent the on disk format of directory entries -
+ had the name field split into name[8] followed by ext[3].
+
+ By far the most operations on name are on the full name including
+ extension and they treated the name field as an 11 byte array. This is
+ an array overflow that worked because the structs have the attribute
+ packed and the extension field is following right after.
+
+ Nevertheless, this is not clean C and the merging of both fields
+ actually simplified the code in a few places.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 0847e4c
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Nov 27 21:29:49 2015 +0100
+
+ Free allocated strings after use
+
+ There are multiple calls to cnv_unicode() in lfn.c which returns an
+ allocated string. Most had the appropriate free() calls after printing
+ the strings. Add the missing two calls where memory was leaked.
+
+ Found by Coverity.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 1b7d91e
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Nov 27 03:34:51 2015 +0100
+
+ Add test for and include linux/hdreg.h in blkdev.c
+
+ Before, blkdev did not include it and depended on its own fallback
+ definition of the ioctl and struct hd_geometry.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 5024372
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Nov 27 03:28:14 2015 +0100
+
+ Add FDGETPRM attempt to blkdev_get_geometry()
+
+ If HDIO_GETGEO isn't available or has failed, try FDGETPRM. This should
+ get the geometry from floppy drivers where HDIO_GETGEO isn't supported.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 4a146d7
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Nov 27 03:25:55 2015 +0100
+
+ Add blkdev_get_start() for getting partition start offset
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 254f8ab
+Author: Andreas Bombe <aeb@debian.org>
+Date: Thu Nov 26 23:33:02 2015 +0100
+
+ Remove use of libblkid again
+
+ It appears libblkid is not as widely available as presumed, since some
+ platforms only have the original libblkid included in e2fsprogs which
+ lacks the needed functionality. This commit removes the requirement and
+ use of libblkid.
+
+ As a replacement, blkdev.c from util-linux is included, which offers the
+ required basic functionality in a portable way.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit c9fb33c
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Oct 21 21:32:30 2015 +0200
+
+ Use just device size not major number in Atari mode
+
+ In Atari mode, read_boot() in boot.c used the device major number to
+ determine whether to use FAT12. It would always use FAT12 for a floppy,
+ otherwise only if it is a RAM disk or loopback device and has a size
+ corresponding to standard floppy formats.
+
+ Since this check was already broken for a long time (another place that
+ assumed 8 bit major numbers) and there is no real point to make the
+ distinction based on device, this commit reduces the check to just
+ compare against standard floppy sizes.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 64486ad
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Oct 21 00:18:22 2015 +0200
+
+ Remove loff_t and llseek()
+
+ There appear to have been multiple conversions to 64 bit file offsets on
+ 32 bit architectures in dosfstools over the years, but today with the
+ proper setup off_t is 64 bits and simple lseek() can be used. The
+ AC_SYS_LARGEFILE macro in configure.ac does what is required to make
+ that happen.
+
+ Given this, convert all uses of loff_t to off_t, remove llseek()
+ definitions and change llseek() calls to plain lseek().
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit e03a5f4
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Oct 16 21:47:04 2015 +0200
+
+ Remove DJGPP support
+
+ These macros have been added back when dosfstools was around version 2.
+ It is difficult to say whether these are still working correctly or
+ whether they are in use at all. FreeDOS appears to still show version
+ 2.11 of dosfstools in their software directory.
+
+ Supporting actual MS-DOS or compatible may need more work in the
+ current state of things and this DJGPP support can be removed until
+ then.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 5b9a88d
+Author: Andreas Bombe <aeb@debian.org>
+Date: Thu Oct 8 16:17:22 2015 +0200
+
+ mkfs.fat: Complete overhaul of device probing
+
+ The device probing in mkfs.fat is used to get device parameters where
+ needed and also to decide whether to refuse overwriting a device due to
+ possible user error. This code has suffered severe bitrot and is highly
+ Linux specific. Highlights include using hardcoded major/minor device
+ numbers to classify a device, and using 8 bits major/minor numbers that
+ have become obsolete a long time ago and thus often misidentifying a
+ device.
+
+ The overhauled implementation is now in src/device_info.c and makes use
+ of libudev (optional, recommended) and libblkid (required) to probe the
+ device and where Linux ioctls are required it provides fallbacks and
+ does not attempt to call these on non-Linux systems. The FAT parameter
+ selection has been unified and simplified in the process.
+
+ A new executable testdevinfo has been added that gets built but not
+ automatically installed. It takes one file name, uses the same probing
+ as mkfs.fat would with verbose messages enabled and displays the
+ results.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 53eddfc
+Author: Andreas Bombe <aeb@debian.org>
+Date: Sat Sep 12 02:54:33 2015 +0200
+
+ Die on out of range cluster values in set_fat()/get_fat()
+
+ To prevent bugs caused by FAT corruption inside fsck to go unnoticed,
+ add a check against out of range requested cluster values in get_fat()
+ and against out of range cluster to change and new cluster value in
+ set_fat().
+
+ When an invalid cluster value is detected, these functions now die()
+ with an "internal error" message.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 456767b
+Author: Andreas Bombe <aeb@debian.org>
+Date: Mon Sep 14 00:33:49 2015 +0200
+
+ configure.ac: Use AS_HELP_STRING to format option help
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 3cfb479
+Author: Andreas Bombe <aeb@debian.org>
+Date: Mon Sep 14 00:30:40 2015 +0200
+
+ version.h: Use @configure_input@ autoconf variable in boilerplate
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 41ef834
+Author: Andreas Bombe <aeb@debian.org>
+Date: Mon Sep 14 00:29:27 2015 +0200
+
+ .gitignore: Add TAGS in addition to tags
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit bdc3d2a
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Sep 11 20:28:12 2015 +0200
+
+ Rename clusters field in DOS_FS struct
+
+ Rename it to data_clusters to prevent mistaking the clusters field of
+ the DOS_FS struct as the total number of FAT entries instead of the
+ number of data clusters (two less than the number of entries).
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 0790812
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Sep 11 19:47:29 2015 +0200
+
+ set_fat(): Fix off-by-2 error leading to corruption in FAT12
+
+ In FAT12 two 12 bit entries are combined to a 24 bit value (three
+ bytes). Therefore, when an even numbered FAT entry is set in FAT12, it
+ must be be combined with the following entry. To prevent accessing
+ beyond the end of the FAT array, it must be checked that the cluster is
+ not the last one.
+
+ Previously, the check tested that the requested cluster was equal to
+ fs->clusters - 1. However, fs->clusters is the number of data clusters
+ not including the two reserved FAT entries at the start so the test
+ triggered two clusters early.
+
+ If the third to last entry was written on a FAT12 filesystem with an
+ odd number of clusters, the second to last entry would be corrupted.
+ This corruption may also lead to invalid memory accesses when the
+ corrupted entry becomes out of bounds and is used later.
+
+ Change the test to fs->clusters + 1 to fix.
+
+ Reported-by: Hanno Böck
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 39ce90f
+Author: Andreas Bombe <aeb@debian.org>
+Date: Fri Sep 11 19:34:10 2015 +0200
+
+ set_fat(): Move FAT12 next cluster check up
+
+ In FAT12 two 12 bit entries are combined to a 24 bit value (three
+ bytes). Therefore, when an even numbered FAT entry is set in FAT12, it
+ must be be combined with the following entry. To prevent accessing
+ beyond the end of the FAT array, it must be checked that the cluster is
+ not the last one.
+
+ This check was broken in ff1b24e9 (first included in 3.0.3) as the
+ lookup was done unconditionally and the check influenced only using the
+ looked up value.
+
+ Move the check up to fix.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 2aad1c8
+Author: Andreas Bombe <aeb@debian.org>
+Date: Tue Sep 8 03:58:29 2015 +0200
+
+ Prevent out of bound array read in date_dos2unix()
+
+ The function date_dos2unix() is called during fsck while showing
+ information about duplicate file names. In case the date field of a
+ directory entry contains the invalid value 0 for the month,
+ date_dos2unix would read index -1 of the day_n array.
+
+ Add a check to prevent that and also make the day_n array const on this
+ occasion.
+
+ Reported-by: Hanno Böck
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 3b95786
+Author: Yann E. MORIN <yann.morin.1998@free.fr>
+Date: Sun Aug 16 15:55:43 2015 +0200
+
+ mkfs.fat: fix incorrect int type
+
+ u_int32_t is not a stanard type, while uint32_t is. This fixes builds
+ with the musl C library, which only defines so-called "clean" headers;
+ build failures are like (back-quotes and elision manually added for
+ readability):
+
+ http://autobuild.buildroot.org/results/a09/a0923d7f6d4dbae02eba4c5024bbdae3a52aa85a/build-end.log
+
+ /home/peko/autobuild/instance-1/output/host/usr/bin/x86_64-linux-gcc -D_LARGEFILE_SOURCE \
+ -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -D_GNU_SOURCE -D_LARGEFILE_SOURCE \
+ -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -c -o mkfs.fat.o src/mkfs.fat.c
+ src/mkfs.fat.c: In function 'main':
+ src/mkfs.fat.c:1415:18: error: 'u_int32_t' undeclared (first use in this function)
+ volume_id = (u_int32_t) ((create_timeval.tv_sec << 20) | create_timeval.tv_usec); [...]
+ ^
+ src/mkfs.fat.c:1415:18: note: each undeclared identifier is reported only once for each
+ function it appears in
+
+ Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 2b1c4d1
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Jun 3 03:33:10 2015 +0200
+
+ Add README.md, remove Markdown formatting from README
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit b720acc
+Author: Andreas Bombe <aeb@debian.org>
+Date: Wed Jun 3 03:27:24 2015 +0200
+
+ Add simple README in Markdown format
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 2b255e6
+Author: Andreas Bombe <aeb@debian.org>
+Date: Tue Jun 2 18:25:06 2015 +0200
+
+ Configure option for legacy names symlinks
+
+ The symlinks from the old names (mkdosfs, dosfsck, etc.) are now only
+ created on "make install" when the --enable-compat-symlinks option was
+ given to configure.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 0643db7
+Author: Andreas Bombe <aeb@debian.org>
+Date: Sun May 31 02:40:19 2015 +0200
+
+ Convert build system to autoconf/automake
+
+ In preparation for fixing the horribly outdated and broken device
+ checking - which will likely involve using additional libraries like
+ libblkid - as well as making this package portable to other operating
+ systems, the build system is now the tried and true autoconf/automake
+ combination which should make both goals a little more straightforward.
+
+ The release version number and date are now in configure.ac and
+ substituted by configure where they are needed. Now it is no longer
+ necessary to change the number in multiple places for a release and the
+ man pages get the number substituted directly into them, making the
+ update-version.sh script and the VERSION file obsolete.
+
+ The English man pages are moved back up one directory to mark their
+ status as the master copy for all translations. At the moment the po4a
+ translation infrastructure is defunct since it isn't integrated into
+ the automake environment yet. So far it hasn't been used, so that is
+ not an actual regression.
+
+ The date in the man pages is not automatically updated anymore. This is
+ as it should be, since the date is supposed to signify the time of the
+ last nontrivial change and not the release date of the software.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
+commit 85022fe (tag: v3.0.28)
+Author: Andreas Bombe <aeb@debian.org>
+Date: Sat May 16 02:56:17 2015 +0200
+
+ Releasing version 3.0.28.
+
+ Signed-off-by: Andreas Bombe <aeb@debian.org>
+
commit ad1342e
Author: Andreas Bombe <aeb@debian.org>
Date: Sat May 16 02:10:18 2015 +0200
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 1593f3d..0000000
--- a/Makefile
+++ /dev/null
@@ -1,170 +0,0 @@
-# Makefile
-#
-# Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
-#
-# 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 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/>.
-#
-# The complete text of the GNU General Public License
-# can be found in /usr/share/common-licenses/GPL-3 file.
-
-SHELL := sh -e
-LANGUAGES = $(shell cd manpages/po && ls)
-
-DESTDIR =
-PREFIX = /usr/local
-SBINDIR = $(PREFIX)/sbin
-DOCDIR = $(PREFIX)/share/doc
-MANDIR = $(PREFIX)/share/man
-
-#OPTFLAGS = -O2 -fomit-frame-pointer -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
-OPTFLAGS = -O2 -fomit-frame-pointer -D_GNU_SOURCE $(shell getconf LFS_CFLAGS)
-#WARNFLAGS = -Wall -pedantic -std=c99
-WARNFLAGS = -Wall -Wextra -Wno-sign-compare -Wno-missing-field-initializers -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings
-DEBUGFLAGS = -g
-CFLAGS += $(OPTFLAGS) $(WARNFLAGS) $(DEBUGFLAGS)
-
-VPATH = src
-
-all: build
-
-build: fatlabel fsck.fat mkfs.fat
-
-fatlabel: boot.o check.o common.o fat.o file.o io.o lfn.o charconv.o fatlabel.o
-
-fsck.fat: boot.o check.o common.o fat.o file.o io.o lfn.o charconv.o fsck.fat.o
-
-mkfs.fat: mkfs.fat.o
-
-rebuild: distclean build
-
-install: install-bin install-doc install-man install-symlinks
-
-install-bin: build
- install -d -m 0755 $(DESTDIR)/$(SBINDIR)
- install -m 0755 fatlabel fsck.fat mkfs.fat $(DESTDIR)/$(SBINDIR)
-
-install-doc:
- install -d -m 0755 $(DESTDIR)/$(DOCDIR)/dosfstools
- install -p -m 0644 ChangeLog doc/* $(DESTDIR)/$(DOCDIR)/dosfstools
-
-install-man:
- for MANPAGE in manpages/en/*; \
- do \
- SECTION="8"; \
- mkdir -p $(DESTDIR)/$(MANDIR)/man$${SECTION}/; \
- install -m 0644 $${MANPAGE} $(DESTDIR)/$(MANDIR)/man$${SECTION}/$$(basename $${MANPAGE}); \
- done
-
- for LANGUAGE in $(LANGUAGES); \
- do \
- for MANPAGE in manpages/$${LANGUAGE}/*; \
- do \
- SECTION="8"; \
- mkdir -p $(DESTDIR)/$(MANDIR)/$${LANGUAGE}/man$${SECTION}/; \
- install -m 0644 $${MANPAGE} $(DESTDIR)/$(MANDIR)/$${LANGUAGE}/man$${SECTION}/$$(basename $${MANPAGE} .$${LANGUAGE}.$${SECTION}).$${SECTION}; \
- done; \
- done
-install-symlinks: install-bin install-man
- if [ -e $(DESTDIR)/$(SBINDIR)/fatlabel ]; \
- then \
- ln -sf fatlabel $(DESTDIR)/$(SBINDIR)/dosfslabel; \
- if [ -e $(DESTDIR)/$(MANDIR)/man8/fatlabel.8 ]; \
- then \
- ln -sf fatlabel.8 $(DESTDIR)/$(MANDIR)/man8/dosfslabel.8; \
- fi; \
- fi
-
- if [ -e $(DESTDIR)/$(SBINDIR)/fsck.fat ]; \
- then \
- ln -sf fsck.fat $(DESTDIR)/$(SBINDIR)/dosfsck; \
- ln -sf fsck.fat $(DESTDIR)/$(SBINDIR)/fsck.msdos; \
- ln -sf fsck.fat $(DESTDIR)/$(SBINDIR)/fsck.vfat; \
- if [ -e $(DESTDIR)/$(MANDIR)/man8/fsck.fat.8 ]; \
- then \
- ln -sf fsck.fat.8 $(DESTDIR)/$(MANDIR)/man8/dosfsck.8; \
- ln -sf fsck.fat.8 $(DESTDIR)/$(MANDIR)/man8/fsck.msdos.8; \
- ln -sf fsck.fat.8 $(DESTDIR)/$(MANDIR)/man8/fsck.vfat.8; \
- fi; \
- fi
-
- if [ -e $(DESTDIR)/$(SBINDIR)/mkfs.fat ]; \
- then \
- ln -sf mkfs.fat $(DESTDIR)/$(SBINDIR)/mkdosfs; \
- ln -sf mkfs.fat $(DESTDIR)/$(SBINDIR)/mkfs.msdos; \
- ln -sf mkfs.fat $(DESTDIR)/$(SBINDIR)/mkfs.vfat; \
- if [ -e $(DESTDIR)/$(MANDIR)/man8/mkfs.fat.8 ]; \
- then \
- ln -sf mkfs.fat.8 $(DESTDIR)/$(MANDIR)/man8/mkdosfs.8; \
- ln -sf mkfs.fat.8 $(DESTDIR)/$(MANDIR)/man8/mkfs.msdos.8; \
- ln -sf mkfs.fat.8 $(DESTDIR)/$(MANDIR)/man8/mkfs.vfat.8; \
- fi; \
- fi
-
-uninstall: uninstall-symlinks uninstall-man uninstall-doc uninstall-bin
-
-uninstall-bin:
- rm -f $(DESTDIR)/$(SBINDIR)/fatlabel
- rm -f $(DESTDIR)/$(SBINDIR)/fsck.fat
- rm -f $(DESTDIR)/$(SBINDIR)/mkfs.fat
-
- rmdir --ignore-fail-on-non-empty $(DESTDIR)/$(SBINDIR)
-
-uninstall-doc:
- rm -rf $(DESTDIR)/$(DOCDIR)/dosfstools
-
- rmdir --ignore-fail-on-non-empty $(DESTDIR)/$(DOCDIR)
-
-uninstall-man:
- for MANPAGE in manpages/en/*; \
- do \
- SECTION="8"; \
- rm -f $(DESTDIR)/$(MANDIR)/man$${SECTION}/$$(basename $${MANPAGE} .en.$${SECTION}).$${SECTION}; \
- done
-
- for LANGUAGE in $(LANGUAGES); \
- do \
- for MANPAGE in manpages/$${LANGUAGE}/*; \
- do \
- SECTION="8"; \
- rm -f $(DESTDIR)/$(MANDIR)/$${LANGUAGE}/man$${SECTION}/$$(basename $${MANPAGE} .$${LANGUAGE}.$${SECTION}).$${SECTION}; \
- done; \
- done
-
-uninstall-symlinks:
- rm -f $(DESTDIR)/$(SBINDIR)/dosfslabel
- rm -f $(DESTDIR)/$(MANDIR)/man8/dosfslabel.8
-
- rm -f $(DESTDIR)/$(SBINDIR)/dosfsck
- rm -f $(DESTDIR)/$(MANDIR)/man8/dosfsck.8
- rm -f $(DESTDIR)/$(SBINDIR)/fsck.msdos
- rm -f $(DESTDIR)/$(MANDIR)/man8/fsck.msdos.8
- rm -f $(DESTDIR)/$(SBINDIR)/fsck.vfat
- rm -f $(DESTDIR)/$(MANDIR)/man8/fsck.vfat.8
-
- rm -f $(DESTDIR)/$(SBINDIR)/mkdosfs
- rm -f $(DESTDIR)/$(MANDIR)/man8/mkdosfs.8
- rm -f $(DESTDIR)/$(SBINDIR)/mkfs.msdos
- rm -f $(DESTDIR)/$(MANDIR)/man8/mkfs.msdos.8
- rm -f $(DESTDIR)/$(SBINDIR)/mkfs.vfat
- rm -f $(DESTDIR)/$(MANDIR)/man8/mkfs.vfat.8
-
-reinstall: distclean install
-
-clean:
- rm -f *.o
-
-distclean: clean
- rm -f fatlabel fsck.fat mkfs.fat
-
-.PHONY: build rebuild install install-bin install-doc install-man install-symlinks uninstall uninstall-bin uninstall-doc uninstall-man uninstall-symlinks reinstall clean distclean
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..e2ec024
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,10 @@
+SUBDIRS = src manpages
+
+dist_doc_DATA = doc/ANNOUNCE.mkdosfs \
+ doc/ChangeLog.dosfsck \
+ doc/ChangeLog.dosfstools-2.x \
+ doc/ChangeLog.mkdosfs \
+ doc/README.dosfsck \
+ doc/README.dosfstools-2.x \
+ doc/README.mkdosfs \
+ doc/TODO.dosfstools-2.x
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..cdf231c
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,76 @@
+dosfstools 4.0 - released 2016-05-06
+====================================
+
+The programs are now portable to non-Linux operating systems. To that end, the
+build system has been converted to use autotools. There have been Linux
+specifics in a lot of places which have been either eliminated or should have
+equivalents so that it should now work in other Unix-like environments. It has
+been tested on FreeBSD and OS X.
+
+As part of making it portable all the code that assumed 8 bit major/minor
+numbers - and in fact masked out all other bits - has been cleaned up. Now
+mkfs.vfat should not misidentify devices anymore and require the -I option to
+override. The new device probing uses libudev (if available) to collect more
+information.
+
+Fixed data corruption errors in fsck.fat: Writing to the third to last cluster
+on FAT12 with an odd number of clusters would corrupt the following cluster. In
+mkfs.fat, long existing bugs in bad cluster marking (from scanning or user
+supplied bad blocks list) were fixed so that it actually marks the correct
+clusters.
+
+The automatic alignment of data clusters that was added in 3.0.8 and broken for
+FAT32 starting with 3.0.20 has been reinstated. If you need to create file
+systems for finicky devices that have broken FAT implementations use the option
+-a to disable alignment.
+
+
+dosfstools 3.0.28 - released 2015-05-16
+=======================================
+
+The major user visible change in this release is that fsck.fat now defaults to
+interactive repair mode which previously had to be selected with -r. The
+previous default of a read only check mode was confusing to users who had to
+repeat a potentially lengthy fsck.fat run with the right option in order to
+actually fix their file system. It was also pointless – the interactive repair
+mode already won't write anything without asking for confirmation.
+
+mkfs.fat now allows choosing 0xF0 as the media byte which was previously
+rejected.
+
+mkfs.fat now supports the --invariant option to facilitate testing mkfs.fat
+itself. It will reproducibly generate filesystems without random or time based
+differences between them when all else is identical.
+
+Bugs fixed in fsck.fat are a read one byte beyond the end of an allocated array
+when checking some FAT12 filesystems, and checking that the first cluster of a
+file as specified in the directory entry is not 1. Previously it could attempt
+to follow a block chain starting on cluster 1 and segfault when the conditions
+are right.
+
+
+dosfstools 3.0.27 - released 2014-11-12
+=======================================
+
+This is a pure bug fix release. The major bugs fixed:
+
+* fatlabel did not recognize long file names and mistook long file name
+ segments in the root directory for labels. This caused output of garbage when
+ asked to print the label and damage to the root directory (loss of long file
+ name after fsck) when used to set the label.
+
+* A fsck.fat check introduced in 3.0.26 triggered use of uninitialized fields
+ in the constructed root directory entry, which randomly caused the code
+ checking file names to consider the empty "file name" of the root directory
+ to be bad:
+
+ $ /sbin/fsck.fat -y bad.img
+ fsck.fat 3.0.26 (2014-03-07)
+ /
+ Bad short file name ().
+ Auto-renaming it.
+ Renamed to
+ bad.img: 14 files, 19388/403266 clusters
+
+* And finally fsck.fat will not print the version string anymore every time the
+ -v option is encountered.
diff --git a/README b/README
new file mode 100644
index 0000000..8fe8249
--- /dev/null
+++ b/README
@@ -0,0 +1,39 @@
+dosfstools consists of the programs mkfs.fat, fsck.fat and fatlabel to create,
+check and label file systems of the FAT family. The dosfstools are licensed
+under the GNU GPL version 3 or later. See the file COPYING for details.
+
+
+### Build Requirements
+
+dosfstools recommends libudev. It is used in mkfs.fat to collect additional
+information about the device to format in order to refuse potentially unsafe
+operations without additional confirmation.
+
+
+### Installing
+
+dosfstools are built using an autoconf/automake system, so the standard method
+applies:
+
+ ./configure
+ make
+ make install
+
+You need to have superuser privileges in order to install into the standard
+system wide locations.
+
+The ./configure script has an option --enable-compat-symlinks that will
+configure the build to symlink older names of the tools to the current ones on
+installation. These are dosfsck, fsck.msdos and fsck.vfat for fsck.fat, mkdosfs,
+mkfs.msdos and mkfs.vfat for mkfs.fat and dosfslabel for fatlabel.
+
+
+### Building from the VCS repository
+
+If you are working directly from a git clone of the official dosfstools
+repository, you will find that you can not run "./configure" straight away
+because it, like other autogenerated files for the build system, is not included
+in the repository.
+
+First, autoconf and automake have to be installed. Then you can run
+"autoreconf -i" to generate all the required files.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f397895
--- /dev/null
+++ b/README.md
@@ -0,0 +1,42 @@
+dosfstools consists of the programs mkfs.fat, fsck.fat and fatlabel to create,
+check and label file systems of the FAT family. The dosfstools are licensed
+under the GNU GPL version 3 or later. See the file `COPYING` for details.
+
+
+### Build Requirements
+
+dosfstools recommends libudev. It is used in mkfs.fat to collect additional
+information about the device to format in order to refuse potentially unsafe
+operations without additional confirmation.
+
+
+### Installing
+
+dosfstools are built using an autoconf/automake system, so the standard method
+applies:
+
+```
+./configure
+make
+make install
+```
+
+You need to have superuser privileges in order to install into the standard
+system wide locations.
+
+The `./configure` script has an option `--enable-compat-symlinks` that will
+configure the build to symlink older names of the tools to the current ones on
+installation. These are `dosfsck`, `fsck.msdos` and `fsck.vfat` for `fsck.fat`,
+`mkdosfs`, `mkfs.msdos` and `mkfs.vfat` for `mkfs.fat` and `dosfslabel` for
+`fatlabel`.
+
+
+### Building from the VCS repository
+
+If you are working directly from a git clone of the official dosfstools
+repository, you will find that you can not run `./configure` straight away
+because it, like other autogenerated files for the build system, is not included
+in the repository.
+
+First, autoconf and automake have to be installed. Then you can run `autoreconf
+-i` to generate all the required files.
diff --git a/VERSION b/VERSION
deleted file mode 100644
index 0baec4d..0000000
--- a/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-3.0.28
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..4d4e522
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,67 @@
+# configure.ac for dosfstools
+# Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
+#
+# 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 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/>.
+
+AC_INIT([dosfstools], [4.0])
+AC_SUBST([RELEASE_DATE], [2016-05-06])
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+
+AC_ARG_ENABLE([compat-symlinks],
+ [AS_HELP_STRING([--enable-compat-symlinks],
+ [install symlinks for legacy names of the tools])],
+ [case "${enableval}" in
+ yes) symlinks=true ;;
+ no) symlinks=false ;;
+ *) AC_MSG_ERROR([bad value ${enableval} for --enable-compat-symlinks]) ;;
+ esac],
+ [symlinks=false])
+AM_CONDITIONAL([COMPAT_SYMLINKS], [test x$symlinks = xtrue])
+
+
+AC_PROG_CC
+AC_PROG_LN_S
+
+AC_SYS_LARGEFILE
+
+AC_CHECK_HEADERS([\
+ err.h \
+ linux/fd.h \
+ linux/hdreg.h \
+ linux/version.h \
+ sys/disk.h \
+ sys/disklabel.h \
+ sys/ioccom.h \
+ sys/mkdev.h \
+ sys/queue.h \
+ ])
+
+AC_CHECK_HEADERS([endian.h sys/endian.h])
+
+AC_CHECK_DECLS([getmntent], [], [], [[#include <mntent.h>]])
+AC_CHECK_DECLS([getmntinfo], [], [], [[#include <sys/mount.h>]])
+
+AC_ARG_WITH([udev], AS_HELP_STRING([--without-udev], [build without libudev support]))
+if test "x$with_udev" != "xno"; then
+ PKG_CHECK_MODULES([UDEV], [libudev],
+ [AC_DEFINE([HAVE_UDEV], [1])],
+ [true])
+fi
+
+AC_SEARCH_LIBS(iconv_open, iconv)
+
+AC_CONFIG_FILES([Makefile src/Makefile src/version.h
+ manpages/Makefile manpages/mkfs.fat.8
+ manpages/fsck.fat.8 manpages/fatlabel.8])
+AC_OUTPUT
diff --git a/manpages/Makefile b/manpages/Makefile
deleted file mode 100644
index ee8a478..0000000
--- a/manpages/Makefile
+++ /dev/null
@@ -1,50 +0,0 @@
-# Makefile
-
-## dosfstools(7)
-## Copyright (C) 2006-2014 Daniel Baumann <mail@daniel-baumann.ch>
-##
-## This program comes with ABSOLUTELY NO WARRANTY; for details see COPYING.
-## This is free software, and you are welcome to redistribute it
-## under certain conditions; see COPYING for details.
-
-
-SHELL := sh -e
-
-LANGUAGES = $(shell cd po && ls)
-
-all: build
-
-po4a.cfg:
- echo "[po4a_langs] $(LANGUAGES)" > po4a.cfg
- echo "[po4a_paths] pot/\$$master.pot \$$lang:po/\$$lang/\$$master.po" >> po4a.cfg
-
- for MANPAGE in en/*; \
- do \
- SECTION="$$(basename $${MANPAGE} | sed -e 's|\.|\n|g' | tail -n1)"; \
- echo "[type: man] $${MANPAGE} \$$lang:\$$lang/$$(basename $${MANPAGE} .$${SECTION}).\$$lang.$${SECTION}" >> po4a.cfg; \
- done
-
-update:
- ./bin/update-version.sh
-
-build: po4a.cfg
- @if [ ! -x "$$(which po4a 2>/dev/null)" ]; \
- then \
- echo "E: po4a - command not found"; \
- echo "I: po4a can be obtained from:"; \
- echo "I: http://po4a.alioth.debian.org/"; \
- echo "I: On Debian based systems, po4a can be installed with:"; \
- echo "I: apt-get install po4a"; \
- exit 1; \
- fi
-
- po4a --keep 0 --no-backups -o untranslated=MT,ME \
- --package-name dosfstools po4a.cfg
-
-clean:
- rm -rf $(LANGUAGES)
-
-distclean: clean
- rm -f po4a.cfg
-
-rebuild: distclean update build
diff --git a/manpages/Makefile.am b/manpages/Makefile.am
new file mode 100644
index 0000000..5473a7f
--- /dev/null
+++ b/manpages/Makefile.am
@@ -0,0 +1,38 @@
+# dosfstools manpages/Makefile.am
+# Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
+#
+# 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 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/>.
+
+man_MANS = fsck.fat.8 mkfs.fat.8 fatlabel.8
+
+
+if COMPAT_SYMLINKS
+install-data-hook:
+ cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f fatlabel.8 dosfslabel.8
+ cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f fsck.fat.8 dosfsck.8
+ cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f fsck.fat.8 fsck.msdos.8
+ cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f fsck.fat.8 fsck.vfat.8
+ cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f mkfs.fat.8 mkdosfs.8
+ cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f mkfs.fat.8 mkfs.msdos.8
+ cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f mkfs.fat.8 mkfs.vfat.8
+
+uninstall-hook:
+ $(RM) $(DESTDIR)$(mandir)/man8/dosfslabel.8
+ $(RM) $(DESTDIR)$(mandir)/man8/dosfsck.8
+ $(RM) $(DESTDIR)$(mandir)/man8/fsck.msdos.8
+ $(RM) $(DESTDIR)$(mandir)/man8/fsck.vfat.8
+ $(RM) $(DESTDIR)$(mandir)/man8/mkdosfs.8
+ $(RM) $(DESTDIR)$(mandir)/man8/mkfs.msdos.8
+ $(RM) $(DESTDIR)$(mandir)/man8/mkfs.vfat.8
+endif
diff --git a/manpages/bin/update-version.sh b/manpages/bin/update-version.sh
deleted file mode 100755
index 48e9c08..0000000
--- a/manpages/bin/update-version.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/sh
-
-## dosfstools(7)
-## Copyright (C) 2006-2014 Daniel Baumann <mail@daniel-baumann.ch>
-##
-## This program comes with ABSOLUTELY NO WARRANTY; for details see COPYING.
-## This is free software, and you are welcome to redistribute it
-## under certain conditions; see COPYING for details.
-
-
-set -e
-
-PROJECT="dosfstools"
-VERSION="$(cat ../VERSION)"
-
-DATE="$(LC_ALL=C date +%Y\\\\-%m\\\\-%d)"
-
-DAY="$(LC_ALL=C date +%d)"
-MONTH="$(LC_ALL=C date +%m)"
-YEAR="$(LC_ALL=C date +%Y)"
-
-echo "Updating version headers..."
-
-for MANPAGE in en/*
-do
- PROGRAM="$(basename ${MANPAGE} | sed -e 's|\(.*\).[0-9]$|\1|' | tr [a-z] [A-Z])"
- SECTION="$(basename ${MANPAGE} | sed -e 's|.*.\([0-9]\)$|\1|')"
-
- sed -i -e "s|^.TH.*$|.TH ${PROGRAM} ${SECTION} ${DATE} ${VERSION} \"${PROJECT}\"|" ${MANPAGE}
-done
-
-# European date format
-for _LANGUAGE in de es fr it
-do
- if ls po/${_LANGUAGE}/*.po > /dev/null 2>&1
- then
- for _FILE in po/${_LANGUAGE}/*.po
- do
- sed -i -e "s|^msgstr .*.2014-.*$|msgstr \"${DAY}.${MONTH}.${YEAR}\"|g" \
- -e "s|^msgstr .*.2014\"$|msgstr \"${DAY}.${MONTH}.${YEAR}\"|g" \
- "${_FILE}"
- done
- fi
-done
-
-# Brazilian date format
-if ls po/pt_BR/*.po > /dev/null 2>&1
-then
- for _FILE in po/pt_BR/*.po
- do
- sed -i -e "s|^msgstr .*.2014-.*$|msgstr \"${DAY}-${MONTH}-${YEAR}\"|g" \
- -e "s|^msgstr .*-2014\"$|msgstr \"${DAY}-${MONTH}-${YEAR}\"|g" \
- "${_FILE}"
- done
-fi
diff --git a/manpages/en/fatlabel.8 b/manpages/fatlabel.8.in
index c00a795..bf5ebbd 100644
--- a/manpages/en/fatlabel.8
+++ b/manpages/fatlabel.8.in
@@ -19,7 +19,7 @@
.\" can be found in /usr/share/common-licenses/GPL-3 file.
.\"
.\"
-.TH FATLABEL 8 2015\-05\-16 3.0.28 "dosfstools"
+.TH FATLABEL 8 2015\-04\-16 "dosfstools @PACKAGE_VERSION@"
.SH NAME
\fBfatlabel\fR \- set or get MS\-DOS filesystem label
.\" ----------------------------------------------------------------------------
diff --git a/manpages/en/fsck.fat.8 b/manpages/fsck.fat.8.in
index f2d44d0..06057a8 100644
--- a/manpages/en/fsck.fat.8
+++ b/manpages/fsck.fat.8.in
@@ -19,7 +19,7 @@
.\" can be found in /usr/share/common-licenses/GPL-3 file.
.\"
.\"
-.TH FSCK.FAT 8 2015\-05\-16 3.0.28 "dosfstools"
+.TH FSCK.FAT 8 2015\-04\-16 "dosfstools @PACKAGE_VERSION@"
.SH NAME
\fBfsck.fat\fR \- check and repair MS\-DOS filesystems
.\" ----------------------------------------------------------------------------
@@ -115,6 +115,9 @@ MS\-DOS uses only 0xfff7 for bad clusters, where on Atari values 0xfff0...0xfff7
are for this purpose (but the standard value is still 0xfff7).
.IP "\fB-b\fR" 4
Make read-only boot sector check.
+.IP "\fB-c\fR \fIPAGE\fR" 4
+Use DOS codepage \fIPAGE\fR to decode short file names.
+By default codepage 437 is used.
.IP "\fB\-d\fR \fIPATH\fR" 4
Delete the specified file.
If more than one file with that name exist, the first one is deleted.
diff --git a/manpages/en/mkfs.fat.8 b/manpages/mkfs.fat.8.in
index 5a5086e..2d19daf 100644
--- a/manpages/en/mkfs.fat.8
+++ b/manpages/mkfs.fat.8.in
@@ -1,6 +1,7 @@
.\" mkfs.fat.8 - manpage for fs.fatck
.\"
.\" Copyright (C) 2006-2014 Daniel Baumann <daniel@debian.org>
+.\" Copyright (C) 2016 Andreas Bombe <aeb@debian.org>
.\"
.\" 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
@@ -19,7 +20,7 @@
.\" can be found in /usr/share/common-licenses/GPL-3 file.
.\"
.\"
-.TH MKFS.FAT 8 2015\-05\-16 3.0.28 "dosfstools"
+.TH MKFS.FAT 8 2016\-01\-25 "dosfstools @PACKAGE_VERSION@"
.SH NAME
\fBmkfs.fat\fR \- create an MS-DOS filesystem under Linux
.\" ----------------------------------------------------------------------------
@@ -135,6 +136,8 @@ Must be a power of 2, i.e. 1, 2, 4, 8, ... 128.
Specify the number of bytes per logical sector.
Must be a power of 2 and greater than or equal to 512, i.e. 512, 1024, 2048,
4096, 8192, 16384, or 32768.
+Values larger than 4096 are not conforming to the FAT file system specification
+and may not work everywhere.
.IP "\fB\-v\fR" 4
Verbose execution.
.IP "\fB\-\-invariant\fR" 4
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..3d22ba7
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,63 @@
+# dosfstools src/Makefile.am
+# Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
+#
+# 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 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/>.
+
+AM_CFLAGS = -Wall -Wextra -Wno-sign-compare -Wno-missing-field-initializers \
+ -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings
+
+sbin_PROGRAMS = fsck.fat mkfs.fat fatlabel
+noinst_PROGRAMS = testdevinfo
+
+fscklabel_common_sources = boot.c boot.h check.c check.h common.c common.h \
+ fat.c fat.h file.c file.h io.c io.h lfn.c lfn.h \
+ charconv.c charconv.h msdos_fs.h \
+ fsck.fat.h endian_compat.h
+fsck_fat_SOURCES = fsck.fat.c $(fscklabel_common_sources)
+fatlabel_SOURCES = fatlabel.c $(fscklabel_common_sources)
+
+mkfs_common_sources = device_info.c device_info.h \
+ blkdev/blkdev.c blkdev/blkdev.h \
+ endian_compat.h \
+ blkdev/linux_version.c blkdev/linux_version.h
+mkfs_fat_SOURCES = mkfs.fat.c msdos_fs.h $(mkfs_common_sources)
+mkfs_fat_CPPFLAGS = -I$(srcdir)/blkdev
+mkfs_fat_CFLAGS = $(AM_CFLAGS) $(UDEV_CFLAGS)
+mkfs_fat_LDFLAGS = $(UDEV_LIBS)
+
+testdevinfo_SOURCES = testdevinfo.c $(mkfs_common_sources)
+testdevinfo_CPPFLAGS = -I$(srcdir)/blkdev
+testdevinfo_CFLAGS = $(AM_CFLAGS) $(UDEV_CFLAGS)
+testdevinfo_LDFLAGS = $(UDEV_LIBS)
+
+
+if COMPAT_SYMLINKS
+install-exec-hook:
+ cd $(DESTDIR)$(sbindir) && $(LN_S) -f fatlabel dosfslabel
+ cd $(DESTDIR)$(sbindir) && $(LN_S) -f fsck.fat dosfsck
+ cd $(DESTDIR)$(sbindir) && $(LN_S) -f fsck.fat fsck.msdos
+ cd $(DESTDIR)$(sbindir) && $(LN_S) -f fsck.fat fsck.vfat
+ cd $(DESTDIR)$(sbindir) && $(LN_S) -f mkfs.fat mkdosfs
+ cd $(DESTDIR)$(sbindir) && $(LN_S) -f mkfs.fat mkfs.msdos
+ cd $(DESTDIR)$(sbindir) && $(LN_S) -f mkfs.fat mkfs.vfat
+
+uninstall-hook:
+ $(RM) $(DESTDIR)$(sbindir)/dosfslabel
+ $(RM) $(DESTDIR)$(sbindir)/dosfsck
+ $(RM) $(DESTDIR)$(sbindir)/fsck.msdos
+ $(RM) $(DESTDIR)$(sbindir)/fsck.vfat
+ $(RM) $(DESTDIR)$(sbindir)/mkdosfs
+ $(RM) $(DESTDIR)$(sbindir)/mkfs.msdos
+ $(RM) $(DESTDIR)$(sbindir)/mkfs.vfat
+endif
diff --git a/src/blkdev/README b/src/blkdev/README
new file mode 100644
index 0000000..af74eb7
--- /dev/null
+++ b/src/blkdev/README
@@ -0,0 +1,3 @@
+The source files blkdev.[ch] and linux_version.[ch] have been taken from
+util-linux (git://git.kernel.org/pub/scm/utils/util-linux/util-linux.git)
+git revision 42f536ee8.
diff --git a/src/blkdev/blkdev.c b/src/blkdev/blkdev.c
new file mode 100644
index 0000000..ae9c8d1
--- /dev/null
+++ b/src/blkdev/blkdev.c
@@ -0,0 +1,376 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#ifdef HAVE_LINUX_HDREG_H
+#include <linux/hdreg.h>
+#endif
+
+#ifdef HAVE_LINUX_FD_H
+#include <linux/fd.h>
+#endif
+
+#ifdef HAVE_SYS_DISKLABEL_H
+#include <sys/disklabel.h>
+#endif
+
+#ifdef HAVE_SYS_DISK_H
+# ifdef HAVE_SYS_QUEUE_H
+# include <sys/queue.h> /* for LIST_HEAD */
+# endif
+# include <sys/disk.h>
+#endif
+
+#include "blkdev.h"
+#include "linux_version.h"
+
+static long
+blkdev_valid_offset (int fd, off_t offset) {
+ char ch;
+
+ if (lseek (fd, offset, 0) < 0)
+ return 0;
+ if (read (fd, &ch, 1) < 1)
+ return 0;
+ return 1;
+}
+
+int is_blkdev(int fd)
+{
+ struct stat st;
+ return (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode));
+}
+
+off_t
+blkdev_find_size (int fd) {
+ uintmax_t high, low = 0;
+
+ for (high = 1024; blkdev_valid_offset (fd, high); ) {
+ if (high == UINTMAX_MAX)
+ return -1;
+
+ low = high;
+
+ if (high >= UINTMAX_MAX/2)
+ high = UINTMAX_MAX;
+ else
+ high *= 2;
+ }
+
+ while (low < high - 1)
+ {
+ uintmax_t mid = (low + high) / 2;
+
+ if (blkdev_valid_offset (fd, mid))
+ low = mid;
+ else
+ high = mid;
+ }
+ blkdev_valid_offset (fd, 0);
+ return (low + 1);
+}
+
+/* get size in bytes */
+int
+blkdev_get_size(int fd, unsigned long long *bytes)
+{
+#ifdef DKIOCGETBLOCKCOUNT
+ /* Apple Darwin */
+ if (ioctl(fd, DKIOCGETBLOCKCOUNT, bytes) >= 0) {
+ *bytes <<= 9;
+ return 0;
+ }
+#endif
+
+#ifdef BLKGETSIZE64
+ {
+#ifdef __linux__
+ int ver = get_linux_version();
+
+ /* kernels 2.4.15-2.4.17, had a broken BLKGETSIZE64 */
+ if (ver >= KERNEL_VERSION (2,6,0) ||
+ (ver >= KERNEL_VERSION (2,4,18) && ver < KERNEL_VERSION (2,5,0)))
+#endif
+ if (ioctl(fd, BLKGETSIZE64, bytes) >= 0)
+ return 0;
+ }
+#endif /* BLKGETSIZE64 */
+
+#ifdef BLKGETSIZE
+ {
+ unsigned long size;
+
+ if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+ *bytes = ((unsigned long long)size << 9);
+ return 0;
+ }
+ }
+
+#endif /* BLKGETSIZE */
+
+#ifdef DIOCGMEDIASIZE
+ /* FreeBSD */
+ if (ioctl(fd, DIOCGMEDIASIZE, bytes) >= 0)
+ return 0;
+#endif
+
+#ifdef FDGETPRM
+ {
+ struct floppy_struct this_floppy;
+
+ if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
+ *bytes = ((unsigned long long) this_floppy.size) << 9;
+ return 0;
+ }
+ }
+#endif /* FDGETPRM */
+
+#ifdef HAVE_SYS_DISKLABEL_H
+ {
+ /*
+ * This code works for FreeBSD 4.11 i386, except for the full device
+ * (such as /dev/ad0). It doesn't work properly for newer FreeBSD
+ * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE
+ * above however.
+ *
+ * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw,
+ * character) devices, so we need to check for S_ISCHR, too.
+ */
+ int part = -1;
+ struct disklabel lab;
+ struct partition *pp;
+ struct stat st;
+
+ if ((fstat(fd, &st) >= 0) &&
+ (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)))
+ part = st.st_rdev & 7;
+
+ if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
+ pp = &lab.d_partitions[part];
+ if (pp->p_size) {
+ *bytes = pp->p_size << 9;
+ return 0;
+ }
+ }
+ }
+#endif /* HAVE_SYS_DISKLABEL_H */
+
+ {
+ struct stat st;
+
+ if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
+ *bytes = st.st_size;
+ return 0;
+ }
+ if (!S_ISBLK(st.st_mode))
+ return -1;
+ }
+
+ *bytes = blkdev_find_size(fd);
+ return 0;
+}
+
+/* get 512-byte sector count */
+int
+blkdev_get_sectors(int fd, unsigned long long *sectors)
+{
+ unsigned long long bytes;
+
+ if (blkdev_get_size(fd, &bytes) == 0) {
+ *sectors = (bytes >> 9);
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Get logical sector size.
+ *
+ * This is the smallest unit the storage device can
+ * address. It is typically 512 bytes.
+ */
+int blkdev_get_sector_size(int fd, int *sector_size)
+{
+#ifdef BLKSSZGET
+ if (ioctl(fd, BLKSSZGET, sector_size) >= 0)
+ return 0;
+ return -1;
+#else
+ (void)fd; /* prevent unused parameter warning */
+ *sector_size = DEFAULT_SECTOR_SIZE;
+ return 0;
+#endif
+}
+
+/*
+ * Get physical block device size. The BLKPBSZGET is supported since Linux
+ * 2.6.32. For old kernels is probably the best to assume that physical sector
+ * size is the same as logical sector size.
+ *
+ * Example:
+ *
+ * rc = blkdev_get_physector_size(fd, &physec);
+ * if (rc || physec == 0) {
+ * rc = blkdev_get_sector_size(fd, &physec);
+ * if (rc)
+ * physec = DEFAULT_SECTOR_SIZE;
+ * }
+ */
+int blkdev_get_physector_size(int fd, int *sector_size)
+{
+#ifdef BLKPBSZGET
+ if (ioctl(fd, BLKPBSZGET, &sector_size) >= 0)
+ return 0;
+ return -1;
+#else
+ (void)fd; /* prevent unused parameter warning */
+ *sector_size = DEFAULT_SECTOR_SIZE;
+ return 0;
+#endif
+}
+
+/*
+ * Return the alignment status of a device
+ */
+int blkdev_is_misaligned(int fd)
+{
+#ifdef BLKALIGNOFF
+ int aligned;
+
+ if (ioctl(fd, BLKALIGNOFF, &aligned) < 0)
+ return 0; /* probably kernel < 2.6.32 */
+ /*
+ * Note that kernel returns -1 as alignement offset if no compatible
+ * sizes and alignments exist for stacked devices
+ */
+ return aligned != 0 ? 1 : 0;
+#else
+ (void)fd; /* prevent unused parameter warning */
+ return 0;
+#endif
+}
+
+int blkdev_is_cdrom(int fd)
+{
+#ifdef CDROM_GET_CAPABILITY
+ int ret;
+
+ if ((ret = ioctl(fd, CDROM_GET_CAPABILITY, NULL)) < 0)
+ return 0;
+ else
+ return ret;
+#else
+ (void)fd; /* prevent unused parameter warning */
+ return 0;
+#endif
+}
+
+/*
+ * Get kernel's interpretation of the device's geometry.
+ *
+ * Returns the heads and sectors - but not cylinders
+ * as it's truncated for disks with more than 65535 tracks.
+ *
+ * Note that this is deprecated in favor of LBA addressing.
+ */
+int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s)
+{
+#ifdef HDIO_GETGEO
+ {
+ struct hd_geometry geometry;
+
+ if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) {
+ *h = geometry.heads;
+ *s = geometry.sectors;
+ return 0;
+ }
+ }
+#endif
+
+#ifdef FDGETPRM
+ {
+ struct floppy_struct fdparam;
+
+ if (ioctl(fd, FDGETPRM, &fdparam) == 0) {
+ *h = fdparam.head;
+ *s = fdparam.sect;
+ return 0;
+ }
+ }
+#endif
+
+ (void)fd; /* prevent unused parameter warning */
+ *h = 0;
+ *s = 0;
+ return -1;
+}
+
+/*
+ * Get start offset of partition
+ */
+int blkdev_get_start(int fd, unsigned int *s)
+{
+#ifdef HDIO_GETGEO
+ struct hd_geometry geometry;
+
+ if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) {
+ *s = geometry.start;
+ return 0;
+ }
+#endif
+
+ (void)fd; /* prevent unused parameter warning */
+ *s = 0;
+ return -1;
+}
+
+/*
+ * Convert scsi type to human readable string.
+ */
+const char *blkdev_scsi_type_to_name(int type)
+{
+ switch (type) {
+ case SCSI_TYPE_DISK:
+ return "disk";
+ case SCSI_TYPE_TAPE:
+ return "tape";
+ case SCSI_TYPE_PRINTER:
+ return "printer";
+ case SCSI_TYPE_PROCESSOR:
+ return "processor";
+ case SCSI_TYPE_WORM:
+ return "worm";
+ case SCSI_TYPE_ROM:
+ return "rom";
+ case SCSI_TYPE_SCANNER:
+ return "scanner";
+ case SCSI_TYPE_MOD:
+ return "mo-disk";
+ case SCSI_TYPE_MEDIUM_CHANGER:
+ return "changer";
+ case SCSI_TYPE_COMM:
+ return "comm";
+ case SCSI_TYPE_RAID:
+ return "raid";
+ case SCSI_TYPE_ENCLOSURE:
+ return "enclosure";
+ case SCSI_TYPE_RBC:
+ return "rbc";
+ case SCSI_TYPE_OSD:
+ return "osd";
+ case SCSI_TYPE_NO_LUN:
+ return "no-lun";
+ default:
+ break;
+ }
+ return NULL;
+}
diff --git a/src/blkdev/blkdev.h b/src/blkdev/blkdev.h
new file mode 100644
index 0000000..b9179ad
--- /dev/null
+++ b/src/blkdev/blkdev.h
@@ -0,0 +1,149 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#ifndef BLKDEV_H
+#define BLKDEV_H
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_IOCCOM_H
+# include <sys/ioccom.h> /* for _IO macro on e.g. Solaris */
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_MKDEV_H
+# include <sys/mkdev.h> /* major and minor on Solaris */
+#endif
+
+#define DEFAULT_SECTOR_SIZE 512
+
+#ifdef __linux__
+/* very basic ioctls, should be available everywhere */
+# ifndef BLKROSET
+# define BLKROSET _IO(0x12,93) /* set device read-only (0 = read-write) */
+# define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */
+# define BLKRRPART _IO(0x12,95) /* re-read partition table */
+# define BLKGETSIZE _IO(0x12,96) /* return device size /512 (long *arg) */
+# define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
+# define BLKRASET _IO(0x12,98) /* set read ahead for block device */
+# define BLKRAGET _IO(0x12,99) /* get current read ahead setting */
+# define BLKFRASET _IO(0x12,100) /* set filesystem (mm/filemap.c) read-ahead */
+# define BLKFRAGET _IO(0x12,101) /* get filesystem (mm/filemap.c) read-ahead */
+# define BLKSECTSET _IO(0x12,102) /* set max sectors per request (ll_rw_blk.c) */
+# define BLKSECTGET _IO(0x12,103) /* get max sectors per request (ll_rw_blk.c) */
+# define BLKSSZGET _IO(0x12,104) /* get block device sector size */
+
+/* ioctls introduced in 2.2.16, removed in 2.5.58 */
+# define BLKELVGET _IOR(0x12,106,size_t) /* elevator get */
+# define BLKELVSET _IOW(0x12,107,size_t) /* elevator set */
+
+# define BLKBSZGET _IOR(0x12,112,size_t)
+# define BLKBSZSET _IOW(0x12,113,size_t)
+# endif /* !BLKROSET */
+
+# ifndef BLKGETSIZE64
+# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
+# endif
+
+/* block device topology ioctls, introduced in 2.6.32 (commit ac481c20) */
+# ifndef BLKIOMIN
+# define BLKIOMIN _IO(0x12,120)
+# define BLKIOOPT _IO(0x12,121)
+# define BLKALIGNOFF _IO(0x12,122)
+# define BLKPBSZGET _IO(0x12,123)
+# endif
+
+/* discard zeroes support, introduced in 2.6.33 (commit 98262f27) */
+# ifndef BLKDISCARDZEROES
+# define BLKDISCARDZEROES _IO(0x12,124)
+# endif
+
+/* filesystem freeze, introduced in 2.6.29 (commit fcccf502) */
+# ifndef FIFREEZE
+# define FIFREEZE _IOWR('X', 119, int) /* Freeze */
+# define FITHAW _IOWR('X', 120, int) /* Thaw */
+# endif
+
+/* uniform CD-ROM information */
+# ifndef CDROM_GET_CAPABILITY
+# define CDROM_GET_CAPABILITY 0x5331
+# endif
+
+#endif /* __linux */
+
+
+#ifdef APPLE_DARWIN
+# define BLKGETSIZE DKIOCGETBLOCKCOUNT32
+#endif
+
+#ifndef HDIO_GETGEO
+# ifdef __linux__
+# define HDIO_GETGEO 0x0301
+# endif
+
+struct hd_geometry {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders; /* truncated */
+ unsigned long start;
+};
+#endif /* HDIO_GETGEO */
+
+
+/* are we working with block device? */
+int is_blkdev(int fd);
+
+/* Determine size in bytes */
+off_t blkdev_find_size (int fd);
+
+/* get size in bytes */
+int blkdev_get_size(int fd, unsigned long long *bytes);
+
+/* get 512-byte sector count */
+int blkdev_get_sectors(int fd, unsigned long long *sectors);
+
+/* get hardware sector size */
+int blkdev_get_sector_size(int fd, int *sector_size);
+
+/* specifies whether or not the device is misaligned */
+int blkdev_is_misaligned(int fd);
+
+/* get physical block device size */
+int blkdev_get_physector_size(int fd, int *sector_size);
+
+/* is the device cdrom capable? */
+int blkdev_is_cdrom(int fd);
+
+/* get device's geometry - legacy */
+int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s);
+
+/* get partition devices start offset */
+int blkdev_get_start(int fd, unsigned int *s);
+
+/* SCSI device types. Copied almost as-is from kernel header.
+ * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/scsi/scsi.h */
+#define SCSI_TYPE_DISK 0x00
+#define SCSI_TYPE_TAPE 0x01
+#define SCSI_TYPE_PRINTER 0x02
+#define SCSI_TYPE_PROCESSOR 0x03 /* HP scanners use this */
+#define SCSI_TYPE_WORM 0x04 /* Treated as ROM by our system */
+#define SCSI_TYPE_ROM 0x05
+#define SCSI_TYPE_SCANNER 0x06
+#define SCSI_TYPE_MOD 0x07 /* Magneto-optical disk - treated as SCSI_TYPE_DISK */
+#define SCSI_TYPE_MEDIUM_CHANGER 0x08
+#define SCSI_TYPE_COMM 0x09 /* Communications device */
+#define SCSI_TYPE_RAID 0x0c
+#define SCSI_TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
+#define SCSI_TYPE_RBC 0x0e
+#define SCSI_TYPE_OSD 0x11
+#define SCSI_TYPE_NO_LUN 0x7f
+
+/* convert scsi type code to name */
+const char *blkdev_scsi_type_to_name(int type);
+
+
+#endif /* BLKDEV_H */
diff --git a/src/blkdev/linux_version.c b/src/blkdev/linux_version.c
new file mode 100644
index 0000000..2bcc2cc
--- /dev/null
+++ b/src/blkdev/linux_version.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <sys/utsname.h>
+
+#include "linux_version.h"
+
+int get_linux_version (void)
+{
+ static int kver = -1;
+ struct utsname uts;
+ int major = 0;
+ int minor = 0;
+ int teeny = 0;
+ int n;
+
+ if (kver != -1)
+ return kver;
+ if (uname (&uts))
+ return kver = 0;
+
+ n = sscanf(uts.release, "%d.%d.%d", &major, &minor, &teeny);
+ if (n < 1 || n > 3)
+ return kver = 0;
+
+ return kver = KERNEL_VERSION(major, minor, teeny);
+}
diff --git a/src/blkdev/linux_version.h b/src/blkdev/linux_version.h
new file mode 100644
index 0000000..a6a1e99
--- /dev/null
+++ b/src/blkdev/linux_version.h
@@ -0,0 +1,14 @@
+#ifndef LINUX_VERSION_H
+#define LINUX_VERSION_H
+
+#ifdef HAVE_LINUX_VERSION_H
+# include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
+int get_linux_version(void);
+
+#endif /* LINUX_VERSION_H */
diff --git a/src/boot.c b/src/boot.c
index 0c0918f..491ecd9 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -3,6 +3,7 @@
Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
+ Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
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
@@ -28,6 +29,7 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
+#include <sys/types.h>
#include <time.h>
#include "common.h"
@@ -101,8 +103,8 @@ static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss)
(unsigned long long)fs->fat_start,
(unsigned long long)fs->fat_start / lss);
printf("%10d FATs, %d bit entries\n", b->fats, fs->fat_bits);
- printf("%10d bytes per FAT (= %u sectors)\n", fs->fat_size,
- fs->fat_size / lss);
+ printf("%10lld bytes per FAT (= %llu sectors)\n", (long long)fs->fat_size,
+ (long long)fs->fat_size / lss);
if (!fs->root_cluster) {
printf("Root directory starts at byte %llu (sector %llu)\n",
(unsigned long long)fs->root_start,
@@ -115,8 +117,9 @@ static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss)
printf("Data area starts at byte %llu (sector %llu)\n",
(unsigned long long)fs->data_start,
(unsigned long long)fs->data_start / lss);
- printf("%10lu data clusters (%llu bytes)\n", (unsigned long)fs->clusters,
- (unsigned long long)fs->clusters * fs->cluster_size);
+ printf("%10lu data clusters (%llu bytes)\n",
+ (unsigned long)fs->data_clusters,
+ (unsigned long long)fs->data_clusters * fs->cluster_size);
printf("%u sectors/track, %u heads\n", le16toh(b->secs_track),
le16toh(b->heads));
printf("%10u hidden sectors\n", atari_format ?
@@ -155,7 +158,7 @@ static void check_backup_boot(DOS_FS * fs, struct boot_sector *b, int lss)
fs->backupboot_start = bbs * lss;
b->backup_boot = htole16(bbs);
fs_write(fs->backupboot_start, sizeof(*b), b);
- fs_write((loff_t) offsetof(struct boot_sector, backup_boot),
+ fs_write(offsetof(struct boot_sector, backup_boot),
sizeof(b->backup_boot), &b->backup_boot);
printf("Created backup of boot sector in sector %d\n", bbs);
return;
@@ -233,9 +236,9 @@ static void read_fsinfo(DOS_FS * fs, struct boot_sector *b, int lss)
break;
if (s > 0 && s < le16toh(b->reserved)) {
init_fsinfo(&i);
- fs_write((loff_t) s * lss, sizeof(i), &i);
+ fs_write((off_t)s * lss, sizeof(i), &i);
b->info_sector = htole16(s);
- fs_write((loff_t) offsetof(struct boot_sector, info_sector),
+ fs_write(offsetof(struct boot_sector, info_sector),
sizeof(b->info_sector), &b->info_sector);
if (fs->backupboot_start)
fs_write(fs->backupboot_start +
@@ -326,8 +329,9 @@ void read_boot(DOS_FS * fs)
struct boot_sector b;
unsigned total_sectors;
unsigned short logical_sector_size, sectors;
- unsigned fat_length;
- loff_t data_size;
+ off_t fat_length;
+ unsigned total_fat_entries;
+ off_t data_size;
fs_read(0, sizeof(b), &b);
logical_sector_size = GET_UNALIGNED_W(b.sector_size);
@@ -352,19 +356,27 @@ void read_boot(DOS_FS * fs)
if (verbose)
printf("Checking we can access the last sector of the filesystem\n");
/* Can't access last odd sector anyway, so round down */
- fs_test((loff_t) ((total_sectors & ~1) - 1) * (loff_t) logical_sector_size,
+ fs_test((off_t)((total_sectors & ~1) - 1) * logical_sector_size,
logical_sector_size);
+
fat_length = le16toh(b.fat_length) ?
le16toh(b.fat_length) : le32toh(b.fat32_length);
- fs->fat_start = (loff_t) le16toh(b.reserved) * logical_sector_size;
- fs->root_start = ((loff_t) le16toh(b.reserved) + b.fats * fat_length) *
+ if (!fat_length)
+ die("FAT size is zero.");
+
+ fs->fat_start = (off_t)le16toh(b.reserved) * logical_sector_size;
+ fs->root_start = ((off_t)le16toh(b.reserved) + b.fats * fat_length) *
logical_sector_size;
fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
fs->data_start = fs->root_start + ROUND_TO_MULTIPLE(fs->root_entries <<
MSDOS_DIR_BITS,
logical_sector_size);
- data_size = (loff_t) total_sectors *logical_sector_size - fs->data_start;
- fs->clusters = data_size / fs->cluster_size;
+
+ data_size = (off_t)total_sectors * logical_sector_size - fs->data_start;
+ if (data_size < fs->cluster_size)
+ die("Filesystem has no space for any data clusters");
+
+ fs->data_clusters = data_size / fs->cluster_size;
fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */
fs->fsinfo_start = 0; /* no FSINFO structure */
fs->free_clusters = -1; /* unknown */
@@ -385,13 +397,13 @@ void read_boot(DOS_FS * fs)
printf("Warning: FAT32 root dir is in a cluster chain, but "
"a separate root dir\n"
" area is defined. Cannot fix this easily.\n");
- if (fs->clusters < FAT16_THRESHOLD)
+ if (fs->data_clusters < FAT16_THRESHOLD)
printf("Warning: Filesystem is FAT32 according to fat_length "
"and fat32_length fields,\n"
" but has only %lu clusters, less than the required "
"minimum of %d.\n"
" This may lead to problems on some systems.\n",
- (unsigned long)fs->clusters, FAT16_THRESHOLD);
+ (unsigned long)fs->data_clusters, FAT16_THRESHOLD);
check_fat_state_bit(fs, &b);
fs->backupboot_start = le16toh(b.backup_boot) * logical_sector_size;
@@ -401,9 +413,9 @@ void read_boot(DOS_FS * fs)
} else if (!atari_format) {
/* On real MS-DOS, a 16 bit FAT is used whenever there would be too
* much clusers otherwise. */
- fs->fat_bits = (fs->clusters >= FAT12_THRESHOLD) ? 16 : 12;
- if (fs->clusters >= FAT16_THRESHOLD)
- die("Too many clusters (%lu) for FAT16 filesystem.", fs->clusters);
+ fs->fat_bits = (fs->data_clusters >= FAT12_THRESHOLD) ? 16 : 12;
+ if (fs->data_clusters >= FAT16_THRESHOLD)
+ die("Too many clusters (%lu) for FAT16 filesystem.", fs->data_clusters);
check_fat_state_bit(fs, &b);
} else {
/* On Atari, things are more difficult: GEMDOS always uses 12bit FATs
@@ -411,14 +423,10 @@ void read_boot(DOS_FS * fs)
fs->fat_bits = 16; /* assume 16 bit FAT for now */
/* If more clusters than fat entries in 16-bit fat, we assume
* it's a real MSDOS FS with 12-bit fat. */
- if (fs->clusters + 2 > fat_length * logical_sector_size * 8 / 16 ||
- /* if it's a floppy disk --> 12bit fat */
- device_no == 2 ||
- /* if it's a ramdisk or loopback device and has one of the usual
- * floppy sizes -> 12bit FAT */
- ((device_no == 1 || device_no == 7) &&
- (total_sectors == 720 || total_sectors == 1440 ||
- total_sectors == 2880)))
+ if (fs->data_clusters + 2 > fat_length * logical_sector_size * 8 / 16 ||
+ /* if it has one of the usual floppy sizes -> 12bit FAT */
+ (total_sectors == 720 || total_sectors == 1440 ||
+ total_sectors == 2880))
fs->fat_bits = 12;
}
/* On FAT32, the high 4 bits of a FAT entry are reserved */
@@ -439,11 +447,10 @@ void read_boot(DOS_FS * fs)
fs->label = NULL;
}
- if (fs->clusters >
- ((uint64_t)fs->fat_size * 8 / fs->fat_bits) - 2)
- die("Filesystem has %d clusters but only space for %d FAT entries.",
- fs->clusters,
- ((unsigned long long)fs->fat_size * 8 / fs->fat_bits) - 2);
+ total_fat_entries = (uint64_t)fs->fat_size * 8 / fs->fat_bits;
+ if (fs->data_clusters > total_fat_entries - 2)
+ die("Filesystem has %u clusters but only space for %u FAT entries.",
+ fs->data_clusters, total_fat_entries - 2);
if (!fs->root_entries && !fs->root_cluster)
die("Root directory has zero size.");
if (fs->root_entries & (MSDOS_DPS - 1))
@@ -491,10 +498,10 @@ static void write_boot_label(DOS_FS * fs, char *label)
}
}
-loff_t find_volume_de(DOS_FS * fs, DIR_ENT * de)
+off_t find_volume_de(DOS_FS * fs, DIR_ENT * de)
{
uint32_t cluster;
- loff_t offset;
+ off_t offset;
int i;
if (fs->root_cluster) {
@@ -525,7 +532,7 @@ static void write_volume_label(DOS_FS * fs, char *label)
{
time_t now = time(NULL);
struct tm *mtime = localtime(&now);
- loff_t offset;
+ off_t offset;
int created;
DIR_ENT de;
diff --git a/src/boot.h b/src/boot.h
index d52e624..dd9404f 100644
--- a/src/boot.h
+++ b/src/boot.h
@@ -25,7 +25,7 @@
void read_boot(DOS_FS * fs);
void write_label(DOS_FS * fs, char *label);
-loff_t find_volume_de(DOS_FS * fs, DIR_ENT * de);
+off_t find_volume_de(DOS_FS * fs, DIR_ENT * de);
/* Reads the boot sector from the currently open device and initializes *FS */
diff --git a/src/check.c b/src/check.c
index d8b9d72..59d6d27 100644
--- a/src/check.c
+++ b/src/check.c
@@ -3,6 +3,7 @@
Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
+ Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
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
@@ -27,7 +28,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <limits.h>
#include <time.h>
#include "common.h"
@@ -38,6 +38,10 @@
#include "lfn.h"
#include "check.h"
+
+/* the longest path on the filesystem that can be handled by path_name() */
+#define PATH_NAME_MAX 1023
+
static DOS_FILE *root;
/* get start field of a dir entry */
@@ -56,7 +60,7 @@ static DOS_FILE *root;
#define MODIFY_START(p,v,fs) \
do { \
- uint32_t __v = (v); \
+ uint32_t __v = (v); \
if (!p->offset) { \
/* writing to fake entry for FAT32 root dir */ \
if (!__v) die("Oops, deleting FAT32 root dir!"); \
@@ -64,7 +68,7 @@ static DOS_FILE *root;
p->dir_ent.start = htole16(__v&0xffff); \
p->dir_ent.starthi = htole16(__v>>16); \
__v = htole32(__v); \
- fs_write((loff_t)offsetof(struct boot_sector,root_cluster), \
+ fs_write(offsetof(struct boot_sector,root_cluster), \
sizeof(((struct boot_sector *)0)->root_cluster), \
&__v); \
} \
@@ -75,16 +79,16 @@ static DOS_FILE *root;
} \
} while(0)
-loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern)
+off_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern)
{
static int curr_num = 0;
- loff_t offset;
+ off_t offset;
if (fs->root_cluster) {
DIR_ENT d2;
int i = 0, got = 0;
uint32_t clu_num, prev = 0;
- loff_t offset2;
+ off_t offset2;
clu_num = fs->root_cluster;
offset = cluster_start(fs, clu_num);
@@ -111,7 +115,7 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern)
for (clu_num = prev + 1; clu_num != prev; clu_num++) {
FAT_ENTRY entry;
- if (clu_num >= fs->clusters + 2)
+ if (clu_num >= fs->data_clusters + 2)
clu_num = 2;
get_fat(&entry, fs->fat, clu_num, fs);
if (!entry.value)
@@ -132,8 +136,7 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern)
while (1) {
char expanded[12];
sprintf(expanded, pattern, curr_num);
- memcpy(de->name, expanded, 8);
- memcpy(de->ext, expanded + 8, 3);
+ memcpy(de->name, expanded, MSDOS_NAME);
clu_num = fs->root_cluster;
i = 0;
offset2 = cluster_start(fs, clu_num);
@@ -177,8 +180,7 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern)
while (1) {
char expanded[12];
sprintf(expanded, pattern, curr_num);
- memcpy(de->name, expanded, 8);
- memcpy(de->ext, expanded + 8, 3);
+ memcpy(de->name, expanded, MSDOS_NAME);
for (scan = 0; scan < fs->root_entries; scan++)
if (scan != next_free &&
!strncmp((const char *)root[scan].name,
@@ -205,12 +207,12 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern)
*/
static char *path_name(DOS_FILE * file)
{
- static char path[PATH_MAX * 2];
+ static char path[PATH_NAME_MAX * 2];
if (!file)
*path = 0; /* Reached the root directory */
else {
- if (strlen(path_name(file->parent)) > PATH_MAX)
+ if (strlen(path_name(file->parent)) > PATH_NAME_MAX)
die("Path name too long.");
if (strcmp(path, "/") != 0)
strcat(path, "/");
@@ -224,9 +226,9 @@ static char *path_name(DOS_FILE * file)
return path;
}
-static int day_n[] =
- { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 };
- /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+static const int day_n[] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 };
+/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
@@ -236,6 +238,10 @@ static time_t date_dos2unix(unsigned short time, unsigned short date)
time_t secs;
month = ((date >> 5) & 15) - 1;
+ if (month < 0) {
+ /* make sure that nothing bad happens if the month bits were zero */
+ month = 0;
+ }
year = date >> 9;
secs =
(time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
@@ -265,7 +271,7 @@ static int bad_name(DOS_FILE * file)
int i, spc, suspicious = 0;
const char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:";
const unsigned char *name = file->dir_ent.name;
- const unsigned char *ext = file->dir_ent.ext;
+ const unsigned char *ext = name + 8;
/* Do not complain about (and auto-correct) the extended attribute files
* of OS/2. */
@@ -283,7 +289,7 @@ static int bad_name(DOS_FILE * file)
if (file->dir_ent.lcase & FAT_NO_83NAME)
return 0;
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < MSDOS_NAME; i++) {
if (name[i] < ' ' || name[i] == 0x7f)
return 1;
if (name[i] > 0x7f)
@@ -292,15 +298,6 @@ static int bad_name(DOS_FILE * file)
return 1;
}
- for (i = 0; i < 3; i++) {
- if (ext[i] < ' ' || ext[i] == 0x7f)
- return 1;
- if (ext[i] > 0x7f)
- ++suspicious;
- if (strchr(bad_chars, ext[i]))
- return 1;
- }
-
spc = 0;
for (i = 0; i < 8; i++) {
if (name[i] == ' ')
@@ -332,7 +329,7 @@ static int bad_name(DOS_FILE * file)
return 0;
}
-static void lfn_remove(loff_t from, loff_t to)
+static void lfn_remove(off_t from, off_t to)
{
DIR_ENT empty;
@@ -356,7 +353,7 @@ static void drop_file(DOS_FS * fs, DOS_FILE * file)
if (file->lfn)
lfn_remove(file->lfn_offset, file->offset);
for (cluster = FSTART(file, fs); cluster > 0 && cluster <
- fs->clusters + 2; cluster = next_cluster(fs, cluster))
+ fs->data_clusters + 2; cluster = next_cluster(fs, cluster))
set_owner(fs, cluster, NULL);
--n_files;
}
@@ -392,8 +389,7 @@ static void auto_rename(DOS_FILE * file)
char num[8];
sprintf(num, "%07lu", (unsigned long)number);
memcpy(file->dir_ent.name, "FSCK", 4);
- memcpy(file->dir_ent.name + 4, num, 4);
- memcpy(file->dir_ent.ext, num + 4, 3);
+ memcpy(file->dir_ent.name + 4, num, 7);
for (walk = first; walk; walk = walk->next)
if (walk != file
&& !strncmp((const char *)walk->dir_ent.name,
@@ -406,7 +402,7 @@ static void auto_rename(DOS_FILE * file)
file->dir_ent.lcase &= ~FAT_NO_83NAME;
/* reset the attributes, only keep DIR and VOLUME */
file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME);
- fs_write(file->offset, MSDOS_NAME + 2, file->dir_ent.name);
+ fs_write(file->offset, MSDOS_NAME + 2, &file->dir_ent);
} else {
fs_write(file->offset, MSDOS_NAME, file->dir_ent.name);
}
@@ -449,7 +445,7 @@ static void rename_file(DOS_FILE * file)
file->dir_ent.lcase &= ~FAT_NO_83NAME;
/* reset the attributes, only keep DIR and VOLUME */
file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME);
- fs_write(file->offset, MSDOS_NAME + 2, file->dir_ent.name);
+ fs_write(file->offset, MSDOS_NAME + 2, &file->dir_ent);
} else {
fs_write(file->offset, MSDOS_NAME, file->dir_ent.name);
}
@@ -552,13 +548,15 @@ static int check_file(DOS_FS * fs, DOS_FILE * file)
die("Bad FAT32 root directory! (bad start cluster 1)\n");
MODIFY_START(file, 0, fs);
}
- if (FSTART(file, fs) >= fs->clusters + 2) {
+ if (FSTART(file, fs) >= fs->data_clusters + 2) {
printf
("%s\n Start cluster beyond limit (%lu > %lu). Truncating file.\n",
- path_name(file), (unsigned long)FSTART(file, fs), (unsigned long)(fs->clusters + 1));
+ path_name(file), (unsigned long)FSTART(file, fs),
+ (unsigned long)(fs->data_clusters + 1));
if (!file->offset)
die("Bad FAT32 root directory! (start cluster beyond limit: %lu > %lu)\n",
- (unsigned long)FSTART(file, fs), (unsigned long)(fs->clusters + 1));
+ (unsigned long)FSTART(file, fs),
+ (unsigned long)(fs->data_clusters + 1));
MODIFY_START(file, 0, fs);
}
clusters = prev = 0;
@@ -581,10 +579,10 @@ static int check_file(DOS_FS * fs, DOS_FILE * file)
if (!(file->dir_ent.attr & ATTR_DIR) && le32toh(file->dir_ent.size) <=
(uint64_t)clusters * fs->cluster_size) {
printf
- ("%s\n File size is %u bytes, cluster chain length is > %lu "
+ ("%s\n File size is %u bytes, cluster chain length is > %llu "
"bytes.\n Truncating file to %u bytes.\n", path_name(file),
le32toh(file->dir_ent.size),
- (uint64_t)clusters * fs->cluster_size,
+ (unsigned long long)clusters * fs->cluster_size,
le32toh(file->dir_ent.size));
truncate_file(fs, file, clusters);
break;
@@ -844,7 +842,7 @@ static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test)
uint32_t walk, prev, clusters, next_clu;
prev = clusters = 0;
- for (walk = FSTART(file, fs); walk > 1 && walk < fs->clusters + 2;
+ for (walk = FSTART(file, fs); walk > 1 && walk < fs->data_clusters + 2;
walk = next_clu) {
next_clu = next_cluster(fs, walk);
@@ -885,7 +883,7 @@ static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test)
set_owner(fs, walk, file);
}
/* Revert ownership (for now) */
- for (walk = FSTART(file, fs); walk > 1 && walk < fs->clusters + 2;
+ for (walk = FSTART(file, fs); walk > 1 && walk < fs->data_clusters + 2;
walk = next_cluster(fs, walk))
if (bad_cluster(fs, walk))
break;
@@ -905,7 +903,7 @@ static void undelete(DOS_FS * fs, DOS_FILE * file)
walk = FSTART(file, fs);
- while (left && (walk >= 2) && (walk < fs->clusters + 2)) {
+ while (left && (walk >= 2) && (walk < fs->data_clusters + 2)) {
FAT_ENTRY curEntry;
get_fat(&curEntry, fs->fat, walk, fs);
@@ -948,7 +946,7 @@ static void new_dir(void)
* @param cp
*/
static void add_file(DOS_FS * fs, DOS_FILE *** chain, DOS_FILE * parent,
- loff_t offset, FDSC ** cp)
+ off_t offset, FDSC ** cp)
{
DOS_FILE *new;
DIR_ENT de;
diff --git a/src/check.h b/src/check.h
index fcb6bea..933bbf4 100644
--- a/src/check.h
+++ b/src/check.h
@@ -23,7 +23,7 @@
#ifndef _CHECK_H
#define _CHECK_H
-loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern);
+off_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern);
/* Allocate a free slot in the root directory for a new file. The file name is
constructed after 'pattern', which must include a %d type format for printf
diff --git a/src/device_info.c b/src/device_info.c
new file mode 100644
index 0000000..f5d11ac
--- /dev/null
+++ b/src/device_info.c
@@ -0,0 +1,332 @@
+/* device_info.c - Collect device information for mkfs.fat
+
+ Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
+
+ 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 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 <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#ifdef HAVE_UDEV
+#include <libudev.h>
+#endif
+
+#if HAVE_DECL_GETMNTENT
+#include <paths.h>
+#include <mntent.h>
+#endif
+
+#if HAVE_DECL_GETMNTINFO
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#endif
+
+#include <unistd.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "blkdev.h"
+#include "device_info.h"
+
+
+static const struct device_info device_info_clueless = {
+ .type = TYPE_UNKNOWN,
+ .partition = -1,
+ .has_children = -1,
+ .geom_heads = -1,
+ .geom_sectors = -1,
+ .geom_start = -1,
+ .sector_size = -1,
+ .size = -1,
+};
+
+
+int device_info_verbose;
+
+
+static void get_block_device_size(struct device_info *info, int fd)
+{
+ unsigned long long bytes;
+
+ if (!blkdev_get_size(fd, &bytes) && bytes != 0)
+ info->size = bytes;
+}
+
+
+static void get_block_geometry(struct device_info *info, int fd)
+{
+ unsigned int heads, sectors, start;
+
+ if (!blkdev_get_geometry(fd, &heads, &sectors)
+ && heads && sectors) {
+ info->geom_heads = heads;
+ info->geom_sectors = sectors;
+ }
+
+ if (!blkdev_get_start(fd, &start))
+ info->geom_start = start;
+}
+
+
+static void get_sector_size(struct device_info *info, int fd)
+{
+ int size;
+
+ if (!blkdev_get_sector_size(fd, &size))
+ info->sector_size = size;
+}
+
+
+static int udev_fill_info(struct device_info *info, struct stat *stat);
+
+#ifdef HAVE_UDEV
+static int udev_fill_info(struct device_info *info, struct stat *stat)
+{
+ struct udev *ctx;
+ struct udev_device *dev, *parent;
+ struct udev_enumerate *uenum;
+ const char *attr;
+ char holders_path[PATH_MAX + 1];
+ DIR *holders_dir;
+ struct dirent *dir_entry;
+ unsigned long number;
+ char *endptr;
+
+ if (device_info_verbose >= 3)
+ printf("udev_fill_info()\n");
+
+ ctx = udev_new();
+ if (!ctx) {
+ if (device_info_verbose)
+ printf("no udev library context\n");
+ return -1;
+ }
+
+ dev = udev_device_new_from_devnum(ctx, 'b', stat->st_rdev);
+ if (!dev) {
+ if (device_info_verbose)
+ printf("no udev context\n");
+ udev_unref(ctx);
+ return -1;
+ }
+
+ /*
+ * first, look for for dependent devices (partitions or virtual mappings on
+ * this device)
+ */
+ if (device_info_verbose >= 3)
+ printf("looking for dependent devices\n");
+
+ uenum = udev_enumerate_new(ctx);
+ if (uenum) {
+ struct udev_list_entry *entry;
+ if (udev_enumerate_add_match_parent(uenum, dev) >= 0 &&
+ udev_enumerate_scan_devices(uenum) >= 0) {
+ entry = udev_enumerate_get_list_entry(uenum);
+ if (entry) {
+ /*
+ * the list of children includes the parent device, so make
+ * sure that has_children is -1 to end up with the correct
+ * count
+ */
+ info->has_children = -1;
+
+ while (entry) {
+ if (device_info_verbose >= 2)
+ printf("child-or-self: %s\n", udev_list_entry_get_name(entry));
+ entry = udev_list_entry_get_next(entry);
+ info->has_children++;
+ }
+ } else
+ info->has_children = 0;
+ }
+ udev_enumerate_unref(uenum);
+ }
+
+ /* see if the holders directory in sysfs exists and has entries */
+ if (device_info_verbose >= 2)
+ printf("syspath: %s\n", udev_device_get_syspath(dev));
+ if (info->has_children < 1 || device_info_verbose >= 3) {
+ snprintf(holders_path, PATH_MAX, "%s/holders",
+ udev_device_get_syspath(dev));
+ holders_path[PATH_MAX] = 0;
+
+ if (info->has_children < 0)
+ info->has_children = 0;
+
+ holders_dir = opendir(holders_path);
+ if (holders_dir) {
+ dir_entry = readdir(holders_dir);
+ while (dir_entry) {
+ if (dir_entry->d_reclen && dir_entry->d_name[0] != '.') {
+ if (device_info_verbose >= 2)
+ printf("holder: %s\n", dir_entry->d_name);
+
+ info->has_children++;
+
+ /* look up and print every holder when very verbose */
+ if (device_info_verbose < 3)
+ break;
+ }
+ dir_entry = readdir(holders_dir);
+ }
+
+ closedir(holders_dir);
+ }
+ }
+
+ /*
+ * block devices on real hardware have either other block devices
+ * (in the case of partitions) or the actual hardware as parent
+ */
+ parent = udev_device_get_parent(dev);
+
+ if (!parent) {
+ if (device_info_verbose >= 3)
+ printf("no parent found, therefore virtual device\n");
+ info->type = TYPE_VIRTUAL;
+ info->partition = 0;
+ udev_device_unref(dev);
+ return 0;
+ }
+
+ attr = udev_device_get_sysattr_value(dev, "removable");
+ if (device_info_verbose >= 3) {
+ if (attr)
+ printf("attribute \"removable\" is \"%s\"\n", attr);
+ else
+ printf("attribute \"removable\" not found\n");
+ }
+ if (attr && !strcmp(attr, "1"))
+ info->type = TYPE_REMOVABLE;
+ else
+ info->type = TYPE_FIXED;
+
+ attr = udev_device_get_sysattr_value(dev, "partition");
+ if (attr) {
+ if (device_info_verbose >= 3)
+ printf("attribute \"partition\" is \"%s\"\n", attr);
+
+ number = strtoul(attr, &endptr, 10);
+ if (!*endptr)
+ info->partition = number;
+ } else {
+ printf("attribute \"partition\" not found\n");
+ if (info->type != TYPE_VIRTUAL && parent) {
+ /* partitions have other block devices as parent */
+ attr = udev_device_get_subsystem(parent);
+ if (attr) {
+ if (device_info_verbose >= 3)
+ printf("parent subsystem is \"%s\"\n", attr);
+
+ if (!strcmp(attr, "block"))
+ /* we don't know the partition number, use 1 */
+ info->partition = 1;
+ else
+ info->partition = 0;
+ }
+ }
+ }
+
+ udev_device_unref(dev);
+ udev_unref(ctx);
+ return 0;
+}
+#else /* HAVE_UDEV */
+static int udev_fill_info(struct device_info *info, struct stat *stat)
+{
+ /* prevent "unused parameter" warning */
+ (void)stat;
+ (void)info;
+
+ return -1;
+}
+#endif
+
+
+int get_device_info(int fd, struct device_info *info)
+{
+ struct stat stat;
+ int ret;
+
+ *info = device_info_clueless;
+
+ ret = fstat(fd, &stat);
+ if (ret < 0) {
+ perror("fstat on target failed");
+ return -1;
+ }
+
+ if (S_ISREG(stat.st_mode)) {
+ /* there is nothing more to discover for an image file */
+ info->type = TYPE_FILE;
+ info->partition = 0;
+ info->size = stat.st_size;
+ return 0;
+ }
+
+ if (!S_ISBLK(stat.st_mode)) {
+ /* neither regular file nor block device? not usable */
+ info->type = TYPE_BAD;
+ return 0;
+ }
+
+ get_block_device_size(info, fd);
+ get_block_geometry(info, fd);
+ get_sector_size(info, fd);
+
+ /* use udev information if available */
+ udev_fill_info(info, &stat);
+
+ return 0;
+}
+
+
+int is_device_mounted(const char *path)
+{
+#if HAVE_DECL_GETMNTENT
+ FILE *f;
+ struct mntent *mnt;
+
+ if ((f = setmntent(_PATH_MOUNTED, "r")) == NULL)
+ return 0;
+ while ((mnt = getmntent(f)) != NULL)
+ if (strcmp(path, mnt->mnt_fsname) == 0)
+ return 1;
+ endmntent(f);
+ return 0;
+#endif
+
+#if HAVE_DECL_GETMNTINFO
+ struct statfs *stat;
+ int count, i;
+
+ count = getmntinfo(&stat, 0);
+ for (i = 0; i < count; i++)
+ if (!strcmp(path, stat[i].f_mntfromname))
+ return 1;
+ return 0;
+#endif
+
+ (void)path; /* prevent unused parameter warning */
+ return 0;
+}
diff --git a/src/device_info.h b/src/device_info.h
new file mode 100644
index 0000000..3f4195a
--- /dev/null
+++ b/src/device_info.h
@@ -0,0 +1,56 @@
+#ifndef DEVICE_INFO_H
+#define DEVICE_INFO_H
+
+enum device_type {
+ TYPE_UNKNOWN, /* type could not be determined */
+ TYPE_BAD, /* neither file nor block device */
+ TYPE_FILE, /* image file rather than device */
+ TYPE_VIRTUAL, /* block devices like LVM or RAID volumes */
+ TYPE_REMOVABLE, /* removable disk device */
+ TYPE_FIXED /* fixed disk device */
+};
+
+struct device_info {
+ enum device_type type;
+
+ /*
+ * partition number if detected
+ * 0 = whole disk device (including unpartitioned image file)
+ * -1 = could not be determined
+ */
+ int partition;
+
+ /*
+ * whether partitions or device mapper devices or any other kind of
+ * children use this device
+ * 1 = yes
+ * 0 = no
+ * -1 = could not be determined
+ */
+ int has_children;
+
+ /*
+ * detected geometry, or -1 if unknown
+ */
+ int geom_heads;
+ int geom_sectors;
+ long geom_start;
+
+ /*
+ * detected sector size or -1 if unknown
+ */
+ int sector_size;
+
+ /*
+ * size in bytes, or -1 if unknown
+ */
+ long long size;
+};
+
+
+extern int device_info_verbose;
+
+int get_device_info(int fd, struct device_info *info);
+int is_device_mounted(const char *path);
+
+#endif
diff --git a/src/endian_compat.h b/src/endian_compat.h
new file mode 100644
index 0000000..44168c7
--- /dev/null
+++ b/src/endian_compat.h
@@ -0,0 +1,29 @@
+#ifndef ENDIAN_COMPAT_H
+#define ENDIAN_COMPAT_H
+
+#if defined(HAVE_ENDIAN_H)
+#include <endian.h>
+#elif defined(HAVE_SYS_ENDIAN_H)
+#include <sys/endian.h>
+#elif defined(__APPLE__)
+ #include <libkern/OSByteOrder.h>
+
+ #define htobe16(x) OSSwapHostToBigInt16(x)
+ #define htole16(x) OSSwapHostToLittleInt16(x)
+ #define be16toh(x) OSSwapBigToHostInt16(x)
+ #define le16toh(x) OSSwapLittleToHostInt16(x)
+
+ #define htobe32(x) OSSwapHostToBigInt32(x)
+ #define htole32(x) OSSwapHostToLittleInt32(x)
+ #define be32toh(x) OSSwapBigToHostInt32(x)
+ #define le32toh(x) OSSwapLittleToHostInt32(x)
+
+ #define htobe64(x) OSSwapHostToBigInt64(x)
+ #define htole64(x) OSSwapHostToLittleInt64(x)
+ #define be64toh(x) OSSwapBigToHostInt64(x)
+ #define le64toh(x) OSSwapLittleToHostInt64(x)
+#else
+#error No endian.h available and no fallback code
+#endif
+
+#endif
diff --git a/src/fat.c b/src/fat.c
index 5a92f56..c32c25b 100644
--- a/src/fat.c
+++ b/src/fat.c
@@ -47,6 +47,11 @@ void get_fat(FAT_ENTRY * entry, void *fat, uint32_t cluster, DOS_FS * fs)
{
unsigned char *ptr;
+ if (cluster > fs->data_clusters + 1) {
+ die("Internal error: cluster out of range in get_fat() (%lu > %lu).",
+ (unsigned long)cluster, (unsigned long)(fs->data_clusters + 1));
+ }
+
switch (fs->fat_bits) {
case 12:
ptr = &((unsigned char *)fat)[cluster * 3 / 2];
@@ -94,7 +99,7 @@ void read_fat(DOS_FS * fs)
fs->fat = NULL;
fs->cluster_owner = NULL;
- total_num_clusters = fs->clusters + 2UL;
+ total_num_clusters = fs->data_clusters + 2;
eff_size = (total_num_clusters * fs->fat_bits + 7) / 8ULL;
if (fs->fat_bits != 12)
@@ -155,17 +160,19 @@ void read_fat(DOS_FS * fs)
memset(fs->cluster_owner, 0, (total_num_clusters * sizeof(DOS_FILE *)));
/* Truncate any cluster chains that link to something out of range */
- for (i = 2; i < fs->clusters + 2; i++) {
+ for (i = 2; i < fs->data_clusters + 2; i++) {
FAT_ENTRY curEntry;
get_fat(&curEntry, fs->fat, i, fs);
if (curEntry.value == 1) {
- printf("Cluster %ld out of range (1). Setting to EOF.\n", (long)(i - 2));
+ printf("Cluster %ld out of range (1). Setting to EOF.\n",
+ (long)(i - 2));
set_fat(fs, i, -1);
}
- if (curEntry.value >= fs->clusters + 2 &&
+ if (curEntry.value >= fs->data_clusters + 2 &&
(curEntry.value < FAT_MIN_BAD(fs))) {
printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
- (long)(i - 2), (long)curEntry.value, (long)(fs->clusters + 2 - 1));
+ (long)(i - 2), (long)curEntry.value,
+ (long)(fs->data_clusters + 2 - 1));
set_fat(fs, i, -1);
}
}
@@ -188,12 +195,22 @@ void set_fat(DOS_FS * fs, uint32_t cluster, int32_t new)
{
unsigned char *data = NULL;
int size;
- loff_t offs;
+ off_t offs;
+
+ if (cluster > fs->data_clusters + 1) {
+ die("Internal error: cluster out of range in set_fat() (%lu > %lu).",
+ (unsigned long)cluster, (unsigned long)(fs->data_clusters + 1));
+ }
if (new == -1)
new = FAT_EOF(fs);
else if ((long)new == -2)
new = FAT_BAD(fs);
+ else if (new > fs->data_clusters + 1) {
+ die("Internal error: new cluster out of range in set_fat() (%lu > %lu).",
+ (unsigned long)new, (unsigned long)(fs->data_clusters + 1));
+ }
+
switch (fs->fat_bits) {
case 12:
data = fs->fat + cluster * 3 / 2;
@@ -205,10 +222,12 @@ void set_fat(DOS_FS * fs, uint32_t cluster, int32_t new)
data[1] = new >> 4;
} else {
FAT_ENTRY subseqEntry;
- get_fat(&subseqEntry, fs->fat, cluster + 1, fs);
+ if (cluster != fs->data_clusters + 1)
+ get_fat(&subseqEntry, fs->fat, cluster + 1, fs);
+ else
+ subseqEntry.value = 0;
data[0] = new & 0xff;
- data[1] = (new >> 8) | (cluster == fs->clusters - 1 ? 0 :
- (0xff & subseqEntry.value) << 4);
+ data[1] = (new >> 8) | ((0xff & subseqEntry.value) << 4);
}
size = 2;
break;
@@ -272,10 +291,9 @@ uint32_t next_cluster(DOS_FS * fs, uint32_t cluster)
return FAT_IS_EOF(fs, value) ? -1 : value;
}
-loff_t cluster_start(DOS_FS * fs, uint32_t cluster)
+off_t cluster_start(DOS_FS * fs, uint32_t cluster)
{
- return fs->data_start + ((loff_t) cluster -
- 2) * (uint64_t)fs->cluster_size;
+ return fs->data_start + ((off_t)cluster - 2) * (uint64_t)fs->cluster_size;
}
/**
@@ -312,7 +330,7 @@ void fix_bad(DOS_FS * fs)
if (verbose)
printf("Checking for bad clusters.\n");
- for (i = 2; i < fs->clusters + 2; i++) {
+ for (i = 2; i < fs->data_clusters + 2; i++) {
FAT_ENTRY curEntry;
get_fat(&curEntry, fs->fat, i, fs);
@@ -332,7 +350,7 @@ void reclaim_free(DOS_FS * fs)
if (verbose)
printf("Checking for unused clusters.\n");
reclaimed = 0;
- for (i = 2; i < fs->clusters + 2; i++) {
+ for (i = 2; i < fs->data_clusters + 2; i++) {
FAT_ENTRY curEntry;
get_fat(&curEntry, fs->fat, i, fs);
@@ -367,7 +385,7 @@ static void tag_free(DOS_FS * fs, DOS_FILE * owner, uint32_t *num_refs,
if (start_cluster == 0)
start_cluster = 2;
- for (i = start_cluster; i < fs->clusters + 2; i++) {
+ for (i = start_cluster; i < fs->data_clusters + 2; i++) {
FAT_ENTRY curEntry;
get_fat(&curEntry, fs->fat, i, fs);
@@ -418,7 +436,7 @@ void reclaim_file(DOS_FS * fs)
if (verbose)
printf("Reclaiming unconnected clusters.\n");
- total_num_clusters = fs->clusters + 2UL;
+ total_num_clusters = fs->data_clusters + 2;
num_refs = alloc(total_num_clusters * sizeof(uint32_t));
memset(num_refs, 0, (total_num_clusters * sizeof(uint32_t)));
@@ -431,7 +449,7 @@ void reclaim_file(DOS_FS * fs)
get_fat(&curEntry, fs->fat, i, fs);
next = curEntry.value;
- if (!get_owner(fs, i) && next && next < fs->clusters + 2) {
+ if (!get_owner(fs, i) && next && next < fs->data_clusters + 2) {
/* Cluster is linked, but not owned (orphan) */
FAT_ENTRY nextEntry;
get_fat(&nextEntry, fs->fat, next, fs);
@@ -483,7 +501,7 @@ void reclaim_file(DOS_FS * fs)
/* If this cluster is the head of an orphan chain... */
if (get_owner(fs, i) == &orphan && !num_refs[i]) {
DIR_ENT de;
- loff_t offset;
+ off_t offset;
files++;
offset = alloc_rootdir_entry(fs, &de, "FSCK%04dREC");
de.start = htole16(i & 0xffff);
@@ -511,7 +529,7 @@ uint32_t update_free(DOS_FS * fs)
uint32_t free = 0;
int do_set = 0;
- for (i = 2; i < fs->clusters + 2; i++) {
+ for (i = 2; i < fs->data_clusters + 2; i++) {
FAT_ENTRY curEntry;
get_fat(&curEntry, fs->fat, i, fs);
diff --git a/src/fat.h b/src/fat.h
index b50ed4a..5c77634 100644
--- a/src/fat.h
+++ b/src/fat.h
@@ -49,7 +49,7 @@ uint32_t next_cluster(DOS_FS * fs, uint32_t cluster);
last cluster of the respective cluster chain. CLUSTER must not be a bad
cluster. */
-loff_t cluster_start(DOS_FS * fs, uint32_t cluster);
+off_t cluster_start(DOS_FS * fs, uint32_t cluster);
/* Returns the byte offset of CLUSTER, relative to the respective device. */
diff --git a/src/fatlabel.c b/src/fatlabel.c
index 1484ba5..9268ddb 100644
--- a/src/fatlabel.c
+++ b/src/fatlabel.c
@@ -4,6 +4,7 @@
Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Copyright (C) 2007 Red Hat, Inc.
Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
+ Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
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
@@ -92,7 +93,7 @@ int main(int argc, char *argv[])
char *device = NULL;
char label[12] = { 0 };
- loff_t offset;
+ off_t offset;
DIR_ENT de;
check_atari();
@@ -134,7 +135,7 @@ int main(int argc, char *argv[])
if (offset == 0)
fprintf(stdout, "%s\n", fs.label);
else
- fprintf(stdout, "%.8s%.3s\n", de.name, de.ext);
+ fprintf(stdout, "%.8s%.3s\n", de.name, de.name + 8);
exit(0);
}
diff --git a/src/fsck.fat.c b/src/fsck.fat.c
index f786a93..c244aba 100644
--- a/src/fsck.fat.c
+++ b/src/fsck.fat.c
@@ -217,7 +217,8 @@ exit:
if (!boot_only)
printf("%s: %u files, %lu/%lu clusters\n", argv[optind],
- n_files, (unsigned long)fs.clusters - free_clusters, (unsigned long)fs.clusters);
+ n_files, (unsigned long)fs.data_clusters - free_clusters,
+ (unsigned long)fs.data_clusters);
return fs_close(rw) ? 1 : 0;
}
diff --git a/src/fsck.fat.h b/src/fsck.fat.h
index e5f6178..168049e 100644
--- a/src/fsck.fat.h
+++ b/src/fsck.fat.h
@@ -3,6 +3,7 @@
Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
+ Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
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
@@ -27,10 +28,11 @@
#ifndef _DOSFSCK_H
#define _DOSFSCK_H
+#include <sys/types.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
-#include <endian.h>
+#include "endian_compat.h"
#include "msdos_fs.h"
@@ -120,7 +122,7 @@ struct info_sector {
};
typedef struct {
- uint8_t name[8], ext[3]; /* name and extension */
+ uint8_t name[MSDOS_NAME]; /* name including extension */
uint8_t attr; /* attribute bits */
uint8_t lcase; /* Case for base and extension */
uint8_t ctime_ms; /* Creation time, milliseconds */
@@ -135,8 +137,8 @@ typedef struct {
typedef struct _dos_file {
DIR_ENT dir_ent;
char *lfn;
- loff_t offset;
- loff_t lfn_offset;
+ off_t offset;
+ off_t lfn_offset;
struct _dos_file *parent; /* parent directory */
struct _dos_file *next; /* next entry */
struct _dos_file *first; /* first entry (directory only) */
@@ -149,19 +151,19 @@ typedef struct {
typedef struct {
int nfats;
- loff_t fat_start;
- unsigned int fat_size; /* unit is bytes */
+ off_t fat_start;
+ off_t fat_size; /* unit is bytes */
unsigned int fat_bits; /* size of a FAT entry */
unsigned int eff_fat_bits; /* # of used bits in a FAT entry */
uint32_t root_cluster; /* 0 for old-style root dir */
- loff_t root_start;
+ off_t root_start;
unsigned int root_entries;
- loff_t data_start;
+ off_t data_start;
unsigned int cluster_size;
- uint32_t clusters;
- loff_t fsinfo_start; /* 0 if not present */
+ uint32_t data_clusters; /* not including two reserved cluster numbers */
+ off_t fsinfo_start; /* 0 if not present */
long free_clusters;
- loff_t backupboot_start; /* 0 if not present */
+ off_t backupboot_start; /* 0 if not present */
unsigned char *fat;
DOS_FILE **cluster_owner;
char *label;
diff --git a/src/io.c b/src/io.c
index 450432c..b2c559b 100644
--- a/src/io.c
+++ b/src/io.c
@@ -3,6 +3,7 @@
Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
+ Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
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
@@ -35,11 +36,10 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
-#include <linux/fd.h>
#include "fsck.fat.h"
#include "common.h"
@@ -47,7 +47,7 @@
typedef struct _change {
void *data;
- loff_t pos;
+ off_t pos;
int size;
struct _change *next;
} CHANGE;
@@ -55,57 +55,15 @@ typedef struct _change {
static CHANGE *changes, *last;
static int fd, did_change = 0;
-unsigned device_no;
-
-#ifdef __DJGPP__
-#include "volume.h" /* DOS lowlevel disk access functions */
-loff_t llseek(int fd, loff_t offset, int whence)
-{
- if ((whence != SEEK_SET) || (fd == 4711))
- return -1; /* only those supported */
- return VolumeSeek(offset);
-}
-
-#define open OpenVolume
-#define close CloseVolume
-#define read(a,b,c) ReadVolume(b,c)
-#define write(a,b,c) WriteVolume(b,c)
-#else
-loff_t llseek(int fd, loff_t offset, int whence)
-{
- return (loff_t) lseek64(fd, (off64_t) offset, whence);
-}
-#endif
void fs_open(char *path, int rw)
{
- struct stat stbuf;
-
if ((fd = open(path, rw ? O_RDWR : O_RDONLY)) < 0) {
perror("open");
exit(6);
}
changes = last = NULL;
did_change = 0;
-
-#ifndef _DJGPP_
- if (fstat(fd, &stbuf) < 0)
- pdie("fstat %s", path);
- device_no = S_ISBLK(stbuf.st_mode) ? (stbuf.st_rdev >> 8) & 0xff : 0;
-#else
- if (IsWorkingOnImageFile()) {
- if (fstat(GetVolumeHandle(), &stbuf) < 0)
- pdie("fstat image %s", path);
- device_no = 0;
- } else {
- /* return 2 for floppy, 1 for ramdisk, 7 for loopback */
- /* used by boot.c in Atari mode: floppy always FAT12, */
- /* loopback / ramdisk only FAT12 if usual floppy size, */
- /* harddisk always FAT16 on Atari... */
- device_no = (GetVolumeHandle() < 2) ? 2 : 1;
- /* telling "floppy" for A:/B:, "ramdisk" for the rest */
- }
-#endif
}
/**
@@ -117,12 +75,12 @@ void fs_open(char *path, int rw)
* @param[in] size Number of bytes to read
* @param[out] data Where to put the data read
*/
-void fs_read(loff_t pos, int size, void *data)
+void fs_read(off_t pos, int size, void *data)
{
CHANGE *walk;
int got;
- if (llseek(fd, pos, 0) != pos)
+ if (lseek(fd, pos, 0) != pos)
pdie("Seek to %lld", pos);
if ((got = read(fd, data, size)) < 0)
pdie("Read %d bytes at %lld", size, pos);
@@ -131,12 +89,8 @@ void fs_read(loff_t pos, int size, void *data)
for (walk = changes; walk; walk = walk->next) {
if (walk->pos < pos + size && walk->pos + walk->size > pos) {
if (walk->pos < pos)
- memcpy(data, (char *)walk->data + pos - walk->pos, min(size,
- walk->
- size -
- pos +
- walk->
- pos));
+ memcpy(data, (char *)walk->data + pos - walk->pos,
+ min(size, walk->size - pos + walk->pos));
else
memcpy((char *)data + walk->pos - pos, walk->data,
min(walk->size, size + pos - walk->pos));
@@ -144,12 +98,12 @@ void fs_read(loff_t pos, int size, void *data)
}
}
-int fs_test(loff_t pos, int size)
+int fs_test(off_t pos, int size)
{
void *scratch;
int okay;
- if (llseek(fd, pos, 0) != pos)
+ if (lseek(fd, pos, 0) != pos)
pdie("Seek to %lld", pos);
scratch = alloc(size);
okay = read(fd, scratch, size) == size;
@@ -157,14 +111,14 @@ int fs_test(loff_t pos, int size)
return okay;
}
-void fs_write(loff_t pos, int size, void *data)
+void fs_write(off_t pos, int size, void *data)
{
CHANGE *new;
int did;
if (write_immed) {
did_change = 1;
- if (llseek(fd, pos, 0) != pos)
+ if (lseek(fd, pos, 0) != pos)
pdie("Seek to %lld", pos);
if ((did = write(fd, data, size)) == size)
return;
@@ -191,7 +145,7 @@ static void fs_flush(void)
while (changes) {
this = changes;
changes = changes->next;
- if (llseek(fd, this->pos, 0) != this->pos)
+ if (lseek(fd, this->pos, 0) != this->pos)
fprintf(stderr,
"Seek to %lld failed: %s\n Did not write %d bytes.\n",
(long long)this->pos, strerror(errno), this->size);
diff --git a/src/io.h b/src/io.h
index d23d07e..4ce032f 100644
--- a/src/io.h
+++ b/src/io.h
@@ -27,28 +27,24 @@
#ifndef _IO_H
#define _IO_H
-#include <fcntl.h> /* for loff_t */
-
-loff_t llseek(int fd, loff_t offset, int whence);
-
-/* lseek() analogue for large offsets. */
+#include <fcntl.h> /* for off_t */
void fs_open(char *path, int rw);
/* Opens the filesystem PATH. If RW is zero, the filesystem is opened
read-only, otherwise, it is opened read-write. */
-void fs_read(loff_t pos, int size, void *data);
+void fs_read(off_t pos, int size, void *data);
/* Reads SIZE bytes starting at POS into DATA. Performs all applicable
changes. */
-int fs_test(loff_t pos, int size);
+int fs_test(off_t pos, int size);
/* Returns a non-zero integer if SIZE bytes starting at POS can be read without
errors. Otherwise, it returns zero. */
-void fs_write(loff_t pos, int size, void *data);
+void fs_write(off_t pos, int size, void *data);
/* If write_immed is non-zero, SIZE bytes are written from DATA to the disk,
starting at POS. If write_immed is zero, the change is added to a list in
@@ -64,8 +60,4 @@ int fs_changed(void);
/* Determines whether the filesystem has changed. See fs_close. */
-extern unsigned device_no;
-
-/* Major number of device (0 if file) and size (in 512 byte sectors) */
-
#endif
diff --git a/src/lfn.c b/src/lfn.c
index 2601172..b33e125 100644
--- a/src/lfn.c
+++ b/src/lfn.c
@@ -2,6 +2,7 @@
Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
+ Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
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
@@ -53,7 +54,7 @@ typedef struct {
unsigned char *lfn_unicode = NULL;
unsigned char lfn_checksum;
int lfn_slot = -1;
-loff_t *lfn_offsets = NULL;
+off_t *lfn_offsets = NULL;
int lfn_parts = 0;
static unsigned char fat_uni2esc[64] = {
@@ -171,7 +172,7 @@ static void clear_lfn_slots(int start, int end)
}
}
-void lfn_fix_checksum(loff_t from, loff_t to, const char *short_name)
+void lfn_fix_checksum(off_t from, off_t to, const char *short_name)
{
int i;
uint8_t sum;
@@ -196,7 +197,7 @@ void lfn_reset(void)
/* This function is only called with de->attr == VFAT_LN_ATTR. It stores part
* of the long name. */
-void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
+void lfn_add_slot(DIR_ENT * de, off_t dir_offset)
{
LFN_ENT *lfn = (LFN_ENT *) de;
int slot = lfn->id & LFN_ID_SLOTMASK;
@@ -254,7 +255,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
lfn_slot = slot;
lfn_checksum = lfn->alias_checksum;
lfn_unicode = alloc((lfn_slot * CHARS_PER_LFN + 1) * 2);
- lfn_offsets = alloc(lfn_slot * sizeof(loff_t));
+ lfn_offsets = alloc(lfn_slot * sizeof(off_t));
lfn_parts = 0;
} else if (lfn_slot == -1 && slot != 0) {
/* No LFN in progress, but slot found; start bit missing */
@@ -265,6 +266,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
printf("Long filename fragment \"%s\" found outside a LFN "
"sequence.\n (Maybe the start bit is missing on the "
"last fragment)\n", part);
+ free(part);
if (interactive) {
printf("1: Delete fragment\n2: Leave it as it is.\n"
"3: Set start bit\n");
@@ -273,7 +275,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
switch (interactive ? get_key("123", "?") : '2') {
case '1':
if (!lfn_offsets)
- lfn_offsets = alloc(sizeof(loff_t));
+ lfn_offsets = alloc(sizeof(off_t));
lfn_offsets[0] = dir_offset;
clear_lfn_slots(0, 0);
lfn_reset();
@@ -288,7 +290,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
lfn_slot = slot;
lfn_checksum = lfn->alias_checksum;
lfn_unicode = alloc((lfn_slot * CHARS_PER_LFN + 1) * 2);
- lfn_offsets = alloc(lfn_slot * sizeof(loff_t));
+ lfn_offsets = alloc(lfn_slot * sizeof(off_t));
lfn_parts = 0;
break;
}
@@ -320,7 +322,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
switch (interactive ? get_key(can_fix ? "123" : "12", "?") : '2') {
case '1':
if (!lfn_offsets) {
- lfn_offsets = alloc(sizeof(loff_t));
+ lfn_offsets = alloc(sizeof(off_t));
lfn_parts = 0;
}
lfn_offsets[lfn_parts++] = dir_offset;
@@ -407,7 +409,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
/* This function is always called when de->attr != VFAT_LN_ATTR is found, to
* retrieve the previously constructed LFN. */
-char *lfn_get(DIR_ENT * de, loff_t * lfn_offset)
+char *lfn_get(DIR_ENT * de, off_t * lfn_offset)
{
char *lfn;
uint8_t sum;
@@ -464,10 +466,8 @@ char *lfn_get(DIR_ENT * de, loff_t * lfn_offset)
}
}
- for (sum = 0, i = 0; i < 8; i++)
+ for (sum = 0, i = 0; i < MSDOS_NAME; i++)
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + de->name[i];
- for (i = 0; i < 3; i++)
- sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + de->ext[i];
if (sum != lfn_checksum) {
/* checksum doesn't match, long name doesn't apply to this alias */
/* Causes: 1) alias renamed */
@@ -517,6 +517,7 @@ void lfn_check_orphaned(void)
long_name = CNV_PARTS_SO_FAR();
printf("Orphaned long file name part \"%s\"\n", long_name);
+ free(long_name);
if (interactive)
printf("1: Delete.\n2: Leave it.\n");
else
diff --git a/src/lfn.h b/src/lfn.h
index e5c3991..fc38ce7 100644
--- a/src/lfn.h
+++ b/src/lfn.h
@@ -26,14 +26,14 @@
void lfn_reset(void);
/* Reset the state of the LFN parser. */
-void lfn_add_slot(DIR_ENT * de, loff_t dir_offset);
+void lfn_add_slot(DIR_ENT * de, off_t dir_offset);
/* Process a dir slot that is a VFAT LFN entry. */
-char *lfn_get(DIR_ENT * de, loff_t * lfn_offset);
+char *lfn_get(DIR_ENT * de, off_t * lfn_offset);
/* Retrieve the long name for the proper dir entry. */
void lfn_check_orphaned(void);
-void lfn_fix_checksum(loff_t from, loff_t to, const char *short_name);
+void lfn_fix_checksum(off_t from, off_t to, const char *short_name);
#endif
diff --git a/src/mkfs.fat.c b/src/mkfs.fat.c
index b38d116..8a320fd 100644
--- a/src/mkfs.fat.c
+++ b/src/mkfs.fat.c
@@ -6,6 +6,7 @@
Copyright (C) 1998 H. Peter Anvin <hpa@zytor.com>
Copyright (C) 1998-2005 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
+ Copyright (C) 2015-2016 Andreas Bombe <aeb@debian.org>
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
@@ -47,17 +48,11 @@
#include "version.h"
#include <fcntl.h>
-#include <linux/hdreg.h>
-#include <sys/mount.h>
-#include <linux/fs.h>
-#include <linux/fd.h>
-#include <endian.h>
-#include <mntent.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
-#include <sys/ioctl.h>
+#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
@@ -65,14 +60,12 @@
#include <errno.h>
#include <ctype.h>
#include <stdint.h>
-#include <endian.h>
#include <getopt.h>
+#include "endian_compat.h"
#include "msdos_fs.h"
+#include "device_info.h"
-/* In earlier versions, an own llseek() was used, but glibc lseek() is
- * sufficient (or even better :) for 64 bit offsets in the meantime */
-#define llseek lseek
/* Constant definitions */
@@ -80,6 +73,7 @@
#define FALSE 0
#define TEST_BUFFER_BLOCKS 16
+#define BLOCK_SIZE 1024
#define HARD_SECTOR_SIZE 512
#define SECTORS_PER_BLOCK ( BLOCK_SIZE / HARD_SECTOR_SIZE )
@@ -247,9 +241,11 @@ static int start_data_sector; /* Sector number for the start of the data area */
static int start_data_block; /* Block number for the start of the data area */
static unsigned char *fat; /* File allocation table */
static unsigned alloced_fat_length; /* # of FAT sectors we can keep in memory */
+static unsigned fat_entries; /* total entries in FAT table (including reserved) */
static unsigned char *info_sector; /* FAT32 info sector */
static struct msdos_dir_entry *root_dir; /* Root directory */
static int size_root_dir; /* Size of the root directory in bytes */
+static uint32_t num_sectors; /* Total number of sectors in device */
static int sectors_per_cluster = 0; /* Number of sectors per disk cluster */
static int root_dir_entries = 0; /* Number of root directory entries */
static char *blank_sector; /* Blank sector - all zeros */
@@ -274,10 +270,8 @@ static long do_check(char *buffer, int try, off_t current_block);
static void alarm_intr(int alnum);
static void check_blocks(void);
static void get_list_blocks(char *filename);
-static int valid_offset(int fd, loff_t offset);
-static uint64_t count_blocks(char *filename, int *remainder);
static void check_mount(char *device_name);
-static void establish_params(int device_num, int size);
+static void establish_params(struct device_info *info);
static void setup_tables(void);
static void write_tables(void);
@@ -295,6 +289,10 @@ static void fatal_error(const char *fmt_string)
static void mark_FAT_cluster(int cluster, unsigned int value)
{
+
+ if (cluster < 0 || cluster >= fat_entries)
+ die("Internal error: out of range cluster number in mark_FAT_cluster");
+
switch (size_fat) {
case 12:
value &= 0x0fff;
@@ -334,12 +332,11 @@ static void mark_FAT_cluster(int cluster, unsigned int value)
static void mark_FAT_sector(int sector, unsigned int value)
{
- int cluster;
+ int cluster = (sector - start_data_sector) / (int)(bs.cluster_size) /
+ (sector_size / HARD_SECTOR_SIZE) + 2;
- cluster = (sector - start_data_sector) / (int)(bs.cluster_size) /
- (sector_size / HARD_SECTOR_SIZE);
- if (cluster < 0)
- die("Invalid cluster number in mark_FAT_sector: probably bug!");
+ if (sector < start_data_sector || sector >= num_sectors)
+ die("Internal error: out of range sector number in mark_FAT_sector");
mark_FAT_cluster(cluster, value);
}
@@ -350,7 +347,7 @@ static long do_check(char *buffer, int try, off_t current_block)
{
long got;
- if (llseek(dev, current_block * BLOCK_SIZE, SEEK_SET) /* Seek to the correct location */
+ if (lseek(dev, current_block * BLOCK_SIZE, SEEK_SET) /* Seek to the correct location */
!=current_block * BLOCK_SIZE)
die("seek failed during testing for blocks");
@@ -431,270 +428,180 @@ static void get_list_blocks(char *filename)
int i;
FILE *listfile;
long blockno;
+ char *line = NULL;
+ size_t linesize = 0;
+ int lineno = 0;
+ char *end, *check;
listfile = fopen(filename, "r");
if (listfile == (FILE *) NULL)
die("Can't open file of bad blocks");
- while (!feof(listfile)) {
- fscanf(listfile, "%ld\n", &blockno);
- for (i = 0; i < SECTORS_PER_BLOCK; i++) /* Mark all of the sectors in the block as bad */
- mark_sector_bad(blockno * SECTORS_PER_BLOCK + i);
- badblocks++;
- }
- fclose(listfile);
+ while (1) {
+ lineno++;
+ ssize_t length = getline(&line, &linesize, listfile);
+ if (length < 0) {
+ if (errno == 0) /* end of file */
+ break;
- if (badblocks)
- printf("%d bad block%s\n", badblocks, (badblocks > 1) ? "s" : "");
-}
+ perror("getline");
+ die("Error while reading bad blocks file");
+ }
-/* Given a file descriptor and an offset, check whether the offset is a valid offset for the file - return FALSE if it
- isn't valid or TRUE if it is */
+ errno = 0;
+ blockno = strtol(line, &end, 10);
-static int valid_offset(int fd, loff_t offset)
-{
- char ch;
+ if (errno) {
+ fprintf(stderr,
+ "While converting bad block number in line %d: %s\n",
+ lineno, strerror(errno));
+ die("Error in bad blocks file");
+ }
- if (llseek(fd, offset, SEEK_SET) < 0)
- return FALSE;
- if (read(fd, &ch, 1) < 1)
- return FALSE;
- return TRUE;
-}
+ check = end;
+ while (*check) {
+ if (!isspace(*check)) {
+ fprintf(stderr,
+ "Badly formed number in bad blocks file line %d\n",
+ lineno);
+ die("Error in bad blocks file");
+ }
-/* Given a filename, look to see how many blocks of BLOCK_SIZE are present, returning the answer */
+ check++;
+ }
-static uint64_t count_blocks(char *filename, int *remainder)
-{
- loff_t high, low;
- int fd;
+ /* ignore empty or white space only lines */
+ if (end == line)
+ continue;
- if ((fd = open(filename, O_RDONLY)) < 0) {
- perror(filename);
- exit(1);
- }
+ /* Mark all of the sectors in the block as bad */
+ for (i = 0; i < SECTORS_PER_BLOCK; i++) {
+ unsigned long sector = blockno * SECTORS_PER_BLOCK + i;
- /* first try SEEK_END, which should work on most devices nowadays */
- if ((low = llseek(fd, 0, SEEK_END)) <= 0) {
- low = 0;
- for (high = 1; valid_offset(fd, high); high *= 2)
- low = high;
- while (low < high - 1) {
- const loff_t mid = (low + high) / 2;
- if (valid_offset(fd, mid))
- low = mid;
- else
- high = mid;
+ if (sector < start_data_sector) {
+ fprintf(stderr, "Block number %ld is before data area\n",
+ blockno);
+ die("Error in bad blocks file");
+ }
+
+ if (sector >= num_sectors) {
+ fprintf(stderr, "Block number %ld is behind end of filesystem\n",
+ blockno);
+ die("Error in bad blocks file");
+ }
+
+ mark_sector_bad(sector);
}
- ++low;
+ badblocks++;
}
+ fclose(listfile);
+ free(line);
- close(fd);
- *remainder = (low % BLOCK_SIZE) / sector_size;
- return (low / BLOCK_SIZE);
+ if (badblocks)
+ printf("%d bad block%s\n", badblocks, (badblocks > 1) ? "s" : "");
}
/* Check to see if the specified device is currently mounted - abort if it is */
static void check_mount(char *device_name)
{
- FILE *f;
- struct mntent *mnt;
-
- if ((f = setmntent(MOUNTED, "r")) == NULL)
- return;
- while ((mnt = getmntent(f)) != NULL)
- if (strcmp(device_name, mnt->mnt_fsname) == 0)
- die("%s contains a mounted filesystem.");
- endmntent(f);
+ if (is_device_mounted(device_name))
+ die("%s contains a mounted filesystem.");
}
/* Establish the geometry and media parameters for the device */
-static void establish_params(int device_num, int size)
+static void establish_params(struct device_info *info)
{
- long loop_size;
- struct hd_geometry geometry;
- struct floppy_struct param;
+ unsigned int sec_per_track = 63;
+ unsigned int heads = 255;
+ unsigned int media = 0xf8;
+ unsigned int cluster_size = 4; /* starting point for FAT12 and FAT16 */
int def_root_dir_entries = 512;
- if ((0 == device_num) || ((device_num & 0xff00) == 0x0200))
- /* file image or floppy disk */
- {
- if (0 == device_num) {
- param.size = size / 512;
- switch (param.size) {
+ if (info->type != TYPE_FIXED) {
+ /* enter default parameters for floppy disks if the size matches */
+ switch (info->size / 1024) {
+ case 360:
+ sec_per_track = 9;
+ heads = 2;
+ media = 0xfd;
+ cluster_size = 2;
+ def_root_dir_entries = 112;
+ break;
+
case 720:
- param.sect = 9;
- param.head = 2;
+ sec_per_track = 9;
+ heads = 2;
+ media = 0xf9;
+ cluster_size = 2;
+ def_root_dir_entries = 112;
break;
- case 1440:
- param.sect = 9;
- param.head = 2;
+
+ case 1200:
+ sec_per_track = 15;
+ heads = 2;
+ media = 0xf9;
+ cluster_size = (atari_format ? 2 : 1);
+ def_root_dir_entries = 224;
break;
- case 2400:
- param.sect = 15;
- param.head = 2;
+
+ case 1440:
+ sec_per_track = 18;
+ heads = 2;
+ media = 0xf0;
+ cluster_size = (atari_format ? 2 : 1);
+ def_root_dir_entries = 224;
break;
+
case 2880:
- param.sect = 18;
- param.head = 2;
+ sec_per_track = 36;
+ heads = 2;
+ media = 0xf0;
+ cluster_size = 2;
+ def_root_dir_entries = 224;
break;
- case 5760:
- param.sect = 36;
- param.head = 2;
- break;
- default:
- /* fake values */
- param.sect = 32;
- param.head = 64;
- break;
- }
-
- } else { /* is a floppy diskette */
-
- if (ioctl(dev, FDGETPRM, &param)) /* Can we get the diskette geometry? */
- die("unable to get diskette geometry for '%s'");
- }
- bs.secs_track = htole16(param.sect); /* Set up the geometry information */
- bs.heads = htole16(param.head);
- switch (param.size) { /* Set up the media descriptor byte */
- case 720: /* 5.25", 2, 9, 40 - 360K */
- bs.media = (char)0xfd;
- bs.cluster_size = (char)2;
- def_root_dir_entries = 112;
- break;
-
- case 1440: /* 3.5", 2, 9, 80 - 720K */
- bs.media = (char)0xf9;
- bs.cluster_size = (char)2;
- def_root_dir_entries = 112;
- break;
-
- case 2400: /* 5.25", 2, 15, 80 - 1200K */
- bs.media = (char)0xf9;
- bs.cluster_size = (char)(atari_format ? 2 : 1);
- def_root_dir_entries = 224;
- break;
-
- case 5760: /* 3.5", 2, 36, 80 - 2880K */
- bs.media = (char)0xf0;
- bs.cluster_size = (char)2;
- def_root_dir_entries = 224;
- break;
-
- case 2880: /* 3.5", 2, 18, 80 - 1440K */
-floppy_default:
- bs.media = (char)0xf0;
- bs.cluster_size = (char)(atari_format ? 2 : 1);
- def_root_dir_entries = 224;
- break;
-
- default: /* Anything else */
- if (0 == device_num)
- goto def_hd_params;
- else
- goto floppy_default;
}
- } else if ((device_num & 0xff00) == 0x0700) { /* This is a loop device */
- if (ioctl(dev, BLKGETSIZE, &loop_size))
- die("unable to get loop device size");
-
- switch (loop_size) { /* Assuming the loop device -> floppy later */
- case 720: /* 5.25", 2, 9, 40 - 360K */
- bs.secs_track = le16toh(9);
- bs.heads = le16toh(2);
- bs.media = (char)0xfd;
- bs.cluster_size = (char)2;
- def_root_dir_entries = 112;
- break;
-
- case 1440: /* 3.5", 2, 9, 80 - 720K */
- bs.secs_track = le16toh(9);
- bs.heads = le16toh(2);
- bs.media = (char)0xf9;
- bs.cluster_size = (char)2;
- def_root_dir_entries = 112;
- break;
-
- case 2400: /* 5.25", 2, 15, 80 - 1200K */
- bs.secs_track = le16toh(15);
- bs.heads = le16toh(2);
- bs.media = (char)0xf9;
- bs.cluster_size = (char)(atari_format ? 2 : 1);
- def_root_dir_entries = 224;
- break;
-
- case 5760: /* 3.5", 2, 36, 80 - 2880K */
- bs.secs_track = le16toh(36);
- bs.heads = le16toh(2);
- bs.media = (char)0xf0;
- bs.cluster_size = (char)2;
- bs.dir_entries[0] = (char)224;
- bs.dir_entries[1] = (char)0;
- break;
+ }
- case 2880: /* 3.5", 2, 18, 80 - 1440K */
- bs.secs_track = le16toh(18);
- bs.heads = le16toh(2);
- bs.media = (char)0xf0;
- bs.cluster_size = (char)(atari_format ? 2 : 1);
- def_root_dir_entries = 224;
- break;
+ if (!size_fat && info->size >= 512 * 1024 * 1024) {
+ if (verbose)
+ printf("Auto-selecting FAT32 for large filesystem\n");
+ size_fat = 32;
+ }
+ if (size_fat == 32) {
+ /*
+ * For FAT32, try to do the same as M$'s format command
+ * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20):
+ * fs size <= 260M: 0.5k clusters
+ * fs size <= 8G: 4k clusters
+ * fs size <= 16G: 8k clusters
+ * fs size <= 32G: 16k clusters
+ * fs size > 32G: 32k clusters
+ *
+ * This only works correctly for 512 byte sectors!
+ */
+ uint32_t sz_mb = info->size / (1024 * 1024);
+ cluster_size =
+ sz_mb > 32 * 1024 ? 64 : sz_mb > 16 * 1024 ? 32 : sz_mb >
+ 8 * 1024 ? 16 : sz_mb > 260 ? 8 : 1;
+ }
- default: /* Anything else: default hd setup */
- printf("Loop device does not match a floppy size, using "
- "default hd params\n");
- bs.secs_track = htole16(32); /* these are fake values... */
- bs.heads = htole16(64);
- goto def_hd_params;
- }
- } else
- /* Must be a hard disk then! */
- {
- /* Can we get the drive geometry? (Note I'm not too sure about */
- /* whether to use HDIO_GETGEO or HDIO_REQ) */
- if (ioctl(dev, HDIO_GETGEO, &geometry) || geometry.sectors == 0
- || geometry.heads == 0) {
- printf("unable to get drive geometry, using default 255/63\n");
- bs.secs_track = htole16(63);
- bs.heads = htole16(255);
- } else {
- bs.secs_track = htole16(geometry.sectors); /* Set up the geometry information */
- bs.heads = htole16(geometry.heads);
- if (!hidden_sectors_by_user)
- hidden_sectors = htole32(geometry.start);
- }
-def_hd_params:
- bs.media = (char)0xf8; /* Set up the media descriptor for a hard drive */
- if (!size_fat && blocks * SECTORS_PER_BLOCK > 1064960) {
- if (verbose)
- printf("Auto-selecting FAT32 for large filesystem\n");
- size_fat = 32;
- }
- if (size_fat == 32) {
- /* For FAT32, try to do the same as M$'s format command
- * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20):
- * fs size <= 260M: 0.5k clusters
- * fs size <= 8G: 4k clusters
- * fs size <= 16G: 8k clusters
- * fs size <= 32G: 16k clusters
- * fs size > 32G: 32k clusters
- */
- uint32_t sz_mb =
- (blocks + (1 << (20 - BLOCK_SIZE_BITS)) - 1) >> (20 -
- BLOCK_SIZE_BITS);
- bs.cluster_size =
- sz_mb > 32 * 1024 ? 64 : sz_mb > 16 * 1024 ? 32 : sz_mb >
- 8 * 1024 ? 16 : sz_mb > 260 ? 8 : 1;
- } else {
- /* FAT12 and FAT16: start at 4 sectors per cluster */
- bs.cluster_size = (char)4;
- }
+ if (info->geom_heads > 0) {
+ heads = info->geom_heads;
+ sec_per_track = info->geom_sectors;
}
+ if (!hidden_sectors_by_user && info->geom_start >= 0)
+ hidden_sectors = htole32(info->geom_start);
+
if (!root_dir_entries)
root_dir_entries = def_root_dir_entries;
+
+ bs.secs_track = htole16(sec_per_track);
+ bs.heads = htole16(heads);
+ bs.media = media;
+ bs.cluster_size = cluster_size;
}
/*
@@ -713,7 +620,6 @@ static unsigned int align_object(unsigned int sectors, unsigned int clustsize)
static void setup_tables(void)
{
- unsigned num_sectors;
unsigned cluster_count = 0, fat_length;
struct tm *ctime;
struct msdos_volume_info *vi =
@@ -807,8 +713,15 @@ static void setup_tables(void)
memcpy(&bs.hidden, &hidden, 2);
}
- num_sectors =
- (long long)(blocks * BLOCK_SIZE / sector_size) + orphaned_sectors;
+ if ((long long)(blocks * BLOCK_SIZE / sector_size) + orphaned_sectors >
+ UINT32_MAX) {
+ printf("Warning: target too large, space at end will be left unused\n");
+ num_sectors = UINT32_MAX;
+ blocks = (uint64_t)UINT32_MAX * sector_size / BLOCK_SIZE;
+ } else {
+ num_sectors =
+ (long long)(blocks * BLOCK_SIZE / sector_size) + orphaned_sectors;
+ }
if (!atari_format) {
unsigned fatdata1216; /* Sectors for FATs + data area (FAT12/16) */
@@ -837,7 +750,8 @@ static void setup_tables(void)
maxclustsize = 128;
do {
- fatdata32 = num_sectors - reserved_sectors;
+ fatdata32 = num_sectors
+ - align_object(reserved_sectors, bs.cluster_size);
fatdata1216 = fatdata32
- align_object(root_dir_sectors, bs.cluster_size);
@@ -899,6 +813,7 @@ static void setup_tables(void)
clust32 = ((long long)fatdata32 * sector_size + nr_fats * 8) /
((int)bs.cluster_size * sector_size + nr_fats * 4);
fatlength32 = cdiv((clust32 + 2) * 4, sector_size);
+ fatlength32 = align_object(fatlength32, bs.cluster_size);
/* Need to recalculate number of clusters, since the unused parts of the
* FATS and data area together could make up space for an additional,
* not really present cluster. */
@@ -985,6 +900,10 @@ static void setup_tables(void)
die("FAT not 12, 16 or 32 bits");
}
+ /* Adjust the reserved number of sectors for alignment */
+ reserved_sectors = align_object(reserved_sectors, bs.cluster_size);
+ bs.reserved = htole16(reserved_sectors);
+
/* Adjust the number of root directory entries to help enforce alignment */
if (align_structures) {
root_dir_entries = align_object(root_dir_sectors, bs.cluster_size)
@@ -1130,9 +1049,11 @@ static void setup_tables(void)
else
die("Attempting to create a too large filesystem");
}
+ fat_entries = cluster_count + 2;
/* The two following vars are in hard sectors, i.e. 512 byte sectors! */
- start_data_sector = (reserved_sectors + nr_fats * fat_length) *
+ start_data_sector = (reserved_sectors + nr_fats * fat_length +
+ cdiv(root_dir_entries * 32, sector_size)) *
(sector_size / HARD_SECTOR_SIZE);
start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) /
SECTORS_PER_BLOCK;
@@ -1209,10 +1130,9 @@ static void setup_tables(void)
}
memset(root_dir, 0, size_root_dir);
- if (memcmp(volume_name, NO_NAME, 11)) {
+ if (memcmp(volume_name, NO_NAME, MSDOS_NAME)) {
struct msdos_dir_entry *de = &root_dir[0];
- memcpy(de->name, volume_name, 8);
- memcpy(de->ext, volume_name + 8, 3);
+ memcpy(de->name, volume_name, MSDOS_NAME);
de->attr = ATTR_VOLUME;
if (!invariant)
ctime = localtime(&create_time);
@@ -1277,8 +1197,8 @@ static void setup_tables(void)
#define seekto(pos,errstr) \
do { \
- loff_t __pos = (pos); \
- if (llseek (dev, __pos, SEEK_SET) != __pos) \
+ off_t __pos = (pos); \
+ if (lseek (dev, __pos, SEEK_SET) != __pos) \
error ("seek to " errstr " failed whilst writing tables"); \
} while(0)
@@ -1388,12 +1308,11 @@ int main(int argc, char **argv)
char *tmp;
char *listfile = NULL;
FILE *msgfile;
- struct stat statbuf;
+ struct device_info devinfo;
int i = 0, pos, ch;
int create = 0;
uint64_t cblocks = 0;
- int min_sector_size;
- int bad_block_count = 0;
+ int blocks_specified = 0;
struct timeval create_timeval;
enum {OPT_HELP=1000, OPT_INVARIANT,};
@@ -1412,7 +1331,7 @@ int main(int argc, char **argv)
gettimeofday(&create_timeval, NULL);
create_time = create_timeval.tv_sec;
- volume_id = (u_int32_t) ((create_timeval.tv_sec << 20) | create_timeval.tv_usec); /* Default volume ID = creation time, fudged for more uniqueness */
+ volume_id = (uint32_t) ((create_timeval.tv_sec << 20) | create_timeval.tv_usec); /* Default volume ID = creation time, fudged for more uniqueness */
check_atari();
printf("mkfs.fat " VERSION " (" VERSION_DATE ")\n");
@@ -1641,38 +1560,34 @@ int main(int argc, char **argv)
printf("Unknown option: %c\n", c);
usage(1);
}
- if (optind < argc) {
- device_name = argv[optind]; /* Determine the number of blocks in the FS */
- if (!device_name) {
- printf("No device specified.\n");
+ if (optind == argc || !argv[optind]) {
+ printf("No device specified.\n");
+ usage(1);
+ }
+
+ device_name = argv[optind++];
+
+ if (optind != argc) {
+ blocks_specified = 1;
+ blocks = strtoull(argv[optind], &tmp, 0);
+
+ if (*tmp) {
+ printf("Bad block count : %s\n", argv[optind]);
usage(1);
}
- if (!create)
- cblocks = count_blocks(device_name, &orphaned_sectors); /* Have a look and see! */
- }
- if (optind == argc - 2) { /* Either check the user specified number */
- blocks = strtoull(argv[optind + 1], &tmp, 0);
- if (!create && blocks != cblocks) {
- fprintf(stderr, "Warning: block count mismatch: ");
- fprintf(stderr, "found %llu but assuming %llu.\n", (unsigned long long)cblocks, (unsigned long long)blocks);
- }
- if (*tmp)
- bad_block_count = 1;
- } else if (optind == argc - 1) { /* Or use value found */
- if (create)
- die("Need intended size with -C.");
- blocks = cblocks;
- } else {
- fprintf(stderr, "No device specified!\n");
- usage(1);
+ optind++;
}
- if (bad_block_count) {
- printf("Bad block count : %s\n", argv[optind + 1]);
+
+ if (optind != argc) {
+ fprintf(stderr, "Excess arguments on command line\n");
usage(1);
}
+ if (create && !blocks_specified)
+ die("Need intended size with -C.");
+
if (check && listfile) /* Auto and specified bad block handling are mutually */
die("-c and -l are incompatible"); /* exclusive of each other! */
@@ -1698,47 +1613,58 @@ int main(int argc, char **argv)
die("unable to resize %s");
}
- if (fstat(dev, &statbuf) < 0)
- die("unable to stat %s");
- if (!S_ISBLK(statbuf.st_mode)) {
- statbuf.st_rdev = 0;
- check = 0;
- } else
- /*
- * Ignore any 'full' fixed disk devices, if -I is not given.
- * On a MO-disk one doesn't need partitions. The filesytem can go
- * directly to the whole disk. Under other OSes this is known as
- * the 'superfloppy' format. As I don't know how to find out if
- * this is a MO disk I introduce a -I (ignore) switch. -Joey
- */
- if (!ignore_full_disk && ((statbuf.st_rdev & 0xffffff3f) == 0x0300 || /* hda, hdb */
- (statbuf.st_rdev & 0xffffff0f) == 0x0800 || /* sd */
- (statbuf.st_rdev & 0xffffff3f) == 0x0d00 || /* xd */
- (statbuf.st_rdev & 0xffffff3f) == 0x1600) /* hdc, hdd */
- )
+ if (get_device_info(dev, &devinfo) < 0)
+ die("error collecting information about %s");
+
+ if (devinfo.size <= 0)
+ die("unable to discover size of %s");
+
+ if (devinfo.sector_size > 0)
+ sector_size = devinfo.sector_size;
+
+ cblocks = devinfo.size / BLOCK_SIZE;
+ orphaned_sectors = (devinfo.size % BLOCK_SIZE) / sector_size;
+
+ if (blocks_specified) {
+ if (blocks != cblocks) {
+ fprintf(stderr, "Warning: block count mismatch: ");
+ fprintf(stderr, "found %llu but assuming %llu.\n",
+ (unsigned long long)cblocks, (unsigned long long)blocks);
+ }
+ } else {
+ blocks = cblocks;
+ }
+
+ /*
+ * Ignore any 'full' fixed disk devices, if -I is not given.
+ */
+ if (!ignore_full_disk && devinfo.type == TYPE_FIXED &&
+ devinfo.partition == 0)
die("Device partition expected, not making filesystem on entire device '%s' (use -I to override)");
- if (sector_size_set) {
- if (ioctl(dev, BLKSSZGET, &min_sector_size) >= 0)
- if (sector_size < min_sector_size) {
- sector_size = min_sector_size;
+ if (!ignore_full_disk && devinfo.has_children > 0)
+ die("Partitions or virtual mappings on device '%s', not making filesystem (use -I to override)");
+
+ if (devinfo.sector_size > 0) {
+ if (sector_size_set) {
+ if (sector_size < devinfo.sector_size) {
+ sector_size = devinfo.sector_size;
fprintf(stderr,
"Warning: sector size was set to %d (minimal for this device)\n",
sector_size);
}
- } else {
- if (ioctl(dev, BLKSSZGET, &min_sector_size) >= 0) {
- sector_size = min_sector_size;
+ } else {
+ sector_size = devinfo.sector_size;
sector_size_set = 1;
}
}
if (sector_size > 4096)
fprintf(stderr,
- "Warning: sector size is set to %d > 4096, such filesystem will not propably mount\n",
+ "Warning: sector size %d > 4096 is non-standard, filesystem may not be usable\n",
sector_size);
- establish_params(statbuf.st_rdev, statbuf.st_size);
+ establish_params(&devinfo);
/* Establish the media parameters */
setup_tables(); /* Establish the filesystem tables */
diff --git a/src/msdos_fs.h b/src/msdos_fs.h
index 54b2a34..d33a2e4 100644
--- a/src/msdos_fs.h
+++ b/src/msdos_fs.h
@@ -46,7 +46,7 @@
#define MSDOS_DOTDOT ".. " /* "..", padded to MSDOS_NAME chars */
struct msdos_dir_entry {
- uint8_t name[8], ext[3]; /* name and extension */
+ uint8_t name[MSDOS_NAME]; /* name including extension */
uint8_t attr; /* attribute bits */
uint8_t lcase; /* Case for base and extension */
uint8_t ctime_cs; /* Creation time, centiseconds (0-199) */
diff --git a/src/testdevinfo.c b/src/testdevinfo.c
new file mode 100644
index 0000000..9c555ed
--- /dev/null
+++ b/src/testdevinfo.c
@@ -0,0 +1,125 @@
+/* testdevinfo - Display device info findings for debugging
+
+ Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
+
+ 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 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 <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "device_info.h"
+
+
+int main(int argc, char **argv)
+{
+ struct device_info info;
+ int fd;
+
+ if (argc != 2) {
+ printf("Usage: testdevinfo FILENAME\n");
+ return 1;
+ }
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd < 0) {
+ perror("open device");
+ return 1;
+ }
+
+ device_info_verbose = 100;
+ get_device_info(fd, &info);
+ close(fd);
+
+ printf("\nfound information:\n");
+
+ printf("device type: ");
+ switch (info.type) {
+ case TYPE_UNKNOWN:
+ printf("unknown\n");
+ break;
+
+ case TYPE_BAD:
+ printf("unusable\n");
+ break;
+
+ case TYPE_FILE:
+ printf("image file\n");
+ break;
+
+ case TYPE_VIRTUAL:
+ printf("virtual\n");
+ break;
+
+ case TYPE_REMOVABLE:
+ printf("removable\n");
+ break;
+
+ case TYPE_FIXED:
+ printf("fixed\n");
+ break;
+
+ default:
+ printf("internal error! invalid value\n");
+ break;
+ }
+
+ printf("is partition: ");
+ if (info.partition < 0)
+ printf("unknown\n");
+ else if (info.partition == 0)
+ printf("no, full disk\n");
+ else
+ printf("number %d\n", info.partition);
+
+ printf("has children: ");
+ if (info.has_children < 0)
+ printf("unknown\n");
+ else if (info.has_children == 0)
+ printf("no\n");
+ else
+ printf("yes\n");
+
+ printf("heads: ");
+ if (info.geom_heads < 0)
+ printf("unknown\n");
+ else
+ printf("%d\n", info.geom_heads);
+
+ printf("sectors: ");
+ if (info.geom_sectors < 0)
+ printf("unknown\n");
+ else
+ printf("%d\n", info.geom_sectors);
+
+ printf("start: ");
+ if (info.geom_start < 0)
+ printf("unknown\n");
+ else
+ printf("%ld\n", info.geom_start);
+
+ printf("sector size: ");
+ if (info.sector_size < 0)
+ printf("unknown\n");
+ else
+ printf("%d\n", info.sector_size);
+
+ printf("size: ");
+ if (info.size < 0)
+ printf("unknown\n");
+ else
+ printf("%lld\n", info.size);
+
+ return 0;
+}
diff --git a/src/version.h b/src/version.h.in
index f0716d3..1487fc5 100644
--- a/src/version.h
+++ b/src/version.h.in
@@ -1,4 +1,4 @@
-/* version.h
+/* @configure_input@
Copyright (C) 1998-2005 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
@@ -23,7 +23,7 @@
#ifndef _version_h
#define _version_h
-#define VERSION "3.0.28"
-#define VERSION_DATE "2015-05-16"
+#define VERSION "@PACKAGE_VERSION@"
+#define VERSION_DATE "@RELEASE_DATE@"
#endif