Imported Upstream version 4.0 upstream/4.0
authorJinWang An <jinwang.an@samsung.com>
Mon, 26 Dec 2022 04:14:07 +0000 (13:14 +0900)
committerJinWang An <jinwang.an@samsung.com>
Mon, 26 Dec 2022 04:14:07 +0000 (13:14 +0900)
41 files changed:
.gitignore
ChangeLog
Makefile [deleted file]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
README.md [new file with mode: 0644]
VERSION [deleted file]
configure.ac [new file with mode: 0644]
manpages/Makefile [deleted file]
manpages/Makefile.am [new file with mode: 0644]
manpages/bin/update-version.sh [deleted file]
manpages/fatlabel.8.in [moved from manpages/en/fatlabel.8 with 97% similarity]
manpages/fsck.fat.8.in [moved from manpages/en/fsck.fat.8 with 97% similarity]
manpages/mkfs.fat.8.in [moved from manpages/en/mkfs.fat.8 with 97% similarity]
src/Makefile.am [new file with mode: 0644]
src/blkdev/README [new file with mode: 0644]
src/blkdev/blkdev.c [new file with mode: 0644]
src/blkdev/blkdev.h [new file with mode: 0644]
src/blkdev/linux_version.c [new file with mode: 0644]
src/blkdev/linux_version.h [new file with mode: 0644]
src/boot.c
src/boot.h
src/check.c
src/check.h
src/device_info.c [new file with mode: 0644]
src/device_info.h [new file with mode: 0644]
src/endian_compat.h [new file with mode: 0644]
src/fat.c
src/fat.h
src/fatlabel.c
src/fsck.fat.c
src/fsck.fat.h
src/io.c
src/io.h
src/lfn.c
src/lfn.h
src/mkfs.fat.c
src/msdos_fs.h
src/testdevinfo.c [new file with mode: 0644]
src/version.h.in [moved from src/version.h with 90% similarity]

index 2dc4ca9..99908a7 100644 (file)
@@ -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
index f6a1e3d..4e9f763 100644 (file)
--- 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 (file)
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 (file)
index 0000000..e2ec024
--- /dev/null
@@ -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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
index 0000000..4d4e522
--- /dev/null
@@ -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 (file)
index ee8a478..0000000
+++ /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 (file)
index 0000000..5473a7f
--- /dev/null
@@ -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 (executable)
index 48e9c08..0000000
+++ /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
similarity index 97%
rename from manpages/en/fatlabel.8
rename to manpages/fatlabel.8.in
index c00a795..bf5ebbd 100644 (file)
@@ -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
 .\" ----------------------------------------------------------------------------
similarity index 97%
rename from manpages/en/fsck.fat.8
rename to manpages/fsck.fat.8.in
index f2d44d0..06057a8 100644 (file)
@@ -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.
similarity index 97%
rename from manpages/en/mkfs.fat.8
rename to manpages/mkfs.fat.8.in
index 5a5086e..2d19daf 100644 (file)
@@ -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 (file)
index 0000000..3d22ba7
--- /dev/null
@@ -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 (file)
index 0000000..af74eb7
--- /dev/null
@@ -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 (file)
index 0000000..ae9c8d1
--- /dev/null
@@ -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 (file)
index 0000000..b9179ad
--- /dev/null
@@ -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 (file)
index 0000000..2bcc2cc
--- /dev/null
@@ -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 (file)
index 0000000..a6a1e99
--- /dev/null
@@ -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 */
index 0c0918f..491ecd9 100644 (file)
@@ -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;
 
index d52e624..dd9404f 100644 (file)
@@ -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 */
 
index d8b9d72..59d6d27 100644 (file)
@@ -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"
 #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;
index fcb6bea..933bbf4 100644 (file)
@@ -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 (file)
index 0000000..f5d11ac
--- /dev/null
@@ -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 (file)
index 0000000..3f4195a
--- /dev/null
@@ -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 (file)
index 0000000..44168c7
--- /dev/null
@@ -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
index 5a92f56..c32c25b 100644 (file)
--- 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);
 
index b50ed4a..5c77634 100644 (file)
--- 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. */
 
index 1484ba5..9268ddb 100644 (file)
@@ -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);
     }
 
index f786a93..c244aba 100644 (file)
@@ -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;
 }
index e5f6178..168049e 100644 (file)
@@ -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
 #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;
index 450432c..b2c559b 100644 (file)
--- 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
 #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);
index d23d07e..4ce032f 100644 (file)
--- a/src/io.h
+++ b/src/io.h
 #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
index 2601172..b33e125 100644 (file)
--- 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
index e5c3991..fc38ce7 100644 (file)
--- a/src/lfn.h
+++ b/src/lfn.h
 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
index b38d116..8a320fd 100644 (file)
@@ -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
 #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>
 #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 */
index 54b2a34..d33a2e4 100644 (file)
@@ -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 (file)
index 0000000..9c555ed
--- /dev/null
@@ -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;
+}
similarity index 90%
rename from src/version.h
rename to src/version.h.in
index f0716d3..1487fc5 100644 (file)
@@ -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