mirror of
https://github.com/openharmony/third_party_exfat-utils.git
synced 2026-07-01 22:34:00 -04:00
暂时用exfatprogs代码替换exfat-utils代码,等exfatprogs仓孵化后本仓下线。替换原因:本仓工具不支持修复exfat中的错误,而exfatprogs是Linux内核exfat驱动的maintainer开发的官方配套工具。
Signed-off-by: xlfeng <xulifeng7@huawei.com>
This commit is contained in:
+47
@@ -0,0 +1,47 @@
|
||||
dist: bionic
|
||||
|
||||
language: c
|
||||
|
||||
notifications:
|
||||
- email: true
|
||||
|
||||
before_script:
|
||||
- sudo apt-get install linux-headers-$(uname -r)
|
||||
- git clone --branch=exfat-next https://github.com/namjaejeon/exfat_oot
|
||||
- ./.travis_get_mainline_kernel
|
||||
- export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
|
||||
- export PATH=/usr/local/lib:$PATH
|
||||
|
||||
script:
|
||||
# run checkpatch.pl
|
||||
- git format-patch -20
|
||||
- ./linux/scripts/checkpatch.pl *.patch || true
|
||||
# build & install exfatprogs
|
||||
- ./autogen.sh > /dev/null
|
||||
- ./configure > /dev/null
|
||||
- make -j$((`nproc`+1)) > /dev/null
|
||||
- sudo make install > /dev/null
|
||||
- cd exfat_oot
|
||||
- make > /dev/null
|
||||
- sudo make install > /dev/null
|
||||
- sudo modprobe exfat
|
||||
- sudo mkdir -p /mnt/test
|
||||
# create file/director test
|
||||
- truncate -s 10G test.img
|
||||
- sudo losetup /dev/loop22 test.img
|
||||
- sudo mkfs.exfat /dev/loop22
|
||||
- sudo mount -t exfat /dev/loop22 /mnt/test/
|
||||
- cd /mnt/test/
|
||||
- i=1;while [ $i -le 10000 ];do sudo touch file$i;if [ $? != 0 ]; then exit 1; fi; i=$(($i + 1));done
|
||||
- sync
|
||||
- sudo rm -rf *
|
||||
- i=1;while [ $i -le 10000 ];do sudo mkdir dir$i;if [ $? != 0 ]; then exit 1; fi; i=$(($i + 1));done
|
||||
- sync
|
||||
- sudo rm -rf *
|
||||
- i=1;while [ $i -le 10000 ];do sudo touch file$i;if [ $? != 0 ]; then exit 1; fi; i=$(($i + 1));done
|
||||
- i=1;while [ $i -le 10000 ];do sudo mkdir dir$i;if [ $? != 0 ]; then exit 1; fi; i=$(($i + 1));done
|
||||
- sync
|
||||
- sudo fsck.exfat /dev/loop22
|
||||
- sudo find . -delete
|
||||
- sudo fsck.exfat /dev/loop22
|
||||
- cd -
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# A simple script we are using to get the latest mainline kernel
|
||||
# tar ball
|
||||
#
|
||||
|
||||
wget https://www.kernel.org/releases.json
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Could not download kernel.org/releases.json"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VER=$(cat releases.json | python2.7 -c "import sys, json; print json.load(sys.stdin)['latest_stable']['version']")
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Could not parse release.json"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "z$VER" = "z" ]; then
|
||||
echo "Could not determine latest release version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MVER=$(echo $VER | cut -d. -f1)
|
||||
|
||||
wget https://cdn.kernel.org/pub/linux/kernel/v"$MVER".x/linux-"$VER".tar.gz
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Could not download $VER kernel version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tar xf linux-"$VER".tar.gz
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Could not untar kernel tar ball"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mv linux-"$VER" linux
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2021 Huawei Device Co., Ltd.
|
||||
# Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
#
|
||||
# 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,26 +28,22 @@ config("exfat-defaults") {
|
||||
"-std=gnu99",
|
||||
"-Wno-error",
|
||||
"-D_FILE_OFFSET_BITS=64",
|
||||
"-DPACKAGE=\"exfat\"",
|
||||
"-DVERSION=\"1.3.0\"",
|
||||
"-DPACKAGE=\"exfatprogs\"",
|
||||
"-DVERSION=\"1.1.3\"",
|
||||
]
|
||||
include_dirs = [
|
||||
"dump",
|
||||
"fsck",
|
||||
"include",
|
||||
"label",
|
||||
"mkfs",
|
||||
"tune",
|
||||
]
|
||||
include_dirs = [ "//developtools/liblog" ]
|
||||
}
|
||||
|
||||
ohos_shared_library("libexfat") {
|
||||
configs = [ ":exfat-defaults" ]
|
||||
sources = [
|
||||
"libexfat/cluster.c",
|
||||
"libexfat/io.c",
|
||||
"libexfat/log.c",
|
||||
"libexfat/lookup.c",
|
||||
"libexfat/mount.c",
|
||||
"libexfat/node.c",
|
||||
"libexfat/repair.c",
|
||||
"libexfat/time.c",
|
||||
"libexfat/utf.c",
|
||||
"libexfat/utils.c",
|
||||
]
|
||||
sources = [ "lib/libexfat.c" ]
|
||||
|
||||
include_dirs = [ "./libexfat" ]
|
||||
|
||||
@@ -63,18 +59,12 @@ ohos_shared_library("libexfat") {
|
||||
ohos_executable("mkfs.exfat") {
|
||||
configs = [ ":exfat-defaults" ]
|
||||
sources = [
|
||||
"mkfs/cbm.c",
|
||||
"mkfs/fat.c",
|
||||
"mkfs/main.c",
|
||||
"mkfs/mkexfat.c",
|
||||
"mkfs/rootdir.c",
|
||||
"mkfs/uct.c",
|
||||
"mkfs/uctc.c",
|
||||
"mkfs/vbr.c",
|
||||
"mkfs/mkfs.c",
|
||||
"mkfs/upcase.c",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"./libexfat",
|
||||
"./lib",
|
||||
"./mkfs",
|
||||
]
|
||||
|
||||
@@ -89,10 +79,14 @@ ohos_executable("mkfs.exfat") {
|
||||
##Build fsck.exfat
|
||||
ohos_executable("fsck.exfat") {
|
||||
configs = [ ":exfat-defaults" ]
|
||||
sources = [ "fsck/main.c" ]
|
||||
sources = [
|
||||
"fsck/de_iter.c",
|
||||
"fsck/fsck.c",
|
||||
"fsck/repair.c",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"./libexfat",
|
||||
"./lib",
|
||||
"./mkfs",
|
||||
"./fsck",
|
||||
]
|
||||
@@ -105,13 +99,13 @@ ohos_executable("fsck.exfat") {
|
||||
}
|
||||
|
||||
###################################################
|
||||
##Build dumpexfat
|
||||
ohos_executable("dumpexfat") {
|
||||
##Build dump.exfat
|
||||
ohos_executable("dump.exfat") {
|
||||
configs = [ ":exfat-defaults" ]
|
||||
sources = [ "dump/main.c" ]
|
||||
sources = [ "dump/dump.c" ]
|
||||
|
||||
include_dirs = [
|
||||
"./libexfat",
|
||||
"./lib",
|
||||
"./mkfs",
|
||||
"./fsck",
|
||||
"./dump",
|
||||
@@ -126,10 +120,28 @@ ohos_executable("dumpexfat") {
|
||||
##Build exfatlable
|
||||
ohos_executable("exfatlable") {
|
||||
configs = [ ":exfat-defaults" ]
|
||||
sources = [ "label/main.c" ]
|
||||
sources = [ "label/label.c" ]
|
||||
|
||||
include_dirs = [
|
||||
"./libexfat",
|
||||
"./lib",
|
||||
"./mkfs",
|
||||
"./fsck",
|
||||
"./label",
|
||||
]
|
||||
|
||||
deps = [ ":libexfat" ]
|
||||
subsystem_name = "filemanagement"
|
||||
part_name = "storage_service"
|
||||
}
|
||||
|
||||
###################################################
|
||||
##Build tune.exfat
|
||||
ohos_executable("tune.exfat") {
|
||||
configs = [ ":exfat-defaults" ]
|
||||
sources = [ "tune/tune.c" ]
|
||||
|
||||
include_dirs = [
|
||||
"./lib",
|
||||
"./mkfs",
|
||||
"./fsck",
|
||||
"./label",
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
1.3.0 (2018-09-15)
|
||||
|
||||
* exfatfsck can now repair some errors.
|
||||
* Added experimental Android support for exfat-utils [liminghao, LongPingWEI,
|
||||
Pablo Mendez Hernandez, Pierre-Hugues Husson].
|
||||
* Cleaned up FUSE code preparing for FUSE 3 support.
|
||||
* Removed OpenBSD support as it does not handle -o option in fuse_main().
|
||||
* Re-introduced FreeBSD support [Oleksii Samorukov].
|
||||
* Fixed DragonFly BSD support [Tomohiro Kusumi].
|
||||
* dirent->d_type in now filled on readdir() [Mark Browning].
|
||||
|
||||
1.2.8 (2018-02-03)
|
||||
|
||||
* Fixed new files or directories creation in the root directory: ensure there
|
||||
are no 0x00 entries before valid ones; otherwise Windows can corrupt them.
|
||||
* Fixed compilation on GNU/HURD platform.
|
||||
|
||||
1.2.7 (2017-06-05)
|
||||
|
||||
* Fixed handling of two last clusters: operations with files that occupy these
|
||||
clusters could fail.
|
||||
* Fixed crash when started with stdin, stdout or stderr closed.
|
||||
|
||||
1.2.6 (2017-01-28)
|
||||
|
||||
* Operations with directories (except initial listing) now make less
|
||||
read/write system calls.
|
||||
* Fixed handling of files with optional tail entries (0xe0-0xff): videoclip
|
||||
files created by Sony cameras were missing.
|
||||
* Write operations now correctly return ENOSPC (instead of EIO) when there is
|
||||
no free disk space left.
|
||||
* Fixed max file name length: it's 255 16-bit code units (not 256).
|
||||
|
||||
1.2.5 (2016-12-05)
|
||||
|
||||
* Added an option for dumpexfat to show file fragments [Daniel Drake].
|
||||
* Fixed crash when directory starts with an invalid cluster.
|
||||
* Daylight saving time in now properly reflected in file timestamps.
|
||||
|
||||
1.2.4 (2016-06-03)
|
||||
|
||||
* Fixed wrong files names hashes when upper case table is compressed.
|
||||
* Man pages are now installed by default.
|
||||
* Commas and backslashes in device names are now escaped.
|
||||
|
||||
1.2.3 (2015-12-19)
|
||||
|
||||
* Fixed clusters loss when file renaming replaces target.
|
||||
|
||||
1.2.2 (2015-11-09)
|
||||
|
||||
* Improved reliability in case of a sudden unplug: FS will be in a clean state
|
||||
after closing all files and performing sync(1).
|
||||
* Fixed compilation on Debian GNU/kFreeBSD and GNU/Hurd platforms.
|
||||
* Updated mount.exfat-fuse man page.
|
||||
|
||||
1.2.1 (2015-09-24)
|
||||
|
||||
* Fixed compatibility with Zalman VE-200: now newly created directories do not
|
||||
have archive bit set.
|
||||
* Fixed heap corruption: malformed FS can use invalid sector or cluster size.
|
||||
* Fixed hang on mount: malformed FS can have cyclic references in the clusters
|
||||
map.
|
||||
|
||||
1.2.0 (2015-08-26)
|
||||
|
||||
* Switched from SCons to autotools.
|
||||
* Added musl libc support [Brendan Heading].
|
||||
* Worked around "FS is larger than device" error for memory cards formatted by
|
||||
Panasonic Lumix cameras.
|
||||
* Worked around "unknown entry type 0xe1" error for memory cards formatted by
|
||||
Sony cameras.
|
||||
|
||||
1.1.1 (2014-11-15)
|
||||
|
||||
* Fixed mkfs crash on some sectors-per-cluster (-s option) values.
|
||||
|
||||
1.1.0 (2014-07-08)
|
||||
|
||||
* Relicensed the project from GPLv3+ to GPLv2+.
|
||||
* OpenBSD support [Helg Bredow].
|
||||
* Improved I/O errors handling.
|
||||
* Implemented fsync() and fsyncdir().
|
||||
* Fixed crash on Mac OS X 10.5 caused by non-standard use of realpath(). Also
|
||||
fixed TrueCrypt disks unmounting.
|
||||
* Avoid extra erase on writes to the end of a file. This should improve linear
|
||||
write speed.
|
||||
* Allow arbitrary changing of lower 9 bits of mode. Allow owner/group changing
|
||||
to the same owner/group. This fixes rsync.
|
||||
* Fixed buffers overflows when handling lengthy file names.
|
||||
* Fixed "real size does not equal to size" error on volumes with pagefile.sys.
|
||||
* Fixed negative IUsed in "df -i" output.
|
||||
|
||||
1.0.1 (2013-02-02)
|
||||
|
||||
* Fixed unexpected removal of a directory if it is moved into itself.
|
||||
* Fixed "Operation not permitted" error on reading an empty file.
|
||||
|
||||
1.0.0 (2013-01-19)
|
||||
|
||||
* Fixed crash when renaming a file within a single directory and a new name
|
||||
differs only in case.
|
||||
* Fixed clusters allocation: a cluster beyond valid clusters range could be
|
||||
allocated.
|
||||
* Fixed crash when a volume is unmounted while some files are open.
|
||||
* SConscript now respects AR and RANLIB environment variables.
|
||||
* Improved error handling.
|
||||
|
||||
Linux:
|
||||
|
||||
* Enabled big_writes. This improves write speed (larger block size means less
|
||||
switches between kernel- and user-space).
|
||||
* Do BLKROGET ioctl to make sure the device is not read-only: after
|
||||
"blockdev --setro" kernel still allows to open the device in read-write mode
|
||||
but fails writes.
|
||||
|
||||
OS X:
|
||||
|
||||
* Fixed OS X 10.8 support.
|
||||
* Switched to 64-bit inode numbers (now Mac OS X 10.5 or later is required).
|
||||
* Switched from unmaintained MacFUSE to OSXFUSE (http://osxfuse.github.com).
|
||||
* Fixed device size detection. Now mkfs works.
|
||||
* Workarounded some utilities failures due to missing chmod() support.
|
||||
* Disabled (senseless) permission checks made by FUSE.
|
||||
|
||||
0.9.8 (2012-08-09)
|
||||
|
||||
* The mkfs utility can now create huge file systems (up to several exabytes).
|
||||
* Fixed handling of characters beyond Basic Multilingual Plane.
|
||||
* Echo messages to syslog only if stderr is not connected to a terminal.
|
||||
|
||||
0.9.7 (2012-03-08)
|
||||
|
||||
* Out-of-the-box FreeBSD support (via ublio library).
|
||||
* Fixed "missing EOD entry" error (could happen while reading directory that
|
||||
consists of several clusters).
|
||||
* Fixed interpretation of minutes field in files timestamps (minutes could be
|
||||
displayed incorrectly).
|
||||
* Fixed mtime seconds field initialization for newly created file (mtime could
|
||||
be 1 sec less than creation time).
|
||||
* SConscript now respects CC, CCFLAGS and LDFLAGS environment variables.
|
||||
|
||||
0.9.6 (2012-01-14)
|
||||
|
||||
* Fixed write performance regression introduced in 0.9.4.
|
||||
* Mount in read-only mode if the device is write-protected.
|
||||
* Set ctime to mtime to ensure we don't break programs that rely on ctime
|
||||
(e.g. rsync considered that all files are outdated) [Eldad Zack].
|
||||
* Indicate that FS in not clean when it was not cleanly unmounted.
|
||||
* Utilities are now compatible with GNU/Hurd.
|
||||
* Fixed several memory leaks that could occur on error handling paths.
|
||||
* Improved handling of corrupted file systems.
|
||||
|
||||
0.9.5 (2011-05-15)
|
||||
|
||||
* Fixed erasing of the root directory cluster when creating a new FS with
|
||||
mkexfatfs. This bug could cause mkexfatfs to produce invalid FS.
|
||||
* Utilities are not linked with libfuse anymore.
|
||||
* Ensure that the path being opened is either a device or a regular file.
|
||||
|
||||
0.9.4 (2011-03-05)
|
||||
|
||||
* Introduced exfat-utils: dumpexfat, exfatfsck, mkexfatfs, exfatlabel.
|
||||
* Fixed "Invalid argument" error while mounting a volume from a disk with sector size greater than 512 bytes.
|
||||
* Wait for all data to be flushed to disk on unmount.
|
||||
* Kernel cache is no longer flushed on open. This can slightly improve read performance by avoiding extra read requests from kernel to user-space.
|
||||
* Allow to unmount volumes as user (fusermount -u) if they were mounted from the very same user [Tino Lange].
|
||||
* Errors and warnings are now duplicated to syslog.
|
||||
|
||||
0.9.3 (2010-09-25)
|
||||
|
||||
* Directories now can shrink.
|
||||
* Improved timestamps resolution from 2 sec to 1 sec.
|
||||
* Fixed timestamps displaying under Mac OS X when compiled for i386 or ppc.
|
||||
* Fixed FS size displaying for non-GNU systems.
|
||||
|
||||
0.9.2 (2010-07-24)
|
||||
|
||||
* Fixed a bug which could cause the whole directory to become unreadable after renaming a file in it.
|
||||
* Support for Solaris and various *BSD [Albert Lee].
|
||||
* Improved error handling on corrupted volumes.
|
||||
* Improved allowed file name characters filter.
|
||||
* Added man page.
|
||||
|
||||
0.9.1 (2010-06-12)
|
||||
|
||||
* Implemented automounting (util-linux-ng 2.18 or later is required).
|
||||
* Fixed mounting when cluster bitmap is larger than expected.
|
||||
* Fixed crash on statfs() when root directory contains error.
|
||||
* Fixed bugs specific to big-endian machines.
|
||||
* Other bugfixes.
|
||||
|
||||
0.9.0 (2010-03-21)
|
||||
|
||||
* Initial release.
|
||||
+24
-22
@@ -1,23 +1,25 @@
|
||||
#
|
||||
# Makefile.am (30.03.15)
|
||||
# Automake source.
|
||||
#
|
||||
# Free exFAT implementation.
|
||||
# Copyright (C) 2010-2018 Andrew Nayenko
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
## Makefile.am
|
||||
|
||||
SUBDIRS = libexfat dump fsck fuse label mkfs
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = lib mkfs fsck tune label dump
|
||||
|
||||
# manpages
|
||||
dist_man8_MANS = \
|
||||
manpages/fsck.exfat.8 \
|
||||
manpages/tune.exfat.8 \
|
||||
manpages/mkfs.exfat.8 \
|
||||
manpages/exfatlabel.8 \
|
||||
manpages/dump.exfat.8
|
||||
|
||||
# other stuff
|
||||
EXTRA_DIST = \
|
||||
include \
|
||||
Android.bp \
|
||||
lib/Android.bp \
|
||||
mkfs/Android.bp \
|
||||
tune/Android.bp \
|
||||
fsck/Android.bp \
|
||||
label/Android.bp \
|
||||
dump/Android.bp \
|
||||
README.md
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
exfatprogs 1.1.3 - released 2021-11-11
|
||||
======================================
|
||||
|
||||
CHANGES :
|
||||
* mkfs.exfat: ensure that the cluster size is greater than or
|
||||
equal than the sector size.
|
||||
* mkfs.exfat: replace lseek() + write() with pwrite().
|
||||
|
||||
BUG FIXES :
|
||||
* mkfs.exfat: prevent an integer overflow when computing the FAT
|
||||
length.
|
||||
* fsck.exfat: fix a double free memory error.
|
||||
|
||||
exfatprogs 1.1.2 - released 2021-05-20
|
||||
======================================
|
||||
|
||||
CHANGES :
|
||||
* mkfs.exfat: set 0x80 to DriveSelect of the boot sector
|
||||
|
||||
BUG FIXES :
|
||||
* Fix issues on 4KB logical sector devices
|
||||
* Fix issues when the sector size of of a file system is different from
|
||||
that of a block device.
|
||||
|
||||
exfatprogs 1.1.1 - released 2021-04-21
|
||||
======================================
|
||||
|
||||
CHANGES :
|
||||
* mkfs.exfat: adjust the boundary alignment calculations to compensate
|
||||
for the volume offset.
|
||||
|
||||
NEW FEATURES :
|
||||
* mkfs.exfat: add the "--pack-bitmap" option to relocate the allocation
|
||||
bitmap to allow the FAT and the bitmap to share the same allocation
|
||||
unit on flash media.
|
||||
|
||||
BUG FIXES :
|
||||
* Fix wrong bit operations on 64-bit big.
|
||||
* Fix memory leaks in error paths.
|
||||
|
||||
exfatprogs 1.1.0 - released 2021-02-09
|
||||
======================================
|
||||
|
||||
CHANGES :
|
||||
* fsck.exfat: recover corrupted boot region.
|
||||
|
||||
NEW FEATURES :
|
||||
* exfatlabel: Print or Set volume label and serial.
|
||||
* dump.exfat: Show the on-disk metadata information and the statistics.
|
||||
|
||||
BUG FIXES :
|
||||
* set _FILE_OFFSET_BITS=64 for Android build.
|
||||
|
||||
exfatprogs 1.0.4 - released 2020-07-31
|
||||
======================================
|
||||
|
||||
CHANGES :
|
||||
* fsck.exfat: display sector, cluster, and volume sizes in the human
|
||||
readable format.
|
||||
* fsck.exfat: reduce the elapsed time using read-ahead.
|
||||
|
||||
NEW FEATURES :
|
||||
* mkfs.exfat: generate pseudo unique serials while creating filesystems.
|
||||
* mkfs.exfat: add the "-b" option to align the start offset of FAT and
|
||||
data clusters.
|
||||
* fsck.exfat: repair zero-byte files which have the NoFatChain attribute.
|
||||
|
||||
BUG FIXES :
|
||||
* Fix memory leaks on error handling paths.
|
||||
* fsck.exfat: fix the bug that cannot access space beyond 2TB.
|
||||
|
||||
exfatprogs 1.0.3 - released 2020-05-12
|
||||
======================================
|
||||
|
||||
CHANGES :
|
||||
* Rename label.exfat to tune.exfat.
|
||||
* tune.exfat: change argument style(-l option for print level,
|
||||
-L option for setting label)
|
||||
* mkfs.exfat: harmonize set volume label option with tune.exfat.
|
||||
|
||||
NEW FEATURES :
|
||||
* Add man page.
|
||||
|
||||
BUG FIXES :
|
||||
* Fix the reported build warnings/errors.
|
||||
* Add memset to clean garbage in allocation.
|
||||
* Fix wrong volume label array size.
|
||||
* Open a device using O_EXCL to avoid formatting it while it is mounted.
|
||||
* Fix incomplete "make dist" generated tarball.
|
||||
|
||||
|
||||
exfatprogs 1.0.2 - released 2020-04-23
|
||||
======================================
|
||||
|
||||
CHANGES :
|
||||
* Rename project name to exfatprogs.
|
||||
* Replace iconv library by standard C functions mbstowcs() and wcrtomb().
|
||||
|
||||
NEW FEATURES :
|
||||
* Add support for Android build system.
|
||||
* label.exfat: Add support for label.exfat to set/get exfat volume label.
|
||||
|
||||
BUG FIXES :
|
||||
* Fix the build warnings/errors and add warning options.
|
||||
* Fix several bugs(memory leak, wrong endian conversion, zero out beyond
|
||||
end of file) and cleanup codes
|
||||
* Fix issues on big endian system and on 32bit system.
|
||||
|
||||
|
||||
exfatprogs 1.0.1 - released 2020-04-09
|
||||
======================================
|
||||
|
||||
NEW FEATURES :
|
||||
* mkfs.exfat: quick/full format support
|
||||
* mkfs.exfat: specify cluster size
|
||||
* mkfs.exfat: set volume label
|
||||
* fsck.exfat: consistency check support
|
||||
@@ -50,19 +50,23 @@
|
||||
<licensefile>COPYING</licensefile>
|
||||
<policylist>
|
||||
<policy name="projectPolicy" desc="">
|
||||
<policyitem type="compatibility" name="GPL-2.0-or-later" path=".*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter" desc="独立进程,独立使用"/>
|
||||
<policyitem type="license" name="GPL-2.0-or-later" path="*/.*" rule="may" group="defaultGroup" filefilter="GPL-2.0-or-later" desc="License is new."/>
|
||||
<policyitem type="copyright" name="Andrew Nayenko" path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
||||
<policyitem type="compatibility" name="GPL-2.0-or-later" path=".*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter" desc=""/>
|
||||
<policyitem type="license" name="GPL-2.0-or-later" path=".*" desc=""/>
|
||||
<policyitem type="copyright" name="Namjae Jeon" path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
||||
<policyitem type="copyright" name="Hyunchul Lee" path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
||||
<policyitem type="copyright" name="Huawei Device Co., Ltd." path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
||||
</policy>
|
||||
</policylist>
|
||||
|
||||
<filefilterlist>
|
||||
<filefilter name="defaultFilter" desc="Files not to check">
|
||||
<filteritem type="filename" name="*.8|README.OpenSource|ChangeLog" desc="NoLicenseHeader"/>
|
||||
<filteritem type="filename" name=".travis_get_mainline_kernel|Makefile.am|autogen.sh|configure.ac|test_fsck.sh" desc="License and Copyright Header Invalid"/>
|
||||
<filteritem type="filepath" name="manpages/.*" desc="License and Copyright Header Invalid"/>
|
||||
</filefilter>
|
||||
<filefilter name="defaultPolicyFilter" desc="Filters for compatibility,license header policies">
|
||||
</filefilter>
|
||||
<filefilter name="copyrightPolicyFilter" desc="Filters for copyright header policies">
|
||||
<filteritem type="filename" name="list.h" desc="desc files"/>
|
||||
</filefilter>
|
||||
<filefilter name="licenseFileNamePolicyFilter" desc="Filters for LICENSE file policies">
|
||||
</filefilter>
|
||||
@@ -71,7 +75,8 @@
|
||||
<filefilter name="readmeOpenSourcefileNamePolicyFilter" desc="Filters for README.OpenSource file policies">
|
||||
</filefilter>
|
||||
<filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies">
|
||||
<filteritem type="filepath" name="tests/.*" desc="Test files"/>
|
||||
</filefilter>
|
||||
</filefilterlist>
|
||||
</oatconfig>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
[
|
||||
{
|
||||
"Name" : "exfat-utils",
|
||||
"Name" : "exfatprogs",
|
||||
"License" : "GPL-2.0-or-later",
|
||||
"License File" : "COPYING",
|
||||
"Version Number" : "1.3.0",
|
||||
"Owner" : "relan@users.noreply.github.com",
|
||||
"Upstream URL" : "https://github.com/relan/exfat",
|
||||
"Description" : "Free exFAT file system implementation."
|
||||
"Version Number" : "1.1.3",
|
||||
"Owner" : "Namjae Jeon",
|
||||
"Upstream URL" : "https://github.com/exfatprogs/exfatprogs/releases/download/1.1.3/exfatprogs-1.1.3.tat.gz",
|
||||
"Description" : "exFAT filesystem userspace utilities."
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,83 +1,119 @@
|
||||
About
|
||||
-----
|
||||
|
||||
This project aims to provide a full-featured [exFAT][1] file system implementation for Unix-like systems. It consists of a [FUSE][2] module (fuse-exfat) and a set of utilities (exfat-utils).
|
||||
## exfatprogs
|
||||
As new exfat filesystem is merged into linux-5.7 kernel, exfatprogs is
|
||||
created as an official userspace utilities that contain all of the standard
|
||||
utilities for creating and fixing and debugging exfat filesystem in linux
|
||||
system. The goal of exfatprogs is to provide high performance and quality
|
||||
at the level of exfat utilities in windows. And this software is licensed
|
||||
under the GNU General Public License Version 2.
|
||||
|
||||
Supported operating systems:
|
||||
## Building exfatprogs
|
||||
Install prerequisite packages:
|
||||
```
|
||||
For Ubuntu:
|
||||
sudo apt-get install autoconf libtool pkg-config
|
||||
|
||||
* GNU/Linux
|
||||
* Mac OS X 10.5 or later
|
||||
* FreeBSD
|
||||
For Fedora, RHEL:
|
||||
sudo yum install autoconf automake libtool
|
||||
```
|
||||
|
||||
Most GNU/Linux distributions already have fuse-exfat and exfat-utils in their repositories, so you can just install and use them. The next chapter describes how to compile them from source.
|
||||
|
||||
Compiling
|
||||
---------
|
||||
|
||||
To build this project on GNU/Linux you need to install the following packages:
|
||||
|
||||
* [git][4]
|
||||
* [autoconf][5]
|
||||
* [automake][6]
|
||||
* [pkg-config][7]
|
||||
* fuse-devel (or libfuse-dev)
|
||||
* [gcc][8]
|
||||
* [make][9]
|
||||
|
||||
On Mac OS X:
|
||||
|
||||
* autoconf
|
||||
* automake
|
||||
* pkg-config
|
||||
* [OSXFUSE][10]
|
||||
* [Xcode][11] (legacy versions include autotools but their versions are too old)
|
||||
|
||||
On OpenBSD:
|
||||
|
||||
* git
|
||||
* autoconf (set AUTOCONF_VERSION environment variable)
|
||||
* automake (set AUTOMAKE_VERSION environment variable)
|
||||
|
||||
Get the source code, change directory and compile:
|
||||
|
||||
git clone https://github.com/relan/exfat.git
|
||||
cd exfat
|
||||
autoreconf --install
|
||||
Build steps:
|
||||
```
|
||||
cd into the exfatprogs directory:
|
||||
./autogen.sh
|
||||
./configure
|
||||
make
|
||||
|
||||
Then install driver and utilities (from root):
|
||||
|
||||
make install
|
||||
```
|
||||
|
||||
You can remove them using this command (from root):
|
||||
## Using exfatprogs
|
||||
```
|
||||
- mkfs.exfat:
|
||||
Build a exfat filesystem on a device or partition(e.g. /dev/hda1, dev/sda1).
|
||||
|
||||
make uninstall
|
||||
Usage example:
|
||||
1. No option(default) : cluster size adjustment as per device size, quick format.
|
||||
mkfs.exfat /dev/sda1
|
||||
2. To change cluster size(KB or MB or Byte) user want
|
||||
mkfs.exfat -c 1048576 /dev/sda1
|
||||
mkfs.exfat -c 1024K /dev/sda1
|
||||
mkfs.exfat -c 1M /dev/sda1
|
||||
3. For full format(zero out)
|
||||
mkfs.exfat -f /dev/sda1
|
||||
4. For set volume label, use -l option with string user want.
|
||||
mkfs.exfat -L "my usb" /dev/sda1
|
||||
5. To change boundary alignment(KB or MB or Byte) user want
|
||||
mkfs.exfat -b 16777216 /dev/sda1
|
||||
mkfs.exfat -b 16384K /dev/sda1
|
||||
mkfs.exfat -b 16M /dev/sda1
|
||||
|
||||
Mounting
|
||||
--------
|
||||
- fsck.exfat:
|
||||
Check the consistency of your exfat filesystem and optionally repair a corrupted device formatted by exfat.
|
||||
|
||||
Modern GNU/Linux distributions (with [util-linux][12] 2.18 or later) will mount exFAT volumes automatically. Anyway, you can mount manually (from root):
|
||||
Usage example:
|
||||
1. check the consistency.
|
||||
fsck.exfat /dev/sda1
|
||||
2. repair and fix.(preparing)
|
||||
|
||||
mount.exfat-fuse /dev/spec /mnt/exfat
|
||||
- tune.exfat:
|
||||
Adjust tunable filesystem parameters on an exFAT filesystem
|
||||
|
||||
where /dev/spec is the [device file][13], /mnt/exfat is a mountpoint.
|
||||
Usage example:
|
||||
1. print current volume label.
|
||||
tune.exfat -l /dev/sda1
|
||||
2. set new volume label.
|
||||
tune.exfat -L "new label" /dev/sda1
|
||||
3. print current volume serial.
|
||||
tune.exfat -i /dev/sda1
|
||||
4. set new volume serial.
|
||||
tune.exfat -I 0x12345678 /dev/sda1
|
||||
|
||||
Feedback
|
||||
--------
|
||||
- exfatlabel:
|
||||
Get or Set volume label or serial
|
||||
|
||||
If you have any questions, issues, suggestions, bug reports, etc. please create an [issue][3]. Pull requests are also welcome!
|
||||
Usage example:
|
||||
1. get current volume label.
|
||||
exfatlabel /dev/sda1
|
||||
2. set new volume label.
|
||||
exfatlabel /dev/sda1 "new label"
|
||||
3. get current volume serial.
|
||||
exfatlabel -i /dev/sda1
|
||||
4. set new volume serial.
|
||||
exfatlabel -i /dev/sda1 0x12345678
|
||||
|
||||
[1]: https://en.wikipedia.org/wiki/ExFAT
|
||||
[2]: https://en.wikipedia.org/wiki/Filesystem_in_Userspace
|
||||
[3]: https://github.com/relan/exfat/issues
|
||||
[4]: https://www.git-scm.com/
|
||||
[5]: https://www.gnu.org/software/autoconf/
|
||||
[6]: https://www.gnu.org/software/automake/
|
||||
[7]: http://www.freedesktop.org/wiki/Software/pkg-config/
|
||||
[8]: https://gcc.gnu.org/
|
||||
[9]: https://www.gnu.org/software/make/
|
||||
[10]: https://osxfuse.github.io/
|
||||
[11]: https://en.wikipedia.org/wiki/Xcode
|
||||
[12]: https://www.kernel.org/pub/linux/utils/util-linux/
|
||||
[13]: https://en.wikipedia.org/wiki/Device_file
|
||||
- dump.exfat:
|
||||
Show on-disk information
|
||||
|
||||
Usage example:
|
||||
dump.exfat /dev/sda1
|
||||
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Some fsck implementations were tested and compared for Samsung 64GB Pro
|
||||
microSDXC UHS-I Class 10 which was filled up to 35GB with 9948 directories
|
||||
and 16506 files by fsstress.
|
||||
|
||||
The difference in the execution time for each testing is very small.
|
||||
|
||||
|
||||
| Implementation | version | execution time (seconds) |
|
||||
|----------------------|-----------------|--------------------------|
|
||||
| **exfatprogs fsck** | 1.0.4 | 11.561 |
|
||||
| Windows fsck | Windows 10 1809 | 11.449 |
|
||||
| [exfat-fuse fsck] | 1.3.0 | 68.977 |
|
||||
|
||||
[exfat-fuse fsck]: https://github.com/relan/exfat
|
||||
|
||||
## Sending feedback
|
||||
If you have any issues, please create [issues][1] or contact to [Namjae Jeon](mailto:linkinjeon@kernel.org) and
|
||||
[Hyunchul Lee](mailto:hyc.lee@gmail.com).
|
||||
[Contributions][2] are also welcome.
|
||||
|
||||
[1]: https://github.com/exfatprogs/exfatprogs/issues
|
||||
[2]: https://github.com/exfatprogs/exfatprogs/pulls
|
||||
|
||||
## Contributor information
|
||||
* Please base your pull requests on the `exfat-next` branch.
|
||||
* Make sure you add 'Signed-Off' information to your commits (e.g. `git commit --signoff`).
|
||||
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
autoreconf --install --verbose
|
||||
+31
-51
@@ -1,57 +1,37 @@
|
||||
#
|
||||
# configure.ac (30.03.15)
|
||||
# Autoconf source.
|
||||
#
|
||||
# Free exFAT implementation.
|
||||
# Copyright (C) 2010-2018 Andrew Nayenko
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
AC_PREREQ([2.68])
|
||||
|
||||
AC_INIT([Free exFAT implementation],
|
||||
[1.3.0],
|
||||
[relan@users.noreply.github.com],
|
||||
[exfat],
|
||||
[https://github.com/relan/exfat])
|
||||
AM_INIT_AUTOMAKE([1.11.2 -Wall -Werror foreign subdir-objects])
|
||||
m4_define([exfat_progs_version], m4_esyscmd_s(
|
||||
grep "define EXFAT_PROGS_VERSION " include/version.h | \
|
||||
awk '{print $3}' | sed 's/\"//g'))
|
||||
|
||||
AC_INIT([exfatprogs],
|
||||
exfat_progs_version,
|
||||
[linkinjeon@kernel.org],
|
||||
[exfatprogs],
|
||||
[https://github.com/exfatprogs/exfatprogs])
|
||||
|
||||
AC_CONFIG_SRCDIR([config.h.in])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AM_INIT_AUTOMAKE([foreign tar-pax dist-xz subdir-objects])
|
||||
|
||||
AC_LANG([C])
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_C99
|
||||
AC_PROG_RANLIB
|
||||
AM_PROG_AR
|
||||
AC_PROG_CC_STDC
|
||||
AM_SILENT_RULES([yes])
|
||||
AC_PROG_LIBTOOL
|
||||
AC_SYS_LARGEFILE
|
||||
AC_CANONICAL_HOST
|
||||
PKG_CHECK_MODULES([UBLIO], [libublio], [
|
||||
CFLAGS="$CFLAGS $UBLIO_CFLAGS"
|
||||
LIBS="$LIBS $UBLIO_LIBS"
|
||||
AC_DEFINE([USE_UBLIO], [1],
|
||||
[Define if block devices are not supported.])
|
||||
], [:])
|
||||
PKG_CHECK_MODULES([FUSE], [fuse])
|
||||
case "$host_os" in
|
||||
*-gnu)
|
||||
AC_DEFINE([_XOPEN_SOURCE], [500], [Enable pread() and pwrite().])
|
||||
AC_DEFINE([_DEFAULT_SOURCE], [], [Enable vsyslog().])
|
||||
;;
|
||||
esac
|
||||
AC_CONFIG_HEADERS([libexfat/config.h])
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
libexfat/Makefile
|
||||
dump/Makefile
|
||||
fsck/Makefile
|
||||
fuse/Makefile
|
||||
label/Makefile
|
||||
Makefile
|
||||
lib/Makefile
|
||||
mkfs/Makefile
|
||||
Makefile])
|
||||
fsck/Makefile
|
||||
tune/Makefile
|
||||
label/Makefile
|
||||
dump/Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
+5
-26
@@ -1,27 +1,6 @@
|
||||
#
|
||||
# Makefile.am (30.03.15)
|
||||
# Automake source.
|
||||
#
|
||||
# Free exFAT implementation.
|
||||
# Copyright (C) 2011-2018 Andrew Nayenko
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common
|
||||
dump_exfat_LDADD = $(top_builddir)/lib/libexfat.a
|
||||
|
||||
sbin_PROGRAMS = dumpexfat
|
||||
dist_man8_MANS = dumpexfat.8
|
||||
dumpexfat_SOURCES = main.c
|
||||
dumpexfat_CPPFLAGS = -I$(top_srcdir)/libexfat
|
||||
dumpexfat_LDADD = ../libexfat/libexfat.a
|
||||
sbin_PROGRAMS = dump.exfat
|
||||
|
||||
dump_exfat_SOURCES = dump.c
|
||||
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2021 Namjae Jeon <linkinjeon@kernel.org>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "exfat_ondisk.h"
|
||||
#include "libexfat.h"
|
||||
|
||||
#define EXFAT_MIN_SECT_SIZE_BITS 9
|
||||
#define EXFAT_MAX_SECT_SIZE_BITS 12
|
||||
#define BITS_PER_BYTE 8
|
||||
#define BITS_PER_BYTE_MASK 0x7
|
||||
|
||||
static const unsigned char used_bit[] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/* 0 ~ 19*/
|
||||
2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~ 39*/
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~ 59*/
|
||||
4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~ 79*/
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~ 99*/
|
||||
3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/
|
||||
4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/
|
||||
3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/
|
||||
4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/
|
||||
5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/
|
||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /*240 ~ 255*/
|
||||
};
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: dump.exfat\n");
|
||||
fprintf(stderr, "\t-V | --version Show version\n");
|
||||
fprintf(stderr, "\t-h | --help Show help\n");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static struct option opts[] = {
|
||||
{"version", no_argument, NULL, 'V' },
|
||||
{"help", no_argument, NULL, 'h' },
|
||||
{"?", no_argument, NULL, '?' },
|
||||
{NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
static unsigned int exfat_count_used_clusters(unsigned char *bitmap,
|
||||
unsigned long long bitmap_len)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
unsigned long long i;
|
||||
|
||||
for (i = 0; i < bitmap_len; i++)
|
||||
count += used_bit[bitmap[i]];
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd)
|
||||
{
|
||||
struct pbr *ppbr;
|
||||
struct bsx64 *pbsx;
|
||||
struct exfat_dentry *ed;
|
||||
unsigned int root_clu_off, bitmap_clu_off, bitmap_clu;
|
||||
unsigned int total_clus, used_clus, clu_offset, root_clu;
|
||||
unsigned long long bitmap_len;
|
||||
int ret;
|
||||
unsigned char *bitmap;
|
||||
char *volume_label;
|
||||
|
||||
ppbr = malloc(EXFAT_MAX_SECTOR_SIZE);
|
||||
if (!ppbr) {
|
||||
exfat_err("Cannot allocate pbr: out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* read main boot sector */
|
||||
if (exfat_read(bd->dev_fd, (char *)ppbr, EXFAT_MAX_SECTOR_SIZE,
|
||||
0) != (ssize_t)EXFAT_MAX_SECTOR_SIZE) {
|
||||
exfat_err("main boot sector read failed\n");
|
||||
ret = -EIO;
|
||||
goto free_ppbr;
|
||||
}
|
||||
|
||||
pbsx = &ppbr->bsx;
|
||||
|
||||
if (pbsx->sect_size_bits < EXFAT_MIN_SECT_SIZE_BITS ||
|
||||
pbsx->sect_size_bits > EXFAT_MAX_SECT_SIZE_BITS) {
|
||||
exfat_err("bogus sector size bits : %u\n",
|
||||
pbsx->sect_size_bits);
|
||||
ret = -EINVAL;
|
||||
goto free_ppbr;
|
||||
}
|
||||
|
||||
if (pbsx->sect_per_clus_bits > 25 - pbsx->sect_size_bits) {
|
||||
exfat_err("bogus sectors bits per cluster : %u\n",
|
||||
pbsx->sect_per_clus_bits);
|
||||
ret = -EINVAL;
|
||||
goto free_ppbr;
|
||||
}
|
||||
|
||||
bd->sector_size_bits = pbsx->sect_size_bits;
|
||||
bd->sector_size = 1 << pbsx->sect_size_bits;
|
||||
|
||||
clu_offset = le32_to_cpu(pbsx->clu_offset);
|
||||
total_clus = le32_to_cpu(pbsx->clu_count);
|
||||
root_clu = le32_to_cpu(pbsx->root_cluster);
|
||||
|
||||
exfat_info("-------------- Dump Boot sector region --------------\n");
|
||||
exfat_info("Volume Length(sectors): \t\t%" PRIu64 "\n",
|
||||
le64_to_cpu(pbsx->vol_length));
|
||||
exfat_info("FAT Offset(sector offset): \t\t%u\n",
|
||||
le32_to_cpu(pbsx->fat_offset));
|
||||
exfat_info("FAT Length(sectors): \t\t\t%u\n",
|
||||
le32_to_cpu(pbsx->fat_length));
|
||||
exfat_info("Cluster Heap Offset (sector offset): \t%u\n", clu_offset);
|
||||
exfat_info("Cluster Count: \t\t\t\t%u\n", total_clus);
|
||||
exfat_info("Root Cluster (cluster offset): \t\t%u\n", root_clu);
|
||||
exfat_info("Volume Serial: \t\t\t\t0x%x\n", le32_to_cpu(pbsx->vol_serial));
|
||||
exfat_info("Sector Size Bits: \t\t\t%u\n", pbsx->sect_size_bits);
|
||||
exfat_info("Sector per Cluster bits: \t\t%u\n\n", pbsx->sect_per_clus_bits);
|
||||
|
||||
bd->cluster_size =
|
||||
1 << (pbsx->sect_per_clus_bits + pbsx->sect_size_bits);
|
||||
root_clu_off = exfat_clus_to_blk_dev_off(bd, clu_offset, root_clu);
|
||||
|
||||
ed = malloc(sizeof(struct exfat_dentry)*3);
|
||||
if (!ed) {
|
||||
exfat_err("failed to allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_ppbr;
|
||||
}
|
||||
|
||||
ret = exfat_read(bd->dev_fd, ed, sizeof(struct exfat_dentry)*3,
|
||||
root_clu_off);
|
||||
if (ret < 0) {
|
||||
exfat_err("bitmap entry read failed: %d\n", errno);
|
||||
ret = -EIO;
|
||||
goto free_entry;
|
||||
}
|
||||
|
||||
volume_label = exfat_conv_volume_label(&ed[0]);
|
||||
if (!volume_label) {
|
||||
ret = -EINVAL;
|
||||
goto free_entry;
|
||||
}
|
||||
|
||||
bitmap_clu = le32_to_cpu(ed[1].bitmap_start_clu);
|
||||
bitmap_clu_off = exfat_clus_to_blk_dev_off(bd, clu_offset,
|
||||
bitmap_clu);
|
||||
bitmap_len = le64_to_cpu(ed[1].bitmap_size);
|
||||
|
||||
exfat_info("----------------- Dump Root entries -----------------\n");
|
||||
exfat_info("Volume entry type: \t\t\t0x%x\n", ed[0].type);
|
||||
exfat_info("Volume label: \t\t\t\t%s\n", volume_label);
|
||||
exfat_info("Volume label character count: \t\t%u\n", ed[0].vol_char_cnt);
|
||||
|
||||
exfat_info("Bitmap entry type: \t\t\t0x%x\n", ed[1].type);
|
||||
exfat_info("Bitmap start cluster: \t\t\t%x\n", bitmap_clu);
|
||||
exfat_info("Bitmap size: \t\t\t\t%llu\n", bitmap_len);
|
||||
|
||||
exfat_info("Upcase table entry type: \t\t0x%x\n", ed[2].type);
|
||||
exfat_info("Upcase table start cluster: \t\t%x\n",
|
||||
le32_to_cpu(ed[2].upcase_start_clu));
|
||||
exfat_info("Upcase table size: \t\t\t%" PRIu64 "\n\n",
|
||||
le64_to_cpu(ed[2].upcase_size));
|
||||
|
||||
bitmap = malloc(bitmap_len);
|
||||
if (!bitmap) {
|
||||
exfat_err("bitmap allocation failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_volume_label;
|
||||
}
|
||||
|
||||
ret = exfat_read(bd->dev_fd, bitmap, bitmap_len, bitmap_clu_off);
|
||||
if (ret < 0) {
|
||||
exfat_err("bitmap entry read failed: %d\n", errno);
|
||||
ret = -EIO;
|
||||
free(bitmap);
|
||||
goto free_volume_label;
|
||||
}
|
||||
|
||||
total_clus = le32_to_cpu(pbsx->clu_count);
|
||||
used_clus = exfat_count_used_clusters(bitmap, bitmap_len);
|
||||
|
||||
exfat_info("---------------- Show the statistics ----------------\n");
|
||||
exfat_info("Cluster size: \t\t\t\t%u\n", bd->cluster_size);
|
||||
exfat_info("Total Clusters: \t\t\t%u\n", total_clus);
|
||||
exfat_info("Free Clusters: \t\t\t\t%u\n", total_clus-used_clus);
|
||||
ret = 0;
|
||||
|
||||
free(bitmap);
|
||||
|
||||
free_volume_label:
|
||||
free(volume_label);
|
||||
free_entry:
|
||||
free(ed);
|
||||
free_ppbr:
|
||||
free(ppbr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int ret = EXIT_FAILURE;
|
||||
struct exfat_blk_dev bd;
|
||||
struct exfat_user_input ui;
|
||||
bool version_only = false;
|
||||
|
||||
init_user_input(&ui);
|
||||
|
||||
if (!setlocale(LC_CTYPE, ""))
|
||||
exfat_err("failed to init locale/codeset\n");
|
||||
|
||||
opterr = 0;
|
||||
while ((c = getopt_long(argc, argv, "iVh", opts, NULL)) != EOF)
|
||||
switch (c) {
|
||||
case 'V':
|
||||
version_only = true;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
show_version();
|
||||
if (version_only)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
memset(ui.dev_name, 0, sizeof(ui.dev_name));
|
||||
snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[1]);
|
||||
|
||||
ret = exfat_get_blk_dev_info(&ui, &bd);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = exfat_show_ondisk_all_info(&bd);
|
||||
close(bd.dev_fd);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
.\" Copyright (C) 2011-2018 Andrew Nayenko
|
||||
.\"
|
||||
.TH DUMPEXFAT 8 "July 2016"
|
||||
.SH NAME
|
||||
.B dumpexfat
|
||||
\- dump exFAT file system
|
||||
.SH SYNOPSIS
|
||||
.B dumpexfat
|
||||
[
|
||||
.B \-s
|
||||
]
|
||||
[
|
||||
.B \-u
|
||||
]
|
||||
[
|
||||
.B \-f
|
||||
.I file
|
||||
]
|
||||
[
|
||||
.B \-V
|
||||
]
|
||||
.I device
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B dumpexfat
|
||||
dumps details about exFAT file system including low-level info. All sizes are
|
||||
in bytes.
|
||||
|
||||
.SH OPTIONS
|
||||
Command line options available:
|
||||
.TP
|
||||
.B \-s
|
||||
Dump only info from super block. May be useful for heavily corrupted file
|
||||
systems.
|
||||
.TP
|
||||
.B \-u
|
||||
Dump ranges of used sectors starting from 0 and separated with spaces. May be
|
||||
useful for backup tools.
|
||||
.TP
|
||||
.B \-f file
|
||||
Print out a list of fragments that compose the given file. Each fragment is
|
||||
printed on its own line, as the start offset (in bytes) into the file system,
|
||||
and the length (in bytes).
|
||||
.TP
|
||||
.BI \-V
|
||||
Print version and copyright.
|
||||
|
||||
.SH EXIT CODES
|
||||
Zero is returned on success. Any other code means an error.
|
||||
|
||||
.SH AUTHOR
|
||||
Andrew Nayenko
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR mkexfatfs (8)
|
||||
-246
@@ -1,246 +0,0 @@
|
||||
/*
|
||||
main.c (08.11.10)
|
||||
Prints detailed information about exFAT volume.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <exfat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void print_generic_info(const struct exfat_super_block* sb)
|
||||
{
|
||||
printf("Volume serial number 0x%08x\n",
|
||||
le32_to_cpu(sb->volume_serial));
|
||||
printf("FS version %hhu.%hhu\n",
|
||||
sb->version.major, sb->version.minor);
|
||||
printf("Sector size %10u\n",
|
||||
SECTOR_SIZE(*sb));
|
||||
printf("Cluster size %10u\n",
|
||||
CLUSTER_SIZE(*sb));
|
||||
}
|
||||
|
||||
static void print_sector_info(const struct exfat_super_block* sb)
|
||||
{
|
||||
printf("Sectors count %10"PRIu64"\n",
|
||||
le64_to_cpu(sb->sector_count));
|
||||
}
|
||||
|
||||
static void print_cluster_info(const struct exfat_super_block* sb)
|
||||
{
|
||||
printf("Clusters count %10u\n",
|
||||
le32_to_cpu(sb->cluster_count));
|
||||
}
|
||||
|
||||
static void print_other_info(const struct exfat_super_block* sb)
|
||||
{
|
||||
printf("First sector %10"PRIu64"\n",
|
||||
le64_to_cpu(sb->sector_start));
|
||||
printf("FAT first sector %10u\n",
|
||||
le32_to_cpu(sb->fat_sector_start));
|
||||
printf("FAT sectors count %10u\n",
|
||||
le32_to_cpu(sb->fat_sector_count));
|
||||
printf("First cluster sector %10u\n",
|
||||
le32_to_cpu(sb->cluster_sector_start));
|
||||
printf("Root directory cluster %10u\n",
|
||||
le32_to_cpu(sb->rootdir_cluster));
|
||||
printf("Volume state 0x%04hx\n",
|
||||
le16_to_cpu(sb->volume_state));
|
||||
printf("FATs count %10hhu\n",
|
||||
sb->fat_count);
|
||||
printf("Drive number 0x%02hhx\n",
|
||||
sb->drive_no);
|
||||
printf("Allocated space %9hhu%%\n",
|
||||
sb->allocated_percent);
|
||||
}
|
||||
|
||||
static int dump_sb(const char* spec)
|
||||
{
|
||||
struct exfat_dev* dev;
|
||||
struct exfat_super_block sb;
|
||||
|
||||
dev = exfat_open(spec, EXFAT_MODE_RO);
|
||||
if (dev == NULL)
|
||||
return 1;
|
||||
|
||||
if (exfat_read(dev, &sb, sizeof(struct exfat_super_block)) < 0)
|
||||
{
|
||||
exfat_close(dev);
|
||||
exfat_error("failed to read from '%s'", spec);
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(sb.oem_name, "EXFAT ", sizeof(sb.oem_name)) != 0)
|
||||
{
|
||||
exfat_close(dev);
|
||||
exfat_error("exFAT file system is not found on '%s'", spec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_generic_info(&sb);
|
||||
print_sector_info(&sb);
|
||||
print_cluster_info(&sb);
|
||||
print_other_info(&sb);
|
||||
|
||||
exfat_close(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_sectors(struct exfat* ef)
|
||||
{
|
||||
off_t a = 0, b = 0;
|
||||
|
||||
printf("Used sectors ");
|
||||
while (exfat_find_used_sectors(ef, &a, &b) == 0)
|
||||
printf(" %"PRIu64"-%"PRIu64, a, b);
|
||||
puts("");
|
||||
}
|
||||
|
||||
static int dump_full(const char* spec, bool used_sectors)
|
||||
{
|
||||
struct exfat ef;
|
||||
uint32_t free_clusters;
|
||||
uint64_t free_sectors;
|
||||
|
||||
if (exfat_mount(&ef, spec, "ro") != 0)
|
||||
return 1;
|
||||
|
||||
free_clusters = exfat_count_free_clusters(&ef);
|
||||
free_sectors = (uint64_t) free_clusters << ef.sb->spc_bits;
|
||||
|
||||
printf("Volume label %15s\n", exfat_get_label(&ef));
|
||||
print_generic_info(ef.sb);
|
||||
print_sector_info(ef.sb);
|
||||
printf("Free sectors %10"PRIu64"\n", free_sectors);
|
||||
print_cluster_info(ef.sb);
|
||||
printf("Free clusters %10u\n", free_clusters);
|
||||
print_other_info(ef.sb);
|
||||
if (used_sectors)
|
||||
dump_sectors(&ef);
|
||||
|
||||
exfat_unmount(&ef);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_file_fragments(const char* spec, const char* path)
|
||||
{
|
||||
struct exfat ef;
|
||||
struct exfat_node* node;
|
||||
cluster_t cluster;
|
||||
cluster_t next_cluster;
|
||||
cluster_t fragment_start_cluster;
|
||||
off_t remainder;
|
||||
off_t fragment_size = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (exfat_mount(&ef, spec, "ro") != 0)
|
||||
return 1;
|
||||
|
||||
rc = exfat_lookup(&ef, &node, path);
|
||||
if (rc != 0)
|
||||
{
|
||||
exfat_unmount(&ef);
|
||||
exfat_error("'%s': %s", path, strerror(-rc));
|
||||
return 1;
|
||||
}
|
||||
|
||||
cluster = fragment_start_cluster = node->start_cluster;
|
||||
remainder = node->size;
|
||||
while (remainder > 0)
|
||||
{
|
||||
off_t lsize;
|
||||
|
||||
if (CLUSTER_INVALID(*ef.sb, cluster))
|
||||
{
|
||||
exfat_error("'%s' has invalid cluster %#x", path, cluster);
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
lsize = MIN(CLUSTER_SIZE(*ef.sb), remainder);
|
||||
fragment_size += lsize;
|
||||
remainder -= lsize;
|
||||
|
||||
next_cluster = exfat_next_cluster(&ef, node, cluster);
|
||||
if (next_cluster != cluster + 1 || remainder == 0)
|
||||
{
|
||||
/* next cluster is not contiguous or this is EOF */
|
||||
printf("%"PRIu64" %"PRIu64"\n",
|
||||
exfat_c2o(&ef, fragment_start_cluster), fragment_size);
|
||||
/* start a new fragment */
|
||||
fragment_start_cluster = next_cluster;
|
||||
fragment_size = 0;
|
||||
}
|
||||
cluster = next_cluster;
|
||||
}
|
||||
|
||||
exfat_put_node(&ef, node);
|
||||
exfat_unmount(&ef);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void usage(const char* prog)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-s] [-u] [-f file] [-V] <device>\n", prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int opt;
|
||||
const char* spec = NULL;
|
||||
bool sb_only = false;
|
||||
bool used_sectors = false;
|
||||
const char* file_path = NULL;
|
||||
|
||||
while ((opt = getopt(argc, argv, "suf:V")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 's':
|
||||
sb_only = true;
|
||||
break;
|
||||
case 'u':
|
||||
used_sectors = true;
|
||||
break;
|
||||
case 'f':
|
||||
file_path = optarg;
|
||||
break;
|
||||
case 'V':
|
||||
printf("dumpexfat %s\n", VERSION);
|
||||
puts("Copyright (C) 2011-2018 Andrew Nayenko");
|
||||
return 0;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if (argc - optind != 1)
|
||||
usage(argv[0]);
|
||||
spec = argv[optind];
|
||||
|
||||
if (file_path)
|
||||
return dump_file_fragments(spec, file_path);
|
||||
|
||||
if (sb_only)
|
||||
return dump_sb(spec);
|
||||
|
||||
return dump_full(spec, used_sectors);
|
||||
}
|
||||
+4
-31
@@ -1,33 +1,6 @@
|
||||
#
|
||||
# Makefile.am (30.03.15)
|
||||
# Automake source.
|
||||
#
|
||||
# Free exFAT implementation.
|
||||
# Copyright (C) 2011-2018 Andrew Nayenko
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common
|
||||
fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.a
|
||||
|
||||
sbin_PROGRAMS = exfatfsck
|
||||
dist_man8_MANS = exfatfsck.8
|
||||
exfatfsck_SOURCES = main.c
|
||||
exfatfsck_CPPFLAGS = -I$(top_srcdir)/libexfat
|
||||
exfatfsck_LDADD = ../libexfat/libexfat.a
|
||||
sbin_PROGRAMS = fsck.exfat
|
||||
|
||||
install-exec-hook:
|
||||
ln -sf $(sbin_PROGRAMS) $(DESTDIR)$(sbindir)/fsck.exfat
|
||||
|
||||
uninstall-hook:
|
||||
rm -f $(DESTDIR)$(sbindir)/fsck.exfat
|
||||
fsck_exfat_SOURCES = fsck.c repair.c fsck.h de_iter.c repair.h
|
||||
|
||||
+313
@@ -0,0 +1,313 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2020 Hyunchul Lee <hyc.lee@gmail.com>
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "exfat_ondisk.h"
|
||||
#include "libexfat.h"
|
||||
#include "fsck.h"
|
||||
|
||||
static ssize_t write_block(struct exfat_de_iter *iter, unsigned int block)
|
||||
{
|
||||
off_t device_offset;
|
||||
struct exfat *exfat = iter->exfat;
|
||||
struct buffer_desc *desc;
|
||||
unsigned int i;
|
||||
|
||||
desc = &iter->buffer_desc[block & 0x01];
|
||||
device_offset = exfat_c2o(exfat, desc->p_clus) + desc->offset;
|
||||
|
||||
for (i = 0; i < iter->read_size / iter->write_size; i++) {
|
||||
if (desc->dirty[i]) {
|
||||
if (exfat_write(exfat->blk_dev->dev_fd,
|
||||
desc->buffer + i * iter->write_size,
|
||||
iter->write_size,
|
||||
device_offset + i * iter->write_size)
|
||||
!= (ssize_t)iter->write_size)
|
||||
return -EIO;
|
||||
desc->dirty[i] = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_ahead_first_blocks(struct exfat_de_iter *iter)
|
||||
{
|
||||
#ifdef POSIX_FADV_WILLNEED
|
||||
struct exfat *exfat = iter->exfat;
|
||||
clus_t clus_count;
|
||||
unsigned int size;
|
||||
|
||||
clus_count = iter->parent->size / exfat->clus_size;
|
||||
|
||||
if (clus_count > 1) {
|
||||
iter->ra_begin_offset = 0;
|
||||
iter->ra_next_clus = 1;
|
||||
size = exfat->clus_size;
|
||||
} else {
|
||||
iter->ra_begin_offset = 0;
|
||||
iter->ra_next_clus = 0;
|
||||
size = iter->ra_partial_size;
|
||||
}
|
||||
return posix_fadvise(exfat->blk_dev->dev_fd,
|
||||
exfat_c2o(exfat, iter->parent->first_clus), size,
|
||||
POSIX_FADV_WILLNEED);
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* read the next fragment in advance, and assume the fragment
|
||||
* which covers @clus is already read.
|
||||
*/
|
||||
static int read_ahead_next_blocks(struct exfat_de_iter *iter,
|
||||
clus_t clus, unsigned int offset, clus_t p_clus)
|
||||
{
|
||||
#ifdef POSIX_FADV_WILLNEED
|
||||
struct exfat *exfat = iter->exfat;
|
||||
off_t device_offset;
|
||||
clus_t clus_count, ra_clus, ra_p_clus;
|
||||
unsigned int size;
|
||||
int ret = 0;
|
||||
|
||||
clus_count = iter->parent->size / exfat->clus_size;
|
||||
if (clus + 1 < clus_count) {
|
||||
ra_clus = clus + 1;
|
||||
if (ra_clus == iter->ra_next_clus &&
|
||||
offset >= iter->ra_begin_offset) {
|
||||
ret = get_next_clus(exfat, iter->parent,
|
||||
p_clus, &ra_p_clus);
|
||||
if (ra_p_clus == EXFAT_EOF_CLUSTER)
|
||||
return -EIO;
|
||||
|
||||
device_offset = exfat_c2o(exfat, ra_p_clus);
|
||||
size = ra_clus + 1 < clus_count ?
|
||||
exfat->clus_size : iter->ra_partial_size;
|
||||
ret = posix_fadvise(exfat->blk_dev->dev_fd,
|
||||
device_offset, size,
|
||||
POSIX_FADV_WILLNEED);
|
||||
iter->ra_next_clus = ra_clus + 1;
|
||||
iter->ra_begin_offset = 0;
|
||||
}
|
||||
} else {
|
||||
if (offset >= iter->ra_begin_offset &&
|
||||
offset + iter->ra_partial_size <=
|
||||
exfat->clus_size) {
|
||||
device_offset = exfat_c2o(exfat, p_clus) +
|
||||
offset + iter->ra_partial_size;
|
||||
ret = posix_fadvise(exfat->blk_dev->dev_fd,
|
||||
device_offset, iter->ra_partial_size,
|
||||
POSIX_FADV_WILLNEED);
|
||||
iter->ra_begin_offset =
|
||||
offset + iter->ra_partial_size;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int read_ahead_next_dir_blocks(struct exfat_de_iter *iter)
|
||||
{
|
||||
#ifdef POSIX_FADV_WILLNEED
|
||||
struct exfat *exfat = iter->exfat;
|
||||
struct list_head *current;
|
||||
struct exfat_inode *next_inode;
|
||||
off_t offset;
|
||||
|
||||
if (list_empty(&exfat->dir_list))
|
||||
return -EINVAL;
|
||||
|
||||
current = exfat->dir_list.next;
|
||||
if (iter->parent == list_entry(current, struct exfat_inode, list) &&
|
||||
current->next != &exfat->dir_list) {
|
||||
next_inode = list_entry(current->next, struct exfat_inode,
|
||||
list);
|
||||
offset = exfat_c2o(exfat, next_inode->first_clus);
|
||||
return posix_fadvise(exfat->blk_dev->dev_fd, offset,
|
||||
iter->ra_partial_size,
|
||||
POSIX_FADV_WILLNEED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static ssize_t read_block(struct exfat_de_iter *iter, unsigned int block)
|
||||
{
|
||||
struct exfat *exfat = iter->exfat;
|
||||
struct buffer_desc *desc, *prev_desc;
|
||||
off_t device_offset;
|
||||
ssize_t ret;
|
||||
|
||||
desc = &iter->buffer_desc[block & 0x01];
|
||||
if (block == 0) {
|
||||
desc->p_clus = iter->parent->first_clus;
|
||||
desc->offset = 0;
|
||||
}
|
||||
|
||||
/* if the buffer already contains dirty dentries, write it */
|
||||
if (write_block(iter, block))
|
||||
return -EIO;
|
||||
|
||||
if (block > 0) {
|
||||
if (block > iter->parent->size / iter->read_size)
|
||||
return EOF;
|
||||
|
||||
prev_desc = &iter->buffer_desc[(block-1) & 0x01];
|
||||
if (prev_desc->offset + 2 * iter->read_size <=
|
||||
exfat->clus_size) {
|
||||
desc->p_clus = prev_desc->p_clus;
|
||||
desc->offset = prev_desc->offset + iter->read_size;
|
||||
} else {
|
||||
ret = get_next_clus(exfat, iter->parent,
|
||||
prev_desc->p_clus, &desc->p_clus);
|
||||
desc->offset = 0;
|
||||
if (!ret && desc->p_clus == EXFAT_EOF_CLUSTER)
|
||||
return EOF;
|
||||
else if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
device_offset = exfat_c2o(exfat, desc->p_clus) + desc->offset;
|
||||
ret = exfat_read(exfat->blk_dev->dev_fd, desc->buffer,
|
||||
iter->read_size, device_offset);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* if a buffer is filled with dentries, read blocks ahead of time,
|
||||
* otherwise read blocks of the next directory in advance.
|
||||
*/
|
||||
if (desc->buffer[iter->read_size - 32] != EXFAT_LAST)
|
||||
read_ahead_next_blocks(iter,
|
||||
(block * iter->read_size) / exfat->clus_size,
|
||||
(block * iter->read_size) % exfat->clus_size,
|
||||
desc->p_clus);
|
||||
else
|
||||
read_ahead_next_dir_blocks(iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat,
|
||||
struct exfat_inode *dir)
|
||||
{
|
||||
iter->exfat = exfat;
|
||||
iter->parent = dir;
|
||||
iter->write_size = exfat->sect_size;
|
||||
iter->read_size = exfat->clus_size <= 4*KB ? exfat->clus_size : 4*KB;
|
||||
if (exfat->clus_size <= 32 * KB)
|
||||
iter->ra_partial_size = MAX(4 * KB, exfat->clus_size / 2);
|
||||
else
|
||||
iter->ra_partial_size = exfat->clus_size / 4;
|
||||
iter->ra_partial_size = MIN(iter->ra_partial_size, 8 * KB);
|
||||
|
||||
if (!iter->buffer_desc)
|
||||
iter->buffer_desc = exfat->buffer_desc;
|
||||
|
||||
if (iter->parent->size == 0)
|
||||
return EOF;
|
||||
|
||||
read_ahead_first_blocks(iter);
|
||||
if (read_block(iter, 0) != (ssize_t)iter->read_size) {
|
||||
exfat_err("failed to read directory entries.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
iter->de_file_offset = 0;
|
||||
iter->next_read_offset = iter->read_size;
|
||||
iter->max_skip_dentries = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_de_iter_get(struct exfat_de_iter *iter,
|
||||
int ith, struct exfat_dentry **dentry)
|
||||
{
|
||||
off_t next_de_file_offset;
|
||||
ssize_t ret;
|
||||
unsigned int block;
|
||||
|
||||
next_de_file_offset = iter->de_file_offset +
|
||||
ith * sizeof(struct exfat_dentry);
|
||||
block = (unsigned int)(next_de_file_offset / iter->read_size);
|
||||
|
||||
if (next_de_file_offset + sizeof(struct exfat_dentry) >
|
||||
iter->parent->size)
|
||||
return EOF;
|
||||
/* the dentry must be in current, or next block which will be read */
|
||||
if (block > iter->de_file_offset / iter->read_size + 1)
|
||||
return -ERANGE;
|
||||
|
||||
/* read next cluster if needed */
|
||||
if (next_de_file_offset >= iter->next_read_offset) {
|
||||
ret = read_block(iter, block);
|
||||
if (ret != (ssize_t)iter->read_size)
|
||||
return ret;
|
||||
iter->next_read_offset += iter->read_size;
|
||||
}
|
||||
|
||||
if (ith + 1 > iter->max_skip_dentries)
|
||||
iter->max_skip_dentries = ith + 1;
|
||||
|
||||
*dentry = (struct exfat_dentry *)
|
||||
(iter->buffer_desc[block & 0x01].buffer +
|
||||
next_de_file_offset % iter->read_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_de_iter_get_dirty(struct exfat_de_iter *iter,
|
||||
int ith, struct exfat_dentry **dentry)
|
||||
{
|
||||
off_t next_file_offset;
|
||||
unsigned int block;
|
||||
int ret, sect_idx;
|
||||
|
||||
ret = exfat_de_iter_get(iter, ith, dentry);
|
||||
if (!ret) {
|
||||
next_file_offset = iter->de_file_offset +
|
||||
ith * sizeof(struct exfat_dentry);
|
||||
block = (unsigned int)(next_file_offset / iter->read_size);
|
||||
sect_idx = (int)((next_file_offset % iter->read_size) /
|
||||
iter->write_size);
|
||||
iter->buffer_desc[block & 0x01].dirty[sect_idx] = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int exfat_de_iter_flush(struct exfat_de_iter *iter)
|
||||
{
|
||||
if (write_block(iter, 0) || write_block(iter, 1))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @skip_dentries must be the largest @ith + 1 of exfat_de_iter_get
|
||||
* since the last call of exfat_de_iter_advance
|
||||
*/
|
||||
int exfat_de_iter_advance(struct exfat_de_iter *iter, int skip_dentries)
|
||||
{
|
||||
if (skip_dentries != iter->max_skip_dentries)
|
||||
return -EINVAL;
|
||||
|
||||
iter->max_skip_dentries = 0;
|
||||
iter->de_file_offset = iter->de_file_offset +
|
||||
skip_dentries * sizeof(struct exfat_dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter)
|
||||
{
|
||||
return iter->de_file_offset;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
.\" Copyright (C) 2011-2018 Andrew Nayenko
|
||||
.\"
|
||||
.TH EXFATFSCK 8 "September 2018"
|
||||
.SH NAME
|
||||
.B exfatfsck
|
||||
\- check an exFAT file system
|
||||
.SH SYNOPSIS
|
||||
.B exfatfsck
|
||||
[
|
||||
.B \-a
|
||||
|
|
||||
.B \-n
|
||||
|
|
||||
.B \-p
|
||||
|
|
||||
.B \-y
|
||||
]
|
||||
.I device
|
||||
.br
|
||||
.B exfatfsck
|
||||
[
|
||||
.B \-V
|
||||
]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B exfatfsck
|
||||
checks an exFAT file system for errors. It can repair some of them.
|
||||
|
||||
.SH COMMAND LINE OPTIONS
|
||||
Command line options available:
|
||||
.TP
|
||||
.BI \-a
|
||||
Automatically repair the file system. No user intervention required.
|
||||
.TP
|
||||
.BI \-n
|
||||
No-operation mode: non-interactively check for errors, but don't write
|
||||
anything to the file system.
|
||||
.TP
|
||||
.BI \-p
|
||||
Same as \fB\-a\fR for compatibility with other *fsck.
|
||||
.TP
|
||||
.BI \-V
|
||||
Print version and copyright.
|
||||
.TP
|
||||
.BI \-y
|
||||
Same as \fB\-a\fR for compatibility with other *fsck.
|
||||
|
||||
.SH EXIT CODES
|
||||
Zero is returned if errors were not found. Any other code means an error.
|
||||
|
||||
.SH AUTHOR
|
||||
Andrew Nayenko
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR fsck (8)
|
||||
+1648
File diff suppressed because it is too large
Load Diff
+99
@@ -0,0 +1,99 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2020 Hyunchul Lee <hyc.lee@gmail.com>
|
||||
*/
|
||||
#ifndef _FSCK_H
|
||||
#define _FSCK_H
|
||||
|
||||
#include "list.h"
|
||||
|
||||
typedef __u32 clus_t;
|
||||
|
||||
struct exfat_inode {
|
||||
struct exfat_inode *parent;
|
||||
struct list_head children;
|
||||
struct list_head sibling;
|
||||
struct list_head list;
|
||||
clus_t first_clus;
|
||||
clus_t last_lclus;
|
||||
clus_t last_pclus;
|
||||
__u16 attr;
|
||||
uint64_t size;
|
||||
bool is_contiguous;
|
||||
__le16 name[0]; /* only for directory */
|
||||
};
|
||||
|
||||
#define EXFAT_NAME_MAX 255
|
||||
#define NAME_BUFFER_SIZE ((EXFAT_NAME_MAX+1)*2)
|
||||
|
||||
struct buffer_desc {
|
||||
clus_t p_clus;
|
||||
unsigned int offset;
|
||||
char *buffer;
|
||||
char *dirty;
|
||||
};
|
||||
|
||||
struct exfat_de_iter {
|
||||
struct exfat *exfat;
|
||||
struct exfat_inode *parent;
|
||||
struct buffer_desc *buffer_desc; /* cluster * 2 */
|
||||
clus_t ra_next_clus;
|
||||
unsigned int ra_begin_offset;
|
||||
unsigned int ra_partial_size;
|
||||
unsigned int read_size; /* cluster size */
|
||||
unsigned int write_size; /* sector size */
|
||||
off_t de_file_offset;
|
||||
off_t next_read_offset;
|
||||
int max_skip_dentries;
|
||||
};
|
||||
|
||||
enum fsck_ui_options {
|
||||
FSCK_OPTS_REPAIR_ASK = 0x01,
|
||||
FSCK_OPTS_REPAIR_YES = 0x02,
|
||||
FSCK_OPTS_REPAIR_NO = 0x04,
|
||||
FSCK_OPTS_REPAIR_AUTO = 0x08,
|
||||
FSCK_OPTS_REPAIR_WRITE = 0x0b,
|
||||
FSCK_OPTS_REPAIR_ALL = 0x0f,
|
||||
};
|
||||
|
||||
struct exfat {
|
||||
enum fsck_ui_options options;
|
||||
bool dirty:1;
|
||||
bool dirty_fat:1;
|
||||
struct exfat_blk_dev *blk_dev;
|
||||
struct pbr *bs;
|
||||
char volume_label[VOLUME_LABEL_BUFFER_SIZE];
|
||||
struct exfat_inode *root;
|
||||
struct list_head dir_list;
|
||||
clus_t clus_count;
|
||||
unsigned int clus_size;
|
||||
unsigned int sect_size;
|
||||
struct exfat_de_iter de_iter;
|
||||
struct buffer_desc buffer_desc[2]; /* cluster * 2 */
|
||||
char *alloc_bitmap;
|
||||
char *disk_bitmap;
|
||||
clus_t disk_bitmap_clus;
|
||||
unsigned int disk_bitmap_size;
|
||||
};
|
||||
|
||||
#define EXFAT_CLUSTER_SIZE(pbr) (1 << ((pbr)->bsx.sect_size_bits + \
|
||||
(pbr)->bsx.sect_per_clus_bits))
|
||||
#define EXFAT_SECTOR_SIZE(pbr) (1 << (pbr)->bsx.sect_size_bits)
|
||||
|
||||
/* fsck.c */
|
||||
off_t exfat_c2o(struct exfat *exfat, unsigned int clus);
|
||||
int get_next_clus(struct exfat *exfat, struct exfat_inode *node,
|
||||
clus_t clus, clus_t *next);
|
||||
|
||||
/* de_iter.c */
|
||||
int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat,
|
||||
struct exfat_inode *dir);
|
||||
int exfat_de_iter_get(struct exfat_de_iter *iter,
|
||||
int ith, struct exfat_dentry **dentry);
|
||||
int exfat_de_iter_get_dirty(struct exfat_de_iter *iter,
|
||||
int ith, struct exfat_dentry **dentry);
|
||||
int exfat_de_iter_flush(struct exfat_de_iter *iter);
|
||||
int exfat_de_iter_advance(struct exfat_de_iter *iter, int skip_dentries);
|
||||
off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter);
|
||||
|
||||
#endif
|
||||
-199
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
main.c (02.09.09)
|
||||
exFAT file system checker.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <exfat.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define exfat_debug(format, ...) do {} while (0)
|
||||
|
||||
uint64_t files_count, directories_count;
|
||||
|
||||
static int nodeck(struct exfat* ef, struct exfat_node* node)
|
||||
{
|
||||
const cluster_t cluster_size = CLUSTER_SIZE(*ef->sb);
|
||||
cluster_t clusters = DIV_ROUND_UP(node->size, cluster_size);
|
||||
cluster_t c = node->start_cluster;
|
||||
int rc = 0;
|
||||
|
||||
while (clusters--)
|
||||
{
|
||||
if (CLUSTER_INVALID(*ef->sb, c))
|
||||
{
|
||||
char name[EXFAT_UTF8_NAME_BUFFER_MAX];
|
||||
|
||||
exfat_get_name(node, name);
|
||||
exfat_error("file '%s' has invalid cluster 0x%x", name, c);
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
if (BMAP_GET(ef->cmap.chunk, c - EXFAT_FIRST_DATA_CLUSTER) == 0)
|
||||
{
|
||||
char name[EXFAT_UTF8_NAME_BUFFER_MAX];
|
||||
|
||||
exfat_get_name(node, name);
|
||||
exfat_error("cluster 0x%x of file '%s' is not allocated", c, name);
|
||||
rc = 1;
|
||||
}
|
||||
c = exfat_next_cluster(ef, node, c);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dirck(struct exfat* ef, const char* path)
|
||||
{
|
||||
struct exfat_node* parent;
|
||||
struct exfat_node* node;
|
||||
struct exfat_iterator it;
|
||||
int rc;
|
||||
size_t path_length;
|
||||
char* entry_path;
|
||||
|
||||
if (exfat_lookup(ef, &parent, path) != 0)
|
||||
exfat_bug("directory '%s' is not found", path);
|
||||
if (!(parent->attrib & EXFAT_ATTRIB_DIR))
|
||||
exfat_bug("'%s' is not a directory (%#hx)", path, parent->attrib);
|
||||
if (nodeck(ef, parent) != 0)
|
||||
{
|
||||
exfat_put_node(ef, parent);
|
||||
return;
|
||||
}
|
||||
|
||||
path_length = strlen(path);
|
||||
entry_path = malloc(path_length + 1 + EXFAT_UTF8_NAME_BUFFER_MAX);
|
||||
if (entry_path == NULL)
|
||||
{
|
||||
exfat_put_node(ef, parent);
|
||||
exfat_error("out of memory");
|
||||
return;
|
||||
}
|
||||
strcpy(entry_path, path);
|
||||
strcat(entry_path, "/");
|
||||
|
||||
rc = exfat_opendir(ef, parent, &it);
|
||||
if (rc != 0)
|
||||
{
|
||||
free(entry_path);
|
||||
exfat_put_node(ef, parent);
|
||||
return;
|
||||
}
|
||||
while ((node = exfat_readdir(&it)))
|
||||
{
|
||||
exfat_get_name(node, entry_path + path_length + 1);
|
||||
exfat_debug("%s: %s, %"PRIu64" bytes, cluster %u", entry_path,
|
||||
node->is_contiguous ? "contiguous" : "fragmented",
|
||||
node->size, node->start_cluster);
|
||||
if (node->attrib & EXFAT_ATTRIB_DIR)
|
||||
{
|
||||
directories_count++;
|
||||
dirck(ef, entry_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
files_count++;
|
||||
nodeck(ef, node);
|
||||
}
|
||||
exfat_flush_node(ef, node);
|
||||
exfat_put_node(ef, node);
|
||||
}
|
||||
exfat_closedir(ef, &it);
|
||||
exfat_flush_node(ef, parent);
|
||||
exfat_put_node(ef, parent);
|
||||
free(entry_path);
|
||||
}
|
||||
|
||||
static void fsck(struct exfat* ef, const char* spec, const char* options)
|
||||
{
|
||||
if (exfat_mount(ef, spec, options) != 0)
|
||||
{
|
||||
fputs("File system checking stopped. ", stdout);
|
||||
return;
|
||||
}
|
||||
|
||||
exfat_print_info(ef->sb, exfat_count_free_clusters(ef));
|
||||
exfat_soil_super_block(ef);
|
||||
dirck(ef, "");
|
||||
exfat_unmount(ef);
|
||||
|
||||
printf("Totally %"PRIu64" directories and %"PRIu64" files.\n",
|
||||
directories_count, files_count);
|
||||
fputs("File system checking finished. ", stdout);
|
||||
}
|
||||
|
||||
static void usage(const char* prog)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-a | -n | -p | -y] <device>\n", prog);
|
||||
fprintf(stderr, " %s -V\n", prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int opt;
|
||||
const char* options;
|
||||
const char* spec = NULL;
|
||||
struct exfat ef;
|
||||
|
||||
printf("exfatfsck %s\n", VERSION);
|
||||
|
||||
if (isatty(STDIN_FILENO))
|
||||
options = "repair=1";
|
||||
else
|
||||
options = "repair=0";
|
||||
|
||||
while ((opt = getopt(argc, argv, "anpVy")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
case 'p':
|
||||
case 'y':
|
||||
options = "repair=2";
|
||||
break;
|
||||
case 'n':
|
||||
options = "repair=0,ro";
|
||||
break;
|
||||
case 'V':
|
||||
puts("Copyright (C) 2011-2018 Andrew Nayenko");
|
||||
return 0;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (argc - optind != 1)
|
||||
usage(argv[0]);
|
||||
spec = argv[optind];
|
||||
|
||||
printf("Checking file system on %s.\n", spec);
|
||||
fsck(&ef, spec, options);
|
||||
if (exfat_errors != 0)
|
||||
{
|
||||
printf("ERRORS FOUND: %d, FIXED: %d.\n",
|
||||
exfat_errors, exfat_errors_fixed);
|
||||
return 1;
|
||||
}
|
||||
puts("No errors found.");
|
||||
return 0;
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2020 Hyunchul Lee <hyc.lee@gmail.com>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "exfat_ondisk.h"
|
||||
#include "libexfat.h"
|
||||
#include "fsck.h"
|
||||
#include "repair.h"
|
||||
|
||||
struct exfat_repair_problem {
|
||||
er_problem_code_t prcode;
|
||||
unsigned int flags;
|
||||
unsigned int prompt_type;
|
||||
};
|
||||
|
||||
/* Problem flags */
|
||||
#define ERF_PREEN_YES 0x00000001
|
||||
#define ERF_DEFAULT_YES 0x00000002
|
||||
#define ERF_DEFAULT_NO 0x00000004
|
||||
|
||||
/* Prompt types */
|
||||
#define ERP_FIX 0x00000001
|
||||
#define ERP_TRUNCATE 0x00000002
|
||||
|
||||
static const char *prompts[] = {
|
||||
"Repair",
|
||||
"Fix",
|
||||
"Truncate",
|
||||
};
|
||||
|
||||
static struct exfat_repair_problem problems[] = {
|
||||
{ER_BS_CHECKSUM, ERF_PREEN_YES, ERP_FIX},
|
||||
{ER_BS_BOOT_REGION, 0, ERP_FIX},
|
||||
{ER_DE_CHECKSUM, ERF_PREEN_YES, ERP_FIX},
|
||||
{ER_FILE_VALID_SIZE, ERF_PREEN_YES, ERP_FIX},
|
||||
{ER_FILE_INVALID_CLUS, ERF_DEFAULT_NO, ERP_TRUNCATE},
|
||||
{ER_FILE_FIRST_CLUS, ERF_DEFAULT_NO, ERP_TRUNCATE},
|
||||
{ER_FILE_SMALLER_SIZE, ERF_DEFAULT_NO, ERP_TRUNCATE},
|
||||
{ER_FILE_LARGER_SIZE, ERF_DEFAULT_NO, ERP_TRUNCATE},
|
||||
{ER_FILE_DUPLICATED_CLUS, ERF_DEFAULT_NO, ERP_TRUNCATE},
|
||||
{ER_FILE_ZERO_NOFAT, ERF_PREEN_YES, ERP_FIX},
|
||||
};
|
||||
|
||||
static struct exfat_repair_problem *find_problem(er_problem_code_t prcode)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < sizeof(problems)/sizeof(problems[0]); i++) {
|
||||
if (problems[i].prcode == prcode) {
|
||||
return &problems[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool ask_repair(struct exfat *exfat, struct exfat_repair_problem *pr)
|
||||
{
|
||||
bool repair = false;
|
||||
char answer[8];
|
||||
|
||||
if (exfat->options & FSCK_OPTS_REPAIR_NO ||
|
||||
pr->flags & ERF_DEFAULT_NO)
|
||||
repair = false;
|
||||
else if (exfat->options & FSCK_OPTS_REPAIR_YES ||
|
||||
pr->flags & ERF_DEFAULT_YES)
|
||||
repair = true;
|
||||
else {
|
||||
if (exfat->options & FSCK_OPTS_REPAIR_ASK) {
|
||||
do {
|
||||
printf(". %s (y/N)? ",
|
||||
prompts[pr->prompt_type]);
|
||||
fflush(stdout);
|
||||
|
||||
if (fgets(answer, sizeof(answer), stdin)) {
|
||||
if (strcasecmp(answer, "Y\n") == 0)
|
||||
return true;
|
||||
else if (strcasecmp(answer, "\n") == 0
|
||||
|| strcasecmp(answer, "N\n") == 0)
|
||||
return false;
|
||||
}
|
||||
} while (1);
|
||||
} else if (exfat->options & FSCK_OPTS_REPAIR_AUTO &&
|
||||
pr->flags & ERF_PREEN_YES)
|
||||
repair = true;
|
||||
}
|
||||
|
||||
printf(". %s (y/N)? %c\n", prompts[pr->prompt_type],
|
||||
repair ? 'y' : 'n');
|
||||
return repair;
|
||||
}
|
||||
|
||||
bool exfat_repair_ask(struct exfat *exfat, er_problem_code_t prcode,
|
||||
const char *desc, ...)
|
||||
{
|
||||
struct exfat_repair_problem *pr = NULL;
|
||||
va_list ap;
|
||||
|
||||
pr = find_problem(prcode);
|
||||
if (!pr) {
|
||||
exfat_err("unknown problem code. %#x\n", prcode);
|
||||
return false;
|
||||
}
|
||||
|
||||
va_start(ap, desc);
|
||||
vprintf(desc, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (ask_repair(exfat, pr)) {
|
||||
if (pr->prompt_type & ERP_TRUNCATE)
|
||||
exfat->dirty_fat = true;
|
||||
exfat->dirty = true;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2020 Hyunchul Lee <hyc.lee@gmail.com>
|
||||
*/
|
||||
#ifndef _REPAIR_H
|
||||
#define _REPAIR_H
|
||||
|
||||
#define ER_BS_CHECKSUM 0x00000001
|
||||
#define ER_BS_BOOT_REGION 0x00000002
|
||||
#define ER_DE_CHECKSUM 0x00001001
|
||||
#define ER_FILE_VALID_SIZE 0x00002001
|
||||
#define ER_FILE_INVALID_CLUS 0x00002002
|
||||
#define ER_FILE_FIRST_CLUS 0x00002003
|
||||
#define ER_FILE_SMALLER_SIZE 0x00002004
|
||||
#define ER_FILE_LARGER_SIZE 0x00002005
|
||||
#define ER_FILE_DUPLICATED_CLUS 0x00002006
|
||||
#define ER_FILE_ZERO_NOFAT 0x00002007
|
||||
|
||||
typedef unsigned int er_problem_code_t;
|
||||
|
||||
bool exfat_repair_ask(struct exfat *exfat, er_problem_code_t prcode,
|
||||
const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
#
|
||||
# Makefile.am (30.03.15)
|
||||
# Automake source.
|
||||
#
|
||||
# Free exFAT implementation.
|
||||
# Copyright (C) 2010-2018 Andrew Nayenko
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
sbin_PROGRAMS = mount.exfat-fuse
|
||||
dist_man8_MANS = mount.exfat-fuse.8
|
||||
mount_exfat_fuse_SOURCES = main.c
|
||||
mount_exfat_fuse_CPPFLAGS = -I$(top_srcdir)/libexfat
|
||||
mount_exfat_fuse_CFLAGS = $(FUSE_CFLAGS)
|
||||
mount_exfat_fuse_LDADD = ../libexfat/libexfat.a $(FUSE_LIBS)
|
||||
|
||||
install-exec-hook:
|
||||
ln -sf $(sbin_PROGRAMS) $(DESTDIR)$(sbindir)/mount.exfat
|
||||
|
||||
uninstall-hook:
|
||||
rm -f $(DESTDIR)$(sbindir)/mount.exfat
|
||||
-644
@@ -1,644 +0,0 @@
|
||||
/*
|
||||
main.c (01.09.09)
|
||||
FUSE-based exFAT implementation. Requires FUSE 2.6 or later.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <exfat.h>
|
||||
#define FUSE_USE_VERSION 26
|
||||
#include <fuse.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef DEBUG
|
||||
#define exfat_debug(format, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#if !defined(FUSE_VERSION) || (FUSE_VERSION < 26)
|
||||
#error FUSE 2.6 or later is required
|
||||
#endif
|
||||
|
||||
struct exfat ef;
|
||||
|
||||
static struct exfat_node* get_node(const struct fuse_file_info* fi)
|
||||
{
|
||||
return (struct exfat_node*) (size_t) fi->fh;
|
||||
}
|
||||
|
||||
static void set_node(struct fuse_file_info* fi, struct exfat_node* node)
|
||||
{
|
||||
fi->fh = (uint64_t) (size_t) node;
|
||||
fi->keep_cache = 1;
|
||||
}
|
||||
|
||||
static int fuse_exfat_getattr(const char* path, struct stat* stbuf)
|
||||
{
|
||||
struct exfat_node* node;
|
||||
int rc;
|
||||
|
||||
exfat_debug("[%s] %s", __func__, path);
|
||||
|
||||
rc = exfat_lookup(&ef, &node, path);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
exfat_stat(&ef, node, stbuf);
|
||||
exfat_put_node(&ef, node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_exfat_truncate(const char* path, off_t size)
|
||||
{
|
||||
struct exfat_node* node;
|
||||
int rc;
|
||||
|
||||
exfat_debug("[%s] %s, %"PRId64, __func__, path, size);
|
||||
|
||||
rc = exfat_lookup(&ef, &node, path);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = exfat_truncate(&ef, node, size, true);
|
||||
if (rc != 0)
|
||||
{
|
||||
exfat_flush_node(&ef, node); /* ignore return code */
|
||||
exfat_put_node(&ef, node);
|
||||
return rc;
|
||||
}
|
||||
rc = exfat_flush_node(&ef, node);
|
||||
exfat_put_node(&ef, node);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fuse_exfat_readdir(const char* path, void* buffer,
|
||||
fuse_fill_dir_t filler, UNUSED off_t offset,
|
||||
UNUSED struct fuse_file_info* fi)
|
||||
{
|
||||
struct exfat_node* parent;
|
||||
struct exfat_node* node;
|
||||
struct exfat_iterator it;
|
||||
int rc;
|
||||
char name[EXFAT_UTF8_NAME_BUFFER_MAX];
|
||||
struct stat stbuf;
|
||||
|
||||
exfat_debug("[%s] %s", __func__, path);
|
||||
|
||||
rc = exfat_lookup(&ef, &parent, path);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
if (!(parent->attrib & EXFAT_ATTRIB_DIR))
|
||||
{
|
||||
exfat_put_node(&ef, parent);
|
||||
exfat_error("'%s' is not a directory (%#hx)", path, parent->attrib);
|
||||
return -ENOTDIR;
|
||||
}
|
||||
|
||||
filler(buffer, ".", NULL, 0);
|
||||
filler(buffer, "..", NULL, 0);
|
||||
|
||||
rc = exfat_opendir(&ef, parent, &it);
|
||||
if (rc != 0)
|
||||
{
|
||||
exfat_put_node(&ef, parent);
|
||||
exfat_error("failed to open directory '%s'", path);
|
||||
return rc;
|
||||
}
|
||||
while ((node = exfat_readdir(&it)))
|
||||
{
|
||||
exfat_get_name(node, name);
|
||||
exfat_debug("[%s] %s: %s, %"PRId64" bytes, cluster 0x%x", __func__,
|
||||
name, node->is_contiguous ? "contiguous" : "fragmented",
|
||||
node->size, node->start_cluster);
|
||||
exfat_stat(&ef, node, &stbuf);
|
||||
filler(buffer, name, &stbuf, 0);
|
||||
exfat_put_node(&ef, node);
|
||||
}
|
||||
exfat_closedir(&ef, &it);
|
||||
exfat_put_node(&ef, parent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_exfat_open(const char* path, struct fuse_file_info* fi)
|
||||
{
|
||||
struct exfat_node* node;
|
||||
int rc;
|
||||
|
||||
exfat_debug("[%s] %s", __func__, path);
|
||||
|
||||
rc = exfat_lookup(&ef, &node, path);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
set_node(fi, node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_exfat_create(const char* path, UNUSED mode_t mode,
|
||||
struct fuse_file_info* fi)
|
||||
{
|
||||
struct exfat_node* node;
|
||||
int rc;
|
||||
|
||||
exfat_debug("[%s] %s 0%ho", __func__, path, mode);
|
||||
|
||||
rc = exfat_mknod(&ef, path);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
rc = exfat_lookup(&ef, &node, path);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
set_node(fi, node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_exfat_release(UNUSED const char* path,
|
||||
struct fuse_file_info* fi)
|
||||
{
|
||||
/*
|
||||
This handler is called by FUSE on close() syscall. If the FUSE
|
||||
implementation does not call flush handler, we will flush node here.
|
||||
But in this case we will not be able to return an error to the caller.
|
||||
See fuse_exfat_flush() below.
|
||||
*/
|
||||
exfat_debug("[%s] %s", __func__, path);
|
||||
exfat_flush_node(&ef, get_node(fi));
|
||||
exfat_put_node(&ef, get_node(fi));
|
||||
return 0; /* FUSE ignores this return value */
|
||||
}
|
||||
|
||||
static int fuse_exfat_flush(UNUSED const char* path, struct fuse_file_info* fi)
|
||||
{
|
||||
/*
|
||||
This handler may be called by FUSE on close() syscall. FUSE also deals
|
||||
with removals of open files, so we don't free clusters on close but
|
||||
only on rmdir and unlink. If the FUSE implementation does not call this
|
||||
handler we will flush node on release. See fuse_exfat_relase() above.
|
||||
*/
|
||||
exfat_debug("[%s] %s", __func__, path);
|
||||
return exfat_flush_node(&ef, get_node(fi));
|
||||
}
|
||||
|
||||
static int fuse_exfat_fsync(UNUSED const char* path, UNUSED int datasync,
|
||||
UNUSED struct fuse_file_info *fi)
|
||||
{
|
||||
int rc;
|
||||
|
||||
exfat_debug("[%s] %s", __func__, path);
|
||||
rc = exfat_flush_nodes(&ef);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
rc = exfat_flush(&ef);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
return exfat_fsync(ef.dev);
|
||||
}
|
||||
|
||||
static int fuse_exfat_read(UNUSED const char* path, char* buffer,
|
||||
size_t size, off_t offset, struct fuse_file_info* fi)
|
||||
{
|
||||
exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
|
||||
return exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
|
||||
}
|
||||
|
||||
static int fuse_exfat_write(UNUSED const char* path, const char* buffer,
|
||||
size_t size, off_t offset, struct fuse_file_info* fi)
|
||||
{
|
||||
exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
|
||||
return exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
|
||||
}
|
||||
|
||||
static int fuse_exfat_unlink(const char* path)
|
||||
{
|
||||
struct exfat_node* node;
|
||||
int rc;
|
||||
|
||||
exfat_debug("[%s] %s", __func__, path);
|
||||
|
||||
rc = exfat_lookup(&ef, &node, path);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = exfat_unlink(&ef, node);
|
||||
exfat_put_node(&ef, node);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
return exfat_cleanup_node(&ef, node);
|
||||
}
|
||||
|
||||
static int fuse_exfat_rmdir(const char* path)
|
||||
{
|
||||
struct exfat_node* node;
|
||||
int rc;
|
||||
|
||||
exfat_debug("[%s] %s", __func__, path);
|
||||
|
||||
rc = exfat_lookup(&ef, &node, path);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = exfat_rmdir(&ef, node);
|
||||
exfat_put_node(&ef, node);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
return exfat_cleanup_node(&ef, node);
|
||||
}
|
||||
|
||||
static int fuse_exfat_mknod(const char* path, UNUSED mode_t mode,
|
||||
UNUSED dev_t dev)
|
||||
{
|
||||
exfat_debug("[%s] %s 0%ho", __func__, path, mode);
|
||||
return exfat_mknod(&ef, path);
|
||||
}
|
||||
|
||||
static int fuse_exfat_mkdir(const char* path, UNUSED mode_t mode)
|
||||
{
|
||||
exfat_debug("[%s] %s 0%ho", __func__, path, mode);
|
||||
return exfat_mkdir(&ef, path);
|
||||
}
|
||||
|
||||
static int fuse_exfat_rename(const char* old_path, const char* new_path)
|
||||
{
|
||||
exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
|
||||
return exfat_rename(&ef, old_path, new_path);
|
||||
}
|
||||
|
||||
static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
|
||||
{
|
||||
struct exfat_node* node;
|
||||
int rc;
|
||||
|
||||
exfat_debug("[%s] %s", __func__, path);
|
||||
|
||||
rc = exfat_lookup(&ef, &node, path);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
exfat_utimes(node, tv);
|
||||
rc = exfat_flush_node(&ef, node);
|
||||
exfat_put_node(&ef, node);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fuse_exfat_chmod(UNUSED const char* path, mode_t mode)
|
||||
{
|
||||
const mode_t VALID_MODE_MASK = S_IFREG | S_IFDIR |
|
||||
S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
|
||||
exfat_debug("[%s] %s 0%ho", __func__, path, mode);
|
||||
if (mode & ~VALID_MODE_MASK)
|
||||
return -EPERM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_exfat_chown(UNUSED const char* path, uid_t uid, gid_t gid)
|
||||
{
|
||||
exfat_debug("[%s] %s %u:%u", __func__, path, uid, gid);
|
||||
if (uid != ef.uid || gid != ef.gid)
|
||||
return -EPERM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_exfat_statfs(UNUSED const char* path, struct statvfs* sfs)
|
||||
{
|
||||
exfat_debug("[%s]", __func__);
|
||||
|
||||
sfs->f_bsize = CLUSTER_SIZE(*ef.sb);
|
||||
sfs->f_frsize = CLUSTER_SIZE(*ef.sb);
|
||||
sfs->f_blocks = le64_to_cpu(ef.sb->sector_count) >> ef.sb->spc_bits;
|
||||
sfs->f_bavail = exfat_count_free_clusters(&ef);
|
||||
sfs->f_bfree = sfs->f_bavail;
|
||||
sfs->f_namemax = EXFAT_NAME_MAX;
|
||||
|
||||
/*
|
||||
Below are fake values because in exFAT there is
|
||||
a) no simple way to count files;
|
||||
b) no such thing as inode;
|
||||
So here we assume that inode = cluster.
|
||||
*/
|
||||
sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
|
||||
sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
|
||||
sfs->f_ffree = sfs->f_bavail;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void* fuse_exfat_init(struct fuse_conn_info* fci)
|
||||
{
|
||||
exfat_debug("[%s]", __func__);
|
||||
#ifdef FUSE_CAP_BIG_WRITES
|
||||
fci->want |= FUSE_CAP_BIG_WRITES;
|
||||
#endif
|
||||
|
||||
/* mark super block as dirty; failure isn't a big deal */
|
||||
exfat_soil_super_block(&ef);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void fuse_exfat_destroy(UNUSED void* unused)
|
||||
{
|
||||
exfat_debug("[%s]", __func__);
|
||||
exfat_unmount(&ef);
|
||||
}
|
||||
|
||||
static void usage(const char* prog)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d] [-o options] [-V] <device> <dir>\n", prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static struct fuse_operations fuse_exfat_ops =
|
||||
{
|
||||
.getattr = fuse_exfat_getattr,
|
||||
.truncate = fuse_exfat_truncate,
|
||||
.readdir = fuse_exfat_readdir,
|
||||
.open = fuse_exfat_open,
|
||||
.create = fuse_exfat_create,
|
||||
.release = fuse_exfat_release,
|
||||
.flush = fuse_exfat_flush,
|
||||
.fsync = fuse_exfat_fsync,
|
||||
.fsyncdir = fuse_exfat_fsync,
|
||||
.read = fuse_exfat_read,
|
||||
.write = fuse_exfat_write,
|
||||
.unlink = fuse_exfat_unlink,
|
||||
.rmdir = fuse_exfat_rmdir,
|
||||
.mknod = fuse_exfat_mknod,
|
||||
.mkdir = fuse_exfat_mkdir,
|
||||
.rename = fuse_exfat_rename,
|
||||
.utimens = fuse_exfat_utimens,
|
||||
.chmod = fuse_exfat_chmod,
|
||||
.chown = fuse_exfat_chown,
|
||||
.statfs = fuse_exfat_statfs,
|
||||
.init = fuse_exfat_init,
|
||||
.destroy = fuse_exfat_destroy,
|
||||
};
|
||||
|
||||
static char* add_option(char* options, const char* name, const char* value)
|
||||
{
|
||||
size_t size;
|
||||
char* optionsf = options;
|
||||
|
||||
if (value)
|
||||
size = strlen(options) + strlen(name) + strlen(value) + 3;
|
||||
else
|
||||
size = strlen(options) + strlen(name) + 2;
|
||||
|
||||
options = realloc(options, size);
|
||||
if (options == NULL)
|
||||
{
|
||||
free(optionsf);
|
||||
exfat_error("failed to reallocate options string");
|
||||
return NULL;
|
||||
}
|
||||
strcat(options, ",");
|
||||
strcat(options, name);
|
||||
if (value)
|
||||
{
|
||||
strcat(options, "=");
|
||||
strcat(options, value);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
static void escape(char* escaped, const char* orig)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (*orig == ',' || *orig == '\\')
|
||||
*escaped++ = '\\';
|
||||
}
|
||||
while ((*escaped++ = *orig++));
|
||||
}
|
||||
|
||||
static char* add_fsname_option(char* options, const char* spec)
|
||||
{
|
||||
/* escaped string cannot be more than twice as big as the original one */
|
||||
char* escaped = malloc(strlen(spec) * 2 + 1);
|
||||
|
||||
if (escaped == NULL)
|
||||
{
|
||||
free(options);
|
||||
exfat_error("failed to allocate escaped string for %s", spec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* on some platforms (e.g. Android, Solaris) device names can contain
|
||||
commas */
|
||||
escape(escaped, spec);
|
||||
options = add_option(options, "fsname", escaped);
|
||||
free(escaped);
|
||||
return options;
|
||||
}
|
||||
|
||||
static char* add_ro_option(char* options, bool ro)
|
||||
{
|
||||
return ro ? add_option(options, "ro", NULL) : options;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
static char* add_user_option(char* options)
|
||||
{
|
||||
struct passwd* pw;
|
||||
|
||||
if (getuid() == 0)
|
||||
return options;
|
||||
|
||||
pw = getpwuid(getuid());
|
||||
if (pw == NULL || pw->pw_name == NULL)
|
||||
{
|
||||
free(options);
|
||||
exfat_error("failed to determine username");
|
||||
return NULL;
|
||||
}
|
||||
return add_option(options, "user", pw->pw_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
static char* add_blksize_option(char* options, long cluster_size)
|
||||
{
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
char blksize[20];
|
||||
|
||||
if (page_size < 1)
|
||||
page_size = 0x1000;
|
||||
|
||||
snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
|
||||
return add_option(options, "blksize", blksize);
|
||||
}
|
||||
#endif
|
||||
|
||||
static char* add_fuse_options(char* options, const char* spec, bool ro)
|
||||
{
|
||||
options = add_fsname_option(options, spec);
|
||||
if (options == NULL)
|
||||
return NULL;
|
||||
options = add_ro_option(options, ro);
|
||||
if (options == NULL)
|
||||
return NULL;
|
||||
#if defined(__linux__)
|
||||
options = add_user_option(options);
|
||||
if (options == NULL)
|
||||
return NULL;
|
||||
options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
|
||||
if (options == NULL)
|
||||
return NULL;
|
||||
#endif
|
||||
return options;
|
||||
}
|
||||
|
||||
static char* add_passthrough_fuse_options(char* fuse_options,
|
||||
const char* options)
|
||||
{
|
||||
const char* passthrough_list[] =
|
||||
{
|
||||
#if defined(__FreeBSD__)
|
||||
"automounted",
|
||||
#endif
|
||||
"nonempty",
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; passthrough_list[i] != NULL; i++)
|
||||
if (exfat_match_option(options, passthrough_list[i]))
|
||||
{
|
||||
fuse_options = add_option(fuse_options, passthrough_list[i], NULL);
|
||||
if (fuse_options == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fuse_options;
|
||||
}
|
||||
|
||||
static int fuse_exfat_main(char* mount_options, char* mount_point)
|
||||
{
|
||||
char* argv[] = {"exfat", "-s", "-o", mount_options, mount_point, NULL};
|
||||
return fuse_main(sizeof(argv) / sizeof(argv[0]) - 1, argv,
|
||||
&fuse_exfat_ops, NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* spec = NULL;
|
||||
char* mount_point = NULL;
|
||||
char* fuse_options;
|
||||
char* exfat_options;
|
||||
int opt;
|
||||
int rc;
|
||||
|
||||
printf("FUSE exfat %s\n", VERSION);
|
||||
|
||||
fuse_options = strdup("allow_other,"
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
"big_writes,"
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
"blkdev,"
|
||||
#endif
|
||||
"default_permissions");
|
||||
exfat_options = strdup("ro_fallback");
|
||||
if (fuse_options == NULL || exfat_options == NULL)
|
||||
{
|
||||
free(fuse_options);
|
||||
free(exfat_options);
|
||||
exfat_error("failed to allocate options string");
|
||||
return 1;
|
||||
}
|
||||
|
||||
while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'd':
|
||||
fuse_options = add_option(fuse_options, "debug", NULL);
|
||||
if (fuse_options == NULL)
|
||||
{
|
||||
free(exfat_options);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
break;
|
||||
case 'o':
|
||||
exfat_options = add_option(exfat_options, optarg, NULL);
|
||||
if (exfat_options == NULL)
|
||||
{
|
||||
free(fuse_options);
|
||||
return 1;
|
||||
}
|
||||
fuse_options = add_passthrough_fuse_options(fuse_options, optarg);
|
||||
if (fuse_options == NULL)
|
||||
{
|
||||
free(exfat_options);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
free(exfat_options);
|
||||
free(fuse_options);
|
||||
puts("Copyright (C) 2010-2018 Andrew Nayenko");
|
||||
return 0;
|
||||
case 'v':
|
||||
break;
|
||||
default:
|
||||
free(exfat_options);
|
||||
free(fuse_options);
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (argc - optind != 2)
|
||||
{
|
||||
free(exfat_options);
|
||||
free(fuse_options);
|
||||
usage(argv[0]);
|
||||
}
|
||||
spec = argv[optind];
|
||||
mount_point = argv[optind + 1];
|
||||
|
||||
if (exfat_mount(&ef, spec, exfat_options) != 0)
|
||||
{
|
||||
free(exfat_options);
|
||||
free(fuse_options);
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(exfat_options);
|
||||
|
||||
fuse_options = add_fuse_options(fuse_options, spec, ef.ro != 0);
|
||||
if (fuse_options == NULL)
|
||||
{
|
||||
exfat_unmount(&ef);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* let FUSE do all its wizardry */
|
||||
rc = fuse_exfat_main(fuse_options, mount_point);
|
||||
|
||||
free(fuse_options);
|
||||
return rc;
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
.\" Copyright (C) 2010-2016 Andrew Nayenko
|
||||
.\"
|
||||
.TH EXFAT-FUSE 8 "November 2015"
|
||||
.SH NAME
|
||||
mount.exfat-fuse \- mount an exFAT file system
|
||||
.SH SYNOPSIS
|
||||
.B mount.exfat-fuse
|
||||
[
|
||||
.B \-d
|
||||
]
|
||||
[
|
||||
.B \-n
|
||||
]
|
||||
[
|
||||
.B \-o
|
||||
.I options
|
||||
]
|
||||
[
|
||||
.B \-V
|
||||
]
|
||||
[
|
||||
.B \-v
|
||||
]
|
||||
.I device dir
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B mount.exfat-fuse
|
||||
is a free exFAT file system implementation with write support. exFAT is a
|
||||
simple file system created by Microsoft. It is intended to replace FAT32
|
||||
removing some of its limitations. exFAT is a standard FS for SDXC memory
|
||||
cards.
|
||||
|
||||
.SH COMMAND LINE OPTIONS
|
||||
Command line options available:
|
||||
.TP
|
||||
.BI \-d
|
||||
Enable debug logging and do not detach from shell.
|
||||
.TP
|
||||
.BI \-n
|
||||
Ignored.
|
||||
.TP
|
||||
.BI \-o " options"
|
||||
File system specific options. For more details see
|
||||
.B FILE SYSTEM OPTIONS
|
||||
section below.
|
||||
.TP
|
||||
.BI \-V
|
||||
Print version and copyright.
|
||||
.TP
|
||||
.BI \-v
|
||||
Ignored.
|
||||
|
||||
.SH FILE SYSTEM OPTIONS
|
||||
.TP
|
||||
.BI umask= value
|
||||
Set the umask (the bitmask of the permissions that are
|
||||
.B not
|
||||
present, in octal).
|
||||
The default is 0.
|
||||
.TP
|
||||
.BI dmask= value
|
||||
Set the umask for directories only.
|
||||
.TP
|
||||
.BI fmask= value
|
||||
Set the umask for files only.
|
||||
.TP
|
||||
.BI uid= n
|
||||
Set the owner for all files and directories.
|
||||
The default is the owner of the current process.
|
||||
.TP
|
||||
.BI gid= n
|
||||
Set the group for all files and directories.
|
||||
The default is the group of the current process.
|
||||
.TP
|
||||
.BI ro
|
||||
Mount the file system in read only mode.
|
||||
.TP
|
||||
.BI noatime
|
||||
Do not update access time when file is read.
|
||||
|
||||
.SH EXIT CODES
|
||||
Zero is returned on successful mount. Any other code means an error.
|
||||
|
||||
.SH BUGS
|
||||
exFAT is a case-insensitive file system. Some things can behave unexpectedly,
|
||||
e.g. directory renaming that changes only case of some characters:
|
||||
|
||||
.B \t$ mv FOO Foo
|
||||
.br
|
||||
.B \tmv: cannot move \(cqFOO\(cq to a subdirectory of itself, \(cqFoo/FOO\(cq
|
||||
|
||||
This happens because
|
||||
.B mv
|
||||
finds that destination exists (for case-insensitive file
|
||||
systems
|
||||
.B FOO
|
||||
and
|
||||
.B Foo
|
||||
are the same thing) and adds source basename to the destination. The file
|
||||
system gets
|
||||
.B rename(\(dqFOO\(dq,\ \(dqFoo/FOO\(dq)
|
||||
syscall and returns an error.
|
||||
|
||||
.SH AUTHOR
|
||||
Andrew Nayenko
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR mount (8)
|
||||
@@ -0,0 +1,222 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
|
||||
*/
|
||||
|
||||
#ifndef _EXFAT_H
|
||||
#define _EXFAT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define cpu_to_le16(x) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))
|
||||
#define cpu_to_le32(x) \
|
||||
((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | \
|
||||
(((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24))
|
||||
#define cpu_to_le64(x) (cpu_to_le32((uint64_t)(x)) << 32 | \
|
||||
cpu_to_le32((uint64_t)(x) >> 32))
|
||||
#else
|
||||
#define cpu_to_le16(x) (x)
|
||||
#define cpu_to_le32(x) (x)
|
||||
#define cpu_to_le64(x) (x)
|
||||
#endif
|
||||
|
||||
#define le64_to_cpu(x) ((uint64_t)cpu_to_le64(x))
|
||||
#define le32_to_cpu(x) ((uint32_t)cpu_to_le32(x))
|
||||
#define le16_to_cpu(x) ((uint16_t)cpu_to_le16(x))
|
||||
|
||||
#define PBR_SIGNATURE 0xAA55
|
||||
|
||||
#define VOL_CLEAN 0x0000
|
||||
#define VOL_DIRTY 0x0002
|
||||
|
||||
#define DENTRY_SIZE 32 /* directory entry size */
|
||||
#define DENTRY_SIZE_BITS 5
|
||||
/* exFAT allows 8388608(256MB) directory entries */
|
||||
#define MAX_EXFAT_DENTRIES 8388608
|
||||
|
||||
/* dentry types */
|
||||
#define MSDOS_DELETED 0xE5 /* deleted mark */
|
||||
#define MSDOS_UNUSED 0x00 /* end of directory */
|
||||
|
||||
#define EXFAT_LAST 0x00 /* end of directory */
|
||||
#define EXFAT_DELETE ~(0x80)
|
||||
#define IS_EXFAT_DELETED(x) ((x) < 0x80) /* deleted file (0x01~0x7F) */
|
||||
#define EXFAT_INVAL 0x80 /* invalid value */
|
||||
#define EXFAT_BITMAP 0x81 /* allocation bitmap */
|
||||
#define EXFAT_UPCASE 0x82 /* upcase table */
|
||||
#define EXFAT_VOLUME 0x83 /* volume label */
|
||||
#define EXFAT_FILE 0x85 /* file or dir */
|
||||
#define EXFAT_GUID 0xA0
|
||||
#define EXFAT_PADDING 0xA1
|
||||
#define EXFAT_ACLTAB 0xA2
|
||||
#define EXFAT_STREAM 0xC0 /* stream entry */
|
||||
#define EXFAT_NAME 0xC1 /* file name entry */
|
||||
#define EXFAT_ACL 0xC2 /* stream entry */
|
||||
|
||||
/* checksum types */
|
||||
#define CS_DIR_ENTRY 0
|
||||
#define CS_PBR_SECTOR 1
|
||||
#define CS_DEFAULT 2
|
||||
|
||||
/* file attributes */
|
||||
#define ATTR_READONLY 0x0001
|
||||
#define ATTR_HIDDEN 0x0002
|
||||
#define ATTR_SYSTEM 0x0004
|
||||
#define ATTR_VOLUME 0x0008
|
||||
#define ATTR_SUBDIR 0x0010
|
||||
#define ATTR_ARCHIVE 0x0020
|
||||
#define ATTR_EXTEND (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | \
|
||||
ATTR_VOLUME) /* 0x000F */
|
||||
|
||||
#define ATTR_EXTEND_MASK (ATTR_EXTEND | ATTR_SUBDIR | ATTR_ARCHIVE)
|
||||
#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \
|
||||
ATTR_SUBDIR | ATTR_ARCHIVE)
|
||||
|
||||
#define ATTR_READONLY_LE cpu_to_le16(0x0001)
|
||||
#define ATTR_HIDDEN_LE cpu_to_le16(0x0002)
|
||||
#define ATTR_SYSTEM_LE cpu_to_le16(0x0004)
|
||||
#define ATTR_VOLUME_LE cpu_to_le16(0x0008)
|
||||
#define ATTR_SUBDIR_LE cpu_to_le16(0x0010)
|
||||
#define ATTR_ARCHIVE_LE cpu_to_le16(0x0020)
|
||||
|
||||
/* stream flags */
|
||||
#define EXFAT_SF_CONTIGUOUS 0x02
|
||||
|
||||
#define CLUSTER_32(x) ((unsigned int)((x) & 0xFFFFFFFFU))
|
||||
#define EXFAT_EOF_CLUSTER CLUSTER_32(~0)
|
||||
#define EXFAT_BAD_CLUSTER (0xFFFFFFF7U)
|
||||
#define EXFAT_FREE_CLUSTER (0)
|
||||
#define EXFAT_FIRST_CLUSTER (2)
|
||||
#define EXFAT_RESERVED_CLUSTERS (2)
|
||||
|
||||
|
||||
/* EXFAT BIOS parameter block (64 bytes) */
|
||||
struct bpb64 {
|
||||
__u8 jmp_boot[3];
|
||||
__u8 oem_name[8];
|
||||
__u8 res_zero[53];
|
||||
};
|
||||
|
||||
/* EXFAT EXTEND BIOS parameter block (56 bytes) */
|
||||
struct bsx64 {
|
||||
__le64 vol_offset;
|
||||
__le64 vol_length;
|
||||
__le32 fat_offset;
|
||||
__le32 fat_length;
|
||||
__le32 clu_offset;
|
||||
__le32 clu_count;
|
||||
__le32 root_cluster;
|
||||
__le32 vol_serial;
|
||||
__u8 fs_version[2];
|
||||
__le16 vol_flags;
|
||||
__u8 sect_size_bits;
|
||||
__u8 sect_per_clus_bits;
|
||||
__u8 num_fats;
|
||||
__u8 phy_drv_no;
|
||||
__u8 perc_in_use;
|
||||
__u8 reserved2[7];
|
||||
};
|
||||
|
||||
/* Common PBR[Partition Boot Record] (512 bytes) */
|
||||
struct pbr {
|
||||
struct bpb64 bpb;
|
||||
struct bsx64 bsx;
|
||||
__u8 boot_code[390];
|
||||
__le16 signature;
|
||||
};
|
||||
|
||||
#define VOLUME_LABEL_MAX_LEN 11
|
||||
#define ENTRY_NAME_MAX 15
|
||||
|
||||
struct exfat_dentry {
|
||||
__u8 type;
|
||||
union {
|
||||
struct {
|
||||
__u8 character_count;
|
||||
__le16 volume_label[VOLUME_LABEL_MAX_LEN];
|
||||
__u8 reserved[8];
|
||||
} __attribute__((packed)) vol; /* file directory entry */
|
||||
|
||||
struct {
|
||||
__u8 num_ext;
|
||||
__le16 checksum;
|
||||
__le16 attr;
|
||||
__le16 reserved1;
|
||||
__le16 create_time;
|
||||
__le16 create_date;
|
||||
__le16 modify_time;
|
||||
__le16 modify_date;
|
||||
__le16 access_time;
|
||||
__le16 access_date;
|
||||
__u8 create_time_ms;
|
||||
__u8 modify_time_ms;
|
||||
__u8 access_time_ms;
|
||||
__u8 reserved2[9];
|
||||
} __attribute__((packed)) file; /* file directory entry */
|
||||
struct {
|
||||
__u8 flags;
|
||||
__u8 reserved1;
|
||||
__u8 name_len;
|
||||
__le16 name_hash;
|
||||
__le16 reserved2;
|
||||
__le64 valid_size;
|
||||
__le32 reserved3;
|
||||
__le32 start_clu;
|
||||
__le64 size;
|
||||
} __attribute__((packed)) stream; /* stream extension directory entry */
|
||||
struct {
|
||||
__u8 flags;
|
||||
__le16 unicode_0_14[15];
|
||||
} __attribute__((packed)) name; /* file name directory entry */
|
||||
struct {
|
||||
__u8 flags;
|
||||
__u8 reserved[18];
|
||||
__le32 start_clu;
|
||||
__le64 size;
|
||||
} __attribute__((packed)) bitmap; /* allocation bitmap directory entry */
|
||||
struct {
|
||||
__u8 reserved1[3];
|
||||
__le32 checksum;
|
||||
__u8 reserved2[12];
|
||||
__le32 start_clu;
|
||||
__le64 size;
|
||||
} __attribute__((packed)) upcase; /* up-case table directory entry */
|
||||
} __attribute__((packed)) dentry;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define vol_char_cnt dentry.vol.character_count
|
||||
#define vol_label dentry.vol.volume_label
|
||||
#define file_num_ext dentry.file.num_ext
|
||||
#define file_checksum dentry.file.checksum
|
||||
#define file_attr dentry.file.attr
|
||||
#define file_create_time dentry.file.create_time
|
||||
#define file_create_date dentry.file.create_date
|
||||
#define file_modify_time dentry.file.modify_time
|
||||
#define file_modify_date dentry.file.modify_date
|
||||
#define file_access_time dentry.file.access_time
|
||||
#define file_access_date dentry.file.access_date
|
||||
#define file_create_time_ms dentry.file.create_time_ms
|
||||
#define file_modify_time_ms dentry.file.modify_time_ms
|
||||
#define file_access_time_ms dentry.file.access_time_ms
|
||||
#define stream_flags dentry.stream.flags
|
||||
#define stream_name_len dentry.stream.name_len
|
||||
#define stream_name_hash dentry.stream.name_hash
|
||||
#define stream_start_clu dentry.stream.start_clu
|
||||
#define stream_valid_size dentry.stream.valid_size
|
||||
#define stream_size dentry.stream.size
|
||||
#define name_flags dentry.name.flags
|
||||
#define name_unicode dentry.name.unicode_0_14
|
||||
#define bitmap_flags dentry.bitmap.flags
|
||||
#define bitmap_start_clu dentry.bitmap.start_clu
|
||||
#define bitmap_size dentry.bitmap.size
|
||||
#define upcase_start_clu dentry.upcase.start_clu
|
||||
#define upcase_size dentry.upcase.size
|
||||
#define upcase_checksum dentry.upcase.checksum
|
||||
|
||||
#endif /* !_EXFAT_H */
|
||||
@@ -0,0 +1,144 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
|
||||
*/
|
||||
|
||||
#ifndef _LIBEXFAT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <wchar.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define KB (1024)
|
||||
#define MB (1024*1024)
|
||||
#define GB (1024UL*1024UL*1024UL)
|
||||
|
||||
#define __round_mask(x, y) ((__typeof__(x))((y)-1))
|
||||
#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
|
||||
#define round_down(x, y) ((x) & ~__round_mask(x, y))
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define DIV_ROUND_UP(__i, __d) (((__i) + (__d) - 1) / (__d))
|
||||
|
||||
#define EXFAT_MIN_NUM_SEC_VOL (2048)
|
||||
#define EXFAT_MAX_NUM_SEC_VOL ((2 << 64) - 1)
|
||||
|
||||
#define EXFAT_MAX_NUM_CLUSTER (0xFFFFFFF5)
|
||||
|
||||
#define DEFAULT_BOUNDARY_ALIGNMENT (1024*1024)
|
||||
|
||||
#define DEFAULT_SECTOR_SIZE (512)
|
||||
|
||||
#define VOLUME_LABEL_BUFFER_SIZE (VOLUME_LABEL_MAX_LEN*MB_LEN_MAX+1)
|
||||
|
||||
/* Upcase table macro */
|
||||
#define EXFAT_UPCASE_TABLE_SIZE (5836)
|
||||
|
||||
/* Flags for tune.exfat and exfatlabel */
|
||||
#define EXFAT_GET_VOLUME_LABEL 0x01
|
||||
#define EXFAT_SET_VOLUME_LABEL 0x02
|
||||
#define EXFAT_GET_VOLUME_SERIAL 0x03
|
||||
#define EXFAT_SET_VOLUME_SERIAL 0x04
|
||||
|
||||
#define EXFAT_MAX_SECTOR_SIZE 4096
|
||||
|
||||
enum {
|
||||
BOOT_SEC_IDX = 0,
|
||||
EXBOOT_SEC_IDX,
|
||||
EXBOOT_SEC_NUM = 8,
|
||||
OEM_SEC_IDX,
|
||||
RESERVED_SEC_IDX,
|
||||
CHECKSUM_SEC_IDX,
|
||||
BACKUP_BOOT_SEC_IDX,
|
||||
};
|
||||
|
||||
struct exfat_blk_dev {
|
||||
int dev_fd;
|
||||
unsigned long long offset;
|
||||
unsigned long long size;
|
||||
unsigned int sector_size;
|
||||
unsigned int sector_size_bits;
|
||||
unsigned long long num_sectors;
|
||||
unsigned int num_clusters;
|
||||
unsigned int cluster_size;
|
||||
};
|
||||
|
||||
struct exfat_user_input {
|
||||
char dev_name[255];
|
||||
bool writeable;
|
||||
unsigned int cluster_size;
|
||||
unsigned int sec_per_clu;
|
||||
unsigned int boundary_align;
|
||||
bool pack_bitmap;
|
||||
bool quick;
|
||||
__u16 volume_label[VOLUME_LABEL_MAX_LEN];
|
||||
int volume_label_len;
|
||||
unsigned int volume_serial;
|
||||
};
|
||||
|
||||
void show_version(void);
|
||||
|
||||
void exfat_set_bit(struct exfat_blk_dev *bd, char *bitmap,
|
||||
unsigned int clu);
|
||||
void exfat_clear_bit(struct exfat_blk_dev *bd, char *bitmap,
|
||||
unsigned int clu);
|
||||
wchar_t exfat_bad_char(wchar_t w);
|
||||
void boot_calc_checksum(unsigned char *sector, unsigned short size,
|
||||
bool is_boot_sec, __le32 *checksum);
|
||||
void init_user_input(struct exfat_user_input *ui);
|
||||
int exfat_get_blk_dev_info(struct exfat_user_input *ui,
|
||||
struct exfat_blk_dev *bd);
|
||||
ssize_t exfat_read(int fd, void *buf, size_t size, off_t offset);
|
||||
ssize_t exfat_write(int fd, void *buf, size_t size, off_t offset);
|
||||
|
||||
size_t exfat_utf16_len(const __le16 *str, size_t max_size);
|
||||
ssize_t exfat_utf16_enc(const char *in_str, __u16 *out_str, size_t out_size);
|
||||
ssize_t exfat_utf16_dec(const __u16 *in_str, size_t in_len,
|
||||
char *out_str, size_t out_size);
|
||||
off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd);
|
||||
int exfat_show_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off);
|
||||
int exfat_set_volume_label(struct exfat_blk_dev *bd,
|
||||
char *label_input, off_t root_clu_off);
|
||||
int exfat_read_sector(struct exfat_blk_dev *bd, void *buf,
|
||||
unsigned int sec_off);
|
||||
int exfat_write_sector(struct exfat_blk_dev *bd, void *buf,
|
||||
unsigned int sec_off);
|
||||
int exfat_write_checksum_sector(struct exfat_blk_dev *bd,
|
||||
unsigned int checksum, bool is_backup);
|
||||
char *exfat_conv_volume_label(struct exfat_dentry *vol_entry);
|
||||
int exfat_show_volume_serial(int fd);
|
||||
int exfat_set_volume_serial(struct exfat_blk_dev *bd,
|
||||
struct exfat_user_input *ui);
|
||||
unsigned int exfat_clus_to_blk_dev_off(struct exfat_blk_dev *bd,
|
||||
unsigned int clu_off, unsigned int clu);
|
||||
|
||||
|
||||
/*
|
||||
* Exfat Print
|
||||
*/
|
||||
|
||||
extern unsigned int print_level;
|
||||
|
||||
#define EXFAT_ERROR (1)
|
||||
#define EXFAT_INFO (2)
|
||||
#define EXFAT_DEBUG (3)
|
||||
|
||||
#define exfat_msg(level, dir, fmt, ...) \
|
||||
do { \
|
||||
if (print_level >= level) { \
|
||||
fprintf(dir, fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0) \
|
||||
|
||||
#define exfat_err(fmt, ...) exfat_msg(EXFAT_ERROR, stderr, \
|
||||
fmt, ##__VA_ARGS__)
|
||||
#define exfat_info(fmt, ...) exfat_msg(EXFAT_INFO, stdout, \
|
||||
fmt, ##__VA_ARGS__)
|
||||
#define exfat_debug(fmt, ...) exfat_msg(EXFAT_DEBUG, stdout, \
|
||||
"[%s:%4d] " fmt, __func__, \
|
||||
__LINE__, ##__VA_ARGS__)
|
||||
|
||||
#endif /* !_LIBEXFAT_H */
|
||||
+333
@@ -0,0 +1,333 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef _LINUX_LIST_H
|
||||
#define _LINUX_LIST_H
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof(((type *)0)->member) * __mptr = (ptr); \
|
||||
(type *)((char *)__mptr - offsetof(type, member)); \
|
||||
})
|
||||
|
||||
/*
|
||||
* These are non-NULL pointers that will result in page faults
|
||||
* under normal circumstances, used to verify that nobody uses
|
||||
* non-initialized list entries.
|
||||
*/
|
||||
#define LIST_POISON1 ((void *) 0x00100100)
|
||||
#define LIST_POISON2 ((void *) 0x00200200)
|
||||
|
||||
/**
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
entry->next = LIST_POISON1;
|
||||
entry->prev = LIST_POISON2;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static inline void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move - delete from one list and add as another's head
|
||||
* @list: the entry to move
|
||||
* @head: the head that will precede our entry
|
||||
*/
|
||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move_tail - delete from one list and add as another's tail
|
||||
* @list: the entry to move
|
||||
* @head: the head that will follow our entry
|
||||
*/
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
static inline void __list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head);
|
||||
INIT_LIST_HEAD(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* __list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*
|
||||
* This variant differs from list_for_each() in that it's the
|
||||
* simplest possible list iteration code, no prefetching is done.
|
||||
* Use this for code that knows the list to be very short (empty
|
||||
* or 1 entry) most of the time.
|
||||
*/
|
||||
#define __list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_prev - iterate over a list backwards
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_prev(pos, head) \
|
||||
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
|
||||
pos = pos->prev)
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_reverse(pos, head, member) \
|
||||
for (pos = list_entry((head)->prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_prepare_entry - prepare a pos entry for use as a start point in
|
||||
* list_for_each_entry_continue
|
||||
* @pos: the type * to use as a start point
|
||||
* @head: the head of the list
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_prepare_entry(pos, head, member) \
|
||||
((pos) ? : list_entry(head, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_continue - iterate over list of given type
|
||||
* continuing after existing point
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_continue(pos, head, member) \
|
||||
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against
|
||||
* removal of list entry
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_continue - iterate over list of given type
|
||||
* continuing after existing point safe against removal of list entry
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe_continue(pos, n, head, member) \
|
||||
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_reverse - iterate backwards over list of given
|
||||
* type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->prev, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2020 Namjae Jeon <linkinjeon@kernel.org>
|
||||
*/
|
||||
|
||||
#ifndef _VERSION_H
|
||||
|
||||
#define EXFAT_PROGS_VERSION "1.1.3"
|
||||
|
||||
#endif /* !_VERSION_H */
|
||||
+4
-25
@@ -1,27 +1,6 @@
|
||||
#
|
||||
# Makefile.am (30.03.15)
|
||||
# Automake source.
|
||||
#
|
||||
# Free exFAT implementation.
|
||||
# Copyright (C) 2011-2018 Andrew Nayenko
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common
|
||||
exfatlabel_LDADD = $(top_builddir)/lib/libexfat.a
|
||||
|
||||
sbin_PROGRAMS = exfatlabel
|
||||
dist_man8_MANS = exfatlabel.8
|
||||
exfatlabel_SOURCES = main.c
|
||||
exfatlabel_CPPFLAGS = -I$(top_srcdir)/libexfat
|
||||
exfatlabel_LDADD = ../libexfat/libexfat.a
|
||||
|
||||
exfatlabel_SOURCES = label.c
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
.\" Copyright (C) 2011-2018 Andrew Nayenko
|
||||
.\"
|
||||
.TH EXFATLABEL 8 "September 2017"
|
||||
.SH NAME
|
||||
.B exfatlabel
|
||||
\- get or set an exFAT file system label
|
||||
.SH SYNOPSIS
|
||||
.B exfatlabel
|
||||
[
|
||||
.B \-V
|
||||
]
|
||||
.I device
|
||||
[
|
||||
.I label
|
||||
]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B exfatlabel
|
||||
reads or changes an exFAT file system label (volume name).
|
||||
|
||||
If
|
||||
.I label
|
||||
argument is present,
|
||||
.B exfatlabel
|
||||
sets the new volume name. Empty label ('') removes volume name. Label can be
|
||||
up to 15 characters. This limit is shorter if characters beyond Unicode BMP
|
||||
are used because internally label is stored in UTF-16.
|
||||
|
||||
If
|
||||
.I label
|
||||
argument is omitted,
|
||||
.B exfatlabel
|
||||
just prints current volume name.
|
||||
|
||||
.SH COMMAND LINE OPTIONS
|
||||
Command line options available:
|
||||
.TP
|
||||
.BI \-V
|
||||
Print version and copyright.
|
||||
|
||||
.SH EXIT CODES
|
||||
Zero is returned on success. Any other code means an error.
|
||||
|
||||
.SH AUTHOR
|
||||
Andrew Nayenko
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR mkexfatfs (8)
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2020 Namjae Jeon <linkinjeon@kernel.org>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "exfat_ondisk.h"
|
||||
#include "libexfat.h"
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: exfatlabel\n");
|
||||
fprintf(stderr, "\t-i | --volume-serial Switch to volume serial mode\n");
|
||||
fprintf(stderr, "\t-V | --version Show version\n");
|
||||
fprintf(stderr, "\t-h | --help Show help\n");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static struct option opts[] = {
|
||||
{"volume-serial", no_argument, NULL, 'i' },
|
||||
{"version", no_argument, NULL, 'V' },
|
||||
{"help", no_argument, NULL, 'h' },
|
||||
{"?", no_argument, NULL, '?' },
|
||||
{NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int ret = EXIT_FAILURE;
|
||||
struct exfat_blk_dev bd;
|
||||
struct exfat_user_input ui;
|
||||
bool version_only = false;
|
||||
off_t root_clu_off;
|
||||
int serial_mode = 0;
|
||||
int flags = 0;
|
||||
|
||||
init_user_input(&ui);
|
||||
|
||||
if (!setlocale(LC_CTYPE, ""))
|
||||
exfat_err("failed to init locale/codeset\n");
|
||||
|
||||
if (argc == 2)
|
||||
flags = EXFAT_GET_VOLUME_LABEL;
|
||||
else if (argc == 3)
|
||||
flags = EXFAT_SET_VOLUME_LABEL;
|
||||
|
||||
opterr = 0;
|
||||
while ((c = getopt_long(argc, argv, "iVh", opts, NULL)) != EOF)
|
||||
switch (c) {
|
||||
case 'i':
|
||||
serial_mode = true;
|
||||
if (argc == 3)
|
||||
flags = EXFAT_GET_VOLUME_SERIAL;
|
||||
else if (argc == 4)
|
||||
flags = EXFAT_SET_VOLUME_SERIAL;
|
||||
|
||||
break;
|
||||
case 'V':
|
||||
version_only = true;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
show_version();
|
||||
if (version_only)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
memset(ui.dev_name, 0, sizeof(ui.dev_name));
|
||||
snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[serial_mode + 1]);
|
||||
|
||||
ret = exfat_get_blk_dev_info(&ui, &bd);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (serial_mode) {
|
||||
/* Mode to change or display volume serial */
|
||||
if (flags == EXFAT_GET_VOLUME_SERIAL) {
|
||||
ret = exfat_show_volume_serial(bd.dev_fd);
|
||||
} else if (flags == EXFAT_SET_VOLUME_SERIAL) {
|
||||
ui.volume_serial = strtoul(argv[3], NULL, 0);
|
||||
ret = exfat_set_volume_serial(&bd, &ui);
|
||||
}
|
||||
} else {
|
||||
/* Mode to change or display volume label */
|
||||
root_clu_off = exfat_get_root_entry_offset(&bd);
|
||||
if (root_clu_off < 0)
|
||||
goto close_fd_out;
|
||||
|
||||
if (flags == EXFAT_GET_VOLUME_LABEL)
|
||||
ret = exfat_show_volume_label(&bd, root_clu_off);
|
||||
else if (flags == EXFAT_SET_VOLUME_LABEL)
|
||||
ret = exfat_set_volume_label(&bd, argv[2], root_clu_off);
|
||||
}
|
||||
|
||||
close_fd_out:
|
||||
close(bd.dev_fd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
main.c (20.01.11)
|
||||
Prints or changes exFAT volume label.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <exfat.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char** pp;
|
||||
struct exfat ef;
|
||||
int rc = 0;
|
||||
|
||||
for (pp = argv + 1; *pp; pp++)
|
||||
if (strcmp(*pp, "-V") == 0)
|
||||
{
|
||||
printf("exfatlabel %s\n", VERSION);
|
||||
puts("Copyright (C) 2011-2018 Andrew Nayenko");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc != 2 && argc != 3)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-V] <device> [label]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argv[2])
|
||||
{
|
||||
if (exfat_mount(&ef, argv[1], "") != 0)
|
||||
return 1;
|
||||
rc = (exfat_set_label(&ef, argv[2]) != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exfat_mount(&ef, argv[1], "ro") != 0)
|
||||
return 1;
|
||||
puts(exfat_get_label(&ef));
|
||||
}
|
||||
|
||||
exfat_unmount(&ef);
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common
|
||||
noinst_LIBRARIES = libexfat.a
|
||||
|
||||
libexfat_a_SOURCES = libexfat.c
|
||||
+658
@@ -0,0 +1,658 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <wchar.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "exfat_ondisk.h"
|
||||
#include "libexfat.h"
|
||||
#include "version.h"
|
||||
|
||||
#define BITS_PER_LONG (sizeof(long) * CHAR_BIT)
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define BITOP_LE_SWIZZLE ((BITS_PER_LONG - 1) & ~0x7)
|
||||
#else
|
||||
#define BITOP_LE_SWIZZLE 0
|
||||
#endif
|
||||
|
||||
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
||||
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||
|
||||
unsigned int print_level = EXFAT_INFO;
|
||||
|
||||
static inline void set_bit(int nr, void *addr)
|
||||
{
|
||||
unsigned long mask = BIT_MASK(nr);
|
||||
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
|
||||
|
||||
*p |= mask;
|
||||
}
|
||||
|
||||
static inline void clear_bit(int nr, void *addr)
|
||||
{
|
||||
unsigned long mask = BIT_MASK(nr);
|
||||
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
|
||||
|
||||
*p &= ~mask;
|
||||
}
|
||||
|
||||
static inline void set_bit_le(int nr, void *addr)
|
||||
{
|
||||
set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
|
||||
}
|
||||
|
||||
static inline void clear_bit_le(int nr, void *addr)
|
||||
{
|
||||
clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
|
||||
}
|
||||
|
||||
void exfat_set_bit(struct exfat_blk_dev *bd, char *bitmap,
|
||||
unsigned int clu)
|
||||
{
|
||||
int b;
|
||||
|
||||
b = clu & ((bd->sector_size << 3) - 1);
|
||||
|
||||
set_bit_le(b, bitmap);
|
||||
}
|
||||
|
||||
void exfat_clear_bit(struct exfat_blk_dev *bd, char *bitmap,
|
||||
unsigned int clu)
|
||||
{
|
||||
int b;
|
||||
|
||||
b = clu & ((bd->sector_size << 3) - 1);
|
||||
|
||||
clear_bit_le(b, bitmap);
|
||||
}
|
||||
|
||||
wchar_t exfat_bad_char(wchar_t w)
|
||||
{
|
||||
return (w < 0x0020)
|
||||
|| (w == '*') || (w == '?') || (w == '<') || (w == '>')
|
||||
|| (w == '|') || (w == '"') || (w == ':') || (w == '/')
|
||||
|| (w == '\\');
|
||||
}
|
||||
|
||||
void boot_calc_checksum(unsigned char *sector, unsigned short size,
|
||||
bool is_boot_sec, __le32 *checksum)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
if (is_boot_sec) {
|
||||
for (index = 0; index < size; index++) {
|
||||
if ((index == 106) || (index == 107) || (index == 112))
|
||||
continue;
|
||||
*checksum = ((*checksum & 1) ? 0x80000000 : 0) +
|
||||
(*checksum >> 1) + sector[index];
|
||||
}
|
||||
} else {
|
||||
for (index = 0; index < size; index++) {
|
||||
*checksum = ((*checksum & 1) ? 0x80000000 : 0) +
|
||||
(*checksum >> 1) + sector[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void show_version(void)
|
||||
{
|
||||
printf("exfatprogs version : %s\n", EXFAT_PROGS_VERSION);
|
||||
}
|
||||
|
||||
static inline unsigned int sector_size_bits(unsigned int size)
|
||||
{
|
||||
unsigned int bits = 8;
|
||||
|
||||
do {
|
||||
bits++;
|
||||
size >>= 1;
|
||||
} while (size > 256);
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
static void exfat_set_default_cluster_size(struct exfat_blk_dev *bd,
|
||||
struct exfat_user_input *ui)
|
||||
{
|
||||
if (256 * MB >= bd->size)
|
||||
ui->cluster_size = 4 * KB;
|
||||
else if (32 * GB >= bd->size)
|
||||
ui->cluster_size = 32 * KB;
|
||||
else
|
||||
ui->cluster_size = 128 * KB;
|
||||
}
|
||||
|
||||
void init_user_input(struct exfat_user_input *ui)
|
||||
{
|
||||
memset(ui, 0, sizeof(struct exfat_user_input));
|
||||
ui->writeable = true;
|
||||
ui->quick = true;
|
||||
}
|
||||
|
||||
int exfat_get_blk_dev_info(struct exfat_user_input *ui,
|
||||
struct exfat_blk_dev *bd)
|
||||
{
|
||||
int fd, ret = -1;
|
||||
off_t blk_dev_size;
|
||||
struct stat st;
|
||||
unsigned long long blk_dev_offset = 0;
|
||||
|
||||
fd = open(ui->dev_name, ui->writeable ? O_RDWR|O_EXCL : O_RDONLY);
|
||||
if (fd < 0) {
|
||||
exfat_err("open failed : %s, %s\n", ui->dev_name,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
blk_dev_size = lseek(fd, 0, SEEK_END);
|
||||
if (blk_dev_size <= 0) {
|
||||
exfat_err("invalid block device size(%s)\n",
|
||||
ui->dev_name);
|
||||
ret = blk_dev_size;
|
||||
close(fd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)) {
|
||||
char pathname[sizeof("/sys/dev/block/4294967295:4294967295/start")];
|
||||
FILE *fp;
|
||||
|
||||
snprintf(pathname, sizeof(pathname), "/sys/dev/block/%u:%u/start",
|
||||
major(st.st_rdev), minor(st.st_rdev));
|
||||
fp = fopen(pathname, "r");
|
||||
if (fp != NULL) {
|
||||
if (fscanf(fp, "%llu", &blk_dev_offset) == 1) {
|
||||
/*
|
||||
* Linux kernel always reports partition offset
|
||||
* in 512-byte units, regardless of sector size
|
||||
*/
|
||||
blk_dev_offset <<= 9;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
bd->dev_fd = fd;
|
||||
bd->offset = blk_dev_offset;
|
||||
bd->size = blk_dev_size;
|
||||
if (!ui->cluster_size)
|
||||
exfat_set_default_cluster_size(bd, ui);
|
||||
|
||||
if (!ui->boundary_align)
|
||||
ui->boundary_align = DEFAULT_BOUNDARY_ALIGNMENT;
|
||||
|
||||
if (ioctl(fd, BLKSSZGET, &bd->sector_size) < 0)
|
||||
bd->sector_size = DEFAULT_SECTOR_SIZE;
|
||||
bd->sector_size_bits = sector_size_bits(bd->sector_size);
|
||||
bd->num_sectors = blk_dev_size / bd->sector_size;
|
||||
bd->num_clusters = blk_dev_size / ui->cluster_size;
|
||||
|
||||
exfat_debug("Block device name : %s\n", ui->dev_name);
|
||||
exfat_debug("Block device offset : %llu\n", bd->offset);
|
||||
exfat_debug("Block device size : %llu\n", bd->size);
|
||||
exfat_debug("Block sector size : %u\n", bd->sector_size);
|
||||
exfat_debug("Number of the sectors : %llu\n",
|
||||
bd->num_sectors);
|
||||
exfat_debug("Number of the clusters : %u\n",
|
||||
bd->num_clusters);
|
||||
|
||||
ret = 0;
|
||||
bd->dev_fd = fd;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t exfat_read(int fd, void *buf, size_t size, off_t offset)
|
||||
{
|
||||
return pread(fd, buf, size, offset);
|
||||
}
|
||||
|
||||
ssize_t exfat_write(int fd, void *buf, size_t size, off_t offset)
|
||||
{
|
||||
return pwrite(fd, buf, size, offset);
|
||||
}
|
||||
|
||||
size_t exfat_utf16_len(const __le16 *str, size_t max_size)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
while (le16_to_cpu(str[i]) && i < max_size)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
ssize_t exfat_utf16_enc(const char *in_str, __u16 *out_str, size_t out_size)
|
||||
{
|
||||
size_t mbs_len, out_len, i;
|
||||
wchar_t *wcs;
|
||||
|
||||
mbs_len = mbstowcs(NULL, in_str, 0);
|
||||
if (mbs_len == (size_t)-1) {
|
||||
if (errno == EINVAL || errno == EILSEQ)
|
||||
exfat_err("invalid character sequence in current locale\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
wcs = calloc(mbs_len+1, sizeof(wchar_t));
|
||||
if (!wcs)
|
||||
return -ENOMEM;
|
||||
|
||||
/* First convert multibyte char* string to wchar_t* string */
|
||||
if (mbstowcs(wcs, in_str, mbs_len+1) == (size_t)-1) {
|
||||
if (errno == EINVAL || errno == EILSEQ)
|
||||
exfat_err("invalid character sequence in current locale\n");
|
||||
free(wcs);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Convert wchar_t* string (sequence of code points) to UTF-16 string */
|
||||
for (i = 0, out_len = 0; i < mbs_len; i++) {
|
||||
if (2*(out_len+1) > out_size ||
|
||||
(wcs[i] >= 0x10000 && 2*(out_len+2) > out_size)) {
|
||||
exfat_err("input string is too long\n");
|
||||
free(wcs);
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
/* Encode code point above Plane0 as UTF-16 surrogate pair */
|
||||
if (wcs[i] >= 0x10000) {
|
||||
out_str[out_len++] =
|
||||
cpu_to_le16(((wcs[i] - 0x10000) >> 10) + 0xD800);
|
||||
wcs[i] = ((wcs[i] - 0x10000) & 0x3FF) + 0xDC00;
|
||||
}
|
||||
|
||||
out_str[out_len++] = cpu_to_le16(wcs[i]);
|
||||
}
|
||||
|
||||
free(wcs);
|
||||
return 2*out_len;
|
||||
}
|
||||
|
||||
ssize_t exfat_utf16_dec(const __u16 *in_str, size_t in_len,
|
||||
char *out_str, size_t out_size)
|
||||
{
|
||||
size_t wcs_len, out_len, c_len, i;
|
||||
char c_str[MB_LEN_MAX];
|
||||
wchar_t *wcs;
|
||||
mbstate_t ps;
|
||||
wchar_t w;
|
||||
|
||||
wcs = calloc(in_len/2+1, sizeof(wchar_t));
|
||||
if (!wcs)
|
||||
return -ENOMEM;
|
||||
|
||||
/* First convert UTF-16 string to wchar_t* string */
|
||||
for (i = 0, wcs_len = 0; i < in_len/2; i++, wcs_len++) {
|
||||
wcs[wcs_len] = le16_to_cpu(in_str[i]);
|
||||
/*
|
||||
* If wchar_t can store code point above Plane0
|
||||
* then unpack UTF-16 surrogate pair to code point
|
||||
*/
|
||||
#if WCHAR_MAX >= 0x10FFFF
|
||||
if (wcs[wcs_len] >= 0xD800 && wcs[wcs_len] <= 0xDBFF &&
|
||||
i+1 < in_len/2) {
|
||||
w = le16_to_cpu(in_str[i+1]);
|
||||
if (w >= 0xDC00 && w <= 0xDFFF) {
|
||||
wcs[wcs_len] = 0x10000 +
|
||||
((wcs[wcs_len] - 0xD800) << 10) +
|
||||
(w - 0xDC00);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
|
||||
/* And then convert wchar_t* string to multibyte char* string */
|
||||
for (i = 0, out_len = 0, c_len = 0; i <= wcs_len; i++) {
|
||||
c_len = wcrtomb(c_str, wcs[i], &ps);
|
||||
/*
|
||||
* If character is non-representable in current locale then
|
||||
* try to store it as Unicode replacement code point U+FFFD
|
||||
*/
|
||||
if (c_len == (size_t)-1 && errno == EILSEQ)
|
||||
c_len = wcrtomb(c_str, 0xFFFD, &ps);
|
||||
/* If U+FFFD is also non-representable, try question mark */
|
||||
if (c_len == (size_t)-1 && errno == EILSEQ)
|
||||
c_len = wcrtomb(c_str, L'?', &ps);
|
||||
/* If also (7bit) question mark fails then we cannot do more */
|
||||
if (c_len == (size_t)-1) {
|
||||
exfat_err("invalid UTF-16 sequence\n");
|
||||
free(wcs);
|
||||
return -errno;
|
||||
}
|
||||
if (out_len+c_len > out_size) {
|
||||
exfat_err("input string is too long\n");
|
||||
free(wcs);
|
||||
return -E2BIG;
|
||||
}
|
||||
memcpy(out_str+out_len, c_str, c_len);
|
||||
out_len += c_len;
|
||||
}
|
||||
|
||||
free(wcs);
|
||||
|
||||
/* Last iteration of above loop should have produced null byte */
|
||||
if (c_len == 0 || out_str[out_len-1] != 0) {
|
||||
exfat_err("invalid UTF-16 sequence\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return out_len-1;
|
||||
}
|
||||
|
||||
off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd)
|
||||
{
|
||||
struct pbr *bs;
|
||||
int nbytes;
|
||||
unsigned int cluster_size, sector_size;
|
||||
off_t root_clu_off;
|
||||
|
||||
bs = (struct pbr *)malloc(EXFAT_MAX_SECTOR_SIZE);
|
||||
if (!bs) {
|
||||
exfat_err("failed to allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nbytes = exfat_read(bd->dev_fd, bs, EXFAT_MAX_SECTOR_SIZE, 0);
|
||||
if (nbytes != EXFAT_MAX_SECTOR_SIZE) {
|
||||
exfat_err("boot sector read failed: %d\n", errno);
|
||||
free(bs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sector_size = 1 << bs->bsx.sect_size_bits;
|
||||
cluster_size = (1 << bs->bsx.sect_per_clus_bits) * sector_size;
|
||||
root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * sector_size +
|
||||
(le32_to_cpu(bs->bsx.root_cluster) - EXFAT_RESERVED_CLUSTERS) *
|
||||
cluster_size;
|
||||
free(bs);
|
||||
|
||||
return root_clu_off;
|
||||
}
|
||||
|
||||
char *exfat_conv_volume_label(struct exfat_dentry *vol_entry)
|
||||
{
|
||||
char *volume_label;
|
||||
__le16 disk_label[VOLUME_LABEL_MAX_LEN];
|
||||
|
||||
volume_label = malloc(VOLUME_LABEL_BUFFER_SIZE);
|
||||
if (!volume_label)
|
||||
return NULL;
|
||||
|
||||
memcpy(disk_label, vol_entry->vol_label, sizeof(disk_label));
|
||||
memset(volume_label, 0, VOLUME_LABEL_BUFFER_SIZE);
|
||||
if (exfat_utf16_dec(disk_label, vol_entry->vol_char_cnt*2,
|
||||
volume_label, VOLUME_LABEL_BUFFER_SIZE) < 0) {
|
||||
exfat_err("failed to decode volume label\n");
|
||||
free(volume_label);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return volume_label;
|
||||
}
|
||||
|
||||
int exfat_show_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off)
|
||||
{
|
||||
struct exfat_dentry *vol_entry;
|
||||
char *volume_label;
|
||||
int nbytes;
|
||||
|
||||
vol_entry = malloc(sizeof(struct exfat_dentry));
|
||||
if (!vol_entry) {
|
||||
exfat_err("failed to allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nbytes = exfat_read(bd->dev_fd, vol_entry,
|
||||
sizeof(struct exfat_dentry), root_clu_off);
|
||||
if (nbytes != sizeof(struct exfat_dentry)) {
|
||||
exfat_err("volume entry read failed: %d\n", errno);
|
||||
free(vol_entry);
|
||||
return -1;
|
||||
}
|
||||
|
||||
volume_label = exfat_conv_volume_label(vol_entry);
|
||||
if (!volume_label) {
|
||||
free(vol_entry);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
exfat_info("label: %s\n", volume_label);
|
||||
|
||||
free(volume_label);
|
||||
free(vol_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_set_volume_label(struct exfat_blk_dev *bd,
|
||||
char *label_input, off_t root_clu_off)
|
||||
{
|
||||
struct exfat_dentry vol;
|
||||
int nbytes;
|
||||
__u16 volume_label[VOLUME_LABEL_MAX_LEN];
|
||||
int volume_label_len;
|
||||
|
||||
volume_label_len = exfat_utf16_enc(label_input,
|
||||
volume_label, sizeof(volume_label));
|
||||
if (volume_label_len < 0) {
|
||||
exfat_err("failed to encode volume label\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vol.type = EXFAT_VOLUME;
|
||||
memset(vol.vol_label, 0, sizeof(vol.vol_label));
|
||||
memcpy(vol.vol_label, volume_label, volume_label_len);
|
||||
vol.vol_char_cnt = volume_label_len/2;
|
||||
|
||||
nbytes = exfat_write(bd->dev_fd, &vol, sizeof(struct exfat_dentry),
|
||||
root_clu_off);
|
||||
if (nbytes != sizeof(struct exfat_dentry)) {
|
||||
exfat_err("volume entry write failed: %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
fsync(bd->dev_fd);
|
||||
|
||||
exfat_info("new label: %s\n", label_input);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_read_sector(struct exfat_blk_dev *bd, void *buf, unsigned int sec_off)
|
||||
{
|
||||
int ret;
|
||||
unsigned long long offset = sec_off * bd->sector_size;
|
||||
|
||||
ret = pread(bd->dev_fd, buf, bd->sector_size, offset);
|
||||
if (ret < 0) {
|
||||
exfat_err("read failed, sec_off : %u\n", sec_off);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_write_sector(struct exfat_blk_dev *bd, void *buf,
|
||||
unsigned int sec_off)
|
||||
{
|
||||
int bytes;
|
||||
unsigned long long offset = sec_off * bd->sector_size;
|
||||
|
||||
bytes = pwrite(bd->dev_fd, buf, bd->sector_size, offset);
|
||||
if (bytes != (int)bd->sector_size) {
|
||||
exfat_err("write failed, sec_off : %u, bytes : %d\n", sec_off,
|
||||
bytes);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_write_checksum_sector(struct exfat_blk_dev *bd,
|
||||
unsigned int checksum, bool is_backup)
|
||||
{
|
||||
__le32 *checksum_buf;
|
||||
int ret = 0;
|
||||
unsigned int i;
|
||||
unsigned int sec_idx = CHECKSUM_SEC_IDX;
|
||||
|
||||
checksum_buf = malloc(bd->sector_size);
|
||||
if (!checksum_buf)
|
||||
return -1;
|
||||
|
||||
if (is_backup)
|
||||
sec_idx += BACKUP_BOOT_SEC_IDX;
|
||||
|
||||
for (i = 0; i < bd->sector_size / sizeof(int); i++)
|
||||
checksum_buf[i] = cpu_to_le32(checksum);
|
||||
|
||||
ret = exfat_write_sector(bd, checksum_buf, sec_idx);
|
||||
if (ret) {
|
||||
exfat_err("checksum sector write failed\n");
|
||||
goto free;
|
||||
}
|
||||
|
||||
free:
|
||||
free(checksum_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int exfat_show_volume_serial(int fd)
|
||||
{
|
||||
struct pbr *ppbr;
|
||||
int ret;
|
||||
|
||||
ppbr = malloc(EXFAT_MAX_SECTOR_SIZE);
|
||||
if (!ppbr) {
|
||||
exfat_err("Cannot allocate pbr: out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read main boot sector */
|
||||
ret = exfat_read(fd, (char *)ppbr, EXFAT_MAX_SECTOR_SIZE, 0);
|
||||
if (ret < 0) {
|
||||
exfat_err("main boot sector read failed\n");
|
||||
ret = -1;
|
||||
goto free_ppbr;
|
||||
}
|
||||
|
||||
exfat_info("volume serial : 0x%x\n", ppbr->bsx.vol_serial);
|
||||
|
||||
free_ppbr:
|
||||
free(ppbr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exfat_update_boot_checksum(struct exfat_blk_dev *bd, bool is_backup)
|
||||
{
|
||||
unsigned int checksum = 0;
|
||||
int ret, sec_idx, backup_sec_idx = 0;
|
||||
unsigned char *buf;
|
||||
|
||||
buf = malloc(bd->sector_size);
|
||||
if (!buf) {
|
||||
exfat_err("Cannot allocate pbr: out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_backup)
|
||||
backup_sec_idx = BACKUP_BOOT_SEC_IDX;
|
||||
|
||||
for (sec_idx = BOOT_SEC_IDX; sec_idx < CHECKSUM_SEC_IDX; sec_idx++) {
|
||||
bool is_boot_sec = false;
|
||||
|
||||
ret = exfat_read_sector(bd, buf, sec_idx + backup_sec_idx);
|
||||
if (ret < 0) {
|
||||
exfat_err("sector(%d) read failed\n", sec_idx);
|
||||
ret = -1;
|
||||
goto free_buf;
|
||||
}
|
||||
|
||||
if (sec_idx == BOOT_SEC_IDX)
|
||||
is_boot_sec = true;
|
||||
|
||||
boot_calc_checksum(buf, bd->sector_size, is_boot_sec,
|
||||
&checksum);
|
||||
}
|
||||
|
||||
ret = exfat_write_checksum_sector(bd, checksum, is_backup);
|
||||
|
||||
free_buf:
|
||||
free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int exfat_set_volume_serial(struct exfat_blk_dev *bd,
|
||||
struct exfat_user_input *ui)
|
||||
{
|
||||
int ret;
|
||||
struct pbr *ppbr;
|
||||
|
||||
ppbr = malloc(EXFAT_MAX_SECTOR_SIZE);
|
||||
if (!ppbr) {
|
||||
exfat_err("Cannot allocate pbr: out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read main boot sector */
|
||||
ret = exfat_read(bd->dev_fd, (char *)ppbr, EXFAT_MAX_SECTOR_SIZE,
|
||||
BOOT_SEC_IDX);
|
||||
if (ret < 0) {
|
||||
exfat_err("main boot sector read failed\n");
|
||||
ret = -1;
|
||||
goto free_ppbr;
|
||||
}
|
||||
|
||||
bd->sector_size = 1 << ppbr->bsx.sect_size_bits;
|
||||
ppbr->bsx.vol_serial = ui->volume_serial;
|
||||
|
||||
/* update main boot sector */
|
||||
ret = exfat_write_sector(bd, (char *)ppbr, BOOT_SEC_IDX);
|
||||
if (ret < 0) {
|
||||
exfat_err("main boot sector write failed\n");
|
||||
ret = -1;
|
||||
goto free_ppbr;
|
||||
}
|
||||
|
||||
/* update backup boot sector */
|
||||
ret = exfat_write_sector(bd, (char *)ppbr, BACKUP_BOOT_SEC_IDX);
|
||||
if (ret < 0) {
|
||||
exfat_err("backup boot sector write failed\n");
|
||||
ret = -1;
|
||||
goto free_ppbr;
|
||||
}
|
||||
|
||||
ret = exfat_update_boot_checksum(bd, 0);
|
||||
if (ret < 0) {
|
||||
exfat_err("main checksum update failed\n");
|
||||
goto free_ppbr;
|
||||
}
|
||||
|
||||
ret = exfat_update_boot_checksum(bd, 1);
|
||||
if (ret < 0)
|
||||
exfat_err("backup checksum update failed\n");
|
||||
free_ppbr:
|
||||
free(ppbr);
|
||||
|
||||
exfat_info("New volume serial : 0x%x\n", ui->volume_serial);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned int exfat_clus_to_blk_dev_off(struct exfat_blk_dev *bd,
|
||||
unsigned int clu_off_sectnr, unsigned int clu)
|
||||
{
|
||||
return clu_off_sectnr * bd->sector_size +
|
||||
(clu - EXFAT_RESERVED_CLUSTERS) * bd->cluster_size;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#
|
||||
# Makefile.am (30.03.15)
|
||||
# Automake source.
|
||||
#
|
||||
# Free exFAT implementation.
|
||||
# Copyright (C) 2010-2018 Andrew Nayenko
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
noinst_LIBRARIES = libexfat.a
|
||||
libexfat_a_SOURCES = \
|
||||
byteorder.h \
|
||||
cluster.c \
|
||||
compiler.h \
|
||||
exfat.h \
|
||||
exfatfs.h \
|
||||
io.c \
|
||||
log.c \
|
||||
lookup.c \
|
||||
mount.c \
|
||||
node.c \
|
||||
platform.h \
|
||||
repair.c \
|
||||
time.c \
|
||||
utf.c \
|
||||
utils.c
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
byteorder.h (12.01.10)
|
||||
Endianness stuff. exFAT uses little-endian byte order.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef BYTEORDER_H_INCLUDED
|
||||
#define BYTEORDER_H_INCLUDED
|
||||
|
||||
#include "platform.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct { uint16_t __u16; } le16_t;
|
||||
typedef struct { uint32_t __u32; } le32_t;
|
||||
typedef struct { uint64_t __u64; } le64_t;
|
||||
|
||||
#if EXFAT_BYTE_ORDER == EXFAT_LITTLE_ENDIAN
|
||||
|
||||
static inline uint16_t le16_to_cpu(le16_t v) { return v.__u16; }
|
||||
static inline uint32_t le32_to_cpu(le32_t v) { return v.__u32; }
|
||||
static inline uint64_t le64_to_cpu(le64_t v) { return v.__u64; }
|
||||
|
||||
static inline le16_t cpu_to_le16(uint16_t v) { le16_t t = {v}; return t; }
|
||||
static inline le32_t cpu_to_le32(uint32_t v) { le32_t t = {v}; return t; }
|
||||
static inline le64_t cpu_to_le64(uint64_t v) { le64_t t = {v}; return t; }
|
||||
|
||||
typedef size_t bitmap_t;
|
||||
|
||||
#elif EXFAT_BYTE_ORDER == EXFAT_BIG_ENDIAN
|
||||
|
||||
static inline uint16_t le16_to_cpu(le16_t v)
|
||||
{ return exfat_bswap16(v.__u16); }
|
||||
static inline uint32_t le32_to_cpu(le32_t v)
|
||||
{ return exfat_bswap32(v.__u32); }
|
||||
static inline uint64_t le64_to_cpu(le64_t v)
|
||||
{ return exfat_bswap64(v.__u64); }
|
||||
|
||||
static inline le16_t cpu_to_le16(uint16_t v)
|
||||
{ le16_t t = {exfat_bswap16(v)}; return t; }
|
||||
static inline le32_t cpu_to_le32(uint32_t v)
|
||||
{ le32_t t = {exfat_bswap32(v)}; return t; }
|
||||
static inline le64_t cpu_to_le64(uint64_t v)
|
||||
{ le64_t t = {exfat_bswap64(v)}; return t; }
|
||||
|
||||
typedef unsigned char bitmap_t;
|
||||
|
||||
#else
|
||||
#error Wow! You have a PDP machine?!
|
||||
#endif
|
||||
|
||||
#endif /* ifndef BYTEORDER_H_INCLUDED */
|
||||
@@ -1,491 +0,0 @@
|
||||
/*
|
||||
cluster.c (03.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/*
|
||||
* Sector to absolute offset.
|
||||
*/
|
||||
static off_t s2o(const struct exfat* ef, off_t sector)
|
||||
{
|
||||
return sector << ef->sb->sector_bits;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cluster to sector.
|
||||
*/
|
||||
static off_t c2s(const struct exfat* ef, cluster_t cluster)
|
||||
{
|
||||
if (cluster < EXFAT_FIRST_DATA_CLUSTER)
|
||||
exfat_bug("invalid cluster number %u", cluster);
|
||||
return le32_to_cpu(ef->sb->cluster_sector_start) +
|
||||
((off_t) (cluster - EXFAT_FIRST_DATA_CLUSTER) << ef->sb->spc_bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cluster to absolute offset.
|
||||
*/
|
||||
off_t exfat_c2o(const struct exfat* ef, cluster_t cluster)
|
||||
{
|
||||
return s2o(ef, c2s(ef, cluster));
|
||||
}
|
||||
|
||||
/*
|
||||
* Sector to cluster.
|
||||
*/
|
||||
static cluster_t s2c(const struct exfat* ef, off_t sector)
|
||||
{
|
||||
return ((sector - le32_to_cpu(ef->sb->cluster_sector_start)) >>
|
||||
ef->sb->spc_bits) + EXFAT_FIRST_DATA_CLUSTER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Size in bytes to size in clusters (rounded upwards).
|
||||
*/
|
||||
static uint32_t bytes2clusters(const struct exfat* ef, uint64_t bytes)
|
||||
{
|
||||
uint64_t cluster_size = CLUSTER_SIZE(*ef->sb);
|
||||
return DIV_ROUND_UP(bytes, cluster_size);
|
||||
}
|
||||
|
||||
cluster_t exfat_next_cluster(const struct exfat* ef,
|
||||
const struct exfat_node* node, cluster_t cluster)
|
||||
{
|
||||
le32_t next;
|
||||
off_t fat_offset;
|
||||
|
||||
if (cluster < EXFAT_FIRST_DATA_CLUSTER)
|
||||
exfat_bug("bad cluster 0x%x", cluster);
|
||||
|
||||
if (node->is_contiguous)
|
||||
return cluster + 1;
|
||||
fat_offset = s2o(ef, le32_to_cpu(ef->sb->fat_sector_start))
|
||||
+ cluster * sizeof(cluster_t);
|
||||
if (exfat_pread(ef->dev, &next, sizeof(next), fat_offset) < 0)
|
||||
return EXFAT_CLUSTER_BAD; /* the caller should handle this and print
|
||||
appropriate error message */
|
||||
return le32_to_cpu(next);
|
||||
}
|
||||
|
||||
cluster_t exfat_advance_cluster(const struct exfat* ef,
|
||||
struct exfat_node* node, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (node->fptr_index > count)
|
||||
{
|
||||
node->fptr_index = 0;
|
||||
node->fptr_cluster = node->start_cluster;
|
||||
}
|
||||
|
||||
for (i = node->fptr_index; i < count; i++)
|
||||
{
|
||||
node->fptr_cluster = exfat_next_cluster(ef, node, node->fptr_cluster);
|
||||
if (CLUSTER_INVALID(*ef->sb, node->fptr_cluster))
|
||||
break; /* the caller should handle this and print appropriate
|
||||
error message */
|
||||
}
|
||||
node->fptr_index = count;
|
||||
return node->fptr_cluster;
|
||||
}
|
||||
|
||||
static cluster_t find_bit_and_set(bitmap_t* bitmap, size_t start, size_t end)
|
||||
{
|
||||
const size_t start_index = start / sizeof(bitmap_t) / 8;
|
||||
const size_t end_index = DIV_ROUND_UP(end, sizeof(bitmap_t) * 8);
|
||||
size_t i;
|
||||
size_t start_bitindex;
|
||||
size_t end_bitindex;
|
||||
size_t c;
|
||||
|
||||
for (i = start_index; i < end_index; i++)
|
||||
{
|
||||
if (bitmap[i] == (bitmap_t) ~((bitmap_t) 0))
|
||||
continue;
|
||||
start_bitindex = MAX(i * sizeof(bitmap_t) * 8, start);
|
||||
end_bitindex = MIN((i + 1) * sizeof(bitmap_t) * 8, end);
|
||||
for (c = start_bitindex; c < end_bitindex; c++)
|
||||
if (BMAP_GET(bitmap, c) == 0)
|
||||
{
|
||||
BMAP_SET(bitmap, c);
|
||||
return c + EXFAT_FIRST_DATA_CLUSTER;
|
||||
}
|
||||
}
|
||||
return EXFAT_CLUSTER_END;
|
||||
}
|
||||
|
||||
static int flush_nodes(struct exfat* ef, struct exfat_node* node)
|
||||
{
|
||||
struct exfat_node* p;
|
||||
|
||||
for (p = node->child; p != NULL; p = p->next)
|
||||
{
|
||||
int rc = flush_nodes(ef, p);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
return exfat_flush_node(ef, node);
|
||||
}
|
||||
|
||||
int exfat_flush_nodes(struct exfat* ef)
|
||||
{
|
||||
return flush_nodes(ef, ef->root);
|
||||
}
|
||||
|
||||
int exfat_flush(struct exfat* ef)
|
||||
{
|
||||
if (ef->cmap.dirty)
|
||||
{
|
||||
if (exfat_pwrite(ef->dev, ef->cmap.chunk,
|
||||
BMAP_SIZE(ef->cmap.chunk_size),
|
||||
exfat_c2o(ef, ef->cmap.start_cluster)) < 0)
|
||||
{
|
||||
exfat_error("failed to write clusters bitmap");
|
||||
return -EIO;
|
||||
}
|
||||
ef->cmap.dirty = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool set_next_cluster(const struct exfat* ef, bool contiguous,
|
||||
cluster_t current, cluster_t next)
|
||||
{
|
||||
off_t fat_offset;
|
||||
le32_t next_le32;
|
||||
|
||||
if (contiguous)
|
||||
return true;
|
||||
fat_offset = s2o(ef, le32_to_cpu(ef->sb->fat_sector_start))
|
||||
+ current * sizeof(cluster_t);
|
||||
next_le32 = cpu_to_le32(next);
|
||||
if (exfat_pwrite(ef->dev, &next_le32, sizeof(next_le32), fat_offset) < 0)
|
||||
{
|
||||
exfat_error("failed to write the next cluster %#x after %#x", next,
|
||||
current);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static cluster_t allocate_cluster(struct exfat* ef, cluster_t hint)
|
||||
{
|
||||
cluster_t cluster;
|
||||
|
||||
hint -= EXFAT_FIRST_DATA_CLUSTER;
|
||||
if (hint >= ef->cmap.chunk_size)
|
||||
hint = 0;
|
||||
|
||||
cluster = find_bit_and_set(ef->cmap.chunk, hint, ef->cmap.chunk_size);
|
||||
if (cluster == EXFAT_CLUSTER_END)
|
||||
cluster = find_bit_and_set(ef->cmap.chunk, 0, hint);
|
||||
if (cluster == EXFAT_CLUSTER_END)
|
||||
{
|
||||
exfat_error("no free space left");
|
||||
return EXFAT_CLUSTER_END;
|
||||
}
|
||||
|
||||
ef->cmap.dirty = true;
|
||||
return cluster;
|
||||
}
|
||||
|
||||
static void free_cluster(struct exfat* ef, cluster_t cluster)
|
||||
{
|
||||
if (cluster - EXFAT_FIRST_DATA_CLUSTER >= ef->cmap.size)
|
||||
exfat_bug("caller must check cluster validity (%#x, %#x)", cluster,
|
||||
ef->cmap.size);
|
||||
|
||||
BMAP_CLR(ef->cmap.chunk, cluster - EXFAT_FIRST_DATA_CLUSTER);
|
||||
ef->cmap.dirty = true;
|
||||
}
|
||||
|
||||
static bool make_noncontiguous(const struct exfat* ef, cluster_t first,
|
||||
cluster_t last)
|
||||
{
|
||||
cluster_t c;
|
||||
|
||||
for (c = first; c < last; c++)
|
||||
if (!set_next_cluster(ef, false, c, c + 1))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int shrink_file(struct exfat* ef, struct exfat_node* node,
|
||||
uint32_t current, uint32_t difference);
|
||||
|
||||
static int grow_file(struct exfat* ef, struct exfat_node* node,
|
||||
uint32_t current, uint32_t difference)
|
||||
{
|
||||
cluster_t previous;
|
||||
cluster_t next;
|
||||
uint32_t allocated = 0;
|
||||
|
||||
if (difference == 0)
|
||||
exfat_bug("zero clusters count passed");
|
||||
|
||||
if (node->start_cluster != EXFAT_CLUSTER_FREE)
|
||||
{
|
||||
/* get the last cluster of the file */
|
||||
previous = exfat_advance_cluster(ef, node, current - 1);
|
||||
if (CLUSTER_INVALID(*ef->sb, previous))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while growing", previous);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node->fptr_index != 0)
|
||||
exfat_bug("non-zero pointer index (%u)", node->fptr_index);
|
||||
/* file does not have clusters (i.e. is empty), allocate
|
||||
the first one for it */
|
||||
previous = allocate_cluster(ef, 0);
|
||||
if (CLUSTER_INVALID(*ef->sb, previous))
|
||||
return -ENOSPC;
|
||||
node->fptr_cluster = node->start_cluster = previous;
|
||||
allocated = 1;
|
||||
/* file consists of only one cluster, so it's contiguous */
|
||||
node->is_contiguous = true;
|
||||
}
|
||||
|
||||
while (allocated < difference)
|
||||
{
|
||||
next = allocate_cluster(ef, previous + 1);
|
||||
if (CLUSTER_INVALID(*ef->sb, next))
|
||||
{
|
||||
if (allocated != 0)
|
||||
shrink_file(ef, node, current + allocated, allocated);
|
||||
return -ENOSPC;
|
||||
}
|
||||
if (next != previous + 1 && node->is_contiguous)
|
||||
{
|
||||
/* it's a pity, but we are not able to keep the file contiguous
|
||||
anymore */
|
||||
if (!make_noncontiguous(ef, node->start_cluster, previous))
|
||||
return -EIO;
|
||||
node->is_contiguous = false;
|
||||
node->is_dirty = true;
|
||||
}
|
||||
if (!set_next_cluster(ef, node->is_contiguous, previous, next))
|
||||
return -EIO;
|
||||
previous = next;
|
||||
allocated++;
|
||||
}
|
||||
|
||||
if (!set_next_cluster(ef, node->is_contiguous, previous,
|
||||
EXFAT_CLUSTER_END))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shrink_file(struct exfat* ef, struct exfat_node* node,
|
||||
uint32_t current, uint32_t difference)
|
||||
{
|
||||
cluster_t previous;
|
||||
cluster_t next;
|
||||
|
||||
if (difference == 0)
|
||||
exfat_bug("zero difference passed");
|
||||
if (node->start_cluster == EXFAT_CLUSTER_FREE)
|
||||
exfat_bug("unable to shrink empty file (%u clusters)", current);
|
||||
if (current < difference)
|
||||
exfat_bug("file underflow (%u < %u)", current, difference);
|
||||
|
||||
/* crop the file */
|
||||
if (current > difference)
|
||||
{
|
||||
cluster_t last = exfat_advance_cluster(ef, node,
|
||||
current - difference - 1);
|
||||
if (CLUSTER_INVALID(*ef->sb, last))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while shrinking", last);
|
||||
return -EIO;
|
||||
}
|
||||
previous = exfat_next_cluster(ef, node, last);
|
||||
if (!set_next_cluster(ef, node->is_contiguous, last,
|
||||
EXFAT_CLUSTER_END))
|
||||
return -EIO;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous = node->start_cluster;
|
||||
node->start_cluster = EXFAT_CLUSTER_FREE;
|
||||
node->is_dirty = true;
|
||||
}
|
||||
node->fptr_index = 0;
|
||||
node->fptr_cluster = node->start_cluster;
|
||||
|
||||
/* free remaining clusters */
|
||||
while (difference--)
|
||||
{
|
||||
if (CLUSTER_INVALID(*ef->sb, previous))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while freeing after shrink",
|
||||
previous);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
next = exfat_next_cluster(ef, node, previous);
|
||||
if (!set_next_cluster(ef, node->is_contiguous, previous,
|
||||
EXFAT_CLUSTER_FREE))
|
||||
return -EIO;
|
||||
free_cluster(ef, previous);
|
||||
previous = next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool erase_raw(struct exfat* ef, size_t size, off_t offset)
|
||||
{
|
||||
if (exfat_pwrite(ef->dev, ef->zero_cluster, size, offset) < 0)
|
||||
{
|
||||
exfat_error("failed to erase %zu bytes at %"PRId64, size, offset);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int erase_range(struct exfat* ef, struct exfat_node* node,
|
||||
uint64_t begin, uint64_t end)
|
||||
{
|
||||
uint64_t cluster_boundary;
|
||||
cluster_t cluster;
|
||||
|
||||
if (begin >= end)
|
||||
return 0;
|
||||
|
||||
cluster_boundary = (begin | (CLUSTER_SIZE(*ef->sb) - 1)) + 1;
|
||||
cluster = exfat_advance_cluster(ef, node,
|
||||
begin / CLUSTER_SIZE(*ef->sb));
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while erasing", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
/* erase from the beginning to the closest cluster boundary */
|
||||
if (!erase_raw(ef, MIN(cluster_boundary, end) - begin,
|
||||
exfat_c2o(ef, cluster) + begin % CLUSTER_SIZE(*ef->sb)))
|
||||
return -EIO;
|
||||
/* erase whole clusters */
|
||||
while (cluster_boundary < end)
|
||||
{
|
||||
cluster = exfat_next_cluster(ef, node, cluster);
|
||||
/* the cluster cannot be invalid because we have just allocated it */
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
exfat_bug("invalid cluster 0x%x after allocation", cluster);
|
||||
if (!erase_raw(ef, CLUSTER_SIZE(*ef->sb), exfat_c2o(ef, cluster)))
|
||||
return -EIO;
|
||||
cluster_boundary += CLUSTER_SIZE(*ef->sb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size,
|
||||
bool erase)
|
||||
{
|
||||
uint32_t c1 = bytes2clusters(ef, node->size);
|
||||
uint32_t c2 = bytes2clusters(ef, size);
|
||||
int rc = 0;
|
||||
|
||||
if (node->references == 0 && node->parent)
|
||||
exfat_bug("no references, node changes can be lost");
|
||||
|
||||
if (node->size == size)
|
||||
return 0;
|
||||
|
||||
if (c1 < c2)
|
||||
rc = grow_file(ef, node, c1, c2 - c1);
|
||||
else if (c1 > c2)
|
||||
rc = shrink_file(ef, node, c1, c1 - c2);
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (erase)
|
||||
{
|
||||
rc = erase_range(ef, node, node->size, size);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
exfat_update_mtime(node);
|
||||
node->size = size;
|
||||
node->is_dirty = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t exfat_count_free_clusters(const struct exfat* ef)
|
||||
{
|
||||
uint32_t free_clusters = 0;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < ef->cmap.size; i++)
|
||||
if (BMAP_GET(ef->cmap.chunk, i) == 0)
|
||||
free_clusters++;
|
||||
return free_clusters;
|
||||
}
|
||||
|
||||
static int find_used_clusters(const struct exfat* ef,
|
||||
cluster_t* a, cluster_t* b)
|
||||
{
|
||||
const cluster_t end = le32_to_cpu(ef->sb->cluster_count);
|
||||
|
||||
/* find first used cluster */
|
||||
for (*a = *b + 1; *a < end; (*a)++)
|
||||
if (BMAP_GET(ef->cmap.chunk, *a - EXFAT_FIRST_DATA_CLUSTER))
|
||||
break;
|
||||
if (*a >= end)
|
||||
return 1;
|
||||
|
||||
/* find last contiguous used cluster */
|
||||
for (*b = *a; *b < end; (*b)++)
|
||||
if (BMAP_GET(ef->cmap.chunk, *b - EXFAT_FIRST_DATA_CLUSTER) == 0)
|
||||
{
|
||||
(*b)--;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_find_used_sectors(const struct exfat* ef, off_t* a, off_t* b)
|
||||
{
|
||||
cluster_t ca, cb;
|
||||
|
||||
if (*a == 0 && *b == 0)
|
||||
ca = cb = EXFAT_FIRST_DATA_CLUSTER - 1;
|
||||
else
|
||||
{
|
||||
ca = s2c(ef, *a);
|
||||
cb = s2c(ef, *b);
|
||||
}
|
||||
if (find_used_clusters(ef, &ca, &cb) != 0)
|
||||
return 1;
|
||||
if (*a != 0 || *b != 0)
|
||||
*a = c2s(ef, ca);
|
||||
*b = c2s(ef, cb) + (CLUSTER_SIZE(*ef->sb) - 1) / SECTOR_SIZE(*ef->sb);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
compiler.h (09.06.13)
|
||||
Compiler-specific definitions. Note that unknown compiler is not a
|
||||
showstopper.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef COMPILER_H_INCLUDED
|
||||
#define COMPILER_H_INCLUDED
|
||||
|
||||
#if __STDC_VERSION__ < 199901L
|
||||
#error C99-compliant compiler is required
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
#define PRINTF __attribute__((format(printf, 1, 2)))
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#define PACKED __attribute__((packed))
|
||||
#define UNUSED __attribute__((unused))
|
||||
#if __has_extension(c_static_assert)
|
||||
#define USE_C11_STATIC_ASSERT
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
#define PRINTF __attribute__((format(printf, 1, 2)))
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#define PACKED __attribute__((packed))
|
||||
#define UNUSED __attribute__((unused))
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#define USE_C11_STATIC_ASSERT
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define PRINTF
|
||||
#define NORETURN
|
||||
#define PACKED
|
||||
#define UNUSED
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_C11_STATIC_ASSERT
|
||||
#define STATIC_ASSERT(cond) _Static_assert(cond, #cond)
|
||||
#else
|
||||
#define CONCAT2(a, b) a ## b
|
||||
#define CONCAT1(a, b) CONCAT2(a, b)
|
||||
#define STATIC_ASSERT(cond) \
|
||||
extern void CONCAT1(static_assert, __LINE__)(int x[(cond) ? 1 : -1])
|
||||
#endif
|
||||
|
||||
#endif /* ifndef COMPILER_H_INCLUDED */
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/* libexfat/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "exfat"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "relan@users.noreply.github.com"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "Free exFAT implementation"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "Free exFAT implementation 1.3.0"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "exfat"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL "https://github.com/relan/exfat"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.3.0"
|
||||
|
||||
/* Define if block devices are not supported. */
|
||||
/* #undef USE_UBLIO */
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "1.3.0"
|
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* Enable vsyslog(). */
|
||||
#define _DEFAULT_SOURCE /**/
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
/* #undef _FILE_OFFSET_BITS */
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
/* #undef _LARGE_FILES */
|
||||
|
||||
/* Enable pread() and pwrite(). */
|
||||
#define _XOPEN_SOURCE 500
|
||||
#endif
|
||||
@@ -1,247 +0,0 @@
|
||||
/*
|
||||
exfat.h (29.08.09)
|
||||
Definitions of structures and constants used in exFAT file system
|
||||
implementation.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef EXFAT_H_INCLUDED
|
||||
#define EXFAT_H_INCLUDED
|
||||
|
||||
#ifndef ANDROID
|
||||
/* Android.bp is used instead of autotools when targeting Android */
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "compiler.h"
|
||||
#include "exfatfs.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define EXFAT_NAME_MAX 255
|
||||
/* UTF-16 encodes code points up to U+FFFF as single 16-bit code units.
|
||||
UTF-8 uses up to 3 bytes (i.e. 8-bit code units) to encode code points
|
||||
up to U+FFFF. One additional character is for null terminator. */
|
||||
#define EXFAT_UTF8_NAME_BUFFER_MAX (EXFAT_NAME_MAX * 3 + 1)
|
||||
#define EXFAT_UTF8_ENAME_BUFFER_MAX (EXFAT_ENAME_MAX * 3 + 1)
|
||||
|
||||
#define SECTOR_SIZE(sb) (1 << (sb).sector_bits)
|
||||
#define CLUSTER_SIZE(sb) (SECTOR_SIZE(sb) << (sb).spc_bits)
|
||||
#define CLUSTER_INVALID(sb, c) ((c) < EXFAT_FIRST_DATA_CLUSTER || \
|
||||
(c) - EXFAT_FIRST_DATA_CLUSTER >= le32_to_cpu((sb).cluster_count))
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define DIV_ROUND_UP(x, d) (((x) + (d) - 1) / (d))
|
||||
#define ROUND_UP(x, d) (DIV_ROUND_UP(x, d) * (d))
|
||||
|
||||
#define BMAP_SIZE(count) (ROUND_UP(count, sizeof(bitmap_t) * 8) / 8)
|
||||
#define BMAP_BLOCK(index) ((index) / sizeof(bitmap_t) / 8)
|
||||
#define BMAP_MASK(index) ((bitmap_t) 1 << ((index) % (sizeof(bitmap_t) * 8)))
|
||||
#define BMAP_GET(bitmap, index) \
|
||||
((bitmap)[BMAP_BLOCK(index)] & BMAP_MASK(index))
|
||||
#define BMAP_SET(bitmap, index) \
|
||||
((bitmap)[BMAP_BLOCK(index)] |= BMAP_MASK(index))
|
||||
#define BMAP_CLR(bitmap, index) \
|
||||
((bitmap)[BMAP_BLOCK(index)] &= ~BMAP_MASK(index))
|
||||
|
||||
#define EXFAT_REPAIR(hook, ef, ...) \
|
||||
(exfat_ask_to_fix(ef) && exfat_fix_ ## hook(ef, __VA_ARGS__))
|
||||
|
||||
/* The size of off_t type must be 64 bits. File systems larger than 2 GB will
|
||||
be corrupted with 32-bit off_t. */
|
||||
STATIC_ASSERT(sizeof(off_t) == 8);
|
||||
|
||||
struct exfat_node
|
||||
{
|
||||
struct exfat_node* parent;
|
||||
struct exfat_node* child;
|
||||
struct exfat_node* next;
|
||||
struct exfat_node* prev;
|
||||
|
||||
int references;
|
||||
uint32_t fptr_index;
|
||||
cluster_t fptr_cluster;
|
||||
off_t entry_offset;
|
||||
cluster_t start_cluster;
|
||||
uint16_t attrib;
|
||||
uint8_t continuations;
|
||||
bool is_contiguous : 1;
|
||||
bool is_cached : 1;
|
||||
bool is_dirty : 1;
|
||||
bool is_unlinked : 1;
|
||||
uint64_t size;
|
||||
time_t mtime, atime;
|
||||
le16_t name[EXFAT_NAME_MAX + 1];
|
||||
};
|
||||
|
||||
enum exfat_mode
|
||||
{
|
||||
EXFAT_MODE_RO,
|
||||
EXFAT_MODE_RW,
|
||||
EXFAT_MODE_ANY,
|
||||
};
|
||||
|
||||
struct exfat_dev;
|
||||
|
||||
struct exfat
|
||||
{
|
||||
struct exfat_dev* dev;
|
||||
struct exfat_super_block* sb;
|
||||
uint16_t* upcase;
|
||||
struct exfat_node* root;
|
||||
struct
|
||||
{
|
||||
cluster_t start_cluster;
|
||||
uint32_t size; /* in bits */
|
||||
bitmap_t* chunk;
|
||||
uint32_t chunk_size; /* in bits */
|
||||
bool dirty;
|
||||
}
|
||||
cmap;
|
||||
char label[EXFAT_UTF8_ENAME_BUFFER_MAX];
|
||||
void* zero_cluster;
|
||||
int dmask, fmask;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
int ro;
|
||||
bool noatime;
|
||||
enum { EXFAT_REPAIR_NO, EXFAT_REPAIR_ASK, EXFAT_REPAIR_YES } repair;
|
||||
};
|
||||
|
||||
/* in-core nodes iterator */
|
||||
struct exfat_iterator
|
||||
{
|
||||
struct exfat_node* parent;
|
||||
struct exfat_node* current;
|
||||
};
|
||||
|
||||
struct exfat_human_bytes
|
||||
{
|
||||
uint64_t value;
|
||||
const char* unit;
|
||||
};
|
||||
|
||||
extern int exfat_errors;
|
||||
extern int exfat_errors_fixed;
|
||||
|
||||
void exfat_bug(const char* format, ...) PRINTF NORETURN;
|
||||
void exfat_error(const char* format, ...) PRINTF;
|
||||
void exfat_warn(const char* format, ...) PRINTF;
|
||||
void exfat_debug(const char* format, ...) PRINTF;
|
||||
|
||||
struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode);
|
||||
int exfat_close(struct exfat_dev* dev);
|
||||
int exfat_fsync(struct exfat_dev* dev);
|
||||
enum exfat_mode exfat_get_mode(const struct exfat_dev* dev);
|
||||
off_t exfat_get_size(const struct exfat_dev* dev);
|
||||
off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence);
|
||||
ssize_t exfat_read(struct exfat_dev* dev, void* buffer, size_t size);
|
||||
ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size);
|
||||
ssize_t exfat_pread(struct exfat_dev* dev, void* buffer, size_t size,
|
||||
off_t offset);
|
||||
ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size,
|
||||
off_t offset);
|
||||
ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
|
||||
void* buffer, size_t size, off_t offset);
|
||||
ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
|
||||
const void* buffer, size_t size, off_t offset);
|
||||
|
||||
int exfat_opendir(struct exfat* ef, struct exfat_node* dir,
|
||||
struct exfat_iterator* it);
|
||||
void exfat_closedir(struct exfat* ef, struct exfat_iterator* it);
|
||||
struct exfat_node* exfat_readdir(struct exfat_iterator* it);
|
||||
int exfat_lookup(struct exfat* ef, struct exfat_node** node,
|
||||
const char* path);
|
||||
int exfat_split(struct exfat* ef, struct exfat_node** parent,
|
||||
struct exfat_node** node, le16_t* name, const char* path);
|
||||
|
||||
off_t exfat_c2o(const struct exfat* ef, cluster_t cluster);
|
||||
cluster_t exfat_next_cluster(const struct exfat* ef,
|
||||
const struct exfat_node* node, cluster_t cluster);
|
||||
cluster_t exfat_advance_cluster(const struct exfat* ef,
|
||||
struct exfat_node* node, uint32_t count);
|
||||
int exfat_flush_nodes(struct exfat* ef);
|
||||
int exfat_flush(struct exfat* ef);
|
||||
int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size,
|
||||
bool erase);
|
||||
uint32_t exfat_count_free_clusters(const struct exfat* ef);
|
||||
int exfat_find_used_sectors(const struct exfat* ef, off_t* a, off_t* b);
|
||||
|
||||
void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
|
||||
struct stat* stbuf);
|
||||
void exfat_get_name(const struct exfat_node* node,
|
||||
char buffer[EXFAT_UTF8_NAME_BUFFER_MAX]);
|
||||
uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry);
|
||||
uint16_t exfat_add_checksum(const void* entry, uint16_t sum);
|
||||
le16_t exfat_calc_checksum(const struct exfat_entry* entries, int n);
|
||||
uint32_t exfat_vbr_start_checksum(const void* sector, size_t size);
|
||||
uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum);
|
||||
le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name,
|
||||
size_t length);
|
||||
void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb);
|
||||
void exfat_print_info(const struct exfat_super_block* sb,
|
||||
uint32_t free_clusters);
|
||||
bool exfat_match_option(const char* options, const char* option_name);
|
||||
|
||||
int exfat_utf16_to_utf8(char* output, const le16_t* input, size_t outsize,
|
||||
size_t insize);
|
||||
int exfat_utf8_to_utf16(le16_t* output, const char* input, size_t outsize,
|
||||
size_t insize);
|
||||
size_t exfat_utf16_length(const le16_t* str);
|
||||
|
||||
struct exfat_node* exfat_get_node(struct exfat_node* node);
|
||||
void exfat_put_node(struct exfat* ef, struct exfat_node* node);
|
||||
int exfat_cleanup_node(struct exfat* ef, struct exfat_node* node);
|
||||
int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir);
|
||||
void exfat_reset_cache(struct exfat* ef);
|
||||
int exfat_flush_node(struct exfat* ef, struct exfat_node* node);
|
||||
int exfat_unlink(struct exfat* ef, struct exfat_node* node);
|
||||
int exfat_rmdir(struct exfat* ef, struct exfat_node* node);
|
||||
int exfat_mknod(struct exfat* ef, const char* path);
|
||||
int exfat_mkdir(struct exfat* ef, const char* path);
|
||||
int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path);
|
||||
void exfat_utimes(struct exfat_node* node, const struct timespec tv[2]);
|
||||
void exfat_update_atime(struct exfat_node* node);
|
||||
void exfat_update_mtime(struct exfat_node* node);
|
||||
const char* exfat_get_label(struct exfat* ef);
|
||||
int exfat_set_label(struct exfat* ef, const char* label);
|
||||
|
||||
int exfat_soil_super_block(const struct exfat* ef);
|
||||
int exfat_mount(struct exfat* ef, const char* spec, const char* options);
|
||||
void exfat_unmount(struct exfat* ef);
|
||||
|
||||
time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec,
|
||||
uint8_t tzoffset);
|
||||
void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
|
||||
uint8_t* centisec, uint8_t* tzoffset);
|
||||
void exfat_tzset(void);
|
||||
|
||||
bool exfat_ask_to_fix(const struct exfat* ef);
|
||||
bool exfat_fix_invalid_vbr_checksum(const struct exfat* ef, void* sector,
|
||||
uint32_t vbr_checksum);
|
||||
bool exfat_fix_invalid_node_checksum(const struct exfat* ef,
|
||||
struct exfat_node* node);
|
||||
bool exfat_fix_unknown_entry(struct exfat* ef, struct exfat_node* dir,
|
||||
const struct exfat_entry* entry, off_t offset);
|
||||
|
||||
#endif /* ifndef EXFAT_H_INCLUDED */
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
exfatfs.h (29.08.09)
|
||||
Definitions of structures and constants used in exFAT file system.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef EXFATFS_H_INCLUDED
|
||||
#define EXFATFS_H_INCLUDED
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "compiler.h"
|
||||
|
||||
typedef uint32_t cluster_t; /* cluster number */
|
||||
|
||||
#define EXFAT_FIRST_DATA_CLUSTER 2
|
||||
#define EXFAT_LAST_DATA_CLUSTER 0xfffffff6
|
||||
|
||||
#define EXFAT_CLUSTER_FREE 0 /* free cluster */
|
||||
#define EXFAT_CLUSTER_BAD 0xfffffff7 /* cluster contains bad sector */
|
||||
#define EXFAT_CLUSTER_END 0xffffffff /* final cluster of file or directory */
|
||||
|
||||
#define EXFAT_STATE_MOUNTED 2
|
||||
|
||||
struct exfat_super_block
|
||||
{
|
||||
uint8_t jump[3]; /* 0x00 jmp and nop instructions */
|
||||
uint8_t oem_name[8]; /* 0x03 "EXFAT " */
|
||||
uint8_t __unused1[53]; /* 0x0B always 0 */
|
||||
le64_t sector_start; /* 0x40 partition first sector */
|
||||
le64_t sector_count; /* 0x48 partition sectors count */
|
||||
le32_t fat_sector_start; /* 0x50 FAT first sector */
|
||||
le32_t fat_sector_count; /* 0x54 FAT sectors count */
|
||||
le32_t cluster_sector_start; /* 0x58 first cluster sector */
|
||||
le32_t cluster_count; /* 0x5C total clusters count */
|
||||
le32_t rootdir_cluster; /* 0x60 first cluster of the root dir */
|
||||
le32_t volume_serial; /* 0x64 volume serial number */
|
||||
struct /* 0x68 FS version */
|
||||
{
|
||||
uint8_t minor;
|
||||
uint8_t major;
|
||||
}
|
||||
version;
|
||||
le16_t volume_state; /* 0x6A volume state flags */
|
||||
uint8_t sector_bits; /* 0x6C sector size as (1 << n) */
|
||||
uint8_t spc_bits; /* 0x6D sectors per cluster as (1 << n) */
|
||||
uint8_t fat_count; /* 0x6E always 1 */
|
||||
uint8_t drive_no; /* 0x6F always 0x80 */
|
||||
uint8_t allocated_percent; /* 0x70 percentage of allocated space */
|
||||
uint8_t __unused2[397]; /* 0x71 always 0 */
|
||||
le16_t boot_signature; /* the value of 0xAA55 */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_super_block) == 512);
|
||||
|
||||
#define EXFAT_ENTRY_VALID 0x80
|
||||
#define EXFAT_ENTRY_CONTINUED 0x40
|
||||
#define EXFAT_ENTRY_OPTIONAL 0x20
|
||||
|
||||
#define EXFAT_ENTRY_BITMAP (0x01 | EXFAT_ENTRY_VALID)
|
||||
#define EXFAT_ENTRY_UPCASE (0x02 | EXFAT_ENTRY_VALID)
|
||||
#define EXFAT_ENTRY_LABEL (0x03 | EXFAT_ENTRY_VALID)
|
||||
#define EXFAT_ENTRY_FILE (0x05 | EXFAT_ENTRY_VALID)
|
||||
#define EXFAT_ENTRY_FILE_INFO (0x00 | EXFAT_ENTRY_VALID | EXFAT_ENTRY_CONTINUED)
|
||||
#define EXFAT_ENTRY_FILE_NAME (0x01 | EXFAT_ENTRY_VALID | EXFAT_ENTRY_CONTINUED)
|
||||
#define EXFAT_ENTRY_FILE_TAIL (0x00 | EXFAT_ENTRY_VALID \
|
||||
| EXFAT_ENTRY_CONTINUED \
|
||||
| EXFAT_ENTRY_OPTIONAL)
|
||||
|
||||
struct exfat_entry /* common container for all entries */
|
||||
{
|
||||
uint8_t type; /* any of EXFAT_ENTRY_xxx */
|
||||
uint8_t data[31];
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry) == 32);
|
||||
|
||||
#define EXFAT_ENAME_MAX 15
|
||||
|
||||
struct exfat_entry_bitmap /* allocated clusters bitmap */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_BITMAP */
|
||||
uint8_t __unknown1[19];
|
||||
le32_t start_cluster;
|
||||
le64_t size; /* in bytes */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_bitmap) == 32);
|
||||
|
||||
#define EXFAT_UPCASE_CHARS 0x10000
|
||||
|
||||
struct exfat_entry_upcase /* upper case translation table */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_UPCASE */
|
||||
uint8_t __unknown1[3];
|
||||
le32_t checksum;
|
||||
uint8_t __unknown2[12];
|
||||
le32_t start_cluster;
|
||||
le64_t size; /* in bytes */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_upcase) == 32);
|
||||
|
||||
struct exfat_entry_label /* volume label */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_LABEL */
|
||||
uint8_t length; /* number of characters */
|
||||
le16_t name[EXFAT_ENAME_MAX]; /* in UTF-16LE */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_label) == 32);
|
||||
|
||||
#define EXFAT_ATTRIB_RO 0x01
|
||||
#define EXFAT_ATTRIB_HIDDEN 0x02
|
||||
#define EXFAT_ATTRIB_SYSTEM 0x04
|
||||
#define EXFAT_ATTRIB_VOLUME 0x08
|
||||
#define EXFAT_ATTRIB_DIR 0x10
|
||||
#define EXFAT_ATTRIB_ARCH 0x20
|
||||
|
||||
struct exfat_entry_meta1 /* file or directory info (part 1) */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_FILE */
|
||||
uint8_t continuations;
|
||||
le16_t checksum;
|
||||
le16_t attrib; /* combination of EXFAT_ATTRIB_xxx */
|
||||
le16_t __unknown1;
|
||||
le16_t crtime, crdate; /* creation date and time */
|
||||
le16_t mtime, mdate; /* latest modification date and time */
|
||||
le16_t atime, adate; /* latest access date and time */
|
||||
uint8_t crtime_cs; /* creation time in cs (centiseconds) */
|
||||
uint8_t mtime_cs; /* latest modification time in cs */
|
||||
uint8_t crtime_tzo, mtime_tzo, atime_tzo; /* timezone offset encoded */
|
||||
uint8_t __unknown2[7];
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_meta1) == 32);
|
||||
|
||||
#define EXFAT_FLAG_ALWAYS1 (1u << 0)
|
||||
#define EXFAT_FLAG_CONTIGUOUS (1u << 1)
|
||||
|
||||
struct exfat_entry_meta2 /* file or directory info (part 2) */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_FILE_INFO */
|
||||
uint8_t flags; /* combination of EXFAT_FLAG_xxx */
|
||||
uint8_t __unknown1;
|
||||
uint8_t name_length;
|
||||
le16_t name_hash;
|
||||
le16_t __unknown2;
|
||||
le64_t valid_size; /* in bytes, less or equal to size */
|
||||
uint8_t __unknown3[4];
|
||||
le32_t start_cluster;
|
||||
le64_t size; /* in bytes */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_meta2) == 32);
|
||||
|
||||
struct exfat_entry_name /* file or directory name */
|
||||
{
|
||||
uint8_t type; /* EXFAT_ENTRY_FILE_NAME */
|
||||
uint8_t __unknown;
|
||||
le16_t name[EXFAT_ENAME_MAX]; /* in UTF-16LE */
|
||||
}
|
||||
PACKED;
|
||||
STATIC_ASSERT(sizeof(struct exfat_entry_name) == 32);
|
||||
|
||||
#endif /* ifndef EXFATFS_H_INCLUDED */
|
||||
-497
@@ -1,497 +0,0 @@
|
||||
/*
|
||||
io.c (02.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#if defined(__APPLE__)
|
||||
#include <sys/disk.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/dkio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#elif defined(__NetBSD__)
|
||||
#include <sys/ioctl.h>
|
||||
#elif __linux__
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
#ifdef USE_UBLIO
|
||||
#include <sys/uio.h>
|
||||
#include <ublio.h>
|
||||
#endif
|
||||
|
||||
struct exfat_dev
|
||||
{
|
||||
int fd;
|
||||
enum exfat_mode mode;
|
||||
off_t size; /* in bytes */
|
||||
#ifdef USE_UBLIO
|
||||
off_t pos;
|
||||
ublio_filehandle_t ufh;
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool is_open(int fd)
|
||||
{
|
||||
return fcntl(fd, F_GETFD) != -1;
|
||||
}
|
||||
|
||||
static int open_ro(const char* spec)
|
||||
{
|
||||
return open(spec, O_RDONLY);
|
||||
}
|
||||
|
||||
static int open_rw(const char* spec)
|
||||
{
|
||||
int fd = open(spec, O_RDWR);
|
||||
#ifdef __linux__
|
||||
int ro = 0;
|
||||
|
||||
/*
|
||||
This ioctl is needed because after "blockdev --setro" kernel still
|
||||
allows to open the device in read-write mode but fails writes.
|
||||
*/
|
||||
if (fd != -1 && ioctl(fd, BLKROGET, &ro) == 0 && ro)
|
||||
{
|
||||
close(fd);
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
|
||||
{
|
||||
struct exfat_dev* dev;
|
||||
struct stat stbuf;
|
||||
#ifdef USE_UBLIO
|
||||
struct ublio_param up;
|
||||
#endif
|
||||
|
||||
/* The system allocates file descriptors sequentially. If we have been
|
||||
started with stdin (0), stdout (1) or stderr (2) closed, the system
|
||||
will give us descriptor 0, 1 or 2 later when we open block device,
|
||||
FUSE communication pipe, etc. As a result, functions using stdin,
|
||||
stdout or stderr will actually work with a different thing and can
|
||||
corrupt it. Protect descriptors 0, 1 and 2 from such misuse. */
|
||||
while (!is_open(STDIN_FILENO)
|
||||
|| !is_open(STDOUT_FILENO)
|
||||
|| !is_open(STDERR_FILENO))
|
||||
{
|
||||
/* we don't need those descriptors, let them leak */
|
||||
if (open("/dev/null", O_RDWR) == -1)
|
||||
{
|
||||
exfat_error("failed to open /dev/null");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dev = malloc(sizeof(struct exfat_dev));
|
||||
if (dev == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate memory for device structure");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case EXFAT_MODE_RO:
|
||||
dev->fd = open_ro(spec);
|
||||
if (dev->fd == -1)
|
||||
{
|
||||
free(dev);
|
||||
exfat_error("failed to open '%s' in read-only mode: %s", spec,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
dev->mode = EXFAT_MODE_RO;
|
||||
break;
|
||||
case EXFAT_MODE_RW:
|
||||
dev->fd = open_rw(spec);
|
||||
if (dev->fd == -1)
|
||||
{
|
||||
free(dev);
|
||||
exfat_error("failed to open '%s' in read-write mode: %s", spec,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
dev->mode = EXFAT_MODE_RW;
|
||||
break;
|
||||
case EXFAT_MODE_ANY:
|
||||
dev->fd = open_rw(spec);
|
||||
if (dev->fd != -1)
|
||||
{
|
||||
dev->mode = EXFAT_MODE_RW;
|
||||
break;
|
||||
}
|
||||
dev->fd = open_ro(spec);
|
||||
if (dev->fd != -1)
|
||||
{
|
||||
dev->mode = EXFAT_MODE_RO;
|
||||
exfat_warn("'%s' is write-protected, mounting read-only", spec);
|
||||
break;
|
||||
}
|
||||
free(dev);
|
||||
exfat_error("failed to open '%s': %s", spec, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fstat(dev->fd, &stbuf) != 0)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to fstat '%s'", spec);
|
||||
return NULL;
|
||||
}
|
||||
if (!S_ISBLK(stbuf.st_mode) &&
|
||||
!S_ISCHR(stbuf.st_mode) &&
|
||||
!S_ISREG(stbuf.st_mode))
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("'%s' is neither a device, nor a regular file", spec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (!S_ISREG(stbuf.st_mode))
|
||||
{
|
||||
uint32_t block_size = 0;
|
||||
uint64_t blocks = 0;
|
||||
|
||||
if (ioctl(dev->fd, DKIOCGETBLOCKSIZE, &block_size) != 0)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to get block size");
|
||||
return NULL;
|
||||
}
|
||||
if (ioctl(dev->fd, DKIOCGETBLOCKCOUNT, &blocks) != 0)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to get blocks count");
|
||||
return NULL;
|
||||
}
|
||||
dev->size = blocks * block_size;
|
||||
}
|
||||
else
|
||||
#elif defined(__OpenBSD__)
|
||||
if (!S_ISREG(stbuf.st_mode))
|
||||
{
|
||||
struct disklabel lab;
|
||||
struct partition* pp;
|
||||
char* partition;
|
||||
|
||||
if (ioctl(dev->fd, DIOCGDINFO, &lab) == -1)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to get disklabel");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Don't need to check that partition letter is valid as we won't get
|
||||
this far otherwise. */
|
||||
partition = strchr(spec, '\0') - 1;
|
||||
pp = &(lab.d_partitions[*partition - 'a']);
|
||||
dev->size = DL_GETPSIZE(pp) * lab.d_secsize;
|
||||
|
||||
if (pp->p_fstype != FS_NTFS)
|
||||
exfat_warn("partition type is not 0x07 (NTFS/exFAT); "
|
||||
"you can fix this with fdisk(8)");
|
||||
}
|
||||
else
|
||||
#elif defined(__NetBSD__)
|
||||
if (!S_ISREG(stbuf.st_mode))
|
||||
{
|
||||
off_t size;
|
||||
|
||||
if (ioctl(dev->fd, DIOCGMEDIASIZE, &size) == -1)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to get media size");
|
||||
return NULL;
|
||||
}
|
||||
dev->size = size;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* works for Linux, FreeBSD, Solaris */
|
||||
dev->size = exfat_seek(dev, 0, SEEK_END);
|
||||
if (dev->size <= 0)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to get size of '%s'", spec);
|
||||
return NULL;
|
||||
}
|
||||
if (exfat_seek(dev, 0, SEEK_SET) == -1)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to seek to the beginning of '%s'", spec);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_UBLIO
|
||||
memset(&up, 0, sizeof(struct ublio_param));
|
||||
up.up_blocksize = 256 * 1024;
|
||||
up.up_items = 64;
|
||||
up.up_grace = 32;
|
||||
up.up_priv = &dev->fd;
|
||||
|
||||
dev->pos = 0;
|
||||
dev->ufh = ublio_open(&up);
|
||||
if (dev->ufh == NULL)
|
||||
{
|
||||
close(dev->fd);
|
||||
free(dev);
|
||||
exfat_error("failed to initialize ublio");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
int exfat_close(struct exfat_dev* dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#ifdef USE_UBLIO
|
||||
if (ublio_close(dev->ufh) != 0)
|
||||
{
|
||||
exfat_error("failed to close ublio");
|
||||
rc = -EIO;
|
||||
}
|
||||
#endif
|
||||
if (close(dev->fd) != 0)
|
||||
{
|
||||
exfat_error("failed to close device: %s", strerror(errno));
|
||||
rc = -EIO;
|
||||
}
|
||||
free(dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int exfat_fsync(struct exfat_dev* dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#ifdef USE_UBLIO
|
||||
if (ublio_fsync(dev->ufh) != 0)
|
||||
{
|
||||
exfat_error("ublio fsync failed");
|
||||
rc = -EIO;
|
||||
}
|
||||
#endif
|
||||
if (fsync(dev->fd) != 0)
|
||||
{
|
||||
exfat_error("fsync failed: %s", strerror(errno));
|
||||
rc = -EIO;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
enum exfat_mode exfat_get_mode(const struct exfat_dev* dev)
|
||||
{
|
||||
return dev->mode;
|
||||
}
|
||||
|
||||
off_t exfat_get_size(const struct exfat_dev* dev)
|
||||
{
|
||||
return dev->size;
|
||||
}
|
||||
|
||||
off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence)
|
||||
{
|
||||
#ifdef USE_UBLIO
|
||||
/* XXX SEEK_CUR will be handled incorrectly */
|
||||
return dev->pos = lseek(dev->fd, offset, whence);
|
||||
#else
|
||||
return lseek(dev->fd, offset, whence);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t exfat_read(struct exfat_dev* dev, void* buffer, size_t size)
|
||||
{
|
||||
#ifdef USE_UBLIO
|
||||
ssize_t result = ublio_pread(dev->ufh, buffer, size, dev->pos);
|
||||
if (result >= 0)
|
||||
dev->pos += size;
|
||||
return result;
|
||||
#else
|
||||
return read(dev->fd, buffer, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size)
|
||||
{
|
||||
#ifdef USE_UBLIO
|
||||
ssize_t result = ublio_pwrite(dev->ufh, (void*) buffer, size, dev->pos);
|
||||
if (result >= 0)
|
||||
dev->pos += size;
|
||||
return result;
|
||||
#else
|
||||
return write(dev->fd, buffer, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t exfat_pread(struct exfat_dev* dev, void* buffer, size_t size,
|
||||
off_t offset)
|
||||
{
|
||||
#ifdef USE_UBLIO
|
||||
return ublio_pread(dev->ufh, buffer, size, offset);
|
||||
#else
|
||||
return pread(dev->fd, buffer, size, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size,
|
||||
off_t offset)
|
||||
{
|
||||
#ifdef USE_UBLIO
|
||||
return ublio_pwrite(dev->ufh, (void*) buffer, size, offset);
|
||||
#else
|
||||
return pwrite(dev->fd, buffer, size, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
|
||||
void* buffer, size_t size, off_t offset)
|
||||
{
|
||||
uint64_t newsize = offset;
|
||||
cluster_t cluster;
|
||||
char* bufp = buffer;
|
||||
off_t lsize, loffset, remainder;
|
||||
|
||||
if (offset < 0)
|
||||
return -EINVAL;
|
||||
if (newsize >= node->size)
|
||||
return 0;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
cluster = exfat_advance_cluster(ef, node, newsize / CLUSTER_SIZE(*ef->sb));
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while reading", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
loffset = newsize % CLUSTER_SIZE(*ef->sb);
|
||||
remainder = MIN(size, node->size - newsize);
|
||||
while (remainder > 0)
|
||||
{
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while reading", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
|
||||
if (exfat_pread(ef->dev, bufp, lsize,
|
||||
exfat_c2o(ef, cluster) + loffset) < 0)
|
||||
{
|
||||
exfat_error("failed to read cluster %#x", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
bufp += lsize;
|
||||
loffset = 0;
|
||||
remainder -= lsize;
|
||||
cluster = exfat_next_cluster(ef, node, cluster);
|
||||
}
|
||||
if (!(node->attrib & EXFAT_ATTRIB_DIR) && !ef->ro && !ef->noatime)
|
||||
exfat_update_atime(node);
|
||||
return MIN(size, node->size - newsize) - remainder;
|
||||
}
|
||||
|
||||
ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
|
||||
const void* buffer, size_t size, off_t offset)
|
||||
{
|
||||
uint64_t newsize = offset;
|
||||
int rc;
|
||||
cluster_t cluster;
|
||||
const char* bufp = buffer;
|
||||
off_t lsize, loffset, remainder;
|
||||
|
||||
if (offset < 0)
|
||||
return -EINVAL;
|
||||
if (newsize > node->size)
|
||||
{
|
||||
rc = exfat_truncate(ef, node, newsize, true);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
if (newsize + size > node->size)
|
||||
{
|
||||
rc = exfat_truncate(ef, node, newsize + size, false);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
cluster = exfat_advance_cluster(ef, node, newsize / CLUSTER_SIZE(*ef->sb));
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while writing", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
loffset = newsize % CLUSTER_SIZE(*ef->sb);
|
||||
remainder = size;
|
||||
while (remainder > 0)
|
||||
{
|
||||
if (CLUSTER_INVALID(*ef->sb, cluster))
|
||||
{
|
||||
exfat_error("invalid cluster 0x%x while writing", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
|
||||
if (exfat_pwrite(ef->dev, bufp, lsize,
|
||||
exfat_c2o(ef, cluster) + loffset) < 0)
|
||||
{
|
||||
exfat_error("failed to write cluster %#x", cluster);
|
||||
return -EIO;
|
||||
}
|
||||
bufp += lsize;
|
||||
loffset = 0;
|
||||
remainder -= lsize;
|
||||
cluster = exfat_next_cluster(ef, node, cluster);
|
||||
}
|
||||
if (!(node->attrib & EXFAT_ATTRIB_DIR))
|
||||
/* directory's mtime should be updated by the caller only when it
|
||||
creates or removes something in this directory */
|
||||
exfat_update_mtime(node);
|
||||
return size - remainder;
|
||||
}
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
log.c (02.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <stdarg.h>
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#else
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
int exfat_errors;
|
||||
|
||||
/*
|
||||
* This message means an internal bug in exFAT implementation.
|
||||
*/
|
||||
void exfat_bug(const char* format, ...)
|
||||
{
|
||||
va_list ap, aq;
|
||||
|
||||
va_start(ap, format);
|
||||
va_copy(aq, ap);
|
||||
|
||||
fflush(stdout);
|
||||
fputs("BUG: ", stderr);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fputs(".\n", stderr);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
__android_log_vprint(ANDROID_LOG_FATAL, PACKAGE, format, aq);
|
||||
#else
|
||||
if (!isatty(STDERR_FILENO))
|
||||
vsyslog(LOG_CRIT, format, aq);
|
||||
#endif
|
||||
va_end(aq);
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* This message means an error in exFAT file system.
|
||||
*/
|
||||
void exfat_error(const char* format, ...)
|
||||
{
|
||||
va_list ap, aq;
|
||||
|
||||
exfat_errors++;
|
||||
va_start(ap, format);
|
||||
va_copy(aq, ap);
|
||||
|
||||
fflush(stdout);
|
||||
fputs("ERROR: ", stderr);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fputs(".\n", stderr);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
__android_log_vprint(ANDROID_LOG_ERROR, PACKAGE, format, aq);
|
||||
#else
|
||||
if (!isatty(STDERR_FILENO))
|
||||
vsyslog(LOG_ERR, format, aq);
|
||||
#endif
|
||||
va_end(aq);
|
||||
}
|
||||
|
||||
/*
|
||||
* This message means that there is something unexpected in exFAT file system
|
||||
* that can be a potential problem.
|
||||
*/
|
||||
void exfat_warn(const char* format, ...)
|
||||
{
|
||||
va_list ap, aq;
|
||||
|
||||
va_start(ap, format);
|
||||
va_copy(aq, ap);
|
||||
|
||||
fflush(stdout);
|
||||
fputs("WARN: ", stderr);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fputs(".\n", stderr);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
__android_log_vprint(ANDROID_LOG_WARN, PACKAGE, format, aq);
|
||||
#else
|
||||
if (!isatty(STDERR_FILENO))
|
||||
vsyslog(LOG_WARNING, format, aq);
|
||||
#endif
|
||||
va_end(aq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just debug message. Disabled by default.
|
||||
*/
|
||||
void exfat_debug(const char* format, ...)
|
||||
{
|
||||
va_list ap, aq;
|
||||
|
||||
va_start(ap, format);
|
||||
va_copy(aq, ap);
|
||||
|
||||
fflush(stdout);
|
||||
fputs("DEBUG: ", stderr);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fputs(".\n", stderr);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
__android_log_vprint(ANDROID_LOG_DEBUG, PACKAGE, format, aq);
|
||||
#else
|
||||
if (!isatty(STDERR_FILENO))
|
||||
vsyslog(LOG_DEBUG, format, aq);
|
||||
#endif
|
||||
va_end(aq);
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
lookup.c (02.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
int exfat_opendir(struct exfat* ef, struct exfat_node* dir,
|
||||
struct exfat_iterator* it)
|
||||
{
|
||||
int rc;
|
||||
|
||||
exfat_get_node(dir);
|
||||
it->parent = dir;
|
||||
it->current = NULL;
|
||||
rc = exfat_cache_directory(ef, dir);
|
||||
if (rc != 0)
|
||||
exfat_put_node(ef, dir);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void exfat_closedir(struct exfat* ef, struct exfat_iterator* it)
|
||||
{
|
||||
exfat_put_node(ef, it->parent);
|
||||
it->parent = NULL;
|
||||
it->current = NULL;
|
||||
}
|
||||
|
||||
struct exfat_node* exfat_readdir(struct exfat_iterator* it)
|
||||
{
|
||||
if (it->current == NULL)
|
||||
it->current = it->parent->child;
|
||||
else
|
||||
it->current = it->current->next;
|
||||
|
||||
if (it->current != NULL)
|
||||
return exfat_get_node(it->current);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int compare_char(struct exfat* ef, uint16_t a, uint16_t b)
|
||||
{
|
||||
return (int) ef->upcase[a] - (int) ef->upcase[b];
|
||||
}
|
||||
|
||||
static int compare_name(struct exfat* ef, const le16_t* a, const le16_t* b)
|
||||
{
|
||||
while (le16_to_cpu(*a) && le16_to_cpu(*b))
|
||||
{
|
||||
int rc = compare_char(ef, le16_to_cpu(*a), le16_to_cpu(*b));
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
return compare_char(ef, le16_to_cpu(*a), le16_to_cpu(*b));
|
||||
}
|
||||
|
||||
static int lookup_name(struct exfat* ef, struct exfat_node* parent,
|
||||
struct exfat_node** node, const char* name, size_t n)
|
||||
{
|
||||
struct exfat_iterator it;
|
||||
le16_t buffer[EXFAT_NAME_MAX + 1];
|
||||
int rc;
|
||||
|
||||
*node = NULL;
|
||||
|
||||
rc = exfat_utf8_to_utf16(buffer, name, EXFAT_NAME_MAX + 1, n);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = exfat_opendir(ef, parent, &it);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
while ((*node = exfat_readdir(&it)))
|
||||
{
|
||||
if (compare_name(ef, buffer, (*node)->name) == 0)
|
||||
{
|
||||
exfat_closedir(ef, &it);
|
||||
return 0;
|
||||
}
|
||||
exfat_put_node(ef, *node);
|
||||
}
|
||||
exfat_closedir(ef, &it);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static size_t get_comp(const char* path, const char** comp)
|
||||
{
|
||||
const char* end;
|
||||
|
||||
*comp = path + strspn(path, "/"); /* skip leading slashes */
|
||||
end = strchr(*comp, '/');
|
||||
if (end == NULL)
|
||||
return strlen(*comp);
|
||||
else
|
||||
return end - *comp;
|
||||
}
|
||||
|
||||
int exfat_lookup(struct exfat* ef, struct exfat_node** node,
|
||||
const char* path)
|
||||
{
|
||||
struct exfat_node* parent;
|
||||
const char* p;
|
||||
size_t n;
|
||||
int rc;
|
||||
|
||||
/* start from the root directory */
|
||||
parent = *node = exfat_get_node(ef->root);
|
||||
for (p = path; (n = get_comp(p, &p)); p += n)
|
||||
{
|
||||
if (n == 1 && *p == '.') /* skip "." component */
|
||||
continue;
|
||||
rc = lookup_name(ef, parent, node, p, n);
|
||||
if (rc != 0)
|
||||
{
|
||||
exfat_put_node(ef, parent);
|
||||
return rc;
|
||||
}
|
||||
exfat_put_node(ef, parent);
|
||||
parent = *node;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_last_comp(const char* comp, size_t length)
|
||||
{
|
||||
const char* p = comp + length;
|
||||
|
||||
return get_comp(p, &p) == 0;
|
||||
}
|
||||
|
||||
static bool is_allowed(const char* comp, size_t length)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
switch (comp[i])
|
||||
{
|
||||
case 0x01 ... 0x1f:
|
||||
case '/':
|
||||
case '\\':
|
||||
case ':':
|
||||
case '*':
|
||||
case '?':
|
||||
case '"':
|
||||
case '<':
|
||||
case '>':
|
||||
case '|':
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int exfat_split(struct exfat* ef, struct exfat_node** parent,
|
||||
struct exfat_node** node, le16_t* name, const char* path)
|
||||
{
|
||||
const char* p;
|
||||
size_t n;
|
||||
int rc;
|
||||
|
||||
memset(name, 0, (EXFAT_NAME_MAX + 1) * sizeof(le16_t));
|
||||
*parent = *node = exfat_get_node(ef->root);
|
||||
for (p = path; (n = get_comp(p, &p)); p += n)
|
||||
{
|
||||
if (n == 1 && *p == '.')
|
||||
continue;
|
||||
if (is_last_comp(p, n))
|
||||
{
|
||||
if (!is_allowed(p, n))
|
||||
{
|
||||
/* contains characters that are not allowed */
|
||||
exfat_put_node(ef, *parent);
|
||||
return -ENOENT;
|
||||
}
|
||||
rc = exfat_utf8_to_utf16(name, p, EXFAT_NAME_MAX + 1, n);
|
||||
if (rc != 0)
|
||||
{
|
||||
exfat_put_node(ef, *parent);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = lookup_name(ef, *parent, node, p, n);
|
||||
if (rc != 0 && rc != -ENOENT)
|
||||
{
|
||||
exfat_put_node(ef, *parent);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
rc = lookup_name(ef, *parent, node, p, n);
|
||||
if (rc != 0)
|
||||
{
|
||||
exfat_put_node(ef, *parent);
|
||||
return rc;
|
||||
}
|
||||
exfat_put_node(ef, *parent);
|
||||
*parent = *node;
|
||||
}
|
||||
exfat_bug("impossible");
|
||||
}
|
||||
@@ -1,373 +0,0 @@
|
||||
/*
|
||||
mount.c (22.10.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
static uint64_t rootdir_size(const struct exfat* ef)
|
||||
{
|
||||
uint32_t clusters = 0;
|
||||
uint32_t clusters_max = le32_to_cpu(ef->sb->cluster_count);
|
||||
cluster_t rootdir_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
|
||||
|
||||
/* Iterate all clusters of the root directory to calculate its size.
|
||||
It can't be contiguous because there is no flag to indicate this. */
|
||||
do
|
||||
{
|
||||
if (clusters == clusters_max) /* infinite loop detected */
|
||||
{
|
||||
exfat_error("root directory cannot occupy all %d clusters",
|
||||
clusters);
|
||||
return 0;
|
||||
}
|
||||
if (CLUSTER_INVALID(*ef->sb, rootdir_cluster))
|
||||
{
|
||||
exfat_error("bad cluster %#x while reading root directory",
|
||||
rootdir_cluster);
|
||||
return 0;
|
||||
}
|
||||
rootdir_cluster = exfat_next_cluster(ef, ef->root, rootdir_cluster);
|
||||
clusters++;
|
||||
}
|
||||
while (rootdir_cluster != EXFAT_CLUSTER_END);
|
||||
|
||||
return (uint64_t) clusters * CLUSTER_SIZE(*ef->sb);
|
||||
}
|
||||
|
||||
static const char* get_option(const char* options, const char* option_name)
|
||||
{
|
||||
const char* p;
|
||||
size_t length = strlen(option_name);
|
||||
|
||||
for (p = strstr(options, option_name); p; p = strstr(p + 1, option_name))
|
||||
if ((p == options || p[-1] == ',') && p[length] == '=')
|
||||
return p + length + 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int get_int_option(const char* options, const char* option_name,
|
||||
int base, int default_value)
|
||||
{
|
||||
const char* p = get_option(options, option_name);
|
||||
|
||||
if (p == NULL)
|
||||
return default_value;
|
||||
return strtol(p, NULL, base);
|
||||
}
|
||||
|
||||
static void parse_options(struct exfat* ef, const char* options)
|
||||
{
|
||||
int opt_umask;
|
||||
|
||||
opt_umask = get_int_option(options, "umask", 8, 0);
|
||||
ef->dmask = get_int_option(options, "dmask", 8, opt_umask);
|
||||
ef->fmask = get_int_option(options, "fmask", 8, opt_umask);
|
||||
|
||||
ef->uid = get_int_option(options, "uid", 10, geteuid());
|
||||
ef->gid = get_int_option(options, "gid", 10, getegid());
|
||||
|
||||
ef->noatime = exfat_match_option(options, "noatime");
|
||||
|
||||
switch (get_int_option(options, "repair", 10, 0))
|
||||
{
|
||||
case 1:
|
||||
ef->repair = EXFAT_REPAIR_ASK;
|
||||
break;
|
||||
case 2:
|
||||
ef->repair = EXFAT_REPAIR_YES;
|
||||
break;
|
||||
default:
|
||||
ef->repair = EXFAT_REPAIR_NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool verify_vbr_checksum(const struct exfat* ef, void* sector)
|
||||
{
|
||||
off_t sector_size = SECTOR_SIZE(*ef->sb);
|
||||
uint32_t vbr_checksum;
|
||||
size_t i;
|
||||
|
||||
if (exfat_pread(ef->dev, sector, sector_size, 0) < 0)
|
||||
{
|
||||
exfat_error("failed to read boot sector");
|
||||
return false;
|
||||
}
|
||||
vbr_checksum = exfat_vbr_start_checksum(sector, sector_size);
|
||||
for (i = 1; i < 11; i++)
|
||||
{
|
||||
if (exfat_pread(ef->dev, sector, sector_size, i * sector_size) < 0)
|
||||
{
|
||||
exfat_error("failed to read VBR sector");
|
||||
return false;
|
||||
}
|
||||
vbr_checksum = exfat_vbr_add_checksum(sector, sector_size,
|
||||
vbr_checksum);
|
||||
}
|
||||
if (exfat_pread(ef->dev, sector, sector_size, i * sector_size) < 0)
|
||||
{
|
||||
exfat_error("failed to read VBR checksum sector");
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < sector_size / sizeof(vbr_checksum); i++)
|
||||
if (le32_to_cpu(((const le32_t*) sector)[i]) != vbr_checksum)
|
||||
{
|
||||
exfat_error("invalid VBR checksum 0x%x (expected 0x%x)",
|
||||
le32_to_cpu(((const le32_t*) sector)[i]), vbr_checksum);
|
||||
if (!EXFAT_REPAIR(invalid_vbr_checksum, ef, sector, vbr_checksum))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int commit_super_block(const struct exfat* ef)
|
||||
{
|
||||
if (exfat_pwrite(ef->dev, ef->sb, sizeof(struct exfat_super_block), 0) < 0)
|
||||
{
|
||||
exfat_error("failed to write super block");
|
||||
return 1;
|
||||
}
|
||||
return exfat_fsync(ef->dev);
|
||||
}
|
||||
|
||||
int exfat_soil_super_block(const struct exfat* ef)
|
||||
{
|
||||
if (ef->ro)
|
||||
return 0;
|
||||
|
||||
ef->sb->volume_state = cpu_to_le16(
|
||||
le16_to_cpu(ef->sb->volume_state) | EXFAT_STATE_MOUNTED);
|
||||
return commit_super_block(ef);
|
||||
}
|
||||
|
||||
static void exfat_free(struct exfat* ef)
|
||||
{
|
||||
exfat_close(ef->dev); /* first of all, close the descriptor */
|
||||
ef->dev = NULL; /* struct exfat_dev is freed by exfat_close() */
|
||||
free(ef->root);
|
||||
ef->root = NULL;
|
||||
free(ef->zero_cluster);
|
||||
ef->zero_cluster = NULL;
|
||||
free(ef->cmap.chunk);
|
||||
ef->cmap.chunk = NULL;
|
||||
free(ef->upcase);
|
||||
ef->upcase = NULL;
|
||||
free(ef->sb);
|
||||
ef->sb = NULL;
|
||||
}
|
||||
|
||||
int exfat_mount(struct exfat* ef, const char* spec, const char* options)
|
||||
{
|
||||
int rc;
|
||||
enum exfat_mode mode;
|
||||
|
||||
exfat_tzset();
|
||||
memset(ef, 0, sizeof(struct exfat));
|
||||
|
||||
parse_options(ef, options);
|
||||
|
||||
if (exfat_match_option(options, "ro"))
|
||||
mode = EXFAT_MODE_RO;
|
||||
else if (exfat_match_option(options, "ro_fallback"))
|
||||
mode = EXFAT_MODE_ANY;
|
||||
else
|
||||
mode = EXFAT_MODE_RW;
|
||||
ef->dev = exfat_open(spec, mode);
|
||||
if (ef->dev == NULL)
|
||||
return -EIO;
|
||||
if (exfat_get_mode(ef->dev) == EXFAT_MODE_RO)
|
||||
{
|
||||
if (mode == EXFAT_MODE_ANY)
|
||||
ef->ro = -1;
|
||||
else
|
||||
ef->ro = 1;
|
||||
}
|
||||
|
||||
ef->sb = malloc(sizeof(struct exfat_super_block));
|
||||
if (ef->sb == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate memory for the super block");
|
||||
exfat_free(ef);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(ef->sb, 0, sizeof(struct exfat_super_block));
|
||||
|
||||
if (exfat_pread(ef->dev, ef->sb, sizeof(struct exfat_super_block), 0) < 0)
|
||||
{
|
||||
exfat_error("failed to read boot sector");
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
if (memcmp(ef->sb->oem_name, "EXFAT ", 8) != 0)
|
||||
{
|
||||
exfat_error("exFAT file system is not found");
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
/* sector cannot be smaller than 512 bytes */
|
||||
if (ef->sb->sector_bits < 9)
|
||||
{
|
||||
exfat_error("too small sector size: 2^%hhd", ef->sb->sector_bits);
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
/* officially exFAT supports cluster size up to 32 MB */
|
||||
if ((int) ef->sb->sector_bits + (int) ef->sb->spc_bits > 25)
|
||||
{
|
||||
exfat_error("too big cluster size: 2^(%hhd+%hhd)",
|
||||
ef->sb->sector_bits, ef->sb->spc_bits);
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
ef->zero_cluster = malloc(CLUSTER_SIZE(*ef->sb));
|
||||
if (ef->zero_cluster == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate zero sector");
|
||||
exfat_free(ef);
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* use zero_cluster as a temporary buffer for VBR checksum verification */
|
||||
if (!verify_vbr_checksum(ef, ef->zero_cluster))
|
||||
{
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
memset(ef->zero_cluster, 0, CLUSTER_SIZE(*ef->sb));
|
||||
if (ef->sb->version.major != 1 || ef->sb->version.minor != 0)
|
||||
{
|
||||
exfat_error("unsupported exFAT version: %hhu.%hhu",
|
||||
ef->sb->version.major, ef->sb->version.minor);
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
if (ef->sb->fat_count != 1)
|
||||
{
|
||||
exfat_error("unsupported FAT count: %hhu", ef->sb->fat_count);
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
if (le64_to_cpu(ef->sb->sector_count) * SECTOR_SIZE(*ef->sb) >
|
||||
(uint64_t) exfat_get_size(ef->dev))
|
||||
{
|
||||
/* this can cause I/O errors later but we don't fail mounting to let
|
||||
user rescue data */
|
||||
exfat_warn("file system in sectors is larger than device: "
|
||||
"%"PRIu64" * %d > %"PRIu64,
|
||||
le64_to_cpu(ef->sb->sector_count), SECTOR_SIZE(*ef->sb),
|
||||
exfat_get_size(ef->dev));
|
||||
}
|
||||
if ((off_t) le32_to_cpu(ef->sb->cluster_count) * CLUSTER_SIZE(*ef->sb) >
|
||||
exfat_get_size(ef->dev))
|
||||
{
|
||||
exfat_error("file system in clusters is larger than device: "
|
||||
"%u * %d > %"PRIu64,
|
||||
le32_to_cpu(ef->sb->cluster_count), CLUSTER_SIZE(*ef->sb),
|
||||
exfat_get_size(ef->dev));
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
if (le16_to_cpu(ef->sb->volume_state) & EXFAT_STATE_MOUNTED)
|
||||
exfat_warn("volume was not unmounted cleanly");
|
||||
|
||||
ef->root = malloc(sizeof(struct exfat_node));
|
||||
if (ef->root == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate root node");
|
||||
exfat_free(ef);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(ef->root, 0, sizeof(struct exfat_node));
|
||||
ef->root->attrib = EXFAT_ATTRIB_DIR;
|
||||
ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
|
||||
ef->root->fptr_cluster = ef->root->start_cluster;
|
||||
ef->root->name[0] = cpu_to_le16('\0');
|
||||
ef->root->size = rootdir_size(ef);
|
||||
if (ef->root->size == 0)
|
||||
{
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
/* exFAT does not have time attributes for the root directory */
|
||||
ef->root->mtime = 0;
|
||||
ef->root->atime = 0;
|
||||
/* always keep at least 1 reference to the root node */
|
||||
exfat_get_node(ef->root);
|
||||
|
||||
rc = exfat_cache_directory(ef, ef->root);
|
||||
if (rc != 0)
|
||||
goto error;
|
||||
if (ef->upcase == NULL)
|
||||
{
|
||||
exfat_error("upcase table is not found");
|
||||
goto error;
|
||||
}
|
||||
if (ef->cmap.chunk == NULL)
|
||||
{
|
||||
exfat_error("clusters bitmap is not found");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
exfat_put_node(ef, ef->root);
|
||||
exfat_reset_cache(ef);
|
||||
exfat_free(ef);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void finalize_super_block(struct exfat* ef)
|
||||
{
|
||||
if (ef->ro)
|
||||
return;
|
||||
|
||||
ef->sb->volume_state = cpu_to_le16(
|
||||
le16_to_cpu(ef->sb->volume_state) & ~EXFAT_STATE_MOUNTED);
|
||||
|
||||
/* Some implementations set the percentage of allocated space to 0xff
|
||||
on FS creation and never update it. In this case leave it as is. */
|
||||
if (ef->sb->allocated_percent != 0xff)
|
||||
{
|
||||
uint32_t free, total;
|
||||
|
||||
free = exfat_count_free_clusters(ef);
|
||||
total = le32_to_cpu(ef->sb->cluster_count);
|
||||
ef->sb->allocated_percent = ((total - free) * 100 + total / 2) / total;
|
||||
}
|
||||
|
||||
commit_super_block(ef); /* ignore return code */
|
||||
}
|
||||
|
||||
void exfat_unmount(struct exfat* ef)
|
||||
{
|
||||
exfat_flush_nodes(ef); /* ignore return code */
|
||||
exfat_flush(ef); /* ignore return code */
|
||||
exfat_put_node(ef, ef->root);
|
||||
exfat_reset_cache(ef);
|
||||
finalize_super_block(ef);
|
||||
exfat_free(ef); /* will close the descriptor */
|
||||
}
|
||||
-1243
File diff suppressed because it is too large
Load Diff
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
platform.h (14.05.13)
|
||||
OS-specific code (libc-specific in fact). Note that systems with the
|
||||
same kernel can use different libc implementations.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef PLATFORM_H_INCLUDED
|
||||
#define PLATFORM_H_INCLUDED
|
||||
|
||||
#if defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)
|
||||
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
#define exfat_bswap16(x) bswap_16(x)
|
||||
#define exfat_bswap32(x) bswap_32(x)
|
||||
#define exfat_bswap64(x) bswap_64(x)
|
||||
#define EXFAT_BYTE_ORDER __BYTE_ORDER
|
||||
#define EXFAT_LITTLE_ENDIAN __LITTLE_ENDIAN
|
||||
#define EXFAT_BIG_ENDIAN __BIG_ENDIAN
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
#include <machine/endian.h>
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define exfat_bswap16(x) OSSwapInt16(x)
|
||||
#define exfat_bswap32(x) OSSwapInt32(x)
|
||||
#define exfat_bswap64(x) OSSwapInt64(x)
|
||||
#define EXFAT_BYTE_ORDER BYTE_ORDER
|
||||
#define EXFAT_LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#define EXFAT_BIG_ENDIAN BIG_ENDIAN
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
|
||||
#include <sys/endian.h>
|
||||
#define exfat_bswap16(x) bswap16(x)
|
||||
#define exfat_bswap32(x) bswap32(x)
|
||||
#define exfat_bswap64(x) bswap64(x)
|
||||
#define EXFAT_BYTE_ORDER _BYTE_ORDER
|
||||
#define EXFAT_LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define EXFAT_BIG_ENDIAN _BIG_ENDIAN
|
||||
|
||||
#elif defined(__sun)
|
||||
|
||||
#include <endian.h>
|
||||
#define exfat_bswap16(x) bswap_16(x)
|
||||
#define exfat_bswap32(x) bswap_32(x)
|
||||
#define exfat_bswap64(x) bswap_64(x)
|
||||
#define EXFAT_BYTE_ORDER __BYTE_ORDER
|
||||
#define EXFAT_LITTLE_ENDIAN __LITTLE_ENDIAN
|
||||
#define EXFAT_BIG_ENDIAN __BIG_ENDIAN
|
||||
|
||||
#else
|
||||
#error Unknown platform
|
||||
#endif
|
||||
|
||||
#endif /* ifndef PLATFORM_H_INCLUDED */
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
repair.c (09.03.17)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <strings.h>
|
||||
|
||||
int exfat_errors_fixed;
|
||||
|
||||
bool exfat_ask_to_fix(const struct exfat* ef)
|
||||
{
|
||||
const char* question = "Fix (Y/N)?";
|
||||
char answer[8];
|
||||
bool yeah, nope;
|
||||
|
||||
switch (ef->repair)
|
||||
{
|
||||
case EXFAT_REPAIR_NO:
|
||||
return false;
|
||||
case EXFAT_REPAIR_YES:
|
||||
printf("%s %s", question, "Y\n");
|
||||
return true;
|
||||
case EXFAT_REPAIR_ASK:
|
||||
do
|
||||
{
|
||||
printf("%s ", question);
|
||||
fflush(stdout);
|
||||
if (fgets(answer, sizeof(answer), stdin))
|
||||
{
|
||||
yeah = strcasecmp(answer, "Y\n") == 0;
|
||||
nope = strcasecmp(answer, "N\n") == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
yeah = false;
|
||||
nope = true;
|
||||
}
|
||||
}
|
||||
while (!yeah && !nope);
|
||||
return yeah;
|
||||
}
|
||||
exfat_bug("invalid repair option value: %d", ef->repair);
|
||||
}
|
||||
|
||||
bool exfat_fix_invalid_vbr_checksum(const struct exfat* ef, void* sector,
|
||||
uint32_t vbr_checksum)
|
||||
{
|
||||
size_t i;
|
||||
off_t sector_size = SECTOR_SIZE(*ef->sb);
|
||||
|
||||
for (i = 0; i < sector_size / sizeof(vbr_checksum); i++)
|
||||
((le32_t*) sector)[i] = cpu_to_le32(vbr_checksum);
|
||||
if (exfat_pwrite(ef->dev, sector, sector_size, 11 * sector_size) < 0)
|
||||
{
|
||||
exfat_error("failed to write correct VBR checksum");
|
||||
return false;
|
||||
}
|
||||
exfat_errors_fixed++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exfat_fix_invalid_node_checksum(UNUSED const struct exfat* ef,
|
||||
struct exfat_node* node)
|
||||
{
|
||||
/* checksum will be rewritten by exfat_flush_node() */
|
||||
node->is_dirty = true;
|
||||
|
||||
exfat_errors_fixed++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exfat_fix_unknown_entry(struct exfat* ef, struct exfat_node* dir,
|
||||
const struct exfat_entry* entry, off_t offset)
|
||||
{
|
||||
struct exfat_entry deleted = *entry;
|
||||
|
||||
deleted.type &= ~EXFAT_ENTRY_VALID;
|
||||
if (exfat_generic_pwrite(ef, dir, &deleted, sizeof(struct exfat_entry),
|
||||
offset) != sizeof(struct exfat_entry))
|
||||
return false;
|
||||
|
||||
exfat_errors_fixed++;
|
||||
return true;
|
||||
}
|
||||
-173
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
time.c (03.02.12)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
|
||||
/* timezone offset from UTC in seconds; positive for western timezones,
|
||||
negative for eastern ones */
|
||||
static long exfat_timezone;
|
||||
|
||||
#define SEC_IN_MIN 60ll
|
||||
#define SEC_IN_HOUR (60 * SEC_IN_MIN)
|
||||
#define SEC_IN_DAY (24 * SEC_IN_HOUR)
|
||||
#define SEC_IN_YEAR (365 * SEC_IN_DAY) /* not leap year */
|
||||
/* Unix epoch started at 0:00:00 UTC 1 January 1970 */
|
||||
#define UNIX_EPOCH_YEAR 1970
|
||||
/* exFAT epoch started at 0:00:00 UTC 1 January 1980 */
|
||||
#define EXFAT_EPOCH_YEAR 1980
|
||||
/* number of years from Unix epoch to exFAT epoch */
|
||||
#define EPOCH_DIFF_YEAR (EXFAT_EPOCH_YEAR - UNIX_EPOCH_YEAR)
|
||||
/* number of days from Unix epoch to exFAT epoch (considering leap days) */
|
||||
#define EPOCH_DIFF_DAYS (EPOCH_DIFF_YEAR * 365 + EPOCH_DIFF_YEAR / 4)
|
||||
/* number of seconds from Unix epoch to exFAT epoch (considering leap days) */
|
||||
#define EPOCH_DIFF_SEC (EPOCH_DIFF_DAYS * SEC_IN_DAY)
|
||||
/* number of leap years passed from exFAT epoch to the specified year
|
||||
(excluding the specified year itself) */
|
||||
#define LEAP_YEARS(year) ((EXFAT_EPOCH_YEAR + (year) - 1) / 4 \
|
||||
- (EXFAT_EPOCH_YEAR - 1) / 4)
|
||||
/* checks whether the specified year is leap */
|
||||
#define IS_LEAP_YEAR(year) ((EXFAT_EPOCH_YEAR + (year)) % 4 == 0)
|
||||
|
||||
static const time_t days_in_year[] =
|
||||
{
|
||||
/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
|
||||
0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
|
||||
};
|
||||
|
||||
time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec,
|
||||
uint8_t tzoffset)
|
||||
{
|
||||
time_t unix_time = EPOCH_DIFF_SEC;
|
||||
uint16_t ndate = le16_to_cpu(date);
|
||||
uint16_t ntime = le16_to_cpu(time);
|
||||
|
||||
uint16_t day = ndate & 0x1f; /* 5 bits, 1-31 */
|
||||
uint16_t month = ndate >> 5 & 0xf; /* 4 bits, 1-12 */
|
||||
uint16_t year = ndate >> 9; /* 7 bits, 1-127 (+1980) */
|
||||
|
||||
uint16_t twosec = ntime & 0x1f; /* 5 bits, 0-29 (2 sec granularity) */
|
||||
uint16_t min = ntime >> 5 & 0x3f; /* 6 bits, 0-59 */
|
||||
uint16_t hour = ntime >> 11; /* 5 bits, 0-23 */
|
||||
|
||||
if (day == 0 || month == 0 || month > 12)
|
||||
{
|
||||
exfat_error("bad date %u-%02hu-%02hu",
|
||||
year + EXFAT_EPOCH_YEAR, month, day);
|
||||
return 0;
|
||||
}
|
||||
if (hour > 23 || min > 59 || twosec > 29)
|
||||
{
|
||||
exfat_error("bad time %hu:%02hu:%02u",
|
||||
hour, min, twosec * 2);
|
||||
return 0;
|
||||
}
|
||||
if (centisec > 199)
|
||||
{
|
||||
exfat_error("bad centiseconds count %hhu", centisec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* every 4th year between 1904 and 2096 is leap */
|
||||
unix_time += year * SEC_IN_YEAR + LEAP_YEARS(year) * SEC_IN_DAY;
|
||||
unix_time += days_in_year[month] * SEC_IN_DAY;
|
||||
/* if it's leap year and February has passed we should add 1 day */
|
||||
if ((EXFAT_EPOCH_YEAR + year) % 4 == 0 && month > 2)
|
||||
unix_time += SEC_IN_DAY;
|
||||
unix_time += (day - 1) * SEC_IN_DAY;
|
||||
|
||||
unix_time += hour * SEC_IN_HOUR;
|
||||
unix_time += min * SEC_IN_MIN;
|
||||
/* exFAT represents time with 2 sec granularity */
|
||||
unix_time += twosec * 2;
|
||||
unix_time += centisec / 100;
|
||||
|
||||
/* exFAT stores timestamps in local time, so we correct it to UTC */
|
||||
if (tzoffset & 0x80)
|
||||
/* lower 7 bits are signed timezone offset in 15 minute increments */
|
||||
unix_time -= (int8_t)(tzoffset << 1) * 15 * 60 / 2;
|
||||
else
|
||||
/* timezone offset not present, assume our local timezone */
|
||||
unix_time += exfat_timezone;
|
||||
|
||||
return unix_time;
|
||||
}
|
||||
|
||||
void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
|
||||
uint8_t* centisec, uint8_t* tzoffset)
|
||||
{
|
||||
time_t shift = EPOCH_DIFF_SEC + exfat_timezone;
|
||||
uint16_t day, month, year;
|
||||
uint16_t twosec, min, hour;
|
||||
int days;
|
||||
int i;
|
||||
|
||||
/* time before exFAT epoch cannot be represented */
|
||||
if (unix_time < shift)
|
||||
unix_time = shift;
|
||||
|
||||
unix_time -= shift;
|
||||
|
||||
days = unix_time / SEC_IN_DAY;
|
||||
year = (4 * days) / (4 * 365 + 1);
|
||||
days -= year * 365 + LEAP_YEARS(year);
|
||||
month = 0;
|
||||
for (i = 1; i <= 12; i++)
|
||||
{
|
||||
int leap_day = (IS_LEAP_YEAR(year) && i == 2);
|
||||
int leap_sub = (IS_LEAP_YEAR(year) && i >= 3);
|
||||
|
||||
if (i == 12 || days - leap_sub < days_in_year[i + 1] + leap_day)
|
||||
{
|
||||
month = i;
|
||||
days -= days_in_year[i] + leap_sub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
day = days + 1;
|
||||
|
||||
hour = (unix_time % SEC_IN_DAY) / SEC_IN_HOUR;
|
||||
min = (unix_time % SEC_IN_HOUR) / SEC_IN_MIN;
|
||||
twosec = (unix_time % SEC_IN_MIN) / 2;
|
||||
|
||||
*date = cpu_to_le16(day | (month << 5) | (year << 9));
|
||||
*time = cpu_to_le16(twosec | (min << 5) | (hour << 11));
|
||||
if (centisec)
|
||||
*centisec = (unix_time % 2) * 100;
|
||||
|
||||
/* record our local timezone offset in exFAT (15 minute increment) format */
|
||||
*tzoffset = (uint8_t)(-exfat_timezone / 60 / 15) | 0x80;
|
||||
}
|
||||
|
||||
void exfat_tzset(void)
|
||||
{
|
||||
time_t now;
|
||||
struct tm* utc;
|
||||
|
||||
tzset();
|
||||
now = time(NULL);
|
||||
utc = gmtime(&now);
|
||||
/* gmtime() always sets tm_isdst to 0 because daylight savings never
|
||||
affect UTC. Setting tm_isdst to -1 makes mktime() to determine whether
|
||||
summer time is in effect. */
|
||||
utc->tm_isdst = -1;
|
||||
exfat_timezone = mktime(utc) - now;
|
||||
}
|
||||
-254
@@ -1,254 +0,0 @@
|
||||
/*
|
||||
utf.c (13.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <errno.h>
|
||||
|
||||
static char* wchar_to_utf8(char* output, wchar_t wc, size_t outsize)
|
||||
{
|
||||
if (wc <= 0x7f)
|
||||
{
|
||||
if (outsize < 1)
|
||||
return NULL;
|
||||
*output++ = (char) wc;
|
||||
}
|
||||
else if (wc <= 0x7ff)
|
||||
{
|
||||
if (outsize < 2)
|
||||
return NULL;
|
||||
*output++ = 0xc0 | (wc >> 6);
|
||||
*output++ = 0x80 | (wc & 0x3f);
|
||||
}
|
||||
else if (wc <= 0xffff)
|
||||
{
|
||||
if (outsize < 3)
|
||||
return NULL;
|
||||
*output++ = 0xe0 | (wc >> 12);
|
||||
*output++ = 0x80 | ((wc >> 6) & 0x3f);
|
||||
*output++ = 0x80 | (wc & 0x3f);
|
||||
}
|
||||
else if (wc <= 0x1fffff)
|
||||
{
|
||||
if (outsize < 4)
|
||||
return NULL;
|
||||
*output++ = 0xf0 | (wc >> 18);
|
||||
*output++ = 0x80 | ((wc >> 12) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 6) & 0x3f);
|
||||
*output++ = 0x80 | (wc & 0x3f);
|
||||
}
|
||||
else if (wc <= 0x3ffffff)
|
||||
{
|
||||
if (outsize < 5)
|
||||
return NULL;
|
||||
*output++ = 0xf8 | (wc >> 24);
|
||||
*output++ = 0x80 | ((wc >> 18) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 12) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 6) & 0x3f);
|
||||
*output++ = 0x80 | (wc & 0x3f);
|
||||
}
|
||||
else if (wc <= 0x7fffffff)
|
||||
{
|
||||
if (outsize < 6)
|
||||
return NULL;
|
||||
*output++ = 0xfc | (wc >> 30);
|
||||
*output++ = 0x80 | ((wc >> 24) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 18) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 12) & 0x3f);
|
||||
*output++ = 0x80 | ((wc >> 6) & 0x3f);
|
||||
*output++ = 0x80 | (wc & 0x3f);
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static const le16_t* utf16_to_wchar(const le16_t* input, wchar_t* wc,
|
||||
size_t insize)
|
||||
{
|
||||
if ((le16_to_cpu(input[0]) & 0xfc00) == 0xd800)
|
||||
{
|
||||
if (insize < 2 || (le16_to_cpu(input[1]) & 0xfc00) != 0xdc00)
|
||||
return NULL;
|
||||
*wc = ((wchar_t) (le16_to_cpu(input[0]) & 0x3ff) << 10);
|
||||
*wc |= (le16_to_cpu(input[1]) & 0x3ff);
|
||||
*wc += 0x10000;
|
||||
return input + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*wc = le16_to_cpu(*input);
|
||||
return input + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int exfat_utf16_to_utf8(char* output, const le16_t* input, size_t outsize,
|
||||
size_t insize)
|
||||
{
|
||||
const le16_t* iptr = input;
|
||||
const le16_t* iend = input + insize;
|
||||
char* optr = output;
|
||||
const char* oend = output + outsize;
|
||||
wchar_t wc;
|
||||
|
||||
while (iptr < iend)
|
||||
{
|
||||
iptr = utf16_to_wchar(iptr, &wc, iend - iptr);
|
||||
if (iptr == NULL)
|
||||
{
|
||||
exfat_error("illegal UTF-16 sequence");
|
||||
return -EILSEQ;
|
||||
}
|
||||
optr = wchar_to_utf8(optr, wc, oend - optr);
|
||||
if (optr == NULL)
|
||||
{
|
||||
exfat_error("name is too long");
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
if (wc == 0)
|
||||
return 0;
|
||||
}
|
||||
if (optr >= oend)
|
||||
{
|
||||
exfat_error("name is too long");
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
*optr = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* utf8_to_wchar(const char* input, wchar_t* wc,
|
||||
size_t insize)
|
||||
{
|
||||
size_t size;
|
||||
size_t i;
|
||||
|
||||
if (insize == 0)
|
||||
exfat_bug("no input for utf8_to_wchar");
|
||||
|
||||
if ((input[0] & 0x80) == 0)
|
||||
{
|
||||
*wc = (wchar_t) input[0];
|
||||
return input + 1;
|
||||
}
|
||||
else if ((input[0] & 0xe0) == 0xc0)
|
||||
{
|
||||
*wc = ((wchar_t) input[0] & 0x1f) << 6;
|
||||
size = 2;
|
||||
}
|
||||
else if ((input[0] & 0xf0) == 0xe0)
|
||||
{
|
||||
*wc = ((wchar_t) input[0] & 0x0f) << 12;
|
||||
size = 3;
|
||||
}
|
||||
else if ((input[0] & 0xf8) == 0xf0)
|
||||
{
|
||||
*wc = ((wchar_t) input[0] & 0x07) << 18;
|
||||
size = 4;
|
||||
}
|
||||
else if ((input[0] & 0xfc) == 0xf8)
|
||||
{
|
||||
*wc = ((wchar_t) input[0] & 0x03) << 24;
|
||||
size = 5;
|
||||
}
|
||||
else if ((input[0] & 0xfe) == 0xfc)
|
||||
{
|
||||
*wc = ((wchar_t) input[0] & 0x01) << 30;
|
||||
size = 6;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (insize < size)
|
||||
return NULL;
|
||||
|
||||
/* the first byte is handled above */
|
||||
for (i = 1; i < size; i++)
|
||||
{
|
||||
if ((input[i] & 0xc0) != 0x80)
|
||||
return NULL;
|
||||
*wc |= (input[i] & 0x3f) << ((size - i - 1) * 6);
|
||||
}
|
||||
|
||||
return input + size;
|
||||
}
|
||||
|
||||
static le16_t* wchar_to_utf16(le16_t* output, wchar_t wc, size_t outsize)
|
||||
{
|
||||
if (wc <= 0xffff) /* if character is from BMP */
|
||||
{
|
||||
if (outsize == 0)
|
||||
return NULL;
|
||||
output[0] = cpu_to_le16(wc);
|
||||
return output + 1;
|
||||
}
|
||||
if (outsize < 2)
|
||||
return NULL;
|
||||
wc -= 0x10000;
|
||||
output[0] = cpu_to_le16(0xd800 | ((wc >> 10) & 0x3ff));
|
||||
output[1] = cpu_to_le16(0xdc00 | (wc & 0x3ff));
|
||||
return output + 2;
|
||||
}
|
||||
|
||||
int exfat_utf8_to_utf16(le16_t* output, const char* input, size_t outsize,
|
||||
size_t insize)
|
||||
{
|
||||
const char* iptr = input;
|
||||
const char* iend = input + insize;
|
||||
le16_t* optr = output;
|
||||
const le16_t* oend = output + outsize;
|
||||
wchar_t wc;
|
||||
|
||||
while (iptr < iend)
|
||||
{
|
||||
iptr = utf8_to_wchar(iptr, &wc, iend - iptr);
|
||||
if (iptr == NULL)
|
||||
{
|
||||
exfat_error("illegal UTF-8 sequence");
|
||||
return -EILSEQ;
|
||||
}
|
||||
optr = wchar_to_utf16(optr, wc, oend - optr);
|
||||
if (optr == NULL)
|
||||
{
|
||||
exfat_error("name is too long");
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
if (wc == 0)
|
||||
break;
|
||||
}
|
||||
if (optr >= oend)
|
||||
{
|
||||
exfat_error("name is too long");
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
*optr = cpu_to_le16(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t exfat_utf16_length(const le16_t* str)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
while (le16_to_cpu(str[i]))
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
utils.c (04.09.09)
|
||||
exFAT file system implementation library.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2010-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "exfat.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
|
||||
struct stat* stbuf)
|
||||
{
|
||||
memset(stbuf, 0, sizeof(struct stat));
|
||||
if (node->attrib & EXFAT_ATTRIB_DIR)
|
||||
stbuf->st_mode = S_IFDIR | (0777 & ~ef->dmask);
|
||||
else
|
||||
stbuf->st_mode = S_IFREG | (0777 & ~ef->fmask);
|
||||
stbuf->st_nlink = 1;
|
||||
stbuf->st_uid = ef->uid;
|
||||
stbuf->st_gid = ef->gid;
|
||||
stbuf->st_size = node->size;
|
||||
stbuf->st_blocks = ROUND_UP(node->size, CLUSTER_SIZE(*ef->sb)) / 512;
|
||||
stbuf->st_mtime = node->mtime;
|
||||
stbuf->st_atime = node->atime;
|
||||
/* set ctime to mtime to ensure we don't break programs that rely on ctime
|
||||
(e.g. rsync) */
|
||||
stbuf->st_ctime = node->mtime;
|
||||
}
|
||||
|
||||
void exfat_get_name(const struct exfat_node* node,
|
||||
char buffer[EXFAT_UTF8_NAME_BUFFER_MAX])
|
||||
{
|
||||
if (exfat_utf16_to_utf8(buffer, node->name, EXFAT_UTF8_NAME_BUFFER_MAX,
|
||||
EXFAT_NAME_MAX) != 0)
|
||||
exfat_bug("failed to convert name to UTF-8");
|
||||
}
|
||||
|
||||
static uint16_t add_checksum_byte(uint16_t sum, uint8_t byte)
|
||||
{
|
||||
return ((sum << 15) | (sum >> 1)) + byte;
|
||||
}
|
||||
|
||||
static uint16_t add_checksum_bytes(uint16_t sum, const void* buffer, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
sum = add_checksum_byte(sum, ((const uint8_t*) buffer)[i]);
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry)
|
||||
{
|
||||
uint16_t sum = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(struct exfat_entry); i++)
|
||||
if (i != 2 && i != 3) /* skip checksum field itself */
|
||||
sum = add_checksum_byte(sum, ((const uint8_t*) entry)[i]);
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint16_t exfat_add_checksum(const void* entry, uint16_t sum)
|
||||
{
|
||||
return add_checksum_bytes(sum, entry, sizeof(struct exfat_entry));
|
||||
}
|
||||
|
||||
le16_t exfat_calc_checksum(const struct exfat_entry* entries, int n)
|
||||
{
|
||||
uint16_t checksum;
|
||||
int i;
|
||||
|
||||
checksum = exfat_start_checksum((const struct exfat_entry_meta1*) entries);
|
||||
for (i = 1; i < n; i++)
|
||||
checksum = exfat_add_checksum(entries + i, checksum);
|
||||
return cpu_to_le16(checksum);
|
||||
}
|
||||
|
||||
uint32_t exfat_vbr_start_checksum(const void* sector, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t sum = 0;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
/* skip volume_state and allocated_percent fields */
|
||||
if (i != 0x6a && i != 0x6b && i != 0x70)
|
||||
sum = ((sum << 31) | (sum >> 1)) + ((const uint8_t*) sector)[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
sum = ((sum << 31) | (sum >> 1)) + ((const uint8_t*) sector)[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name,
|
||||
size_t length)
|
||||
{
|
||||
size_t i;
|
||||
uint16_t hash = 0;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
uint16_t c = le16_to_cpu(name[i]);
|
||||
|
||||
/* convert to upper case */
|
||||
c = ef->upcase[c];
|
||||
|
||||
hash = ((hash << 15) | (hash >> 1)) + (c & 0xff);
|
||||
hash = ((hash << 15) | (hash >> 1)) + (c >> 8);
|
||||
}
|
||||
return cpu_to_le16(hash);
|
||||
}
|
||||
|
||||
void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb)
|
||||
{
|
||||
size_t i;
|
||||
/* 16 EB (minus 1 byte) is the largest size that can be represented by
|
||||
uint64_t */
|
||||
const char* units[] = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB"};
|
||||
uint64_t divisor = 1;
|
||||
uint64_t temp = 0;
|
||||
|
||||
for (i = 0; ; i++, divisor *= 1024)
|
||||
{
|
||||
temp = (value + divisor / 2) / divisor;
|
||||
|
||||
if (temp == 0)
|
||||
break;
|
||||
if (temp / 1024 * 1024 == temp)
|
||||
continue;
|
||||
if (temp < 10240)
|
||||
break;
|
||||
}
|
||||
hb->value = temp;
|
||||
hb->unit = units[i];
|
||||
}
|
||||
|
||||
void exfat_print_info(const struct exfat_super_block* sb,
|
||||
uint32_t free_clusters)
|
||||
{
|
||||
struct exfat_human_bytes hb;
|
||||
off_t total_space = le64_to_cpu(sb->sector_count) * SECTOR_SIZE(*sb);
|
||||
off_t avail_space = (off_t) free_clusters * CLUSTER_SIZE(*sb);
|
||||
|
||||
printf("File system version %hhu.%hhu\n",
|
||||
sb->version.major, sb->version.minor);
|
||||
exfat_humanize_bytes(SECTOR_SIZE(*sb), &hb);
|
||||
printf("Sector size %10"PRIu64" %s\n", hb.value, hb.unit);
|
||||
exfat_humanize_bytes(CLUSTER_SIZE(*sb), &hb);
|
||||
printf("Cluster size %10"PRIu64" %s\n", hb.value, hb.unit);
|
||||
exfat_humanize_bytes(total_space, &hb);
|
||||
printf("Volume size %10"PRIu64" %s\n", hb.value, hb.unit);
|
||||
exfat_humanize_bytes(total_space - avail_space, &hb);
|
||||
printf("Used space %10"PRIu64" %s\n", hb.value, hb.unit);
|
||||
exfat_humanize_bytes(avail_space, &hb);
|
||||
printf("Available space %10"PRIu64" %s\n", hb.value, hb.unit);
|
||||
}
|
||||
|
||||
bool exfat_match_option(const char* options, const char* option_name)
|
||||
{
|
||||
const char* p;
|
||||
size_t length = strlen(option_name);
|
||||
|
||||
for (p = strstr(options, option_name); p; p = strstr(p + 1, option_name))
|
||||
if ((p == options || p[-1] == ',') &&
|
||||
(p[length] == ',' || p[length] == '\0'))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
.TH dump.exfat 8
|
||||
.SH NAME
|
||||
dump.exfat \- Show on-disk information of exfat filesystem
|
||||
.SH SYNOPSIS
|
||||
.B dump.exfat
|
||||
.I device
|
||||
.br
|
||||
.B dump.exfat \-V
|
||||
.SH DESCRIPTION
|
||||
.B dump.exfat
|
||||
Print on-disk information from given device that formatted by exFAT filesystem.
|
||||
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-V
|
||||
Prints the version number and exits.
|
||||
@@ -0,0 +1,36 @@
|
||||
.TH exfatlabel 8
|
||||
.SH NAME
|
||||
exfatlabel \- Get or Set volume label or volume serial of an exFAT filesystem
|
||||
.SH SYNOPSIS
|
||||
.B exfatlabel
|
||||
[
|
||||
.B \-i
|
||||
.I volume-label
|
||||
] [
|
||||
.B \-v
|
||||
]
|
||||
.I device
|
||||
[
|
||||
.I label_string or serial_value
|
||||
]
|
||||
.br
|
||||
.B exfatlabel \-V
|
||||
.SH DESCRIPTION
|
||||
.B exfatlabel
|
||||
Print or set volume label of an existing exFAT filesystem.
|
||||
|
||||
If there is a
|
||||
.I label_string
|
||||
in argument of exfatlabel, It will be written to volume label
|
||||
field on given device. If not, exfatlabel will just print out
|
||||
after reading volume label field from given device. If -i or
|
||||
--volume-serial is given, It can be switched to volume serial
|
||||
mode.
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-i
|
||||
Switch to volume serial mode.
|
||||
.TP
|
||||
.B \-V
|
||||
Prints the version number and exits.
|
||||
@@ -0,0 +1,51 @@
|
||||
.TH fsck.exfat 8
|
||||
.SH NAME
|
||||
fsck.exfat \- check an exFAT filesystem
|
||||
.SH SYNOPSIS
|
||||
.B fsck.exfat
|
||||
[
|
||||
.B \-a
|
||||
] [
|
||||
.B \-n
|
||||
] [
|
||||
.B \-r
|
||||
] [
|
||||
.B \-v
|
||||
] [
|
||||
.B \-y
|
||||
] [
|
||||
.B \-v
|
||||
]
|
||||
.I device
|
||||
.br
|
||||
.B fsck.exfat \-V
|
||||
.SH DESCRIPTION
|
||||
.B fsck.exfat
|
||||
checks an exFAT filesystem and repairs the filesystem
|
||||
depending on the options passed.
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-a
|
||||
This option does the same thing as the -p option. It is provided for backwards compatibility only; it is suggested that people use -p option whenever possible.
|
||||
.TP
|
||||
.BI \-n
|
||||
Check the filesystem but do not attempt to repair the filesystem.
|
||||
.TP
|
||||
.BI \-p
|
||||
Repair the filesystem without user interaction if it can be done safely.
|
||||
.TP
|
||||
.BI \-r
|
||||
Repair the filesystem interactively.
|
||||
.TP
|
||||
.BI \-v
|
||||
Prints verbose debugging information while checking the exFAT filesystem.
|
||||
.TP
|
||||
.BI \-V
|
||||
Prints the version number and exits.
|
||||
.TP
|
||||
.B \-y
|
||||
Repair the filesystem answering yes to all questions.
|
||||
.SH SEE ALSO
|
||||
.BR fsck (8),
|
||||
.BR fstab (5),
|
||||
@@ -0,0 +1,111 @@
|
||||
.TH mkfs.exfat 8
|
||||
.SH NAME
|
||||
mkfs.exfat \- create an exFAT filesystem
|
||||
.SH SYNOPSIS
|
||||
.B mkfs.exfat
|
||||
[
|
||||
.B \-b
|
||||
.I boundary_alignment
|
||||
] [
|
||||
.B \-c
|
||||
.I cluster_size
|
||||
] [
|
||||
.B \-f
|
||||
] [
|
||||
.B \-h
|
||||
] [
|
||||
.B \-L
|
||||
.I volume_label
|
||||
] [
|
||||
.B \-\-pack\-bitmap
|
||||
] [
|
||||
.B \-v
|
||||
]
|
||||
.I device
|
||||
.br
|
||||
.B mkfs.exfat \-V
|
||||
.SH DESCRIPTION
|
||||
.B mkfs.exfat
|
||||
creates an exFAT filesystem by writing on a special
|
||||
file using the values found in the arguments of the command line.
|
||||
It is invoked automatically by
|
||||
.BR mkfs (8)
|
||||
when it is given the
|
||||
.B \-t exfat
|
||||
option.
|
||||
.PP
|
||||
As an example, to make a filesystem on the first partition on the first
|
||||
SCSI disk, use:
|
||||
.IP
|
||||
.B mkfs.exfat /dev/sda1
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-b ", " \-\-boundary\-align =\fIalignment\fR
|
||||
Specifies the alignment for the FAT and the start of the cluster heap.
|
||||
The \fIalignment\fR argument is specified in bytes or may be specified with
|
||||
\fBm\fR/\fBM\fR suffix for mebibytes or \fBk\fR/\fBK\fR suffix for kibibytes
|
||||
and should be a power of two.
|
||||
Some media like SD cards need this for optimal performance and endurance,
|
||||
in which case \fIalignment\fR should be set to half of the card's native
|
||||
boundary unit size.
|
||||
If the card's native boundary unit size is not known, refer to the following
|
||||
table of boundary unit sizes recommended by the SD Card Association.
|
||||
.\" source: SD Specifications Part 2: File System Specification Version 3.00
|
||||
.TS
|
||||
center;
|
||||
cb1s6cbcb,nnnn.
|
||||
Card Capacity Range Cluster Size Boundary Unit
|
||||
_
|
||||
\[<=]8 MiB 8 KiB 8 KiB
|
||||
>8 MiB \[<=]64 MiB 16 KiB 16 KiB
|
||||
>64 MiB \[<=]256 MiB 16 KiB 32 KiB
|
||||
>256 MiB \[<=]1 GiB 16 KiB 64 KiB
|
||||
>1 GiB \[<=]2 GiB 32 KiB 64 KiB
|
||||
>2 GiB \[<=]32 GiB 32 KiB 4 MiB
|
||||
>32 GiB \[<=]128 GiB 128 KiB 16 MiB
|
||||
>128 GiB \[<=]512 GiB 256 KiB 32 MiB
|
||||
>512 GiB \[<=]2 TiB 512 KiB 64 MiB
|
||||
.TE
|
||||
.TP
|
||||
.BR \-c ", " \-\-cluster\-size =\fIsize\fR
|
||||
Specifies the cluster size of the exFAT file system.
|
||||
The \fIsize\fR argument is specified in bytes or may be specified with
|
||||
\fBm\fR/\fBM\fR suffix for mebibytes or \fBk\fR/\fBK\fR suffix for kibibytes
|
||||
and must be a power of two.
|
||||
.TP
|
||||
.BR \-f ", " \-\-full\-format
|
||||
Performs a full format.
|
||||
This zeros the entire disk device while creating the exFAT filesystem.
|
||||
.TP
|
||||
.BR \-h ", " \-\-help
|
||||
Prints the help and exit.
|
||||
.TP
|
||||
.BR \-L ", " \-\-volume\-label =\fIlabel\fR
|
||||
Specifies the volume label to be associated with the exFAT filesystem.
|
||||
.TP
|
||||
.B \-\-pack\-bitmap
|
||||
Attempts to relocate the exFAT allocation bitmap so that it ends at the
|
||||
alignment boundary immediately following the FAT rather than beginning at that
|
||||
boundary.
|
||||
This strictly violates the SD card specification but may improve performance
|
||||
and endurance on SD cards and other flash media not designed for use with exFAT
|
||||
by allowing file-system metadata updates to touch fewer flash allocation units.
|
||||
Furthermore, many SD cards and other flash devices specially optimize the
|
||||
allocation unit where the FAT resides so as to support tiny writes with reduced
|
||||
write amplification but expect only larger writes in subsequent allocation
|
||||
units \[em] where the exFAT bitmap would be placed by default.
|
||||
Specifying \fB\-\-pack\-bitmap\fR attempts to avoid the potential problems
|
||||
associated with issuing many small writes to the bitmap by making it share an
|
||||
allocation unit with the FAT.
|
||||
If there is insufficient space for the bitmap there, then this option will have
|
||||
no effect, and the bitmap will be aligned at the boundary as by default.
|
||||
.TP
|
||||
.BR \-v ", " \-\-verbose
|
||||
Prints verbose debugging information while creating the exFAT filesystem.
|
||||
.TP
|
||||
.BR \-V ", " \-\-version
|
||||
Prints the version number and exits.
|
||||
.SH SEE ALSO
|
||||
.BR mkfs (8),
|
||||
.BR mount (8),
|
||||
@@ -0,0 +1,46 @@
|
||||
.TH tune.exfat 8
|
||||
.SH NAME
|
||||
tune.exfat \- adjust tunable filesystem parameters on an exFAT filesystem
|
||||
.SH SYNOPSIS
|
||||
.B tune.exfat
|
||||
[
|
||||
.B \-l
|
||||
.I print-label
|
||||
] [
|
||||
.B \-L
|
||||
.I set-label
|
||||
] [
|
||||
.B \-i
|
||||
.I print-serial
|
||||
] [
|
||||
.B \-I
|
||||
.I set-serial
|
||||
] [
|
||||
.B \-v
|
||||
]
|
||||
.I device
|
||||
.br
|
||||
.B tune.exfat \-V
|
||||
.SH DESCRIPTION
|
||||
.B tune.exfat
|
||||
adjust tunable ondisk parameters of an existing exFAT filesystem.
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-l " print-label"
|
||||
Print the volume label of the exFAT filesystem.
|
||||
.TP
|
||||
.BI \-L " set-label"
|
||||
Set the volume label of the filesystem to the provided argument.
|
||||
.TP
|
||||
.BI \-i " print-serial"
|
||||
Print the volume serial of the exFAT filesystem.
|
||||
.TP
|
||||
.BI \-I " set-serial"
|
||||
Set the volume serial of the filesystem to the provided argument.
|
||||
.TP
|
||||
.BI \-v
|
||||
Prints verbose debugging information while extracting or tuning parameters of the exFAT filesystem.
|
||||
.TP
|
||||
.B \-V
|
||||
Prints the version number and exits.
|
||||
+4
-46
@@ -1,48 +1,6 @@
|
||||
#
|
||||
# Makefile.am (30.03.15)
|
||||
# Automake source.
|
||||
#
|
||||
# Free exFAT implementation.
|
||||
# Copyright (C) 2011-2018 Andrew Nayenko
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common
|
||||
mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.a
|
||||
|
||||
sbin_PROGRAMS = mkexfatfs
|
||||
dist_man8_MANS = mkexfatfs.8
|
||||
mkexfatfs_SOURCES = \
|
||||
cbm.c \
|
||||
cbm.h \
|
||||
fat.c \
|
||||
fat.h \
|
||||
main.c \
|
||||
mkexfat.c \
|
||||
mkexfat.h \
|
||||
rootdir.c \
|
||||
rootdir.h \
|
||||
uct.c \
|
||||
uct.h \
|
||||
uctc.c \
|
||||
uctc.h \
|
||||
vbr.c \
|
||||
vbr.h
|
||||
mkexfatfs_CPPFLAGS = -I$(top_srcdir)/libexfat
|
||||
mkexfatfs_LDADD = ../libexfat/libexfat.a
|
||||
sbin_PROGRAMS = mkfs.exfat
|
||||
|
||||
install-exec-hook:
|
||||
ln -sf $(sbin_PROGRAMS) $(DESTDIR)$(sbindir)/mkfs.exfat
|
||||
|
||||
uninstall-hook:
|
||||
rm -f $(DESTDIR)$(sbindir)/mkfs.exfat
|
||||
mkfs_exfat_SOURCES = mkfs.c upcase.c mkfs.h
|
||||
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
cbm.c (09.11.10)
|
||||
Clusters Bitmap creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "cbm.h"
|
||||
#include "fat.h"
|
||||
#include "uct.h"
|
||||
#include "rootdir.h"
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
static off_t cbm_alignment(void)
|
||||
{
|
||||
return get_cluster_size();
|
||||
}
|
||||
|
||||
static off_t cbm_size(void)
|
||||
{
|
||||
return DIV_ROUND_UP(
|
||||
(get_volume_size() - get_position(&cbm)) / get_cluster_size(),
|
||||
CHAR_BIT);
|
||||
}
|
||||
|
||||
static int cbm_write(struct exfat_dev* dev)
|
||||
{
|
||||
uint32_t allocated_clusters =
|
||||
DIV_ROUND_UP(cbm.get_size(), get_cluster_size()) +
|
||||
DIV_ROUND_UP(uct.get_size(), get_cluster_size()) +
|
||||
DIV_ROUND_UP(rootdir.get_size(), get_cluster_size());
|
||||
size_t bitmap_size = ROUND_UP(allocated_clusters, CHAR_BIT);
|
||||
bitmap_t* bitmap = malloc(BMAP_SIZE(bitmap_size));
|
||||
size_t i;
|
||||
|
||||
if (bitmap == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate bitmap of %zu bytes",
|
||||
BMAP_SIZE(bitmap_size));
|
||||
return 1;
|
||||
}
|
||||
memset(bitmap, 0, BMAP_SIZE(bitmap_size));
|
||||
|
||||
for (i = 0; i < bitmap_size; i++)
|
||||
if (i < allocated_clusters)
|
||||
BMAP_SET(bitmap, i);
|
||||
if (exfat_write(dev, bitmap, bitmap_size / CHAR_BIT) < 0)
|
||||
{
|
||||
free(bitmap);
|
||||
exfat_error("failed to write bitmap of %zu bytes",
|
||||
bitmap_size / CHAR_BIT);
|
||||
return 1;
|
||||
}
|
||||
free(bitmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct fs_object cbm =
|
||||
{
|
||||
.get_alignment = cbm_alignment,
|
||||
.get_size = cbm_size,
|
||||
.write = cbm_write,
|
||||
};
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
cbm.h (09.11.10)
|
||||
Clusters Bitmap creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_CBM_H_INCLUDED
|
||||
#define MKFS_CBM_H_INCLUDED
|
||||
|
||||
#include "mkexfat.h"
|
||||
|
||||
extern const struct fs_object cbm;
|
||||
|
||||
#endif /* ifndef MKFS_CBM_H_INCLUDED */
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
fat.c (09.11.10)
|
||||
File Allocation Table creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "fat.h"
|
||||
#include "cbm.h"
|
||||
#include "uct.h"
|
||||
#include "rootdir.h"
|
||||
#include <unistd.h>
|
||||
|
||||
static off_t fat_alignment(void)
|
||||
{
|
||||
return (off_t) 128 * get_sector_size();
|
||||
}
|
||||
|
||||
static off_t fat_size(void)
|
||||
{
|
||||
return get_volume_size() / get_cluster_size() * sizeof(cluster_t);
|
||||
}
|
||||
|
||||
static cluster_t fat_write_entry(struct exfat_dev* dev, cluster_t cluster,
|
||||
cluster_t value)
|
||||
{
|
||||
le32_t fat_entry = cpu_to_le32(value);
|
||||
if (exfat_write(dev, &fat_entry, sizeof(fat_entry)) < 0)
|
||||
{
|
||||
exfat_error("failed to write FAT entry 0x%x", value);
|
||||
return 0;
|
||||
}
|
||||
return cluster + 1;
|
||||
}
|
||||
|
||||
static cluster_t fat_write_entries(struct exfat_dev* dev, cluster_t cluster,
|
||||
uint64_t length)
|
||||
{
|
||||
cluster_t end = cluster + DIV_ROUND_UP(length, get_cluster_size());
|
||||
|
||||
while (cluster < end - 1)
|
||||
{
|
||||
cluster = fat_write_entry(dev, cluster, cluster + 1);
|
||||
if (cluster == 0)
|
||||
return 0;
|
||||
}
|
||||
return fat_write_entry(dev, cluster, EXFAT_CLUSTER_END);
|
||||
}
|
||||
|
||||
static int fat_write(struct exfat_dev* dev)
|
||||
{
|
||||
cluster_t c = 0;
|
||||
|
||||
if (!(c = fat_write_entry(dev, c, 0xfffffff8))) /* media type */
|
||||
return 1;
|
||||
if (!(c = fat_write_entry(dev, c, 0xffffffff))) /* some weird constant */
|
||||
return 1;
|
||||
if (!(c = fat_write_entries(dev, c, cbm.get_size())))
|
||||
return 1;
|
||||
if (!(c = fat_write_entries(dev, c, uct.get_size())))
|
||||
return 1;
|
||||
if (!(c = fat_write_entries(dev, c, rootdir.get_size())))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct fs_object fat =
|
||||
{
|
||||
.get_alignment = fat_alignment,
|
||||
.get_size = fat_size,
|
||||
.write = fat_write,
|
||||
};
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
fat.h (09.11.10)
|
||||
File Allocation Table creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_FAT_H_INCLUDED
|
||||
#define MKFS_FAT_H_INCLUDED
|
||||
|
||||
#include "mkexfat.h"
|
||||
|
||||
extern const struct fs_object fat;
|
||||
|
||||
#endif /* ifndef MKFS_FAT_H_INCLUDED */
|
||||
-255
@@ -1,255 +0,0 @@
|
||||
/*
|
||||
main.c (15.08.10)
|
||||
Creates exFAT file system.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "mkexfat.h"
|
||||
#include "vbr.h"
|
||||
#include "fat.h"
|
||||
#include "cbm.h"
|
||||
#include "uct.h"
|
||||
#include "rootdir.h"
|
||||
#include <exfat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
const struct fs_object* objects[] =
|
||||
{
|
||||
&vbr,
|
||||
&vbr,
|
||||
&fat,
|
||||
/* clusters heap */
|
||||
&cbm,
|
||||
&uct,
|
||||
&rootdir,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
int sector_bits;
|
||||
int spc_bits;
|
||||
off_t volume_size;
|
||||
le16_t volume_label[EXFAT_ENAME_MAX + 1];
|
||||
uint32_t volume_serial;
|
||||
uint64_t first_sector;
|
||||
}
|
||||
param;
|
||||
|
||||
int get_sector_bits(void)
|
||||
{
|
||||
return param.sector_bits;
|
||||
}
|
||||
|
||||
int get_spc_bits(void)
|
||||
{
|
||||
return param.spc_bits;
|
||||
}
|
||||
|
||||
off_t get_volume_size(void)
|
||||
{
|
||||
return param.volume_size;
|
||||
}
|
||||
|
||||
const le16_t* get_volume_label(void)
|
||||
{
|
||||
return param.volume_label;
|
||||
}
|
||||
|
||||
uint32_t get_volume_serial(void)
|
||||
{
|
||||
return param.volume_serial;
|
||||
}
|
||||
|
||||
uint64_t get_first_sector(void)
|
||||
{
|
||||
return param.first_sector;
|
||||
}
|
||||
|
||||
int get_sector_size(void)
|
||||
{
|
||||
return 1 << get_sector_bits();
|
||||
}
|
||||
|
||||
int get_cluster_size(void)
|
||||
{
|
||||
return get_sector_size() << get_spc_bits();
|
||||
}
|
||||
|
||||
static int setup_spc_bits(int sector_bits, int user_defined, off_t volume_size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (user_defined != -1)
|
||||
{
|
||||
off_t cluster_size = 1 << sector_bits << user_defined;
|
||||
if (volume_size / cluster_size > EXFAT_LAST_DATA_CLUSTER)
|
||||
{
|
||||
struct exfat_human_bytes chb, vhb;
|
||||
|
||||
exfat_humanize_bytes(cluster_size, &chb);
|
||||
exfat_humanize_bytes(volume_size, &vhb);
|
||||
exfat_error("cluster size %"PRIu64" %s is too small for "
|
||||
"%"PRIu64" %s volume, try -s %d",
|
||||
chb.value, chb.unit,
|
||||
vhb.value, vhb.unit,
|
||||
1 << setup_spc_bits(sector_bits, -1, volume_size));
|
||||
return -1;
|
||||
}
|
||||
return user_defined;
|
||||
}
|
||||
|
||||
if (volume_size < 256LL * 1024 * 1024)
|
||||
return MAX(0, 12 - sector_bits); /* 4 KB */
|
||||
if (volume_size < 32LL * 1024 * 1024 * 1024)
|
||||
return MAX(0, 15 - sector_bits); /* 32 KB */
|
||||
|
||||
for (i = 17; ; i++) /* 128 KB or more */
|
||||
if (DIV_ROUND_UP(volume_size, 1 << i) <= EXFAT_LAST_DATA_CLUSTER)
|
||||
return MAX(0, i - sector_bits);
|
||||
}
|
||||
|
||||
static int setup_volume_label(le16_t label[EXFAT_ENAME_MAX + 1], const char* s)
|
||||
{
|
||||
memset(label, 0, (EXFAT_ENAME_MAX + 1) * sizeof(le16_t));
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
return exfat_utf8_to_utf16(label, s, EXFAT_ENAME_MAX + 1, strlen(s));
|
||||
}
|
||||
|
||||
static uint32_t setup_volume_serial(uint32_t user_defined)
|
||||
{
|
||||
struct timeval now;
|
||||
|
||||
if (user_defined != 0)
|
||||
return user_defined;
|
||||
|
||||
if (gettimeofday(&now, NULL) != 0)
|
||||
{
|
||||
exfat_error("failed to form volume id");
|
||||
return 0;
|
||||
}
|
||||
return (now.tv_sec << 20) | now.tv_usec;
|
||||
}
|
||||
|
||||
static int setup(struct exfat_dev* dev, int sector_bits, int spc_bits,
|
||||
const char* volume_label, uint32_t volume_serial,
|
||||
uint64_t first_sector)
|
||||
{
|
||||
param.sector_bits = sector_bits;
|
||||
param.first_sector = first_sector;
|
||||
param.volume_size = exfat_get_size(dev);
|
||||
|
||||
param.spc_bits = setup_spc_bits(sector_bits, spc_bits, param.volume_size);
|
||||
if (param.spc_bits == -1)
|
||||
return 1;
|
||||
|
||||
if (setup_volume_label(param.volume_label, volume_label) != 0)
|
||||
return 1;
|
||||
|
||||
param.volume_serial = setup_volume_serial(volume_serial);
|
||||
if (param.volume_serial == 0)
|
||||
return 1;
|
||||
|
||||
return mkfs(dev, param.volume_size);
|
||||
}
|
||||
|
||||
static int logarithm2(int n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(int) * CHAR_BIT - 1; i++)
|
||||
if ((1 << i) == n)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void usage(const char* prog)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-i volume-id] [-n label] "
|
||||
"[-p partition-first-sector] "
|
||||
"[-s sectors-per-cluster] [-V] <device>\n", prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* spec = NULL;
|
||||
int opt;
|
||||
int spc_bits = -1;
|
||||
const char* volume_label = NULL;
|
||||
uint32_t volume_serial = 0;
|
||||
uint64_t first_sector = 0;
|
||||
struct exfat_dev* dev;
|
||||
|
||||
printf("mkexfatfs %s\n", VERSION);
|
||||
|
||||
while ((opt = getopt(argc, argv, "i:n:p:s:V")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'i':
|
||||
volume_serial = strtol(optarg, NULL, 16);
|
||||
break;
|
||||
case 'n':
|
||||
volume_label = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
first_sector = strtoll(optarg, NULL, 10);
|
||||
break;
|
||||
case 's':
|
||||
spc_bits = logarithm2(atoi(optarg));
|
||||
if (spc_bits < 0)
|
||||
{
|
||||
exfat_error("invalid option value: '%s'", optarg);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
puts("Copyright (C) 2011-2018 Andrew Nayenko");
|
||||
return 0;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (argc - optind != 1)
|
||||
usage(argv[0]);
|
||||
spec = argv[optind];
|
||||
|
||||
dev = exfat_open(spec, EXFAT_MODE_RW);
|
||||
if (dev == NULL)
|
||||
return 1;
|
||||
if (setup(dev, 9, spc_bits, volume_label, volume_serial,
|
||||
first_sector) != 0)
|
||||
{
|
||||
exfat_close(dev);
|
||||
return 1;
|
||||
}
|
||||
if (exfat_close(dev) != 0)
|
||||
return 1;
|
||||
printf("File system created successfully.\n");
|
||||
return 0;
|
||||
}
|
||||
-162
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
mkexfat.c (22.04.12)
|
||||
FS creation engine.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "mkexfat.h"
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static int check_size(off_t volume_size)
|
||||
{
|
||||
const struct fs_object** pp;
|
||||
off_t position = 0;
|
||||
|
||||
for (pp = objects; *pp; pp++)
|
||||
{
|
||||
position = ROUND_UP(position, (*pp)->get_alignment());
|
||||
position += (*pp)->get_size();
|
||||
}
|
||||
|
||||
if (position > volume_size)
|
||||
{
|
||||
struct exfat_human_bytes vhb;
|
||||
|
||||
exfat_humanize_bytes(volume_size, &vhb);
|
||||
exfat_error("too small device (%"PRIu64" %s)", vhb.value, vhb.unit);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int erase_object(struct exfat_dev* dev, const void* block,
|
||||
off_t block_size, off_t start, off_t size)
|
||||
{
|
||||
const off_t block_count = DIV_ROUND_UP(size, block_size);
|
||||
off_t i;
|
||||
|
||||
if (exfat_seek(dev, start, SEEK_SET) == (off_t) -1)
|
||||
{
|
||||
exfat_error("seek to 0x%"PRIx64" failed", start);
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < size; i += block_size)
|
||||
{
|
||||
if (exfat_write(dev, block, MIN(size - i, block_size)) < 0)
|
||||
{
|
||||
exfat_error("failed to erase block %"PRIu64"/%"PRIu64
|
||||
" at 0x%"PRIx64, i + 1, block_count, start);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int erase(struct exfat_dev* dev)
|
||||
{
|
||||
const struct fs_object** pp;
|
||||
off_t position = 0;
|
||||
const off_t block_size = 1024 * 1024;
|
||||
void* block = malloc(block_size);
|
||||
|
||||
if (block == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate erase block");
|
||||
return 1;
|
||||
}
|
||||
memset(block, 0, block_size);
|
||||
|
||||
for (pp = objects; *pp; pp++)
|
||||
{
|
||||
position = ROUND_UP(position, (*pp)->get_alignment());
|
||||
if (erase_object(dev, block, block_size, position,
|
||||
(*pp)->get_size()) != 0)
|
||||
{
|
||||
free(block);
|
||||
return 1;
|
||||
}
|
||||
position += (*pp)->get_size();
|
||||
}
|
||||
|
||||
free(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create(struct exfat_dev* dev)
|
||||
{
|
||||
const struct fs_object** pp;
|
||||
off_t position = 0;
|
||||
|
||||
for (pp = objects; *pp; pp++)
|
||||
{
|
||||
position = ROUND_UP(position, (*pp)->get_alignment());
|
||||
if (exfat_seek(dev, position, SEEK_SET) == (off_t) -1)
|
||||
{
|
||||
exfat_error("seek to 0x%"PRIx64" failed", position);
|
||||
return 1;
|
||||
}
|
||||
if ((*pp)->write(dev) != 0)
|
||||
return 1;
|
||||
position += (*pp)->get_size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkfs(struct exfat_dev* dev, off_t volume_size)
|
||||
{
|
||||
if (check_size(volume_size) != 0)
|
||||
return 1;
|
||||
|
||||
fputs("Creating... ", stdout);
|
||||
fflush(stdout);
|
||||
if (erase(dev) != 0)
|
||||
return 1;
|
||||
if (create(dev) != 0)
|
||||
return 1;
|
||||
puts("done.");
|
||||
|
||||
fputs("Flushing... ", stdout);
|
||||
fflush(stdout);
|
||||
if (exfat_fsync(dev) != 0)
|
||||
return 1;
|
||||
puts("done.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_t get_position(const struct fs_object* object)
|
||||
{
|
||||
const struct fs_object** pp;
|
||||
off_t position = 0;
|
||||
|
||||
for (pp = objects; *pp; pp++)
|
||||
{
|
||||
position = ROUND_UP(position, (*pp)->get_alignment());
|
||||
if (*pp == object)
|
||||
return position;
|
||||
position += (*pp)->get_size();
|
||||
}
|
||||
exfat_bug("unknown object");
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
mkexfat.h (09.11.10)
|
||||
FS creation engine.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_MKEXFAT_H_INCLUDED
|
||||
#define MKFS_MKEXFAT_H_INCLUDED
|
||||
|
||||
#include <exfat.h>
|
||||
|
||||
struct fs_object
|
||||
{
|
||||
off_t (*get_alignment)(void);
|
||||
off_t (*get_size)(void);
|
||||
int (*write)(struct exfat_dev* dev);
|
||||
};
|
||||
|
||||
extern const struct fs_object* objects[];
|
||||
|
||||
int get_sector_bits(void);
|
||||
int get_spc_bits(void);
|
||||
off_t get_volume_size(void);
|
||||
const le16_t* get_volume_label(void);
|
||||
uint32_t get_volume_serial(void);
|
||||
uint64_t get_first_sector(void);
|
||||
int get_sector_size(void);
|
||||
int get_cluster_size(void);
|
||||
|
||||
int mkfs(struct exfat_dev* dev, off_t volume_size);
|
||||
off_t get_position(const struct fs_object* object);
|
||||
|
||||
#endif /* ifndef MKFS_MKEXFAT_H_INCLUDED */
|
||||
@@ -1,71 +0,0 @@
|
||||
.\" Copyright (C) 2011-2018 Andrew Nayenko
|
||||
.\"
|
||||
.TH MKEXFATFS 8 "January 2014"
|
||||
.SH NAME
|
||||
.B mkexfatfs
|
||||
\- create an exFAT file system
|
||||
.SH SYNOPSIS
|
||||
.B mkexfatfs
|
||||
[
|
||||
.B \-i
|
||||
.I volume-id
|
||||
]
|
||||
[
|
||||
.B \-n
|
||||
.I volume-name
|
||||
]
|
||||
[
|
||||
.B \-p
|
||||
.I partition-first-sector
|
||||
]
|
||||
[
|
||||
.B \-s
|
||||
.I sectors-per-cluster
|
||||
]
|
||||
[
|
||||
.B \-V
|
||||
]
|
||||
.I device
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B mkexfatfs
|
||||
creates an exFAT file system on a block device.
|
||||
.I device
|
||||
is a special file corresponding to the partition on the device. Note that if
|
||||
this is an MBR partition then the file system type should be set to 0x07
|
||||
(NTFS/exFAT) otherwise other operating systems may refuse to mount the
|
||||
file system.
|
||||
|
||||
.SH OPTIONS
|
||||
Command line options available:
|
||||
.TP
|
||||
.BI \-i " volume-id"
|
||||
A 32-bit hexadecimal number. By default a value based on current time is set.
|
||||
.TP
|
||||
.BI \-n " volume-name"
|
||||
Volume name (label), up to 15 characters. By default no label is set.
|
||||
.TP
|
||||
.BI \-p " partition-first-sector"
|
||||
First sector of the partition starting from the beginning of the whole disk.
|
||||
exFAT super block has a field for this value but in fact it's optional and
|
||||
does not affect anything. Default is 0.
|
||||
.TP
|
||||
.BI \-s " sectors-per-cluster"
|
||||
Number of physical sectors per cluster (cluster is an allocation unit in
|
||||
exFAT). Must be a power of 2, i.e. 1, 2, 4, 8, etc. Cluster size can not
|
||||
exceed 32 MB. Default cluster sizes are:
|
||||
4 KB if volume size is less than 256 MB,
|
||||
32 KB if volume size is from 256 MB to 32 GB,
|
||||
128 KB if volume size is 32 GB or larger.
|
||||
.TP
|
||||
.BI \-V
|
||||
Print version and copyright.
|
||||
|
||||
.SH EXIT CODES
|
||||
Zero is returned on successful creation. Any other code means an error.
|
||||
|
||||
.SH AUTHOR
|
||||
Andrew Nayenko
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR mkfs (8), fdisk (8)
|
||||
+712
@@ -0,0 +1,712 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "exfat_ondisk.h"
|
||||
#include "libexfat.h"
|
||||
#include "mkfs.h"
|
||||
|
||||
struct exfat_mkfs_info finfo;
|
||||
|
||||
/* random serial generator based on current time */
|
||||
static unsigned int get_new_serial(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts)) {
|
||||
/* set 0000-0000 on error */
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
|
||||
return (unsigned int)(ts.tv_nsec << 12 | ts.tv_sec);
|
||||
}
|
||||
|
||||
static void exfat_setup_boot_sector(struct pbr *ppbr,
|
||||
struct exfat_blk_dev *bd, struct exfat_user_input *ui)
|
||||
{
|
||||
struct bpb64 *pbpb = &ppbr->bpb;
|
||||
struct bsx64 *pbsx = &ppbr->bsx;
|
||||
unsigned int i;
|
||||
|
||||
/* Fill exfat BIOS parameter block */
|
||||
pbpb->jmp_boot[0] = 0xeb;
|
||||
pbpb->jmp_boot[1] = 0x76;
|
||||
pbpb->jmp_boot[2] = 0x90;
|
||||
memcpy(pbpb->oem_name, "EXFAT ", 8);
|
||||
memset(pbpb->res_zero, 0, 53);
|
||||
|
||||
/* Fill exfat extend BIOS parameter block */
|
||||
pbsx->vol_offset = cpu_to_le64(bd->offset / bd->sector_size);
|
||||
pbsx->vol_length = cpu_to_le64(bd->size / bd->sector_size);
|
||||
pbsx->fat_offset = cpu_to_le32(finfo.fat_byte_off / bd->sector_size);
|
||||
pbsx->fat_length = cpu_to_le32(finfo.fat_byte_len / bd->sector_size);
|
||||
pbsx->clu_offset = cpu_to_le32(finfo.clu_byte_off / bd->sector_size);
|
||||
pbsx->clu_count = cpu_to_le32(finfo.total_clu_cnt);
|
||||
pbsx->root_cluster = cpu_to_le32(finfo.root_start_clu);
|
||||
pbsx->vol_serial = cpu_to_le32(finfo.volume_serial);
|
||||
pbsx->vol_flags = 0;
|
||||
pbsx->sect_size_bits = bd->sector_size_bits;
|
||||
pbsx->sect_per_clus_bits = 0;
|
||||
/* Compute base 2 logarithm of ui->cluster_size / bd->sector_size */
|
||||
for (i = ui->cluster_size / bd->sector_size; i > 1; i /= 2)
|
||||
pbsx->sect_per_clus_bits++;
|
||||
pbsx->num_fats = 1;
|
||||
/* fs_version[0] : minor and fs_version[1] : major */
|
||||
pbsx->fs_version[0] = 0;
|
||||
pbsx->fs_version[1] = 1;
|
||||
pbsx->phy_drv_no = 0x80;
|
||||
memset(pbsx->reserved2, 0, 7);
|
||||
|
||||
memset(ppbr->boot_code, 0, 390);
|
||||
ppbr->signature = cpu_to_le16(PBR_SIGNATURE);
|
||||
|
||||
exfat_debug("Volume Offset(sectors) : %" PRIu64 "\n",
|
||||
le64_to_cpu(pbsx->vol_offset));
|
||||
exfat_debug("Volume Length(sectors) : %" PRIu64 "\n",
|
||||
le64_to_cpu(pbsx->vol_length));
|
||||
exfat_debug("FAT Offset(sector offset) : %u\n",
|
||||
le32_to_cpu(pbsx->fat_offset));
|
||||
exfat_debug("FAT Length(sectors) : %u\n",
|
||||
le32_to_cpu(pbsx->fat_length));
|
||||
exfat_debug("Cluster Heap Offset (sector offset) : %u\n",
|
||||
le32_to_cpu(pbsx->clu_offset));
|
||||
exfat_debug("Cluster Count : %u\n",
|
||||
le32_to_cpu(pbsx->clu_count));
|
||||
exfat_debug("Root Cluster (cluster offset) : %u\n",
|
||||
le32_to_cpu(pbsx->root_cluster));
|
||||
exfat_debug("Volume Serial : 0x%x\n", le32_to_cpu(pbsx->vol_serial));
|
||||
exfat_debug("Sector Size Bits : %u\n",
|
||||
pbsx->sect_size_bits);
|
||||
exfat_debug("Sector per Cluster bits : %u\n",
|
||||
pbsx->sect_per_clus_bits);
|
||||
}
|
||||
|
||||
static int exfat_write_boot_sector(struct exfat_blk_dev *bd,
|
||||
struct exfat_user_input *ui, unsigned int *checksum,
|
||||
bool is_backup)
|
||||
{
|
||||
struct pbr *ppbr;
|
||||
unsigned int sec_idx = BOOT_SEC_IDX;
|
||||
int ret = 0;
|
||||
|
||||
if (is_backup)
|
||||
sec_idx += BACKUP_BOOT_SEC_IDX;
|
||||
|
||||
ppbr = malloc(bd->sector_size);
|
||||
if (!ppbr) {
|
||||
exfat_err("Cannot allocate pbr: out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
memset(ppbr, 0, bd->sector_size);
|
||||
|
||||
exfat_setup_boot_sector(ppbr, bd, ui);
|
||||
|
||||
/* write main boot sector */
|
||||
ret = exfat_write_sector(bd, ppbr, sec_idx);
|
||||
if (ret < 0) {
|
||||
exfat_err("main boot sector write failed\n");
|
||||
ret = -1;
|
||||
goto free_ppbr;
|
||||
}
|
||||
|
||||
boot_calc_checksum((unsigned char *)ppbr, bd->sector_size,
|
||||
true, checksum);
|
||||
|
||||
free_ppbr:
|
||||
free(ppbr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd,
|
||||
unsigned int *checksum, bool is_backup)
|
||||
{
|
||||
char *peb;
|
||||
__le16 *peb_signature;
|
||||
int ret = 0;
|
||||
int i;
|
||||
unsigned int sec_idx = EXBOOT_SEC_IDX;
|
||||
|
||||
peb = malloc(bd->sector_size);
|
||||
if (!peb)
|
||||
return -1;
|
||||
|
||||
if (is_backup)
|
||||
sec_idx += BACKUP_BOOT_SEC_IDX;
|
||||
|
||||
memset(peb, 0, bd->sector_size);
|
||||
peb_signature = (__le16*) (peb + bd->sector_size - 2);
|
||||
*peb_signature = cpu_to_le16(PBR_SIGNATURE);
|
||||
for (i = 0; i < EXBOOT_SEC_NUM; i++) {
|
||||
if (exfat_write_sector(bd, peb, sec_idx++)) {
|
||||
exfat_err("extended boot sector write failed\n");
|
||||
ret = -1;
|
||||
goto free_peb;
|
||||
}
|
||||
|
||||
boot_calc_checksum((unsigned char *) peb, bd->sector_size,
|
||||
false, checksum);
|
||||
}
|
||||
|
||||
free_peb:
|
||||
free(peb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exfat_write_oem_sector(struct exfat_blk_dev *bd,
|
||||
unsigned int *checksum, bool is_backup)
|
||||
{
|
||||
char *oem;
|
||||
int ret = 0;
|
||||
unsigned int sec_idx = OEM_SEC_IDX;
|
||||
|
||||
oem = malloc(bd->sector_size);
|
||||
if (!oem)
|
||||
return -1;
|
||||
|
||||
if (is_backup)
|
||||
sec_idx += BACKUP_BOOT_SEC_IDX;
|
||||
|
||||
memset(oem, 0xFF, bd->sector_size);
|
||||
ret = exfat_write_sector(bd, oem, sec_idx);
|
||||
if (ret) {
|
||||
exfat_err("oem sector write failed\n");
|
||||
ret = -1;
|
||||
goto free_oem;
|
||||
}
|
||||
|
||||
boot_calc_checksum((unsigned char *)oem, bd->sector_size, false,
|
||||
checksum);
|
||||
|
||||
/* Zero out reserved sector */
|
||||
memset(oem, 0, bd->sector_size);
|
||||
ret = exfat_write_sector(bd, oem, sec_idx + 1);
|
||||
if (ret) {
|
||||
exfat_err("reserved sector write failed\n");
|
||||
ret = -1;
|
||||
goto free_oem;
|
||||
}
|
||||
|
||||
boot_calc_checksum((unsigned char *)oem, bd->sector_size, false,
|
||||
checksum);
|
||||
|
||||
free_oem:
|
||||
free(oem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd,
|
||||
struct exfat_user_input *ui, bool is_backup)
|
||||
{
|
||||
unsigned int checksum = 0;
|
||||
int ret;
|
||||
|
||||
ret = exfat_write_boot_sector(bd, ui, &checksum, is_backup);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = exfat_write_extended_boot_sectors(bd, &checksum, is_backup);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = exfat_write_oem_sector(bd, &checksum, is_backup);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return exfat_write_checksum_sector(bd, checksum, is_backup);
|
||||
}
|
||||
|
||||
static int write_fat_entry(int fd, __le32 clu,
|
||||
unsigned long long offset)
|
||||
{
|
||||
int nbyte;
|
||||
off_t fat_entry_offset = finfo.fat_byte_off + (offset * sizeof(__le32));
|
||||
|
||||
nbyte = pwrite(fd, (__u8 *) &clu, sizeof(__le32), fat_entry_offset);
|
||||
if (nbyte != sizeof(int)) {
|
||||
exfat_err("write failed, offset : %llu, clu : %x\n",
|
||||
offset, clu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_fat_entries(struct exfat_user_input *ui, int fd,
|
||||
unsigned int clu, unsigned int length)
|
||||
{
|
||||
int ret;
|
||||
unsigned int count;
|
||||
|
||||
count = clu + round_up(length, ui->cluster_size) / ui->cluster_size;
|
||||
|
||||
for (; clu < count - 1; clu++) {
|
||||
ret = write_fat_entry(fd, cpu_to_le32(clu + 1), clu);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = write_fat_entry(fd, cpu_to_le32(EXFAT_EOF_CLUSTER), clu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return clu;
|
||||
}
|
||||
|
||||
static int exfat_create_fat_table(struct exfat_blk_dev *bd,
|
||||
struct exfat_user_input *ui)
|
||||
{
|
||||
int ret, clu;
|
||||
|
||||
/* fat entry 0 should be media type field(0xF8) */
|
||||
ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xfffffff8), 0);
|
||||
if (ret) {
|
||||
exfat_err("fat 0 entry write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* fat entry 1 is historical precedence(0xFFFFFFFF) */
|
||||
ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xffffffff), 1);
|
||||
if (ret) {
|
||||
exfat_err("fat 1 entry write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* write bitmap entries */
|
||||
clu = write_fat_entries(ui, bd->dev_fd, EXFAT_FIRST_CLUSTER,
|
||||
finfo.bitmap_byte_len);
|
||||
if (clu < 0)
|
||||
return ret;
|
||||
|
||||
/* write upcase table entries */
|
||||
clu = write_fat_entries(ui, bd->dev_fd, clu + 1, finfo.ut_byte_len);
|
||||
if (clu < 0)
|
||||
return ret;
|
||||
|
||||
/* write root directory entries */
|
||||
clu = write_fat_entries(ui, bd->dev_fd, clu + 1, finfo.root_byte_len);
|
||||
if (clu < 0)
|
||||
return ret;
|
||||
|
||||
finfo.used_clu_cnt = clu + 1;
|
||||
exfat_debug("Total used cluster count : %d\n", finfo.used_clu_cnt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exfat_create_bitmap(struct exfat_blk_dev *bd)
|
||||
{
|
||||
char *bitmap;
|
||||
unsigned int i, nbytes;
|
||||
|
||||
bitmap = calloc(finfo.bitmap_byte_len, sizeof(*bitmap));
|
||||
if (!bitmap)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < finfo.used_clu_cnt - EXFAT_FIRST_CLUSTER; i++)
|
||||
exfat_set_bit(bd, bitmap, i);
|
||||
|
||||
nbytes = pwrite(bd->dev_fd, bitmap, finfo.bitmap_byte_len, finfo.bitmap_byte_off);
|
||||
if (nbytes != finfo.bitmap_byte_len) {
|
||||
exfat_err("write failed, nbytes : %d, bitmap_len : %d\n",
|
||||
nbytes, finfo.bitmap_byte_len);
|
||||
free(bitmap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(bitmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exfat_create_root_dir(struct exfat_blk_dev *bd,
|
||||
struct exfat_user_input *ui)
|
||||
{
|
||||
struct exfat_dentry ed[3];
|
||||
int dentries_len = sizeof(struct exfat_dentry) * 3;
|
||||
int nbytes;
|
||||
|
||||
/* Set volume label entry */
|
||||
ed[0].type = EXFAT_VOLUME;
|
||||
memset(ed[0].vol_label, 0, 22);
|
||||
memcpy(ed[0].vol_label, ui->volume_label, ui->volume_label_len);
|
||||
ed[0].vol_char_cnt = ui->volume_label_len/2;
|
||||
|
||||
/* Set bitmap entry */
|
||||
ed[1].type = EXFAT_BITMAP;
|
||||
ed[1].bitmap_flags = 0;
|
||||
ed[1].bitmap_start_clu = cpu_to_le32(EXFAT_FIRST_CLUSTER);
|
||||
ed[1].bitmap_size = cpu_to_le64(finfo.bitmap_byte_len);
|
||||
|
||||
/* Set upcase table entry */
|
||||
ed[2].type = EXFAT_UPCASE;
|
||||
ed[2].upcase_checksum = cpu_to_le32(0xe619d30d);
|
||||
ed[2].upcase_start_clu = cpu_to_le32(finfo.ut_start_clu);
|
||||
ed[2].upcase_size = cpu_to_le64(EXFAT_UPCASE_TABLE_SIZE);
|
||||
|
||||
nbytes = pwrite(bd->dev_fd, ed, dentries_len, finfo.root_byte_off);
|
||||
if (nbytes != dentries_len) {
|
||||
exfat_err("write failed, nbytes : %d, dentries_len : %d\n",
|
||||
nbytes, dentries_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fputs("Usage: mkfs.exfat\n"
|
||||
"\t-L | --volume-label=label Set volume label\n"
|
||||
"\t-c | --cluster-size=size(or suffixed by 'K' or 'M') Specify cluster size\n"
|
||||
"\t-b | --boundary-align=size(or suffixed by 'K' or 'M') Specify boundary alignment\n"
|
||||
"\t --pack-bitmap Move bitmap into FAT segment\n"
|
||||
"\t-f | --full-format Full format\n"
|
||||
"\t-V | --version Show version\n"
|
||||
"\t-v | --verbose Print debug\n"
|
||||
"\t-h | --help Show help\n",
|
||||
stderr);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define PACK_BITMAP (CHAR_MAX + 1)
|
||||
|
||||
static const struct option opts[] = {
|
||||
{"volume-label", required_argument, NULL, 'L' },
|
||||
{"cluster-size", required_argument, NULL, 'c' },
|
||||
{"boundary-align", required_argument, NULL, 'b' },
|
||||
{"pack-bitmap", no_argument, NULL, PACK_BITMAP },
|
||||
{"full-format", no_argument, NULL, 'f' },
|
||||
{"version", no_argument, NULL, 'V' },
|
||||
{"verbose", no_argument, NULL, 'v' },
|
||||
{"help", no_argument, NULL, 'h' },
|
||||
{"?", no_argument, NULL, '?' },
|
||||
{NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Moves the bitmap to just before the alignment boundary if there is space
|
||||
* between the boundary and the end of the FAT. This may allow the FAT and the
|
||||
* bitmap to share the same allocation unit on flash media, thereby improving
|
||||
* performance and endurance.
|
||||
*/
|
||||
static int exfat_pack_bitmap(const struct exfat_user_input *ui)
|
||||
{
|
||||
unsigned int fat_byte_end = finfo.fat_byte_off + finfo.fat_byte_len,
|
||||
bitmap_byte_len = finfo.bitmap_byte_len,
|
||||
bitmap_clu_len = round_up(bitmap_byte_len, ui->cluster_size),
|
||||
bitmap_clu_cnt, total_clu_cnt, new_bitmap_clu_len;
|
||||
|
||||
for (;;) {
|
||||
bitmap_clu_cnt = bitmap_clu_len / ui->cluster_size;
|
||||
if (finfo.clu_byte_off - bitmap_clu_len < fat_byte_end ||
|
||||
finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER -
|
||||
bitmap_clu_cnt)
|
||||
return -1;
|
||||
total_clu_cnt = finfo.total_clu_cnt + bitmap_clu_cnt;
|
||||
bitmap_byte_len = round_up(total_clu_cnt, 8) / 8;
|
||||
new_bitmap_clu_len = round_up(bitmap_byte_len, ui->cluster_size);
|
||||
if (new_bitmap_clu_len == bitmap_clu_len) {
|
||||
finfo.clu_byte_off -= bitmap_clu_len;
|
||||
finfo.total_clu_cnt = total_clu_cnt;
|
||||
finfo.bitmap_byte_off -= bitmap_clu_len;
|
||||
finfo.bitmap_byte_len = bitmap_byte_len;
|
||||
return 0;
|
||||
}
|
||||
bitmap_clu_len = new_bitmap_clu_len;
|
||||
}
|
||||
}
|
||||
|
||||
static int exfat_build_mkfs_info(struct exfat_blk_dev *bd,
|
||||
struct exfat_user_input *ui)
|
||||
{
|
||||
unsigned long long total_clu_cnt;
|
||||
int clu_len;
|
||||
|
||||
if (ui->cluster_size < bd->sector_size) {
|
||||
exfat_err("cluster size (%u bytes) is smaller than sector size (%u bytes)\n",
|
||||
ui->cluster_size, bd->sector_size);
|
||||
return -1;
|
||||
}
|
||||
if (ui->boundary_align < bd->sector_size) {
|
||||
exfat_err("boundary alignment is too small (min %d)\n",
|
||||
bd->sector_size);
|
||||
return -1;
|
||||
}
|
||||
finfo.fat_byte_off = round_up(bd->offset + 24 * bd->sector_size,
|
||||
ui->boundary_align) - bd->offset;
|
||||
/* Prevent integer overflow when computing the FAT length */
|
||||
if (bd->num_clusters > UINT32_MAX / 4) {
|
||||
exfat_err("cluster size (%u bytes) is too small\n", ui->cluster_size);
|
||||
return -1;
|
||||
}
|
||||
finfo.fat_byte_len = round_up((bd->num_clusters * 4), ui->cluster_size);
|
||||
finfo.clu_byte_off = round_up(bd->offset + finfo.fat_byte_off +
|
||||
finfo.fat_byte_len, ui->boundary_align) - bd->offset;
|
||||
if (bd->size <= finfo.clu_byte_off) {
|
||||
exfat_err("boundary alignment is too big\n");
|
||||
return -1;
|
||||
}
|
||||
total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size;
|
||||
if (total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) {
|
||||
exfat_err("cluster size is too small\n");
|
||||
return -1;
|
||||
}
|
||||
finfo.total_clu_cnt = (unsigned int) total_clu_cnt;
|
||||
|
||||
finfo.bitmap_byte_off = finfo.clu_byte_off;
|
||||
finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8;
|
||||
if (ui->pack_bitmap)
|
||||
exfat_pack_bitmap(ui);
|
||||
clu_len = round_up(finfo.bitmap_byte_len, ui->cluster_size);
|
||||
|
||||
finfo.ut_start_clu = EXFAT_FIRST_CLUSTER + clu_len / ui->cluster_size;
|
||||
finfo.ut_byte_off = finfo.bitmap_byte_off + clu_len;
|
||||
finfo.ut_byte_len = EXFAT_UPCASE_TABLE_SIZE;
|
||||
clu_len = round_up(finfo.ut_byte_len, ui->cluster_size);
|
||||
|
||||
finfo.root_start_clu = finfo.ut_start_clu + clu_len / ui->cluster_size;
|
||||
finfo.root_byte_off = finfo.ut_byte_off + clu_len;
|
||||
finfo.root_byte_len = sizeof(struct exfat_dentry) * 3;
|
||||
finfo.volume_serial = get_new_serial();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exfat_zero_out_disk(struct exfat_blk_dev *bd,
|
||||
struct exfat_user_input *ui)
|
||||
{
|
||||
int nbytes;
|
||||
unsigned long long total_written = 0;
|
||||
char *buf;
|
||||
unsigned int chunk_size = ui->cluster_size;
|
||||
unsigned long long size;
|
||||
|
||||
if (ui->quick)
|
||||
size = finfo.root_byte_off + chunk_size;
|
||||
else
|
||||
size = bd->size;
|
||||
|
||||
buf = malloc(chunk_size);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
memset(buf, 0, chunk_size);
|
||||
lseek(bd->dev_fd, 0, SEEK_SET);
|
||||
do {
|
||||
|
||||
nbytes = write(bd->dev_fd, buf, chunk_size);
|
||||
if (nbytes <= 0) {
|
||||
if (nbytes < 0)
|
||||
exfat_err("write failed(errno : %d)\n", errno);
|
||||
break;
|
||||
}
|
||||
total_written += nbytes;
|
||||
} while (total_written < size);
|
||||
|
||||
free(buf);
|
||||
exfat_debug("zero out written size : %llu, disk size : %llu\n",
|
||||
total_written, bd->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui)
|
||||
{
|
||||
int ret;
|
||||
|
||||
exfat_info("Creating exFAT filesystem(%s, cluster size=%u)\n\n",
|
||||
ui->dev_name, ui->cluster_size);
|
||||
|
||||
exfat_info("Writing volume boot record: ");
|
||||
ret = exfat_create_volume_boot_record(bd, ui, 0);
|
||||
exfat_info("%s\n", ret ? "failed" : "done");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
exfat_info("Writing backup volume boot record: ");
|
||||
/* backup sector */
|
||||
ret = exfat_create_volume_boot_record(bd, ui, 1);
|
||||
exfat_info("%s\n", ret ? "failed" : "done");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
exfat_info("Fat table creation: ");
|
||||
ret = exfat_create_fat_table(bd, ui);
|
||||
exfat_info("%s\n", ret ? "failed" : "done");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
exfat_info("Allocation bitmap creation: ");
|
||||
ret = exfat_create_bitmap(bd);
|
||||
exfat_info("%s\n", ret ? "failed" : "done");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
exfat_info("Upcase table creation: ");
|
||||
ret = exfat_create_upcase_table(bd);
|
||||
exfat_info("%s\n", ret ? "failed" : "done");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
exfat_info("Writing root directory entry: ");
|
||||
ret = exfat_create_root_dir(bd, ui);
|
||||
exfat_info("%s\n", ret ? "failed" : "done");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long long parse_size(const char *size)
|
||||
{
|
||||
char *data_unit;
|
||||
unsigned long long byte_size = strtoull(size, &data_unit, 0);
|
||||
|
||||
switch (*data_unit) {
|
||||
case 'M':
|
||||
case 'm':
|
||||
byte_size <<= 20;
|
||||
break;
|
||||
case 'K':
|
||||
case 'k':
|
||||
byte_size <<= 10;
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
default:
|
||||
exfat_err("Wrong unit input('%c') for size\n",
|
||||
*data_unit);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return byte_size;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int ret = EXIT_FAILURE;
|
||||
struct exfat_blk_dev bd;
|
||||
struct exfat_user_input ui;
|
||||
bool version_only = false;
|
||||
|
||||
init_user_input(&ui);
|
||||
|
||||
if (!setlocale(LC_CTYPE, ""))
|
||||
exfat_err("failed to init locale/codeset\n");
|
||||
|
||||
opterr = 0;
|
||||
while ((c = getopt_long(argc, argv, "n:L:c:b:fVvh", opts, NULL)) != EOF)
|
||||
switch (c) {
|
||||
/*
|
||||
* Make 'n' option fallthrough to 'L' option for for backward
|
||||
* compatibility with old utils.
|
||||
*/
|
||||
case 'n':
|
||||
case 'L':
|
||||
{
|
||||
ret = exfat_utf16_enc(optarg,
|
||||
ui.volume_label, sizeof(ui.volume_label));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ui.volume_label_len = ret;
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
ret = parse_size(optarg);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
else if (ret & (ret - 1)) {
|
||||
exfat_err("cluster size(%d) is not a power of 2)\n",
|
||||
ret);
|
||||
goto out;
|
||||
} else if (ret > EXFAT_MAX_CLUSTER_SIZE) {
|
||||
exfat_err("cluster size(%d) exceeds max cluster size(%d)\n",
|
||||
ui.cluster_size, EXFAT_MAX_CLUSTER_SIZE);
|
||||
goto out;
|
||||
}
|
||||
ui.cluster_size = ret;
|
||||
break;
|
||||
case 'b':
|
||||
ret = parse_size(optarg);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
else if (ret & (ret - 1)) {
|
||||
exfat_err("boundary align(%d) is not a power of 2)\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
ui.boundary_align = ret;
|
||||
break;
|
||||
case PACK_BITMAP:
|
||||
ui.pack_bitmap = true;
|
||||
break;
|
||||
case 'f':
|
||||
ui.quick = false;
|
||||
break;
|
||||
case 'V':
|
||||
version_only = true;
|
||||
break;
|
||||
case 'v':
|
||||
print_level = EXFAT_DEBUG;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
show_version();
|
||||
if (version_only)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (argc - optind != 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
memset(ui.dev_name, 0, sizeof(ui.dev_name));
|
||||
snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[optind]);
|
||||
|
||||
ret = exfat_get_blk_dev_info(&ui, &bd);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = exfat_build_mkfs_info(&bd, &ui);
|
||||
if (ret)
|
||||
goto close;
|
||||
|
||||
ret = exfat_zero_out_disk(&bd, &ui);
|
||||
if (ret)
|
||||
goto close;
|
||||
|
||||
ret = make_exfat(&bd, &ui);
|
||||
if (ret)
|
||||
goto close;
|
||||
|
||||
exfat_info("Synchronizing...\n");
|
||||
ret = fsync(bd.dev_fd);
|
||||
close:
|
||||
close(bd.dev_fd);
|
||||
out:
|
||||
if (!ret)
|
||||
exfat_info("\nexFAT format complete!\n");
|
||||
else
|
||||
exfat_info("\nexFAT format fail!\n");
|
||||
return ret;
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
|
||||
*/
|
||||
|
||||
#ifndef _MKFS_H
|
||||
|
||||
#define MIN_NUM_SECTOR (2048)
|
||||
#define EXFAT_MAX_CLUSTER_SIZE (32*1024*1024)
|
||||
|
||||
struct exfat_mkfs_info {
|
||||
unsigned int total_clu_cnt;
|
||||
unsigned int used_clu_cnt;
|
||||
unsigned int fat_byte_off;
|
||||
unsigned int fat_byte_len;
|
||||
unsigned int clu_byte_off;
|
||||
unsigned int bitmap_byte_off;
|
||||
unsigned int bitmap_byte_len;
|
||||
unsigned int ut_byte_off;
|
||||
unsigned int ut_start_clu;
|
||||
unsigned int ut_clus_off;
|
||||
unsigned int ut_byte_len;
|
||||
unsigned int root_byte_off;
|
||||
unsigned int root_byte_len;
|
||||
unsigned int root_start_clu;
|
||||
unsigned int volume_serial;
|
||||
};
|
||||
|
||||
extern struct exfat_mkfs_info finfo;
|
||||
|
||||
int exfat_create_upcase_table(struct exfat_blk_dev *bd);
|
||||
|
||||
#endif /* !_MKFS_H */
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
rootdir.c (09.11.10)
|
||||
Root directory creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "rootdir.h"
|
||||
#include "uct.h"
|
||||
#include "cbm.h"
|
||||
#include "uctc.h"
|
||||
#include <string.h>
|
||||
|
||||
static off_t rootdir_alignment(void)
|
||||
{
|
||||
return get_cluster_size();
|
||||
}
|
||||
|
||||
static off_t rootdir_size(void)
|
||||
{
|
||||
return get_cluster_size();
|
||||
}
|
||||
|
||||
static void init_label_entry(struct exfat_entry_label* label_entry)
|
||||
{
|
||||
memset(label_entry, 0, sizeof(struct exfat_entry_label));
|
||||
label_entry->type = EXFAT_ENTRY_LABEL ^ EXFAT_ENTRY_VALID;
|
||||
|
||||
if (exfat_utf16_length(get_volume_label()) == 0)
|
||||
return;
|
||||
|
||||
memcpy(label_entry->name, get_volume_label(),
|
||||
EXFAT_ENAME_MAX * sizeof(le16_t));
|
||||
label_entry->length = exfat_utf16_length(get_volume_label());
|
||||
label_entry->type |= EXFAT_ENTRY_VALID;
|
||||
}
|
||||
|
||||
static void init_bitmap_entry(struct exfat_entry_bitmap* bitmap_entry)
|
||||
{
|
||||
memset(bitmap_entry, 0, sizeof(struct exfat_entry_bitmap));
|
||||
bitmap_entry->type = EXFAT_ENTRY_BITMAP;
|
||||
bitmap_entry->start_cluster = cpu_to_le32(EXFAT_FIRST_DATA_CLUSTER);
|
||||
bitmap_entry->size = cpu_to_le64(cbm.get_size());
|
||||
}
|
||||
|
||||
static void init_upcase_entry(struct exfat_entry_upcase* upcase_entry)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t sum = 0;
|
||||
|
||||
for (i = 0; i < sizeof(upcase_table); i++)
|
||||
sum = ((sum << 31) | (sum >> 1)) + upcase_table[i];
|
||||
|
||||
memset(upcase_entry, 0, sizeof(struct exfat_entry_upcase));
|
||||
upcase_entry->type = EXFAT_ENTRY_UPCASE;
|
||||
upcase_entry->checksum = cpu_to_le32(sum);
|
||||
upcase_entry->start_cluster = cpu_to_le32(
|
||||
(get_position(&uct) - get_position(&cbm)) / get_cluster_size() +
|
||||
EXFAT_FIRST_DATA_CLUSTER);
|
||||
upcase_entry->size = cpu_to_le64(sizeof(upcase_table));
|
||||
}
|
||||
|
||||
static int rootdir_write(struct exfat_dev* dev)
|
||||
{
|
||||
struct exfat_entry_label label_entry;
|
||||
struct exfat_entry_bitmap bitmap_entry;
|
||||
struct exfat_entry_upcase upcase_entry;
|
||||
|
||||
init_label_entry(&label_entry);
|
||||
init_bitmap_entry(&bitmap_entry);
|
||||
init_upcase_entry(&upcase_entry);
|
||||
|
||||
if (exfat_write(dev, &label_entry, sizeof(struct exfat_entry)) < 0)
|
||||
return 1;
|
||||
if (exfat_write(dev, &bitmap_entry, sizeof(struct exfat_entry)) < 0)
|
||||
return 1;
|
||||
if (exfat_write(dev, &upcase_entry, sizeof(struct exfat_entry)) < 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct fs_object rootdir =
|
||||
{
|
||||
.get_alignment = rootdir_alignment,
|
||||
.get_size = rootdir_size,
|
||||
.write = rootdir_write,
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
rootdir.h (09.11.10)
|
||||
Root directory creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_ROOTDIR_H_INCLUDED
|
||||
#define MKFS_ROOTDIR_H_INCLUDED
|
||||
|
||||
#include "mkexfat.h"
|
||||
|
||||
extern const struct fs_object rootdir;
|
||||
|
||||
#endif /* ifndef MKFS_ROOTDIR_H_INCLUDED */
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
uct.c (09.11.10)
|
||||
Upper Case Table creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "uct.h"
|
||||
#include "uctc.h"
|
||||
|
||||
static off_t uct_alignment(void)
|
||||
{
|
||||
return get_cluster_size();
|
||||
}
|
||||
|
||||
static off_t uct_size(void)
|
||||
{
|
||||
return sizeof(upcase_table);
|
||||
}
|
||||
|
||||
static int uct_write(struct exfat_dev* dev)
|
||||
{
|
||||
if (exfat_write(dev, upcase_table, sizeof(upcase_table)) < 0)
|
||||
{
|
||||
exfat_error("failed to write upcase table of %zu bytes",
|
||||
sizeof(upcase_table));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct fs_object uct =
|
||||
{
|
||||
.get_alignment = uct_alignment,
|
||||
.get_size = uct_size,
|
||||
.write = uct_write,
|
||||
};
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
uct.h (09.11.10)
|
||||
Upper Case Table creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_UCT_H_INCLUDED
|
||||
#define MKFS_UCT_H_INCLUDED
|
||||
|
||||
#include "mkexfat.h"
|
||||
|
||||
extern const struct fs_object uct;
|
||||
|
||||
#endif /* ifndef MKFS_UCT_H_INCLUDED */
|
||||
-757
@@ -1,757 +0,0 @@
|
||||
/*
|
||||
uctc.c (30.04.12)
|
||||
Upper Case Table contents.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "uctc.h"
|
||||
|
||||
uint8_t upcase_table[5836] =
|
||||
{
|
||||
0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00,
|
||||
0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00,
|
||||
0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00,
|
||||
0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00,
|
||||
0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00,
|
||||
0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
|
||||
0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00,
|
||||
0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00,
|
||||
0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00,
|
||||
0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00,
|
||||
0x28, 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00,
|
||||
0x2c, 0x00, 0x2d, 0x00, 0x2e, 0x00, 0x2f, 0x00,
|
||||
0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00,
|
||||
0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00,
|
||||
0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00,
|
||||
0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00,
|
||||
0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00,
|
||||
0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
|
||||
0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00,
|
||||
0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00,
|
||||
0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
|
||||
0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
|
||||
0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00,
|
||||
0x5c, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5f, 0x00,
|
||||
0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00,
|
||||
0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
|
||||
0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00,
|
||||
0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00,
|
||||
0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
|
||||
0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
|
||||
0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x7b, 0x00,
|
||||
0x7c, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7f, 0x00,
|
||||
0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00,
|
||||
0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00,
|
||||
0x88, 0x00, 0x89, 0x00, 0x8a, 0x00, 0x8b, 0x00,
|
||||
0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f, 0x00,
|
||||
0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00,
|
||||
0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00,
|
||||
0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00,
|
||||
0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00,
|
||||
0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00,
|
||||
0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7, 0x00,
|
||||
0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00,
|
||||
0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00,
|
||||
0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0x00,
|
||||
0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00,
|
||||
0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00,
|
||||
0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbf, 0x00,
|
||||
0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00,
|
||||
0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00,
|
||||
0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00,
|
||||
0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x00,
|
||||
0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00,
|
||||
0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd7, 0x00,
|
||||
0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00,
|
||||
0xdc, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xdf, 0x00,
|
||||
0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00,
|
||||
0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00,
|
||||
0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00,
|
||||
0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x00,
|
||||
0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00,
|
||||
0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xf7, 0x00,
|
||||
0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00,
|
||||
0xdc, 0x00, 0xdd, 0x00, 0xde, 0x00, 0x78, 0x01,
|
||||
0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01,
|
||||
0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01,
|
||||
0x08, 0x01, 0x08, 0x01, 0x0a, 0x01, 0x0a, 0x01,
|
||||
0x0c, 0x01, 0x0c, 0x01, 0x0e, 0x01, 0x0e, 0x01,
|
||||
0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01,
|
||||
0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01,
|
||||
0x18, 0x01, 0x18, 0x01, 0x1a, 0x01, 0x1a, 0x01,
|
||||
0x1c, 0x01, 0x1c, 0x01, 0x1e, 0x01, 0x1e, 0x01,
|
||||
0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01,
|
||||
0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01,
|
||||
0x28, 0x01, 0x28, 0x01, 0x2a, 0x01, 0x2a, 0x01,
|
||||
0x2c, 0x01, 0x2c, 0x01, 0x2e, 0x01, 0x2e, 0x01,
|
||||
0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01,
|
||||
0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01,
|
||||
0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3b, 0x01,
|
||||
0x3b, 0x01, 0x3d, 0x01, 0x3d, 0x01, 0x3f, 0x01,
|
||||
0x3f, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01,
|
||||
0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01,
|
||||
0x47, 0x01, 0x49, 0x01, 0x4a, 0x01, 0x4a, 0x01,
|
||||
0x4c, 0x01, 0x4c, 0x01, 0x4e, 0x01, 0x4e, 0x01,
|
||||
0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01,
|
||||
0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01,
|
||||
0x58, 0x01, 0x58, 0x01, 0x5a, 0x01, 0x5a, 0x01,
|
||||
0x5c, 0x01, 0x5c, 0x01, 0x5e, 0x01, 0x5e, 0x01,
|
||||
0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01,
|
||||
0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01,
|
||||
0x68, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x6a, 0x01,
|
||||
0x6c, 0x01, 0x6c, 0x01, 0x6e, 0x01, 0x6e, 0x01,
|
||||
0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01,
|
||||
0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01,
|
||||
0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7b, 0x01,
|
||||
0x7b, 0x01, 0x7d, 0x01, 0x7d, 0x01, 0x7f, 0x01,
|
||||
0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01,
|
||||
0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01,
|
||||
0x87, 0x01, 0x89, 0x01, 0x8a, 0x01, 0x8b, 0x01,
|
||||
0x8b, 0x01, 0x8d, 0x01, 0x8e, 0x01, 0x8f, 0x01,
|
||||
0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01,
|
||||
0x94, 0x01, 0xf6, 0x01, 0x96, 0x01, 0x97, 0x01,
|
||||
0x98, 0x01, 0x98, 0x01, 0x3d, 0x02, 0x9b, 0x01,
|
||||
0x9c, 0x01, 0x9d, 0x01, 0x20, 0x02, 0x9f, 0x01,
|
||||
0xa0, 0x01, 0xa0, 0x01, 0xa2, 0x01, 0xa2, 0x01,
|
||||
0xa4, 0x01, 0xa4, 0x01, 0xa6, 0x01, 0xa7, 0x01,
|
||||
0xa7, 0x01, 0xa9, 0x01, 0xaa, 0x01, 0xab, 0x01,
|
||||
0xac, 0x01, 0xac, 0x01, 0xae, 0x01, 0xaf, 0x01,
|
||||
0xaf, 0x01, 0xb1, 0x01, 0xb2, 0x01, 0xb3, 0x01,
|
||||
0xb3, 0x01, 0xb5, 0x01, 0xb5, 0x01, 0xb7, 0x01,
|
||||
0xb8, 0x01, 0xb8, 0x01, 0xba, 0x01, 0xbb, 0x01,
|
||||
0xbc, 0x01, 0xbc, 0x01, 0xbe, 0x01, 0xf7, 0x01,
|
||||
0xc0, 0x01, 0xc1, 0x01, 0xc2, 0x01, 0xc3, 0x01,
|
||||
0xc4, 0x01, 0xc5, 0x01, 0xc4, 0x01, 0xc7, 0x01,
|
||||
0xc8, 0x01, 0xc7, 0x01, 0xca, 0x01, 0xcb, 0x01,
|
||||
0xca, 0x01, 0xcd, 0x01, 0xcd, 0x01, 0xcf, 0x01,
|
||||
0xcf, 0x01, 0xd1, 0x01, 0xd1, 0x01, 0xd3, 0x01,
|
||||
0xd3, 0x01, 0xd5, 0x01, 0xd5, 0x01, 0xd7, 0x01,
|
||||
0xd7, 0x01, 0xd9, 0x01, 0xd9, 0x01, 0xdb, 0x01,
|
||||
0xdb, 0x01, 0x8e, 0x01, 0xde, 0x01, 0xde, 0x01,
|
||||
0xe0, 0x01, 0xe0, 0x01, 0xe2, 0x01, 0xe2, 0x01,
|
||||
0xe4, 0x01, 0xe4, 0x01, 0xe6, 0x01, 0xe6, 0x01,
|
||||
0xe8, 0x01, 0xe8, 0x01, 0xea, 0x01, 0xea, 0x01,
|
||||
0xec, 0x01, 0xec, 0x01, 0xee, 0x01, 0xee, 0x01,
|
||||
0xf0, 0x01, 0xf1, 0x01, 0xf2, 0x01, 0xf1, 0x01,
|
||||
0xf4, 0x01, 0xf4, 0x01, 0xf6, 0x01, 0xf7, 0x01,
|
||||
0xf8, 0x01, 0xf8, 0x01, 0xfa, 0x01, 0xfa, 0x01,
|
||||
0xfc, 0x01, 0xfc, 0x01, 0xfe, 0x01, 0xfe, 0x01,
|
||||
0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02,
|
||||
0x08, 0x02, 0x08, 0x02, 0x0a, 0x02, 0x0a, 0x02,
|
||||
0x0c, 0x02, 0x0c, 0x02, 0x0e, 0x02, 0x0e, 0x02,
|
||||
0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02,
|
||||
0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02,
|
||||
0x18, 0x02, 0x18, 0x02, 0x1a, 0x02, 0x1a, 0x02,
|
||||
0x1c, 0x02, 0x1c, 0x02, 0x1e, 0x02, 0x1e, 0x02,
|
||||
0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02,
|
||||
0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02,
|
||||
0x28, 0x02, 0x28, 0x02, 0x2a, 0x02, 0x2a, 0x02,
|
||||
0x2c, 0x02, 0x2c, 0x02, 0x2e, 0x02, 0x2e, 0x02,
|
||||
0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02,
|
||||
0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02,
|
||||
0x38, 0x02, 0x39, 0x02, 0x65, 0x2c, 0x3b, 0x02,
|
||||
0x3b, 0x02, 0x3d, 0x02, 0x66, 0x2c, 0x3f, 0x02,
|
||||
0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02,
|
||||
0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02,
|
||||
0x48, 0x02, 0x48, 0x02, 0x4a, 0x02, 0x4a, 0x02,
|
||||
0x4c, 0x02, 0x4c, 0x02, 0x4e, 0x02, 0x4e, 0x02,
|
||||
0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01,
|
||||
0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8a, 0x01,
|
||||
0x58, 0x02, 0x8f, 0x01, 0x5a, 0x02, 0x90, 0x01,
|
||||
0x5c, 0x02, 0x5d, 0x02, 0x5e, 0x02, 0x5f, 0x02,
|
||||
0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01,
|
||||
0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02,
|
||||
0x97, 0x01, 0x96, 0x01, 0x6a, 0x02, 0x62, 0x2c,
|
||||
0x6c, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x9c, 0x01,
|
||||
0x70, 0x02, 0x71, 0x02, 0x9d, 0x01, 0x73, 0x02,
|
||||
0x74, 0x02, 0x9f, 0x01, 0x76, 0x02, 0x77, 0x02,
|
||||
0x78, 0x02, 0x79, 0x02, 0x7a, 0x02, 0x7b, 0x02,
|
||||
0x7c, 0x02, 0x64, 0x2c, 0x7e, 0x02, 0x7f, 0x02,
|
||||
0xa6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xa9, 0x01,
|
||||
0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02,
|
||||
0xae, 0x01, 0x44, 0x02, 0xb1, 0x01, 0xb2, 0x01,
|
||||
0x45, 0x02, 0x8d, 0x02, 0x8e, 0x02, 0x8f, 0x02,
|
||||
0x90, 0x02, 0x91, 0x02, 0xb7, 0x01, 0x93, 0x02,
|
||||
0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02,
|
||||
0x98, 0x02, 0x99, 0x02, 0x9a, 0x02, 0x9b, 0x02,
|
||||
0x9c, 0x02, 0x9d, 0x02, 0x9e, 0x02, 0x9f, 0x02,
|
||||
0xa0, 0x02, 0xa1, 0x02, 0xa2, 0x02, 0xa3, 0x02,
|
||||
0xa4, 0x02, 0xa5, 0x02, 0xa6, 0x02, 0xa7, 0x02,
|
||||
0xa8, 0x02, 0xa9, 0x02, 0xaa, 0x02, 0xab, 0x02,
|
||||
0xac, 0x02, 0xad, 0x02, 0xae, 0x02, 0xaf, 0x02,
|
||||
0xb0, 0x02, 0xb1, 0x02, 0xb2, 0x02, 0xb3, 0x02,
|
||||
0xb4, 0x02, 0xb5, 0x02, 0xb6, 0x02, 0xb7, 0x02,
|
||||
0xb8, 0x02, 0xb9, 0x02, 0xba, 0x02, 0xbb, 0x02,
|
||||
0xbc, 0x02, 0xbd, 0x02, 0xbe, 0x02, 0xbf, 0x02,
|
||||
0xc0, 0x02, 0xc1, 0x02, 0xc2, 0x02, 0xc3, 0x02,
|
||||
0xc4, 0x02, 0xc5, 0x02, 0xc6, 0x02, 0xc7, 0x02,
|
||||
0xc8, 0x02, 0xc9, 0x02, 0xca, 0x02, 0xcb, 0x02,
|
||||
0xcc, 0x02, 0xcd, 0x02, 0xce, 0x02, 0xcf, 0x02,
|
||||
0xd0, 0x02, 0xd1, 0x02, 0xd2, 0x02, 0xd3, 0x02,
|
||||
0xd4, 0x02, 0xd5, 0x02, 0xd6, 0x02, 0xd7, 0x02,
|
||||
0xd8, 0x02, 0xd9, 0x02, 0xda, 0x02, 0xdb, 0x02,
|
||||
0xdc, 0x02, 0xdd, 0x02, 0xde, 0x02, 0xdf, 0x02,
|
||||
0xe0, 0x02, 0xe1, 0x02, 0xe2, 0x02, 0xe3, 0x02,
|
||||
0xe4, 0x02, 0xe5, 0x02, 0xe6, 0x02, 0xe7, 0x02,
|
||||
0xe8, 0x02, 0xe9, 0x02, 0xea, 0x02, 0xeb, 0x02,
|
||||
0xec, 0x02, 0xed, 0x02, 0xee, 0x02, 0xef, 0x02,
|
||||
0xf0, 0x02, 0xf1, 0x02, 0xf2, 0x02, 0xf3, 0x02,
|
||||
0xf4, 0x02, 0xf5, 0x02, 0xf6, 0x02, 0xf7, 0x02,
|
||||
0xf8, 0x02, 0xf9, 0x02, 0xfa, 0x02, 0xfb, 0x02,
|
||||
0xfc, 0x02, 0xfd, 0x02, 0xfe, 0x02, 0xff, 0x02,
|
||||
0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03,
|
||||
0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03,
|
||||
0x08, 0x03, 0x09, 0x03, 0x0a, 0x03, 0x0b, 0x03,
|
||||
0x0c, 0x03, 0x0d, 0x03, 0x0e, 0x03, 0x0f, 0x03,
|
||||
0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03,
|
||||
0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03,
|
||||
0x18, 0x03, 0x19, 0x03, 0x1a, 0x03, 0x1b, 0x03,
|
||||
0x1c, 0x03, 0x1d, 0x03, 0x1e, 0x03, 0x1f, 0x03,
|
||||
0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03,
|
||||
0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03,
|
||||
0x28, 0x03, 0x29, 0x03, 0x2a, 0x03, 0x2b, 0x03,
|
||||
0x2c, 0x03, 0x2d, 0x03, 0x2e, 0x03, 0x2f, 0x03,
|
||||
0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03,
|
||||
0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03,
|
||||
0x38, 0x03, 0x39, 0x03, 0x3a, 0x03, 0x3b, 0x03,
|
||||
0x3c, 0x03, 0x3d, 0x03, 0x3e, 0x03, 0x3f, 0x03,
|
||||
0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03,
|
||||
0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03,
|
||||
0x48, 0x03, 0x49, 0x03, 0x4a, 0x03, 0x4b, 0x03,
|
||||
0x4c, 0x03, 0x4d, 0x03, 0x4e, 0x03, 0x4f, 0x03,
|
||||
0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03,
|
||||
0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03,
|
||||
0x58, 0x03, 0x59, 0x03, 0x5a, 0x03, 0x5b, 0x03,
|
||||
0x5c, 0x03, 0x5d, 0x03, 0x5e, 0x03, 0x5f, 0x03,
|
||||
0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03,
|
||||
0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03,
|
||||
0x68, 0x03, 0x69, 0x03, 0x6a, 0x03, 0x6b, 0x03,
|
||||
0x6c, 0x03, 0x6d, 0x03, 0x6e, 0x03, 0x6f, 0x03,
|
||||
0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03,
|
||||
0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03,
|
||||
0x78, 0x03, 0x79, 0x03, 0x7a, 0x03, 0xfd, 0x03,
|
||||
0xfe, 0x03, 0xff, 0x03, 0x7e, 0x03, 0x7f, 0x03,
|
||||
0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03,
|
||||
0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03,
|
||||
0x88, 0x03, 0x89, 0x03, 0x8a, 0x03, 0x8b, 0x03,
|
||||
0x8c, 0x03, 0x8d, 0x03, 0x8e, 0x03, 0x8f, 0x03,
|
||||
0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03,
|
||||
0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03,
|
||||
0x98, 0x03, 0x99, 0x03, 0x9a, 0x03, 0x9b, 0x03,
|
||||
0x9c, 0x03, 0x9d, 0x03, 0x9e, 0x03, 0x9f, 0x03,
|
||||
0xa0, 0x03, 0xa1, 0x03, 0xa2, 0x03, 0xa3, 0x03,
|
||||
0xa4, 0x03, 0xa5, 0x03, 0xa6, 0x03, 0xa7, 0x03,
|
||||
0xa8, 0x03, 0xa9, 0x03, 0xaa, 0x03, 0xab, 0x03,
|
||||
0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8a, 0x03,
|
||||
0xb0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03,
|
||||
0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03,
|
||||
0x98, 0x03, 0x99, 0x03, 0x9a, 0x03, 0x9b, 0x03,
|
||||
0x9c, 0x03, 0x9d, 0x03, 0x9e, 0x03, 0x9f, 0x03,
|
||||
0xa0, 0x03, 0xa1, 0x03, 0xa3, 0x03, 0xa3, 0x03,
|
||||
0xa4, 0x03, 0xa5, 0x03, 0xa6, 0x03, 0xa7, 0x03,
|
||||
0xa8, 0x03, 0xa9, 0x03, 0xaa, 0x03, 0xab, 0x03,
|
||||
0x8c, 0x03, 0x8e, 0x03, 0x8f, 0x03, 0xcf, 0x03,
|
||||
0xd0, 0x03, 0xd1, 0x03, 0xd2, 0x03, 0xd3, 0x03,
|
||||
0xd4, 0x03, 0xd5, 0x03, 0xd6, 0x03, 0xd7, 0x03,
|
||||
0xd8, 0x03, 0xd8, 0x03, 0xda, 0x03, 0xda, 0x03,
|
||||
0xdc, 0x03, 0xdc, 0x03, 0xde, 0x03, 0xde, 0x03,
|
||||
0xe0, 0x03, 0xe0, 0x03, 0xe2, 0x03, 0xe2, 0x03,
|
||||
0xe4, 0x03, 0xe4, 0x03, 0xe6, 0x03, 0xe6, 0x03,
|
||||
0xe8, 0x03, 0xe8, 0x03, 0xea, 0x03, 0xea, 0x03,
|
||||
0xec, 0x03, 0xec, 0x03, 0xee, 0x03, 0xee, 0x03,
|
||||
0xf0, 0x03, 0xf1, 0x03, 0xf9, 0x03, 0xf3, 0x03,
|
||||
0xf4, 0x03, 0xf5, 0x03, 0xf6, 0x03, 0xf7, 0x03,
|
||||
0xf7, 0x03, 0xf9, 0x03, 0xfa, 0x03, 0xfa, 0x03,
|
||||
0xfc, 0x03, 0xfd, 0x03, 0xfe, 0x03, 0xff, 0x03,
|
||||
0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04,
|
||||
0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
|
||||
0x08, 0x04, 0x09, 0x04, 0x0a, 0x04, 0x0b, 0x04,
|
||||
0x0c, 0x04, 0x0d, 0x04, 0x0e, 0x04, 0x0f, 0x04,
|
||||
0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04,
|
||||
0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
|
||||
0x18, 0x04, 0x19, 0x04, 0x1a, 0x04, 0x1b, 0x04,
|
||||
0x1c, 0x04, 0x1d, 0x04, 0x1e, 0x04, 0x1f, 0x04,
|
||||
0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04,
|
||||
0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04,
|
||||
0x28, 0x04, 0x29, 0x04, 0x2a, 0x04, 0x2b, 0x04,
|
||||
0x2c, 0x04, 0x2d, 0x04, 0x2e, 0x04, 0x2f, 0x04,
|
||||
0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04,
|
||||
0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
|
||||
0x18, 0x04, 0x19, 0x04, 0x1a, 0x04, 0x1b, 0x04,
|
||||
0x1c, 0x04, 0x1d, 0x04, 0x1e, 0x04, 0x1f, 0x04,
|
||||
0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04,
|
||||
0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04,
|
||||
0x28, 0x04, 0x29, 0x04, 0x2a, 0x04, 0x2b, 0x04,
|
||||
0x2c, 0x04, 0x2d, 0x04, 0x2e, 0x04, 0x2f, 0x04,
|
||||
0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04,
|
||||
0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
|
||||
0x08, 0x04, 0x09, 0x04, 0x0a, 0x04, 0x0b, 0x04,
|
||||
0x0c, 0x04, 0x0d, 0x04, 0x0e, 0x04, 0x0f, 0x04,
|
||||
0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04,
|
||||
0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04,
|
||||
0x68, 0x04, 0x68, 0x04, 0x6a, 0x04, 0x6a, 0x04,
|
||||
0x6c, 0x04, 0x6c, 0x04, 0x6e, 0x04, 0x6e, 0x04,
|
||||
0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04,
|
||||
0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04,
|
||||
0x78, 0x04, 0x78, 0x04, 0x7a, 0x04, 0x7a, 0x04,
|
||||
0x7c, 0x04, 0x7c, 0x04, 0x7e, 0x04, 0x7e, 0x04,
|
||||
0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04,
|
||||
0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04,
|
||||
0x88, 0x04, 0x89, 0x04, 0x8a, 0x04, 0x8a, 0x04,
|
||||
0x8c, 0x04, 0x8c, 0x04, 0x8e, 0x04, 0x8e, 0x04,
|
||||
0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04,
|
||||
0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04,
|
||||
0x98, 0x04, 0x98, 0x04, 0x9a, 0x04, 0x9a, 0x04,
|
||||
0x9c, 0x04, 0x9c, 0x04, 0x9e, 0x04, 0x9e, 0x04,
|
||||
0xa0, 0x04, 0xa0, 0x04, 0xa2, 0x04, 0xa2, 0x04,
|
||||
0xa4, 0x04, 0xa4, 0x04, 0xa6, 0x04, 0xa6, 0x04,
|
||||
0xa8, 0x04, 0xa8, 0x04, 0xaa, 0x04, 0xaa, 0x04,
|
||||
0xac, 0x04, 0xac, 0x04, 0xae, 0x04, 0xae, 0x04,
|
||||
0xb0, 0x04, 0xb0, 0x04, 0xb2, 0x04, 0xb2, 0x04,
|
||||
0xb4, 0x04, 0xb4, 0x04, 0xb6, 0x04, 0xb6, 0x04,
|
||||
0xb8, 0x04, 0xb8, 0x04, 0xba, 0x04, 0xba, 0x04,
|
||||
0xbc, 0x04, 0xbc, 0x04, 0xbe, 0x04, 0xbe, 0x04,
|
||||
0xc0, 0x04, 0xc1, 0x04, 0xc1, 0x04, 0xc3, 0x04,
|
||||
0xc3, 0x04, 0xc5, 0x04, 0xc5, 0x04, 0xc7, 0x04,
|
||||
0xc7, 0x04, 0xc9, 0x04, 0xc9, 0x04, 0xcb, 0x04,
|
||||
0xcb, 0x04, 0xcd, 0x04, 0xcd, 0x04, 0xc0, 0x04,
|
||||
0xd0, 0x04, 0xd0, 0x04, 0xd2, 0x04, 0xd2, 0x04,
|
||||
0xd4, 0x04, 0xd4, 0x04, 0xd6, 0x04, 0xd6, 0x04,
|
||||
0xd8, 0x04, 0xd8, 0x04, 0xda, 0x04, 0xda, 0x04,
|
||||
0xdc, 0x04, 0xdc, 0x04, 0xde, 0x04, 0xde, 0x04,
|
||||
0xe0, 0x04, 0xe0, 0x04, 0xe2, 0x04, 0xe2, 0x04,
|
||||
0xe4, 0x04, 0xe4, 0x04, 0xe6, 0x04, 0xe6, 0x04,
|
||||
0xe8, 0x04, 0xe8, 0x04, 0xea, 0x04, 0xea, 0x04,
|
||||
0xec, 0x04, 0xec, 0x04, 0xee, 0x04, 0xee, 0x04,
|
||||
0xf0, 0x04, 0xf0, 0x04, 0xf2, 0x04, 0xf2, 0x04,
|
||||
0xf4, 0x04, 0xf4, 0x04, 0xf6, 0x04, 0xf6, 0x04,
|
||||
0xf8, 0x04, 0xf8, 0x04, 0xfa, 0x04, 0xfa, 0x04,
|
||||
0xfc, 0x04, 0xfc, 0x04, 0xfe, 0x04, 0xfe, 0x04,
|
||||
0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05,
|
||||
0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05,
|
||||
0x08, 0x05, 0x08, 0x05, 0x0a, 0x05, 0x0a, 0x05,
|
||||
0x0c, 0x05, 0x0c, 0x05, 0x0e, 0x05, 0x0e, 0x05,
|
||||
0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05,
|
||||
0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05,
|
||||
0x18, 0x05, 0x19, 0x05, 0x1a, 0x05, 0x1b, 0x05,
|
||||
0x1c, 0x05, 0x1d, 0x05, 0x1e, 0x05, 0x1f, 0x05,
|
||||
0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05,
|
||||
0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05,
|
||||
0x28, 0x05, 0x29, 0x05, 0x2a, 0x05, 0x2b, 0x05,
|
||||
0x2c, 0x05, 0x2d, 0x05, 0x2e, 0x05, 0x2f, 0x05,
|
||||
0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05,
|
||||
0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05,
|
||||
0x38, 0x05, 0x39, 0x05, 0x3a, 0x05, 0x3b, 0x05,
|
||||
0x3c, 0x05, 0x3d, 0x05, 0x3e, 0x05, 0x3f, 0x05,
|
||||
0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05,
|
||||
0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05,
|
||||
0x48, 0x05, 0x49, 0x05, 0x4a, 0x05, 0x4b, 0x05,
|
||||
0x4c, 0x05, 0x4d, 0x05, 0x4e, 0x05, 0x4f, 0x05,
|
||||
0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05,
|
||||
0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05,
|
||||
0x58, 0x05, 0x59, 0x05, 0x5a, 0x05, 0x5b, 0x05,
|
||||
0x5c, 0x05, 0x5d, 0x05, 0x5e, 0x05, 0x5f, 0x05,
|
||||
0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05,
|
||||
0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05,
|
||||
0x38, 0x05, 0x39, 0x05, 0x3a, 0x05, 0x3b, 0x05,
|
||||
0x3c, 0x05, 0x3d, 0x05, 0x3e, 0x05, 0x3f, 0x05,
|
||||
0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05,
|
||||
0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05,
|
||||
0x48, 0x05, 0x49, 0x05, 0x4a, 0x05, 0x4b, 0x05,
|
||||
0x4c, 0x05, 0x4d, 0x05, 0x4e, 0x05, 0x4f, 0x05,
|
||||
0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05,
|
||||
0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xff, 0xff,
|
||||
0xf6, 0x17, 0x63, 0x2c, 0x7e, 0x1d, 0x7f, 0x1d,
|
||||
0x80, 0x1d, 0x81, 0x1d, 0x82, 0x1d, 0x83, 0x1d,
|
||||
0x84, 0x1d, 0x85, 0x1d, 0x86, 0x1d, 0x87, 0x1d,
|
||||
0x88, 0x1d, 0x89, 0x1d, 0x8a, 0x1d, 0x8b, 0x1d,
|
||||
0x8c, 0x1d, 0x8d, 0x1d, 0x8e, 0x1d, 0x8f, 0x1d,
|
||||
0x90, 0x1d, 0x91, 0x1d, 0x92, 0x1d, 0x93, 0x1d,
|
||||
0x94, 0x1d, 0x95, 0x1d, 0x96, 0x1d, 0x97, 0x1d,
|
||||
0x98, 0x1d, 0x99, 0x1d, 0x9a, 0x1d, 0x9b, 0x1d,
|
||||
0x9c, 0x1d, 0x9d, 0x1d, 0x9e, 0x1d, 0x9f, 0x1d,
|
||||
0xa0, 0x1d, 0xa1, 0x1d, 0xa2, 0x1d, 0xa3, 0x1d,
|
||||
0xa4, 0x1d, 0xa5, 0x1d, 0xa6, 0x1d, 0xa7, 0x1d,
|
||||
0xa8, 0x1d, 0xa9, 0x1d, 0xaa, 0x1d, 0xab, 0x1d,
|
||||
0xac, 0x1d, 0xad, 0x1d, 0xae, 0x1d, 0xaf, 0x1d,
|
||||
0xb0, 0x1d, 0xb1, 0x1d, 0xb2, 0x1d, 0xb3, 0x1d,
|
||||
0xb4, 0x1d, 0xb5, 0x1d, 0xb6, 0x1d, 0xb7, 0x1d,
|
||||
0xb8, 0x1d, 0xb9, 0x1d, 0xba, 0x1d, 0xbb, 0x1d,
|
||||
0xbc, 0x1d, 0xbd, 0x1d, 0xbe, 0x1d, 0xbf, 0x1d,
|
||||
0xc0, 0x1d, 0xc1, 0x1d, 0xc2, 0x1d, 0xc3, 0x1d,
|
||||
0xc4, 0x1d, 0xc5, 0x1d, 0xc6, 0x1d, 0xc7, 0x1d,
|
||||
0xc8, 0x1d, 0xc9, 0x1d, 0xca, 0x1d, 0xcb, 0x1d,
|
||||
0xcc, 0x1d, 0xcd, 0x1d, 0xce, 0x1d, 0xcf, 0x1d,
|
||||
0xd0, 0x1d, 0xd1, 0x1d, 0xd2, 0x1d, 0xd3, 0x1d,
|
||||
0xd4, 0x1d, 0xd5, 0x1d, 0xd6, 0x1d, 0xd7, 0x1d,
|
||||
0xd8, 0x1d, 0xd9, 0x1d, 0xda, 0x1d, 0xdb, 0x1d,
|
||||
0xdc, 0x1d, 0xdd, 0x1d, 0xde, 0x1d, 0xdf, 0x1d,
|
||||
0xe0, 0x1d, 0xe1, 0x1d, 0xe2, 0x1d, 0xe3, 0x1d,
|
||||
0xe4, 0x1d, 0xe5, 0x1d, 0xe6, 0x1d, 0xe7, 0x1d,
|
||||
0xe8, 0x1d, 0xe9, 0x1d, 0xea, 0x1d, 0xeb, 0x1d,
|
||||
0xec, 0x1d, 0xed, 0x1d, 0xee, 0x1d, 0xef, 0x1d,
|
||||
0xf0, 0x1d, 0xf1, 0x1d, 0xf2, 0x1d, 0xf3, 0x1d,
|
||||
0xf4, 0x1d, 0xf5, 0x1d, 0xf6, 0x1d, 0xf7, 0x1d,
|
||||
0xf8, 0x1d, 0xf9, 0x1d, 0xfa, 0x1d, 0xfb, 0x1d,
|
||||
0xfc, 0x1d, 0xfd, 0x1d, 0xfe, 0x1d, 0xff, 0x1d,
|
||||
0x00, 0x1e, 0x00, 0x1e, 0x02, 0x1e, 0x02, 0x1e,
|
||||
0x04, 0x1e, 0x04, 0x1e, 0x06, 0x1e, 0x06, 0x1e,
|
||||
0x08, 0x1e, 0x08, 0x1e, 0x0a, 0x1e, 0x0a, 0x1e,
|
||||
0x0c, 0x1e, 0x0c, 0x1e, 0x0e, 0x1e, 0x0e, 0x1e,
|
||||
0x10, 0x1e, 0x10, 0x1e, 0x12, 0x1e, 0x12, 0x1e,
|
||||
0x14, 0x1e, 0x14, 0x1e, 0x16, 0x1e, 0x16, 0x1e,
|
||||
0x18, 0x1e, 0x18, 0x1e, 0x1a, 0x1e, 0x1a, 0x1e,
|
||||
0x1c, 0x1e, 0x1c, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
|
||||
0x20, 0x1e, 0x20, 0x1e, 0x22, 0x1e, 0x22, 0x1e,
|
||||
0x24, 0x1e, 0x24, 0x1e, 0x26, 0x1e, 0x26, 0x1e,
|
||||
0x28, 0x1e, 0x28, 0x1e, 0x2a, 0x1e, 0x2a, 0x1e,
|
||||
0x2c, 0x1e, 0x2c, 0x1e, 0x2e, 0x1e, 0x2e, 0x1e,
|
||||
0x30, 0x1e, 0x30, 0x1e, 0x32, 0x1e, 0x32, 0x1e,
|
||||
0x34, 0x1e, 0x34, 0x1e, 0x36, 0x1e, 0x36, 0x1e,
|
||||
0x38, 0x1e, 0x38, 0x1e, 0x3a, 0x1e, 0x3a, 0x1e,
|
||||
0x3c, 0x1e, 0x3c, 0x1e, 0x3e, 0x1e, 0x3e, 0x1e,
|
||||
0x40, 0x1e, 0x40, 0x1e, 0x42, 0x1e, 0x42, 0x1e,
|
||||
0x44, 0x1e, 0x44, 0x1e, 0x46, 0x1e, 0x46, 0x1e,
|
||||
0x48, 0x1e, 0x48, 0x1e, 0x4a, 0x1e, 0x4a, 0x1e,
|
||||
0x4c, 0x1e, 0x4c, 0x1e, 0x4e, 0x1e, 0x4e, 0x1e,
|
||||
0x50, 0x1e, 0x50, 0x1e, 0x52, 0x1e, 0x52, 0x1e,
|
||||
0x54, 0x1e, 0x54, 0x1e, 0x56, 0x1e, 0x56, 0x1e,
|
||||
0x58, 0x1e, 0x58, 0x1e, 0x5a, 0x1e, 0x5a, 0x1e,
|
||||
0x5c, 0x1e, 0x5c, 0x1e, 0x5e, 0x1e, 0x5e, 0x1e,
|
||||
0x60, 0x1e, 0x60, 0x1e, 0x62, 0x1e, 0x62, 0x1e,
|
||||
0x64, 0x1e, 0x64, 0x1e, 0x66, 0x1e, 0x66, 0x1e,
|
||||
0x68, 0x1e, 0x68, 0x1e, 0x6a, 0x1e, 0x6a, 0x1e,
|
||||
0x6c, 0x1e, 0x6c, 0x1e, 0x6e, 0x1e, 0x6e, 0x1e,
|
||||
0x70, 0x1e, 0x70, 0x1e, 0x72, 0x1e, 0x72, 0x1e,
|
||||
0x74, 0x1e, 0x74, 0x1e, 0x76, 0x1e, 0x76, 0x1e,
|
||||
0x78, 0x1e, 0x78, 0x1e, 0x7a, 0x1e, 0x7a, 0x1e,
|
||||
0x7c, 0x1e, 0x7c, 0x1e, 0x7e, 0x1e, 0x7e, 0x1e,
|
||||
0x80, 0x1e, 0x80, 0x1e, 0x82, 0x1e, 0x82, 0x1e,
|
||||
0x84, 0x1e, 0x84, 0x1e, 0x86, 0x1e, 0x86, 0x1e,
|
||||
0x88, 0x1e, 0x88, 0x1e, 0x8a, 0x1e, 0x8a, 0x1e,
|
||||
0x8c, 0x1e, 0x8c, 0x1e, 0x8e, 0x1e, 0x8e, 0x1e,
|
||||
0x90, 0x1e, 0x90, 0x1e, 0x92, 0x1e, 0x92, 0x1e,
|
||||
0x94, 0x1e, 0x94, 0x1e, 0x96, 0x1e, 0x97, 0x1e,
|
||||
0x98, 0x1e, 0x99, 0x1e, 0x9a, 0x1e, 0x9b, 0x1e,
|
||||
0x9c, 0x1e, 0x9d, 0x1e, 0x9e, 0x1e, 0x9f, 0x1e,
|
||||
0xa0, 0x1e, 0xa0, 0x1e, 0xa2, 0x1e, 0xa2, 0x1e,
|
||||
0xa4, 0x1e, 0xa4, 0x1e, 0xa6, 0x1e, 0xa6, 0x1e,
|
||||
0xa8, 0x1e, 0xa8, 0x1e, 0xaa, 0x1e, 0xaa, 0x1e,
|
||||
0xac, 0x1e, 0xac, 0x1e, 0xae, 0x1e, 0xae, 0x1e,
|
||||
0xb0, 0x1e, 0xb0, 0x1e, 0xb2, 0x1e, 0xb2, 0x1e,
|
||||
0xb4, 0x1e, 0xb4, 0x1e, 0xb6, 0x1e, 0xb6, 0x1e,
|
||||
0xb8, 0x1e, 0xb8, 0x1e, 0xba, 0x1e, 0xba, 0x1e,
|
||||
0xbc, 0x1e, 0xbc, 0x1e, 0xbe, 0x1e, 0xbe, 0x1e,
|
||||
0xc0, 0x1e, 0xc0, 0x1e, 0xc2, 0x1e, 0xc2, 0x1e,
|
||||
0xc4, 0x1e, 0xc4, 0x1e, 0xc6, 0x1e, 0xc6, 0x1e,
|
||||
0xc8, 0x1e, 0xc8, 0x1e, 0xca, 0x1e, 0xca, 0x1e,
|
||||
0xcc, 0x1e, 0xcc, 0x1e, 0xce, 0x1e, 0xce, 0x1e,
|
||||
0xd0, 0x1e, 0xd0, 0x1e, 0xd2, 0x1e, 0xd2, 0x1e,
|
||||
0xd4, 0x1e, 0xd4, 0x1e, 0xd6, 0x1e, 0xd6, 0x1e,
|
||||
0xd8, 0x1e, 0xd8, 0x1e, 0xda, 0x1e, 0xda, 0x1e,
|
||||
0xdc, 0x1e, 0xdc, 0x1e, 0xde, 0x1e, 0xde, 0x1e,
|
||||
0xe0, 0x1e, 0xe0, 0x1e, 0xe2, 0x1e, 0xe2, 0x1e,
|
||||
0xe4, 0x1e, 0xe4, 0x1e, 0xe6, 0x1e, 0xe6, 0x1e,
|
||||
0xe8, 0x1e, 0xe8, 0x1e, 0xea, 0x1e, 0xea, 0x1e,
|
||||
0xec, 0x1e, 0xec, 0x1e, 0xee, 0x1e, 0xee, 0x1e,
|
||||
0xf0, 0x1e, 0xf0, 0x1e, 0xf2, 0x1e, 0xf2, 0x1e,
|
||||
0xf4, 0x1e, 0xf4, 0x1e, 0xf6, 0x1e, 0xf6, 0x1e,
|
||||
0xf8, 0x1e, 0xf8, 0x1e, 0xfa, 0x1e, 0xfb, 0x1e,
|
||||
0xfc, 0x1e, 0xfd, 0x1e, 0xfe, 0x1e, 0xff, 0x1e,
|
||||
0x08, 0x1f, 0x09, 0x1f, 0x0a, 0x1f, 0x0b, 0x1f,
|
||||
0x0c, 0x1f, 0x0d, 0x1f, 0x0e, 0x1f, 0x0f, 0x1f,
|
||||
0x08, 0x1f, 0x09, 0x1f, 0x0a, 0x1f, 0x0b, 0x1f,
|
||||
0x0c, 0x1f, 0x0d, 0x1f, 0x0e, 0x1f, 0x0f, 0x1f,
|
||||
0x18, 0x1f, 0x19, 0x1f, 0x1a, 0x1f, 0x1b, 0x1f,
|
||||
0x1c, 0x1f, 0x1d, 0x1f, 0x16, 0x1f, 0x17, 0x1f,
|
||||
0x18, 0x1f, 0x19, 0x1f, 0x1a, 0x1f, 0x1b, 0x1f,
|
||||
0x1c, 0x1f, 0x1d, 0x1f, 0x1e, 0x1f, 0x1f, 0x1f,
|
||||
0x28, 0x1f, 0x29, 0x1f, 0x2a, 0x1f, 0x2b, 0x1f,
|
||||
0x2c, 0x1f, 0x2d, 0x1f, 0x2e, 0x1f, 0x2f, 0x1f,
|
||||
0x28, 0x1f, 0x29, 0x1f, 0x2a, 0x1f, 0x2b, 0x1f,
|
||||
0x2c, 0x1f, 0x2d, 0x1f, 0x2e, 0x1f, 0x2f, 0x1f,
|
||||
0x38, 0x1f, 0x39, 0x1f, 0x3a, 0x1f, 0x3b, 0x1f,
|
||||
0x3c, 0x1f, 0x3d, 0x1f, 0x3e, 0x1f, 0x3f, 0x1f,
|
||||
0x38, 0x1f, 0x39, 0x1f, 0x3a, 0x1f, 0x3b, 0x1f,
|
||||
0x3c, 0x1f, 0x3d, 0x1f, 0x3e, 0x1f, 0x3f, 0x1f,
|
||||
0x48, 0x1f, 0x49, 0x1f, 0x4a, 0x1f, 0x4b, 0x1f,
|
||||
0x4c, 0x1f, 0x4d, 0x1f, 0x46, 0x1f, 0x47, 0x1f,
|
||||
0x48, 0x1f, 0x49, 0x1f, 0x4a, 0x1f, 0x4b, 0x1f,
|
||||
0x4c, 0x1f, 0x4d, 0x1f, 0x4e, 0x1f, 0x4f, 0x1f,
|
||||
0x50, 0x1f, 0x59, 0x1f, 0x52, 0x1f, 0x5b, 0x1f,
|
||||
0x54, 0x1f, 0x5d, 0x1f, 0x56, 0x1f, 0x5f, 0x1f,
|
||||
0x58, 0x1f, 0x59, 0x1f, 0x5a, 0x1f, 0x5b, 0x1f,
|
||||
0x5c, 0x1f, 0x5d, 0x1f, 0x5e, 0x1f, 0x5f, 0x1f,
|
||||
0x68, 0x1f, 0x69, 0x1f, 0x6a, 0x1f, 0x6b, 0x1f,
|
||||
0x6c, 0x1f, 0x6d, 0x1f, 0x6e, 0x1f, 0x6f, 0x1f,
|
||||
0x68, 0x1f, 0x69, 0x1f, 0x6a, 0x1f, 0x6b, 0x1f,
|
||||
0x6c, 0x1f, 0x6d, 0x1f, 0x6e, 0x1f, 0x6f, 0x1f,
|
||||
0xba, 0x1f, 0xbb, 0x1f, 0xc8, 0x1f, 0xc9, 0x1f,
|
||||
0xca, 0x1f, 0xcb, 0x1f, 0xda, 0x1f, 0xdb, 0x1f,
|
||||
0xf8, 0x1f, 0xf9, 0x1f, 0xea, 0x1f, 0xeb, 0x1f,
|
||||
0xfa, 0x1f, 0xfb, 0x1f, 0x7e, 0x1f, 0x7f, 0x1f,
|
||||
0x88, 0x1f, 0x89, 0x1f, 0x8a, 0x1f, 0x8b, 0x1f,
|
||||
0x8c, 0x1f, 0x8d, 0x1f, 0x8e, 0x1f, 0x8f, 0x1f,
|
||||
0x88, 0x1f, 0x89, 0x1f, 0x8a, 0x1f, 0x8b, 0x1f,
|
||||
0x8c, 0x1f, 0x8d, 0x1f, 0x8e, 0x1f, 0x8f, 0x1f,
|
||||
0x98, 0x1f, 0x99, 0x1f, 0x9a, 0x1f, 0x9b, 0x1f,
|
||||
0x9c, 0x1f, 0x9d, 0x1f, 0x9e, 0x1f, 0x9f, 0x1f,
|
||||
0x98, 0x1f, 0x99, 0x1f, 0x9a, 0x1f, 0x9b, 0x1f,
|
||||
0x9c, 0x1f, 0x9d, 0x1f, 0x9e, 0x1f, 0x9f, 0x1f,
|
||||
0xa8, 0x1f, 0xa9, 0x1f, 0xaa, 0x1f, 0xab, 0x1f,
|
||||
0xac, 0x1f, 0xad, 0x1f, 0xae, 0x1f, 0xaf, 0x1f,
|
||||
0xa8, 0x1f, 0xa9, 0x1f, 0xaa, 0x1f, 0xab, 0x1f,
|
||||
0xac, 0x1f, 0xad, 0x1f, 0xae, 0x1f, 0xaf, 0x1f,
|
||||
0xb8, 0x1f, 0xb9, 0x1f, 0xb2, 0x1f, 0xbc, 0x1f,
|
||||
0xb4, 0x1f, 0xb5, 0x1f, 0xb6, 0x1f, 0xb7, 0x1f,
|
||||
0xb8, 0x1f, 0xb9, 0x1f, 0xba, 0x1f, 0xbb, 0x1f,
|
||||
0xbc, 0x1f, 0xbd, 0x1f, 0xbe, 0x1f, 0xbf, 0x1f,
|
||||
0xc0, 0x1f, 0xc1, 0x1f, 0xc2, 0x1f, 0xc3, 0x1f,
|
||||
0xc4, 0x1f, 0xc5, 0x1f, 0xc6, 0x1f, 0xc7, 0x1f,
|
||||
0xc8, 0x1f, 0xc9, 0x1f, 0xca, 0x1f, 0xcb, 0x1f,
|
||||
0xc3, 0x1f, 0xcd, 0x1f, 0xce, 0x1f, 0xcf, 0x1f,
|
||||
0xd8, 0x1f, 0xd9, 0x1f, 0xd2, 0x1f, 0xd3, 0x1f,
|
||||
0xd4, 0x1f, 0xd5, 0x1f, 0xd6, 0x1f, 0xd7, 0x1f,
|
||||
0xd8, 0x1f, 0xd9, 0x1f, 0xda, 0x1f, 0xdb, 0x1f,
|
||||
0xdc, 0x1f, 0xdd, 0x1f, 0xde, 0x1f, 0xdf, 0x1f,
|
||||
0xe8, 0x1f, 0xe9, 0x1f, 0xe2, 0x1f, 0xe3, 0x1f,
|
||||
0xe4, 0x1f, 0xec, 0x1f, 0xe6, 0x1f, 0xe7, 0x1f,
|
||||
0xe8, 0x1f, 0xe9, 0x1f, 0xea, 0x1f, 0xeb, 0x1f,
|
||||
0xec, 0x1f, 0xed, 0x1f, 0xee, 0x1f, 0xef, 0x1f,
|
||||
0xf0, 0x1f, 0xf1, 0x1f, 0xf2, 0x1f, 0xf3, 0x1f,
|
||||
0xf4, 0x1f, 0xf5, 0x1f, 0xf6, 0x1f, 0xf7, 0x1f,
|
||||
0xf8, 0x1f, 0xf9, 0x1f, 0xfa, 0x1f, 0xfb, 0x1f,
|
||||
0xf3, 0x1f, 0xfd, 0x1f, 0xfe, 0x1f, 0xff, 0x1f,
|
||||
0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20,
|
||||
0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20,
|
||||
0x08, 0x20, 0x09, 0x20, 0x0a, 0x20, 0x0b, 0x20,
|
||||
0x0c, 0x20, 0x0d, 0x20, 0x0e, 0x20, 0x0f, 0x20,
|
||||
0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20,
|
||||
0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20,
|
||||
0x18, 0x20, 0x19, 0x20, 0x1a, 0x20, 0x1b, 0x20,
|
||||
0x1c, 0x20, 0x1d, 0x20, 0x1e, 0x20, 0x1f, 0x20,
|
||||
0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20,
|
||||
0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20,
|
||||
0x28, 0x20, 0x29, 0x20, 0x2a, 0x20, 0x2b, 0x20,
|
||||
0x2c, 0x20, 0x2d, 0x20, 0x2e, 0x20, 0x2f, 0x20,
|
||||
0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20,
|
||||
0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20,
|
||||
0x38, 0x20, 0x39, 0x20, 0x3a, 0x20, 0x3b, 0x20,
|
||||
0x3c, 0x20, 0x3d, 0x20, 0x3e, 0x20, 0x3f, 0x20,
|
||||
0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20,
|
||||
0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20,
|
||||
0x48, 0x20, 0x49, 0x20, 0x4a, 0x20, 0x4b, 0x20,
|
||||
0x4c, 0x20, 0x4d, 0x20, 0x4e, 0x20, 0x4f, 0x20,
|
||||
0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20,
|
||||
0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20,
|
||||
0x58, 0x20, 0x59, 0x20, 0x5a, 0x20, 0x5b, 0x20,
|
||||
0x5c, 0x20, 0x5d, 0x20, 0x5e, 0x20, 0x5f, 0x20,
|
||||
0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20,
|
||||
0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20,
|
||||
0x68, 0x20, 0x69, 0x20, 0x6a, 0x20, 0x6b, 0x20,
|
||||
0x6c, 0x20, 0x6d, 0x20, 0x6e, 0x20, 0x6f, 0x20,
|
||||
0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20,
|
||||
0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20,
|
||||
0x78, 0x20, 0x79, 0x20, 0x7a, 0x20, 0x7b, 0x20,
|
||||
0x7c, 0x20, 0x7d, 0x20, 0x7e, 0x20, 0x7f, 0x20,
|
||||
0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20,
|
||||
0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20,
|
||||
0x88, 0x20, 0x89, 0x20, 0x8a, 0x20, 0x8b, 0x20,
|
||||
0x8c, 0x20, 0x8d, 0x20, 0x8e, 0x20, 0x8f, 0x20,
|
||||
0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20,
|
||||
0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20,
|
||||
0x98, 0x20, 0x99, 0x20, 0x9a, 0x20, 0x9b, 0x20,
|
||||
0x9c, 0x20, 0x9d, 0x20, 0x9e, 0x20, 0x9f, 0x20,
|
||||
0xa0, 0x20, 0xa1, 0x20, 0xa2, 0x20, 0xa3, 0x20,
|
||||
0xa4, 0x20, 0xa5, 0x20, 0xa6, 0x20, 0xa7, 0x20,
|
||||
0xa8, 0x20, 0xa9, 0x20, 0xaa, 0x20, 0xab, 0x20,
|
||||
0xac, 0x20, 0xad, 0x20, 0xae, 0x20, 0xaf, 0x20,
|
||||
0xb0, 0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20,
|
||||
0xb4, 0x20, 0xb5, 0x20, 0xb6, 0x20, 0xb7, 0x20,
|
||||
0xb8, 0x20, 0xb9, 0x20, 0xba, 0x20, 0xbb, 0x20,
|
||||
0xbc, 0x20, 0xbd, 0x20, 0xbe, 0x20, 0xbf, 0x20,
|
||||
0xc0, 0x20, 0xc1, 0x20, 0xc2, 0x20, 0xc3, 0x20,
|
||||
0xc4, 0x20, 0xc5, 0x20, 0xc6, 0x20, 0xc7, 0x20,
|
||||
0xc8, 0x20, 0xc9, 0x20, 0xca, 0x20, 0xcb, 0x20,
|
||||
0xcc, 0x20, 0xcd, 0x20, 0xce, 0x20, 0xcf, 0x20,
|
||||
0xd0, 0x20, 0xd1, 0x20, 0xd2, 0x20, 0xd3, 0x20,
|
||||
0xd4, 0x20, 0xd5, 0x20, 0xd6, 0x20, 0xd7, 0x20,
|
||||
0xd8, 0x20, 0xd9, 0x20, 0xda, 0x20, 0xdb, 0x20,
|
||||
0xdc, 0x20, 0xdd, 0x20, 0xde, 0x20, 0xdf, 0x20,
|
||||
0xe0, 0x20, 0xe1, 0x20, 0xe2, 0x20, 0xe3, 0x20,
|
||||
0xe4, 0x20, 0xe5, 0x20, 0xe6, 0x20, 0xe7, 0x20,
|
||||
0xe8, 0x20, 0xe9, 0x20, 0xea, 0x20, 0xeb, 0x20,
|
||||
0xec, 0x20, 0xed, 0x20, 0xee, 0x20, 0xef, 0x20,
|
||||
0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3, 0x20,
|
||||
0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20,
|
||||
0xf8, 0x20, 0xf9, 0x20, 0xfa, 0x20, 0xfb, 0x20,
|
||||
0xfc, 0x20, 0xfd, 0x20, 0xfe, 0x20, 0xff, 0x20,
|
||||
0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21,
|
||||
0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21,
|
||||
0x08, 0x21, 0x09, 0x21, 0x0a, 0x21, 0x0b, 0x21,
|
||||
0x0c, 0x21, 0x0d, 0x21, 0x0e, 0x21, 0x0f, 0x21,
|
||||
0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21,
|
||||
0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21,
|
||||
0x18, 0x21, 0x19, 0x21, 0x1a, 0x21, 0x1b, 0x21,
|
||||
0x1c, 0x21, 0x1d, 0x21, 0x1e, 0x21, 0x1f, 0x21,
|
||||
0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21,
|
||||
0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21,
|
||||
0x28, 0x21, 0x29, 0x21, 0x2a, 0x21, 0x2b, 0x21,
|
||||
0x2c, 0x21, 0x2d, 0x21, 0x2e, 0x21, 0x2f, 0x21,
|
||||
0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21,
|
||||
0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21,
|
||||
0x38, 0x21, 0x39, 0x21, 0x3a, 0x21, 0x3b, 0x21,
|
||||
0x3c, 0x21, 0x3d, 0x21, 0x3e, 0x21, 0x3f, 0x21,
|
||||
0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21,
|
||||
0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21,
|
||||
0x48, 0x21, 0x49, 0x21, 0x4a, 0x21, 0x4b, 0x21,
|
||||
0x4c, 0x21, 0x4d, 0x21, 0x32, 0x21, 0x4f, 0x21,
|
||||
0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21,
|
||||
0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21,
|
||||
0x58, 0x21, 0x59, 0x21, 0x5a, 0x21, 0x5b, 0x21,
|
||||
0x5c, 0x21, 0x5d, 0x21, 0x5e, 0x21, 0x5f, 0x21,
|
||||
0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21,
|
||||
0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21,
|
||||
0x68, 0x21, 0x69, 0x21, 0x6a, 0x21, 0x6b, 0x21,
|
||||
0x6c, 0x21, 0x6d, 0x21, 0x6e, 0x21, 0x6f, 0x21,
|
||||
0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21,
|
||||
0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21,
|
||||
0x68, 0x21, 0x69, 0x21, 0x6a, 0x21, 0x6b, 0x21,
|
||||
0x6c, 0x21, 0x6d, 0x21, 0x6e, 0x21, 0x6f, 0x21,
|
||||
0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21,
|
||||
0x83, 0x21, 0xff, 0xff, 0x4b, 0x03, 0xb6, 0x24,
|
||||
0xb7, 0x24, 0xb8, 0x24, 0xb9, 0x24, 0xba, 0x24,
|
||||
0xbb, 0x24, 0xbc, 0x24, 0xbd, 0x24, 0xbe, 0x24,
|
||||
0xbf, 0x24, 0xc0, 0x24, 0xc1, 0x24, 0xc2, 0x24,
|
||||
0xc3, 0x24, 0xc4, 0x24, 0xc5, 0x24, 0xc6, 0x24,
|
||||
0xc7, 0x24, 0xc8, 0x24, 0xc9, 0x24, 0xca, 0x24,
|
||||
0xcb, 0x24, 0xcc, 0x24, 0xcd, 0x24, 0xce, 0x24,
|
||||
0xcf, 0x24, 0xff, 0xff, 0x46, 0x07, 0x00, 0x2c,
|
||||
0x01, 0x2c, 0x02, 0x2c, 0x03, 0x2c, 0x04, 0x2c,
|
||||
0x05, 0x2c, 0x06, 0x2c, 0x07, 0x2c, 0x08, 0x2c,
|
||||
0x09, 0x2c, 0x0a, 0x2c, 0x0b, 0x2c, 0x0c, 0x2c,
|
||||
0x0d, 0x2c, 0x0e, 0x2c, 0x0f, 0x2c, 0x10, 0x2c,
|
||||
0x11, 0x2c, 0x12, 0x2c, 0x13, 0x2c, 0x14, 0x2c,
|
||||
0x15, 0x2c, 0x16, 0x2c, 0x17, 0x2c, 0x18, 0x2c,
|
||||
0x19, 0x2c, 0x1a, 0x2c, 0x1b, 0x2c, 0x1c, 0x2c,
|
||||
0x1d, 0x2c, 0x1e, 0x2c, 0x1f, 0x2c, 0x20, 0x2c,
|
||||
0x21, 0x2c, 0x22, 0x2c, 0x23, 0x2c, 0x24, 0x2c,
|
||||
0x25, 0x2c, 0x26, 0x2c, 0x27, 0x2c, 0x28, 0x2c,
|
||||
0x29, 0x2c, 0x2a, 0x2c, 0x2b, 0x2c, 0x2c, 0x2c,
|
||||
0x2d, 0x2c, 0x2e, 0x2c, 0x5f, 0x2c, 0x60, 0x2c,
|
||||
0x60, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x2c,
|
||||
0x65, 0x2c, 0x66, 0x2c, 0x67, 0x2c, 0x67, 0x2c,
|
||||
0x69, 0x2c, 0x69, 0x2c, 0x6b, 0x2c, 0x6b, 0x2c,
|
||||
0x6d, 0x2c, 0x6e, 0x2c, 0x6f, 0x2c, 0x70, 0x2c,
|
||||
0x71, 0x2c, 0x72, 0x2c, 0x73, 0x2c, 0x74, 0x2c,
|
||||
0x75, 0x2c, 0x75, 0x2c, 0x77, 0x2c, 0x78, 0x2c,
|
||||
0x79, 0x2c, 0x7a, 0x2c, 0x7b, 0x2c, 0x7c, 0x2c,
|
||||
0x7d, 0x2c, 0x7e, 0x2c, 0x7f, 0x2c, 0x80, 0x2c,
|
||||
0x80, 0x2c, 0x82, 0x2c, 0x82, 0x2c, 0x84, 0x2c,
|
||||
0x84, 0x2c, 0x86, 0x2c, 0x86, 0x2c, 0x88, 0x2c,
|
||||
0x88, 0x2c, 0x8a, 0x2c, 0x8a, 0x2c, 0x8c, 0x2c,
|
||||
0x8c, 0x2c, 0x8e, 0x2c, 0x8e, 0x2c, 0x90, 0x2c,
|
||||
0x90, 0x2c, 0x92, 0x2c, 0x92, 0x2c, 0x94, 0x2c,
|
||||
0x94, 0x2c, 0x96, 0x2c, 0x96, 0x2c, 0x98, 0x2c,
|
||||
0x98, 0x2c, 0x9a, 0x2c, 0x9a, 0x2c, 0x9c, 0x2c,
|
||||
0x9c, 0x2c, 0x9e, 0x2c, 0x9e, 0x2c, 0xa0, 0x2c,
|
||||
0xa0, 0x2c, 0xa2, 0x2c, 0xa2, 0x2c, 0xa4, 0x2c,
|
||||
0xa4, 0x2c, 0xa6, 0x2c, 0xa6, 0x2c, 0xa8, 0x2c,
|
||||
0xa8, 0x2c, 0xaa, 0x2c, 0xaa, 0x2c, 0xac, 0x2c,
|
||||
0xac, 0x2c, 0xae, 0x2c, 0xae, 0x2c, 0xb0, 0x2c,
|
||||
0xb0, 0x2c, 0xb2, 0x2c, 0xb2, 0x2c, 0xb4, 0x2c,
|
||||
0xb4, 0x2c, 0xb6, 0x2c, 0xb6, 0x2c, 0xb8, 0x2c,
|
||||
0xb8, 0x2c, 0xba, 0x2c, 0xba, 0x2c, 0xbc, 0x2c,
|
||||
0xbc, 0x2c, 0xbe, 0x2c, 0xbe, 0x2c, 0xc0, 0x2c,
|
||||
0xc0, 0x2c, 0xc2, 0x2c, 0xc2, 0x2c, 0xc4, 0x2c,
|
||||
0xc4, 0x2c, 0xc6, 0x2c, 0xc6, 0x2c, 0xc8, 0x2c,
|
||||
0xc8, 0x2c, 0xca, 0x2c, 0xca, 0x2c, 0xcc, 0x2c,
|
||||
0xcc, 0x2c, 0xce, 0x2c, 0xce, 0x2c, 0xd0, 0x2c,
|
||||
0xd0, 0x2c, 0xd2, 0x2c, 0xd2, 0x2c, 0xd4, 0x2c,
|
||||
0xd4, 0x2c, 0xd6, 0x2c, 0xd6, 0x2c, 0xd8, 0x2c,
|
||||
0xd8, 0x2c, 0xda, 0x2c, 0xda, 0x2c, 0xdc, 0x2c,
|
||||
0xdc, 0x2c, 0xde, 0x2c, 0xde, 0x2c, 0xe0, 0x2c,
|
||||
0xe0, 0x2c, 0xe2, 0x2c, 0xe2, 0x2c, 0xe4, 0x2c,
|
||||
0xe5, 0x2c, 0xe6, 0x2c, 0xe7, 0x2c, 0xe8, 0x2c,
|
||||
0xe9, 0x2c, 0xea, 0x2c, 0xeb, 0x2c, 0xec, 0x2c,
|
||||
0xed, 0x2c, 0xee, 0x2c, 0xef, 0x2c, 0xf0, 0x2c,
|
||||
0xf1, 0x2c, 0xf2, 0x2c, 0xf3, 0x2c, 0xf4, 0x2c,
|
||||
0xf5, 0x2c, 0xf6, 0x2c, 0xf7, 0x2c, 0xf8, 0x2c,
|
||||
0xf9, 0x2c, 0xfa, 0x2c, 0xfb, 0x2c, 0xfc, 0x2c,
|
||||
0xfd, 0x2c, 0xfe, 0x2c, 0xff, 0x2c, 0xa0, 0x10,
|
||||
0xa1, 0x10, 0xa2, 0x10, 0xa3, 0x10, 0xa4, 0x10,
|
||||
0xa5, 0x10, 0xa6, 0x10, 0xa7, 0x10, 0xa8, 0x10,
|
||||
0xa9, 0x10, 0xaa, 0x10, 0xab, 0x10, 0xac, 0x10,
|
||||
0xad, 0x10, 0xae, 0x10, 0xaf, 0x10, 0xb0, 0x10,
|
||||
0xb1, 0x10, 0xb2, 0x10, 0xb3, 0x10, 0xb4, 0x10,
|
||||
0xb5, 0x10, 0xb6, 0x10, 0xb7, 0x10, 0xb8, 0x10,
|
||||
0xb9, 0x10, 0xba, 0x10, 0xbb, 0x10, 0xbc, 0x10,
|
||||
0xbd, 0x10, 0xbe, 0x10, 0xbf, 0x10, 0xc0, 0x10,
|
||||
0xc1, 0x10, 0xc2, 0x10, 0xc3, 0x10, 0xc4, 0x10,
|
||||
0xc5, 0x10, 0xff, 0xff, 0x1b, 0xd2, 0x21, 0xff,
|
||||
0x22, 0xff, 0x23, 0xff, 0x24, 0xff, 0x25, 0xff,
|
||||
0x26, 0xff, 0x27, 0xff, 0x28, 0xff, 0x29, 0xff,
|
||||
0x2a, 0xff, 0x2b, 0xff, 0x2c, 0xff, 0x2d, 0xff,
|
||||
0x2e, 0xff, 0x2f, 0xff, 0x30, 0xff, 0x31, 0xff,
|
||||
0x32, 0xff, 0x33, 0xff, 0x34, 0xff, 0x35, 0xff,
|
||||
0x36, 0xff, 0x37, 0xff, 0x38, 0xff, 0x39, 0xff,
|
||||
0x3a, 0xff, 0x5b, 0xff, 0x5c, 0xff, 0x5d, 0xff,
|
||||
0x5e, 0xff, 0x5f, 0xff, 0x60, 0xff, 0x61, 0xff,
|
||||
0x62, 0xff, 0x63, 0xff, 0x64, 0xff, 0x65, 0xff,
|
||||
0x66, 0xff, 0x67, 0xff, 0x68, 0xff, 0x69, 0xff,
|
||||
0x6a, 0xff, 0x6b, 0xff, 0x6c, 0xff, 0x6d, 0xff,
|
||||
0x6e, 0xff, 0x6f, 0xff, 0x70, 0xff, 0x71, 0xff,
|
||||
0x72, 0xff, 0x73, 0xff, 0x74, 0xff, 0x75, 0xff,
|
||||
0x76, 0xff, 0x77, 0xff, 0x78, 0xff, 0x79, 0xff,
|
||||
0x7a, 0xff, 0x7b, 0xff, 0x7c, 0xff, 0x7d, 0xff,
|
||||
0x7e, 0xff, 0x7f, 0xff, 0x80, 0xff, 0x81, 0xff,
|
||||
0x82, 0xff, 0x83, 0xff, 0x84, 0xff, 0x85, 0xff,
|
||||
0x86, 0xff, 0x87, 0xff, 0x88, 0xff, 0x89, 0xff,
|
||||
0x8a, 0xff, 0x8b, 0xff, 0x8c, 0xff, 0x8d, 0xff,
|
||||
0x8e, 0xff, 0x8f, 0xff, 0x90, 0xff, 0x91, 0xff,
|
||||
0x92, 0xff, 0x93, 0xff, 0x94, 0xff, 0x95, 0xff,
|
||||
0x96, 0xff, 0x97, 0xff, 0x98, 0xff, 0x99, 0xff,
|
||||
0x9a, 0xff, 0x9b, 0xff, 0x9c, 0xff, 0x9d, 0xff,
|
||||
0x9e, 0xff, 0x9f, 0xff, 0xa0, 0xff, 0xa1, 0xff,
|
||||
0xa2, 0xff, 0xa3, 0xff, 0xa4, 0xff, 0xa5, 0xff,
|
||||
0xa6, 0xff, 0xa7, 0xff, 0xa8, 0xff, 0xa9, 0xff,
|
||||
0xaa, 0xff, 0xab, 0xff, 0xac, 0xff, 0xad, 0xff,
|
||||
0xae, 0xff, 0xaf, 0xff, 0xb0, 0xff, 0xb1, 0xff,
|
||||
0xb2, 0xff, 0xb3, 0xff, 0xb4, 0xff, 0xb5, 0xff,
|
||||
0xb6, 0xff, 0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xff,
|
||||
0xba, 0xff, 0xbb, 0xff, 0xbc, 0xff, 0xbd, 0xff,
|
||||
0xbe, 0xff, 0xbf, 0xff, 0xc0, 0xff, 0xc1, 0xff,
|
||||
0xc2, 0xff, 0xc3, 0xff, 0xc4, 0xff, 0xc5, 0xff,
|
||||
0xc6, 0xff, 0xc7, 0xff, 0xc8, 0xff, 0xc9, 0xff,
|
||||
0xca, 0xff, 0xcb, 0xff, 0xcc, 0xff, 0xcd, 0xff,
|
||||
0xce, 0xff, 0xcf, 0xff, 0xd0, 0xff, 0xd1, 0xff,
|
||||
0xd2, 0xff, 0xd3, 0xff, 0xd4, 0xff, 0xd5, 0xff,
|
||||
0xd6, 0xff, 0xd7, 0xff, 0xd8, 0xff, 0xd9, 0xff,
|
||||
0xda, 0xff, 0xdb, 0xff, 0xdc, 0xff, 0xdd, 0xff,
|
||||
0xde, 0xff, 0xdf, 0xff, 0xe0, 0xff, 0xe1, 0xff,
|
||||
0xe2, 0xff, 0xe3, 0xff, 0xe4, 0xff, 0xe5, 0xff,
|
||||
0xe6, 0xff, 0xe7, 0xff, 0xe8, 0xff, 0xe9, 0xff,
|
||||
0xea, 0xff, 0xeb, 0xff, 0xec, 0xff, 0xed, 0xff,
|
||||
0xee, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xf1, 0xff,
|
||||
0xf2, 0xff, 0xf3, 0xff, 0xf4, 0xff, 0xf5, 0xff,
|
||||
0xf6, 0xff, 0xf7, 0xff, 0xf8, 0xff, 0xf9, 0xff,
|
||||
0xfa, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfd, 0xff,
|
||||
0xfe, 0xff, 0xff, 0xff
|
||||
};
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
uctc.h (30.10.10)
|
||||
Upper Case Table declaration.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_UCTC_H_INCLUDED
|
||||
#define MKFS_UCTC_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint8_t upcase_table[5836];
|
||||
|
||||
#endif /* ifndef MKFS_UCTC_H_INCLUDED */
|
||||
+514
@@ -0,0 +1,514 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "exfat_ondisk.h"
|
||||
#include "libexfat.h"
|
||||
#include "mkfs.h"
|
||||
|
||||
static const unsigned char upcase_table[EXFAT_UPCASE_TABLE_SIZE] = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00,
|
||||
0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00,
|
||||
0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x11, 0x00,
|
||||
0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
|
||||
0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, 0x1C, 0x00, 0x1D, 0x00,
|
||||
0x1E, 0x00, 0x1F, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00,
|
||||
0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x28, 0x00, 0x29, 0x00,
|
||||
0x2A, 0x00, 0x2B, 0x00, 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00,
|
||||
0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00,
|
||||
0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00,
|
||||
0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40, 0x00, 0x41, 0x00,
|
||||
0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
|
||||
0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00,
|
||||
0x4E, 0x00, 0x4F, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
|
||||
0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00,
|
||||
0x5A, 0x00, 0x5B, 0x00, 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00,
|
||||
0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00,
|
||||
0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00,
|
||||
0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, 0x50, 0x00, 0x51, 0x00,
|
||||
0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
|
||||
0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7B, 0x00, 0x7C, 0x00, 0x7D, 0x00,
|
||||
0x7E, 0x00, 0x7F, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00,
|
||||
0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89, 0x00,
|
||||
0x8A, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00,
|
||||
0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00,
|
||||
0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00,
|
||||
0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00, 0xA0, 0x00, 0xA1, 0x00,
|
||||
0xA2, 0x00, 0xA3, 0x00, 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00,
|
||||
0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00, 0xAC, 0x00, 0xAD, 0x00,
|
||||
0xAE, 0x00, 0xAF, 0x00, 0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00,
|
||||
0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00, 0xB8, 0x00, 0xB9, 0x00,
|
||||
0xBA, 0x00, 0xBB, 0x00, 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00,
|
||||
0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0xC4, 0x00, 0xC5, 0x00,
|
||||
0xC6, 0x00, 0xC7, 0x00, 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00,
|
||||
0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, 0xD0, 0x00, 0xD1, 0x00,
|
||||
0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00,
|
||||
0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0xDD, 0x00,
|
||||
0xDE, 0x00, 0xDF, 0x00, 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00,
|
||||
0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, 0xC8, 0x00, 0xC9, 0x00,
|
||||
0xCA, 0x00, 0xCB, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00,
|
||||
0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00,
|
||||
0xD6, 0x00, 0xF7, 0x00, 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00,
|
||||
0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0x78, 0x01, 0x00, 0x01, 0x00, 0x01,
|
||||
0x02, 0x01, 0x02, 0x01, 0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01,
|
||||
0x08, 0x01, 0x08, 0x01, 0x0A, 0x01, 0x0A, 0x01, 0x0C, 0x01, 0x0C, 0x01,
|
||||
0x0E, 0x01, 0x0E, 0x01, 0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01,
|
||||
0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01, 0x18, 0x01, 0x18, 0x01,
|
||||
0x1A, 0x01, 0x1A, 0x01, 0x1C, 0x01, 0x1C, 0x01, 0x1E, 0x01, 0x1E, 0x01,
|
||||
0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01, 0x24, 0x01, 0x24, 0x01,
|
||||
0x26, 0x01, 0x26, 0x01, 0x28, 0x01, 0x28, 0x01, 0x2A, 0x01, 0x2A, 0x01,
|
||||
0x2C, 0x01, 0x2C, 0x01, 0x2E, 0x01, 0x2E, 0x01, 0x30, 0x01, 0x31, 0x01,
|
||||
0x32, 0x01, 0x32, 0x01, 0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01,
|
||||
0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3B, 0x01, 0x3B, 0x01, 0x3D, 0x01,
|
||||
0x3D, 0x01, 0x3F, 0x01, 0x3F, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01,
|
||||
0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01, 0x47, 0x01, 0x49, 0x01,
|
||||
0x4A, 0x01, 0x4A, 0x01, 0x4C, 0x01, 0x4C, 0x01, 0x4E, 0x01, 0x4E, 0x01,
|
||||
0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01, 0x54, 0x01, 0x54, 0x01,
|
||||
0x56, 0x01, 0x56, 0x01, 0x58, 0x01, 0x58, 0x01, 0x5A, 0x01, 0x5A, 0x01,
|
||||
0x5C, 0x01, 0x5C, 0x01, 0x5E, 0x01, 0x5E, 0x01, 0x60, 0x01, 0x60, 0x01,
|
||||
0x62, 0x01, 0x62, 0x01, 0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01,
|
||||
0x68, 0x01, 0x68, 0x01, 0x6A, 0x01, 0x6A, 0x01, 0x6C, 0x01, 0x6C, 0x01,
|
||||
0x6E, 0x01, 0x6E, 0x01, 0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01,
|
||||
0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01, 0x78, 0x01, 0x79, 0x01,
|
||||
0x79, 0x01, 0x7B, 0x01, 0x7B, 0x01, 0x7D, 0x01, 0x7D, 0x01, 0x7F, 0x01,
|
||||
0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01, 0x84, 0x01, 0x84, 0x01,
|
||||
0x86, 0x01, 0x87, 0x01, 0x87, 0x01, 0x89, 0x01, 0x8A, 0x01, 0x8B, 0x01,
|
||||
0x8B, 0x01, 0x8D, 0x01, 0x8E, 0x01, 0x8F, 0x01, 0x90, 0x01, 0x91, 0x01,
|
||||
0x91, 0x01, 0x93, 0x01, 0x94, 0x01, 0xF6, 0x01, 0x96, 0x01, 0x97, 0x01,
|
||||
0x98, 0x01, 0x98, 0x01, 0x3D, 0x02, 0x9B, 0x01, 0x9C, 0x01, 0x9D, 0x01,
|
||||
0x20, 0x02, 0x9F, 0x01, 0xA0, 0x01, 0xA0, 0x01, 0xA2, 0x01, 0xA2, 0x01,
|
||||
0xA4, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0xA7, 0x01, 0xA7, 0x01, 0xA9, 0x01,
|
||||
0xAA, 0x01, 0xAB, 0x01, 0xAC, 0x01, 0xAC, 0x01, 0xAE, 0x01, 0xAF, 0x01,
|
||||
0xAF, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xB3, 0x01, 0xB3, 0x01, 0xB5, 0x01,
|
||||
0xB5, 0x01, 0xB7, 0x01, 0xB8, 0x01, 0xB8, 0x01, 0xBA, 0x01, 0xBB, 0x01,
|
||||
0xBC, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xF7, 0x01, 0xC0, 0x01, 0xC1, 0x01,
|
||||
0xC2, 0x01, 0xC3, 0x01, 0xC4, 0x01, 0xC5, 0x01, 0xC4, 0x01, 0xC7, 0x01,
|
||||
0xC8, 0x01, 0xC7, 0x01, 0xCA, 0x01, 0xCB, 0x01, 0xCA, 0x01, 0xCD, 0x01,
|
||||
0xCD, 0x01, 0xCF, 0x01, 0xCF, 0x01, 0xD1, 0x01, 0xD1, 0x01, 0xD3, 0x01,
|
||||
0xD3, 0x01, 0xD5, 0x01, 0xD5, 0x01, 0xD7, 0x01, 0xD7, 0x01, 0xD9, 0x01,
|
||||
0xD9, 0x01, 0xDB, 0x01, 0xDB, 0x01, 0x8E, 0x01, 0xDE, 0x01, 0xDE, 0x01,
|
||||
0xE0, 0x01, 0xE0, 0x01, 0xE2, 0x01, 0xE2, 0x01, 0xE4, 0x01, 0xE4, 0x01,
|
||||
0xE6, 0x01, 0xE6, 0x01, 0xE8, 0x01, 0xE8, 0x01, 0xEA, 0x01, 0xEA, 0x01,
|
||||
0xEC, 0x01, 0xEC, 0x01, 0xEE, 0x01, 0xEE, 0x01, 0xF0, 0x01, 0xF1, 0x01,
|
||||
0xF2, 0x01, 0xF1, 0x01, 0xF4, 0x01, 0xF4, 0x01, 0xF6, 0x01, 0xF7, 0x01,
|
||||
0xF8, 0x01, 0xF8, 0x01, 0xFA, 0x01, 0xFA, 0x01, 0xFC, 0x01, 0xFC, 0x01,
|
||||
0xFE, 0x01, 0xFE, 0x01, 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02, 0x08, 0x02, 0x08, 0x02,
|
||||
0x0A, 0x02, 0x0A, 0x02, 0x0C, 0x02, 0x0C, 0x02, 0x0E, 0x02, 0x0E, 0x02,
|
||||
0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02, 0x14, 0x02, 0x14, 0x02,
|
||||
0x16, 0x02, 0x16, 0x02, 0x18, 0x02, 0x18, 0x02, 0x1A, 0x02, 0x1A, 0x02,
|
||||
0x1C, 0x02, 0x1C, 0x02, 0x1E, 0x02, 0x1E, 0x02, 0x20, 0x02, 0x21, 0x02,
|
||||
0x22, 0x02, 0x22, 0x02, 0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02,
|
||||
0x28, 0x02, 0x28, 0x02, 0x2A, 0x02, 0x2A, 0x02, 0x2C, 0x02, 0x2C, 0x02,
|
||||
0x2E, 0x02, 0x2E, 0x02, 0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02,
|
||||
0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02, 0x38, 0x02, 0x39, 0x02,
|
||||
0x65, 0x2C, 0x3B, 0x02, 0x3B, 0x02, 0x3D, 0x02, 0x66, 0x2C, 0x3F, 0x02,
|
||||
0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02, 0x44, 0x02, 0x45, 0x02,
|
||||
0x46, 0x02, 0x46, 0x02, 0x48, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x4A, 0x02,
|
||||
0x4C, 0x02, 0x4C, 0x02, 0x4E, 0x02, 0x4E, 0x02, 0x50, 0x02, 0x51, 0x02,
|
||||
0x52, 0x02, 0x81, 0x01, 0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8A, 0x01,
|
||||
0x58, 0x02, 0x8F, 0x01, 0x5A, 0x02, 0x90, 0x01, 0x5C, 0x02, 0x5D, 0x02,
|
||||
0x5E, 0x02, 0x5F, 0x02, 0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01,
|
||||
0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02, 0x97, 0x01, 0x96, 0x01,
|
||||
0x6A, 0x02, 0x62, 0x2C, 0x6C, 0x02, 0x6D, 0x02, 0x6E, 0x02, 0x9C, 0x01,
|
||||
0x70, 0x02, 0x71, 0x02, 0x9D, 0x01, 0x73, 0x02, 0x74, 0x02, 0x9F, 0x01,
|
||||
0x76, 0x02, 0x77, 0x02, 0x78, 0x02, 0x79, 0x02, 0x7A, 0x02, 0x7B, 0x02,
|
||||
0x7C, 0x02, 0x64, 0x2C, 0x7E, 0x02, 0x7F, 0x02, 0xA6, 0x01, 0x81, 0x02,
|
||||
0x82, 0x02, 0xA9, 0x01, 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02,
|
||||
0xAE, 0x01, 0x44, 0x02, 0xB1, 0x01, 0xB2, 0x01, 0x45, 0x02, 0x8D, 0x02,
|
||||
0x8E, 0x02, 0x8F, 0x02, 0x90, 0x02, 0x91, 0x02, 0xB7, 0x01, 0x93, 0x02,
|
||||
0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02, 0x98, 0x02, 0x99, 0x02,
|
||||
0x9A, 0x02, 0x9B, 0x02, 0x9C, 0x02, 0x9D, 0x02, 0x9E, 0x02, 0x9F, 0x02,
|
||||
0xA0, 0x02, 0xA1, 0x02, 0xA2, 0x02, 0xA3, 0x02, 0xA4, 0x02, 0xA5, 0x02,
|
||||
0xA6, 0x02, 0xA7, 0x02, 0xA8, 0x02, 0xA9, 0x02, 0xAA, 0x02, 0xAB, 0x02,
|
||||
0xAC, 0x02, 0xAD, 0x02, 0xAE, 0x02, 0xAF, 0x02, 0xB0, 0x02, 0xB1, 0x02,
|
||||
0xB2, 0x02, 0xB3, 0x02, 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, 0xB7, 0x02,
|
||||
0xB8, 0x02, 0xB9, 0x02, 0xBA, 0x02, 0xBB, 0x02, 0xBC, 0x02, 0xBD, 0x02,
|
||||
0xBE, 0x02, 0xBF, 0x02, 0xC0, 0x02, 0xC1, 0x02, 0xC2, 0x02, 0xC3, 0x02,
|
||||
0xC4, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC7, 0x02, 0xC8, 0x02, 0xC9, 0x02,
|
||||
0xCA, 0x02, 0xCB, 0x02, 0xCC, 0x02, 0xCD, 0x02, 0xCE, 0x02, 0xCF, 0x02,
|
||||
0xD0, 0x02, 0xD1, 0x02, 0xD2, 0x02, 0xD3, 0x02, 0xD4, 0x02, 0xD5, 0x02,
|
||||
0xD6, 0x02, 0xD7, 0x02, 0xD8, 0x02, 0xD9, 0x02, 0xDA, 0x02, 0xDB, 0x02,
|
||||
0xDC, 0x02, 0xDD, 0x02, 0xDE, 0x02, 0xDF, 0x02, 0xE0, 0x02, 0xE1, 0x02,
|
||||
0xE2, 0x02, 0xE3, 0x02, 0xE4, 0x02, 0xE5, 0x02, 0xE6, 0x02, 0xE7, 0x02,
|
||||
0xE8, 0x02, 0xE9, 0x02, 0xEA, 0x02, 0xEB, 0x02, 0xEC, 0x02, 0xED, 0x02,
|
||||
0xEE, 0x02, 0xEF, 0x02, 0xF0, 0x02, 0xF1, 0x02, 0xF2, 0x02, 0xF3, 0x02,
|
||||
0xF4, 0x02, 0xF5, 0x02, 0xF6, 0x02, 0xF7, 0x02, 0xF8, 0x02, 0xF9, 0x02,
|
||||
0xFA, 0x02, 0xFB, 0x02, 0xFC, 0x02, 0xFD, 0x02, 0xFE, 0x02, 0xFF, 0x02,
|
||||
0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03, 0x04, 0x03, 0x05, 0x03,
|
||||
0x06, 0x03, 0x07, 0x03, 0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x03,
|
||||
0x0C, 0x03, 0x0D, 0x03, 0x0E, 0x03, 0x0F, 0x03, 0x10, 0x03, 0x11, 0x03,
|
||||
0x12, 0x03, 0x13, 0x03, 0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03,
|
||||
0x18, 0x03, 0x19, 0x03, 0x1A, 0x03, 0x1B, 0x03, 0x1C, 0x03, 0x1D, 0x03,
|
||||
0x1E, 0x03, 0x1F, 0x03, 0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03,
|
||||
0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03, 0x28, 0x03, 0x29, 0x03,
|
||||
0x2A, 0x03, 0x2B, 0x03, 0x2C, 0x03, 0x2D, 0x03, 0x2E, 0x03, 0x2F, 0x03,
|
||||
0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03, 0x34, 0x03, 0x35, 0x03,
|
||||
0x36, 0x03, 0x37, 0x03, 0x38, 0x03, 0x39, 0x03, 0x3A, 0x03, 0x3B, 0x03,
|
||||
0x3C, 0x03, 0x3D, 0x03, 0x3E, 0x03, 0x3F, 0x03, 0x40, 0x03, 0x41, 0x03,
|
||||
0x42, 0x03, 0x43, 0x03, 0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03,
|
||||
0x48, 0x03, 0x49, 0x03, 0x4A, 0x03, 0x4B, 0x03, 0x4C, 0x03, 0x4D, 0x03,
|
||||
0x4E, 0x03, 0x4F, 0x03, 0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03,
|
||||
0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03, 0x58, 0x03, 0x59, 0x03,
|
||||
0x5A, 0x03, 0x5B, 0x03, 0x5C, 0x03, 0x5D, 0x03, 0x5E, 0x03, 0x5F, 0x03,
|
||||
0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03, 0x64, 0x03, 0x65, 0x03,
|
||||
0x66, 0x03, 0x67, 0x03, 0x68, 0x03, 0x69, 0x03, 0x6A, 0x03, 0x6B, 0x03,
|
||||
0x6C, 0x03, 0x6D, 0x03, 0x6E, 0x03, 0x6F, 0x03, 0x70, 0x03, 0x71, 0x03,
|
||||
0x72, 0x03, 0x73, 0x03, 0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03,
|
||||
0x78, 0x03, 0x79, 0x03, 0x7A, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03,
|
||||
0x7E, 0x03, 0x7F, 0x03, 0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03,
|
||||
0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03, 0x88, 0x03, 0x89, 0x03,
|
||||
0x8A, 0x03, 0x8B, 0x03, 0x8C, 0x03, 0x8D, 0x03, 0x8E, 0x03, 0x8F, 0x03,
|
||||
0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95, 0x03,
|
||||
0x96, 0x03, 0x97, 0x03, 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03,
|
||||
0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, 0xA0, 0x03, 0xA1, 0x03,
|
||||
0xA2, 0x03, 0xA3, 0x03, 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03,
|
||||
0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, 0x86, 0x03, 0x88, 0x03,
|
||||
0x89, 0x03, 0x8A, 0x03, 0xB0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03,
|
||||
0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, 0x98, 0x03, 0x99, 0x03,
|
||||
0x9A, 0x03, 0x9B, 0x03, 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03,
|
||||
0xA0, 0x03, 0xA1, 0x03, 0xA3, 0x03, 0xA3, 0x03, 0xA4, 0x03, 0xA5, 0x03,
|
||||
0xA6, 0x03, 0xA7, 0x03, 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03,
|
||||
0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0xCF, 0x03, 0xD0, 0x03, 0xD1, 0x03,
|
||||
0xD2, 0x03, 0xD3, 0x03, 0xD4, 0x03, 0xD5, 0x03, 0xD6, 0x03, 0xD7, 0x03,
|
||||
0xD8, 0x03, 0xD8, 0x03, 0xDA, 0x03, 0xDA, 0x03, 0xDC, 0x03, 0xDC, 0x03,
|
||||
0xDE, 0x03, 0xDE, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE2, 0x03, 0xE2, 0x03,
|
||||
0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03, 0xE8, 0x03, 0xE8, 0x03,
|
||||
0xEA, 0x03, 0xEA, 0x03, 0xEC, 0x03, 0xEC, 0x03, 0xEE, 0x03, 0xEE, 0x03,
|
||||
0xF0, 0x03, 0xF1, 0x03, 0xF9, 0x03, 0xF3, 0x03, 0xF4, 0x03, 0xF5, 0x03,
|
||||
0xF6, 0x03, 0xF7, 0x03, 0xF7, 0x03, 0xF9, 0x03, 0xFA, 0x03, 0xFA, 0x03,
|
||||
0xFC, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, 0x00, 0x04, 0x01, 0x04,
|
||||
0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
|
||||
0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, 0x0C, 0x04, 0x0D, 0x04,
|
||||
0x0E, 0x04, 0x0F, 0x04, 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04,
|
||||
0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, 0x18, 0x04, 0x19, 0x04,
|
||||
0x1A, 0x04, 0x1B, 0x04, 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04,
|
||||
0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04,
|
||||
0x26, 0x04, 0x27, 0x04, 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04,
|
||||
0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, 0x10, 0x04, 0x11, 0x04,
|
||||
0x12, 0x04, 0x13, 0x04, 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
|
||||
0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, 0x1C, 0x04, 0x1D, 0x04,
|
||||
0x1E, 0x04, 0x1F, 0x04, 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04,
|
||||
0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, 0x28, 0x04, 0x29, 0x04,
|
||||
0x2A, 0x04, 0x2B, 0x04, 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04,
|
||||
0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04,
|
||||
0x06, 0x04, 0x07, 0x04, 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04,
|
||||
0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, 0x60, 0x04, 0x60, 0x04,
|
||||
0x62, 0x04, 0x62, 0x04, 0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04,
|
||||
0x68, 0x04, 0x68, 0x04, 0x6A, 0x04, 0x6A, 0x04, 0x6C, 0x04, 0x6C, 0x04,
|
||||
0x6E, 0x04, 0x6E, 0x04, 0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04,
|
||||
0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04, 0x78, 0x04, 0x78, 0x04,
|
||||
0x7A, 0x04, 0x7A, 0x04, 0x7C, 0x04, 0x7C, 0x04, 0x7E, 0x04, 0x7E, 0x04,
|
||||
0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04, 0x84, 0x04, 0x85, 0x04,
|
||||
0x86, 0x04, 0x87, 0x04, 0x88, 0x04, 0x89, 0x04, 0x8A, 0x04, 0x8A, 0x04,
|
||||
0x8C, 0x04, 0x8C, 0x04, 0x8E, 0x04, 0x8E, 0x04, 0x90, 0x04, 0x90, 0x04,
|
||||
0x92, 0x04, 0x92, 0x04, 0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04,
|
||||
0x98, 0x04, 0x98, 0x04, 0x9A, 0x04, 0x9A, 0x04, 0x9C, 0x04, 0x9C, 0x04,
|
||||
0x9E, 0x04, 0x9E, 0x04, 0xA0, 0x04, 0xA0, 0x04, 0xA2, 0x04, 0xA2, 0x04,
|
||||
0xA4, 0x04, 0xA4, 0x04, 0xA6, 0x04, 0xA6, 0x04, 0xA8, 0x04, 0xA8, 0x04,
|
||||
0xAA, 0x04, 0xAA, 0x04, 0xAC, 0x04, 0xAC, 0x04, 0xAE, 0x04, 0xAE, 0x04,
|
||||
0xB0, 0x04, 0xB0, 0x04, 0xB2, 0x04, 0xB2, 0x04, 0xB4, 0x04, 0xB4, 0x04,
|
||||
0xB6, 0x04, 0xB6, 0x04, 0xB8, 0x04, 0xB8, 0x04, 0xBA, 0x04, 0xBA, 0x04,
|
||||
0xBC, 0x04, 0xBC, 0x04, 0xBE, 0x04, 0xBE, 0x04, 0xC0, 0x04, 0xC1, 0x04,
|
||||
0xC1, 0x04, 0xC3, 0x04, 0xC3, 0x04, 0xC5, 0x04, 0xC5, 0x04, 0xC7, 0x04,
|
||||
0xC7, 0x04, 0xC9, 0x04, 0xC9, 0x04, 0xCB, 0x04, 0xCB, 0x04, 0xCD, 0x04,
|
||||
0xCD, 0x04, 0xC0, 0x04, 0xD0, 0x04, 0xD0, 0x04, 0xD2, 0x04, 0xD2, 0x04,
|
||||
0xD4, 0x04, 0xD4, 0x04, 0xD6, 0x04, 0xD6, 0x04, 0xD8, 0x04, 0xD8, 0x04,
|
||||
0xDA, 0x04, 0xDA, 0x04, 0xDC, 0x04, 0xDC, 0x04, 0xDE, 0x04, 0xDE, 0x04,
|
||||
0xE0, 0x04, 0xE0, 0x04, 0xE2, 0x04, 0xE2, 0x04, 0xE4, 0x04, 0xE4, 0x04,
|
||||
0xE6, 0x04, 0xE6, 0x04, 0xE8, 0x04, 0xE8, 0x04, 0xEA, 0x04, 0xEA, 0x04,
|
||||
0xEC, 0x04, 0xEC, 0x04, 0xEE, 0x04, 0xEE, 0x04, 0xF0, 0x04, 0xF0, 0x04,
|
||||
0xF2, 0x04, 0xF2, 0x04, 0xF4, 0x04, 0xF4, 0x04, 0xF6, 0x04, 0xF6, 0x04,
|
||||
0xF8, 0x04, 0xF8, 0x04, 0xFA, 0x04, 0xFA, 0x04, 0xFC, 0x04, 0xFC, 0x04,
|
||||
0xFE, 0x04, 0xFE, 0x04, 0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05,
|
||||
0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05, 0x08, 0x05, 0x08, 0x05,
|
||||
0x0A, 0x05, 0x0A, 0x05, 0x0C, 0x05, 0x0C, 0x05, 0x0E, 0x05, 0x0E, 0x05,
|
||||
0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05, 0x14, 0x05, 0x15, 0x05,
|
||||
0x16, 0x05, 0x17, 0x05, 0x18, 0x05, 0x19, 0x05, 0x1A, 0x05, 0x1B, 0x05,
|
||||
0x1C, 0x05, 0x1D, 0x05, 0x1E, 0x05, 0x1F, 0x05, 0x20, 0x05, 0x21, 0x05,
|
||||
0x22, 0x05, 0x23, 0x05, 0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05,
|
||||
0x28, 0x05, 0x29, 0x05, 0x2A, 0x05, 0x2B, 0x05, 0x2C, 0x05, 0x2D, 0x05,
|
||||
0x2E, 0x05, 0x2F, 0x05, 0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05,
|
||||
0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, 0x38, 0x05, 0x39, 0x05,
|
||||
0x3A, 0x05, 0x3B, 0x05, 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05,
|
||||
0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, 0x44, 0x05, 0x45, 0x05,
|
||||
0x46, 0x05, 0x47, 0x05, 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05,
|
||||
0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, 0x50, 0x05, 0x51, 0x05,
|
||||
0x52, 0x05, 0x53, 0x05, 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05,
|
||||
0x58, 0x05, 0x59, 0x05, 0x5A, 0x05, 0x5B, 0x05, 0x5C, 0x05, 0x5D, 0x05,
|
||||
0x5E, 0x05, 0x5F, 0x05, 0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05,
|
||||
0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, 0x38, 0x05, 0x39, 0x05,
|
||||
0x3A, 0x05, 0x3B, 0x05, 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05,
|
||||
0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, 0x44, 0x05, 0x45, 0x05,
|
||||
0x46, 0x05, 0x47, 0x05, 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05,
|
||||
0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, 0x50, 0x05, 0x51, 0x05,
|
||||
0x52, 0x05, 0x53, 0x05, 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xFF, 0xFF,
|
||||
0xF6, 0x17, 0x63, 0x2C, 0x7E, 0x1D, 0x7F, 0x1D, 0x80, 0x1D, 0x81, 0x1D,
|
||||
0x82, 0x1D, 0x83, 0x1D, 0x84, 0x1D, 0x85, 0x1D, 0x86, 0x1D, 0x87, 0x1D,
|
||||
0x88, 0x1D, 0x89, 0x1D, 0x8A, 0x1D, 0x8B, 0x1D, 0x8C, 0x1D, 0x8D, 0x1D,
|
||||
0x8E, 0x1D, 0x8F, 0x1D, 0x90, 0x1D, 0x91, 0x1D, 0x92, 0x1D, 0x93, 0x1D,
|
||||
0x94, 0x1D, 0x95, 0x1D, 0x96, 0x1D, 0x97, 0x1D, 0x98, 0x1D, 0x99, 0x1D,
|
||||
0x9A, 0x1D, 0x9B, 0x1D, 0x9C, 0x1D, 0x9D, 0x1D, 0x9E, 0x1D, 0x9F, 0x1D,
|
||||
0xA0, 0x1D, 0xA1, 0x1D, 0xA2, 0x1D, 0xA3, 0x1D, 0xA4, 0x1D, 0xA5, 0x1D,
|
||||
0xA6, 0x1D, 0xA7, 0x1D, 0xA8, 0x1D, 0xA9, 0x1D, 0xAA, 0x1D, 0xAB, 0x1D,
|
||||
0xAC, 0x1D, 0xAD, 0x1D, 0xAE, 0x1D, 0xAF, 0x1D, 0xB0, 0x1D, 0xB1, 0x1D,
|
||||
0xB2, 0x1D, 0xB3, 0x1D, 0xB4, 0x1D, 0xB5, 0x1D, 0xB6, 0x1D, 0xB7, 0x1D,
|
||||
0xB8, 0x1D, 0xB9, 0x1D, 0xBA, 0x1D, 0xBB, 0x1D, 0xBC, 0x1D, 0xBD, 0x1D,
|
||||
0xBE, 0x1D, 0xBF, 0x1D, 0xC0, 0x1D, 0xC1, 0x1D, 0xC2, 0x1D, 0xC3, 0x1D,
|
||||
0xC4, 0x1D, 0xC5, 0x1D, 0xC6, 0x1D, 0xC7, 0x1D, 0xC8, 0x1D, 0xC9, 0x1D,
|
||||
0xCA, 0x1D, 0xCB, 0x1D, 0xCC, 0x1D, 0xCD, 0x1D, 0xCE, 0x1D, 0xCF, 0x1D,
|
||||
0xD0, 0x1D, 0xD1, 0x1D, 0xD2, 0x1D, 0xD3, 0x1D, 0xD4, 0x1D, 0xD5, 0x1D,
|
||||
0xD6, 0x1D, 0xD7, 0x1D, 0xD8, 0x1D, 0xD9, 0x1D, 0xDA, 0x1D, 0xDB, 0x1D,
|
||||
0xDC, 0x1D, 0xDD, 0x1D, 0xDE, 0x1D, 0xDF, 0x1D, 0xE0, 0x1D, 0xE1, 0x1D,
|
||||
0xE2, 0x1D, 0xE3, 0x1D, 0xE4, 0x1D, 0xE5, 0x1D, 0xE6, 0x1D, 0xE7, 0x1D,
|
||||
0xE8, 0x1D, 0xE9, 0x1D, 0xEA, 0x1D, 0xEB, 0x1D, 0xEC, 0x1D, 0xED, 0x1D,
|
||||
0xEE, 0x1D, 0xEF, 0x1D, 0xF0, 0x1D, 0xF1, 0x1D, 0xF2, 0x1D, 0xF3, 0x1D,
|
||||
0xF4, 0x1D, 0xF5, 0x1D, 0xF6, 0x1D, 0xF7, 0x1D, 0xF8, 0x1D, 0xF9, 0x1D,
|
||||
0xFA, 0x1D, 0xFB, 0x1D, 0xFC, 0x1D, 0xFD, 0x1D, 0xFE, 0x1D, 0xFF, 0x1D,
|
||||
0x00, 0x1E, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E, 0x04, 0x1E, 0x04, 0x1E,
|
||||
0x06, 0x1E, 0x06, 0x1E, 0x08, 0x1E, 0x08, 0x1E, 0x0A, 0x1E, 0x0A, 0x1E,
|
||||
0x0C, 0x1E, 0x0C, 0x1E, 0x0E, 0x1E, 0x0E, 0x1E, 0x10, 0x1E, 0x10, 0x1E,
|
||||
0x12, 0x1E, 0x12, 0x1E, 0x14, 0x1E, 0x14, 0x1E, 0x16, 0x1E, 0x16, 0x1E,
|
||||
0x18, 0x1E, 0x18, 0x1E, 0x1A, 0x1E, 0x1A, 0x1E, 0x1C, 0x1E, 0x1C, 0x1E,
|
||||
0x1E, 0x1E, 0x1E, 0x1E, 0x20, 0x1E, 0x20, 0x1E, 0x22, 0x1E, 0x22, 0x1E,
|
||||
0x24, 0x1E, 0x24, 0x1E, 0x26, 0x1E, 0x26, 0x1E, 0x28, 0x1E, 0x28, 0x1E,
|
||||
0x2A, 0x1E, 0x2A, 0x1E, 0x2C, 0x1E, 0x2C, 0x1E, 0x2E, 0x1E, 0x2E, 0x1E,
|
||||
0x30, 0x1E, 0x30, 0x1E, 0x32, 0x1E, 0x32, 0x1E, 0x34, 0x1E, 0x34, 0x1E,
|
||||
0x36, 0x1E, 0x36, 0x1E, 0x38, 0x1E, 0x38, 0x1E, 0x3A, 0x1E, 0x3A, 0x1E,
|
||||
0x3C, 0x1E, 0x3C, 0x1E, 0x3E, 0x1E, 0x3E, 0x1E, 0x40, 0x1E, 0x40, 0x1E,
|
||||
0x42, 0x1E, 0x42, 0x1E, 0x44, 0x1E, 0x44, 0x1E, 0x46, 0x1E, 0x46, 0x1E,
|
||||
0x48, 0x1E, 0x48, 0x1E, 0x4A, 0x1E, 0x4A, 0x1E, 0x4C, 0x1E, 0x4C, 0x1E,
|
||||
0x4E, 0x1E, 0x4E, 0x1E, 0x50, 0x1E, 0x50, 0x1E, 0x52, 0x1E, 0x52, 0x1E,
|
||||
0x54, 0x1E, 0x54, 0x1E, 0x56, 0x1E, 0x56, 0x1E, 0x58, 0x1E, 0x58, 0x1E,
|
||||
0x5A, 0x1E, 0x5A, 0x1E, 0x5C, 0x1E, 0x5C, 0x1E, 0x5E, 0x1E, 0x5E, 0x1E,
|
||||
0x60, 0x1E, 0x60, 0x1E, 0x62, 0x1E, 0x62, 0x1E, 0x64, 0x1E, 0x64, 0x1E,
|
||||
0x66, 0x1E, 0x66, 0x1E, 0x68, 0x1E, 0x68, 0x1E, 0x6A, 0x1E, 0x6A, 0x1E,
|
||||
0x6C, 0x1E, 0x6C, 0x1E, 0x6E, 0x1E, 0x6E, 0x1E, 0x70, 0x1E, 0x70, 0x1E,
|
||||
0x72, 0x1E, 0x72, 0x1E, 0x74, 0x1E, 0x74, 0x1E, 0x76, 0x1E, 0x76, 0x1E,
|
||||
0x78, 0x1E, 0x78, 0x1E, 0x7A, 0x1E, 0x7A, 0x1E, 0x7C, 0x1E, 0x7C, 0x1E,
|
||||
0x7E, 0x1E, 0x7E, 0x1E, 0x80, 0x1E, 0x80, 0x1E, 0x82, 0x1E, 0x82, 0x1E,
|
||||
0x84, 0x1E, 0x84, 0x1E, 0x86, 0x1E, 0x86, 0x1E, 0x88, 0x1E, 0x88, 0x1E,
|
||||
0x8A, 0x1E, 0x8A, 0x1E, 0x8C, 0x1E, 0x8C, 0x1E, 0x8E, 0x1E, 0x8E, 0x1E,
|
||||
0x90, 0x1E, 0x90, 0x1E, 0x92, 0x1E, 0x92, 0x1E, 0x94, 0x1E, 0x94, 0x1E,
|
||||
0x96, 0x1E, 0x97, 0x1E, 0x98, 0x1E, 0x99, 0x1E, 0x9A, 0x1E, 0x9B, 0x1E,
|
||||
0x9C, 0x1E, 0x9D, 0x1E, 0x9E, 0x1E, 0x9F, 0x1E, 0xA0, 0x1E, 0xA0, 0x1E,
|
||||
0xA2, 0x1E, 0xA2, 0x1E, 0xA4, 0x1E, 0xA4, 0x1E, 0xA6, 0x1E, 0xA6, 0x1E,
|
||||
0xA8, 0x1E, 0xA8, 0x1E, 0xAA, 0x1E, 0xAA, 0x1E, 0xAC, 0x1E, 0xAC, 0x1E,
|
||||
0xAE, 0x1E, 0xAE, 0x1E, 0xB0, 0x1E, 0xB0, 0x1E, 0xB2, 0x1E, 0xB2, 0x1E,
|
||||
0xB4, 0x1E, 0xB4, 0x1E, 0xB6, 0x1E, 0xB6, 0x1E, 0xB8, 0x1E, 0xB8, 0x1E,
|
||||
0xBA, 0x1E, 0xBA, 0x1E, 0xBC, 0x1E, 0xBC, 0x1E, 0xBE, 0x1E, 0xBE, 0x1E,
|
||||
0xC0, 0x1E, 0xC0, 0x1E, 0xC2, 0x1E, 0xC2, 0x1E, 0xC4, 0x1E, 0xC4, 0x1E,
|
||||
0xC6, 0x1E, 0xC6, 0x1E, 0xC8, 0x1E, 0xC8, 0x1E, 0xCA, 0x1E, 0xCA, 0x1E,
|
||||
0xCC, 0x1E, 0xCC, 0x1E, 0xCE, 0x1E, 0xCE, 0x1E, 0xD0, 0x1E, 0xD0, 0x1E,
|
||||
0xD2, 0x1E, 0xD2, 0x1E, 0xD4, 0x1E, 0xD4, 0x1E, 0xD6, 0x1E, 0xD6, 0x1E,
|
||||
0xD8, 0x1E, 0xD8, 0x1E, 0xDA, 0x1E, 0xDA, 0x1E, 0xDC, 0x1E, 0xDC, 0x1E,
|
||||
0xDE, 0x1E, 0xDE, 0x1E, 0xE0, 0x1E, 0xE0, 0x1E, 0xE2, 0x1E, 0xE2, 0x1E,
|
||||
0xE4, 0x1E, 0xE4, 0x1E, 0xE6, 0x1E, 0xE6, 0x1E, 0xE8, 0x1E, 0xE8, 0x1E,
|
||||
0xEA, 0x1E, 0xEA, 0x1E, 0xEC, 0x1E, 0xEC, 0x1E, 0xEE, 0x1E, 0xEE, 0x1E,
|
||||
0xF0, 0x1E, 0xF0, 0x1E, 0xF2, 0x1E, 0xF2, 0x1E, 0xF4, 0x1E, 0xF4, 0x1E,
|
||||
0xF6, 0x1E, 0xF6, 0x1E, 0xF8, 0x1E, 0xF8, 0x1E, 0xFA, 0x1E, 0xFB, 0x1E,
|
||||
0xFC, 0x1E, 0xFD, 0x1E, 0xFE, 0x1E, 0xFF, 0x1E, 0x08, 0x1F, 0x09, 0x1F,
|
||||
0x0A, 0x1F, 0x0B, 0x1F, 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F,
|
||||
0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, 0x0C, 0x1F, 0x0D, 0x1F,
|
||||
0x0E, 0x1F, 0x0F, 0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F,
|
||||
0x1C, 0x1F, 0x1D, 0x1F, 0x16, 0x1F, 0x17, 0x1F, 0x18, 0x1F, 0x19, 0x1F,
|
||||
0x1A, 0x1F, 0x1B, 0x1F, 0x1C, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F,
|
||||
0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, 0x2C, 0x1F, 0x2D, 0x1F,
|
||||
0x2E, 0x1F, 0x2F, 0x1F, 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F,
|
||||
0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x38, 0x1F, 0x39, 0x1F,
|
||||
0x3A, 0x1F, 0x3B, 0x1F, 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F,
|
||||
0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, 0x3C, 0x1F, 0x3D, 0x1F,
|
||||
0x3E, 0x1F, 0x3F, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F,
|
||||
0x4C, 0x1F, 0x4D, 0x1F, 0x46, 0x1F, 0x47, 0x1F, 0x48, 0x1F, 0x49, 0x1F,
|
||||
0x4A, 0x1F, 0x4B, 0x1F, 0x4C, 0x1F, 0x4D, 0x1F, 0x4E, 0x1F, 0x4F, 0x1F,
|
||||
0x50, 0x1F, 0x59, 0x1F, 0x52, 0x1F, 0x5B, 0x1F, 0x54, 0x1F, 0x5D, 0x1F,
|
||||
0x56, 0x1F, 0x5F, 0x1F, 0x58, 0x1F, 0x59, 0x1F, 0x5A, 0x1F, 0x5B, 0x1F,
|
||||
0x5C, 0x1F, 0x5D, 0x1F, 0x5E, 0x1F, 0x5F, 0x1F, 0x68, 0x1F, 0x69, 0x1F,
|
||||
0x6A, 0x1F, 0x6B, 0x1F, 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F,
|
||||
0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, 0x6C, 0x1F, 0x6D, 0x1F,
|
||||
0x6E, 0x1F, 0x6F, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F,
|
||||
0xCA, 0x1F, 0xCB, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, 0xF8, 0x1F, 0xF9, 0x1F,
|
||||
0xEA, 0x1F, 0xEB, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F, 0x7E, 0x1F, 0x7F, 0x1F,
|
||||
0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 0x1F,
|
||||
0x8E, 0x1F, 0x8F, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F,
|
||||
0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x98, 0x1F, 0x99, 0x1F,
|
||||
0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F,
|
||||
0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F,
|
||||
0x9E, 0x1F, 0x9F, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F,
|
||||
0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F,
|
||||
0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F,
|
||||
0xB8, 0x1F, 0xB9, 0x1F, 0xB2, 0x1F, 0xBC, 0x1F, 0xB4, 0x1F, 0xB5, 0x1F,
|
||||
0xB6, 0x1F, 0xB7, 0x1F, 0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F,
|
||||
0xBC, 0x1F, 0xBD, 0x1F, 0xBE, 0x1F, 0xBF, 0x1F, 0xC0, 0x1F, 0xC1, 0x1F,
|
||||
0xC2, 0x1F, 0xC3, 0x1F, 0xC4, 0x1F, 0xC5, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F,
|
||||
0xC8, 0x1F, 0xC9, 0x1F, 0xCA, 0x1F, 0xCB, 0x1F, 0xC3, 0x1F, 0xCD, 0x1F,
|
||||
0xCE, 0x1F, 0xCF, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F, 0xD2, 0x1F, 0xD3, 0x1F,
|
||||
0xD4, 0x1F, 0xD5, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F,
|
||||
0xDA, 0x1F, 0xDB, 0x1F, 0xDC, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F,
|
||||
0xE8, 0x1F, 0xE9, 0x1F, 0xE2, 0x1F, 0xE3, 0x1F, 0xE4, 0x1F, 0xEC, 0x1F,
|
||||
0xE6, 0x1F, 0xE7, 0x1F, 0xE8, 0x1F, 0xE9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F,
|
||||
0xEC, 0x1F, 0xED, 0x1F, 0xEE, 0x1F, 0xEF, 0x1F, 0xF0, 0x1F, 0xF1, 0x1F,
|
||||
0xF2, 0x1F, 0xF3, 0x1F, 0xF4, 0x1F, 0xF5, 0x1F, 0xF6, 0x1F, 0xF7, 0x1F,
|
||||
0xF8, 0x1F, 0xF9, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F, 0xF3, 0x1F, 0xFD, 0x1F,
|
||||
0xFE, 0x1F, 0xFF, 0x1F, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20,
|
||||
0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x09, 0x20,
|
||||
0x0A, 0x20, 0x0B, 0x20, 0x0C, 0x20, 0x0D, 0x20, 0x0E, 0x20, 0x0F, 0x20,
|
||||
0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20, 0x14, 0x20, 0x15, 0x20,
|
||||
0x16, 0x20, 0x17, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1A, 0x20, 0x1B, 0x20,
|
||||
0x1C, 0x20, 0x1D, 0x20, 0x1E, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20,
|
||||
0x22, 0x20, 0x23, 0x20, 0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20,
|
||||
0x28, 0x20, 0x29, 0x20, 0x2A, 0x20, 0x2B, 0x20, 0x2C, 0x20, 0x2D, 0x20,
|
||||
0x2E, 0x20, 0x2F, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20,
|
||||
0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20, 0x38, 0x20, 0x39, 0x20,
|
||||
0x3A, 0x20, 0x3B, 0x20, 0x3C, 0x20, 0x3D, 0x20, 0x3E, 0x20, 0x3F, 0x20,
|
||||
0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20, 0x44, 0x20, 0x45, 0x20,
|
||||
0x46, 0x20, 0x47, 0x20, 0x48, 0x20, 0x49, 0x20, 0x4A, 0x20, 0x4B, 0x20,
|
||||
0x4C, 0x20, 0x4D, 0x20, 0x4E, 0x20, 0x4F, 0x20, 0x50, 0x20, 0x51, 0x20,
|
||||
0x52, 0x20, 0x53, 0x20, 0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20,
|
||||
0x58, 0x20, 0x59, 0x20, 0x5A, 0x20, 0x5B, 0x20, 0x5C, 0x20, 0x5D, 0x20,
|
||||
0x5E, 0x20, 0x5F, 0x20, 0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20,
|
||||
0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20, 0x68, 0x20, 0x69, 0x20,
|
||||
0x6A, 0x20, 0x6B, 0x20, 0x6C, 0x20, 0x6D, 0x20, 0x6E, 0x20, 0x6F, 0x20,
|
||||
0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20, 0x74, 0x20, 0x75, 0x20,
|
||||
0x76, 0x20, 0x77, 0x20, 0x78, 0x20, 0x79, 0x20, 0x7A, 0x20, 0x7B, 0x20,
|
||||
0x7C, 0x20, 0x7D, 0x20, 0x7E, 0x20, 0x7F, 0x20, 0x80, 0x20, 0x81, 0x20,
|
||||
0x82, 0x20, 0x83, 0x20, 0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20,
|
||||
0x88, 0x20, 0x89, 0x20, 0x8A, 0x20, 0x8B, 0x20, 0x8C, 0x20, 0x8D, 0x20,
|
||||
0x8E, 0x20, 0x8F, 0x20, 0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20,
|
||||
0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20, 0x98, 0x20, 0x99, 0x20,
|
||||
0x9A, 0x20, 0x9B, 0x20, 0x9C, 0x20, 0x9D, 0x20, 0x9E, 0x20, 0x9F, 0x20,
|
||||
0xA0, 0x20, 0xA1, 0x20, 0xA2, 0x20, 0xA3, 0x20, 0xA4, 0x20, 0xA5, 0x20,
|
||||
0xA6, 0x20, 0xA7, 0x20, 0xA8, 0x20, 0xA9, 0x20, 0xAA, 0x20, 0xAB, 0x20,
|
||||
0xAC, 0x20, 0xAD, 0x20, 0xAE, 0x20, 0xAF, 0x20, 0xB0, 0x20, 0xB1, 0x20,
|
||||
0xB2, 0x20, 0xB3, 0x20, 0xB4, 0x20, 0xB5, 0x20, 0xB6, 0x20, 0xB7, 0x20,
|
||||
0xB8, 0x20, 0xB9, 0x20, 0xBA, 0x20, 0xBB, 0x20, 0xBC, 0x20, 0xBD, 0x20,
|
||||
0xBE, 0x20, 0xBF, 0x20, 0xC0, 0x20, 0xC1, 0x20, 0xC2, 0x20, 0xC3, 0x20,
|
||||
0xC4, 0x20, 0xC5, 0x20, 0xC6, 0x20, 0xC7, 0x20, 0xC8, 0x20, 0xC9, 0x20,
|
||||
0xCA, 0x20, 0xCB, 0x20, 0xCC, 0x20, 0xCD, 0x20, 0xCE, 0x20, 0xCF, 0x20,
|
||||
0xD0, 0x20, 0xD1, 0x20, 0xD2, 0x20, 0xD3, 0x20, 0xD4, 0x20, 0xD5, 0x20,
|
||||
0xD6, 0x20, 0xD7, 0x20, 0xD8, 0x20, 0xD9, 0x20, 0xDA, 0x20, 0xDB, 0x20,
|
||||
0xDC, 0x20, 0xDD, 0x20, 0xDE, 0x20, 0xDF, 0x20, 0xE0, 0x20, 0xE1, 0x20,
|
||||
0xE2, 0x20, 0xE3, 0x20, 0xE4, 0x20, 0xE5, 0x20, 0xE6, 0x20, 0xE7, 0x20,
|
||||
0xE8, 0x20, 0xE9, 0x20, 0xEA, 0x20, 0xEB, 0x20, 0xEC, 0x20, 0xED, 0x20,
|
||||
0xEE, 0x20, 0xEF, 0x20, 0xF0, 0x20, 0xF1, 0x20, 0xF2, 0x20, 0xF3, 0x20,
|
||||
0xF4, 0x20, 0xF5, 0x20, 0xF6, 0x20, 0xF7, 0x20, 0xF8, 0x20, 0xF9, 0x20,
|
||||
0xFA, 0x20, 0xFB, 0x20, 0xFC, 0x20, 0xFD, 0x20, 0xFE, 0x20, 0xFF, 0x20,
|
||||
0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21, 0x04, 0x21, 0x05, 0x21,
|
||||
0x06, 0x21, 0x07, 0x21, 0x08, 0x21, 0x09, 0x21, 0x0A, 0x21, 0x0B, 0x21,
|
||||
0x0C, 0x21, 0x0D, 0x21, 0x0E, 0x21, 0x0F, 0x21, 0x10, 0x21, 0x11, 0x21,
|
||||
0x12, 0x21, 0x13, 0x21, 0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21,
|
||||
0x18, 0x21, 0x19, 0x21, 0x1A, 0x21, 0x1B, 0x21, 0x1C, 0x21, 0x1D, 0x21,
|
||||
0x1E, 0x21, 0x1F, 0x21, 0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21,
|
||||
0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21, 0x28, 0x21, 0x29, 0x21,
|
||||
0x2A, 0x21, 0x2B, 0x21, 0x2C, 0x21, 0x2D, 0x21, 0x2E, 0x21, 0x2F, 0x21,
|
||||
0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21, 0x34, 0x21, 0x35, 0x21,
|
||||
0x36, 0x21, 0x37, 0x21, 0x38, 0x21, 0x39, 0x21, 0x3A, 0x21, 0x3B, 0x21,
|
||||
0x3C, 0x21, 0x3D, 0x21, 0x3E, 0x21, 0x3F, 0x21, 0x40, 0x21, 0x41, 0x21,
|
||||
0x42, 0x21, 0x43, 0x21, 0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21,
|
||||
0x48, 0x21, 0x49, 0x21, 0x4A, 0x21, 0x4B, 0x21, 0x4C, 0x21, 0x4D, 0x21,
|
||||
0x32, 0x21, 0x4F, 0x21, 0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21,
|
||||
0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21, 0x58, 0x21, 0x59, 0x21,
|
||||
0x5A, 0x21, 0x5B, 0x21, 0x5C, 0x21, 0x5D, 0x21, 0x5E, 0x21, 0x5F, 0x21,
|
||||
0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, 0x64, 0x21, 0x65, 0x21,
|
||||
0x66, 0x21, 0x67, 0x21, 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21,
|
||||
0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, 0x60, 0x21, 0x61, 0x21,
|
||||
0x62, 0x21, 0x63, 0x21, 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21,
|
||||
0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, 0x6C, 0x21, 0x6D, 0x21,
|
||||
0x6E, 0x21, 0x6F, 0x21, 0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21,
|
||||
0x83, 0x21, 0xFF, 0xFF, 0x4B, 0x03, 0xB6, 0x24, 0xB7, 0x24, 0xB8, 0x24,
|
||||
0xB9, 0x24, 0xBA, 0x24, 0xBB, 0x24, 0xBC, 0x24, 0xBD, 0x24, 0xBE, 0x24,
|
||||
0xBF, 0x24, 0xC0, 0x24, 0xC1, 0x24, 0xC2, 0x24, 0xC3, 0x24, 0xC4, 0x24,
|
||||
0xC5, 0x24, 0xC6, 0x24, 0xC7, 0x24, 0xC8, 0x24, 0xC9, 0x24, 0xCA, 0x24,
|
||||
0xCB, 0x24, 0xCC, 0x24, 0xCD, 0x24, 0xCE, 0x24, 0xCF, 0x24, 0xFF, 0xFF,
|
||||
0x46, 0x07, 0x00, 0x2C, 0x01, 0x2C, 0x02, 0x2C, 0x03, 0x2C, 0x04, 0x2C,
|
||||
0x05, 0x2C, 0x06, 0x2C, 0x07, 0x2C, 0x08, 0x2C, 0x09, 0x2C, 0x0A, 0x2C,
|
||||
0x0B, 0x2C, 0x0C, 0x2C, 0x0D, 0x2C, 0x0E, 0x2C, 0x0F, 0x2C, 0x10, 0x2C,
|
||||
0x11, 0x2C, 0x12, 0x2C, 0x13, 0x2C, 0x14, 0x2C, 0x15, 0x2C, 0x16, 0x2C,
|
||||
0x17, 0x2C, 0x18, 0x2C, 0x19, 0x2C, 0x1A, 0x2C, 0x1B, 0x2C, 0x1C, 0x2C,
|
||||
0x1D, 0x2C, 0x1E, 0x2C, 0x1F, 0x2C, 0x20, 0x2C, 0x21, 0x2C, 0x22, 0x2C,
|
||||
0x23, 0x2C, 0x24, 0x2C, 0x25, 0x2C, 0x26, 0x2C, 0x27, 0x2C, 0x28, 0x2C,
|
||||
0x29, 0x2C, 0x2A, 0x2C, 0x2B, 0x2C, 0x2C, 0x2C, 0x2D, 0x2C, 0x2E, 0x2C,
|
||||
0x5F, 0x2C, 0x60, 0x2C, 0x60, 0x2C, 0x62, 0x2C, 0x63, 0x2C, 0x64, 0x2C,
|
||||
0x65, 0x2C, 0x66, 0x2C, 0x67, 0x2C, 0x67, 0x2C, 0x69, 0x2C, 0x69, 0x2C,
|
||||
0x6B, 0x2C, 0x6B, 0x2C, 0x6D, 0x2C, 0x6E, 0x2C, 0x6F, 0x2C, 0x70, 0x2C,
|
||||
0x71, 0x2C, 0x72, 0x2C, 0x73, 0x2C, 0x74, 0x2C, 0x75, 0x2C, 0x75, 0x2C,
|
||||
0x77, 0x2C, 0x78, 0x2C, 0x79, 0x2C, 0x7A, 0x2C, 0x7B, 0x2C, 0x7C, 0x2C,
|
||||
0x7D, 0x2C, 0x7E, 0x2C, 0x7F, 0x2C, 0x80, 0x2C, 0x80, 0x2C, 0x82, 0x2C,
|
||||
0x82, 0x2C, 0x84, 0x2C, 0x84, 0x2C, 0x86, 0x2C, 0x86, 0x2C, 0x88, 0x2C,
|
||||
0x88, 0x2C, 0x8A, 0x2C, 0x8A, 0x2C, 0x8C, 0x2C, 0x8C, 0x2C, 0x8E, 0x2C,
|
||||
0x8E, 0x2C, 0x90, 0x2C, 0x90, 0x2C, 0x92, 0x2C, 0x92, 0x2C, 0x94, 0x2C,
|
||||
0x94, 0x2C, 0x96, 0x2C, 0x96, 0x2C, 0x98, 0x2C, 0x98, 0x2C, 0x9A, 0x2C,
|
||||
0x9A, 0x2C, 0x9C, 0x2C, 0x9C, 0x2C, 0x9E, 0x2C, 0x9E, 0x2C, 0xA0, 0x2C,
|
||||
0xA0, 0x2C, 0xA2, 0x2C, 0xA2, 0x2C, 0xA4, 0x2C, 0xA4, 0x2C, 0xA6, 0x2C,
|
||||
0xA6, 0x2C, 0xA8, 0x2C, 0xA8, 0x2C, 0xAA, 0x2C, 0xAA, 0x2C, 0xAC, 0x2C,
|
||||
0xAC, 0x2C, 0xAE, 0x2C, 0xAE, 0x2C, 0xB0, 0x2C, 0xB0, 0x2C, 0xB2, 0x2C,
|
||||
0xB2, 0x2C, 0xB4, 0x2C, 0xB4, 0x2C, 0xB6, 0x2C, 0xB6, 0x2C, 0xB8, 0x2C,
|
||||
0xB8, 0x2C, 0xBA, 0x2C, 0xBA, 0x2C, 0xBC, 0x2C, 0xBC, 0x2C, 0xBE, 0x2C,
|
||||
0xBE, 0x2C, 0xC0, 0x2C, 0xC0, 0x2C, 0xC2, 0x2C, 0xC2, 0x2C, 0xC4, 0x2C,
|
||||
0xC4, 0x2C, 0xC6, 0x2C, 0xC6, 0x2C, 0xC8, 0x2C, 0xC8, 0x2C, 0xCA, 0x2C,
|
||||
0xCA, 0x2C, 0xCC, 0x2C, 0xCC, 0x2C, 0xCE, 0x2C, 0xCE, 0x2C, 0xD0, 0x2C,
|
||||
0xD0, 0x2C, 0xD2, 0x2C, 0xD2, 0x2C, 0xD4, 0x2C, 0xD4, 0x2C, 0xD6, 0x2C,
|
||||
0xD6, 0x2C, 0xD8, 0x2C, 0xD8, 0x2C, 0xDA, 0x2C, 0xDA, 0x2C, 0xDC, 0x2C,
|
||||
0xDC, 0x2C, 0xDE, 0x2C, 0xDE, 0x2C, 0xE0, 0x2C, 0xE0, 0x2C, 0xE2, 0x2C,
|
||||
0xE2, 0x2C, 0xE4, 0x2C, 0xE5, 0x2C, 0xE6, 0x2C, 0xE7, 0x2C, 0xE8, 0x2C,
|
||||
0xE9, 0x2C, 0xEA, 0x2C, 0xEB, 0x2C, 0xEC, 0x2C, 0xED, 0x2C, 0xEE, 0x2C,
|
||||
0xEF, 0x2C, 0xF0, 0x2C, 0xF1, 0x2C, 0xF2, 0x2C, 0xF3, 0x2C, 0xF4, 0x2C,
|
||||
0xF5, 0x2C, 0xF6, 0x2C, 0xF7, 0x2C, 0xF8, 0x2C, 0xF9, 0x2C, 0xFA, 0x2C,
|
||||
0xFB, 0x2C, 0xFC, 0x2C, 0xFD, 0x2C, 0xFE, 0x2C, 0xFF, 0x2C, 0xA0, 0x10,
|
||||
0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, 0xA5, 0x10, 0xA6, 0x10,
|
||||
0xA7, 0x10, 0xA8, 0x10, 0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10,
|
||||
0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10, 0xB1, 0x10, 0xB2, 0x10,
|
||||
0xB3, 0x10, 0xB4, 0x10, 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10,
|
||||
0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10, 0xBD, 0x10, 0xBE, 0x10,
|
||||
0xBF, 0x10, 0xC0, 0x10, 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10,
|
||||
0xC5, 0x10, 0xFF, 0xFF, 0x1B, 0xD2, 0x21, 0xFF, 0x22, 0xFF, 0x23, 0xFF,
|
||||
0x24, 0xFF, 0x25, 0xFF, 0x26, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x29, 0xFF,
|
||||
0x2A, 0xFF, 0x2B, 0xFF, 0x2C, 0xFF, 0x2D, 0xFF, 0x2E, 0xFF, 0x2F, 0xFF,
|
||||
0x30, 0xFF, 0x31, 0xFF, 0x32, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x35, 0xFF,
|
||||
0x36, 0xFF, 0x37, 0xFF, 0x38, 0xFF, 0x39, 0xFF, 0x3A, 0xFF, 0x5B, 0xFF,
|
||||
0x5C, 0xFF, 0x5D, 0xFF, 0x5E, 0xFF, 0x5F, 0xFF, 0x60, 0xFF, 0x61, 0xFF,
|
||||
0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x65, 0xFF, 0x66, 0xFF, 0x67, 0xFF,
|
||||
0x68, 0xFF, 0x69, 0xFF, 0x6A, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0x6D, 0xFF,
|
||||
0x6E, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x71, 0xFF, 0x72, 0xFF, 0x73, 0xFF,
|
||||
0x74, 0xFF, 0x75, 0xFF, 0x76, 0xFF, 0x77, 0xFF, 0x78, 0xFF, 0x79, 0xFF,
|
||||
0x7A, 0xFF, 0x7B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF, 0x7E, 0xFF, 0x7F, 0xFF,
|
||||
0x80, 0xFF, 0x81, 0xFF, 0x82, 0xFF, 0x83, 0xFF, 0x84, 0xFF, 0x85, 0xFF,
|
||||
0x86, 0xFF, 0x87, 0xFF, 0x88, 0xFF, 0x89, 0xFF, 0x8A, 0xFF, 0x8B, 0xFF,
|
||||
0x8C, 0xFF, 0x8D, 0xFF, 0x8E, 0xFF, 0x8F, 0xFF, 0x90, 0xFF, 0x91, 0xFF,
|
||||
0x92, 0xFF, 0x93, 0xFF, 0x94, 0xFF, 0x95, 0xFF, 0x96, 0xFF, 0x97, 0xFF,
|
||||
0x98, 0xFF, 0x99, 0xFF, 0x9A, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF,
|
||||
0x9E, 0xFF, 0x9F, 0xFF, 0xA0, 0xFF, 0xA1, 0xFF, 0xA2, 0xFF, 0xA3, 0xFF,
|
||||
0xA4, 0xFF, 0xA5, 0xFF, 0xA6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF,
|
||||
0xAA, 0xFF, 0xAB, 0xFF, 0xAC, 0xFF, 0xAD, 0xFF, 0xAE, 0xFF, 0xAF, 0xFF,
|
||||
0xB0, 0xFF, 0xB1, 0xFF, 0xB2, 0xFF, 0xB3, 0xFF, 0xB4, 0xFF, 0xB5, 0xFF,
|
||||
0xB6, 0xFF, 0xB7, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF, 0xBA, 0xFF, 0xBB, 0xFF,
|
||||
0xBC, 0xFF, 0xBD, 0xFF, 0xBE, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF,
|
||||
0xC2, 0xFF, 0xC3, 0xFF, 0xC4, 0xFF, 0xC5, 0xFF, 0xC6, 0xFF, 0xC7, 0xFF,
|
||||
0xC8, 0xFF, 0xC9, 0xFF, 0xCA, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF,
|
||||
0xCE, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xD1, 0xFF, 0xD2, 0xFF, 0xD3, 0xFF,
|
||||
0xD4, 0xFF, 0xD5, 0xFF, 0xD6, 0xFF, 0xD7, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF,
|
||||
0xDA, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF, 0xDE, 0xFF, 0xDF, 0xFF,
|
||||
0xE0, 0xFF, 0xE1, 0xFF, 0xE2, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF,
|
||||
0xE6, 0xFF, 0xE7, 0xFF, 0xE8, 0xFF, 0xE9, 0xFF, 0xEA, 0xFF, 0xEB, 0xFF,
|
||||
0xEC, 0xFF, 0xED, 0xFF, 0xEE, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF,
|
||||
0xF2, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF,
|
||||
0xF8, 0xFF, 0xF9, 0xFF, 0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF,
|
||||
0xFE, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
int exfat_create_upcase_table(struct exfat_blk_dev *bd)
|
||||
{
|
||||
int nbytes;
|
||||
|
||||
nbytes = pwrite(bd->dev_fd, upcase_table, EXFAT_UPCASE_TABLE_SIZE, finfo.ut_byte_off);
|
||||
if (nbytes != EXFAT_UPCASE_TABLE_SIZE)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
vbr.c (09.11.10)
|
||||
Volume Boot Record creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "vbr.h"
|
||||
#include "fat.h"
|
||||
#include "cbm.h"
|
||||
#include "uct.h"
|
||||
#include "rootdir.h"
|
||||
#include <string.h>
|
||||
|
||||
static off_t vbr_alignment(void)
|
||||
{
|
||||
return get_sector_size();
|
||||
}
|
||||
|
||||
static off_t vbr_size(void)
|
||||
{
|
||||
return 12 * get_sector_size();
|
||||
}
|
||||
|
||||
static void init_sb(struct exfat_super_block* sb)
|
||||
{
|
||||
uint32_t clusters_max;
|
||||
uint32_t fat_sectors;
|
||||
|
||||
clusters_max = get_volume_size() / get_cluster_size();
|
||||
fat_sectors = DIV_ROUND_UP((off_t) clusters_max * sizeof(cluster_t),
|
||||
get_sector_size());
|
||||
|
||||
memset(sb, 0, sizeof(struct exfat_super_block));
|
||||
sb->jump[0] = 0xeb;
|
||||
sb->jump[1] = 0x76;
|
||||
sb->jump[2] = 0x90;
|
||||
memcpy(sb->oem_name, "EXFAT ", sizeof(sb->oem_name));
|
||||
sb->sector_start = cpu_to_le64(get_first_sector());
|
||||
sb->sector_count = cpu_to_le64(get_volume_size() / get_sector_size());
|
||||
sb->fat_sector_start = cpu_to_le32(
|
||||
fat.get_alignment() / get_sector_size());
|
||||
sb->fat_sector_count = cpu_to_le32(ROUND_UP(
|
||||
le32_to_cpu(sb->fat_sector_start) + fat_sectors,
|
||||
1 << get_spc_bits()) -
|
||||
le32_to_cpu(sb->fat_sector_start));
|
||||
sb->cluster_sector_start = cpu_to_le32(
|
||||
get_position(&cbm) / get_sector_size());
|
||||
sb->cluster_count = cpu_to_le32(clusters_max -
|
||||
((le32_to_cpu(sb->fat_sector_start) +
|
||||
le32_to_cpu(sb->fat_sector_count)) >> get_spc_bits()));
|
||||
sb->rootdir_cluster = cpu_to_le32(
|
||||
(get_position(&rootdir) - get_position(&cbm)) / get_cluster_size()
|
||||
+ EXFAT_FIRST_DATA_CLUSTER);
|
||||
sb->volume_serial = cpu_to_le32(get_volume_serial());
|
||||
sb->version.major = 1;
|
||||
sb->version.minor = 0;
|
||||
sb->volume_state = cpu_to_le16(0);
|
||||
sb->sector_bits = get_sector_bits();
|
||||
sb->spc_bits = get_spc_bits();
|
||||
sb->fat_count = 1;
|
||||
sb->drive_no = 0x80;
|
||||
sb->allocated_percent = 0;
|
||||
sb->boot_signature = cpu_to_le16(0xaa55);
|
||||
}
|
||||
|
||||
static int vbr_write(struct exfat_dev* dev)
|
||||
{
|
||||
struct exfat_super_block sb;
|
||||
uint32_t checksum;
|
||||
le32_t* sector = malloc(get_sector_size());
|
||||
size_t i;
|
||||
|
||||
if (sector == NULL)
|
||||
{
|
||||
exfat_error("failed to allocate sector-sized block of memory");
|
||||
return 1;
|
||||
}
|
||||
|
||||
init_sb(&sb);
|
||||
if (exfat_write(dev, &sb, sizeof(struct exfat_super_block)) < 0)
|
||||
{
|
||||
free(sector);
|
||||
exfat_error("failed to write super block sector");
|
||||
return 1;
|
||||
}
|
||||
checksum = exfat_vbr_start_checksum(&sb, sizeof(struct exfat_super_block));
|
||||
|
||||
memset(sector, 0, get_sector_size());
|
||||
sector[get_sector_size() / sizeof(sector[0]) - 1] =
|
||||
cpu_to_le32(0xaa550000);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (exfat_write(dev, sector, get_sector_size()) < 0)
|
||||
{
|
||||
free(sector);
|
||||
exfat_error("failed to write a sector with boot signature");
|
||||
return 1;
|
||||
}
|
||||
checksum = exfat_vbr_add_checksum(sector, get_sector_size(), checksum);
|
||||
}
|
||||
|
||||
memset(sector, 0, get_sector_size());
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if (exfat_write(dev, sector, get_sector_size()) < 0)
|
||||
{
|
||||
free(sector);
|
||||
exfat_error("failed to write an empty sector");
|
||||
return 1;
|
||||
}
|
||||
checksum = exfat_vbr_add_checksum(sector, get_sector_size(), checksum);
|
||||
}
|
||||
|
||||
for (i = 0; i < get_sector_size() / sizeof(sector[0]); i++)
|
||||
sector[i] = cpu_to_le32(checksum);
|
||||
if (exfat_write(dev, sector, get_sector_size()) < 0)
|
||||
{
|
||||
free(sector);
|
||||
exfat_error("failed to write checksum sector");
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(sector);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct fs_object vbr =
|
||||
{
|
||||
.get_alignment = vbr_alignment,
|
||||
.get_size = vbr_size,
|
||||
.write = vbr_write,
|
||||
};
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
vbr.h (09.11.10)
|
||||
Volume Boot Record creation code.
|
||||
|
||||
Free exFAT implementation.
|
||||
Copyright (C) 2011-2018 Andrew Nayenko
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MKFS_VBR_H_INCLUDED
|
||||
#define MKFS_VBR_H_INCLUDED
|
||||
|
||||
#include "mkexfat.h"
|
||||
|
||||
extern const struct fs_object vbr;
|
||||
|
||||
#endif /* ifndef MKFS_VBR_H_INCLUDED */
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
+73
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
TESTCASE_DIR=$1
|
||||
IMAGE_FILE=exfat.img
|
||||
FSCK_PROG=../build/sbin/fsck.exfat
|
||||
FSCK_OPTS=-y
|
||||
PASS_COUNT=0
|
||||
|
||||
cleanup() {
|
||||
echo ""
|
||||
echo "Passed ${PASS_COUNT} of ${TEST_COUNT}"
|
||||
exit
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
TESTCASE_DIRS=$(find . -mindepth 1 -maxdepth 1 -type d)
|
||||
TEST_COUNT=$(find . -mindepth 1 -maxdepth 1 -type d | wc -l)
|
||||
else
|
||||
TESTCASE_DIRS=$@
|
||||
TEST_COUNT=$#
|
||||
fi
|
||||
|
||||
for TESTCASE_DIR in $TESTCASE_DIRS; do
|
||||
if [ ! -e "${TESTCASE_DIR}/${IMAGE_FILE}.tar.xz" ]; then
|
||||
TEST_COUNT=$((TEST_COUNT - 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Running ${TESTCASE_DIR}"
|
||||
echo "-----------------------------------"
|
||||
|
||||
# Set up image file as loop device
|
||||
tar -C . -xf "${TESTCASE_DIR}/${IMAGE_FILE}.tar.xz"
|
||||
DEV_FILE=$(losetup -f "${IMAGE_FILE}" --show)
|
||||
|
||||
# Run fsck for repair
|
||||
$FSCK_PROG $FSCK_OPTS "$DEV_FILE"
|
||||
if [ $? -ne 1 ]; then
|
||||
echo ""
|
||||
echo "Failed to repair ${TESTCASE_DIR}"
|
||||
losetup -d "${DEV_FILE}"
|
||||
cleanup
|
||||
fi
|
||||
|
||||
echo ""
|
||||
# Run fsck again
|
||||
$FSCK_PROG -n "$DEV_FILE"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Failed, corrupted ${TESTCASE_DIR}"
|
||||
losetup -d "${DEV_FILE}"
|
||||
cleanup
|
||||
fi
|
||||
|
||||
if [ -e "${TESTCASE_DIR}/exfat.img.expected.xz" ]; then
|
||||
EXPECTED_FILE=${IMAGE_FILE}.expected
|
||||
unxz -cfk "${TESTCASE_DIR}/${EXPECTED_FILE}.xz" > "${EXPECTED_FILE}"
|
||||
diff <(xxd "${IMAGE_FILE}") <(xxd "${EXPECTED_FILE}")
|
||||
if [ $? -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Failed ${TESTCASE_DIR}"
|
||||
losetup -d "${DEV_FILE}"
|
||||
cleanup
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Passed ${TESTCASE_DIR}"
|
||||
PASS_COUNT=$((PASS_COUNT + 1))
|
||||
|
||||
losetup -d "${DEV_FILE}"
|
||||
done
|
||||
cleanup
|
||||
@@ -0,0 +1,6 @@
|
||||
AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common
|
||||
tune_exfat_LDADD = $(top_builddir)/lib/libexfat.a
|
||||
|
||||
sbin_PROGRAMS = tune.exfat
|
||||
|
||||
tune_exfat_SOURCES = tune.c
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "exfat_ondisk.h"
|
||||
#include "libexfat.h"
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: tune.exfat\n");
|
||||
fprintf(stderr, "\t-l | --print-label Print volume label\n");
|
||||
fprintf(stderr, "\t-L | --set-label=label Set volume label\n");
|
||||
fprintf(stderr, "\t-i | --print-serial Print volume serial\n");
|
||||
fprintf(stderr, "\t-I | --set-serial=value Set volume serial\n");
|
||||
fprintf(stderr, "\t-V | --version Show version\n");
|
||||
fprintf(stderr, "\t-v | --verbose Print debug\n");
|
||||
fprintf(stderr, "\t-h | --help Show help\n");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static struct option opts[] = {
|
||||
{"print-label", no_argument, NULL, 'l' },
|
||||
{"set-label", required_argument, NULL, 'L' },
|
||||
{"print-serial", no_argument, NULL, 'i' },
|
||||
{"set-serial", required_argument, NULL, 'I' },
|
||||
{"version", no_argument, NULL, 'V' },
|
||||
{"verbose", no_argument, NULL, 'v' },
|
||||
{"help", no_argument, NULL, 'h' },
|
||||
{"?", no_argument, NULL, '?' },
|
||||
{NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int ret = EXIT_FAILURE;
|
||||
struct exfat_blk_dev bd;
|
||||
struct exfat_user_input ui;
|
||||
bool version_only = false;
|
||||
int flags = 0;
|
||||
char label_input[VOLUME_LABEL_BUFFER_SIZE];
|
||||
off_t root_clu_off;
|
||||
|
||||
init_user_input(&ui);
|
||||
|
||||
if (!setlocale(LC_CTYPE, ""))
|
||||
exfat_err("failed to init locale/codeset\n");
|
||||
|
||||
opterr = 0;
|
||||
while ((c = getopt_long(argc, argv, "I:iL:lVvh", opts, NULL)) != EOF)
|
||||
switch (c) {
|
||||
case 'l':
|
||||
flags = EXFAT_GET_VOLUME_LABEL;
|
||||
break;
|
||||
case 'L':
|
||||
snprintf(label_input, sizeof(label_input), "%s",
|
||||
optarg);
|
||||
flags = EXFAT_SET_VOLUME_LABEL;
|
||||
break;
|
||||
case 'i':
|
||||
flags = EXFAT_GET_VOLUME_SERIAL;
|
||||
break;
|
||||
case 'I':
|
||||
ui.volume_serial = strtoul(optarg, NULL, 0);
|
||||
flags = EXFAT_SET_VOLUME_SERIAL;
|
||||
break;
|
||||
case 'V':
|
||||
version_only = true;
|
||||
break;
|
||||
case 'v':
|
||||
print_level = EXFAT_DEBUG;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
show_version();
|
||||
if (version_only)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (argc < 3)
|
||||
usage();
|
||||
|
||||
memset(ui.dev_name, 0, sizeof(ui.dev_name));
|
||||
snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[argc - 1]);
|
||||
|
||||
ret = exfat_get_blk_dev_info(&ui, &bd);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* Mode to change or display volume serial */
|
||||
if (flags == EXFAT_GET_VOLUME_SERIAL) {
|
||||
ret = exfat_show_volume_serial(bd.dev_fd);
|
||||
goto close_fd_out;
|
||||
} else if (flags == EXFAT_SET_VOLUME_SERIAL) {
|
||||
ret = exfat_set_volume_serial(&bd, &ui);
|
||||
goto close_fd_out;
|
||||
}
|
||||
|
||||
root_clu_off = exfat_get_root_entry_offset(&bd);
|
||||
if (root_clu_off < 0)
|
||||
goto close_fd_out;
|
||||
|
||||
if (flags == EXFAT_GET_VOLUME_LABEL)
|
||||
ret = exfat_show_volume_label(&bd, root_clu_off);
|
||||
else if (flags == EXFAT_SET_VOLUME_LABEL)
|
||||
ret = exfat_set_volume_label(&bd, label_input, root_clu_off);
|
||||
close_fd_out:
|
||||
close(bd.dev_fd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user