暂时用exfatprogs代码替换exfat-utils代码,等exfatprogs仓孵化后本仓下线。替换原因:本仓工具不支持修复exfat中的错误,而exfatprogs是Linux内核exfat驱动的maintainer开发的官方配套工具。

Signed-off-by: xlfeng <xulifeng7@huawei.com>
This commit is contained in:
xlfeng
2022-04-22 20:17:58 +08:00
parent 93cdc776f1
commit 452da39902
88 changed files with 6107 additions and 8326 deletions
+47
View File
@@ -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 -
+39
View File
@@ -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
+45 -33
View File
@@ -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",
-195
View File
@@ -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
View File
@@ -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
+117
View File
@@ -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
+10 -5
View File
@@ -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 compatibilitylicense 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
View File
@@ -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."
}
]
+103 -67
View File
@@ -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
View File
@@ -0,0 +1,3 @@
#!/bin/sh
autoreconf --install --verbose
+31 -51
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
-55
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
-55
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+99
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+24
View File
@@ -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
-34
View File
@@ -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
View File
@@ -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;
}
-108
View File
@@ -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)
+222
View File
@@ -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 */
+144
View File
@@ -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
View File
@@ -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
+10
View File
@@ -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
View File
@@ -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
-48
View File
@@ -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
View File
@@ -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;
}
-62
View File
@@ -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;
}
+4
View File
@@ -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
View File
@@ -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;
}
-39
View File
@@ -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
-68
View File
@@ -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 */
-491
View File
@@ -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;
}
-69
View File
@@ -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 */
-66
View File
@@ -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
-247
View File
@@ -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 */
-181
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
-222
View File
@@ -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");
}
-373
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
-73
View File
@@ -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 */
-102
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
-192
View File
@@ -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;
}
+17
View File
@@ -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.
+36
View File
@@ -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.
+51
View File
@@ -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),
+111
View File
@@ -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),
+46
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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");
}
-49
View File
@@ -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 */
-71
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
};
-30
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+73
View File
@@ -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
+6
View File
@@ -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
View File
@@ -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;
}