From 9a7966555cb8146da9a47e2270b3e45bda06ea1c Mon Sep 17 00:00:00 2001 From: JinWang An Date: Mon, 26 Dec 2022 13:14:07 +0900 Subject: [PATCH] Imported Upstream version 4.0 --- .gitignore | 27 +- ChangeLog | 765 ++++++++++++++++++++++++++++++ Makefile | 170 ------- Makefile.am | 10 + NEWS | 76 +++ README | 39 ++ README.md | 42 ++ VERSION | 1 - configure.ac | 67 +++ manpages/Makefile | 50 -- manpages/Makefile.am | 38 ++ manpages/bin/update-version.sh | 55 --- manpages/{en/fatlabel.8 => fatlabel.8.in} | 2 +- manpages/{en/fsck.fat.8 => fsck.fat.8.in} | 5 +- manpages/{en/mkfs.fat.8 => mkfs.fat.8.in} | 5 +- src/Makefile.am | 63 +++ src/blkdev/README | 3 + src/blkdev/blkdev.c | 376 +++++++++++++++ src/blkdev/blkdev.h | 149 ++++++ src/blkdev/linux_version.c | 25 + src/blkdev/linux_version.h | 14 + src/boot.c | 77 +-- src/boot.h | 2 +- src/check.c | 82 ++-- src/check.h | 2 +- src/device_info.c | 332 +++++++++++++ src/device_info.h | 56 +++ src/endian_compat.h | 29 ++ src/fat.c | 56 ++- src/fat.h | 2 +- src/fatlabel.c | 5 +- src/fsck.fat.c | 3 +- src/fsck.fat.h | 24 +- src/io.c | 70 +-- src/io.h | 16 +- src/lfn.c | 23 +- src/lfn.h | 6 +- src/mkfs.fat.c | 540 +++++++++------------ src/msdos_fs.h | 2 +- src/testdevinfo.c | 125 +++++ src/{version.h => version.h.in} | 6 +- 41 files changed, 2650 insertions(+), 790 deletions(-) delete mode 100644 Makefile create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 README.md delete mode 100644 VERSION create mode 100644 configure.ac delete mode 100644 manpages/Makefile create mode 100644 manpages/Makefile.am delete mode 100755 manpages/bin/update-version.sh rename manpages/{en/fatlabel.8 => fatlabel.8.in} (97%) rename manpages/{en/fsck.fat.8 => fsck.fat.8.in} (97%) rename manpages/{en/mkfs.fat.8 => mkfs.fat.8.in} (97%) create mode 100644 src/Makefile.am create mode 100644 src/blkdev/README create mode 100644 src/blkdev/blkdev.c create mode 100644 src/blkdev/blkdev.h create mode 100644 src/blkdev/linux_version.c create mode 100644 src/blkdev/linux_version.h create mode 100644 src/device_info.c create mode 100644 src/device_info.h create mode 100644 src/endian_compat.h create mode 100644 src/testdevinfo.c rename src/{version.h => version.h.in} (90%) diff --git a/.gitignore b/.gitignore index 2dc4ca9..99908a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,32 @@ *.o -/fatlabel -/fsck.fat -/mkfs.fat +src/fatlabel +src/fsck.fat +src/mkfs.fat +src/testdevinfo tags +TAGS *~ .*.sw[a-p] *.orig *.rej *.DS_Store + +aclocal.m4 +autom4te.cache +config.log +config.status +configure +compile +depcomp +install-sh +missing +.deps +.dirstamp + +Makefile +Makefile.in +src/version.h +manpages/fatlabel.8 +manpages/mkfs.fat.8 +manpages/fsck.fat.8 diff --git a/ChangeLog b/ChangeLog index f6a1e3d..4e9f763 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,768 @@ +commit a79ff90 +Author: Andreas Bombe +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 + +commit e8eff14 +Author: Andreas Bombe +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 + +commit 016800e +Author: Andreas Bombe +Date: Wed Apr 27 14:16:53 2016 +0200 + + Use variable total_fat_entries in read_boot() for readability + + Signed-off-by: Andreas Bombe + +commit a6478d8 +Author: Álvaro Fernández Rojas +Date: Fri Apr 8 12:20:46 2016 +0200 + + Add missing iconv library for OS X + + Signed-off-by: Álvaro Fernández Rojas + Signed-off-by: Andreas Bombe + +commit ce67dc6 +Author: Álvaro Fernández Rojas +Date: Fri Apr 8 12:20:27 2016 +0200 + + Add endian support for OS X + + Signed-off-by: Álvaro Fernández Rojas + Signed-off-by: Andreas Bombe + +commit 08f3869 +Author: Joel Holdsworth +Date: Thu Mar 10 00:53:07 2016 +0000 + + Configure option to disable building with libudev + + Signed-off-by: Andreas Bombe + +commit ed4e47b +Author: Andreas Bombe +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 + +commit b1a38ab +Author: Andreas Bombe +Date: Wed Feb 17 21:04:35 2016 +0100 + + Add preliminary entry for release 4.0 to NEWS + + Signed-off-by: Andreas Bombe + +commit 4ad3e9e +Author: Andreas Bombe +Date: Wed Feb 17 21:02:06 2016 +0100 + + Adjust ridiculous source indentation in io.c + + Signed-off-by: Andreas Bombe + +commit b96acb2 +Author: Andreas Bombe +Date: Wed Feb 17 20:51:53 2016 +0100 + + Document ./configure --enable-compat-symlinks in README + + Signed-off-by: Andreas Bombe + +commit de39c5c +Author: Andreas Bombe +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 + +commit 86c7acd +Author: Andreas Bombe +Date: Wed Feb 17 15:06:56 2016 +0100 + + man fsck: Document the -c option + + Signed-off-by: Andreas Bombe + +commit ef9a73c +Author: Andreas Bombe +Date: Mon Feb 15 02:10:57 2016 +0100 + + Add NEWS file with changes of the last two releases + + Signed-off-by: Andreas Bombe + +commit bda6551 +Author: Andreas Bombe +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 + +commit 4b8c9cc +Author: Andreas Bombe +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 + +commit d7665f2 +Author: Andreas Bombe +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 + +commit 6225e59 +Author: Andreas Bombe +Date: Fri Feb 5 14:39:00 2016 +0100 + + blkdev.c: Prevent unused parameter warnings in fallback code + + Signed-off-by: Andreas Bombe + +commit 34cdded +Author: Andreas Bombe +Date: Fri Feb 5 14:36:14 2016 +0100 + + blkdev_get_size(): Remove unused variable ch + + Signed-off-by: Andreas Bombe + +commit 5571d29 +Author: Andreas Bombe +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 + +commit 2c71ace +Author: Andreas Bombe +Date: Wed Feb 3 03:38:33 2016 +0100 + + Makefile.am: Add historic documentation to distribution + + Signed-off-by: Andreas Bombe + +commit bcbae63 +Author: Andreas Bombe +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 + +commit 19d1a13 +Author: Andreas Bombe +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 + +commit f691660 +Author: Andreas Bombe +Date: Wed Feb 3 02:31:00 2016 +0100 + + Reinstate some #include + + 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 + +commit 51afd41 +Author: Andreas Bombe +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 + +commit bf6f142 +Author: Andreas Bombe +Date: Wed Jan 27 15:28:42 2016 +0100 + + mkfs man: Note that sector sizes > 4096 are non-standard + + Signed-off-by: Andreas Bombe + +commit ea96c32 +Author: Andreas Bombe +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 + +commit dfb5bea +Author: Andreas Bombe +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 + +commit fc0343f +Author: Andreas Bombe +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 + +commit 9211c8a +Author: Andreas Bombe +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 + +commit 0627a62 +Author: Andreas Bombe +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 + +commit 2dca9aa +Author: Andreas Bombe +Date: Thu Jan 14 14:43:00 2016 +0100 + + .gitignore: Add .dirstamp + + Signed-off-by: Andreas Bombe + +commit 6a966fb +Author: Andreas Bombe +Date: Thu Jan 14 14:38:53 2016 +0100 + + mkfs: Reword non-standard sector size warning + + Signed-off-by: Andreas Bombe + +commit bebc9ac +Author: Andreas Bombe +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 + +commit 12a1d46 +Author: Andreas Bombe +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 + +commit d38bd2d +Author: Andreas Bombe +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 + +commit 0847e4c +Author: Andreas Bombe +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 + +commit 1b7d91e +Author: Andreas Bombe +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 + +commit 5024372 +Author: Andreas Bombe +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 + +commit 4a146d7 +Author: Andreas Bombe +Date: Fri Nov 27 03:25:55 2015 +0100 + + Add blkdev_get_start() for getting partition start offset + + Signed-off-by: Andreas Bombe + +commit 254f8ab +Author: Andreas Bombe +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 + +commit c9fb33c +Author: Andreas Bombe +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 + +commit 64486ad +Author: Andreas Bombe +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 + +commit e03a5f4 +Author: Andreas Bombe +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 + +commit 5b9a88d +Author: Andreas Bombe +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 + +commit 53eddfc +Author: Andreas Bombe +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 + +commit 456767b +Author: Andreas Bombe +Date: Mon Sep 14 00:33:49 2015 +0200 + + configure.ac: Use AS_HELP_STRING to format option help + + Signed-off-by: Andreas Bombe + +commit 3cfb479 +Author: Andreas Bombe +Date: Mon Sep 14 00:30:40 2015 +0200 + + version.h: Use @configure_input@ autoconf variable in boilerplate + + Signed-off-by: Andreas Bombe + +commit 41ef834 +Author: Andreas Bombe +Date: Mon Sep 14 00:29:27 2015 +0200 + + .gitignore: Add TAGS in addition to tags + + Signed-off-by: Andreas Bombe + +commit bdc3d2a +Author: Andreas Bombe +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 + +commit 0790812 +Author: Andreas Bombe +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 + +commit 39ce90f +Author: Andreas Bombe +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 + +commit 2aad1c8 +Author: Andreas Bombe +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 + +commit 3b95786 +Author: Yann E. MORIN +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" + Signed-off-by: Andreas Bombe + +commit 2b1c4d1 +Author: Andreas Bombe +Date: Wed Jun 3 03:33:10 2015 +0200 + + Add README.md, remove Markdown formatting from README + + Signed-off-by: Andreas Bombe + +commit b720acc +Author: Andreas Bombe +Date: Wed Jun 3 03:27:24 2015 +0200 + + Add simple README in Markdown format + + Signed-off-by: Andreas Bombe + +commit 2b255e6 +Author: Andreas Bombe +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 + +commit 0643db7 +Author: Andreas Bombe +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 + +commit 85022fe (tag: v3.0.28) +Author: Andreas Bombe +Date: Sat May 16 02:56:17 2015 +0200 + + Releasing version 3.0.28. + + Signed-off-by: Andreas Bombe + commit ad1342e Author: Andreas Bombe Date: Sat May 16 02:10:18 2015 +0200 diff --git a/Makefile b/Makefile deleted file mode 100644 index 1593f3d..0000000 --- a/Makefile +++ /dev/null @@ -1,170 +0,0 @@ -# Makefile -# -# Copyright (C) 2008-2014 Daniel Baumann -# -# 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 . -# -# The complete text of the GNU General Public License -# can be found in /usr/share/common-licenses/GPL-3 file. - -SHELL := sh -e -LANGUAGES = $(shell cd manpages/po && ls) - -DESTDIR = -PREFIX = /usr/local -SBINDIR = $(PREFIX)/sbin -DOCDIR = $(PREFIX)/share/doc -MANDIR = $(PREFIX)/share/man - -#OPTFLAGS = -O2 -fomit-frame-pointer -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -OPTFLAGS = -O2 -fomit-frame-pointer -D_GNU_SOURCE $(shell getconf LFS_CFLAGS) -#WARNFLAGS = -Wall -pedantic -std=c99 -WARNFLAGS = -Wall -Wextra -Wno-sign-compare -Wno-missing-field-initializers -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -DEBUGFLAGS = -g -CFLAGS += $(OPTFLAGS) $(WARNFLAGS) $(DEBUGFLAGS) - -VPATH = src - -all: build - -build: fatlabel fsck.fat mkfs.fat - -fatlabel: boot.o check.o common.o fat.o file.o io.o lfn.o charconv.o fatlabel.o - -fsck.fat: boot.o check.o common.o fat.o file.o io.o lfn.o charconv.o fsck.fat.o - -mkfs.fat: mkfs.fat.o - -rebuild: distclean build - -install: install-bin install-doc install-man install-symlinks - -install-bin: build - install -d -m 0755 $(DESTDIR)/$(SBINDIR) - install -m 0755 fatlabel fsck.fat mkfs.fat $(DESTDIR)/$(SBINDIR) - -install-doc: - install -d -m 0755 $(DESTDIR)/$(DOCDIR)/dosfstools - install -p -m 0644 ChangeLog doc/* $(DESTDIR)/$(DOCDIR)/dosfstools - -install-man: - for MANPAGE in manpages/en/*; \ - do \ - SECTION="8"; \ - mkdir -p $(DESTDIR)/$(MANDIR)/man$${SECTION}/; \ - install -m 0644 $${MANPAGE} $(DESTDIR)/$(MANDIR)/man$${SECTION}/$$(basename $${MANPAGE}); \ - done - - for LANGUAGE in $(LANGUAGES); \ - do \ - for MANPAGE in manpages/$${LANGUAGE}/*; \ - do \ - SECTION="8"; \ - mkdir -p $(DESTDIR)/$(MANDIR)/$${LANGUAGE}/man$${SECTION}/; \ - install -m 0644 $${MANPAGE} $(DESTDIR)/$(MANDIR)/$${LANGUAGE}/man$${SECTION}/$$(basename $${MANPAGE} .$${LANGUAGE}.$${SECTION}).$${SECTION}; \ - done; \ - done -install-symlinks: install-bin install-man - if [ -e $(DESTDIR)/$(SBINDIR)/fatlabel ]; \ - then \ - ln -sf fatlabel $(DESTDIR)/$(SBINDIR)/dosfslabel; \ - if [ -e $(DESTDIR)/$(MANDIR)/man8/fatlabel.8 ]; \ - then \ - ln -sf fatlabel.8 $(DESTDIR)/$(MANDIR)/man8/dosfslabel.8; \ - fi; \ - fi - - if [ -e $(DESTDIR)/$(SBINDIR)/fsck.fat ]; \ - then \ - ln -sf fsck.fat $(DESTDIR)/$(SBINDIR)/dosfsck; \ - ln -sf fsck.fat $(DESTDIR)/$(SBINDIR)/fsck.msdos; \ - ln -sf fsck.fat $(DESTDIR)/$(SBINDIR)/fsck.vfat; \ - if [ -e $(DESTDIR)/$(MANDIR)/man8/fsck.fat.8 ]; \ - then \ - ln -sf fsck.fat.8 $(DESTDIR)/$(MANDIR)/man8/dosfsck.8; \ - ln -sf fsck.fat.8 $(DESTDIR)/$(MANDIR)/man8/fsck.msdos.8; \ - ln -sf fsck.fat.8 $(DESTDIR)/$(MANDIR)/man8/fsck.vfat.8; \ - fi; \ - fi - - if [ -e $(DESTDIR)/$(SBINDIR)/mkfs.fat ]; \ - then \ - ln -sf mkfs.fat $(DESTDIR)/$(SBINDIR)/mkdosfs; \ - ln -sf mkfs.fat $(DESTDIR)/$(SBINDIR)/mkfs.msdos; \ - ln -sf mkfs.fat $(DESTDIR)/$(SBINDIR)/mkfs.vfat; \ - if [ -e $(DESTDIR)/$(MANDIR)/man8/mkfs.fat.8 ]; \ - then \ - ln -sf mkfs.fat.8 $(DESTDIR)/$(MANDIR)/man8/mkdosfs.8; \ - ln -sf mkfs.fat.8 $(DESTDIR)/$(MANDIR)/man8/mkfs.msdos.8; \ - ln -sf mkfs.fat.8 $(DESTDIR)/$(MANDIR)/man8/mkfs.vfat.8; \ - fi; \ - fi - -uninstall: uninstall-symlinks uninstall-man uninstall-doc uninstall-bin - -uninstall-bin: - rm -f $(DESTDIR)/$(SBINDIR)/fatlabel - rm -f $(DESTDIR)/$(SBINDIR)/fsck.fat - rm -f $(DESTDIR)/$(SBINDIR)/mkfs.fat - - rmdir --ignore-fail-on-non-empty $(DESTDIR)/$(SBINDIR) - -uninstall-doc: - rm -rf $(DESTDIR)/$(DOCDIR)/dosfstools - - rmdir --ignore-fail-on-non-empty $(DESTDIR)/$(DOCDIR) - -uninstall-man: - for MANPAGE in manpages/en/*; \ - do \ - SECTION="8"; \ - rm -f $(DESTDIR)/$(MANDIR)/man$${SECTION}/$$(basename $${MANPAGE} .en.$${SECTION}).$${SECTION}; \ - done - - for LANGUAGE in $(LANGUAGES); \ - do \ - for MANPAGE in manpages/$${LANGUAGE}/*; \ - do \ - SECTION="8"; \ - rm -f $(DESTDIR)/$(MANDIR)/$${LANGUAGE}/man$${SECTION}/$$(basename $${MANPAGE} .$${LANGUAGE}.$${SECTION}).$${SECTION}; \ - done; \ - done - -uninstall-symlinks: - rm -f $(DESTDIR)/$(SBINDIR)/dosfslabel - rm -f $(DESTDIR)/$(MANDIR)/man8/dosfslabel.8 - - rm -f $(DESTDIR)/$(SBINDIR)/dosfsck - rm -f $(DESTDIR)/$(MANDIR)/man8/dosfsck.8 - rm -f $(DESTDIR)/$(SBINDIR)/fsck.msdos - rm -f $(DESTDIR)/$(MANDIR)/man8/fsck.msdos.8 - rm -f $(DESTDIR)/$(SBINDIR)/fsck.vfat - rm -f $(DESTDIR)/$(MANDIR)/man8/fsck.vfat.8 - - rm -f $(DESTDIR)/$(SBINDIR)/mkdosfs - rm -f $(DESTDIR)/$(MANDIR)/man8/mkdosfs.8 - rm -f $(DESTDIR)/$(SBINDIR)/mkfs.msdos - rm -f $(DESTDIR)/$(MANDIR)/man8/mkfs.msdos.8 - rm -f $(DESTDIR)/$(SBINDIR)/mkfs.vfat - rm -f $(DESTDIR)/$(MANDIR)/man8/mkfs.vfat.8 - -reinstall: distclean install - -clean: - rm -f *.o - -distclean: clean - rm -f fatlabel fsck.fat mkfs.fat - -.PHONY: build rebuild install install-bin install-doc install-man install-symlinks uninstall uninstall-bin uninstall-doc uninstall-man uninstall-symlinks reinstall clean distclean diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..e2ec024 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,10 @@ +SUBDIRS = src manpages + +dist_doc_DATA = doc/ANNOUNCE.mkdosfs \ + doc/ChangeLog.dosfsck \ + doc/ChangeLog.dosfstools-2.x \ + doc/ChangeLog.mkdosfs \ + doc/README.dosfsck \ + doc/README.dosfstools-2.x \ + doc/README.mkdosfs \ + doc/TODO.dosfstools-2.x diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..cdf231c --- /dev/null +++ b/NEWS @@ -0,0 +1,76 @@ +dosfstools 4.0 - released 2016-05-06 +==================================== + +The programs are now portable to non-Linux operating systems. To that end, the +build system has been converted to use autotools. There have been Linux +specifics in a lot of places which have been either eliminated or should have +equivalents so that it should now work in other Unix-like environments. It has +been tested on FreeBSD and OS X. + +As part of making it portable all the code that assumed 8 bit major/minor +numbers - and in fact masked out all other bits - has been cleaned up. Now +mkfs.vfat should not misidentify devices anymore and require the -I option to +override. The new device probing uses libudev (if available) to collect more +information. + +Fixed data corruption errors in fsck.fat: Writing to the third to last cluster +on FAT12 with an odd number of clusters would corrupt the following cluster. In +mkfs.fat, long existing bugs in bad cluster marking (from scanning or user +supplied bad blocks list) were fixed so that it actually marks the correct +clusters. + +The automatic alignment of data clusters that was added in 3.0.8 and broken for +FAT32 starting with 3.0.20 has been reinstated. If you need to create file +systems for finicky devices that have broken FAT implementations use the option +-a to disable alignment. + + +dosfstools 3.0.28 - released 2015-05-16 +======================================= + +The major user visible change in this release is that fsck.fat now defaults to +interactive repair mode which previously had to be selected with -r. The +previous default of a read only check mode was confusing to users who had to +repeat a potentially lengthy fsck.fat run with the right option in order to +actually fix their file system. It was also pointless – the interactive repair +mode already won't write anything without asking for confirmation. + +mkfs.fat now allows choosing 0xF0 as the media byte which was previously +rejected. + +mkfs.fat now supports the --invariant option to facilitate testing mkfs.fat +itself. It will reproducibly generate filesystems without random or time based +differences between them when all else is identical. + +Bugs fixed in fsck.fat are a read one byte beyond the end of an allocated array +when checking some FAT12 filesystems, and checking that the first cluster of a +file as specified in the directory entry is not 1. Previously it could attempt +to follow a block chain starting on cluster 1 and segfault when the conditions +are right. + + +dosfstools 3.0.27 - released 2014-11-12 +======================================= + +This is a pure bug fix release. The major bugs fixed: + +* fatlabel did not recognize long file names and mistook long file name + segments in the root directory for labels. This caused output of garbage when + asked to print the label and damage to the root directory (loss of long file + name after fsck) when used to set the label. + +* A fsck.fat check introduced in 3.0.26 triggered use of uninitialized fields + in the constructed root directory entry, which randomly caused the code + checking file names to consider the empty "file name" of the root directory + to be bad: + + $ /sbin/fsck.fat -y bad.img + fsck.fat 3.0.26 (2014-03-07) + / + Bad short file name (). + Auto-renaming it. + Renamed to + bad.img: 14 files, 19388/403266 clusters + +* And finally fsck.fat will not print the version string anymore every time the + -v option is encountered. diff --git a/README b/README new file mode 100644 index 0000000..8fe8249 --- /dev/null +++ b/README @@ -0,0 +1,39 @@ +dosfstools consists of the programs mkfs.fat, fsck.fat and fatlabel to create, +check and label file systems of the FAT family. The dosfstools are licensed +under the GNU GPL version 3 or later. See the file COPYING for details. + + +### Build Requirements + +dosfstools recommends libudev. It is used in mkfs.fat to collect additional +information about the device to format in order to refuse potentially unsafe +operations without additional confirmation. + + +### Installing + +dosfstools are built using an autoconf/automake system, so the standard method +applies: + + ./configure + make + make install + +You need to have superuser privileges in order to install into the standard +system wide locations. + +The ./configure script has an option --enable-compat-symlinks that will +configure the build to symlink older names of the tools to the current ones on +installation. These are dosfsck, fsck.msdos and fsck.vfat for fsck.fat, mkdosfs, +mkfs.msdos and mkfs.vfat for mkfs.fat and dosfslabel for fatlabel. + + +### Building from the VCS repository + +If you are working directly from a git clone of the official dosfstools +repository, you will find that you can not run "./configure" straight away +because it, like other autogenerated files for the build system, is not included +in the repository. + +First, autoconf and automake have to be installed. Then you can run +"autoreconf -i" to generate all the required files. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f397895 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +dosfstools consists of the programs mkfs.fat, fsck.fat and fatlabel to create, +check and label file systems of the FAT family. The dosfstools are licensed +under the GNU GPL version 3 or later. See the file `COPYING` for details. + + +### Build Requirements + +dosfstools recommends libudev. It is used in mkfs.fat to collect additional +information about the device to format in order to refuse potentially unsafe +operations without additional confirmation. + + +### Installing + +dosfstools are built using an autoconf/automake system, so the standard method +applies: + +``` +./configure +make +make install +``` + +You need to have superuser privileges in order to install into the standard +system wide locations. + +The `./configure` script has an option `--enable-compat-symlinks` that will +configure the build to symlink older names of the tools to the current ones on +installation. These are `dosfsck`, `fsck.msdos` and `fsck.vfat` for `fsck.fat`, +`mkdosfs`, `mkfs.msdos` and `mkfs.vfat` for `mkfs.fat` and `dosfslabel` for +`fatlabel`. + + +### Building from the VCS repository + +If you are working directly from a git clone of the official dosfstools +repository, you will find that you can not run `./configure` straight away +because it, like other autogenerated files for the build system, is not included +in the repository. + +First, autoconf and automake have to be installed. Then you can run `autoreconf +-i` to generate all the required files. diff --git a/VERSION b/VERSION deleted file mode 100644 index 0baec4d..0000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -3.0.28 diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..4d4e522 --- /dev/null +++ b/configure.ac @@ -0,0 +1,67 @@ +# configure.ac for dosfstools +# Copyright (C) 2015 Andreas Bombe +# +# 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 . + +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 ]]) +AC_CHECK_DECLS([getmntinfo], [], [], [[#include ]]) + +AC_ARG_WITH([udev], AS_HELP_STRING([--without-udev], [build without libudev support])) +if test "x$with_udev" != "xno"; then + PKG_CHECK_MODULES([UDEV], [libudev], + [AC_DEFINE([HAVE_UDEV], [1])], + [true]) +fi + +AC_SEARCH_LIBS(iconv_open, iconv) + +AC_CONFIG_FILES([Makefile src/Makefile src/version.h + manpages/Makefile manpages/mkfs.fat.8 + manpages/fsck.fat.8 manpages/fatlabel.8]) +AC_OUTPUT diff --git a/manpages/Makefile b/manpages/Makefile deleted file mode 100644 index ee8a478..0000000 --- a/manpages/Makefile +++ /dev/null @@ -1,50 +0,0 @@ -# Makefile - -## dosfstools(7) -## Copyright (C) 2006-2014 Daniel Baumann -## -## This program comes with ABSOLUTELY NO WARRANTY; for details see COPYING. -## This is free software, and you are welcome to redistribute it -## under certain conditions; see COPYING for details. - - -SHELL := sh -e - -LANGUAGES = $(shell cd po && ls) - -all: build - -po4a.cfg: - echo "[po4a_langs] $(LANGUAGES)" > po4a.cfg - echo "[po4a_paths] pot/\$$master.pot \$$lang:po/\$$lang/\$$master.po" >> po4a.cfg - - for MANPAGE in en/*; \ - do \ - SECTION="$$(basename $${MANPAGE} | sed -e 's|\.|\n|g' | tail -n1)"; \ - echo "[type: man] $${MANPAGE} \$$lang:\$$lang/$$(basename $${MANPAGE} .$${SECTION}).\$$lang.$${SECTION}" >> po4a.cfg; \ - done - -update: - ./bin/update-version.sh - -build: po4a.cfg - @if [ ! -x "$$(which po4a 2>/dev/null)" ]; \ - then \ - echo "E: po4a - command not found"; \ - echo "I: po4a can be obtained from:"; \ - echo "I: http://po4a.alioth.debian.org/"; \ - echo "I: On Debian based systems, po4a can be installed with:"; \ - echo "I: apt-get install po4a"; \ - exit 1; \ - fi - - po4a --keep 0 --no-backups -o untranslated=MT,ME \ - --package-name dosfstools po4a.cfg - -clean: - rm -rf $(LANGUAGES) - -distclean: clean - rm -f po4a.cfg - -rebuild: distclean update build diff --git a/manpages/Makefile.am b/manpages/Makefile.am new file mode 100644 index 0000000..5473a7f --- /dev/null +++ b/manpages/Makefile.am @@ -0,0 +1,38 @@ +# dosfstools manpages/Makefile.am +# Copyright (C) 2015 Andreas Bombe +# +# 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 . + +man_MANS = fsck.fat.8 mkfs.fat.8 fatlabel.8 + + +if COMPAT_SYMLINKS +install-data-hook: + cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f fatlabel.8 dosfslabel.8 + cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f fsck.fat.8 dosfsck.8 + cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f fsck.fat.8 fsck.msdos.8 + cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f fsck.fat.8 fsck.vfat.8 + cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f mkfs.fat.8 mkdosfs.8 + cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f mkfs.fat.8 mkfs.msdos.8 + cd $(DESTDIR)$(mandir)/man8 && $(LN_S) -f mkfs.fat.8 mkfs.vfat.8 + +uninstall-hook: + $(RM) $(DESTDIR)$(mandir)/man8/dosfslabel.8 + $(RM) $(DESTDIR)$(mandir)/man8/dosfsck.8 + $(RM) $(DESTDIR)$(mandir)/man8/fsck.msdos.8 + $(RM) $(DESTDIR)$(mandir)/man8/fsck.vfat.8 + $(RM) $(DESTDIR)$(mandir)/man8/mkdosfs.8 + $(RM) $(DESTDIR)$(mandir)/man8/mkfs.msdos.8 + $(RM) $(DESTDIR)$(mandir)/man8/mkfs.vfat.8 +endif diff --git a/manpages/bin/update-version.sh b/manpages/bin/update-version.sh deleted file mode 100755 index 48e9c08..0000000 --- a/manpages/bin/update-version.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/sh - -## dosfstools(7) -## Copyright (C) 2006-2014 Daniel Baumann -## -## This program comes with ABSOLUTELY NO WARRANTY; for details see COPYING. -## This is free software, and you are welcome to redistribute it -## under certain conditions; see COPYING for details. - - -set -e - -PROJECT="dosfstools" -VERSION="$(cat ../VERSION)" - -DATE="$(LC_ALL=C date +%Y\\\\-%m\\\\-%d)" - -DAY="$(LC_ALL=C date +%d)" -MONTH="$(LC_ALL=C date +%m)" -YEAR="$(LC_ALL=C date +%Y)" - -echo "Updating version headers..." - -for MANPAGE in en/* -do - PROGRAM="$(basename ${MANPAGE} | sed -e 's|\(.*\).[0-9]$|\1|' | tr [a-z] [A-Z])" - SECTION="$(basename ${MANPAGE} | sed -e 's|.*.\([0-9]\)$|\1|')" - - sed -i -e "s|^.TH.*$|.TH ${PROGRAM} ${SECTION} ${DATE} ${VERSION} \"${PROJECT}\"|" ${MANPAGE} -done - -# European date format -for _LANGUAGE in de es fr it -do - if ls po/${_LANGUAGE}/*.po > /dev/null 2>&1 - then - for _FILE in po/${_LANGUAGE}/*.po - do - sed -i -e "s|^msgstr .*.2014-.*$|msgstr \"${DAY}.${MONTH}.${YEAR}\"|g" \ - -e "s|^msgstr .*.2014\"$|msgstr \"${DAY}.${MONTH}.${YEAR}\"|g" \ - "${_FILE}" - done - fi -done - -# Brazilian date format -if ls po/pt_BR/*.po > /dev/null 2>&1 -then - for _FILE in po/pt_BR/*.po - do - sed -i -e "s|^msgstr .*.2014-.*$|msgstr \"${DAY}-${MONTH}-${YEAR}\"|g" \ - -e "s|^msgstr .*-2014\"$|msgstr \"${DAY}-${MONTH}-${YEAR}\"|g" \ - "${_FILE}" - done -fi diff --git a/manpages/en/fatlabel.8 b/manpages/fatlabel.8.in similarity index 97% rename from manpages/en/fatlabel.8 rename to manpages/fatlabel.8.in index c00a795..bf5ebbd 100644 --- a/manpages/en/fatlabel.8 +++ b/manpages/fatlabel.8.in @@ -19,7 +19,7 @@ .\" can be found in /usr/share/common-licenses/GPL-3 file. .\" .\" -.TH FATLABEL 8 2015\-05\-16 3.0.28 "dosfstools" +.TH FATLABEL 8 2015\-04\-16 "dosfstools @PACKAGE_VERSION@" .SH NAME \fBfatlabel\fR \- set or get MS\-DOS filesystem label .\" ---------------------------------------------------------------------------- diff --git a/manpages/en/fsck.fat.8 b/manpages/fsck.fat.8.in similarity index 97% rename from manpages/en/fsck.fat.8 rename to manpages/fsck.fat.8.in index f2d44d0..06057a8 100644 --- a/manpages/en/fsck.fat.8 +++ b/manpages/fsck.fat.8.in @@ -19,7 +19,7 @@ .\" can be found in /usr/share/common-licenses/GPL-3 file. .\" .\" -.TH FSCK.FAT 8 2015\-05\-16 3.0.28 "dosfstools" +.TH FSCK.FAT 8 2015\-04\-16 "dosfstools @PACKAGE_VERSION@" .SH NAME \fBfsck.fat\fR \- check and repair MS\-DOS filesystems .\" ---------------------------------------------------------------------------- @@ -115,6 +115,9 @@ MS\-DOS uses only 0xfff7 for bad clusters, where on Atari values 0xfff0...0xfff7 are for this purpose (but the standard value is still 0xfff7). .IP "\fB-b\fR" 4 Make read-only boot sector check. +.IP "\fB-c\fR \fIPAGE\fR" 4 +Use DOS codepage \fIPAGE\fR to decode short file names. +By default codepage 437 is used. .IP "\fB\-d\fR \fIPATH\fR" 4 Delete the specified file. If more than one file with that name exist, the first one is deleted. diff --git a/manpages/en/mkfs.fat.8 b/manpages/mkfs.fat.8.in similarity index 97% rename from manpages/en/mkfs.fat.8 rename to manpages/mkfs.fat.8.in index 5a5086e..2d19daf 100644 --- a/manpages/en/mkfs.fat.8 +++ b/manpages/mkfs.fat.8.in @@ -1,6 +1,7 @@ .\" mkfs.fat.8 - manpage for fs.fatck .\" .\" Copyright (C) 2006-2014 Daniel Baumann +.\" Copyright (C) 2016 Andreas Bombe .\" .\" This program is free software: you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by @@ -19,7 +20,7 @@ .\" can be found in /usr/share/common-licenses/GPL-3 file. .\" .\" -.TH MKFS.FAT 8 2015\-05\-16 3.0.28 "dosfstools" +.TH MKFS.FAT 8 2016\-01\-25 "dosfstools @PACKAGE_VERSION@" .SH NAME \fBmkfs.fat\fR \- create an MS-DOS filesystem under Linux .\" ---------------------------------------------------------------------------- @@ -135,6 +136,8 @@ Must be a power of 2, i.e. 1, 2, 4, 8, ... 128. Specify the number of bytes per logical sector. Must be a power of 2 and greater than or equal to 512, i.e. 512, 1024, 2048, 4096, 8192, 16384, or 32768. +Values larger than 4096 are not conforming to the FAT file system specification +and may not work everywhere. .IP "\fB\-v\fR" 4 Verbose execution. .IP "\fB\-\-invariant\fR" 4 diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..3d22ba7 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,63 @@ +# dosfstools src/Makefile.am +# Copyright (C) 2015 Andreas Bombe +# +# 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 . + +AM_CFLAGS = -Wall -Wextra -Wno-sign-compare -Wno-missing-field-initializers \ + -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings + +sbin_PROGRAMS = fsck.fat mkfs.fat fatlabel +noinst_PROGRAMS = testdevinfo + +fscklabel_common_sources = boot.c boot.h check.c check.h common.c common.h \ + fat.c fat.h file.c file.h io.c io.h lfn.c lfn.h \ + charconv.c charconv.h msdos_fs.h \ + fsck.fat.h endian_compat.h +fsck_fat_SOURCES = fsck.fat.c $(fscklabel_common_sources) +fatlabel_SOURCES = fatlabel.c $(fscklabel_common_sources) + +mkfs_common_sources = device_info.c device_info.h \ + blkdev/blkdev.c blkdev/blkdev.h \ + endian_compat.h \ + blkdev/linux_version.c blkdev/linux_version.h +mkfs_fat_SOURCES = mkfs.fat.c msdos_fs.h $(mkfs_common_sources) +mkfs_fat_CPPFLAGS = -I$(srcdir)/blkdev +mkfs_fat_CFLAGS = $(AM_CFLAGS) $(UDEV_CFLAGS) +mkfs_fat_LDFLAGS = $(UDEV_LIBS) + +testdevinfo_SOURCES = testdevinfo.c $(mkfs_common_sources) +testdevinfo_CPPFLAGS = -I$(srcdir)/blkdev +testdevinfo_CFLAGS = $(AM_CFLAGS) $(UDEV_CFLAGS) +testdevinfo_LDFLAGS = $(UDEV_LIBS) + + +if COMPAT_SYMLINKS +install-exec-hook: + cd $(DESTDIR)$(sbindir) && $(LN_S) -f fatlabel dosfslabel + cd $(DESTDIR)$(sbindir) && $(LN_S) -f fsck.fat dosfsck + cd $(DESTDIR)$(sbindir) && $(LN_S) -f fsck.fat fsck.msdos + cd $(DESTDIR)$(sbindir) && $(LN_S) -f fsck.fat fsck.vfat + cd $(DESTDIR)$(sbindir) && $(LN_S) -f mkfs.fat mkdosfs + cd $(DESTDIR)$(sbindir) && $(LN_S) -f mkfs.fat mkfs.msdos + cd $(DESTDIR)$(sbindir) && $(LN_S) -f mkfs.fat mkfs.vfat + +uninstall-hook: + $(RM) $(DESTDIR)$(sbindir)/dosfslabel + $(RM) $(DESTDIR)$(sbindir)/dosfsck + $(RM) $(DESTDIR)$(sbindir)/fsck.msdos + $(RM) $(DESTDIR)$(sbindir)/fsck.vfat + $(RM) $(DESTDIR)$(sbindir)/mkdosfs + $(RM) $(DESTDIR)$(sbindir)/mkfs.msdos + $(RM) $(DESTDIR)$(sbindir)/mkfs.vfat +endif diff --git a/src/blkdev/README b/src/blkdev/README new file mode 100644 index 0000000..af74eb7 --- /dev/null +++ b/src/blkdev/README @@ -0,0 +1,3 @@ +The source files blkdev.[ch] and linux_version.[ch] have been taken from +util-linux (git://git.kernel.org/pub/scm/utils/util-linux/util-linux.git) +git revision 42f536ee8. diff --git a/src/blkdev/blkdev.c b/src/blkdev/blkdev.c new file mode 100644 index 0000000..ae9c8d1 --- /dev/null +++ b/src/blkdev/blkdev.c @@ -0,0 +1,376 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak + */ +#include +#include +#include +#include +#include + +#ifdef HAVE_LINUX_HDREG_H +#include +#endif + +#ifdef HAVE_LINUX_FD_H +#include +#endif + +#ifdef HAVE_SYS_DISKLABEL_H +#include +#endif + +#ifdef HAVE_SYS_DISK_H +# ifdef HAVE_SYS_QUEUE_H +# include /* for LIST_HEAD */ +# endif +# include +#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, §or_size) >= 0) + return 0; + return -1; +#else + (void)fd; /* prevent unused parameter warning */ + *sector_size = DEFAULT_SECTOR_SIZE; + return 0; +#endif +} + +/* + * Return the alignment status of a device + */ +int blkdev_is_misaligned(int fd) +{ +#ifdef BLKALIGNOFF + int aligned; + + if (ioctl(fd, BLKALIGNOFF, &aligned) < 0) + return 0; /* probably kernel < 2.6.32 */ + /* + * Note that kernel returns -1 as alignement offset if no compatible + * sizes and alignments exist for stacked devices + */ + return aligned != 0 ? 1 : 0; +#else + (void)fd; /* prevent unused parameter warning */ + return 0; +#endif +} + +int blkdev_is_cdrom(int fd) +{ +#ifdef CDROM_GET_CAPABILITY + int ret; + + if ((ret = ioctl(fd, CDROM_GET_CAPABILITY, NULL)) < 0) + return 0; + else + return ret; +#else + (void)fd; /* prevent unused parameter warning */ + return 0; +#endif +} + +/* + * Get kernel's interpretation of the device's geometry. + * + * Returns the heads and sectors - but not cylinders + * as it's truncated for disks with more than 65535 tracks. + * + * Note that this is deprecated in favor of LBA addressing. + */ +int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s) +{ +#ifdef HDIO_GETGEO + { + struct hd_geometry geometry; + + if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) { + *h = geometry.heads; + *s = geometry.sectors; + return 0; + } + } +#endif + +#ifdef FDGETPRM + { + struct floppy_struct fdparam; + + if (ioctl(fd, FDGETPRM, &fdparam) == 0) { + *h = fdparam.head; + *s = fdparam.sect; + return 0; + } + } +#endif + + (void)fd; /* prevent unused parameter warning */ + *h = 0; + *s = 0; + return -1; +} + +/* + * Get start offset of partition + */ +int blkdev_get_start(int fd, unsigned int *s) +{ +#ifdef HDIO_GETGEO + struct hd_geometry geometry; + + if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) { + *s = geometry.start; + return 0; + } +#endif + + (void)fd; /* prevent unused parameter warning */ + *s = 0; + return -1; +} + +/* + * Convert scsi type to human readable string. + */ +const char *blkdev_scsi_type_to_name(int type) +{ + switch (type) { + case SCSI_TYPE_DISK: + return "disk"; + case SCSI_TYPE_TAPE: + return "tape"; + case SCSI_TYPE_PRINTER: + return "printer"; + case SCSI_TYPE_PROCESSOR: + return "processor"; + case SCSI_TYPE_WORM: + return "worm"; + case SCSI_TYPE_ROM: + return "rom"; + case SCSI_TYPE_SCANNER: + return "scanner"; + case SCSI_TYPE_MOD: + return "mo-disk"; + case SCSI_TYPE_MEDIUM_CHANGER: + return "changer"; + case SCSI_TYPE_COMM: + return "comm"; + case SCSI_TYPE_RAID: + return "raid"; + case SCSI_TYPE_ENCLOSURE: + return "enclosure"; + case SCSI_TYPE_RBC: + return "rbc"; + case SCSI_TYPE_OSD: + return "osd"; + case SCSI_TYPE_NO_LUN: + return "no-lun"; + default: + break; + } + return NULL; +} diff --git a/src/blkdev/blkdev.h b/src/blkdev/blkdev.h new file mode 100644 index 0000000..b9179ad --- /dev/null +++ b/src/blkdev/blkdev.h @@ -0,0 +1,149 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak + */ +#ifndef BLKDEV_H +#define BLKDEV_H + +#include +#include +#ifdef HAVE_SYS_IOCCOM_H +# include /* for _IO macro on e.g. Solaris */ +#endif +#include +#include + +#ifdef HAVE_SYS_MKDEV_H +# include /* major and minor on Solaris */ +#endif + +#define DEFAULT_SECTOR_SIZE 512 + +#ifdef __linux__ +/* very basic ioctls, should be available everywhere */ +# ifndef BLKROSET +# define BLKROSET _IO(0x12,93) /* set device read-only (0 = read-write) */ +# define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */ +# define BLKRRPART _IO(0x12,95) /* re-read partition table */ +# define BLKGETSIZE _IO(0x12,96) /* return device size /512 (long *arg) */ +# define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ +# define BLKRASET _IO(0x12,98) /* set read ahead for block device */ +# define BLKRAGET _IO(0x12,99) /* get current read ahead setting */ +# define BLKFRASET _IO(0x12,100) /* set filesystem (mm/filemap.c) read-ahead */ +# define BLKFRAGET _IO(0x12,101) /* get filesystem (mm/filemap.c) read-ahead */ +# define BLKSECTSET _IO(0x12,102) /* set max sectors per request (ll_rw_blk.c) */ +# define BLKSECTGET _IO(0x12,103) /* get max sectors per request (ll_rw_blk.c) */ +# define BLKSSZGET _IO(0x12,104) /* get block device sector size */ + +/* ioctls introduced in 2.2.16, removed in 2.5.58 */ +# define BLKELVGET _IOR(0x12,106,size_t) /* elevator get */ +# define BLKELVSET _IOW(0x12,107,size_t) /* elevator set */ + +# define BLKBSZGET _IOR(0x12,112,size_t) +# define BLKBSZSET _IOW(0x12,113,size_t) +# endif /* !BLKROSET */ + +# ifndef BLKGETSIZE64 +# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ +# endif + +/* block device topology ioctls, introduced in 2.6.32 (commit ac481c20) */ +# ifndef BLKIOMIN +# define BLKIOMIN _IO(0x12,120) +# define BLKIOOPT _IO(0x12,121) +# define BLKALIGNOFF _IO(0x12,122) +# define BLKPBSZGET _IO(0x12,123) +# endif + +/* discard zeroes support, introduced in 2.6.33 (commit 98262f27) */ +# ifndef BLKDISCARDZEROES +# define BLKDISCARDZEROES _IO(0x12,124) +# endif + +/* filesystem freeze, introduced in 2.6.29 (commit fcccf502) */ +# ifndef FIFREEZE +# define FIFREEZE _IOWR('X', 119, int) /* Freeze */ +# define FITHAW _IOWR('X', 120, int) /* Thaw */ +# endif + +/* uniform CD-ROM information */ +# ifndef CDROM_GET_CAPABILITY +# define CDROM_GET_CAPABILITY 0x5331 +# endif + +#endif /* __linux */ + + +#ifdef APPLE_DARWIN +# define BLKGETSIZE DKIOCGETBLOCKCOUNT32 +#endif + +#ifndef HDIO_GETGEO +# ifdef __linux__ +# define HDIO_GETGEO 0x0301 +# endif + +struct hd_geometry { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; /* truncated */ + unsigned long start; +}; +#endif /* HDIO_GETGEO */ + + +/* are we working with block device? */ +int is_blkdev(int fd); + +/* Determine size in bytes */ +off_t blkdev_find_size (int fd); + +/* get size in bytes */ +int blkdev_get_size(int fd, unsigned long long *bytes); + +/* get 512-byte sector count */ +int blkdev_get_sectors(int fd, unsigned long long *sectors); + +/* get hardware sector size */ +int blkdev_get_sector_size(int fd, int *sector_size); + +/* specifies whether or not the device is misaligned */ +int blkdev_is_misaligned(int fd); + +/* get physical block device size */ +int blkdev_get_physector_size(int fd, int *sector_size); + +/* is the device cdrom capable? */ +int blkdev_is_cdrom(int fd); + +/* get device's geometry - legacy */ +int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s); + +/* get partition devices start offset */ +int blkdev_get_start(int fd, unsigned int *s); + +/* SCSI device types. Copied almost as-is from kernel header. + * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/scsi/scsi.h */ +#define SCSI_TYPE_DISK 0x00 +#define SCSI_TYPE_TAPE 0x01 +#define SCSI_TYPE_PRINTER 0x02 +#define SCSI_TYPE_PROCESSOR 0x03 /* HP scanners use this */ +#define SCSI_TYPE_WORM 0x04 /* Treated as ROM by our system */ +#define SCSI_TYPE_ROM 0x05 +#define SCSI_TYPE_SCANNER 0x06 +#define SCSI_TYPE_MOD 0x07 /* Magneto-optical disk - treated as SCSI_TYPE_DISK */ +#define SCSI_TYPE_MEDIUM_CHANGER 0x08 +#define SCSI_TYPE_COMM 0x09 /* Communications device */ +#define SCSI_TYPE_RAID 0x0c +#define SCSI_TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */ +#define SCSI_TYPE_RBC 0x0e +#define SCSI_TYPE_OSD 0x11 +#define SCSI_TYPE_NO_LUN 0x7f + +/* convert scsi type code to name */ +const char *blkdev_scsi_type_to_name(int type); + + +#endif /* BLKDEV_H */ diff --git a/src/blkdev/linux_version.c b/src/blkdev/linux_version.c new file mode 100644 index 0000000..2bcc2cc --- /dev/null +++ b/src/blkdev/linux_version.c @@ -0,0 +1,25 @@ +#include +#include + +#include "linux_version.h" + +int get_linux_version (void) +{ + static int kver = -1; + struct utsname uts; + int major = 0; + int minor = 0; + int teeny = 0; + int n; + + if (kver != -1) + return kver; + if (uname (&uts)) + return kver = 0; + + n = sscanf(uts.release, "%d.%d.%d", &major, &minor, &teeny); + if (n < 1 || n > 3) + return kver = 0; + + return kver = KERNEL_VERSION(major, minor, teeny); +} diff --git a/src/blkdev/linux_version.h b/src/blkdev/linux_version.h new file mode 100644 index 0000000..a6a1e99 --- /dev/null +++ b/src/blkdev/linux_version.h @@ -0,0 +1,14 @@ +#ifndef LINUX_VERSION_H +#define LINUX_VERSION_H + +#ifdef HAVE_LINUX_VERSION_H +# include +#endif + +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +int get_linux_version(void); + +#endif /* LINUX_VERSION_H */ diff --git a/src/boot.c b/src/boot.c index 0c0918f..491ecd9 100644 --- a/src/boot.c +++ b/src/boot.c @@ -3,6 +3,7 @@ Copyright (C) 1993 Werner Almesberger Copyright (C) 1998 Roman Hodek Copyright (C) 2008-2014 Daniel Baumann + Copyright (C) 2015 Andreas Bombe 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 #include #include +#include #include #include "common.h" @@ -101,8 +103,8 @@ static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss) (unsigned long long)fs->fat_start, (unsigned long long)fs->fat_start / lss); printf("%10d FATs, %d bit entries\n", b->fats, fs->fat_bits); - printf("%10d bytes per FAT (= %u sectors)\n", fs->fat_size, - fs->fat_size / lss); + printf("%10lld bytes per FAT (= %llu sectors)\n", (long long)fs->fat_size, + (long long)fs->fat_size / lss); if (!fs->root_cluster) { printf("Root directory starts at byte %llu (sector %llu)\n", (unsigned long long)fs->root_start, @@ -115,8 +117,9 @@ static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss) printf("Data area starts at byte %llu (sector %llu)\n", (unsigned long long)fs->data_start, (unsigned long long)fs->data_start / lss); - printf("%10lu data clusters (%llu bytes)\n", (unsigned long)fs->clusters, - (unsigned long long)fs->clusters * fs->cluster_size); + printf("%10lu data clusters (%llu bytes)\n", + (unsigned long)fs->data_clusters, + (unsigned long long)fs->data_clusters * fs->cluster_size); printf("%u sectors/track, %u heads\n", le16toh(b->secs_track), le16toh(b->heads)); printf("%10u hidden sectors\n", atari_format ? @@ -155,7 +158,7 @@ static void check_backup_boot(DOS_FS * fs, struct boot_sector *b, int lss) fs->backupboot_start = bbs * lss; b->backup_boot = htole16(bbs); fs_write(fs->backupboot_start, sizeof(*b), b); - fs_write((loff_t) offsetof(struct boot_sector, backup_boot), + fs_write(offsetof(struct boot_sector, backup_boot), sizeof(b->backup_boot), &b->backup_boot); printf("Created backup of boot sector in sector %d\n", bbs); return; @@ -233,9 +236,9 @@ static void read_fsinfo(DOS_FS * fs, struct boot_sector *b, int lss) break; if (s > 0 && s < le16toh(b->reserved)) { init_fsinfo(&i); - fs_write((loff_t) s * lss, sizeof(i), &i); + fs_write((off_t)s * lss, sizeof(i), &i); b->info_sector = htole16(s); - fs_write((loff_t) offsetof(struct boot_sector, info_sector), + fs_write(offsetof(struct boot_sector, info_sector), sizeof(b->info_sector), &b->info_sector); if (fs->backupboot_start) fs_write(fs->backupboot_start + @@ -326,8 +329,9 @@ void read_boot(DOS_FS * fs) struct boot_sector b; unsigned total_sectors; unsigned short logical_sector_size, sectors; - unsigned fat_length; - loff_t data_size; + off_t fat_length; + unsigned total_fat_entries; + off_t data_size; fs_read(0, sizeof(b), &b); logical_sector_size = GET_UNALIGNED_W(b.sector_size); @@ -352,19 +356,27 @@ void read_boot(DOS_FS * fs) if (verbose) printf("Checking we can access the last sector of the filesystem\n"); /* Can't access last odd sector anyway, so round down */ - fs_test((loff_t) ((total_sectors & ~1) - 1) * (loff_t) logical_sector_size, + fs_test((off_t)((total_sectors & ~1) - 1) * logical_sector_size, logical_sector_size); + fat_length = le16toh(b.fat_length) ? le16toh(b.fat_length) : le32toh(b.fat32_length); - fs->fat_start = (loff_t) le16toh(b.reserved) * logical_sector_size; - fs->root_start = ((loff_t) le16toh(b.reserved) + b.fats * fat_length) * + if (!fat_length) + die("FAT size is zero."); + + fs->fat_start = (off_t)le16toh(b.reserved) * logical_sector_size; + fs->root_start = ((off_t)le16toh(b.reserved) + b.fats * fat_length) * logical_sector_size; fs->root_entries = GET_UNALIGNED_W(b.dir_entries); fs->data_start = fs->root_start + ROUND_TO_MULTIPLE(fs->root_entries << MSDOS_DIR_BITS, logical_sector_size); - data_size = (loff_t) total_sectors *logical_sector_size - fs->data_start; - fs->clusters = data_size / fs->cluster_size; + + data_size = (off_t)total_sectors * logical_sector_size - fs->data_start; + if (data_size < fs->cluster_size) + die("Filesystem has no space for any data clusters"); + + fs->data_clusters = data_size / fs->cluster_size; fs->root_cluster = 0; /* indicates standard, pre-FAT32 root dir */ fs->fsinfo_start = 0; /* no FSINFO structure */ fs->free_clusters = -1; /* unknown */ @@ -385,13 +397,13 @@ void read_boot(DOS_FS * fs) printf("Warning: FAT32 root dir is in a cluster chain, but " "a separate root dir\n" " area is defined. Cannot fix this easily.\n"); - if (fs->clusters < FAT16_THRESHOLD) + if (fs->data_clusters < FAT16_THRESHOLD) printf("Warning: Filesystem is FAT32 according to fat_length " "and fat32_length fields,\n" " but has only %lu clusters, less than the required " "minimum of %d.\n" " This may lead to problems on some systems.\n", - (unsigned long)fs->clusters, FAT16_THRESHOLD); + (unsigned long)fs->data_clusters, FAT16_THRESHOLD); check_fat_state_bit(fs, &b); fs->backupboot_start = le16toh(b.backup_boot) * logical_sector_size; @@ -401,9 +413,9 @@ void read_boot(DOS_FS * fs) } else if (!atari_format) { /* On real MS-DOS, a 16 bit FAT is used whenever there would be too * much clusers otherwise. */ - fs->fat_bits = (fs->clusters >= FAT12_THRESHOLD) ? 16 : 12; - if (fs->clusters >= FAT16_THRESHOLD) - die("Too many clusters (%lu) for FAT16 filesystem.", fs->clusters); + fs->fat_bits = (fs->data_clusters >= FAT12_THRESHOLD) ? 16 : 12; + if (fs->data_clusters >= FAT16_THRESHOLD) + die("Too many clusters (%lu) for FAT16 filesystem.", fs->data_clusters); check_fat_state_bit(fs, &b); } else { /* On Atari, things are more difficult: GEMDOS always uses 12bit FATs @@ -411,14 +423,10 @@ void read_boot(DOS_FS * fs) fs->fat_bits = 16; /* assume 16 bit FAT for now */ /* If more clusters than fat entries in 16-bit fat, we assume * it's a real MSDOS FS with 12-bit fat. */ - if (fs->clusters + 2 > fat_length * logical_sector_size * 8 / 16 || - /* if it's a floppy disk --> 12bit fat */ - device_no == 2 || - /* if it's a ramdisk or loopback device and has one of the usual - * floppy sizes -> 12bit FAT */ - ((device_no == 1 || device_no == 7) && - (total_sectors == 720 || total_sectors == 1440 || - total_sectors == 2880))) + if (fs->data_clusters + 2 > fat_length * logical_sector_size * 8 / 16 || + /* if it has one of the usual floppy sizes -> 12bit FAT */ + (total_sectors == 720 || total_sectors == 1440 || + total_sectors == 2880)) fs->fat_bits = 12; } /* On FAT32, the high 4 bits of a FAT entry are reserved */ @@ -439,11 +447,10 @@ void read_boot(DOS_FS * fs) fs->label = NULL; } - if (fs->clusters > - ((uint64_t)fs->fat_size * 8 / fs->fat_bits) - 2) - die("Filesystem has %d clusters but only space for %d FAT entries.", - fs->clusters, - ((unsigned long long)fs->fat_size * 8 / fs->fat_bits) - 2); + total_fat_entries = (uint64_t)fs->fat_size * 8 / fs->fat_bits; + if (fs->data_clusters > total_fat_entries - 2) + die("Filesystem has %u clusters but only space for %u FAT entries.", + fs->data_clusters, total_fat_entries - 2); if (!fs->root_entries && !fs->root_cluster) die("Root directory has zero size."); if (fs->root_entries & (MSDOS_DPS - 1)) @@ -491,10 +498,10 @@ static void write_boot_label(DOS_FS * fs, char *label) } } -loff_t find_volume_de(DOS_FS * fs, DIR_ENT * de) +off_t find_volume_de(DOS_FS * fs, DIR_ENT * de) { uint32_t cluster; - loff_t offset; + off_t offset; int i; if (fs->root_cluster) { @@ -525,7 +532,7 @@ static void write_volume_label(DOS_FS * fs, char *label) { time_t now = time(NULL); struct tm *mtime = localtime(&now); - loff_t offset; + off_t offset; int created; DIR_ENT de; diff --git a/src/boot.h b/src/boot.h index d52e624..dd9404f 100644 --- a/src/boot.h +++ b/src/boot.h @@ -25,7 +25,7 @@ void read_boot(DOS_FS * fs); void write_label(DOS_FS * fs, char *label); -loff_t find_volume_de(DOS_FS * fs, DIR_ENT * de); +off_t find_volume_de(DOS_FS * fs, DIR_ENT * de); /* Reads the boot sector from the currently open device and initializes *FS */ diff --git a/src/check.c b/src/check.c index d8b9d72..59d6d27 100644 --- a/src/check.c +++ b/src/check.c @@ -3,6 +3,7 @@ Copyright (C) 1993 Werner Almesberger Copyright (C) 1998 Roman Hodek Copyright (C) 2008-2014 Daniel Baumann + Copyright (C) 2015 Andreas Bombe 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 #include #include -#include #include #include "common.h" @@ -38,6 +38,10 @@ #include "lfn.h" #include "check.h" + +/* the longest path on the filesystem that can be handled by path_name() */ +#define PATH_NAME_MAX 1023 + static DOS_FILE *root; /* get start field of a dir entry */ @@ -56,7 +60,7 @@ static DOS_FILE *root; #define MODIFY_START(p,v,fs) \ do { \ - uint32_t __v = (v); \ + uint32_t __v = (v); \ if (!p->offset) { \ /* writing to fake entry for FAT32 root dir */ \ if (!__v) die("Oops, deleting FAT32 root dir!"); \ @@ -64,7 +68,7 @@ static DOS_FILE *root; p->dir_ent.start = htole16(__v&0xffff); \ p->dir_ent.starthi = htole16(__v>>16); \ __v = htole32(__v); \ - fs_write((loff_t)offsetof(struct boot_sector,root_cluster), \ + fs_write(offsetof(struct boot_sector,root_cluster), \ sizeof(((struct boot_sector *)0)->root_cluster), \ &__v); \ } \ @@ -75,16 +79,16 @@ static DOS_FILE *root; } \ } while(0) -loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern) +off_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern) { static int curr_num = 0; - loff_t offset; + off_t offset; if (fs->root_cluster) { DIR_ENT d2; int i = 0, got = 0; uint32_t clu_num, prev = 0; - loff_t offset2; + off_t offset2; clu_num = fs->root_cluster; offset = cluster_start(fs, clu_num); @@ -111,7 +115,7 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern) for (clu_num = prev + 1; clu_num != prev; clu_num++) { FAT_ENTRY entry; - if (clu_num >= fs->clusters + 2) + if (clu_num >= fs->data_clusters + 2) clu_num = 2; get_fat(&entry, fs->fat, clu_num, fs); if (!entry.value) @@ -132,8 +136,7 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern) while (1) { char expanded[12]; sprintf(expanded, pattern, curr_num); - memcpy(de->name, expanded, 8); - memcpy(de->ext, expanded + 8, 3); + memcpy(de->name, expanded, MSDOS_NAME); clu_num = fs->root_cluster; i = 0; offset2 = cluster_start(fs, clu_num); @@ -177,8 +180,7 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern) while (1) { char expanded[12]; sprintf(expanded, pattern, curr_num); - memcpy(de->name, expanded, 8); - memcpy(de->ext, expanded + 8, 3); + memcpy(de->name, expanded, MSDOS_NAME); for (scan = 0; scan < fs->root_entries; scan++) if (scan != next_free && !strncmp((const char *)root[scan].name, @@ -205,12 +207,12 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern) */ static char *path_name(DOS_FILE * file) { - static char path[PATH_MAX * 2]; + static char path[PATH_NAME_MAX * 2]; if (!file) *path = 0; /* Reached the root directory */ else { - if (strlen(path_name(file->parent)) > PATH_MAX) + if (strlen(path_name(file->parent)) > PATH_NAME_MAX) die("Path name too long."); if (strcmp(path, "/") != 0) strcat(path, "/"); @@ -224,9 +226,9 @@ static char *path_name(DOS_FILE * file) return path; } -static int day_n[] = - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 }; - /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ +static const int day_n[] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 }; +/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ @@ -236,6 +238,10 @@ static time_t date_dos2unix(unsigned short time, unsigned short date) time_t secs; month = ((date >> 5) & 15) - 1; + if (month < 0) { + /* make sure that nothing bad happens if the month bits were zero */ + month = 0; + } year = date >> 9; secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + @@ -265,7 +271,7 @@ static int bad_name(DOS_FILE * file) int i, spc, suspicious = 0; const char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:"; const unsigned char *name = file->dir_ent.name; - const unsigned char *ext = file->dir_ent.ext; + const unsigned char *ext = name + 8; /* Do not complain about (and auto-correct) the extended attribute files * of OS/2. */ @@ -283,7 +289,7 @@ static int bad_name(DOS_FILE * file) if (file->dir_ent.lcase & FAT_NO_83NAME) return 0; - for (i = 0; i < 8; i++) { + for (i = 0; i < MSDOS_NAME; i++) { if (name[i] < ' ' || name[i] == 0x7f) return 1; if (name[i] > 0x7f) @@ -292,15 +298,6 @@ static int bad_name(DOS_FILE * file) return 1; } - for (i = 0; i < 3; i++) { - if (ext[i] < ' ' || ext[i] == 0x7f) - return 1; - if (ext[i] > 0x7f) - ++suspicious; - if (strchr(bad_chars, ext[i])) - return 1; - } - spc = 0; for (i = 0; i < 8; i++) { if (name[i] == ' ') @@ -332,7 +329,7 @@ static int bad_name(DOS_FILE * file) return 0; } -static void lfn_remove(loff_t from, loff_t to) +static void lfn_remove(off_t from, off_t to) { DIR_ENT empty; @@ -356,7 +353,7 @@ static void drop_file(DOS_FS * fs, DOS_FILE * file) if (file->lfn) lfn_remove(file->lfn_offset, file->offset); for (cluster = FSTART(file, fs); cluster > 0 && cluster < - fs->clusters + 2; cluster = next_cluster(fs, cluster)) + fs->data_clusters + 2; cluster = next_cluster(fs, cluster)) set_owner(fs, cluster, NULL); --n_files; } @@ -392,8 +389,7 @@ static void auto_rename(DOS_FILE * file) char num[8]; sprintf(num, "%07lu", (unsigned long)number); memcpy(file->dir_ent.name, "FSCK", 4); - memcpy(file->dir_ent.name + 4, num, 4); - memcpy(file->dir_ent.ext, num + 4, 3); + memcpy(file->dir_ent.name + 4, num, 7); for (walk = first; walk; walk = walk->next) if (walk != file && !strncmp((const char *)walk->dir_ent.name, @@ -406,7 +402,7 @@ static void auto_rename(DOS_FILE * file) file->dir_ent.lcase &= ~FAT_NO_83NAME; /* reset the attributes, only keep DIR and VOLUME */ file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME); - fs_write(file->offset, MSDOS_NAME + 2, file->dir_ent.name); + fs_write(file->offset, MSDOS_NAME + 2, &file->dir_ent); } else { fs_write(file->offset, MSDOS_NAME, file->dir_ent.name); } @@ -449,7 +445,7 @@ static void rename_file(DOS_FILE * file) file->dir_ent.lcase &= ~FAT_NO_83NAME; /* reset the attributes, only keep DIR and VOLUME */ file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME); - fs_write(file->offset, MSDOS_NAME + 2, file->dir_ent.name); + fs_write(file->offset, MSDOS_NAME + 2, &file->dir_ent); } else { fs_write(file->offset, MSDOS_NAME, file->dir_ent.name); } @@ -552,13 +548,15 @@ static int check_file(DOS_FS * fs, DOS_FILE * file) die("Bad FAT32 root directory! (bad start cluster 1)\n"); MODIFY_START(file, 0, fs); } - if (FSTART(file, fs) >= fs->clusters + 2) { + if (FSTART(file, fs) >= fs->data_clusters + 2) { printf ("%s\n Start cluster beyond limit (%lu > %lu). Truncating file.\n", - path_name(file), (unsigned long)FSTART(file, fs), (unsigned long)(fs->clusters + 1)); + path_name(file), (unsigned long)FSTART(file, fs), + (unsigned long)(fs->data_clusters + 1)); if (!file->offset) die("Bad FAT32 root directory! (start cluster beyond limit: %lu > %lu)\n", - (unsigned long)FSTART(file, fs), (unsigned long)(fs->clusters + 1)); + (unsigned long)FSTART(file, fs), + (unsigned long)(fs->data_clusters + 1)); MODIFY_START(file, 0, fs); } clusters = prev = 0; @@ -581,10 +579,10 @@ static int check_file(DOS_FS * fs, DOS_FILE * file) if (!(file->dir_ent.attr & ATTR_DIR) && le32toh(file->dir_ent.size) <= (uint64_t)clusters * fs->cluster_size) { printf - ("%s\n File size is %u bytes, cluster chain length is > %lu " + ("%s\n File size is %u bytes, cluster chain length is > %llu " "bytes.\n Truncating file to %u bytes.\n", path_name(file), le32toh(file->dir_ent.size), - (uint64_t)clusters * fs->cluster_size, + (unsigned long long)clusters * fs->cluster_size, le32toh(file->dir_ent.size)); truncate_file(fs, file, clusters); break; @@ -844,7 +842,7 @@ static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test) uint32_t walk, prev, clusters, next_clu; prev = clusters = 0; - for (walk = FSTART(file, fs); walk > 1 && walk < fs->clusters + 2; + for (walk = FSTART(file, fs); walk > 1 && walk < fs->data_clusters + 2; walk = next_clu) { next_clu = next_cluster(fs, walk); @@ -885,7 +883,7 @@ static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test) set_owner(fs, walk, file); } /* Revert ownership (for now) */ - for (walk = FSTART(file, fs); walk > 1 && walk < fs->clusters + 2; + for (walk = FSTART(file, fs); walk > 1 && walk < fs->data_clusters + 2; walk = next_cluster(fs, walk)) if (bad_cluster(fs, walk)) break; @@ -905,7 +903,7 @@ static void undelete(DOS_FS * fs, DOS_FILE * file) walk = FSTART(file, fs); - while (left && (walk >= 2) && (walk < fs->clusters + 2)) { + while (left && (walk >= 2) && (walk < fs->data_clusters + 2)) { FAT_ENTRY curEntry; get_fat(&curEntry, fs->fat, walk, fs); @@ -948,7 +946,7 @@ static void new_dir(void) * @param cp */ static void add_file(DOS_FS * fs, DOS_FILE *** chain, DOS_FILE * parent, - loff_t offset, FDSC ** cp) + off_t offset, FDSC ** cp) { DOS_FILE *new; DIR_ENT de; diff --git a/src/check.h b/src/check.h index fcb6bea..933bbf4 100644 --- a/src/check.h +++ b/src/check.h @@ -23,7 +23,7 @@ #ifndef _CHECK_H #define _CHECK_H -loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern); +off_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern); /* Allocate a free slot in the root directory for a new file. The file name is constructed after 'pattern', which must include a %d type format for printf diff --git a/src/device_info.c b/src/device_info.c new file mode 100644 index 0000000..f5d11ac --- /dev/null +++ b/src/device_info.c @@ -0,0 +1,332 @@ +/* device_info.c - Collect device information for mkfs.fat + + Copyright (C) 2015 Andreas Bombe + + 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 . +*/ + + +#include +#include +#include +#include +#include + +#ifdef HAVE_UDEV +#include +#endif + +#if HAVE_DECL_GETMNTENT +#include +#include +#endif + +#if HAVE_DECL_GETMNTINFO +#include +#include +#include +#endif + +#include +#include +#include +#include +#include + +#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, §ors) + && heads && sectors) { + info->geom_heads = heads; + info->geom_sectors = sectors; + } + + if (!blkdev_get_start(fd, &start)) + info->geom_start = start; +} + + +static void get_sector_size(struct device_info *info, int fd) +{ + int size; + + if (!blkdev_get_sector_size(fd, &size)) + info->sector_size = size; +} + + +static int udev_fill_info(struct device_info *info, struct stat *stat); + +#ifdef HAVE_UDEV +static int udev_fill_info(struct device_info *info, struct stat *stat) +{ + struct udev *ctx; + struct udev_device *dev, *parent; + struct udev_enumerate *uenum; + const char *attr; + char holders_path[PATH_MAX + 1]; + DIR *holders_dir; + struct dirent *dir_entry; + unsigned long number; + char *endptr; + + if (device_info_verbose >= 3) + printf("udev_fill_info()\n"); + + ctx = udev_new(); + if (!ctx) { + if (device_info_verbose) + printf("no udev library context\n"); + return -1; + } + + dev = udev_device_new_from_devnum(ctx, 'b', stat->st_rdev); + if (!dev) { + if (device_info_verbose) + printf("no udev context\n"); + udev_unref(ctx); + return -1; + } + + /* + * first, look for for dependent devices (partitions or virtual mappings on + * this device) + */ + if (device_info_verbose >= 3) + printf("looking for dependent devices\n"); + + uenum = udev_enumerate_new(ctx); + if (uenum) { + struct udev_list_entry *entry; + if (udev_enumerate_add_match_parent(uenum, dev) >= 0 && + udev_enumerate_scan_devices(uenum) >= 0) { + entry = udev_enumerate_get_list_entry(uenum); + if (entry) { + /* + * the list of children includes the parent device, so make + * sure that has_children is -1 to end up with the correct + * count + */ + info->has_children = -1; + + while (entry) { + if (device_info_verbose >= 2) + printf("child-or-self: %s\n", udev_list_entry_get_name(entry)); + entry = udev_list_entry_get_next(entry); + info->has_children++; + } + } else + info->has_children = 0; + } + udev_enumerate_unref(uenum); + } + + /* see if the holders directory in sysfs exists and has entries */ + if (device_info_verbose >= 2) + printf("syspath: %s\n", udev_device_get_syspath(dev)); + if (info->has_children < 1 || device_info_verbose >= 3) { + snprintf(holders_path, PATH_MAX, "%s/holders", + udev_device_get_syspath(dev)); + holders_path[PATH_MAX] = 0; + + if (info->has_children < 0) + info->has_children = 0; + + holders_dir = opendir(holders_path); + if (holders_dir) { + dir_entry = readdir(holders_dir); + while (dir_entry) { + if (dir_entry->d_reclen && dir_entry->d_name[0] != '.') { + if (device_info_verbose >= 2) + printf("holder: %s\n", dir_entry->d_name); + + info->has_children++; + + /* look up and print every holder when very verbose */ + if (device_info_verbose < 3) + break; + } + dir_entry = readdir(holders_dir); + } + + closedir(holders_dir); + } + } + + /* + * block devices on real hardware have either other block devices + * (in the case of partitions) or the actual hardware as parent + */ + parent = udev_device_get_parent(dev); + + if (!parent) { + if (device_info_verbose >= 3) + printf("no parent found, therefore virtual device\n"); + info->type = TYPE_VIRTUAL; + info->partition = 0; + udev_device_unref(dev); + return 0; + } + + attr = udev_device_get_sysattr_value(dev, "removable"); + if (device_info_verbose >= 3) { + if (attr) + printf("attribute \"removable\" is \"%s\"\n", attr); + else + printf("attribute \"removable\" not found\n"); + } + if (attr && !strcmp(attr, "1")) + info->type = TYPE_REMOVABLE; + else + info->type = TYPE_FIXED; + + attr = udev_device_get_sysattr_value(dev, "partition"); + if (attr) { + if (device_info_verbose >= 3) + printf("attribute \"partition\" is \"%s\"\n", attr); + + number = strtoul(attr, &endptr, 10); + if (!*endptr) + info->partition = number; + } else { + printf("attribute \"partition\" not found\n"); + if (info->type != TYPE_VIRTUAL && parent) { + /* partitions have other block devices as parent */ + attr = udev_device_get_subsystem(parent); + if (attr) { + if (device_info_verbose >= 3) + printf("parent subsystem is \"%s\"\n", attr); + + if (!strcmp(attr, "block")) + /* we don't know the partition number, use 1 */ + info->partition = 1; + else + info->partition = 0; + } + } + } + + udev_device_unref(dev); + udev_unref(ctx); + return 0; +} +#else /* HAVE_UDEV */ +static int udev_fill_info(struct device_info *info, struct stat *stat) +{ + /* prevent "unused parameter" warning */ + (void)stat; + (void)info; + + return -1; +} +#endif + + +int get_device_info(int fd, struct device_info *info) +{ + struct stat stat; + int ret; + + *info = device_info_clueless; + + ret = fstat(fd, &stat); + if (ret < 0) { + perror("fstat on target failed"); + return -1; + } + + if (S_ISREG(stat.st_mode)) { + /* there is nothing more to discover for an image file */ + info->type = TYPE_FILE; + info->partition = 0; + info->size = stat.st_size; + return 0; + } + + if (!S_ISBLK(stat.st_mode)) { + /* neither regular file nor block device? not usable */ + info->type = TYPE_BAD; + return 0; + } + + get_block_device_size(info, fd); + get_block_geometry(info, fd); + get_sector_size(info, fd); + + /* use udev information if available */ + udev_fill_info(info, &stat); + + return 0; +} + + +int is_device_mounted(const char *path) +{ +#if HAVE_DECL_GETMNTENT + FILE *f; + struct mntent *mnt; + + if ((f = setmntent(_PATH_MOUNTED, "r")) == NULL) + return 0; + while ((mnt = getmntent(f)) != NULL) + if (strcmp(path, mnt->mnt_fsname) == 0) + return 1; + endmntent(f); + return 0; +#endif + +#if HAVE_DECL_GETMNTINFO + struct statfs *stat; + int count, i; + + count = getmntinfo(&stat, 0); + for (i = 0; i < count; i++) + if (!strcmp(path, stat[i].f_mntfromname)) + return 1; + return 0; +#endif + + (void)path; /* prevent unused parameter warning */ + return 0; +} diff --git a/src/device_info.h b/src/device_info.h new file mode 100644 index 0000000..3f4195a --- /dev/null +++ b/src/device_info.h @@ -0,0 +1,56 @@ +#ifndef DEVICE_INFO_H +#define DEVICE_INFO_H + +enum device_type { + TYPE_UNKNOWN, /* type could not be determined */ + TYPE_BAD, /* neither file nor block device */ + TYPE_FILE, /* image file rather than device */ + TYPE_VIRTUAL, /* block devices like LVM or RAID volumes */ + TYPE_REMOVABLE, /* removable disk device */ + TYPE_FIXED /* fixed disk device */ +}; + +struct device_info { + enum device_type type; + + /* + * partition number if detected + * 0 = whole disk device (including unpartitioned image file) + * -1 = could not be determined + */ + int partition; + + /* + * whether partitions or device mapper devices or any other kind of + * children use this device + * 1 = yes + * 0 = no + * -1 = could not be determined + */ + int has_children; + + /* + * detected geometry, or -1 if unknown + */ + int geom_heads; + int geom_sectors; + long geom_start; + + /* + * detected sector size or -1 if unknown + */ + int sector_size; + + /* + * size in bytes, or -1 if unknown + */ + long long size; +}; + + +extern int device_info_verbose; + +int get_device_info(int fd, struct device_info *info); +int is_device_mounted(const char *path); + +#endif diff --git a/src/endian_compat.h b/src/endian_compat.h new file mode 100644 index 0000000..44168c7 --- /dev/null +++ b/src/endian_compat.h @@ -0,0 +1,29 @@ +#ifndef ENDIAN_COMPAT_H +#define ENDIAN_COMPAT_H + +#if defined(HAVE_ENDIAN_H) +#include +#elif defined(HAVE_SYS_ENDIAN_H) +#include +#elif defined(__APPLE__) + #include + + #define htobe16(x) OSSwapHostToBigInt16(x) + #define htole16(x) OSSwapHostToLittleInt16(x) + #define be16toh(x) OSSwapBigToHostInt16(x) + #define le16toh(x) OSSwapLittleToHostInt16(x) + + #define htobe32(x) OSSwapHostToBigInt32(x) + #define htole32(x) OSSwapHostToLittleInt32(x) + #define be32toh(x) OSSwapBigToHostInt32(x) + #define le32toh(x) OSSwapLittleToHostInt32(x) + + #define htobe64(x) OSSwapHostToBigInt64(x) + #define htole64(x) OSSwapHostToLittleInt64(x) + #define be64toh(x) OSSwapBigToHostInt64(x) + #define le64toh(x) OSSwapLittleToHostInt64(x) +#else +#error No endian.h available and no fallback code +#endif + +#endif diff --git a/src/fat.c b/src/fat.c index 5a92f56..c32c25b 100644 --- a/src/fat.c +++ b/src/fat.c @@ -47,6 +47,11 @@ void get_fat(FAT_ENTRY * entry, void *fat, uint32_t cluster, DOS_FS * fs) { unsigned char *ptr; + if (cluster > fs->data_clusters + 1) { + die("Internal error: cluster out of range in get_fat() (%lu > %lu).", + (unsigned long)cluster, (unsigned long)(fs->data_clusters + 1)); + } + switch (fs->fat_bits) { case 12: ptr = &((unsigned char *)fat)[cluster * 3 / 2]; @@ -94,7 +99,7 @@ void read_fat(DOS_FS * fs) fs->fat = NULL; fs->cluster_owner = NULL; - total_num_clusters = fs->clusters + 2UL; + total_num_clusters = fs->data_clusters + 2; eff_size = (total_num_clusters * fs->fat_bits + 7) / 8ULL; if (fs->fat_bits != 12) @@ -155,17 +160,19 @@ void read_fat(DOS_FS * fs) memset(fs->cluster_owner, 0, (total_num_clusters * sizeof(DOS_FILE *))); /* Truncate any cluster chains that link to something out of range */ - for (i = 2; i < fs->clusters + 2; i++) { + for (i = 2; i < fs->data_clusters + 2; i++) { FAT_ENTRY curEntry; get_fat(&curEntry, fs->fat, i, fs); if (curEntry.value == 1) { - printf("Cluster %ld out of range (1). Setting to EOF.\n", (long)(i - 2)); + printf("Cluster %ld out of range (1). Setting to EOF.\n", + (long)(i - 2)); set_fat(fs, i, -1); } - if (curEntry.value >= fs->clusters + 2 && + if (curEntry.value >= fs->data_clusters + 2 && (curEntry.value < FAT_MIN_BAD(fs))) { printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n", - (long)(i - 2), (long)curEntry.value, (long)(fs->clusters + 2 - 1)); + (long)(i - 2), (long)curEntry.value, + (long)(fs->data_clusters + 2 - 1)); set_fat(fs, i, -1); } } @@ -188,12 +195,22 @@ void set_fat(DOS_FS * fs, uint32_t cluster, int32_t new) { unsigned char *data = NULL; int size; - loff_t offs; + off_t offs; + + if (cluster > fs->data_clusters + 1) { + die("Internal error: cluster out of range in set_fat() (%lu > %lu).", + (unsigned long)cluster, (unsigned long)(fs->data_clusters + 1)); + } if (new == -1) new = FAT_EOF(fs); else if ((long)new == -2) new = FAT_BAD(fs); + else if (new > fs->data_clusters + 1) { + die("Internal error: new cluster out of range in set_fat() (%lu > %lu).", + (unsigned long)new, (unsigned long)(fs->data_clusters + 1)); + } + switch (fs->fat_bits) { case 12: data = fs->fat + cluster * 3 / 2; @@ -205,10 +222,12 @@ void set_fat(DOS_FS * fs, uint32_t cluster, int32_t new) data[1] = new >> 4; } else { FAT_ENTRY subseqEntry; - get_fat(&subseqEntry, fs->fat, cluster + 1, fs); + if (cluster != fs->data_clusters + 1) + get_fat(&subseqEntry, fs->fat, cluster + 1, fs); + else + subseqEntry.value = 0; data[0] = new & 0xff; - data[1] = (new >> 8) | (cluster == fs->clusters - 1 ? 0 : - (0xff & subseqEntry.value) << 4); + data[1] = (new >> 8) | ((0xff & subseqEntry.value) << 4); } size = 2; break; @@ -272,10 +291,9 @@ uint32_t next_cluster(DOS_FS * fs, uint32_t cluster) return FAT_IS_EOF(fs, value) ? -1 : value; } -loff_t cluster_start(DOS_FS * fs, uint32_t cluster) +off_t cluster_start(DOS_FS * fs, uint32_t cluster) { - return fs->data_start + ((loff_t) cluster - - 2) * (uint64_t)fs->cluster_size; + return fs->data_start + ((off_t)cluster - 2) * (uint64_t)fs->cluster_size; } /** @@ -312,7 +330,7 @@ void fix_bad(DOS_FS * fs) if (verbose) printf("Checking for bad clusters.\n"); - for (i = 2; i < fs->clusters + 2; i++) { + for (i = 2; i < fs->data_clusters + 2; i++) { FAT_ENTRY curEntry; get_fat(&curEntry, fs->fat, i, fs); @@ -332,7 +350,7 @@ void reclaim_free(DOS_FS * fs) if (verbose) printf("Checking for unused clusters.\n"); reclaimed = 0; - for (i = 2; i < fs->clusters + 2; i++) { + for (i = 2; i < fs->data_clusters + 2; i++) { FAT_ENTRY curEntry; get_fat(&curEntry, fs->fat, i, fs); @@ -367,7 +385,7 @@ static void tag_free(DOS_FS * fs, DOS_FILE * owner, uint32_t *num_refs, if (start_cluster == 0) start_cluster = 2; - for (i = start_cluster; i < fs->clusters + 2; i++) { + for (i = start_cluster; i < fs->data_clusters + 2; i++) { FAT_ENTRY curEntry; get_fat(&curEntry, fs->fat, i, fs); @@ -418,7 +436,7 @@ void reclaim_file(DOS_FS * fs) if (verbose) printf("Reclaiming unconnected clusters.\n"); - total_num_clusters = fs->clusters + 2UL; + total_num_clusters = fs->data_clusters + 2; num_refs = alloc(total_num_clusters * sizeof(uint32_t)); memset(num_refs, 0, (total_num_clusters * sizeof(uint32_t))); @@ -431,7 +449,7 @@ void reclaim_file(DOS_FS * fs) get_fat(&curEntry, fs->fat, i, fs); next = curEntry.value; - if (!get_owner(fs, i) && next && next < fs->clusters + 2) { + if (!get_owner(fs, i) && next && next < fs->data_clusters + 2) { /* Cluster is linked, but not owned (orphan) */ FAT_ENTRY nextEntry; get_fat(&nextEntry, fs->fat, next, fs); @@ -483,7 +501,7 @@ void reclaim_file(DOS_FS * fs) /* If this cluster is the head of an orphan chain... */ if (get_owner(fs, i) == &orphan && !num_refs[i]) { DIR_ENT de; - loff_t offset; + off_t offset; files++; offset = alloc_rootdir_entry(fs, &de, "FSCK%04dREC"); de.start = htole16(i & 0xffff); @@ -511,7 +529,7 @@ uint32_t update_free(DOS_FS * fs) uint32_t free = 0; int do_set = 0; - for (i = 2; i < fs->clusters + 2; i++) { + for (i = 2; i < fs->data_clusters + 2; i++) { FAT_ENTRY curEntry; get_fat(&curEntry, fs->fat, i, fs); diff --git a/src/fat.h b/src/fat.h index b50ed4a..5c77634 100644 --- a/src/fat.h +++ b/src/fat.h @@ -49,7 +49,7 @@ uint32_t next_cluster(DOS_FS * fs, uint32_t cluster); last cluster of the respective cluster chain. CLUSTER must not be a bad cluster. */ -loff_t cluster_start(DOS_FS * fs, uint32_t cluster); +off_t cluster_start(DOS_FS * fs, uint32_t cluster); /* Returns the byte offset of CLUSTER, relative to the respective device. */ diff --git a/src/fatlabel.c b/src/fatlabel.c index 1484ba5..9268ddb 100644 --- a/src/fatlabel.c +++ b/src/fatlabel.c @@ -4,6 +4,7 @@ Copyright (C) 1998 Roman Hodek Copyright (C) 2007 Red Hat, Inc. Copyright (C) 2008-2014 Daniel Baumann + Copyright (C) 2015 Andreas Bombe This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -92,7 +93,7 @@ int main(int argc, char *argv[]) char *device = NULL; char label[12] = { 0 }; - loff_t offset; + off_t offset; DIR_ENT de; check_atari(); @@ -134,7 +135,7 @@ int main(int argc, char *argv[]) if (offset == 0) fprintf(stdout, "%s\n", fs.label); else - fprintf(stdout, "%.8s%.3s\n", de.name, de.ext); + fprintf(stdout, "%.8s%.3s\n", de.name, de.name + 8); exit(0); } diff --git a/src/fsck.fat.c b/src/fsck.fat.c index f786a93..c244aba 100644 --- a/src/fsck.fat.c +++ b/src/fsck.fat.c @@ -217,7 +217,8 @@ exit: if (!boot_only) printf("%s: %u files, %lu/%lu clusters\n", argv[optind], - n_files, (unsigned long)fs.clusters - free_clusters, (unsigned long)fs.clusters); + n_files, (unsigned long)fs.data_clusters - free_clusters, + (unsigned long)fs.data_clusters); return fs_close(rw) ? 1 : 0; } diff --git a/src/fsck.fat.h b/src/fsck.fat.h index e5f6178..168049e 100644 --- a/src/fsck.fat.h +++ b/src/fsck.fat.h @@ -3,6 +3,7 @@ Copyright (C) 1993 Werner Almesberger Copyright (C) 1998 Roman Hodek Copyright (C) 2008-2014 Daniel Baumann + Copyright (C) 2015 Andreas Bombe This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,10 +28,11 @@ #ifndef _DOSFSCK_H #define _DOSFSCK_H +#include #include #include #include -#include +#include "endian_compat.h" #include "msdos_fs.h" @@ -120,7 +122,7 @@ struct info_sector { }; typedef struct { - uint8_t name[8], ext[3]; /* name and extension */ + uint8_t name[MSDOS_NAME]; /* name including extension */ uint8_t attr; /* attribute bits */ uint8_t lcase; /* Case for base and extension */ uint8_t ctime_ms; /* Creation time, milliseconds */ @@ -135,8 +137,8 @@ typedef struct { typedef struct _dos_file { DIR_ENT dir_ent; char *lfn; - loff_t offset; - loff_t lfn_offset; + off_t offset; + off_t lfn_offset; struct _dos_file *parent; /* parent directory */ struct _dos_file *next; /* next entry */ struct _dos_file *first; /* first entry (directory only) */ @@ -149,19 +151,19 @@ typedef struct { typedef struct { int nfats; - loff_t fat_start; - unsigned int fat_size; /* unit is bytes */ + off_t fat_start; + off_t fat_size; /* unit is bytes */ unsigned int fat_bits; /* size of a FAT entry */ unsigned int eff_fat_bits; /* # of used bits in a FAT entry */ uint32_t root_cluster; /* 0 for old-style root dir */ - loff_t root_start; + off_t root_start; unsigned int root_entries; - loff_t data_start; + off_t data_start; unsigned int cluster_size; - uint32_t clusters; - loff_t fsinfo_start; /* 0 if not present */ + uint32_t data_clusters; /* not including two reserved cluster numbers */ + off_t fsinfo_start; /* 0 if not present */ long free_clusters; - loff_t backupboot_start; /* 0 if not present */ + off_t backupboot_start; /* 0 if not present */ unsigned char *fat; DOS_FILE **cluster_owner; char *label; diff --git a/src/io.c b/src/io.c index 450432c..b2c559b 100644 --- a/src/io.c +++ b/src/io.c @@ -3,6 +3,7 @@ Copyright (C) 1993 Werner Almesberger Copyright (C) 1998 Roman Hodek Copyright (C) 2008-2014 Daniel Baumann + Copyright (C) 2015 Andreas Bombe This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,11 +36,10 @@ #include #include #include +#include #include -#include #include #include -#include #include "fsck.fat.h" #include "common.h" @@ -47,7 +47,7 @@ typedef struct _change { void *data; - loff_t pos; + off_t pos; int size; struct _change *next; } CHANGE; @@ -55,57 +55,15 @@ typedef struct _change { static CHANGE *changes, *last; static int fd, did_change = 0; -unsigned device_no; - -#ifdef __DJGPP__ -#include "volume.h" /* DOS lowlevel disk access functions */ -loff_t llseek(int fd, loff_t offset, int whence) -{ - if ((whence != SEEK_SET) || (fd == 4711)) - return -1; /* only those supported */ - return VolumeSeek(offset); -} - -#define open OpenVolume -#define close CloseVolume -#define read(a,b,c) ReadVolume(b,c) -#define write(a,b,c) WriteVolume(b,c) -#else -loff_t llseek(int fd, loff_t offset, int whence) -{ - return (loff_t) lseek64(fd, (off64_t) offset, whence); -} -#endif void fs_open(char *path, int rw) { - struct stat stbuf; - if ((fd = open(path, rw ? O_RDWR : O_RDONLY)) < 0) { perror("open"); exit(6); } changes = last = NULL; did_change = 0; - -#ifndef _DJGPP_ - if (fstat(fd, &stbuf) < 0) - pdie("fstat %s", path); - device_no = S_ISBLK(stbuf.st_mode) ? (stbuf.st_rdev >> 8) & 0xff : 0; -#else - if (IsWorkingOnImageFile()) { - if (fstat(GetVolumeHandle(), &stbuf) < 0) - pdie("fstat image %s", path); - device_no = 0; - } else { - /* return 2 for floppy, 1 for ramdisk, 7 for loopback */ - /* used by boot.c in Atari mode: floppy always FAT12, */ - /* loopback / ramdisk only FAT12 if usual floppy size, */ - /* harddisk always FAT16 on Atari... */ - device_no = (GetVolumeHandle() < 2) ? 2 : 1; - /* telling "floppy" for A:/B:, "ramdisk" for the rest */ - } -#endif } /** @@ -117,12 +75,12 @@ void fs_open(char *path, int rw) * @param[in] size Number of bytes to read * @param[out] data Where to put the data read */ -void fs_read(loff_t pos, int size, void *data) +void fs_read(off_t pos, int size, void *data) { CHANGE *walk; int got; - if (llseek(fd, pos, 0) != pos) + if (lseek(fd, pos, 0) != pos) pdie("Seek to %lld", pos); if ((got = read(fd, data, size)) < 0) pdie("Read %d bytes at %lld", size, pos); @@ -131,12 +89,8 @@ void fs_read(loff_t pos, int size, void *data) for (walk = changes; walk; walk = walk->next) { if (walk->pos < pos + size && walk->pos + walk->size > pos) { if (walk->pos < pos) - memcpy(data, (char *)walk->data + pos - walk->pos, min(size, - walk-> - size - - pos + - walk-> - pos)); + memcpy(data, (char *)walk->data + pos - walk->pos, + min(size, walk->size - pos + walk->pos)); else memcpy((char *)data + walk->pos - pos, walk->data, min(walk->size, size + pos - walk->pos)); @@ -144,12 +98,12 @@ void fs_read(loff_t pos, int size, void *data) } } -int fs_test(loff_t pos, int size) +int fs_test(off_t pos, int size) { void *scratch; int okay; - if (llseek(fd, pos, 0) != pos) + if (lseek(fd, pos, 0) != pos) pdie("Seek to %lld", pos); scratch = alloc(size); okay = read(fd, scratch, size) == size; @@ -157,14 +111,14 @@ int fs_test(loff_t pos, int size) return okay; } -void fs_write(loff_t pos, int size, void *data) +void fs_write(off_t pos, int size, void *data) { CHANGE *new; int did; if (write_immed) { did_change = 1; - if (llseek(fd, pos, 0) != pos) + if (lseek(fd, pos, 0) != pos) pdie("Seek to %lld", pos); if ((did = write(fd, data, size)) == size) return; @@ -191,7 +145,7 @@ static void fs_flush(void) while (changes) { this = changes; changes = changes->next; - if (llseek(fd, this->pos, 0) != this->pos) + if (lseek(fd, this->pos, 0) != this->pos) fprintf(stderr, "Seek to %lld failed: %s\n Did not write %d bytes.\n", (long long)this->pos, strerror(errno), this->size); diff --git a/src/io.h b/src/io.h index d23d07e..4ce032f 100644 --- a/src/io.h +++ b/src/io.h @@ -27,28 +27,24 @@ #ifndef _IO_H #define _IO_H -#include /* for loff_t */ - -loff_t llseek(int fd, loff_t offset, int whence); - -/* lseek() analogue for large offsets. */ +#include /* for off_t */ void fs_open(char *path, int rw); /* Opens the filesystem PATH. If RW is zero, the filesystem is opened read-only, otherwise, it is opened read-write. */ -void fs_read(loff_t pos, int size, void *data); +void fs_read(off_t pos, int size, void *data); /* Reads SIZE bytes starting at POS into DATA. Performs all applicable changes. */ -int fs_test(loff_t pos, int size); +int fs_test(off_t pos, int size); /* Returns a non-zero integer if SIZE bytes starting at POS can be read without errors. Otherwise, it returns zero. */ -void fs_write(loff_t pos, int size, void *data); +void fs_write(off_t pos, int size, void *data); /* If write_immed is non-zero, SIZE bytes are written from DATA to the disk, starting at POS. If write_immed is zero, the change is added to a list in @@ -64,8 +60,4 @@ int fs_changed(void); /* Determines whether the filesystem has changed. See fs_close. */ -extern unsigned device_no; - -/* Major number of device (0 if file) and size (in 512 byte sectors) */ - #endif diff --git a/src/lfn.c b/src/lfn.c index 2601172..b33e125 100644 --- a/src/lfn.c +++ b/src/lfn.c @@ -2,6 +2,7 @@ Copyright (C) 1998 Roman Hodek Copyright (C) 2008-2014 Daniel Baumann + Copyright (C) 2015 Andreas Bombe This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -53,7 +54,7 @@ typedef struct { unsigned char *lfn_unicode = NULL; unsigned char lfn_checksum; int lfn_slot = -1; -loff_t *lfn_offsets = NULL; +off_t *lfn_offsets = NULL; int lfn_parts = 0; static unsigned char fat_uni2esc[64] = { @@ -171,7 +172,7 @@ static void clear_lfn_slots(int start, int end) } } -void lfn_fix_checksum(loff_t from, loff_t to, const char *short_name) +void lfn_fix_checksum(off_t from, off_t to, const char *short_name) { int i; uint8_t sum; @@ -196,7 +197,7 @@ void lfn_reset(void) /* This function is only called with de->attr == VFAT_LN_ATTR. It stores part * of the long name. */ -void lfn_add_slot(DIR_ENT * de, loff_t dir_offset) +void lfn_add_slot(DIR_ENT * de, off_t dir_offset) { LFN_ENT *lfn = (LFN_ENT *) de; int slot = lfn->id & LFN_ID_SLOTMASK; @@ -254,7 +255,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset) lfn_slot = slot; lfn_checksum = lfn->alias_checksum; lfn_unicode = alloc((lfn_slot * CHARS_PER_LFN + 1) * 2); - lfn_offsets = alloc(lfn_slot * sizeof(loff_t)); + lfn_offsets = alloc(lfn_slot * sizeof(off_t)); lfn_parts = 0; } else if (lfn_slot == -1 && slot != 0) { /* No LFN in progress, but slot found; start bit missing */ @@ -265,6 +266,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset) printf("Long filename fragment \"%s\" found outside a LFN " "sequence.\n (Maybe the start bit is missing on the " "last fragment)\n", part); + free(part); if (interactive) { printf("1: Delete fragment\n2: Leave it as it is.\n" "3: Set start bit\n"); @@ -273,7 +275,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset) switch (interactive ? get_key("123", "?") : '2') { case '1': if (!lfn_offsets) - lfn_offsets = alloc(sizeof(loff_t)); + lfn_offsets = alloc(sizeof(off_t)); lfn_offsets[0] = dir_offset; clear_lfn_slots(0, 0); lfn_reset(); @@ -288,7 +290,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset) lfn_slot = slot; lfn_checksum = lfn->alias_checksum; lfn_unicode = alloc((lfn_slot * CHARS_PER_LFN + 1) * 2); - lfn_offsets = alloc(lfn_slot * sizeof(loff_t)); + lfn_offsets = alloc(lfn_slot * sizeof(off_t)); lfn_parts = 0; break; } @@ -320,7 +322,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset) switch (interactive ? get_key(can_fix ? "123" : "12", "?") : '2') { case '1': if (!lfn_offsets) { - lfn_offsets = alloc(sizeof(loff_t)); + lfn_offsets = alloc(sizeof(off_t)); lfn_parts = 0; } lfn_offsets[lfn_parts++] = dir_offset; @@ -407,7 +409,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset) /* This function is always called when de->attr != VFAT_LN_ATTR is found, to * retrieve the previously constructed LFN. */ -char *lfn_get(DIR_ENT * de, loff_t * lfn_offset) +char *lfn_get(DIR_ENT * de, off_t * lfn_offset) { char *lfn; uint8_t sum; @@ -464,10 +466,8 @@ char *lfn_get(DIR_ENT * de, loff_t * lfn_offset) } } - for (sum = 0, i = 0; i < 8; i++) + for (sum = 0, i = 0; i < MSDOS_NAME; i++) sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + de->name[i]; - for (i = 0; i < 3; i++) - sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + de->ext[i]; if (sum != lfn_checksum) { /* checksum doesn't match, long name doesn't apply to this alias */ /* Causes: 1) alias renamed */ @@ -517,6 +517,7 @@ void lfn_check_orphaned(void) long_name = CNV_PARTS_SO_FAR(); printf("Orphaned long file name part \"%s\"\n", long_name); + free(long_name); if (interactive) printf("1: Delete.\n2: Leave it.\n"); else diff --git a/src/lfn.h b/src/lfn.h index e5c3991..fc38ce7 100644 --- a/src/lfn.h +++ b/src/lfn.h @@ -26,14 +26,14 @@ void lfn_reset(void); /* Reset the state of the LFN parser. */ -void lfn_add_slot(DIR_ENT * de, loff_t dir_offset); +void lfn_add_slot(DIR_ENT * de, off_t dir_offset); /* Process a dir slot that is a VFAT LFN entry. */ -char *lfn_get(DIR_ENT * de, loff_t * lfn_offset); +char *lfn_get(DIR_ENT * de, off_t * lfn_offset); /* Retrieve the long name for the proper dir entry. */ void lfn_check_orphaned(void); -void lfn_fix_checksum(loff_t from, loff_t to, const char *short_name); +void lfn_fix_checksum(off_t from, off_t to, const char *short_name); #endif diff --git a/src/mkfs.fat.c b/src/mkfs.fat.c index b38d116..8a320fd 100644 --- a/src/mkfs.fat.c +++ b/src/mkfs.fat.c @@ -6,6 +6,7 @@ Copyright (C) 1998 H. Peter Anvin Copyright (C) 1998-2005 Roman Hodek Copyright (C) 2008-2014 Daniel Baumann + Copyright (C) 2015-2016 Andreas Bombe This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -47,17 +48,11 @@ #include "version.h" #include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include +#include #include #include #include @@ -65,14 +60,12 @@ #include #include #include -#include #include +#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, ¶m)) /* Can we get the diskette geometry? */ - die("unable to get diskette geometry for '%s'"); - } - bs.secs_track = htole16(param.sect); /* Set up the geometry information */ - bs.heads = htole16(param.head); - switch (param.size) { /* Set up the media descriptor byte */ - case 720: /* 5.25", 2, 9, 40 - 360K */ - bs.media = (char)0xfd; - bs.cluster_size = (char)2; - def_root_dir_entries = 112; - break; - - case 1440: /* 3.5", 2, 9, 80 - 720K */ - bs.media = (char)0xf9; - bs.cluster_size = (char)2; - def_root_dir_entries = 112; - break; - - case 2400: /* 5.25", 2, 15, 80 - 1200K */ - bs.media = (char)0xf9; - bs.cluster_size = (char)(atari_format ? 2 : 1); - def_root_dir_entries = 224; - break; - - case 5760: /* 3.5", 2, 36, 80 - 2880K */ - bs.media = (char)0xf0; - bs.cluster_size = (char)2; - def_root_dir_entries = 224; - break; - - case 2880: /* 3.5", 2, 18, 80 - 1440K */ -floppy_default: - bs.media = (char)0xf0; - bs.cluster_size = (char)(atari_format ? 2 : 1); - def_root_dir_entries = 224; - break; - - default: /* Anything else */ - if (0 == device_num) - goto def_hd_params; - else - goto floppy_default; } - } else if ((device_num & 0xff00) == 0x0700) { /* This is a loop device */ - if (ioctl(dev, BLKGETSIZE, &loop_size)) - die("unable to get loop device size"); - - switch (loop_size) { /* Assuming the loop device -> floppy later */ - case 720: /* 5.25", 2, 9, 40 - 360K */ - bs.secs_track = le16toh(9); - bs.heads = le16toh(2); - bs.media = (char)0xfd; - bs.cluster_size = (char)2; - def_root_dir_entries = 112; - break; - - case 1440: /* 3.5", 2, 9, 80 - 720K */ - bs.secs_track = le16toh(9); - bs.heads = le16toh(2); - bs.media = (char)0xf9; - bs.cluster_size = (char)2; - def_root_dir_entries = 112; - break; - - case 2400: /* 5.25", 2, 15, 80 - 1200K */ - bs.secs_track = le16toh(15); - bs.heads = le16toh(2); - bs.media = (char)0xf9; - bs.cluster_size = (char)(atari_format ? 2 : 1); - def_root_dir_entries = 224; - break; - - case 5760: /* 3.5", 2, 36, 80 - 2880K */ - bs.secs_track = le16toh(36); - bs.heads = le16toh(2); - bs.media = (char)0xf0; - bs.cluster_size = (char)2; - bs.dir_entries[0] = (char)224; - bs.dir_entries[1] = (char)0; - break; + } - case 2880: /* 3.5", 2, 18, 80 - 1440K */ - bs.secs_track = le16toh(18); - bs.heads = le16toh(2); - bs.media = (char)0xf0; - bs.cluster_size = (char)(atari_format ? 2 : 1); - def_root_dir_entries = 224; - break; + if (!size_fat && info->size >= 512 * 1024 * 1024) { + if (verbose) + printf("Auto-selecting FAT32 for large filesystem\n"); + size_fat = 32; + } + if (size_fat == 32) { + /* + * For FAT32, try to do the same as M$'s format command + * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20): + * fs size <= 260M: 0.5k clusters + * fs size <= 8G: 4k clusters + * fs size <= 16G: 8k clusters + * fs size <= 32G: 16k clusters + * fs size > 32G: 32k clusters + * + * This only works correctly for 512 byte sectors! + */ + uint32_t sz_mb = info->size / (1024 * 1024); + cluster_size = + sz_mb > 32 * 1024 ? 64 : sz_mb > 16 * 1024 ? 32 : sz_mb > + 8 * 1024 ? 16 : sz_mb > 260 ? 8 : 1; + } - default: /* Anything else: default hd setup */ - printf("Loop device does not match a floppy size, using " - "default hd params\n"); - bs.secs_track = htole16(32); /* these are fake values... */ - bs.heads = htole16(64); - goto def_hd_params; - } - } else - /* Must be a hard disk then! */ - { - /* Can we get the drive geometry? (Note I'm not too sure about */ - /* whether to use HDIO_GETGEO or HDIO_REQ) */ - if (ioctl(dev, HDIO_GETGEO, &geometry) || geometry.sectors == 0 - || geometry.heads == 0) { - printf("unable to get drive geometry, using default 255/63\n"); - bs.secs_track = htole16(63); - bs.heads = htole16(255); - } else { - bs.secs_track = htole16(geometry.sectors); /* Set up the geometry information */ - bs.heads = htole16(geometry.heads); - if (!hidden_sectors_by_user) - hidden_sectors = htole32(geometry.start); - } -def_hd_params: - bs.media = (char)0xf8; /* Set up the media descriptor for a hard drive */ - if (!size_fat && blocks * SECTORS_PER_BLOCK > 1064960) { - if (verbose) - printf("Auto-selecting FAT32 for large filesystem\n"); - size_fat = 32; - } - if (size_fat == 32) { - /* For FAT32, try to do the same as M$'s format command - * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20): - * fs size <= 260M: 0.5k clusters - * fs size <= 8G: 4k clusters - * fs size <= 16G: 8k clusters - * fs size <= 32G: 16k clusters - * fs size > 32G: 32k clusters - */ - uint32_t sz_mb = - (blocks + (1 << (20 - BLOCK_SIZE_BITS)) - 1) >> (20 - - BLOCK_SIZE_BITS); - bs.cluster_size = - sz_mb > 32 * 1024 ? 64 : sz_mb > 16 * 1024 ? 32 : sz_mb > - 8 * 1024 ? 16 : sz_mb > 260 ? 8 : 1; - } else { - /* FAT12 and FAT16: start at 4 sectors per cluster */ - bs.cluster_size = (char)4; - } + if (info->geom_heads > 0) { + heads = info->geom_heads; + sec_per_track = info->geom_sectors; } + if (!hidden_sectors_by_user && info->geom_start >= 0) + hidden_sectors = htole32(info->geom_start); + if (!root_dir_entries) root_dir_entries = def_root_dir_entries; + + bs.secs_track = htole16(sec_per_track); + bs.heads = htole16(heads); + bs.media = media; + bs.cluster_size = cluster_size; } /* @@ -713,7 +620,6 @@ static unsigned int align_object(unsigned int sectors, unsigned int clustsize) static void setup_tables(void) { - unsigned num_sectors; unsigned cluster_count = 0, fat_length; struct tm *ctime; struct msdos_volume_info *vi = @@ -807,8 +713,15 @@ static void setup_tables(void) memcpy(&bs.hidden, &hidden, 2); } - num_sectors = - (long long)(blocks * BLOCK_SIZE / sector_size) + orphaned_sectors; + if ((long long)(blocks * BLOCK_SIZE / sector_size) + orphaned_sectors > + UINT32_MAX) { + printf("Warning: target too large, space at end will be left unused\n"); + num_sectors = UINT32_MAX; + blocks = (uint64_t)UINT32_MAX * sector_size / BLOCK_SIZE; + } else { + num_sectors = + (long long)(blocks * BLOCK_SIZE / sector_size) + orphaned_sectors; + } if (!atari_format) { unsigned fatdata1216; /* Sectors for FATs + data area (FAT12/16) */ @@ -837,7 +750,8 @@ static void setup_tables(void) maxclustsize = 128; do { - fatdata32 = num_sectors - reserved_sectors; + fatdata32 = num_sectors + - align_object(reserved_sectors, bs.cluster_size); fatdata1216 = fatdata32 - align_object(root_dir_sectors, bs.cluster_size); @@ -899,6 +813,7 @@ static void setup_tables(void) clust32 = ((long long)fatdata32 * sector_size + nr_fats * 8) / ((int)bs.cluster_size * sector_size + nr_fats * 4); fatlength32 = cdiv((clust32 + 2) * 4, sector_size); + fatlength32 = align_object(fatlength32, bs.cluster_size); /* Need to recalculate number of clusters, since the unused parts of the * FATS and data area together could make up space for an additional, * not really present cluster. */ @@ -985,6 +900,10 @@ static void setup_tables(void) die("FAT not 12, 16 or 32 bits"); } + /* Adjust the reserved number of sectors for alignment */ + reserved_sectors = align_object(reserved_sectors, bs.cluster_size); + bs.reserved = htole16(reserved_sectors); + /* Adjust the number of root directory entries to help enforce alignment */ if (align_structures) { root_dir_entries = align_object(root_dir_sectors, bs.cluster_size) @@ -1130,9 +1049,11 @@ static void setup_tables(void) else die("Attempting to create a too large filesystem"); } + fat_entries = cluster_count + 2; /* The two following vars are in hard sectors, i.e. 512 byte sectors! */ - start_data_sector = (reserved_sectors + nr_fats * fat_length) * + start_data_sector = (reserved_sectors + nr_fats * fat_length + + cdiv(root_dir_entries * 32, sector_size)) * (sector_size / HARD_SECTOR_SIZE); start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) / SECTORS_PER_BLOCK; @@ -1209,10 +1130,9 @@ static void setup_tables(void) } memset(root_dir, 0, size_root_dir); - if (memcmp(volume_name, NO_NAME, 11)) { + if (memcmp(volume_name, NO_NAME, MSDOS_NAME)) { struct msdos_dir_entry *de = &root_dir[0]; - memcpy(de->name, volume_name, 8); - memcpy(de->ext, volume_name + 8, 3); + memcpy(de->name, volume_name, MSDOS_NAME); de->attr = ATTR_VOLUME; if (!invariant) ctime = localtime(&create_time); @@ -1277,8 +1197,8 @@ static void setup_tables(void) #define seekto(pos,errstr) \ do { \ - loff_t __pos = (pos); \ - if (llseek (dev, __pos, SEEK_SET) != __pos) \ + off_t __pos = (pos); \ + if (lseek (dev, __pos, SEEK_SET) != __pos) \ error ("seek to " errstr " failed whilst writing tables"); \ } while(0) @@ -1388,12 +1308,11 @@ int main(int argc, char **argv) char *tmp; char *listfile = NULL; FILE *msgfile; - struct stat statbuf; + struct device_info devinfo; int i = 0, pos, ch; int create = 0; uint64_t cblocks = 0; - int min_sector_size; - int bad_block_count = 0; + int blocks_specified = 0; struct timeval create_timeval; enum {OPT_HELP=1000, OPT_INVARIANT,}; @@ -1412,7 +1331,7 @@ int main(int argc, char **argv) gettimeofday(&create_timeval, NULL); create_time = create_timeval.tv_sec; - volume_id = (u_int32_t) ((create_timeval.tv_sec << 20) | create_timeval.tv_usec); /* Default volume ID = creation time, fudged for more uniqueness */ + volume_id = (uint32_t) ((create_timeval.tv_sec << 20) | create_timeval.tv_usec); /* Default volume ID = creation time, fudged for more uniqueness */ check_atari(); printf("mkfs.fat " VERSION " (" VERSION_DATE ")\n"); @@ -1641,38 +1560,34 @@ int main(int argc, char **argv) printf("Unknown option: %c\n", c); usage(1); } - if (optind < argc) { - device_name = argv[optind]; /* Determine the number of blocks in the FS */ - if (!device_name) { - printf("No device specified.\n"); + if (optind == argc || !argv[optind]) { + printf("No device specified.\n"); + usage(1); + } + + device_name = argv[optind++]; + + if (optind != argc) { + blocks_specified = 1; + blocks = strtoull(argv[optind], &tmp, 0); + + if (*tmp) { + printf("Bad block count : %s\n", argv[optind]); usage(1); } - if (!create) - cblocks = count_blocks(device_name, &orphaned_sectors); /* Have a look and see! */ - } - if (optind == argc - 2) { /* Either check the user specified number */ - blocks = strtoull(argv[optind + 1], &tmp, 0); - if (!create && blocks != cblocks) { - fprintf(stderr, "Warning: block count mismatch: "); - fprintf(stderr, "found %llu but assuming %llu.\n", (unsigned long long)cblocks, (unsigned long long)blocks); - } - if (*tmp) - bad_block_count = 1; - } else if (optind == argc - 1) { /* Or use value found */ - if (create) - die("Need intended size with -C."); - blocks = cblocks; - } else { - fprintf(stderr, "No device specified!\n"); - usage(1); + optind++; } - if (bad_block_count) { - printf("Bad block count : %s\n", argv[optind + 1]); + + if (optind != argc) { + fprintf(stderr, "Excess arguments on command line\n"); usage(1); } + if (create && !blocks_specified) + die("Need intended size with -C."); + if (check && listfile) /* Auto and specified bad block handling are mutually */ die("-c and -l are incompatible"); /* exclusive of each other! */ @@ -1698,47 +1613,58 @@ int main(int argc, char **argv) die("unable to resize %s"); } - if (fstat(dev, &statbuf) < 0) - die("unable to stat %s"); - if (!S_ISBLK(statbuf.st_mode)) { - statbuf.st_rdev = 0; - check = 0; - } else - /* - * Ignore any 'full' fixed disk devices, if -I is not given. - * On a MO-disk one doesn't need partitions. The filesytem can go - * directly to the whole disk. Under other OSes this is known as - * the 'superfloppy' format. As I don't know how to find out if - * this is a MO disk I introduce a -I (ignore) switch. -Joey - */ - if (!ignore_full_disk && ((statbuf.st_rdev & 0xffffff3f) == 0x0300 || /* hda, hdb */ - (statbuf.st_rdev & 0xffffff0f) == 0x0800 || /* sd */ - (statbuf.st_rdev & 0xffffff3f) == 0x0d00 || /* xd */ - (statbuf.st_rdev & 0xffffff3f) == 0x1600) /* hdc, hdd */ - ) + if (get_device_info(dev, &devinfo) < 0) + die("error collecting information about %s"); + + if (devinfo.size <= 0) + die("unable to discover size of %s"); + + if (devinfo.sector_size > 0) + sector_size = devinfo.sector_size; + + cblocks = devinfo.size / BLOCK_SIZE; + orphaned_sectors = (devinfo.size % BLOCK_SIZE) / sector_size; + + if (blocks_specified) { + if (blocks != cblocks) { + fprintf(stderr, "Warning: block count mismatch: "); + fprintf(stderr, "found %llu but assuming %llu.\n", + (unsigned long long)cblocks, (unsigned long long)blocks); + } + } else { + blocks = cblocks; + } + + /* + * Ignore any 'full' fixed disk devices, if -I is not given. + */ + if (!ignore_full_disk && devinfo.type == TYPE_FIXED && + devinfo.partition == 0) die("Device partition expected, not making filesystem on entire device '%s' (use -I to override)"); - if (sector_size_set) { - if (ioctl(dev, BLKSSZGET, &min_sector_size) >= 0) - if (sector_size < min_sector_size) { - sector_size = min_sector_size; + if (!ignore_full_disk && devinfo.has_children > 0) + die("Partitions or virtual mappings on device '%s', not making filesystem (use -I to override)"); + + if (devinfo.sector_size > 0) { + if (sector_size_set) { + if (sector_size < devinfo.sector_size) { + sector_size = devinfo.sector_size; fprintf(stderr, "Warning: sector size was set to %d (minimal for this device)\n", sector_size); } - } else { - if (ioctl(dev, BLKSSZGET, &min_sector_size) >= 0) { - sector_size = min_sector_size; + } else { + sector_size = devinfo.sector_size; sector_size_set = 1; } } if (sector_size > 4096) fprintf(stderr, - "Warning: sector size is set to %d > 4096, such filesystem will not propably mount\n", + "Warning: sector size %d > 4096 is non-standard, filesystem may not be usable\n", sector_size); - establish_params(statbuf.st_rdev, statbuf.st_size); + establish_params(&devinfo); /* Establish the media parameters */ setup_tables(); /* Establish the filesystem tables */ diff --git a/src/msdos_fs.h b/src/msdos_fs.h index 54b2a34..d33a2e4 100644 --- a/src/msdos_fs.h +++ b/src/msdos_fs.h @@ -46,7 +46,7 @@ #define MSDOS_DOTDOT ".. " /* "..", padded to MSDOS_NAME chars */ struct msdos_dir_entry { - uint8_t name[8], ext[3]; /* name and extension */ + uint8_t name[MSDOS_NAME]; /* name including extension */ uint8_t attr; /* attribute bits */ uint8_t lcase; /* Case for base and extension */ uint8_t ctime_cs; /* Creation time, centiseconds (0-199) */ diff --git a/src/testdevinfo.c b/src/testdevinfo.c new file mode 100644 index 0000000..9c555ed --- /dev/null +++ b/src/testdevinfo.c @@ -0,0 +1,125 @@ +/* testdevinfo - Display device info findings for debugging + + Copyright (C) 2015 Andreas Bombe + + 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 . +*/ + +#include +#include +#include +#include "device_info.h" + + +int main(int argc, char **argv) +{ + struct device_info info; + int fd; + + if (argc != 2) { + printf("Usage: testdevinfo FILENAME\n"); + return 1; + } + + fd = open(argv[1], O_RDONLY); + if (fd < 0) { + perror("open device"); + return 1; + } + + device_info_verbose = 100; + get_device_info(fd, &info); + close(fd); + + printf("\nfound information:\n"); + + printf("device type: "); + switch (info.type) { + case TYPE_UNKNOWN: + printf("unknown\n"); + break; + + case TYPE_BAD: + printf("unusable\n"); + break; + + case TYPE_FILE: + printf("image file\n"); + break; + + case TYPE_VIRTUAL: + printf("virtual\n"); + break; + + case TYPE_REMOVABLE: + printf("removable\n"); + break; + + case TYPE_FIXED: + printf("fixed\n"); + break; + + default: + printf("internal error! invalid value\n"); + break; + } + + printf("is partition: "); + if (info.partition < 0) + printf("unknown\n"); + else if (info.partition == 0) + printf("no, full disk\n"); + else + printf("number %d\n", info.partition); + + printf("has children: "); + if (info.has_children < 0) + printf("unknown\n"); + else if (info.has_children == 0) + printf("no\n"); + else + printf("yes\n"); + + printf("heads: "); + if (info.geom_heads < 0) + printf("unknown\n"); + else + printf("%d\n", info.geom_heads); + + printf("sectors: "); + if (info.geom_sectors < 0) + printf("unknown\n"); + else + printf("%d\n", info.geom_sectors); + + printf("start: "); + if (info.geom_start < 0) + printf("unknown\n"); + else + printf("%ld\n", info.geom_start); + + printf("sector size: "); + if (info.sector_size < 0) + printf("unknown\n"); + else + printf("%d\n", info.sector_size); + + printf("size: "); + if (info.size < 0) + printf("unknown\n"); + else + printf("%lld\n", info.size); + + return 0; +} diff --git a/src/version.h b/src/version.h.in similarity index 90% rename from src/version.h rename to src/version.h.in index f0716d3..1487fc5 100644 --- a/src/version.h +++ b/src/version.h.in @@ -1,4 +1,4 @@ -/* version.h +/* @configure_input@ Copyright (C) 1998-2005 Roman Hodek Copyright (C) 2008-2014 Daniel Baumann @@ -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 -- 2.7.4