From a8380629099e2bcceda92376b0da1e2be02206ea Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 14 Nov 2019 09:19:53 +0900 Subject: Initial commit --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..9da0585 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# exfat-tools \ No newline at end of file -- cgit v1.2.3 From 63f3a7187b25539e49b59cc63a982768abef8550 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 14 Nov 2019 21:45:27 -0500 Subject: exfat-tools: initial commit Signed-off-by: Namjae Jeon --- COPYING | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile.am | 5 + autogen.sh | 3 + configure.ac | 37 ++++++ dump/Makefile.am | 6 + dump/dump.c | 13 +++ fsck/Makefile.am | 6 + fsck/fsck.c | 13 +++ include/exfat.h | 216 +++++++++++++++++++++++++++++++++++ lib/Makefile.am | 5 + lib/libexfat.c | 7 ++ mkfs/Makefile.am | 6 + mkfs/mkfs.c | 40 +++++++ 13 files changed, 696 insertions(+) create mode 100755 COPYING create mode 100755 Makefile.am create mode 100755 autogen.sh create mode 100755 configure.ac create mode 100644 dump/Makefile.am create mode 100644 dump/dump.c create mode 100644 fsck/Makefile.am create mode 100644 fsck/fsck.c create mode 100644 include/exfat.h create mode 100644 lib/Makefile.am create mode 100644 lib/libexfat.c create mode 100644 mkfs/Makefile.am create mode 100644 mkfs/mkfs.c diff --git a/COPYING b/COPYING new file mode 100755 index 0000000..941c87d --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Makefile.am b/Makefile.am new file mode 100755 index 0000000..4297c79 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,5 @@ +## Makefile.am + +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = lib mkfs fsck dump diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..552165f --- /dev/null +++ b/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +autoreconf --install --verbose diff --git a/configure.ac b/configure.ac new file mode 100755 index 0000000..fca92cf --- /dev/null +++ b/configure.ac @@ -0,0 +1,37 @@ +AC_PREREQ([2.68]) + +m4_define([exfat_tools_major_ver], [1]) +m4_define([exfat_tools_minor_ver], [0]) +m4_define([exfat_tools_micro_ver], [0]) + +m4_define([exfat_tools_version], + [exfat_tools_major_ver.exfat_tools_minor_ver.exfat_tools_micro_ver]) + +AC_INIT([CIFSD tools], [exfat_tools_version], + [linkinjeon@gmail.com]) + +AC_DEFINE([EXFAT_TOOLS_VERSION], "exfat_tools_version", [exfat-tools version]) + +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_STDC +AM_SILENT_RULES([yes]) +AC_PROG_LIBTOOL + +PKG_PROG_PKG_CONFIG([0.9]) + +AC_CONFIG_FILES([ + Makefile + lib/Makefile + mkfs/Makefile + fsck/Makefile + dump/Makefile +]) + +AC_OUTPUT diff --git a/dump/Makefile.am b/dump/Makefile.am new file mode 100644 index 0000000..5a9b9f5 --- /dev/null +++ b/dump/Makefile.am @@ -0,0 +1,6 @@ +AM_CFLAGS = -I$(top_srcdir)/include -fno-common +dump_LDADD = $(top_builddir)/lib/libexfat.la + +sbin_PROGRAMS = dump.exfat + +dump_SOURCES = dump.c diff --git a/dump/dump.c b/dump/dump.c new file mode 100644 index 0000000..7abb21d --- /dev/null +++ b/dump/dump.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Namjae Jeon + */ + +#include + +#include "exfat.h" + +int main() +{ + return 0; +} diff --git a/fsck/Makefile.am b/fsck/Makefile.am new file mode 100644 index 0000000..78df08c --- /dev/null +++ b/fsck/Makefile.am @@ -0,0 +1,6 @@ +AM_CFLAGS = -I$(top_srcdir)/include -fno-common +fsck_LDADD = $(top_builddir)/lib/libexfat.la + +sbin_PROGRAMS = fsck.exfat + +fsck_SOURCES = fsck.c diff --git a/fsck/fsck.c b/fsck/fsck.c new file mode 100644 index 0000000..7abb21d --- /dev/null +++ b/fsck/fsck.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Namjae Jeon + */ + +#include + +#include "exfat.h" + +int main() +{ + return 0; +} diff --git a/include/exfat.h b/include/exfat.h new file mode 100644 index 0000000..caa4bc0 --- /dev/null +++ b/include/exfat.h @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#ifndef _EXFAT_H +#define _EXFAT_H + +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +typedef uint16_t __le16; +typedef uint32_t __le32; +typedef uint64_t __le64; +typedef uint8_t __u8; + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_le64(x) (x) +#else +#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(x) << 32) | cpu_to_le32((x) >> 32)) +#endif + +#define le64_to_cpu(x) cpu_to_le64(x) +#define le32_to_cpu(x) cpu_to_le32(x) +#define le16_to_cpu(x) 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_UNUSED 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) + +/* 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]; +}; + +/* EXFAT PBR[BPB+BSX] (120 bytes) */ +struct pbr64 { + struct bpb64 bpb; + struct bsx64 bsx; +}; + +/* Common PBR[Partition Boot Record] (512 bytes) */ +struct pbr { + union { + __u8 raw[64]; + struct bpb64 f64; + } bpb; + union { + __u8 raw[56]; + struct bsx64 f64; + } bsx; + __u8 boot_code[390]; + __le16 signature; +}; + +struct exfat_dentry { + __u8 type; + union { + 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 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 */ diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..1c952b4 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,5 @@ +AM_CFLAGS = -I$(top_srcdir)/include -fno-common + +lib_LTLIBRARIES = libexfat.la + +libexfat_la_SOURCES = libexfat.c diff --git a/lib/libexfat.c b/lib/libexfat.c new file mode 100644 index 0000000..ff31d39 --- /dev/null +++ b/lib/libexfat.c @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Namjae Jeon + */ + + + diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am new file mode 100644 index 0000000..b27c845 --- /dev/null +++ b/mkfs/Makefile.am @@ -0,0 +1,6 @@ +AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) -fno-common +mkfs_LDADD = $(top_builddir)/lib/libexfat.la + +sbin_PROGRAMS = mkfs.exfat + +mkfs_SOURCES = mkfs.c diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c new file mode 100644 index 0000000..6722e8c --- /dev/null +++ b/mkfs/mkfs.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Namjae Jeon + */ + +#include +#include +#include +#include + +#include "exfat.h" + +static void usage(void) +{ + fprintf(stderr, "exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); + fprintf(stderr, "Usage: mkfs.exfat\n"); + + fprintf(stderr, "\t-v | --verbose\n"); + + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int c; + int ret = EXIT_FAILURE; + + opterr = 0; + while ((c = getopt(argc, argv, "c:i:a:d:u:p:vh")) != EOF) + switch (c) { + case 'v': + break; + case '?': + case 'h': + default: + usage(); + } + + return 0; +} -- cgit v1.2.3 From 3171ed8e047ec8c8c97d4325ffba2132e5ab6e76 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 12 Dec 2019 21:53:12 +0900 Subject: exfat-tools: add mkfs initial work (not test) Signed-off-by: Namjae Jeon --- dump/dump.c | 2 +- fsck/fsck.c | 2 +- include/exfat.h | 216 --------------------- include/exfat_ondisk.h | 231 ++++++++++++++++++++++ include/exfat_tools.h | 47 +++++ include/mkfs.h | 35 ++++ lib/libexfat.c | 57 ++++++ mkfs/Makefile.am | 6 +- mkfs/mkfs.c | 405 ++++++++++++++++++++++++++++++++++++++- mkfs/upcase.c | 507 +++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1284 insertions(+), 224 deletions(-) delete mode 100644 include/exfat.h create mode 100644 include/exfat_ondisk.h create mode 100644 include/exfat_tools.h create mode 100644 include/mkfs.h create mode 100644 mkfs/upcase.c diff --git a/dump/dump.c b/dump/dump.c index 7abb21d..698487b 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -5,7 +5,7 @@ #include -#include "exfat.h" +#include "exfat_ondisk.h" int main() { diff --git a/fsck/fsck.c b/fsck/fsck.c index 7abb21d..698487b 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -5,7 +5,7 @@ #include -#include "exfat.h" +#include "exfat_ondisk.h" int main() { diff --git a/include/exfat.h b/include/exfat.h deleted file mode 100644 index caa4bc0..0000000 --- a/include/exfat.h +++ /dev/null @@ -1,216 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. - */ - -#ifndef _EXFAT_H -#define _EXFAT_H - -#include -#include - -#ifdef HAVE_CONFIG_H -#include -#endif - -typedef uint16_t __le16; -typedef uint32_t __le32; -typedef uint64_t __le64; -typedef uint8_t __u8; - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define cpu_to_le16(x) (x) -#define cpu_to_le32(x) (x) -#define cpu_to_le64(x) (x) -#else -#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(x) << 32) | cpu_to_le32((x) >> 32)) -#endif - -#define le64_to_cpu(x) cpu_to_le64(x) -#define le32_to_cpu(x) cpu_to_le32(x) -#define le16_to_cpu(x) 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_UNUSED 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) - -/* 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]; -}; - -/* EXFAT PBR[BPB+BSX] (120 bytes) */ -struct pbr64 { - struct bpb64 bpb; - struct bsx64 bsx; -}; - -/* Common PBR[Partition Boot Record] (512 bytes) */ -struct pbr { - union { - __u8 raw[64]; - struct bpb64 f64; - } bpb; - union { - __u8 raw[56]; - struct bsx64 f64; - } bsx; - __u8 boot_code[390]; - __le16 signature; -}; - -struct exfat_dentry { - __u8 type; - union { - 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 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 */ diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h new file mode 100644 index 0000000..660ca36 --- /dev/null +++ b/include/exfat_ondisk.h @@ -0,0 +1,231 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019 Namjae Jeon + */ + +#ifndef _EXFAT_H +#define _EXFAT_H + +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +typedef uint16_t __le16; +typedef uint32_t __le32; +typedef uint64_t __le64; +typedef uint8_t __u8; + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_le64(x) (x) +#else +#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(x) << 32) | cpu_to_le32((x) >> 32)) +#endif + +#define le64_to_cpu(x) cpu_to_le64(x) +#define le32_to_cpu(x) cpu_to_le32(x) +#define le16_to_cpu(x) 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_UNUSED 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) + +#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_REVERVED_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; +}; + +/* Extended Boot Sector */ +struct exbs { + __u8 zero[510]; + __le16 signature; +}; + +/* Extended Boot Record (8 sectors) */ +struct expbr { + struct exbs eb[8]; +}; + +struct exfat_dentry { + __u8 type; + union { + struct { + __u8 character_count; + __u8 volume_label[22]; + __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 */ diff --git a/include/exfat_tools.h b/include/exfat_tools.h new file mode 100644 index 0000000..55c8807 --- /dev/null +++ b/include/exfat_tools.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019 Namjae Jeon + */ + +#ifndef _EXFAT_TOOLS_H + +#define EXFAT_MIN_NUM_SEC_VOL (2048) +#define EXFAT_MAX_NUM_SEC_VOL ((2 << 64) - 1) + +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) + +/* Upcase tabel macro */ +#define EXFAT_UPCASE_TABLE_SIZE (5836) + +enum { + BOOT_SEC_NUM = 0, + EXBOOT_SEC_NUM, + EXBOOT_SEC8_NUM = 8, + OEM_SEC_NUM, + RESERVED_SEC_NUM, + CHECKSUM_NUM, +}; + +struct exfat_blk_dev { + int dev_fd; + unsigned long long size; + unsigned int sector_size; + unsigned int sector_size_bits; + unsigned int num_sectors; + unsigned int num_clusters; +}; + +struct exfat_user_input { + char dev_name[255]; + unsigned int cluster_size; + unsigned int sec_per_clu; +}; + +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); + +#endif /* !_EXFA_TOOLS_H */ diff --git a/include/mkfs.h b/include/mkfs.h new file mode 100644 index 0000000..458ae4f --- /dev/null +++ b/include/mkfs.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019 Namjae Jeon + */ + +#ifndef _MKFS_H + +#define DEFAULT_CLUSTER_SIZE (1024 * 1024) +#define DEFAULT_SECTOR_SIZE (512) +#define MIN_NUM_SECTOR (2048) +#define MAX_CLUSTER_SIZE (32*1024*1024) + +struct exfat_mkfs_info { + int total_clu_cnt; + int used_clu_cnt; + int fat_byte_off; + int fat_byte_len; + int clu_byte_off; + int bitmap_byte_off; + int bitmap_byte_len; + int ut_byte_off; + int ut_start_clu; + int ut_clus_off; + int ut_byte_len; + int root_byte_off; + int root_byte_len; + int root_start_clu; +}; + +struct exfat_mkfs_info finfo; + +int exfat_create_upcase_table(struct exfat_blk_dev *bd, + struct exfat_user_input *ui); + +#endif /* !_MKFS_H */ diff --git a/lib/libexfat.c b/lib/libexfat.c index ff31d39..7be3448 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -3,5 +3,62 @@ * Copyright (C) 2019 Namjae Jeon */ +#include "exfat_ondisk.h" +#include "exfat_tools.h" +#if defined(__LITTLE_ENDIAN) +#define BITOP_LE_SWIZZLE 0 +#elif defined(__BIG_ENDIAN) +#define BITOP_LE_SWIZZLE (~0x7) +#endif +#define BIT_MASK(nr) ((1) << ((nr) % 32)) +#define BIT_WORD(nr) ((nr) / 32) + +static inline void set_bit(int nr, volatile unsigned int *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, volatile unsigned int *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 i, b; + + i = clu >> (bd->sector_size_bits + 3); + 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 i, b; + + i = clu >> (bd->sector_size_bits + 3); + b = clu & ((bd->sector_size << 3) - 1); + + clear_bit_le(b, bitmap); +} diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index b27c845..a1e1b43 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,6 +1,6 @@ -AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) -fno-common -mkfs_LDADD = $(top_builddir)/lib/libexfat.la +AM_CFLAGS = -I$(top_srcdir)/include -fno-common +#mkfs_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = mkfs.exfat -mkfs_SOURCES = mkfs.c +mkfs_SOURCES = mkfs.c upcase.c diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 6722e8c..b30dde1 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -5,10 +5,330 @@ #include #include +#include +#include +#include +#include +#include +#include #include #include -#include "exfat.h" +#include "exfat_ondisk.h" +#include "exfat_tools.h" +#include "mkfs.h" + +static void calc_checksum(char *sector, unsigned short size, + bool is_boot_sec, unsigned int *checksum) +{ + unsigned int index; + + for (index = 0; index < size; index++) + { + if (is_boot_sec == true && + ((index == 106) || (index == 107) || (index == 112))) + continue; + *checksum = ((*checksum & 1) ? 0x80000000 : 0) + + (*checksum >> 1) + (unsigned int)sector[index]; + } +} + +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; + + /* Fill exfat BIOS paramemter 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 paramemter block */ + pbsx->vol_offset = 0; + 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_byte_off / ui->cluster_size); + pbsx->vol_serial = 1234; + pbsx->vol_flags = 0; + pbsx->sect_size_bits = bd->sector_size_bits; + pbsx->sect_per_clus_bits = ui->sec_per_clu; + pbsx->num_fats = 1; + /* fs_version[0] : minor and fs_version[1] : major */ + pbsx->fs_version[0] = 0; + pbsx->fs_version[1] = 1; + memset(pbsx->reserved2, 0, 7); + + memset(ppbr->boot_code, 0, 390); + ppbr->signature = cpu_to_le16(PBR_SIGNATURE); +} + +static 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; + + lseek(bd->dev_fd, offset, SEEK_SET); + bytes = write(bd->dev_fd, buf, bd->sector_size); + if (bytes != bd->sector_size) + return -1; + return 0; +} + +static int exfat_write_boot_sectors(struct exfat_blk_dev *bd, + struct exfat_user_input *ui, unsigned int *checksum) +{ + struct pbr *ppbr; + int ret; + + ppbr = malloc(sizeof(struct pbr)); + if (!ppbr) { + printf("Cannot allocate pbr: out of memory\n"); + return -1; + } + memset(ppbr, 0, sizeof(struct pbr)); + + exfat_setup_boot_sector(ppbr, bd, ui); + + /* write main boot sector */ + ret = exfat_write_sector(bd, ppbr, 0); + if (ret < 0) { + ret = -1; + goto free_ppbr; + } + + /* write backup boot sector */ + ret = exfat_write_sector(bd, ppbr, 1); + if (ret < 0) { + ret = -1; + goto free_ppbr; + } + + calc_checksum((char *)ppbr, sizeof(struct pbr), true, checksum); + +free_ppbr: + free(ppbr); + return 0; +} + +static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, + unsigned int *checksum) +{ + int sec_idx; + struct expbr ep; + + memset(&ep, 0, EXBOOT_SEC8_NUM * bd->sector_size); + for (sec_idx = EXBOOT_SEC_NUM; sec_idx <= EXBOOT_SEC8_NUM; sec_idx++) { + int ret; + + ep.eb[sec_idx - 1].signature = cpu_to_le16(0xAA55); + if (exfat_write_sector(bd, &ep, sec_idx)) + return -1; + + calc_checksum((char *) &ep, sizeof(struct expbr), false, checksum); + } + + return 0; +} + +static int exfat_write_oem_sector(struct exfat_blk_dev *bd, + unsigned int *checksum) +{ + char *oem; + + oem = malloc(bd->sector_size); + if (oem) + return -1; + + memset(oem, 0xFF, bd->sector_size); + if (exfat_write_sector(bd, oem, OEM_SEC_NUM)) + return -1; + + calc_checksum((char *)oem, bd->sector_size, false, checksum); +} + +static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, + unsigned int checksum) +{ + int *checksum_buf; + + checksum_buf = malloc(bd->sector_size); + if (checksum_buf) + return -1; + + memset(checksum_buf, checksum, bd->sector_size / sizeof(int)); + if (exfat_write_sector(bd, checksum_buf, OEM_SEC_NUM)) + return -1; +} + +static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, + struct exfat_user_input *ui) +{ + int ret; + unsigned int checksum; + + ret = exfat_write_boot_sectors(bd, ui, &checksum); + if (ret) + return ret; + + ret = exfat_write_extended_boot_sectors(bd, &checksum); + if (ret) + return ret; + + ret = exfat_write_oem_sector(bd, &checksum); + if (ret) + return ret; + + ret = exfat_write_checksum_sector(bd, checksum); + return ret; +} + +static int write_fat_entry(int fd, unsigned int entry, + unsigned long long offset) +{ + int nbyte; + + lseek(fd, finfo.fat_byte_off + (offset * sizeof(int)), SEEK_SET); + nbyte = write(fd, (char *) &entry, sizeof(unsigned int)); + if (nbyte != sizeof(int)) + return -1; +} + +static int exfat_create_fat_table(struct exfat_blk_dev *bd, + struct exfat_user_input *ui) +{ + int ret, clu, clu_cnt, bitmap_clu_cnt, ut_cnt, root_cnt; + int count; + + /* fat entry 0 should be media type field(0xF8) */ + ret = write_fat_entry(bd->dev_fd, 0xfffffff8, 0); + if (ret) + return ret; + + /* fat entry 1 is historical precedence(0xFFFFFFFF) */ + ret = write_fat_entry(bd->dev_fd, 0xffffffff, 1); + if (ret) + return ret; + + /* write bitmap entries */ + count = EXFAT_FIRST_CLUSTER + (finfo.bitmap_byte_len / ui->cluster_size); + for (clu = EXFAT_FIRST_CLUSTER; clu < count; clu++) { + ret = write_fat_entry(bd->dev_fd, clu, clu * sizeof(int)); + if (ret) + return ret; + } + + /* write upcase table entries */ + count += finfo.ut_byte_len / ui->cluster_size; + finfo.ut_start_clu = clu; + for (; clu < count; clu++) { + ret = write_fat_entry(bd->dev_fd, clu, clu); + if (ret) + return ret; + } + + /* write root directory entries */ + count += finfo.root_byte_len / ui->cluster_size; + finfo.root_start_clu = clu; + for (; clu < count; clu++) { + ret = write_fat_entry(bd->dev_fd, clu, clu); + if (ret) + return ret; + } + + finfo.used_clu_cnt = count; + + return ret; +} + +static int exfat_create_bitmap(struct exfat_blk_dev *bd, + struct exfat_user_input *ui) +{ + char *bitmap; + int i,nbytes; + + bitmap = malloc(finfo.bitmap_byte_len); + if (!bitmap) + return -1; + + for (i = 0; i < finfo.used_clu_cnt; i++) + exfat_set_bit(bd, bitmap, i); + + lseek(bd->dev_fd, finfo.bitmap_byte_off, SEEK_SET); + nbytes = write(bd->dev_fd, bitmap, finfo.bitmap_byte_len); + if (nbytes != finfo.bitmap_byte_len) + return -1; + + 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; + strcpy(ed[0].vol_label, "EXFAT"); + ed[0].vol_char_cnt = strlen("EXFAT"); + + /* Set bitmap entry */ + ed[1].type = EXFAT_BITMAP; + ed[1].bitmap_flags = 0; + ed[1].bitmap_start_clu = EXFAT_FIRST_CLUSTER; + ed[1].bitmap_size = 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 = finfo.ut_start_clu; + ed[2].upcase_size = EXFAT_UPCASE_TABLE_SIZE; + + lseek(bd->dev_fd, finfo.root_byte_off, SEEK_SET); + nbytes = write(bd->dev_fd, ed, dentries_len); + if (nbytes != dentries_len) + return -1; + + return 0; +} + +int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_dev *bd) +{ + int fd, ret = -1; + unsigned long long blk_dev_size; + + fd = open(ui->dev_name, O_RDONLY); + if (fd < 0) + return -1; + + blk_dev_size = lseek(fd, 0, SEEK_END); + if (blk_dev_size <= 0) { + perror("exfat-tools\n"); + goto out; + } + + bd->size = blk_dev_size; + bd->sector_size = DEFAULT_SECTOR_SIZE; + bd->sector_size_bits = 9; + bd->num_sectors = blk_dev_size / DEFAULT_SECTOR_SIZE; + if (bd->num_sectors < MIN_NUM_SECTOR) { + printf(" \n"); + goto out; + } + bd->num_clusters = blk_dev_size / ui->cluster_size; + + ret = 0; + bd->dev_fd = fd; +out: + return ret; +} static void usage(void) { @@ -20,14 +340,58 @@ static void usage(void) exit(EXIT_FAILURE); } +static int verify_user_input(struct exfat_blk_dev *bd, + struct exfat_user_input *ui) +{ + ui->sec_per_clu = ui->cluster_size / bd->sector_size; + return 0; +} + +static void make_exfat_layout_info(struct exfat_blk_dev *bd, + struct exfat_user_input *ui) +{ + int num_bitmap_clu; + + if (DEFAULT_CLUSTER_SIZE < ui->sec_per_clu) + finfo.fat_byte_off = ui->cluster_size; + else + finfo.fat_byte_off = DEFAULT_CLUSTER_SIZE; + finfo.fat_byte_len = round_up((bd->num_clusters * sizeof(int)), + ui->cluster_size); + finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len, + DEFAULT_CLUSTER_SIZE); + finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; + finfo.bitmap_byte_off = EXFAT_REVERVED_CLUSTERS * ui->cluster_size; + finfo.bitmap_byte_len = + round_up((bd->num_clusters / 8) , ui->cluster_size) * + ui->cluster_size; + finfo.ut_byte_off = finfo.bitmap_byte_off + finfo.bitmap_byte_len; + finfo.ut_start_clu = finfo.ut_byte_off / ui->cluster_size; + finfo.ut_byte_len = round_up(EXFAT_UPCASE_TABLE_SIZE, ui->cluster_size); + finfo.root_byte_off = finfo.ut_byte_off + finfo.ut_byte_len; + finfo.root_start_clu = finfo.root_byte_off / ui->cluster_size; + finfo.root_byte_len = sizeof(struct exfat_dentry) * 3; +} + int main(int argc, char *argv[]) { int c; int ret = EXIT_FAILURE; + char *blk_dev_name; + struct exfat_blk_dev bd; + struct exfat_user_input ui; opterr = 0; - while ((c = getopt(argc, argv, "c:i:a:d:u:p:vh")) != EOF) + while ((c = getopt(argc, argv, "s:vh")) != EOF) switch (c) { + case 'c': + ui.cluster_size = atoi(optarg); + if (ui.cluster_size > MAX_CLUSTER_SIZE) { + printf("cluster size(%d) exceeds max cluster size(%d)", + ui.cluster_size, MAX_CLUSTER_SIZE); + goto out; + } + break; case 'v': break; case '?': @@ -36,5 +400,40 @@ int main(int argc, char *argv[]) usage(); } - return 0; + if (argc - optind != 1) + usage(); + + memset(ui.dev_name, 0, 255); + strncpy(ui.dev_name, argv[optind], 255); + + ret = exfat_get_blk_dev_info(&ui, &bd); + if (ret < 0) + goto out; + + ret = verify_user_input(&bd, &ui); + if (ret < 0) + goto out; + + make_exfat_layout_info(&bd, &ui); + + ret = exfat_create_volume_boot_record(&bd, &ui); + if (ret) + goto out; + + ret = exfat_create_fat_table(&bd, &ui); + if (ret) + goto out; + + ret = exfat_create_bitmap(&bd, &ui); + if (ret) + goto out; + + ret = exfat_create_upcase_table(&bd, &ui); + if (ret) + goto out; + + ret = exfat_create_root_dir(&bd, &ui); + +out: + return ret; } diff --git a/mkfs/upcase.c b/mkfs/upcase.c new file mode 100644 index 0000000..eacfcef --- /dev/null +++ b/mkfs/upcase.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Namjae Jeon + */ + +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, + struct exfat_user_input *ui) +{ + int ut_off, nbytes; + + lseek(bd->dev_fd, finfo.ut_byte_off, SEEK_SET); + nbytes = write(bd->dev_fd, upcase_table, EXFAT_UPCASE_TABLE_SIZE); + if (nbytes != EXFAT_UPCASE_TABLE_SIZE) + return -1; + + return 0; +} -- cgit v1.2.3 From e5987e16fde9336caaa0ceba56a99286b92e44eb Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 12 Dec 2019 22:02:39 +0900 Subject: exfat-tools: add traivs CI build test Signed-off-by: Namjae Jeon --- .travis.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cecd184 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +dist: bionic + +language: c + +notifications: + - email: true + +script: + # Compilation + - ./autogen.sh + - ./configure + - make -- cgit v1.2.3 From 9debc50b3a5dae253078ca6c815f111c3ca17954 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 15 Dec 2019 23:47:13 -0500 Subject: exfat-tools: mkfs: open device node with Read/write mode Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index b30dde1..9ca3395 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -304,7 +304,7 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_dev *bd int fd, ret = -1; unsigned long long blk_dev_size; - fd = open(ui->dev_name, O_RDONLY); + fd = open(ui->dev_name, O_RDWR); if (fd < 0) return -1; -- cgit v1.2.3 From 4b1650511e27d10c45424b0d3ab90b12900d3b6f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 01:12:46 -0500 Subject: exfat-tools: fix incorrect calculation of value in boot sector Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 9ca3395..98c0fae 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -57,7 +57,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, pbsx->vol_serial = 1234; pbsx->vol_flags = 0; pbsx->sect_size_bits = bd->sector_size_bits; - pbsx->sect_per_clus_bits = ui->sec_per_clu; + pbsx->sect_per_clus_bits = ui->sec_per_clu / 32; pbsx->num_fats = 1; /* fs_version[0] : minor and fs_version[1] : major */ pbsx->fs_version[0] = 0; @@ -363,8 +363,7 @@ static void make_exfat_layout_info(struct exfat_blk_dev *bd, finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; finfo.bitmap_byte_off = EXFAT_REVERVED_CLUSTERS * ui->cluster_size; finfo.bitmap_byte_len = - round_up((bd->num_clusters / 8) , ui->cluster_size) * - ui->cluster_size; + round_up((bd->num_clusters / 8) , ui->cluster_size); finfo.ut_byte_off = finfo.bitmap_byte_off + finfo.bitmap_byte_len; finfo.ut_start_clu = finfo.ut_byte_off / ui->cluster_size; finfo.ut_byte_len = round_up(EXFAT_UPCASE_TABLE_SIZE, ui->cluster_size); @@ -381,6 +380,12 @@ int main(int argc, char *argv[]) struct exfat_blk_dev bd; struct exfat_user_input ui; + /* + * Default cluster size, Need to adjust default cluster size + * according to device size + */ + ui.cluster_size = 128 * 1024; + opterr = 0; while ((c = getopt(argc, argv, "s:vh")) != EOF) switch (c) { -- cgit v1.2.3 From baa0a6c0aa027d7d9d6e8293cc461cbd90a57e94 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 03:16:06 -0500 Subject: exfat-tools: fix wrong bitmap_byte_len and ut_byte_len Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 98c0fae..46ff081 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -362,11 +362,10 @@ static void make_exfat_layout_info(struct exfat_blk_dev *bd, DEFAULT_CLUSTER_SIZE); finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; finfo.bitmap_byte_off = EXFAT_REVERVED_CLUSTERS * ui->cluster_size; - finfo.bitmap_byte_len = - round_up((bd->num_clusters / 8) , ui->cluster_size); + finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8; finfo.ut_byte_off = finfo.bitmap_byte_off + finfo.bitmap_byte_len; finfo.ut_start_clu = finfo.ut_byte_off / ui->cluster_size; - finfo.ut_byte_len = round_up(EXFAT_UPCASE_TABLE_SIZE, ui->cluster_size); + finfo.ut_byte_len = EXFAT_UPCASE_TABLE_SIZE; finfo.root_byte_off = finfo.ut_byte_off + finfo.ut_byte_len; finfo.root_start_clu = finfo.root_byte_off / ui->cluster_size; finfo.root_byte_len = sizeof(struct exfat_dentry) * 3; -- cgit v1.2.3 From f48bfbb5b4c7111234fb19ad6075eef6cfc0787e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 03:27:10 -0500 Subject: exfat-tools: fix wrong ut_byte_off and root_byte_off Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 46ff081..6c83edf 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -363,10 +363,10 @@ static void make_exfat_layout_info(struct exfat_blk_dev *bd, finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; finfo.bitmap_byte_off = EXFAT_REVERVED_CLUSTERS * ui->cluster_size; finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8; - finfo.ut_byte_off = finfo.bitmap_byte_off + finfo.bitmap_byte_len; + finfo.ut_byte_off = round_up(finfo.bitmap_byte_off + finfo.bitmap_byte_len, ui->cluster_size); finfo.ut_start_clu = finfo.ut_byte_off / ui->cluster_size; finfo.ut_byte_len = EXFAT_UPCASE_TABLE_SIZE; - finfo.root_byte_off = finfo.ut_byte_off + finfo.ut_byte_len; + finfo.root_byte_off = round_up(finfo.ut_byte_off + finfo.ut_byte_len, ui->cluster_size); finfo.root_start_clu = finfo.root_byte_off / ui->cluster_size; finfo.root_byte_len = sizeof(struct exfat_dentry) * 3; } -- cgit v1.2.3 From e47f2c6400ea48e494c998d8e0f2d95a02482289 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 21:06:36 +0900 Subject: exfat-tools: rename make_exfat_layout_info to exfat_build_mkfs_info Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 6c83edf..864466d 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -347,11 +347,9 @@ static int verify_user_input(struct exfat_blk_dev *bd, return 0; } -static void make_exfat_layout_info(struct exfat_blk_dev *bd, +static void exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - int num_bitmap_clu; - if (DEFAULT_CLUSTER_SIZE < ui->sec_per_clu) finfo.fat_byte_off = ui->cluster_size; else @@ -418,7 +416,7 @@ int main(int argc, char *argv[]) if (ret < 0) goto out; - make_exfat_layout_info(&bd, &ui); + exfat_build_mkfs_info(&bd, &ui); ret = exfat_create_volume_boot_record(&bd, &ui); if (ret) -- cgit v1.2.3 From 0539f4e203bb1ee89ca2783c6bf0a28fa9ac59e9 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 22:42:28 +0900 Subject: exfat-tools: add exfat_msg print function Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 17 +++++++++++++++++ mkfs/mkfs.c | 14 +++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 55c8807..81fa695 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -44,4 +44,21 @@ void exfat_set_bit(struct exfat_blk_dev *bd, char *bitmap, void exfat_clear_bit(struct exfat_blk_dev *bd, char *bitmap, unsigned int clu); +/* + * Exfat Print + */ + +unsigned int print_level; + +#define EXFAT_ERROR (0) +#define EXFAT_DEBUG (1) + +#define exfat_msg(level, fmt, ...) \ + do { \ + if (print_level >= level) { \ + printf("[%s:%4d] " fmt, \ + __func__, __LINE__, ##__VA_ARGS__); \ + } \ + } while (0) \ + #endif /* !_EXFA_TOOLS_H */ diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 864466d..5f2b637 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -195,8 +195,12 @@ static int write_fat_entry(int fd, unsigned int entry, lseek(fd, finfo.fat_byte_off + (offset * sizeof(int)), SEEK_SET); nbyte = write(fd, (char *) &entry, sizeof(unsigned int)); - if (nbyte != sizeof(int)) + if (nbyte != sizeof(int)) { + exfat_msg(EXFAT_ERROR, + "write failed, offset : %llu, entry : %x\n", + offset, entry); return -1; + } } static int exfat_create_fat_table(struct exfat_blk_dev *bd, @@ -216,7 +220,9 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, return ret; /* write bitmap entries */ - count = EXFAT_FIRST_CLUSTER + (finfo.bitmap_byte_len / ui->cluster_size); + count = EXFAT_FIRST_CLUSTER; + count += round_up(finfo.bitmap_byte_len, ui->cluster_size) / + ui->cluster_size; for (clu = EXFAT_FIRST_CLUSTER; clu < count; clu++) { ret = write_fat_entry(bd->dev_fd, clu, clu * sizeof(int)); if (ret) @@ -224,7 +230,8 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, } /* write upcase table entries */ - count += finfo.ut_byte_len / ui->cluster_size; + count += round_up(finfo.ut_byte_len, ui->cluster_size) / + ui->cluster_size; finfo.ut_start_clu = clu; for (; clu < count; clu++) { ret = write_fat_entry(bd->dev_fd, clu, clu); @@ -395,6 +402,7 @@ int main(int argc, char *argv[]) } break; case 'v': + print_level = EXFAT_DEBUG; break; case '?': case 'h': -- cgit v1.2.3 From 0730ee203d4910d649ac54a6362055e53adab08e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 19:32:30 -0500 Subject: exfat-tools: move default cluster size set to verify_user_input Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 5f2b637..204c1ab 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -350,6 +350,14 @@ static void usage(void) static int verify_user_input(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { + if (!ui.ui.cluster_size) { + /* + * Default cluster size, Need to adjust default cluster size + * according to device size + */ + ui.cluster_size = 128 * 1024; + } + ui->sec_per_clu = ui->cluster_size / bd->sector_size; return 0; } @@ -384,12 +392,6 @@ int main(int argc, char *argv[]) struct exfat_blk_dev bd; struct exfat_user_input ui; - /* - * Default cluster size, Need to adjust default cluster size - * according to device size - */ - ui.cluster_size = 128 * 1024; - opterr = 0; while ((c = getopt(argc, argv, "s:vh")) != EOF) switch (c) { -- cgit v1.2.3 From 7e02644c008085e3f74225b19650287d702e6418 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 19:38:27 -0500 Subject: exfat-tools: add -V option to show exfat-tools version Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 204c1ab..a2fd8cb 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -339,7 +339,6 @@ out: static void usage(void) { - fprintf(stderr, "exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); fprintf(stderr, "Usage: mkfs.exfat\n"); fprintf(stderr, "\t-v | --verbose\n"); @@ -347,15 +346,21 @@ static void usage(void) exit(EXIT_FAILURE); } +static void show_version(void) +{ + printf("exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); + exit(EXIT_FAILURE); +} + static int verify_user_input(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - if (!ui.ui.cluster_size) { + if (!ui->cluster_size) { /* * Default cluster size, Need to adjust default cluster size * according to device size */ - ui.cluster_size = 128 * 1024; + ui->cluster_size = 128 * 1024; } ui->sec_per_clu = ui->cluster_size / bd->sector_size; @@ -403,6 +408,9 @@ int main(int argc, char *argv[]) goto out; } break; + case 'V': + show_version(); + break; case 'v': print_level = EXFAT_DEBUG; break; -- cgit v1.2.3 From 4c70ba785c08e6498d7a225d9651bcc78cd55191 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 20:03:26 -0500 Subject: exfat-tools: change getopt with getopt_long Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index a2fd8cb..a0e1ccc 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -340,8 +340,10 @@ out: static void usage(void) { fprintf(stderr, "Usage: mkfs.exfat\n"); - + fprintf(stderr, "\t-c | --cluster-size\n"); + fprintf(stderr, "\t-V | --version\n"); fprintf(stderr, "\t-v | --verbose\n"); + fprintf(stderr, "\t-h | --help\n"); exit(EXIT_FAILURE); } @@ -352,6 +354,14 @@ static void show_version(void) exit(EXIT_FAILURE); } +static struct option opts[] = { + {"cluster-size", required_argument, NULL, 'c' }, + {"version", no_argument, NULL, 'V' }, + {"help", no_argument, NULL, 'h' }, + {"?", no_argument, NULL, '?' }, + {NULL, 0, NULL, 0 } +}; + static int verify_user_input(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { @@ -398,7 +408,7 @@ int main(int argc, char *argv[]) struct exfat_user_input ui; opterr = 0; - while ((c = getopt(argc, argv, "s:vh")) != EOF) + while ((c = getopt_long(argc, argv, "c:Vvh", opts, NULL)) != EOF) switch (c) { case 'c': ui.cluster_size = atoi(optarg); -- cgit v1.2.3 From 73e4eeb007e19a3e49d6685bac49fb60711c23f3 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 20:21:24 -0500 Subject: exfat-tools: memset exfat_user_input as zero Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index a0e1ccc..d82e4a9 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -407,6 +407,8 @@ int main(int argc, char *argv[]) struct exfat_blk_dev bd; struct exfat_user_input ui; + memset(&ui, 0, sizeof(struct exfat_user_input)); + opterr = 0; while ((c = getopt_long(argc, argv, "c:Vvh", opts, NULL)) != EOF) switch (c) { -- cgit v1.2.3 From e464059537b74524c1ec99892be88d414aa0313f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 20:55:42 -0500 Subject: exfat-tools: add BLKSSZGET ioctl to get sector size Signed-off-by: Namjae Jeon --- include/exfat_ondisk.h | 6 +----- mkfs/mkfs.c | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index 660ca36..61293b4 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -8,16 +8,12 @@ #include #include +#include #ifdef HAVE_CONFIG_H #include #endif -typedef uint16_t __le16; -typedef uint32_t __le32; -typedef uint64_t __le64; -typedef uint8_t __u8; - #if __BYTE_ORDER == __LITTLE_ENDIAN #define cpu_to_le16(x) (x) #define cpu_to_le32(x) (x) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index d82e4a9..4bdbf49 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -88,7 +89,7 @@ static int exfat_write_boot_sectors(struct exfat_blk_dev *bd, ppbr = malloc(sizeof(struct pbr)); if (!ppbr) { - printf("Cannot allocate pbr: out of memory\n"); + exfat_msg(EXFAT_ERROR, "Cannot allocate pbr: out of memory\n"); return -1; } memset(ppbr, 0, sizeof(struct pbr)); @@ -306,7 +307,17 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, return 0; } -int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_dev *bd) +static inline unsigned int sector_size_bits(unsigned int size) +{ + unsigned int bits = 8; + do { + bits++; + size >>= 1; + } while (size > 256); + return bits; +} + +static int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_dev *bd) { int fd, ret = -1; unsigned long long blk_dev_size; @@ -322,13 +333,11 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_dev *bd } bd->size = blk_dev_size; - bd->sector_size = DEFAULT_SECTOR_SIZE; - bd->sector_size_bits = 9; + + 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 / DEFAULT_SECTOR_SIZE; - if (bd->num_sectors < MIN_NUM_SECTOR) { - printf(" \n"); - goto out; - } bd->num_clusters = blk_dev_size / ui->cluster_size; ret = 0; -- cgit v1.2.3 From f9aaec7dff7c15b08c4c90a5f6dc6f14dd127aab Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 21:10:35 -0500 Subject: exfat-tools: add init_user_input function Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 4bdbf49..09bf3c6 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -333,7 +333,6 @@ static int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_ } bd->size = blk_dev_size; - if (ioctl(fd, BLKSSZGET, &bd->sector_size) < 0) bd->sector_size = DEFAULT_SECTOR_SIZE; bd->sector_size_bits = sector_size_bits(bd->sector_size); @@ -371,17 +370,19 @@ static struct option opts[] = { {NULL, 0, NULL, 0 } }; +static void init_user_input(struct exfat_user_input *ui) +{ + memset(ui, 0, sizeof(struct exfat_user_input)); + /* + * Default cluster size, Need to adjust default cluster size + * according to device size + */ + ui->cluster_size = 128 * 1024; +} + static int verify_user_input(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - if (!ui->cluster_size) { - /* - * Default cluster size, Need to adjust default cluster size - * according to device size - */ - ui->cluster_size = 128 * 1024; - } - ui->sec_per_clu = ui->cluster_size / bd->sector_size; return 0; } @@ -416,7 +417,7 @@ int main(int argc, char *argv[]) struct exfat_blk_dev bd; struct exfat_user_input ui; - memset(&ui, 0, sizeof(struct exfat_user_input)); + init_user_input(&ui); opterr = 0; while ((c = getopt_long(argc, argv, "c:Vvh", opts, NULL)) != EOF) @@ -424,8 +425,9 @@ int main(int argc, char *argv[]) case 'c': ui.cluster_size = atoi(optarg); if (ui.cluster_size > MAX_CLUSTER_SIZE) { - printf("cluster size(%d) exceeds max cluster size(%d)", - ui.cluster_size, MAX_CLUSTER_SIZE); + exfat_msg(EXFAT_ERROR, + "cluster size(%d) exceeds max cluster size(%d)", + ui.cluster_size, MAX_CLUSTER_SIZE); goto out; } break; -- cgit v1.2.3 From a7496a8d7f1678b785d8338eeef512171b42081e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 16 Dec 2019 22:03:16 -0500 Subject: exfat: add debug/error messages Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 09bf3c6..c6265d5 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -76,8 +76,11 @@ static int exfat_write_sector(struct exfat_blk_dev *bd, void *buf, unsigned int lseek(bd->dev_fd, offset, SEEK_SET); bytes = write(bd->dev_fd, buf, bd->sector_size); - if (bytes != bd->sector_size) + if (bytes != bd->sector_size) { + exfat_msg(EXFAT_ERROR, + "write failed, sec_off : %u, bytes : %d\n", sec_off, bytes); return -1; + } return 0; } @@ -99,14 +102,16 @@ static int exfat_write_boot_sectors(struct exfat_blk_dev *bd, /* write main boot sector */ ret = exfat_write_sector(bd, ppbr, 0); if (ret < 0) { - ret = -1; + exfat_msg(EXFAT_ERROR, + "main boot sector write failed\n"); goto free_ppbr; } /* write backup boot sector */ ret = exfat_write_sector(bd, ppbr, 1); if (ret < 0) { - ret = -1; + exfat_msg(EXFAT_ERROR, + "main backup sector write failed\n"); goto free_ppbr; } @@ -128,8 +133,11 @@ static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, int ret; ep.eb[sec_idx - 1].signature = cpu_to_le16(0xAA55); - if (exfat_write_sector(bd, &ep, sec_idx)) + if (exfat_write_sector(bd, &ep, sec_idx)) { + exfat_msg(EXFAT_ERROR, + "extended boot sector write failed\n"); return -1; + } calc_checksum((char *) &ep, sizeof(struct expbr), false, checksum); } @@ -147,8 +155,11 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, return -1; memset(oem, 0xFF, bd->sector_size); - if (exfat_write_sector(bd, oem, OEM_SEC_NUM)) + if (exfat_write_sector(bd, oem, OEM_SEC_NUM)) { + exfat_msg(EXFAT_ERROR, + "oem sector write failed\n"); return -1; + } calc_checksum((char *)oem, bd->sector_size, false, checksum); } @@ -163,8 +174,11 @@ static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, return -1; memset(checksum_buf, checksum, bd->sector_size / sizeof(int)); - if (exfat_write_sector(bd, checksum_buf, OEM_SEC_NUM)) + if (exfat_write_sector(bd, checksum_buf, OEM_SEC_NUM)) { + exfat_msg(EXFAT_ERROR, + "checksum sector write failed\n"); return -1; + } } static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, @@ -212,22 +226,31 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, /* fat entry 0 should be media type field(0xF8) */ ret = write_fat_entry(bd->dev_fd, 0xfffffff8, 0); - if (ret) + if (ret) { + exfat_msg(EXFAT_ERROR, + "fat 0 entry write failed\n"); return ret; + } /* fat entry 1 is historical precedence(0xFFFFFFFF) */ ret = write_fat_entry(bd->dev_fd, 0xffffffff, 1); - if (ret) + if (ret) { + exfat_msg(EXFAT_ERROR, + "fat 1 entry write failed\n"); return ret; + } /* write bitmap entries */ count = EXFAT_FIRST_CLUSTER; count += round_up(finfo.bitmap_byte_len, ui->cluster_size) / ui->cluster_size; for (clu = EXFAT_FIRST_CLUSTER; clu < count; clu++) { - ret = write_fat_entry(bd->dev_fd, clu, clu * sizeof(int)); - if (ret) + ret = write_fat_entry(bd->dev_fd, clu, clu); + if (ret) { + exfat_msg(EXFAT_ERROR, + "bitmap entry write failed, clu : %d\n", clu); return ret; + } } /* write upcase table entries */ @@ -236,8 +259,11 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, finfo.ut_start_clu = clu; for (; clu < count; clu++) { ret = write_fat_entry(bd->dev_fd, clu, clu); - if (ret) + if (ret) { + exfat_msg(EXFAT_ERROR, + "upcase entry write failed, clu : %d\n", clu); return ret; + } } /* write root directory entries */ @@ -245,11 +271,15 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, finfo.root_start_clu = clu; for (; clu < count; clu++) { ret = write_fat_entry(bd->dev_fd, clu, clu); - if (ret) + if (ret) { + exfat_msg(EXFAT_ERROR, + "root entry write failed, clu : %d\n", clu); + } return ret; } finfo.used_clu_cnt = count; + exfat_msg(EXFAT_DEBUG, "Total used cluster count : %d\n", count); return ret; } @@ -258,7 +288,7 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { char *bitmap; - int i,nbytes; + int i, nbytes; bitmap = malloc(finfo.bitmap_byte_len); if (!bitmap) @@ -270,6 +300,9 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd, lseek(bd->dev_fd, finfo.bitmap_byte_off, SEEK_SET); nbytes = write(bd->dev_fd, bitmap, finfo.bitmap_byte_len); if (nbytes != finfo.bitmap_byte_len) + exfat_msg(EXFAT_ERROR, + "write failed, nbytes : %d, bitmap_len : %d\n", + nbytes, finfo.bitmap_byte_len); return -1; return 0; @@ -301,8 +334,12 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, lseek(bd->dev_fd, finfo.root_byte_off, SEEK_SET); nbytes = write(bd->dev_fd, ed, dentries_len); - if (nbytes != dentries_len) + if (nbytes != dentries_len) { + exfat_msg(EXFAT_ERROR, + "write failed, nbytes : %d, dentries_len : %d\n", + nbytes, dentries_len); return -1; + } return 0; } @@ -320,7 +357,7 @@ static inline unsigned int sector_size_bits(unsigned int size) static int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_dev *bd) { int fd, ret = -1; - unsigned long long blk_dev_size; + long long blk_dev_size; fd = open(ui->dev_name, O_RDWR); if (fd < 0) @@ -328,10 +365,14 @@ static int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_ blk_dev_size = lseek(fd, 0, SEEK_END); if (blk_dev_size <= 0) { - perror("exfat-tools\n"); + exfat_msg(EXFAT_ERROR, "invalid block device size(%s) : %lld\n", + ui->dev_name, blk_dev_size); + ret = blk_dev_size; + close(fd); goto out; } + bd->dev_fd = fd; bd->size = blk_dev_size; if (ioctl(fd, BLKSSZGET, &bd->sector_size) < 0) bd->sector_size = DEFAULT_SECTOR_SIZE; @@ -339,6 +380,12 @@ static int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_ bd->num_sectors = blk_dev_size / DEFAULT_SECTOR_SIZE; bd->num_clusters = blk_dev_size / ui->cluster_size; + exfat_msg(EXFAT_DEBUG, "Block device name : %s\n", ui->dev_name); + exfat_msg(EXFAT_DEBUG, "Block device size : %lld\n", bd->size); + exfat_msg(EXFAT_DEBUG, "Block sector size : %u\n", bd->sector_size); + exfat_msg(EXFAT_DEBUG, "Number of the sectors : %u\n", bd->num_sectors); + exfat_msg(EXFAT_DEBUG, "Number of the clusters : %u\n", bd->num_clusters); + ret = 0; bd->dev_fd = fd; out: -- cgit v1.2.3 From e6476bef3b0cbcfa249ef69616be53f5be932947 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 18 Dec 2019 21:37:37 -0500 Subject: exfat-tools: remove dump util Signed-off-by: Namjae Jeon --- Makefile.am | 2 +- configure.ac | 1 - dump/Makefile.am | 6 ------ dump/dump.c | 13 ------------- 4 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 dump/Makefile.am delete mode 100644 dump/dump.c diff --git a/Makefile.am b/Makefile.am index 4297c79..21676de 100755 --- a/Makefile.am +++ b/Makefile.am @@ -2,4 +2,4 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = lib mkfs fsck dump +SUBDIRS = lib mkfs fsck diff --git a/configure.ac b/configure.ac index fca92cf..b5ff039 100755 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,6 @@ AC_CONFIG_FILES([ lib/Makefile mkfs/Makefile fsck/Makefile - dump/Makefile ]) AC_OUTPUT diff --git a/dump/Makefile.am b/dump/Makefile.am deleted file mode 100644 index 5a9b9f5..0000000 --- a/dump/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -AM_CFLAGS = -I$(top_srcdir)/include -fno-common -dump_LDADD = $(top_builddir)/lib/libexfat.la - -sbin_PROGRAMS = dump.exfat - -dump_SOURCES = dump.c diff --git a/dump/dump.c b/dump/dump.c deleted file mode 100644 index 698487b..0000000 --- a/dump/dump.c +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2019 Namjae Jeon - */ - -#include - -#include "exfat_ondisk.h" - -int main() -{ - return 0; -} -- cgit v1.2.3 From 3a520851912e657d89579e04cc807bbba2be079c Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 19 Dec 2019 20:31:06 -0500 Subject: exfat-tools: add boot sector debug prints Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index c6265d5..6910330 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -67,6 +67,15 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, memset(ppbr->boot_code, 0, 390); ppbr->signature = cpu_to_le16(PBR_SIGNATURE); + + exfat_msg(EXFAT_DEBUG, "Volume Length(sectors) : %llu\n", cpu_to_le64(pbsx->vol_length)); + exfat_msg(EXFAT_DEBUG, "FAT Offset(sector offset) : %u\n", cpu_to_le64(pbsx->fat_offset)); + exfat_msg(EXFAT_DEBUG, "FAT Length(sectors) : %u\n", cpu_to_le32(pbsx->fat_length)); + exfat_msg(EXFAT_DEBUG, "Cluster Heap Offset (sector offset) : %u\n", cpu_to_le32(pbsx->clu_offset)); + exfat_msg(EXFAT_DEBUG, "Cluster Count (sectors) : %u\n", cpu_to_le32(pbsx->clu_count)); + exfat_msg(EXFAT_DEBUG, "Root Cluster (cluster offset) : %u\n", cpu_to_le32(pbsx->root_cluster)); + exfat_msg(EXFAT_DEBUG, "Sector Size Bits : %u\n", cpu_to_le32(pbsx->sect_size_bits)); + exfat_msg(EXFAT_DEBUG, "Sector per Cluster bits : %u\n", cpu_to_le32(pbsx->sect_per_clus_bits)); } static int exfat_write_sector(struct exfat_blk_dev *bd, void *buf, unsigned int sec_off) -- cgit v1.2.3 From 4c097f52906ef0fface8e249547e6081f23a8988 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 20 Dec 2019 04:20:30 -0500 Subject: exfat-tools: fix wrong backup boot sector write Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 9 +-------- mkfs/Makefile.am | 2 +- mkfs/mkfs.c | 48 ++++++++++++++++++++++++------------------------ 3 files changed, 26 insertions(+), 33 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 81fa695..f662125 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -14,14 +14,7 @@ /* Upcase tabel macro */ #define EXFAT_UPCASE_TABLE_SIZE (5836) -enum { - BOOT_SEC_NUM = 0, - EXBOOT_SEC_NUM, - EXBOOT_SEC8_NUM = 8, - OEM_SEC_NUM, - RESERVED_SEC_NUM, - CHECKSUM_NUM, -}; +#define EXBOOT_SEC_NUM (8) struct exfat_blk_dev { int dev_fd; diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index a1e1b43..e7520d3 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,5 +1,5 @@ AM_CFLAGS = -I$(top_srcdir)/include -fno-common -#mkfs_LDADD = $(top_builddir)/lib/libexfat.la +mkfs_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = mkfs.exfat diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 6910330..07ec680 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -94,7 +94,8 @@ static int exfat_write_sector(struct exfat_blk_dev *bd, void *buf, unsigned int } static int exfat_write_boot_sectors(struct exfat_blk_dev *bd, - struct exfat_user_input *ui, unsigned int *checksum) + struct exfat_user_input *ui, unsigned int *checksum, + unsigned sec_idx) { struct pbr *ppbr; int ret; @@ -109,21 +110,13 @@ static int exfat_write_boot_sectors(struct exfat_blk_dev *bd, exfat_setup_boot_sector(ppbr, bd, ui); /* write main boot sector */ - ret = exfat_write_sector(bd, ppbr, 0); + ret = exfat_write_sector(bd, ppbr, sec_idx); if (ret < 0) { exfat_msg(EXFAT_ERROR, "main boot sector write failed\n"); goto free_ppbr; } - /* write backup boot sector */ - ret = exfat_write_sector(bd, ppbr, 1); - if (ret < 0) { - exfat_msg(EXFAT_ERROR, - "main backup sector write failed\n"); - goto free_ppbr; - } - calc_checksum((char *)ppbr, sizeof(struct pbr), true, checksum); free_ppbr: @@ -132,13 +125,13 @@ free_ppbr: } static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, - unsigned int *checksum) + unsigned int *checksum, unsigned int sec_idx) { - int sec_idx; struct expbr ep; + int exboot_sec_num = sec_idx + EXBOOT_SEC_NUM; - memset(&ep, 0, EXBOOT_SEC8_NUM * bd->sector_size); - for (sec_idx = EXBOOT_SEC_NUM; sec_idx <= EXBOOT_SEC8_NUM; sec_idx++) { + memset(&ep, 0, EXBOOT_SEC_NUM * bd->sector_size); + for (; sec_idx <= exboot_sec_num; sec_idx++) { int ret; ep.eb[sec_idx - 1].signature = cpu_to_le16(0xAA55); @@ -155,7 +148,7 @@ static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, } static int exfat_write_oem_sector(struct exfat_blk_dev *bd, - unsigned int *checksum) + unsigned int *checksum, unsigned int sec_idx) { char *oem; @@ -164,7 +157,7 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, return -1; memset(oem, 0xFF, bd->sector_size); - if (exfat_write_sector(bd, oem, OEM_SEC_NUM)) { + if (exfat_write_sector(bd, oem, sec_idx)) { exfat_msg(EXFAT_ERROR, "oem sector write failed\n"); return -1; @@ -174,7 +167,7 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, } static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, - unsigned int checksum) + unsigned int checksum, unsigned int sec_idx) { int *checksum_buf; @@ -183,7 +176,7 @@ static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, return -1; memset(checksum_buf, checksum, bd->sector_size / sizeof(int)); - if (exfat_write_sector(bd, checksum_buf, OEM_SEC_NUM)) { + if (exfat_write_sector(bd, checksum_buf, sec_idx)) { exfat_msg(EXFAT_ERROR, "checksum sector write failed\n"); return -1; @@ -191,24 +184,26 @@ static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, } static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, - struct exfat_user_input *ui) + struct exfat_user_input *ui, unsigned int sec_idx) { int ret; unsigned int checksum; - ret = exfat_write_boot_sectors(bd, ui, &checksum); + ret = exfat_write_boot_sectors(bd, ui, &checksum, sec_idx); if (ret) return ret; - ret = exfat_write_extended_boot_sectors(bd, &checksum); + ret = exfat_write_extended_boot_sectors(bd, &checksum, ++sec_idx); if (ret) return ret; - ret = exfat_write_oem_sector(bd, &checksum); + sec_idx += EXBOOT_SEC_NUM; + + ret = exfat_write_oem_sector(bd, &checksum, sec_idx); if (ret) return ret; - ret = exfat_write_checksum_sector(bd, checksum); + ret = exfat_write_checksum_sector(bd, checksum, ++sec_idx); return ret; } @@ -515,7 +510,12 @@ int main(int argc, char *argv[]) exfat_build_mkfs_info(&bd, &ui); - ret = exfat_create_volume_boot_record(&bd, &ui); + ret = exfat_create_volume_boot_record(&bd, &ui, 0); + if (ret) + goto out; + + /* backup boot record */ + ret = exfat_create_volume_boot_record(&bd, &ui, 13); if (ret) goto out; -- cgit v1.2.3 From de895b1707a810b0d7f6ed12f993b7d4e57a950e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 21 Dec 2019 20:43:52 +0900 Subject: exfat: reorganize backup boot sector write Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 10 +++++- mkfs/mkfs.c | 99 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 70 insertions(+), 39 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index f662125..098e895 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -14,7 +14,15 @@ /* Upcase tabel macro */ #define EXFAT_UPCASE_TABLE_SIZE (5836) -#define EXBOOT_SEC_NUM (8) +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; diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 07ec680..9c03ff9 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -93,12 +93,16 @@ static int exfat_write_sector(struct exfat_blk_dev *bd, void *buf, unsigned int return 0; } -static int exfat_write_boot_sectors(struct exfat_blk_dev *bd, +static int exfat_write_boot_sector(struct exfat_blk_dev *bd, struct exfat_user_input *ui, unsigned int *checksum, - unsigned sec_idx) + bool is_backup) { struct pbr *ppbr; - int ret; + unsigned int sec_idx = BOOT_SEC_IDX; + int ret = 0; + + if (is_backup) + sec_idx += BACKUP_BOOT_SEC_IDX; ppbr = malloc(sizeof(struct pbr)); if (!ppbr) { @@ -114,6 +118,7 @@ static int exfat_write_boot_sectors(struct exfat_blk_dev *bd, if (ret < 0) { exfat_msg(EXFAT_ERROR, "main boot sector write failed\n"); + ret = -1; goto free_ppbr; } @@ -121,19 +126,23 @@ static int exfat_write_boot_sectors(struct exfat_blk_dev *bd, free_ppbr: free(ppbr); - return 0; + return ret; } static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, - unsigned int *checksum, unsigned int sec_idx) + unsigned int *checksum, bool is_backup) { struct expbr ep; + unsigned int sec_idx = EXBOOT_SEC_IDX; int exboot_sec_num = sec_idx + EXBOOT_SEC_NUM; + if (is_backup) { + sec_idx += BACKUP_BOOT_SEC_IDX; + exboot_sec_num += BACKUP_BOOT_SEC_IDX; + } + memset(&ep, 0, EXBOOT_SEC_NUM * bd->sector_size); for (; sec_idx <= exboot_sec_num; sec_idx++) { - int ret; - ep.eb[sec_idx - 1].signature = cpu_to_le16(0xAA55); if (exfat_write_sector(bd, &ep, sec_idx)) { exfat_msg(EXFAT_ERROR, @@ -144,67 +153,81 @@ static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, calc_checksum((char *) &ep, sizeof(struct expbr), false, checksum); } +out: return 0; } static int exfat_write_oem_sector(struct exfat_blk_dev *bd, - unsigned int *checksum, unsigned int sec_idx) + 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) + if (!oem) return -1; + if (is_backup) + sec_idx += BACKUP_BOOT_SEC_IDX; + memset(oem, 0xFF, bd->sector_size); - if (exfat_write_sector(bd, oem, sec_idx)) { - exfat_msg(EXFAT_ERROR, - "oem sector write failed\n"); - return -1; + ret = exfat_write_sector(bd, oem, sec_idx); + if (ret) { + exfat_msg(EXFAT_ERROR, "oem sector write failed\n"); + ret = -1; + goto free_oem; } calc_checksum((char *)oem, bd->sector_size, false, checksum); + +free_oem: + free(oem); + return ret; } static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, - unsigned int checksum, unsigned int sec_idx) + unsigned int checksum, bool is_backup) { - int *checksum_buf; + char *checksum_buf, ret = 0; + unsigned int sec_idx = CHECKSUM_SEC_IDX; checksum_buf = malloc(bd->sector_size); - if (checksum_buf) + if (!checksum_buf) return -1; + if (is_backup) + sec_idx += BACKUP_BOOT_SEC_IDX; + memset(checksum_buf, checksum, bd->sector_size / sizeof(int)); - if (exfat_write_sector(bd, checksum_buf, sec_idx)) { - exfat_msg(EXFAT_ERROR, - "checksum sector write failed\n"); - return -1; + ret = exfat_write_sector(bd, checksum_buf, sec_idx); + if (ret) { + exfat_msg(EXFAT_ERROR, "checksum sector write failed\n"); + goto free; } + +free: + free(checksum_buf); + return ret; } static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, - struct exfat_user_input *ui, unsigned int sec_idx) + struct exfat_user_input *ui, bool is_backup) { + unsigned int checksum = 0, sec_idx = 0; int ret; - unsigned int checksum; - ret = exfat_write_boot_sectors(bd, ui, &checksum, sec_idx); + ret = exfat_write_boot_sector(bd, ui, &checksum, is_backup); if (ret) - return ret; - - ret = exfat_write_extended_boot_sectors(bd, &checksum, ++sec_idx); + return -1; + ret = exfat_write_extended_boot_sectors(bd, &checksum, is_backup); if (ret) - return ret; - - sec_idx += EXBOOT_SEC_NUM; - - ret = exfat_write_oem_sector(bd, &checksum, sec_idx); + return -1; + ret = exfat_write_oem_sector(bd, &checksum, is_backup); if (ret) - return ret; + return -1; - ret = exfat_write_checksum_sector(bd, checksum, ++sec_idx); - return ret; + return exfat_write_checksum_sector(bd, checksum, is_backup); } static int write_fat_entry(int fd, unsigned int entry, @@ -298,8 +321,8 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd, if (!bitmap) return -1; - for (i = 0; i < finfo.used_clu_cnt; i++) - exfat_set_bit(bd, bitmap, i); +// for (i = 0; i < finfo.used_clu_cnt; i++) +// exfat_set_bit(bd, bitmap, i); lseek(bd->dev_fd, finfo.bitmap_byte_off, SEEK_SET); nbytes = write(bd->dev_fd, bitmap, finfo.bitmap_byte_len); @@ -514,8 +537,8 @@ int main(int argc, char *argv[]) if (ret) goto out; - /* backup boot record */ - ret = exfat_create_volume_boot_record(&bd, &ui, 13); + /* backup sector */ + ret = exfat_create_volume_boot_record(&bd, &ui, 1); if (ret) goto out; -- cgit v1.2.3 From 6b38a05b32751ae6abd7972be37569083fb0e8c7 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 22 Dec 2019 10:15:54 +0900 Subject: exfat-tools: build error Signed-off-by: Namjae Jeon --- fsck/Makefile.am | 4 ++-- include/exfat_tools.h | 2 +- include/mkfs.h | 2 +- mkfs/Makefile.am | 4 ++-- mkfs/mkfs.c | 6 ++++-- mkfs/upcase.c | 9 +++++++++ 6 files changed, 19 insertions(+), 8 deletions(-) diff --git a/fsck/Makefile.am b/fsck/Makefile.am index 78df08c..6397dbe 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = -I$(top_srcdir)/include -fno-common -fsck_LDADD = $(top_builddir)/lib/libexfat.la +fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = fsck.exfat -fsck_SOURCES = fsck.c +fsck_exfat_SOURCES = fsck.c diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 098e895..0983e36 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -49,7 +49,7 @@ void exfat_clear_bit(struct exfat_blk_dev *bd, char *bitmap, * Exfat Print */ -unsigned int print_level; +static unsigned int print_level; #define EXFAT_ERROR (0) #define EXFAT_DEBUG (1) diff --git a/include/mkfs.h b/include/mkfs.h index 458ae4f..30bbd68 100644 --- a/include/mkfs.h +++ b/include/mkfs.h @@ -27,7 +27,7 @@ struct exfat_mkfs_info { int root_start_clu; }; -struct exfat_mkfs_info finfo; +extern struct exfat_mkfs_info finfo; int exfat_create_upcase_table(struct exfat_blk_dev *bd, struct exfat_user_input *ui); diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index e7520d3..61b80b8 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = -I$(top_srcdir)/include -fno-common -mkfs_LDADD = $(top_builddir)/lib/libexfat.la +mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = mkfs.exfat -mkfs_SOURCES = mkfs.c upcase.c +mkfs_exfat_SOURCES = mkfs.c upcase.c diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 9c03ff9..c66dc6d 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -19,6 +19,8 @@ #include "exfat_tools.h" #include "mkfs.h" +struct exfat_mkfs_info finfo; + static void calc_checksum(char *sector, unsigned short size, bool is_boot_sec, unsigned int *checksum) { @@ -321,8 +323,8 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd, if (!bitmap) return -1; -// for (i = 0; i < finfo.used_clu_cnt; i++) -// exfat_set_bit(bd, bitmap, i); + for (i = 0; i < finfo.used_clu_cnt; i++) + exfat_set_bit(bd, bitmap, i); lseek(bd->dev_fd, finfo.bitmap_byte_off, SEEK_SET); nbytes = write(bd->dev_fd, bitmap, finfo.bitmap_byte_len); diff --git a/mkfs/upcase.c b/mkfs/upcase.c index eacfcef..230d975 100644 --- a/mkfs/upcase.c +++ b/mkfs/upcase.c @@ -3,6 +3,15 @@ * Copyright (C) 2019 Namjae Jeon */ +#include +#include +#include +#include + +#include "exfat_ondisk.h" +#include "exfat_tools.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, -- cgit v1.2.3 From 4fb5c49f839a0c4c41084c6431a58b955eab3e47 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 22 Dec 2019 15:03:06 +0900 Subject: exfat-tools: add missing return Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index c66dc6d..e6312c2 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -221,13 +221,13 @@ static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, ret = exfat_write_boot_sector(bd, ui, &checksum, is_backup); if (ret) - return -1; + return ret; ret = exfat_write_extended_boot_sectors(bd, &checksum, is_backup); if (ret) - return -1; + return ret; ret = exfat_write_oem_sector(bd, &checksum, is_backup); if (ret) - return -1; + return ret; return exfat_write_checksum_sector(bd, checksum, is_backup); } @@ -245,6 +245,8 @@ static int write_fat_entry(int fd, unsigned int entry, offset, entry); return -1; } + + return 0; } static int exfat_create_fat_table(struct exfat_blk_dev *bd, -- cgit v1.2.3 From c2ad1d66bf1525454756e8797b22284476f98685 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 22 Dec 2019 15:54:11 +0900 Subject: exfat-tools: fix wrong root entry calculation Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index e6312c2..658212a 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -252,8 +252,7 @@ static int write_fat_entry(int fd, unsigned int entry, static int exfat_create_fat_table(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - int ret, clu, clu_cnt, bitmap_clu_cnt, ut_cnt, root_cnt; - int count; + int ret, clu, count; /* fat entry 0 should be media type field(0xF8) */ ret = write_fat_entry(bd->dev_fd, 0xfffffff8, 0); @@ -298,7 +297,7 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, } /* write root directory entries */ - count += finfo.root_byte_len / ui->cluster_size; + count += round_up(finfo.root_byte_len, ui->cluster_size) / ui->cluster_size; finfo.root_start_clu = clu; for (; clu < count; clu++) { ret = write_fat_entry(bd->dev_fd, clu, clu); -- cgit v1.2.3 From b915777d4dfa2b055a15e826994c5df7fd1e9f20 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 22 Dec 2019 16:06:40 +0900 Subject: exfat-tools: add wrong brace location Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 658212a..cce1168 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -304,8 +304,8 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, if (ret) { exfat_msg(EXFAT_ERROR, "root entry write failed, clu : %d\n", clu); - } return ret; + } } finfo.used_clu_cnt = count; @@ -329,11 +329,12 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd, lseek(bd->dev_fd, finfo.bitmap_byte_off, SEEK_SET); nbytes = write(bd->dev_fd, bitmap, finfo.bitmap_byte_len); - if (nbytes != finfo.bitmap_byte_len) + if (nbytes != finfo.bitmap_byte_len) { exfat_msg(EXFAT_ERROR, "write failed, nbytes : %d, bitmap_len : %d\n", nbytes, finfo.bitmap_byte_len); return -1; + } return 0; } -- cgit v1.2.3 From f54dae56792cfb3807076f6f6450787e879a17b0 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 22 Dec 2019 16:10:21 +0900 Subject: exfat-tools: add debug prints Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index cce1168..d8bfe73 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -218,6 +218,8 @@ static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, { unsigned int checksum = 0, sec_idx = 0; int ret; + + exfat_msg(EXFAT_DEBUG, "Create Volume Boot Record\n"); ret = exfat_write_boot_sector(bd, ui, &checksum, is_backup); if (ret) @@ -254,6 +256,8 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, { int ret, clu, count; + exfat_msg(EXFAT_DEBUG, "Create FAT Table\n"); + /* fat entry 0 should be media type field(0xF8) */ ret = write_fat_entry(bd->dev_fd, 0xfffffff8, 0); if (ret) { @@ -320,6 +324,8 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd, char *bitmap; int i, nbytes; + exfat_msg(EXFAT_DEBUG, "Create Allocation Bitmap\n"); + bitmap = malloc(finfo.bitmap_byte_len); if (!bitmap) return -1; @@ -346,6 +352,8 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, int dentries_len = sizeof(struct exfat_dentry) * 3; int nbytes; + exfat_msg(EXFAT_DEBUG, "Create Root Directory entry : %u\n"); + /* Set volume label entry */ ed[0].type = EXFAT_VOLUME; strcpy(ed[0].vol_label, "EXFAT"); -- cgit v1.2.3 From c08c5dd413298f49b50d0f99bba9999ba1efc32f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 22 Dec 2019 16:31:21 +0900 Subject: exfat-tools: fix segfault error Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index d8bfe73..53657d4 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -134,25 +134,23 @@ free_ppbr: static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, unsigned int *checksum, bool is_backup) { - struct expbr ep; + struct exbs eb; + int i; unsigned int sec_idx = EXBOOT_SEC_IDX; - int exboot_sec_num = sec_idx + EXBOOT_SEC_NUM; - if (is_backup) { + if (is_backup) sec_idx += BACKUP_BOOT_SEC_IDX; - exboot_sec_num += BACKUP_BOOT_SEC_IDX; - } - memset(&ep, 0, EXBOOT_SEC_NUM * bd->sector_size); - for (; sec_idx <= exboot_sec_num; sec_idx++) { - ep.eb[sec_idx - 1].signature = cpu_to_le16(0xAA55); - if (exfat_write_sector(bd, &ep, sec_idx)) { + memset(&eb, 0, sizeof(struct exbs)); + eb.signature = cpu_to_le16(0xAA55); + for (i = 0; i < EXBOOT_SEC_NUM; i++) { + if (exfat_write_sector(bd, &eb, sec_idx++)) { exfat_msg(EXFAT_ERROR, "extended boot sector write failed\n"); return -1; } - calc_checksum((char *) &ep, sizeof(struct expbr), false, checksum); + calc_checksum((char *) &eb, sizeof(struct exbs), false, checksum); } out: @@ -352,7 +350,7 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, int dentries_len = sizeof(struct exfat_dentry) * 3; int nbytes; - exfat_msg(EXFAT_DEBUG, "Create Root Directory entry : %u\n"); + exfat_msg(EXFAT_DEBUG, "Create Root Directory entry\n"); /* Set volume label entry */ ed[0].type = EXFAT_VOLUME; -- cgit v1.2.3 From 5e65c7d37f2ef79fb014da319138d60b3d835f10 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 22 Dec 2019 22:57:19 +0900 Subject: exfat-tools: add full format support Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 3 +++ mkfs/mkfs.c | 26 +++++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 0983e36..5e81e90 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -5,6 +5,8 @@ #ifndef _EXFAT_TOOLS_H +#include + #define EXFAT_MIN_NUM_SEC_VOL (2048) #define EXFAT_MAX_NUM_SEC_VOL ((2 << 64) - 1) @@ -37,6 +39,7 @@ struct exfat_user_input { char dev_name[255]; unsigned int cluster_size; unsigned int sec_per_clu; + bool quick; }; void exfat_set_bit(struct exfat_blk_dev *bd, char *bitmap, diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 53657d4..94a033f 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -432,10 +432,11 @@ out: static void usage(void) { fprintf(stderr, "Usage: mkfs.exfat\n"); - fprintf(stderr, "\t-c | --cluster-size\n"); - fprintf(stderr, "\t-V | --version\n"); - fprintf(stderr, "\t-v | --verbose\n"); - fprintf(stderr, "\t-h | --help\n"); + fprintf(stderr, "\t-c=size | --cluster-size=size Set cluster size\n"); + fprintf(stderr, "\t-f | --full-format Full Format\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); } @@ -462,6 +463,7 @@ static void init_user_input(struct exfat_user_input *ui) * according to device size */ ui->cluster_size = 128 * 1024; + ui->quick = true; } static int verify_user_input(struct exfat_blk_dev *bd, @@ -493,6 +495,11 @@ static void exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.root_byte_len = sizeof(struct exfat_dentry) * 3; } +static int exfat_zero_out_disk(struct exfat_blk_dev *bd) +{ + return 0; +} + int main(int argc, char *argv[]) { int c; @@ -504,7 +511,7 @@ int main(int argc, char *argv[]) init_user_input(&ui); opterr = 0; - while ((c = getopt_long(argc, argv, "c:Vvh", opts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "c:f:Vvh", opts, NULL)) != EOF) switch (c) { case 'c': ui.cluster_size = atoi(optarg); @@ -515,6 +522,9 @@ int main(int argc, char *argv[]) goto out; } break; + case 'f': + ui.quick = false; + break; case 'V': show_version(); break; @@ -541,6 +551,12 @@ int main(int argc, char *argv[]) if (ret < 0) goto out; + if (ui.quick == false) { + ret = exfat_zero_out_disk(&bd); + if (ret) + goto out; + } + exfat_build_mkfs_info(&bd, &ui); ret = exfat_create_volume_boot_record(&bd, &ui, 0); -- cgit v1.2.3 From a1e876e6284a3d246890289f8a46bb9c8a128ae9 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 22 Dec 2019 23:51:39 -0500 Subject: exfat-tools: fix wrong clu value Signed-off-by: Namjae Jeon --- include/mkfs.h | 28 ++++++++++----------- mkfs/mkfs.c | 77 +++++++++++++++++++++++++++++----------------------------- 2 files changed, 53 insertions(+), 52 deletions(-) diff --git a/include/mkfs.h b/include/mkfs.h index 30bbd68..62a6768 100644 --- a/include/mkfs.h +++ b/include/mkfs.h @@ -11,20 +11,20 @@ #define MAX_CLUSTER_SIZE (32*1024*1024) struct exfat_mkfs_info { - int total_clu_cnt; - int used_clu_cnt; - int fat_byte_off; - int fat_byte_len; - int clu_byte_off; - int bitmap_byte_off; - int bitmap_byte_len; - int ut_byte_off; - int ut_start_clu; - int ut_clus_off; - int ut_byte_len; - int root_byte_off; - int root_byte_len; - int root_start_clu; + 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; }; extern struct exfat_mkfs_info finfo; diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 94a033f..14cb0c1 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -232,23 +232,45 @@ static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, return exfat_write_checksum_sector(bd, checksum, is_backup); } -static int write_fat_entry(int fd, unsigned int entry, +static int write_fat_entry(int fd, unsigned int clu, unsigned long long offset) { int nbyte; lseek(fd, finfo.fat_byte_off + (offset * sizeof(int)), SEEK_SET); - nbyte = write(fd, (char *) &entry, sizeof(unsigned int)); + nbyte = write(fd, (char *) &clu, sizeof(unsigned int)); if (nbyte != sizeof(int)) { exfat_msg(EXFAT_ERROR, - "write failed, offset : %llu, entry : %x\n", - offset, entry); + "write failed, offset : %llu, clu : %x\n", + offset, clu); return -1; } return 0; } +static int write_fat_entris(struct exfat_user_input *ui, int fd, + unsigned int clu, unsigned int length) +{ + int ret; + unsigned int count; + + count = clu + round_up(finfo.bitmap_byte_len, ui->cluster_size) / + ui->cluster_size; + + for (; clu < count; clu++) { + ret = write_fat_entry(fd, clu + 1, clu); + if (ret) + return ret; + } + + ret = write_fat_entry(fd, 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) { @@ -273,45 +295,24 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, } /* write bitmap entries */ - count = EXFAT_FIRST_CLUSTER; - count += round_up(finfo.bitmap_byte_len, ui->cluster_size) / - ui->cluster_size; - for (clu = EXFAT_FIRST_CLUSTER; clu < count; clu++) { - ret = write_fat_entry(bd->dev_fd, clu, clu); - if (ret) { - exfat_msg(EXFAT_ERROR, - "bitmap entry write failed, clu : %d\n", clu); - return ret; - } - } + clu = write_fat_entris(ui, bd->dev_fd, EXFAT_FIRST_CLUSTER, + finfo.bitmap_byte_len); + if (clu < 0) + return ret; /* write upcase table entries */ - count += round_up(finfo.ut_byte_len, ui->cluster_size) / - ui->cluster_size; - finfo.ut_start_clu = clu; - for (; clu < count; clu++) { - ret = write_fat_entry(bd->dev_fd, clu, clu); - if (ret) { - exfat_msg(EXFAT_ERROR, - "upcase entry write failed, clu : %d\n", clu); - return ret; - } - } + clu = write_fat_entris(ui, bd->dev_fd, clu, finfo.ut_byte_len); + if (clu < 0) + return ret; + /* write root directory entries */ - count += round_up(finfo.root_byte_len, ui->cluster_size) / ui->cluster_size; - finfo.root_start_clu = clu; - for (; clu < count; clu++) { - ret = write_fat_entry(bd->dev_fd, clu, clu); - if (ret) { - exfat_msg(EXFAT_ERROR, - "root entry write failed, clu : %d\n", clu); - return ret; - } - } + clu = write_fat_entris(ui, bd->dev_fd, clu, finfo.root_byte_len); + if (clu < 0) + return ret; - finfo.used_clu_cnt = count; - exfat_msg(EXFAT_DEBUG, "Total used cluster count : %d\n", count); + finfo.used_clu_cnt = clu; + exfat_msg(EXFAT_DEBUG, "Total used cluster count : %d\n", finfo.used_clu_cnt); return ret; } -- cgit v1.2.3 From 7279b0c25378aa0574f2d484b820573ce7c92d93 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 23 Dec 2019 02:46:04 -0500 Subject: exfat-tools: fix wrong calculations Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 14cb0c1..87f9a38 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -56,7 +56,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, 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_byte_off / ui->cluster_size); + pbsx->root_cluster = cpu_to_le32(finfo.root_start_clu); pbsx->vol_serial = 1234; pbsx->vol_flags = 0; pbsx->sect_size_bits = bd->sector_size_bits; @@ -258,7 +258,7 @@ static int write_fat_entris(struct exfat_user_input *ui, int fd, count = clu + round_up(finfo.bitmap_byte_len, ui->cluster_size) / ui->cluster_size; - for (; clu < count; clu++) { + for (; clu < count - 1; clu++) { ret = write_fat_entry(fd, clu + 1, clu); if (ret) return ret; @@ -301,17 +301,16 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, return ret; /* write upcase table entries */ - clu = write_fat_entris(ui, bd->dev_fd, clu, finfo.ut_byte_len); + clu = write_fat_entris(ui, bd->dev_fd, clu + 1, finfo.ut_byte_len); if (clu < 0) return ret; - /* write root directory entries */ - clu = write_fat_entris(ui, bd->dev_fd, clu, finfo.root_byte_len); + clu = write_fat_entris(ui, bd->dev_fd, clu + 1, finfo.root_byte_len); if (clu < 0) return ret; - finfo.used_clu_cnt = clu; + finfo.used_clu_cnt = clu + 1; exfat_msg(EXFAT_DEBUG, "Total used cluster count : %d\n", finfo.used_clu_cnt); return ret; @@ -486,13 +485,13 @@ static void exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len, DEFAULT_CLUSTER_SIZE); finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; - finfo.bitmap_byte_off = EXFAT_REVERVED_CLUSTERS * ui->cluster_size; + finfo.bitmap_byte_off = finfo.clu_byte_off; finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8; + finfo.ut_start_clu = round_up(EXFAT_REVERVED_CLUSTERS * ui->cluster_size + finfo.bitmap_byte_len, ui->cluster_size) / ui->cluster_size; finfo.ut_byte_off = round_up(finfo.bitmap_byte_off + finfo.bitmap_byte_len, ui->cluster_size); - finfo.ut_start_clu = finfo.ut_byte_off / ui->cluster_size; finfo.ut_byte_len = EXFAT_UPCASE_TABLE_SIZE; + finfo.root_start_clu = round_up(finfo.ut_start_clu * ui->cluster_size + finfo.ut_byte_len, ui->cluster_size) / ui->cluster_size; finfo.root_byte_off = round_up(finfo.ut_byte_off + finfo.ut_byte_len, ui->cluster_size); - finfo.root_start_clu = finfo.root_byte_off / ui->cluster_size; finfo.root_byte_len = sizeof(struct exfat_dentry) * 3; } -- cgit v1.2.3 From 5b758a2ffd6b6ce65eb70937c885fb8efee2c21e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 23 Dec 2019 03:17:51 -0500 Subject: exfat-tools: reorganize checksum codes Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 87f9a38..8624ff2 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -142,7 +142,7 @@ static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, sec_idx += BACKUP_BOOT_SEC_IDX; memset(&eb, 0, sizeof(struct exbs)); - eb.signature = cpu_to_le16(0xAA55); + eb.signature = cpu_to_le16(PBR_SIGNATURE); for (i = 0; i < EXBOOT_SEC_NUM; i++) { if (exfat_write_sector(bd, &eb, sec_idx++)) { exfat_msg(EXFAT_ERROR, @@ -178,6 +178,17 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, ret = -1; goto free_oem; } + + calc_checksum((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_msg(EXFAT_ERROR, "reserved sector write failed\n"); + ret = -1; + goto free_oem; + } calc_checksum((char *)oem, bd->sector_size, false, checksum); @@ -189,7 +200,8 @@ free_oem: static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, unsigned int checksum, bool is_backup) { - char *checksum_buf, ret = 0; + __le32 *checksum_buf; + int i, ret = 0; unsigned int sec_idx = CHECKSUM_SEC_IDX; checksum_buf = malloc(bd->sector_size); @@ -199,7 +211,9 @@ static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, if (is_backup) sec_idx += BACKUP_BOOT_SEC_IDX; - memset(checksum_buf, checksum, bd->sector_size / sizeof(int)); + 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_msg(EXFAT_ERROR, "checksum sector write failed\n"); @@ -214,7 +228,7 @@ free: static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, struct exfat_user_input *ui, bool is_backup) { - unsigned int checksum = 0, sec_idx = 0; + unsigned int checksum = 0; int ret; exfat_msg(EXFAT_DEBUG, "Create Volume Boot Record\n"); -- cgit v1.2.3 From 91455f477797e38a12e7db5542b171d5e5e91d4b Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 23 Dec 2019 20:54:36 +0900 Subject: exfat-tools: fix checksum error Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 8624ff2..886d6e6 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -21,7 +21,7 @@ struct exfat_mkfs_info finfo; -static void calc_checksum(char *sector, unsigned short size, +static void boot_calc_checksum(unsigned char *sector, unsigned short size, bool is_boot_sec, unsigned int *checksum) { unsigned int index; @@ -32,7 +32,7 @@ static void calc_checksum(char *sector, unsigned short size, ((index == 106) || (index == 107) || (index == 112))) continue; *checksum = ((*checksum & 1) ? 0x80000000 : 0) + - (*checksum >> 1) + (unsigned int)sector[index]; + (*checksum >> 1) + sector[index]; } } @@ -124,7 +124,7 @@ static int exfat_write_boot_sector(struct exfat_blk_dev *bd, goto free_ppbr; } - calc_checksum((char *)ppbr, sizeof(struct pbr), true, checksum); + boot_calc_checksum((unsigned char *)ppbr, sizeof(struct pbr), true, checksum); free_ppbr: free(ppbr); @@ -150,7 +150,7 @@ static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, return -1; } - calc_checksum((char *) &eb, sizeof(struct exbs), false, checksum); + boot_calc_checksum((unsigned char *) &eb, sizeof(struct exbs), false, checksum); } out: @@ -179,7 +179,7 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, goto free_oem; } - calc_checksum((char *)oem, bd->sector_size, false, checksum); + boot_calc_checksum((unsigned char *)oem, bd->sector_size, false, checksum); /* Zero out reserved sector */ memset(oem, 0, bd->sector_size); @@ -190,7 +190,7 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, goto free_oem; } - calc_checksum((char *)oem, bd->sector_size, false, checksum); + boot_calc_checksum((unsigned char *)oem, bd->sector_size, false, checksum); free_oem: free(oem); -- cgit v1.2.3 From 339d7047ffc8f5a679d47308ae97462402e33c41 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 23 Dec 2019 22:22:23 +0900 Subject: exfat-tools: add volume label option Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 1 + mkfs/mkfs.c | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 5e81e90..b706e08 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -40,6 +40,7 @@ struct exfat_user_input { unsigned int cluster_size; unsigned int sec_per_clu; bool quick; + char volume_label[22]; }; void exfat_set_bit(struct exfat_blk_dev *bd, char *bitmap, diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 886d6e6..1719ac8 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -362,14 +362,17 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, { struct exfat_dentry ed[3]; int dentries_len = sizeof(struct exfat_dentry) * 3; - int nbytes; + int nbytes, vol_len; exfat_msg(EXFAT_DEBUG, "Create Root Directory entry\n"); /* Set volume label entry */ - ed[0].type = EXFAT_VOLUME; - strcpy(ed[0].vol_label, "EXFAT"); - ed[0].vol_char_cnt = strlen("EXFAT"); + vol_len = strlen(ui->volume_label); + if (vol_len) { + ed[0].type = EXFAT_VOLUME; + strcpy(ed[0].vol_label, ui->volume_label); + ed[0].vol_char_cnt = strlen("EXFAT"); + } /* Set bitmap entry */ ed[1].type = EXFAT_BITMAP; @@ -446,11 +449,12 @@ out: static void usage(void) { fprintf(stderr, "Usage: mkfs.exfat\n"); - fprintf(stderr, "\t-c=size | --cluster-size=size Set cluster size\n"); - fprintf(stderr, "\t-f | --full-format Full Format\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"); + fprintf(stderr, "\t-l=string | --volume-label=string Set volume label\n"); + fprintf(stderr, "\t-c=size | --cluster-size=size Set cluster size\n"); + fprintf(stderr, "\t-f | --full-format Full format\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); } @@ -462,7 +466,9 @@ static void show_version(void) } static struct option opts[] = { + {"volme-label", required_argument, NULL, 'l' }, {"cluster-size", required_argument, NULL, 'c' }, + {"full-format", no_argument, NULL, 'f' }, {"version", no_argument, NULL, 'V' }, {"help", no_argument, NULL, 'h' }, {"?", no_argument, NULL, '?' }, @@ -525,8 +531,10 @@ int main(int argc, char *argv[]) init_user_input(&ui); opterr = 0; - while ((c = getopt_long(argc, argv, "c:f:Vvh", opts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "l:c:f:Vvh", opts, NULL)) != EOF) switch (c) { + case 'l': + break; case 'c': ui.cluster_size = atoi(optarg); if (ui.cluster_size > MAX_CLUSTER_SIZE) { -- cgit v1.2.3 From 4939bfea5e4b1b00fe8847fcd67e6f2f59d1b3ab Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 23 Dec 2019 22:37:50 +0900 Subject: exfat-tools: add math library Signed-off-by: Namjae Jeon --- mkfs/Makefile.am | 1 + mkfs/mkfs.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index 61b80b8..535ea9b 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,4 +1,5 @@ AM_CFLAGS = -I$(top_srcdir)/include -fno-common +LIBS = -lm mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = mkfs.exfat diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 1719ac8..7cc16c0 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "exfat_ondisk.h" #include "exfat_tools.h" @@ -60,7 +61,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, pbsx->vol_serial = 1234; pbsx->vol_flags = 0; pbsx->sect_size_bits = bd->sector_size_bits; - pbsx->sect_per_clus_bits = ui->sec_per_clu / 32; + pbsx->sect_per_clus_bits = log2(ui->sec_per_clu); pbsx->num_fats = 1; /* fs_version[0] : minor and fs_version[1] : major */ pbsx->fs_version[0] = 0; -- cgit v1.2.3 From a6859c0df31561399c5a89ba202c72d96aad735b Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 24 Dec 2019 00:33:55 -0500 Subject: exfat-tools: verify label string Signed-off-by: Namjae Jeon --- include/exfat_ondisk.h | 1 + include/exfat_tools.h | 3 ++- lib/libexfat.c | 8 ++++++++ mkfs/mkfs.c | 39 +++++++++++++++++++++++++++++++++------ 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index 61293b4..e9c2e1d 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -139,6 +139,7 @@ struct expbr { struct exbs eb[8]; }; +#define VOLUME_LABEL_MAX_LEN 22 struct exfat_dentry { __u8 type; union { diff --git a/include/exfat_tools.h b/include/exfat_tools.h index b706e08..320fd48 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -6,6 +6,7 @@ #ifndef _EXFAT_TOOLS_H #include +#include #define EXFAT_MIN_NUM_SEC_VOL (2048) #define EXFAT_MAX_NUM_SEC_VOL ((2 << 64) - 1) @@ -45,9 +46,9 @@ struct exfat_user_input { 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); /* * Exfat Print diff --git a/lib/libexfat.c b/lib/libexfat.c index 7be3448..bea3720 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -62,3 +62,11 @@ void exfat_clear_bit(struct exfat_blk_dev *bd, char *bitmap, 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 == '\\'); +} diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 7cc16c0..c6197be 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -368,12 +368,9 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, exfat_msg(EXFAT_DEBUG, "Create Root Directory entry\n"); /* Set volume label entry */ - vol_len = strlen(ui->volume_label); - if (vol_len) { - ed[0].type = EXFAT_VOLUME; - strcpy(ed[0].vol_label, ui->volume_label); - ed[0].vol_char_cnt = strlen("EXFAT"); - } + ed[0].type = EXFAT_VOLUME; + strcpy(ed[0].vol_label, ui->volume_label); + ed[0].vol_char_cnt = strlen("EXFAT"); /* Set bitmap entry */ ed[1].type = EXFAT_BITMAP; @@ -535,7 +532,37 @@ int main(int argc, char *argv[]) while ((c = getopt_long(argc, argv, "l:c:f:Vvh", opts, NULL)) != EOF) switch (c) { case 'l': + { + int i; + size_t mbslen; + wchar_t label[22]; + + mbslen = mbstowcs(NULL, optarg, 0); + printf("mbslen : %zd\n", mbslen); + if (mbslen == (size_t) -1) { + exfat_msg(EXFAT_ERROR, "mbstowcs return error(%d)\n", errno); + goto out; + } + + if (mbslen > VOLUME_LABEL_MAX_LEN - 1) { + exfat_msg(EXFAT_ERROR, "Volume Label is too longer(MAX 21 characters)\n"); + goto out; + } + + if (mbstowcs(label, optarg, mbslen + 1) == (size_t) -1) { + exfat_msg(EXFAT_ERROR, "mbstowcs return error(%d)\n", errno); + goto out; + } + + for (i = 0; i < VOLUME_LABEL_MAX_LEN; i++) { + if (exfat_bad_char(label[i])) { + exfat_msg(EXFAT_ERROR, "bad char error(%x)\n", label[i]); + goto out; + } + } + break; + } case 'c': ui.cluster_size = atoi(optarg); if (ui.cluster_size > MAX_CLUSTER_SIZE) { -- cgit v1.2.3 From 7fa1862ee3dbafef4eb3f1a4eb27ff40ec4d74dd Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 29 Dec 2019 18:36:39 +0900 Subject: exfat-tools: check max number of clusters Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 2 ++ mkfs/mkfs.c | 29 +++++++++++++---------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 320fd48..27e80a0 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -11,6 +11,8 @@ #define EXFAT_MIN_NUM_SEC_VOL (2048) #define EXFAT_MAX_NUM_SEC_VOL ((2 << 64) - 1) +#define EXFAT_MAX_NUM_CLUSTER (0xFFFFFFF5) + #define __round_mask(x, y) ((__typeof__(x))((y)-1)) #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index c6197be..33c5689 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -61,7 +61,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, pbsx->vol_serial = 1234; pbsx->vol_flags = 0; pbsx->sect_size_bits = bd->sector_size_bits; - pbsx->sect_per_clus_bits = log2(ui->sec_per_clu); + pbsx->sect_per_clus_bits = log2(ui->cluster_size / bd->sector_size); pbsx->num_fats = 1; /* fs_version[0] : minor and fs_version[1] : major */ pbsx->fs_version[0] = 0; @@ -484,17 +484,10 @@ static void init_user_input(struct exfat_user_input *ui) ui->quick = true; } -static int verify_user_input(struct exfat_blk_dev *bd, +static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - ui->sec_per_clu = ui->cluster_size / bd->sector_size; - return 0; -} - -static void exfat_build_mkfs_info(struct exfat_blk_dev *bd, - struct exfat_user_input *ui) -{ - if (DEFAULT_CLUSTER_SIZE < ui->sec_per_clu) + if (DEFAULT_CLUSTER_SIZE < ui->cluster_size) finfo.fat_byte_off = ui->cluster_size; else finfo.fat_byte_off = DEFAULT_CLUSTER_SIZE; @@ -503,6 +496,11 @@ static void exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len, DEFAULT_CLUSTER_SIZE); finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; + if (finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) { + exfat_msg(EXFAT_ERROR, "cluster size is too small\n"); + return -1; + } + finfo.bitmap_byte_off = finfo.clu_byte_off; finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8; finfo.ut_start_clu = round_up(EXFAT_REVERVED_CLUSTERS * ui->cluster_size + finfo.bitmap_byte_len, ui->cluster_size) / ui->cluster_size; @@ -511,6 +509,8 @@ static void exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.root_start_clu = round_up(finfo.ut_start_clu * ui->cluster_size + finfo.ut_byte_len, ui->cluster_size) / ui->cluster_size; finfo.root_byte_off = round_up(finfo.ut_byte_off + finfo.ut_byte_len, ui->cluster_size); finfo.root_byte_len = sizeof(struct exfat_dentry) * 3; + + return 0; } static int exfat_zero_out_disk(struct exfat_blk_dev *bd) @@ -538,7 +538,6 @@ int main(int argc, char *argv[]) wchar_t label[22]; mbslen = mbstowcs(NULL, optarg, 0); - printf("mbslen : %zd\n", mbslen); if (mbslen == (size_t) -1) { exfat_msg(EXFAT_ERROR, "mbstowcs return error(%d)\n", errno); goto out; @@ -597,17 +596,15 @@ int main(int argc, char *argv[]) if (ret < 0) goto out; - ret = verify_user_input(&bd, &ui); - if (ret < 0) - goto out; - if (ui.quick == false) { ret = exfat_zero_out_disk(&bd); if (ret) goto out; } - exfat_build_mkfs_info(&bd, &ui); + ret = exfat_build_mkfs_info(&bd, &ui); + if (ret) + goto out; ret = exfat_create_volume_boot_record(&bd, &ui, 0); if (ret) -- cgit v1.2.3 From 10b09096fe284dc5f3075c71d7fd81f07a5c3ec1 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 29 Dec 2019 18:40:01 +0900 Subject: exfat-tools: add exfat prefix for MAX_CLUSTER_SIZE Signed-off-by: Namjae Jeon --- include/mkfs.h | 2 +- mkfs/mkfs.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mkfs.h b/include/mkfs.h index 62a6768..a90cb6b 100644 --- a/include/mkfs.h +++ b/include/mkfs.h @@ -8,7 +8,7 @@ #define DEFAULT_CLUSTER_SIZE (1024 * 1024) #define DEFAULT_SECTOR_SIZE (512) #define MIN_NUM_SECTOR (2048) -#define MAX_CLUSTER_SIZE (32*1024*1024) +#define EXFAT_MAX_CLUSTER_SIZE (32*1024*1024) struct exfat_mkfs_info { unsigned int total_clu_cnt; diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 33c5689..64ca20d 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -564,10 +564,10 @@ int main(int argc, char *argv[]) } case 'c': ui.cluster_size = atoi(optarg); - if (ui.cluster_size > MAX_CLUSTER_SIZE) { + if (ui.cluster_size > EXFAT_MAX_CLUSTER_SIZE) { exfat_msg(EXFAT_ERROR, "cluster size(%d) exceeds max cluster size(%d)", - ui.cluster_size, MAX_CLUSTER_SIZE); + ui.cluster_size, EXFAT_MAX_CLUSTER_SIZE); goto out; } break; -- cgit v1.2.3 From 0fe03a2bca732f8d50428a56cdddcef6d4b1c1dd Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 29 Dec 2019 21:45:39 +0900 Subject: exfat-tools: implement zero out code Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 64ca20d..2283d52 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -515,6 +515,19 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, static int exfat_zero_out_disk(struct exfat_blk_dev *bd) { + int nbytes; + int chunk_size = 128 * 1024; + unsigned long long total_written = 0; + + do { + + nbytes = write(bd->dev_fd, 0, chunk_size); + if (nbytes <= 0) + break; + total_written += nbytes; + } while(total_written <= bd->size); + + exfat_msg(EXFAT_DEBUG, "zero out written size : %llu, disk size : %llu\n", total_written, bd->size); return 0; } @@ -566,7 +579,7 @@ int main(int argc, char *argv[]) ui.cluster_size = atoi(optarg); if (ui.cluster_size > EXFAT_MAX_CLUSTER_SIZE) { exfat_msg(EXFAT_ERROR, - "cluster size(%d) exceeds max cluster size(%d)", + "cluster size(%d) exceeds max cluster size(%d)\n", ui.cluster_size, EXFAT_MAX_CLUSTER_SIZE); goto out; } -- cgit v1.2.3 From d6980ddd952e1006af6bd7f8e54d41961fc2232e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 29 Dec 2019 22:09:34 +0900 Subject: exfat-tools: fix write error fault issue Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 2283d52..71a20d4 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -518,12 +518,22 @@ static int exfat_zero_out_disk(struct exfat_blk_dev *bd) int nbytes; int chunk_size = 128 * 1024; unsigned long long total_written = 0; + char *buf; + 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, 0, chunk_size); - if (nbytes <= 0) + nbytes = write(bd->dev_fd, buf, chunk_size); + if (nbytes <= 0) { + if (nbytes < 0) + exfat_msg(EXFAT_ERROR, "write failed(errno : %d)\n", errno); break; + } total_written += nbytes; } while(total_written <= bd->size); @@ -542,7 +552,7 @@ int main(int argc, char *argv[]) init_user_input(&ui); opterr = 0; - while ((c = getopt_long(argc, argv, "l:c:f:Vvh", opts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "l:c:fVvh", opts, NULL)) != EOF) switch (c) { case 'l': { -- cgit v1.2.3 From 3a1a6433595aba1c12ca5f02a24e3802fa330bea Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 09:45:25 +0900 Subject: exfat-tools: fix wrong bitmap bit count Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 71a20d4..8ed5836 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -343,7 +343,7 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd, if (!bitmap) return -1; - for (i = 0; i < finfo.used_clu_cnt; i++) + for (i = 0; i < finfo.used_clu_cnt - EXFAT_FIRST_CLUSTER; i++) exfat_set_bit(bd, bitmap, i); lseek(bd->dev_fd, finfo.bitmap_byte_off, SEEK_SET); -- cgit v1.2.3 From 86dd877e8a45a88a5fa2fefb516f47d784ac731d Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 09:47:07 +0900 Subject: exfat-tools: add fsync at the end of format Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 8ed5836..c737521 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -652,6 +652,7 @@ int main(int argc, char *argv[]) ret = exfat_create_root_dir(&bd, &ui); + fsync(bd.dev_fd); out: return ret; } -- cgit v1.2.3 From bf0a88ee0f4be55d672562975f3280a3a8ed9cbe Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 10:02:13 +0900 Subject: exfat-tools: add device fd close Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index c737521..d5409ad 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -654,5 +654,6 @@ int main(int argc, char *argv[]) fsync(bd.dev_fd); out: + close(bd.dev_fd); return ret; } -- cgit v1.2.3 From 019458d8869b0b41978e616fd117b0404e6210b1 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 10:04:42 +0900 Subject: exfat-tools: set zero volume label length Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index d5409ad..b0356af 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -370,7 +370,7 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, /* Set volume label entry */ ed[0].type = EXFAT_VOLUME; strcpy(ed[0].vol_label, ui->volume_label); - ed[0].vol_char_cnt = strlen("EXFAT"); + ed[0].vol_char_cnt = 0; /* Set bitmap entry */ ed[1].type = EXFAT_BITMAP; -- cgit v1.2.3 From a7e8f89aea1cffa00abad5699c5bdda16fd1d15a Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 13:04:48 +0900 Subject: exfat-tools: adjust default cluster size as device size Signed-off-by: Namjae Jeon --- include/mkfs.h | 6 +++++- mkfs/mkfs.c | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/include/mkfs.h b/include/mkfs.h index a90cb6b..b35af2b 100644 --- a/include/mkfs.h +++ b/include/mkfs.h @@ -5,11 +5,15 @@ #ifndef _MKFS_H -#define DEFAULT_CLUSTER_SIZE (1024 * 1024) +#define DEFAULT_CLUSTER_SIZE (1024*1024) #define DEFAULT_SECTOR_SIZE (512) #define MIN_NUM_SECTOR (2048) #define EXFAT_MAX_CLUSTER_SIZE (32*1024*1024) +#define KB (1024) +#define MB (1024*1024) +#define GB (1024UL*1024UL*1024UL) + struct exfat_mkfs_info { unsigned int total_clu_cnt; unsigned int used_clu_cnt; diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index b0356af..cfb563a 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -476,14 +476,20 @@ static struct option opts[] = { static void init_user_input(struct exfat_user_input *ui) { memset(ui, 0, sizeof(struct exfat_user_input)); - /* - * Default cluster size, Need to adjust default cluster size - * according to device size - */ - ui->cluster_size = 128 * 1024; ui->quick = true; } +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; +} + static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { @@ -625,6 +631,9 @@ int main(int argc, char *argv[]) goto out; } + if (!ui.cluster_size) + exfat_set_default_cluster_size(&bd, &ui); + ret = exfat_build_mkfs_info(&bd, &ui); if (ret) goto out; -- cgit v1.2.3 From 612f8a8692e5a653109ef2cba66a3ebf3b6802a5 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 14:31:52 +0900 Subject: exfat-tools: move boot_calc_checksum to libexfat Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 2 ++ lib/libexfat.c | 15 +++++++++++++++ mkfs/mkfs.c | 15 --------------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 27e80a0..833eebc 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -51,6 +51,8 @@ void exfat_set_bit(struct exfat_blk_dev *bd, char *bitmap, 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, unsigned int *checksum); /* * Exfat Print diff --git a/lib/libexfat.c b/lib/libexfat.c index bea3720..ec4e04f 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -70,3 +70,18 @@ wchar_t exfat_bad_char(wchar_t w) || (w == '|') || (w == '"') || (w == ':') || (w == '/') || (w == '\\'); } + +void boot_calc_checksum(unsigned char *sector, unsigned short size, + bool is_boot_sec, unsigned int *checksum) +{ + unsigned int index; + + for (index = 0; index < size; index++) + { + if (is_boot_sec == true && + ((index == 106) || (index == 107) || (index == 112))) + continue; + *checksum = ((*checksum & 1) ? 0x80000000 : 0) + + (*checksum >> 1) + sector[index]; + } +} diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index cfb563a..020ce55 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -22,21 +22,6 @@ struct exfat_mkfs_info finfo; -static void boot_calc_checksum(unsigned char *sector, unsigned short size, - bool is_boot_sec, unsigned int *checksum) -{ - unsigned int index; - - for (index = 0; index < size; index++) - { - if (is_boot_sec == true && - ((index == 106) || (index == 107) || (index == 112))) - continue; - *checksum = ((*checksum & 1) ? 0x80000000 : 0) + - (*checksum >> 1) + sector[index]; - } -} - static void exfat_setup_boot_sector(struct pbr *ppbr, struct exfat_blk_dev *bd, struct exfat_user_input *ui) { -- cgit v1.2.3 From 09dc157a25805fd872d695279056716f109cdf2e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 14:42:11 +0900 Subject: exfat-tools: add missing cpu_to_le() Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 020ce55..4e3bbad 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -43,7 +43,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, 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 = 1234; + pbsx->vol_serial = cpu_to_le32(1234); pbsx->vol_flags = 0; pbsx->sect_size_bits = bd->sector_size_bits; pbsx->sect_per_clus_bits = log2(ui->cluster_size / bd->sector_size); @@ -232,13 +232,13 @@ static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, return exfat_write_checksum_sector(bd, checksum, is_backup); } -static int write_fat_entry(int fd, unsigned int clu, +static int write_fat_entry(int fd, __le32 clu, unsigned long long offset) { int nbyte; - lseek(fd, finfo.fat_byte_off + (offset * sizeof(int)), SEEK_SET); - nbyte = write(fd, (char *) &clu, sizeof(unsigned int)); + lseek(fd, finfo.fat_byte_off + (offset * sizeof(__le32)), SEEK_SET); + nbyte = write(fd, (__u8 *) &clu, sizeof(__le32)); if (nbyte != sizeof(int)) { exfat_msg(EXFAT_ERROR, "write failed, offset : %llu, clu : %x\n", @@ -259,12 +259,12 @@ static int write_fat_entris(struct exfat_user_input *ui, int fd, ui->cluster_size; for (; clu < count - 1; clu++) { - ret = write_fat_entry(fd, clu + 1, clu); + ret = write_fat_entry(fd, cpu_to_le32(clu + 1), clu); if (ret) return ret; } - ret = write_fat_entry(fd, EXFAT_EOF_CLUSTER, clu); + ret = write_fat_entry(fd, cpu_to_le32(EXFAT_EOF_CLUSTER), clu); if (ret) return ret; @@ -279,7 +279,7 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, exfat_msg(EXFAT_DEBUG, "Create FAT Table\n"); /* fat entry 0 should be media type field(0xF8) */ - ret = write_fat_entry(bd->dev_fd, 0xfffffff8, 0); + ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xfffffff8), 0); if (ret) { exfat_msg(EXFAT_ERROR, "fat 0 entry write failed\n"); @@ -287,7 +287,7 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, } /* fat entry 1 is historical precedence(0xFFFFFFFF) */ - ret = write_fat_entry(bd->dev_fd, 0xffffffff, 1); + ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xffffffff), 1); if (ret) { exfat_msg(EXFAT_ERROR, "fat 1 entry write failed\n"); @@ -360,14 +360,14 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, /* Set bitmap entry */ ed[1].type = EXFAT_BITMAP; ed[1].bitmap_flags = 0; - ed[1].bitmap_start_clu = EXFAT_FIRST_CLUSTER; - ed[1].bitmap_size = finfo.bitmap_byte_len; + 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 = finfo.ut_start_clu; - ed[2].upcase_size = EXFAT_UPCASE_TABLE_SIZE; + ed[2].upcase_start_clu = cpu_to_le32(finfo.ut_start_clu); + ed[2].upcase_size = cpu_to_le32(EXFAT_UPCASE_TABLE_SIZE); lseek(bd->dev_fd, finfo.root_byte_off, SEEK_SET); nbytes = write(bd->dev_fd, ed, dentries_len); -- cgit v1.2.3 From e8d5be2805f3a20cbb0cdb005bd5796cfc032c52 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 14:43:21 +0900 Subject: exfat-tools: fix typo function name Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 4e3bbad..7ae580f 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -249,7 +249,7 @@ static int write_fat_entry(int fd, __le32 clu, return 0; } -static int write_fat_entris(struct exfat_user_input *ui, int fd, +static int write_fat_entries(struct exfat_user_input *ui, int fd, unsigned int clu, unsigned int length) { int ret; @@ -295,18 +295,18 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, } /* write bitmap entries */ - clu = write_fat_entris(ui, bd->dev_fd, EXFAT_FIRST_CLUSTER, + 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_entris(ui, bd->dev_fd, clu + 1, finfo.ut_byte_len); + 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_entris(ui, bd->dev_fd, clu + 1, finfo.root_byte_len); + clu = write_fat_entries(ui, bd->dev_fd, clu + 1, finfo.root_byte_len); if (clu < 0) return ret; -- cgit v1.2.3 From 0eb89f9a3d216d207e6d3235b4f715cf0751ae21 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 14:56:37 +0900 Subject: exfat-tools: fix over 80 char warnings Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 92 +++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 7ae580f..b7ba06e 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -56,17 +56,26 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, memset(ppbr->boot_code, 0, 390); ppbr->signature = cpu_to_le16(PBR_SIGNATURE); - exfat_msg(EXFAT_DEBUG, "Volume Length(sectors) : %llu\n", cpu_to_le64(pbsx->vol_length)); - exfat_msg(EXFAT_DEBUG, "FAT Offset(sector offset) : %u\n", cpu_to_le64(pbsx->fat_offset)); - exfat_msg(EXFAT_DEBUG, "FAT Length(sectors) : %u\n", cpu_to_le32(pbsx->fat_length)); - exfat_msg(EXFAT_DEBUG, "Cluster Heap Offset (sector offset) : %u\n", cpu_to_le32(pbsx->clu_offset)); - exfat_msg(EXFAT_DEBUG, "Cluster Count (sectors) : %u\n", cpu_to_le32(pbsx->clu_count)); - exfat_msg(EXFAT_DEBUG, "Root Cluster (cluster offset) : %u\n", cpu_to_le32(pbsx->root_cluster)); - exfat_msg(EXFAT_DEBUG, "Sector Size Bits : %u\n", cpu_to_le32(pbsx->sect_size_bits)); - exfat_msg(EXFAT_DEBUG, "Sector per Cluster bits : %u\n", cpu_to_le32(pbsx->sect_per_clus_bits)); + exfat_msg(EXFAT_DEBUG, "Volume Length(sectors) : %llu\n", + cpu_to_le64(pbsx->vol_length)); + exfat_msg(EXFAT_DEBUG, "FAT Offset(sector offset) : %u\n", + cpu_to_le64(pbsx->fat_offset)); + exfat_msg(EXFAT_DEBUG, "FAT Length(sectors) : %u\n", + cpu_to_le32(pbsx->fat_length)); + exfat_msg(EXFAT_DEBUG, "Cluster Heap Offset (sector offset) : %u\n", + cpu_to_le32(pbsx->clu_offset)); + exfat_msg(EXFAT_DEBUG, "Cluster Count (sectors) : %u\n", + cpu_to_le32(pbsx->clu_count)); + exfat_msg(EXFAT_DEBUG, "Root Cluster (cluster offset) : %u\n", + cpu_to_le32(pbsx->root_cluster)); + exfat_msg(EXFAT_DEBUG, "Sector Size Bits : %u\n", + cpu_to_le32(pbsx->sect_size_bits)); + exfat_msg(EXFAT_DEBUG, "Sector per Cluster bits : %u\n", + cpu_to_le32(pbsx->sect_per_clus_bits)); } -static int exfat_write_sector(struct exfat_blk_dev *bd, void *buf, unsigned int sec_off) +static 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; @@ -75,7 +84,8 @@ static int exfat_write_sector(struct exfat_blk_dev *bd, void *buf, unsigned int bytes = write(bd->dev_fd, buf, bd->sector_size); if (bytes != bd->sector_size) { exfat_msg(EXFAT_ERROR, - "write failed, sec_off : %u, bytes : %d\n", sec_off, bytes); + "write failed, sec_off : %u, bytes : %d\n", sec_off, + bytes); return -1; } return 0; @@ -110,7 +120,8 @@ static int exfat_write_boot_sector(struct exfat_blk_dev *bd, goto free_ppbr; } - boot_calc_checksum((unsigned char *)ppbr, sizeof(struct pbr), true, checksum); + boot_calc_checksum((unsigned char *)ppbr, sizeof(struct pbr), + true, checksum); free_ppbr: free(ppbr); @@ -136,7 +147,8 @@ static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, return -1; } - boot_calc_checksum((unsigned char *) &eb, sizeof(struct exbs), false, checksum); + boot_calc_checksum((unsigned char *) &eb, sizeof(struct exbs), + false, checksum); } out: @@ -165,7 +177,8 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, goto free_oem; } - boot_calc_checksum((unsigned char *)oem, bd->sector_size, false, checksum); + boot_calc_checksum((unsigned char *)oem, bd->sector_size, false, + checksum); /* Zero out reserved sector */ memset(oem, 0, bd->sector_size); @@ -176,7 +189,8 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, goto free_oem; } - boot_calc_checksum((unsigned char *)oem, bd->sector_size, false, checksum); + boot_calc_checksum((unsigned char *)oem, bd->sector_size, false, + checksum); free_oem: free(oem); @@ -311,7 +325,8 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, return ret; finfo.used_clu_cnt = clu + 1; - exfat_msg(EXFAT_DEBUG, "Total used cluster count : %d\n", finfo.used_clu_cnt); + exfat_msg(EXFAT_DEBUG, "Total used cluster count : %d\n", + finfo.used_clu_cnt); return ret; } @@ -391,7 +406,8 @@ static inline unsigned int sector_size_bits(unsigned int size) return bits; } -static int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_dev *bd) +static int exfat_get_blk_dev_info(struct exfat_user_input *ui, + struct exfat_blk_dev *bd) { int fd, ret = -1; long long blk_dev_size; @@ -402,7 +418,8 @@ static int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_ blk_dev_size = lseek(fd, 0, SEEK_END); if (blk_dev_size <= 0) { - exfat_msg(EXFAT_ERROR, "invalid block device size(%s) : %lld\n", + exfat_msg(EXFAT_ERROR, + "invalid block device size(%s) : %lld\n", ui->dev_name, blk_dev_size); ret = blk_dev_size; close(fd); @@ -420,8 +437,10 @@ static int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_ exfat_msg(EXFAT_DEBUG, "Block device name : %s\n", ui->dev_name); exfat_msg(EXFAT_DEBUG, "Block device size : %lld\n", bd->size); exfat_msg(EXFAT_DEBUG, "Block sector size : %u\n", bd->sector_size); - exfat_msg(EXFAT_DEBUG, "Number of the sectors : %u\n", bd->num_sectors); - exfat_msg(EXFAT_DEBUG, "Number of the clusters : %u\n", bd->num_clusters); + exfat_msg(EXFAT_DEBUG, "Number of the sectors : %u\n", + bd->num_sectors); + exfat_msg(EXFAT_DEBUG, "Number of the clusters : %u\n", + bd->num_clusters); ret = 0; bd->dev_fd = fd; @@ -486,7 +505,8 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, ui->cluster_size); finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len, DEFAULT_CLUSTER_SIZE); - finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; + finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / + ui->cluster_size; if (finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) { exfat_msg(EXFAT_ERROR, "cluster size is too small\n"); return -1; @@ -494,11 +514,16 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.bitmap_byte_off = finfo.clu_byte_off; finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8; - finfo.ut_start_clu = round_up(EXFAT_REVERVED_CLUSTERS * ui->cluster_size + finfo.bitmap_byte_len, ui->cluster_size) / ui->cluster_size; - finfo.ut_byte_off = round_up(finfo.bitmap_byte_off + finfo.bitmap_byte_len, ui->cluster_size); + finfo.ut_start_clu = round_up(EXFAT_REVERVED_CLUSTERS * + ui->cluster_size + finfo.bitmap_byte_len, ui->cluster_size) / + ui->cluster_size; + finfo.ut_byte_off = round_up(finfo.bitmap_byte_off + + finfo.bitmap_byte_len, ui->cluster_size); finfo.ut_byte_len = EXFAT_UPCASE_TABLE_SIZE; - finfo.root_start_clu = round_up(finfo.ut_start_clu * ui->cluster_size + finfo.ut_byte_len, ui->cluster_size) / ui->cluster_size; - finfo.root_byte_off = round_up(finfo.ut_byte_off + finfo.ut_byte_len, ui->cluster_size); + finfo.root_start_clu = round_up(finfo.ut_start_clu * ui->cluster_size + + finfo.ut_byte_len, ui->cluster_size) / ui->cluster_size; + finfo.root_byte_off = round_up(finfo.ut_byte_off + finfo.ut_byte_len, + ui->cluster_size); finfo.root_byte_len = sizeof(struct exfat_dentry) * 3; return 0; @@ -522,13 +547,16 @@ static int exfat_zero_out_disk(struct exfat_blk_dev *bd) nbytes = write(bd->dev_fd, buf, chunk_size); if (nbytes <= 0) { if (nbytes < 0) - exfat_msg(EXFAT_ERROR, "write failed(errno : %d)\n", errno); + exfat_msg(EXFAT_ERROR, + "write failed(errno : %d)\n", errno); break; } total_written += nbytes; } while(total_written <= bd->size); - exfat_msg(EXFAT_DEBUG, "zero out written size : %llu, disk size : %llu\n", total_written, bd->size); + exfat_msg(EXFAT_DEBUG, + "zero out written size : %llu, disk size : %llu\n", + total_written, bd->size); return 0; } @@ -553,23 +581,27 @@ int main(int argc, char *argv[]) mbslen = mbstowcs(NULL, optarg, 0); if (mbslen == (size_t) -1) { - exfat_msg(EXFAT_ERROR, "mbstowcs return error(%d)\n", errno); + exfat_msg(EXFAT_ERROR, + "mbstowcs return error(%d)\n", errno); goto out; } if (mbslen > VOLUME_LABEL_MAX_LEN - 1) { - exfat_msg(EXFAT_ERROR, "Volume Label is too longer(MAX 21 characters)\n"); + exfat_msg(EXFAT_ERROR, + "Volume Label is too longer(MAX 21 characters)\n"); goto out; } if (mbstowcs(label, optarg, mbslen + 1) == (size_t) -1) { - exfat_msg(EXFAT_ERROR, "mbstowcs return error(%d)\n", errno); + exfat_msg(EXFAT_ERROR, + "mbstowcs return error(%d)\n", errno); goto out; } for (i = 0; i < VOLUME_LABEL_MAX_LEN; i++) { if (exfat_bad_char(label[i])) { - exfat_msg(EXFAT_ERROR, "bad char error(%x)\n", label[i]); + exfat_msg(EXFAT_ERROR, + "bad char error(%x)\n", label[i]); goto out; } } -- cgit v1.2.3 From 87308147368a0d526d51992f07e25ed6872d79cc Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 15:03:50 +0900 Subject: exfat: don't use voltile Signed-off-by: Namjae Jeon --- lib/libexfat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/libexfat.c b/lib/libexfat.c index ec4e04f..3e47abc 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -15,7 +15,7 @@ #define BIT_MASK(nr) ((1) << ((nr) % 32)) #define BIT_WORD(nr) ((nr) / 32) -static inline void set_bit(int nr, volatile unsigned int *addr) +static inline void set_bit(int nr, unsigned int *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); @@ -23,7 +23,7 @@ static inline void set_bit(int nr, volatile unsigned int *addr) *p |= mask; } -static inline void clear_bit(int nr, volatile unsigned int *addr) +static inline void clear_bit(int nr, unsigned int *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); -- cgit v1.2.3 From 484ce8bf1f0ad8266054ab0a4a6eea90be418b81 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 31 Dec 2019 15:15:58 +0900 Subject: exfat-tools: fix checkpatch.pl warnings Signed-off-by: Namjae Jeon --- lib/libexfat.c | 15 ++++++------- mkfs/mkfs.c | 70 +++++++++++++++++++++++++++++++--------------------------- 2 files changed, 44 insertions(+), 41 deletions(-) diff --git a/lib/libexfat.c b/lib/libexfat.c index 3e47abc..4d82832 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -17,18 +17,18 @@ static inline void set_bit(int nr, unsigned int *addr) { - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - *p |= mask; + *p |= mask; } static inline void clear_bit(int nr, unsigned int *addr) { - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - *p &= ~mask; + *p &= ~mask; } static inline void set_bit_le(int nr, void *addr) @@ -76,8 +76,7 @@ void boot_calc_checksum(unsigned char *sector, unsigned short size, { unsigned int index; - for (index = 0; index < size; index++) - { + for (index = 0; index < size; index++) { if (is_boot_sec == true && ((index == 106) || (index == 107) || (index == 112))) continue; diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index b7ba06e..bb9e444 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -32,7 +32,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, pbpb->jmp_boot[0] = 0xeb; pbpb->jmp_boot[1] = 0x76; pbpb->jmp_boot[2] = 0x90; - memcpy(pbpb->oem_name, "EXFAT ", 8); + memcpy(pbpb->oem_name, "EXFAT ", 8); memset(pbpb->res_zero, 0, 53); /* Fill exfat extend BIOS paramemter block */ @@ -53,7 +53,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, pbsx->fs_version[1] = 1; memset(pbsx->reserved2, 0, 7); - memset(ppbr->boot_code, 0, 390); + memset(ppbr->boot_code, 0, 390); ppbr->signature = cpu_to_le16(PBR_SIGNATURE); exfat_msg(EXFAT_DEBUG, "Volume Length(sectors) : %llu\n", @@ -133,10 +133,10 @@ static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, { struct exbs eb; int i; - unsigned int sec_idx = EXBOOT_SEC_IDX; + unsigned int sec_idx = EXBOOT_SEC_IDX; if (is_backup) - sec_idx += BACKUP_BOOT_SEC_IDX; + sec_idx += BACKUP_BOOT_SEC_IDX; memset(&eb, 0, sizeof(struct exbs)); eb.signature = cpu_to_le16(PBR_SIGNATURE); @@ -160,7 +160,7 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, { char *oem; int ret = 0; - unsigned int sec_idx = OEM_SEC_IDX; + unsigned int sec_idx = OEM_SEC_IDX; oem = malloc(bd->sector_size); if (!oem) @@ -174,9 +174,9 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, if (ret) { exfat_msg(EXFAT_ERROR, "oem sector write failed\n"); ret = -1; - goto free_oem; + goto free_oem; } - + boot_calc_checksum((unsigned char *)oem, bd->sector_size, false, checksum); @@ -186,7 +186,7 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, if (ret) { exfat_msg(EXFAT_ERROR, "reserved sector write failed\n"); ret = -1; - goto free_oem; + goto free_oem; } boot_calc_checksum((unsigned char *)oem, bd->sector_size, false, @@ -202,7 +202,7 @@ static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, { __le32 *checksum_buf; int i, ret = 0; - unsigned int sec_idx = CHECKSUM_SEC_IDX; + unsigned int sec_idx = CHECKSUM_SEC_IDX; checksum_buf = malloc(bd->sector_size); if (!checksum_buf) @@ -230,7 +230,7 @@ static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, { unsigned int checksum = 0; int ret; - + exfat_msg(EXFAT_DEBUG, "Create Volume Boot Record\n"); ret = exfat_write_boot_sector(bd, ui, &checksum, is_backup); @@ -399,10 +399,12 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, static inline unsigned int sector_size_bits(unsigned int size) { unsigned int bits = 8; + do { bits++; size >>= 1; } while (size > 256); + return bits; } @@ -449,14 +451,14 @@ out: } static void usage(void) -{ +{ fprintf(stderr, "Usage: mkfs.exfat\n"); fprintf(stderr, "\t-l=string | --volume-label=string Set volume label\n"); fprintf(stderr, "\t-c=size | --cluster-size=size Set cluster size\n"); fprintf(stderr, "\t-f | --full-format Full format\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"); + fprintf(stderr, "\t-v | --verbose Print debug\n"); + fprintf(stderr, "\t-h | --help Show help\n"); exit(EXIT_FAILURE); } @@ -497,7 +499,7 @@ static void exfat_set_default_cluster_size(struct exfat_blk_dev *bd, static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - if (DEFAULT_CLUSTER_SIZE < ui->cluster_size) + if (ui->cluster_size > DEFAULT_CLUSTER_SIZE) finfo.fat_byte_off = ui->cluster_size; else finfo.fat_byte_off = DEFAULT_CLUSTER_SIZE; @@ -516,7 +518,7 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8; finfo.ut_start_clu = round_up(EXFAT_REVERVED_CLUSTERS * ui->cluster_size + finfo.bitmap_byte_len, ui->cluster_size) / - ui->cluster_size; + ui->cluster_size; finfo.ut_byte_off = round_up(finfo.bitmap_byte_off + finfo.bitmap_byte_len, ui->cluster_size); finfo.ut_byte_len = EXFAT_UPCASE_TABLE_SIZE; @@ -552,28 +554,28 @@ static int exfat_zero_out_disk(struct exfat_blk_dev *bd) break; } total_written += nbytes; - } while(total_written <= bd->size); + } while (total_written <= bd->size); exfat_msg(EXFAT_DEBUG, "zero out written size : %llu, disk size : %llu\n", total_written, bd->size); - return 0; + return 0; } int main(int argc, char *argv[]) { int c; - int ret = EXIT_FAILURE; + int ret = EXIT_FAILURE; char *blk_dev_name; struct exfat_blk_dev bd; struct exfat_user_input ui; init_user_input(&ui); - opterr = 0; - while ((c = getopt_long(argc, argv, "l:c:fVvh", opts, NULL)) != EOF) - switch (c) { - case 'l': + opterr = 0; + while ((c = getopt_long(argc, argv, "l:c:fVvh", opts, NULL)) != EOF) + switch (c) { + case 'l': { int i; size_t mbslen; @@ -592,7 +594,8 @@ int main(int argc, char *argv[]) goto out; } - if (mbstowcs(label, optarg, mbslen + 1) == (size_t) -1) { + if (mbstowcs(label, optarg, mbslen + 1) == + (size_t) -1) { exfat_msg(EXFAT_ERROR, "mbstowcs return error(%d)\n", errno); goto out; @@ -601,14 +604,15 @@ int main(int argc, char *argv[]) for (i = 0; i < VOLUME_LABEL_MAX_LEN; i++) { if (exfat_bad_char(label[i])) { exfat_msg(EXFAT_ERROR, - "bad char error(%x)\n", label[i]); + "bad char error(%x)\n", + label[i]); goto out; } } break; } - case 'c': + case 'c': ui.cluster_size = atoi(optarg); if (ui.cluster_size > EXFAT_MAX_CLUSTER_SIZE) { exfat_msg(EXFAT_ERROR, @@ -617,20 +621,20 @@ int main(int argc, char *argv[]) goto out; } break; - case 'f': + case 'f': ui.quick = false; break; case 'V': show_version(); break; - case 'v': + case 'v': print_level = EXFAT_DEBUG; - break; - case '?': - case 'h': - default: - usage(); - } + break; + case '?': + case 'h': + default: + usage(); + } if (argc - optind != 1) usage(); -- cgit v1.2.3 From 2d2d19726ff771a69d3f319ec34a19d4a8472a8a Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 1 Jan 2020 07:48:19 +0900 Subject: exfat-tools: move exfat_set_default_cluster_size to exfat_get_blk_dev_info() Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index bb9e444..72610ed 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -408,6 +408,17 @@ static inline unsigned int sector_size_bits(unsigned int size) 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; +} + static int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_dev *bd) { @@ -430,6 +441,9 @@ static int exfat_get_blk_dev_info(struct exfat_user_input *ui, bd->dev_fd = fd; bd->size = blk_dev_size; + if (!ui->cluster_size) + exfat_set_default_cluster_size(bd, ui); + if (ioctl(fd, BLKSSZGET, &bd->sector_size) < 0) bd->sector_size = DEFAULT_SECTOR_SIZE; bd->sector_size_bits = sector_size_bits(bd->sector_size); @@ -485,17 +499,6 @@ static void init_user_input(struct exfat_user_input *ui) ui->quick = true; } -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; -} - static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { @@ -652,9 +655,6 @@ int main(int argc, char *argv[]) goto out; } - if (!ui.cluster_size) - exfat_set_default_cluster_size(&bd, &ui); - ret = exfat_build_mkfs_info(&bd, &ui); if (ret) goto out; -- cgit v1.2.3 From f43ec163e822726880e123fffbacfe6c099e3b1f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 3 Jan 2020 15:54:23 +0800 Subject: exfat-tools: add EXFAT_INFO print level Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 833eebc..ef34855 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -58,10 +58,11 @@ void boot_calc_checksum(unsigned char *sector, unsigned short size, * Exfat Print */ -static unsigned int print_level; +static unsigned int print_level = 1; #define EXFAT_ERROR (0) -#define EXFAT_DEBUG (1) +#define EXFAT_INFO (1) +#define EXFAT_DEBUG (2) #define exfat_msg(level, fmt, ...) \ do { \ -- cgit v1.2.3 From d285e84ff18e7a9b98dd679fee6826edc9d0a55c Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 3 Jan 2020 16:02:22 +0800 Subject: exfat-tools: change byte cluster size to kilobyte Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 72610ed..8ed483a 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -468,7 +468,7 @@ static void usage(void) { fprintf(stderr, "Usage: mkfs.exfat\n"); fprintf(stderr, "\t-l=string | --volume-label=string Set volume label\n"); - fprintf(stderr, "\t-c=size | --cluster-size=size Set cluster size\n"); + fprintf(stderr, "\t-c=KB size | --cluster-size=KB size Set cluster size\n"); fprintf(stderr, "\t-f | --full-format Full format\n"); fprintf(stderr, "\t-V | --version Show version\n"); fprintf(stderr, "\t-v | --verbose Print debug\n"); @@ -616,7 +616,7 @@ int main(int argc, char *argv[]) break; } case 'c': - ui.cluster_size = atoi(optarg); + ui.cluster_size = atoi(optarg) * KB; if (ui.cluster_size > EXFAT_MAX_CLUSTER_SIZE) { exfat_msg(EXFAT_ERROR, "cluster size(%d) exceeds max cluster size(%d)\n", -- cgit v1.2.3 From 729de20eb560d724a1808e324a49cd4fca3ac9ed Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 19 Jan 2020 12:58:03 +0900 Subject: exfat: zero out to root cluster from boot sector Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 8ed483a..9a05654 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -534,12 +534,19 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, return 0; } -static int exfat_zero_out_disk(struct exfat_blk_dev *bd) +static int exfat_zero_out_disk(struct exfat_blk_dev *bd, + struct exfat_user_input *ui) { int nbytes; - int chunk_size = 128 * 1024; 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) @@ -557,7 +564,7 @@ static int exfat_zero_out_disk(struct exfat_blk_dev *bd) break; } total_written += nbytes; - } while (total_written <= bd->size); + } while (total_written <= size); exfat_msg(EXFAT_DEBUG, "zero out written size : %llu, disk size : %llu\n", @@ -649,16 +656,14 @@ int main(int argc, char *argv[]) if (ret < 0) goto out; - if (ui.quick == false) { - ret = exfat_zero_out_disk(&bd); - if (ret) - goto out; - } - ret = exfat_build_mkfs_info(&bd, &ui); if (ret) goto out; + ret = exfat_zero_out_disk(&bd, &ui); + if (ret) + goto out; + ret = exfat_create_volume_boot_record(&bd, &ui, 0); if (ret) goto out; -- cgit v1.2.3 From 0199df132735b7ca20de091462c7a04cfa1e44bb Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 19 Jan 2020 13:55:24 +0900 Subject: exfat: print format stages Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 17 ++++++----- mkfs/mkfs.c | 80 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 62 insertions(+), 35 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index ef34855..ad02ba9 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -64,12 +64,15 @@ static unsigned int print_level = 1; #define EXFAT_INFO (1) #define EXFAT_DEBUG (2) -#define exfat_msg(level, fmt, ...) \ - do { \ - if (print_level >= level) { \ - printf("[%s:%4d] " fmt, \ - __func__, __LINE__, ##__VA_ARGS__); \ - } \ - } while (0) \ +#define exfat_msg(level, fmt, ...) \ + do { \ + if (print_level >= level) { \ + if (print_level == EXFAT_INFO) \ + printf(fmt, ##__VA_ARGS__); \ + else \ + printf("[%s:%4d] " fmt, \ + __func__, __LINE__, ##__VA_ARGS__); \ + } \ + } while (0) \ #endif /* !_EXFA_TOOLS_H */ diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 9a05654..b464b0b 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -231,8 +231,6 @@ static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, unsigned int checksum = 0; int ret; - exfat_msg(EXFAT_DEBUG, "Create Volume Boot Record\n"); - ret = exfat_write_boot_sector(bd, ui, &checksum, is_backup); if (ret) return ret; @@ -290,8 +288,6 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, { int ret, clu, count; - exfat_msg(EXFAT_DEBUG, "Create FAT Table\n"); - /* fat entry 0 should be media type field(0xF8) */ ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xfffffff8), 0); if (ret) { @@ -337,8 +333,6 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd, char *bitmap; int i, nbytes; - exfat_msg(EXFAT_DEBUG, "Create Allocation Bitmap\n"); - bitmap = malloc(finfo.bitmap_byte_len); if (!bitmap) return -1; @@ -365,8 +359,6 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, int dentries_len = sizeof(struct exfat_dentry) * 3; int nbytes, vol_len; - exfat_msg(EXFAT_DEBUG, "Create Root Directory entry\n"); - /* Set volume label entry */ ed[0].type = EXFAT_VOLUME; strcpy(ed[0].vol_label, ui->volume_label); @@ -572,6 +564,56 @@ static int exfat_zero_out_disk(struct exfat_blk_dev *bd, return 0; } +static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui) +{ + int ret; + + exfat_msg(EXFAT_INFO, + "Creating exFAT filesystem(%s) with %u cluster size\n\n", + ui->dev_name, ui->cluster_size); + + exfat_msg(EXFAT_INFO, "Writing volume boot record: "); + ret = exfat_create_volume_boot_record(bd, ui, 0); + exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + if (ret) + return ret; + + exfat_msg(EXFAT_INFO, "Writing backup volume boot record: "); + /* backup sector */ + ret = exfat_create_volume_boot_record(bd, ui, 1); + exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + if (ret) + return ret; + + exfat_msg(EXFAT_INFO, "Fat table creation: "); + ret = exfat_create_fat_table(bd, ui); + exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + if (ret) + return ret; + + exfat_msg(EXFAT_INFO, "Allocation bitmap creation: "); + ret = exfat_create_bitmap(bd, ui); + exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + if (ret) + return ret; + + exfat_msg(EXFAT_INFO, "Upcate table creation: "); + ret = exfat_create_upcase_table(bd, ui); + exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + if (ret) + return ret; + + exfat_msg(EXFAT_INFO, "Writing root directory entry: "); + ret = exfat_create_root_dir(bd, ui); + exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + if (ret) + return ret; + + exfat_msg(EXFAT_INFO, "\nexFAT format complete!\n"); + + return 0; +} + int main(int argc, char *argv[]) { int c; @@ -652,6 +694,7 @@ int main(int argc, char *argv[]) memset(ui.dev_name, 0, 255); strncpy(ui.dev_name, argv[optind], 255); + printf("exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); ret = exfat_get_blk_dev_info(&ui, &bd); if (ret < 0) goto out; @@ -664,29 +707,10 @@ int main(int argc, char *argv[]) if (ret) goto out; - ret = exfat_create_volume_boot_record(&bd, &ui, 0); + ret = make_exfat(&bd, &ui); if (ret) goto out; - /* backup sector */ - ret = exfat_create_volume_boot_record(&bd, &ui, 1); - if (ret) - goto out; - - ret = exfat_create_fat_table(&bd, &ui); - if (ret) - goto out; - - ret = exfat_create_bitmap(&bd, &ui); - if (ret) - goto out; - - ret = exfat_create_upcase_table(&bd, &ui); - if (ret) - goto out; - - ret = exfat_create_root_dir(&bd, &ui); - fsync(bd.dev_fd); out: close(bd.dev_fd); -- cgit v1.2.3 From 51e471a747630ddfe7830dc8cf74bdb6dc6a4bc9 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 19 Jan 2020 20:48:01 +0900 Subject: exfat-tools: update README Signed-off-by: Namjae Jeon --- README.md | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9da0585..83d6171 100644 --- a/README.md +++ b/README.md @@ -1 +1,40 @@ -# exfat-tools \ No newline at end of file + +## exfat-tools ? +Exfat-tools is mkfs(format)/fsck(repair) implementation for exfat filesystem under GNU GPL version 2. This opensource project was created by Namjae Jeon as exfat is officially supported in Linux kernel. + +## Maintainers + +* Namjae Jeon +* Hyunchul Lee + +## building exfat tools + +Install preprequisite packages: + For Ubuntu: + sudo apt-get install autoconf libtool pkg-config + + For Fedora, RHEL: + sudo yum install autoconf automake libtool + +Build steps: + - cd into the exfat-tools directory + - ./autogen.sh + - ./configure + - make + - make install + +## USING exFAT TOOLS + +- mkfs.exfat: + Build a exfat filesystem on a device or partition(e.g. /dev/hda1, dev/sda1). + +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) user want + mkfs.exfat -c 128 /dev/sda1 + 3. For full format(zero out) + mkfs.exfat -f /dev/sda1 + +- fsck.exfat(Preparing): + Check the consistency of your exfat filesystem and optinally repair a corrupted device formatted by exfat. -- cgit v1.2.3 From 6c88a2b918d6f1446a006ca2b35f800f67c06fd3 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 19 Jan 2020 20:55:09 +0900 Subject: exfat: update README #2 Signed-off-by: Namjae Jeon --- README.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 83d6171..019de5f 100644 --- a/README.md +++ b/README.md @@ -10,21 +10,27 @@ Exfat-tools is mkfs(format)/fsck(repair) implementation for exfat filesystem und ## building exfat tools Install preprequisite packages: +``` For Ubuntu: sudo apt-get install autoconf libtool pkg-config +``` +``` For Fedora, RHEL: sudo yum install autoconf automake libtool +``` Build steps: - - cd into the exfat-tools directory - - ./autogen.sh - - ./configure - - make - - make install +``` + cd into the exfat-tools directory + ./autogen.sh + ./configure + make + make install +``` ## USING exFAT TOOLS - +``` - mkfs.exfat: Build a exfat filesystem on a device or partition(e.g. /dev/hda1, dev/sda1). @@ -38,3 +44,4 @@ Usage example: - fsck.exfat(Preparing): Check the consistency of your exfat filesystem and optinally repair a corrupted device formatted by exfat. +``` -- cgit v1.2.3 From 160ad28ebf2431f12f86ad98190404b01729a75c Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 19 Jan 2020 20:59:14 +0900 Subject: exfat-tools: update README #3 Signed-off-by: Namjae Jeon --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 019de5f..17b2e6e 100644 --- a/README.md +++ b/README.md @@ -3,19 +3,15 @@ Exfat-tools is mkfs(format)/fsck(repair) implementation for exfat filesystem under GNU GPL version 2. This opensource project was created by Namjae Jeon as exfat is officially supported in Linux kernel. ## Maintainers - * Namjae Jeon * Hyunchul Lee -## building exfat tools - +## Buidling exfat tools Install preprequisite packages: ``` For Ubuntu: sudo apt-get install autoconf libtool pkg-config -``` -``` For Fedora, RHEL: sudo yum install autoconf automake libtool ``` @@ -29,7 +25,7 @@ Build steps: make install ``` -## USING exFAT TOOLS +## Using exFAT tools ``` - mkfs.exfat: Build a exfat filesystem on a device or partition(e.g. /dev/hda1, dev/sda1). -- cgit v1.2.3 From bacb605c6ae9ef82c220b087989a5e4657ac715e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 20 Jan 2020 22:23:12 +0900 Subject: exfat: update README#4 Signed-off-by: Namjae Jeon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 17b2e6e..d56fec5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## exfat-tools ? -Exfat-tools is mkfs(format)/fsck(repair) implementation for exfat filesystem under GNU GPL version 2. This opensource project was created by Namjae Jeon as exfat is officially supported in Linux kernel. +Exfat-tools is mkfs(format)/fsck(repair) implementation for exfat filesystem under GNU GPL version 2. ## Maintainers * Namjae Jeon -- cgit v1.2.3 From 191aa27267864a85fedbb0a00f57b04ea3fcc6ee Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 23 Jan 2020 13:08:13 +0900 Subject: exfat-tools: adding sync message before complete message Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index b464b0b..9eb1572 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -609,8 +609,6 @@ static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui) if (ret) return ret; - exfat_msg(EXFAT_INFO, "\nexFAT format complete!\n"); - return 0; } @@ -711,8 +709,12 @@ int main(int argc, char *argv[]) if (ret) goto out; - fsync(bd.dev_fd); + exfat_msg(EXFAT_INFO, "\nSynchronizing... \n"); + ret = fsync(bd.dev_fd); + exfat_msg(EXFAT_INFO, "\nexFAT format complete!\n"); out: + if (ret) + exfat_msg(EXFAT_INFO, "\nexFAT format fail!\n"); close(bd.dev_fd); return ret; } -- cgit v1.2.3 From e14edf379349d862850dfec80e19df375ebbd437 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 23 Jan 2020 13:12:40 +0900 Subject: exfat-tool: avoid complete and fail message print at same time Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 9eb1572..c3c9302 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -709,11 +709,12 @@ int main(int argc, char *argv[]) if (ret) goto out; - exfat_msg(EXFAT_INFO, "\nSynchronizing... \n"); + exfat_msg(EXFAT_INFO, "Synchronizing... \n"); ret = fsync(bd.dev_fd); - exfat_msg(EXFAT_INFO, "\nexFAT format complete!\n"); out: - if (ret) + if (!ret) + exfat_msg(EXFAT_INFO, "\nexFAT format complete!\n"); + else exfat_msg(EXFAT_INFO, "\nexFAT format fail!\n"); close(bd.dev_fd); return ret; -- cgit v1.2.3 From f38cfb4ea72575c3a55db00a53b9e73d22149bca Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 23 Jan 2020 13:48:05 +0900 Subject: exfat-tools: fix wrong length for number of cluster calculation in write fat entries Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index c3c9302..2ed9839 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -267,8 +267,7 @@ static int write_fat_entries(struct exfat_user_input *ui, int fd, int ret; unsigned int count; - count = clu + round_up(finfo.bitmap_byte_len, ui->cluster_size) / - ui->cluster_size; + 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); -- cgit v1.2.3 From 24e2c21c29ab1078557a0466c58119dc709a5349 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 17:12:34 +0900 Subject: tools: move exfat_get_blk_dev_info to libexfat.c Move exfat_get_blk_dev_info to libexfat.c Signed-off-by: Hyunchul Lee --- include/exfat_tools.h | 5 ++++ lib/libexfat.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ mkfs/mkfs.c | 75 +--------------------------------------------- 3 files changed, 89 insertions(+), 74 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index ad02ba9..4a12e7a 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -40,12 +40,15 @@ struct exfat_blk_dev { struct exfat_user_input { char dev_name[255]; + bool writeable; unsigned int cluster_size; unsigned int sec_per_clu; bool quick; char volume_label[22]; }; +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, @@ -53,6 +56,8 @@ void exfat_clear_bit(struct exfat_blk_dev *bd, char *bitmap, wchar_t exfat_bad_char(wchar_t w); void boot_calc_checksum(unsigned char *sector, unsigned short size, bool is_boot_sec, unsigned int *checksum); +int exfat_get_blk_dev_info(struct exfat_user_input *ui, + struct exfat_blk_dev *bd); /* * Exfat Print diff --git a/lib/libexfat.c b/lib/libexfat.c index 4d82832..888a860 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -3,8 +3,17 @@ * Copyright (C) 2019 Namjae Jeon */ +#include +#include +#include +#include +#include +#include +#include + #include "exfat_ondisk.h" #include "exfat_tools.h" +#include "mkfs.h" #if defined(__LITTLE_ENDIAN) #define BITOP_LE_SWIZZLE 0 @@ -84,3 +93,77 @@ void boot_calc_checksum(unsigned char *sector, unsigned short size, (*checksum >> 1) + sector[index]; } } + +void show_version(void) +{ + printf("exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); + exit(EXIT_FAILURE); +} + +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; +} + +int exfat_get_blk_dev_info(struct exfat_user_input *ui, + struct exfat_blk_dev *bd) +{ + int fd, ret = -1; + long long blk_dev_size; + + fd = open(ui->dev_name, ui->writeable ? O_RDWR : O_RDONLY); + if (fd < 0) + return -1; + + blk_dev_size = lseek(fd, 0, SEEK_END); + if (blk_dev_size <= 0) { + exfat_msg(EXFAT_ERROR, + "invalid block device size(%s) : %lld\n", + ui->dev_name, blk_dev_size); + ret = blk_dev_size; + close(fd); + goto out; + } + + bd->dev_fd = fd; + bd->size = blk_dev_size; + if (!ui->cluster_size) + exfat_set_default_cluster_size(bd, ui); + + 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 / DEFAULT_SECTOR_SIZE; + bd->num_clusters = blk_dev_size / ui->cluster_size; + + exfat_msg(EXFAT_DEBUG, "Block device name : %s\n", ui->dev_name); + exfat_msg(EXFAT_DEBUG, "Block device size : %lld\n", bd->size); + exfat_msg(EXFAT_DEBUG, "Block sector size : %u\n", bd->sector_size); + exfat_msg(EXFAT_DEBUG, "Number of the sectors : %u\n", + bd->num_sectors); + exfat_msg(EXFAT_DEBUG, "Number of the clusters : %u\n", + bd->num_clusters); + + ret = 0; + bd->dev_fd = fd; +out: + return ret; +} diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 2ed9839..ca47b42 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -387,74 +387,6 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, return 0; } -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; -} - -static int exfat_get_blk_dev_info(struct exfat_user_input *ui, - struct exfat_blk_dev *bd) -{ - int fd, ret = -1; - long long blk_dev_size; - - fd = open(ui->dev_name, O_RDWR); - if (fd < 0) - return -1; - - blk_dev_size = lseek(fd, 0, SEEK_END); - if (blk_dev_size <= 0) { - exfat_msg(EXFAT_ERROR, - "invalid block device size(%s) : %lld\n", - ui->dev_name, blk_dev_size); - ret = blk_dev_size; - close(fd); - goto out; - } - - bd->dev_fd = fd; - bd->size = blk_dev_size; - if (!ui->cluster_size) - exfat_set_default_cluster_size(bd, ui); - - 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 / DEFAULT_SECTOR_SIZE; - bd->num_clusters = blk_dev_size / ui->cluster_size; - - exfat_msg(EXFAT_DEBUG, "Block device name : %s\n", ui->dev_name); - exfat_msg(EXFAT_DEBUG, "Block device size : %lld\n", bd->size); - exfat_msg(EXFAT_DEBUG, "Block sector size : %u\n", bd->sector_size); - exfat_msg(EXFAT_DEBUG, "Number of the sectors : %u\n", - bd->num_sectors); - exfat_msg(EXFAT_DEBUG, "Number of the clusters : %u\n", - bd->num_clusters); - - ret = 0; - bd->dev_fd = fd; -out: - return ret; -} - static void usage(void) { fprintf(stderr, "Usage: mkfs.exfat\n"); @@ -468,12 +400,6 @@ static void usage(void) exit(EXIT_FAILURE); } -static void show_version(void) -{ - printf("exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); - exit(EXIT_FAILURE); -} - static struct option opts[] = { {"volme-label", required_argument, NULL, 'l' }, {"cluster-size", required_argument, NULL, 'c' }, @@ -487,6 +413,7 @@ static struct option opts[] = { static void init_user_input(struct exfat_user_input *ui) { memset(ui, 0, sizeof(struct exfat_user_input)); + ui->writeable = true; ui->quick = true; } -- cgit v1.2.3 From c1d8362b6820d3664adaf3e17bcd014e95f87fe9 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 17:15:10 +0900 Subject: tools: add functions of short names for printing messages Add functions of short names for printing messages Signed-off-by: Hyunchul Lee --- include/exfat_tools.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 4a12e7a..040e2f6 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -80,4 +80,8 @@ static unsigned int print_level = 1; } \ } while (0) \ +#define exfat_err(fmt, ...) exfat_msg(EXFAT_ERROR, fmt, ##__VA_ARGS__) +#define exfat_info(fmt, ...) exfat_msg(EXFAT_INFO, fmt, ##__VA_ARGS__) +#define exfat_debug(fmt, ...) exfat_msg(EXFAT_DEBUG, fmt, ##__VA_ARGS__) + #endif /* !_EXFA_TOOLS_H */ -- cgit v1.2.3 From 92e4f373c320e91081eac17161768c0946db336a Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 17:18:47 +0900 Subject: fsck: add initial commit Add initial commit Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 698487b..166a129 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1,13 +1,85 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2019 Namjae Jeon + * Copyright (C) 2020 Hyunchul Lee */ +#include +#include #include +#include +#include #include "exfat_ondisk.h" +#include "exfat_tools.h" -int main() +enum fsck_ui_options { + FSCK_OPTS_REPAIR = 0x01, +}; + +struct fsck_user_input { + struct exfat_user_input ei; + enum fsck_ui_options options; +}; + +static struct option opts[] = { + {"version", no_argument, NULL, 'V' }, + {"verbose", no_argument, NULL, 'v' }, + {"help", no_argument, NULL, 'h' }, + {"?", no_argument, NULL, '?' }, + {NULL, 0, NULL, 0 } +}; + +static void usage(char *name) +{ + fprintf(stderr, "Usage: %s\n", name); + fprintf(stderr, "\t-r | --repair Repair\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); +} + +int main(int argc, char * const argv[]) { - return 0; + int c, ret; + struct fsck_user_input ui = {0,}; + struct exfat_blk_dev bd = {0,}; + + opterr = 0; + while ((c = getopt_long(argc, argv, "Vvh", opts, NULL)) != EOF) { + switch (c) { + case 'r': + ui.options |= FSCK_OPTS_REPAIR; + ui.ei.writeable = true; + break; + case 'V': + show_version(); + break; + case 'v': + if (print_level < EXFAT_DEBUG) + print_level++; + break; + case '?': + case 'h': + default: + usage(argv[0]); + } + } + + if (optind != argc - 1) + usage(argv[0]); + + printf("fsck.ext4 %s\n", EXFAT_TOOLS_VERSION); + + strncpy(ui.ei.dev_name, argv[optind], sizeof(ui.ei.dev_name)); + ret = exfat_get_blk_dev_info(&ui.ei, &bd); + if (ret < 0) { + exfat_err("failed to open %s. %d\n", ui.ei.dev_name, ret); + return ret; + } + + close(bd.dev_fd); + return ret; } -- cgit v1.2.3 From e141050a733c7259373b12fb716e813bbc0bd426 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 20:53:42 +0900 Subject: fsck: introduce exfat structures Introduce exfat structures Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 94 ++++++++++++++++ include/list.h | 336 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 430 insertions(+) create mode 100644 include/list.h diff --git a/fsck/fsck.c b/fsck/fsck.c index 166a129..c807e60 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -9,9 +9,11 @@ #include #include #include +#include #include "exfat_ondisk.h" #include "exfat_tools.h" +#include "list.h" enum fsck_ui_options { FSCK_OPTS_REPAIR = 0x01, @@ -22,6 +24,40 @@ struct fsck_user_input { enum fsck_ui_options options; }; +typedef __u32 clus_t; + +enum exfat_file_attr { + EXFAT_FA_NONE = 0x00, + EXFAT_FA_DIR = 0x01, +}; + +struct exfat_node { + struct exfat_node *parent; + struct list_head children; + struct list_head sibling; + struct list_head list; + clus_t first_clus; + __u16 attr; + __u64 size; + bool is_contiguous; + off_t dentry_file_offset; + __le16 name[0]; /* only for directory */ +}; + +#define EXFAT_NAME_MAX 255 +#define UTF16_NAME_BUFFER_SIZE ((EXFAT_NAME_MAX + 1) * sizeof(__le16)) +#define UTF8_NAME_BUFFER_SIZE (EXFAT_NAME_MAX * 3 + 1) + +struct exfat { + struct exfat_blk_dev *blk_dev; + struct pbr *bs; + char volume_label[VOLUME_LABEL_MAX_LEN*3+1]; + struct exfat_node *root; + struct list_head dir_list; + __u32 *alloc_bitmap; + __u64 bit_count; +}; + static struct option opts[] = { {"version", no_argument, NULL, 'V' }, {"verbose", no_argument, NULL, 'v' }, @@ -41,11 +77,61 @@ static void usage(char *name) exit(EXIT_FAILURE); } +static struct exfat_node *alloc_exfat_node(__u16 attr) +{ + struct exfat_node *node; + int size; + + size = offsetof(struct exfat_node, name) + UTF16_NAME_BUFFER_SIZE; + node = (struct exfat_node *)calloc(1, size); + if (!node) { + exfat_err("failed to allocate exfat_node\n"); + return NULL; + } + + node->parent = NULL; + INIT_LIST_HEAD(&node->children); + INIT_LIST_HEAD(&node->sibling); + INIT_LIST_HEAD(&node->list); + + node->attr = attr; + return node; +} + +static void free_exfat_node(struct exfat_node *node) +{ + free(node); +} + +static struct exfat *alloc_exfat(struct exfat_blk_dev *bd) +{ + struct exfat *exfat; + + exfat = (struct exfat *)calloc(1, sizeof(*exfat)); + if (!exfat) { + exfat_err("failed to allocate exfat\n"); + return NULL; + } + + exfat->blk_dev = bd; + INIT_LIST_HEAD(&exfat->dir_list); + return exfat; +} + +static void free_exfat(struct exfat *exfat) +{ + if (exfat) { + free(exfat->bs); + free(exfat); + } +} + int main(int argc, char * const argv[]) { int c, ret; struct fsck_user_input ui = {0,}; struct exfat_blk_dev bd = {0,}; + struct exfat *exfat = NULL; opterr = 0; while ((c = getopt_long(argc, argv, "Vvh", opts, NULL)) != EOF) { @@ -80,6 +166,14 @@ int main(int argc, char * const argv[]) return ret; } + exfat = alloc_exfat(&bd); + if (!exfat) { + ret = -ENOMEM; + goto err; + } + +err: + free_exfat(exfat); close(bd.dev_fd); return ret; } diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000..6d887e4 --- /dev/null +++ b/include/list.h @@ -0,0 +1,336 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#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 -- cgit v1.2.3 From a6b1ffa7c54b35b37ad79c77a401210368f1664d Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 20:58:28 +0900 Subject: fsck: introduce exfat_stat structure Introduce exfat_stat structure Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index c807e60..35cc9e9 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -58,6 +58,15 @@ struct exfat { __u64 bit_count; }; +struct exfat_stat { + long dir_count; + long file_count; + long dir_free_count; + long file_free_count; +}; + +struct exfat_stat exfat_stat; + static struct option opts[] = { {"version", no_argument, NULL, 'V' }, {"verbose", no_argument, NULL, 'v' }, @@ -94,12 +103,20 @@ static struct exfat_node *alloc_exfat_node(__u16 attr) INIT_LIST_HEAD(&node->sibling); INIT_LIST_HEAD(&node->list); + if (attr & ATTR_SUBDIR) + exfat_stat.dir_count++; + else + exfat_stat.file_count++; node->attr = attr; return node; } static void free_exfat_node(struct exfat_node *node) { + if (node->attr & ATTR_SUBDIR) + exfat_stat.dir_free_count++; + else + exfat_stat.file_free_count++; free(node); } @@ -126,6 +143,16 @@ static void free_exfat(struct exfat *exfat) } } +void exfat_show_stat(struct exfat *exfat) +{ + exfat_debug("Found directories: %ld\n", exfat_stat.dir_count); + exfat_debug("Found files: %ld\n", exfat_stat.file_count); + exfat_debug("Found leak directories: %ld\n", + exfat_stat.dir_count - exfat_stat.dir_free_count); + exfat_debug("Found leak files: %ld\n", + exfat_stat.file_count - exfat_stat.file_free_count); +} + int main(int argc, char * const argv[]) { int c, ret; @@ -172,6 +199,7 @@ int main(int argc, char * const argv[]) goto err; } + exfat_show_stat(exfat); err: free_exfat(exfat); close(bd.dev_fd); -- cgit v1.2.3 From 01b6a977ee2357a2ca04822bf07051c70c58c695 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 21:20:12 +0900 Subject: fsck: add boot region check Add boot region check Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++- include/exfat_tools.h | 5 +- lib/libexfat.c | 27 +++++++---- 3 files changed, 151 insertions(+), 11 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 35cc9e9..80ff4eb 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -15,6 +15,10 @@ #include "exfat_tools.h" #include "list.h" +#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) + enum fsck_ui_options { FSCK_OPTS_REPAIR = 0x01, }; @@ -138,11 +142,129 @@ static struct exfat *alloc_exfat(struct exfat_blk_dev *bd) static void free_exfat(struct exfat *exfat) { if (exfat) { - free(exfat->bs); + if (exfat->bs) + free(exfat->bs); free(exfat); } } +static int boot_region_checksum(struct exfat *exfat) +{ + __le32 checksum; + unsigned short size; + void *sect; + int i; + + size = EXFAT_SECTOR_SIZE(exfat->bs); + sect = malloc(size); + if (!sect) + return -ENOMEM; + + checksum = 0; + + boot_calc_checksum((unsigned char *)exfat->bs, size, true, &checksum); + for (i = 1; i < 11; i++) { + if (exfat_read(exfat->blk_dev->dev_fd, sect, size, i * size) != + (ssize_t)size) { + free(sect); + return -EIO; + } + boot_calc_checksum(sect, size, false, &checksum); + } + + if (exfat_read(exfat->blk_dev->dev_fd, sect, size, i * size) != + (ssize_t)size) { + free(sect); + return -EIO; + } + for (i = 0; i < size/sizeof(checksum); i++) { + if (le32_to_cpu(((__le32 *)sect)[i]) != checksum) { + exfat_err("invalid checksum. 0x%x\n", + le32_to_cpu(((__le32 *)sect)[i])); + free(sect); + return -EIO; + } + } + + free(sect); + return 0; +} + +static bool exfat_boot_region_check(struct exfat *exfat) +{ + struct pbr *bs; + ssize_t ret; + + bs = (struct pbr *)malloc(sizeof(struct pbr)); + if (!bs) { + exfat_err("failed to allocate memory\n"); + return false; + } + + exfat->bs = bs; + + ret = exfat_read(exfat->blk_dev->dev_fd, bs, sizeof(*bs), 0); + if (ret != sizeof(*bs)) { + exfat_err("failed to read a boot sector. %ld\n", ret); + goto err; + } + + if (memcmp(bs->bpb.oem_name, "EXFAT ", 8) != 0) { + exfat_err("failed to find exfat file system.\n"); + goto err; + } + + if (EXFAT_SECTOR_SIZE(bs) < 512) { + exfat_err("too small sector size: %d\n", EXFAT_SECTOR_SIZE(bs)); + goto err; + } + + if (EXFAT_CLUSTER_SIZE(bs) > 32U * 1024 * 1024) { + exfat_err("too big cluster size: %d\n", EXFAT_CLUSTER_SIZE(bs)); + goto err; + } + + ret = boot_region_checksum(exfat); + if (ret) { + exfat_err("failed to verify the checksum of a boot region. %ld\n", + ret); + goto err; + } + + if (bs->bsx.fs_version[1] != 1 || bs->bsx.fs_version[0] != 0) { + exfat_err("unsupported exfat version: %d.%d\n", + bs->bsx.fs_version[1], bs->bsx.fs_version[0]); + goto err; + } + + if (bs->bsx.num_fats != 1) { + exfat_err("unsupported FAT count: %d\n", bs->bsx.num_fats); + goto err; + } + + if (le64_to_cpu(bs->bsx.vol_length) * EXFAT_SECTOR_SIZE(bs) > + exfat->blk_dev->size) { + exfat_err("too large sector count: %llu\n, expected: %llu\n", + le64_to_cpu(bs->bsx.vol_length), + exfat->blk_dev->num_sectors); + goto err; + } + + if (le32_to_cpu(bs->bsx.clu_count) * EXFAT_CLUSTER_SIZE(bs) > + exfat->blk_dev->size) { + exfat_err("too large cluster count: %u, expected: %u\n", + le32_to_cpu(bs->bsx.clu_count), + exfat->blk_dev->num_clusters); + goto err; + } + + return true; +err: + free(bs); + exfat->bs = NULL; + return false; +} + void exfat_show_stat(struct exfat *exfat) { exfat_debug("Found directories: %ld\n", exfat_stat.dir_count); @@ -199,6 +321,12 @@ int main(int argc, char * const argv[]) goto err; } + exfat_debug("verifying boot regions...\n"); + if (!exfat_boot_region_check(exfat)) { + exfat_err("failed to verify boot regions.\n"); + goto err; + } + exfat_show_stat(exfat); err: free_exfat(exfat); diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 040e2f6..8a6db0f 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -34,7 +34,7 @@ struct exfat_blk_dev { unsigned long long size; unsigned int sector_size; unsigned int sector_size_bits; - unsigned int num_sectors; + unsigned long long num_sectors; unsigned int num_clusters; }; @@ -55,9 +55,10 @@ 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, unsigned int *checksum); + bool is_boot_sec, __le32 *checksum); 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); /* * Exfat Print diff --git a/lib/libexfat.c b/lib/libexfat.c index 888a860..cbb4995 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -81,16 +81,22 @@ wchar_t exfat_bad_char(wchar_t w) } void boot_calc_checksum(unsigned char *sector, unsigned short size, - bool is_boot_sec, unsigned int *checksum) + bool is_boot_sec, __le32 *checksum) { unsigned int index; - for (index = 0; index < size; index++) { - if (is_boot_sec == true && - ((index == 106) || (index == 107) || (index == 112))) - continue; - *checksum = ((*checksum & 1) ? 0x80000000 : 0) + - (*checksum >> 1) + sector[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]; + } } } @@ -157,7 +163,7 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, exfat_msg(EXFAT_DEBUG, "Block device name : %s\n", ui->dev_name); exfat_msg(EXFAT_DEBUG, "Block device size : %lld\n", bd->size); exfat_msg(EXFAT_DEBUG, "Block sector size : %u\n", bd->sector_size); - exfat_msg(EXFAT_DEBUG, "Number of the sectors : %u\n", + exfat_msg(EXFAT_DEBUG, "Number of the sectors : %llu\n", bd->num_sectors); exfat_msg(EXFAT_DEBUG, "Number of the clusters : %u\n", bd->num_clusters); @@ -167,3 +173,8 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, out: return ret; } + +ssize_t exfat_read(int fd, void *buf, size_t size, off_t offset) +{ + return pread(fd, buf, size, offset); +} -- cgit v1.2.3 From 75ed541a9b5f67503664c981b790e19b94fdc8e5 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 21:22:21 +0900 Subject: fsck: add printing boot sector information Add printing boot sector information Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index 80ff4eb..4efa90a 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -265,6 +265,21 @@ err: return false; } +void exfat_show_info(struct exfat *exfat) +{ + exfat_info("volume label [%s]\n", + exfat->volume_label); + exfat_info("Bytes per sector: %d\n", + 1 << le32_to_cpu(exfat->bs->bsx.sect_size_bits)); + exfat_info("Sectors per cluster: %d\n", + 1 << le32_to_cpu(exfat->bs->bsx.sect_per_clus_bits)); + exfat_info("Cluster heap count: %d(0x%x)\n", + le32_to_cpu(exfat->bs->bsx.clu_count), + le32_to_cpu(exfat->bs->bsx.clu_count)); + exfat_info("Cluster heap offset: %#x\n", + le32_to_cpu(exfat->bs->bsx.clu_offset)); +} + void exfat_show_stat(struct exfat *exfat) { exfat_debug("Found directories: %ld\n", exfat_stat.dir_count); @@ -327,6 +342,8 @@ int main(int argc, char * const argv[]) goto err; } + exfat_show_info(exfat); + exfat_show_stat(exfat); err: free_exfat(exfat); -- cgit v1.2.3 From 977ba2f0887ec6c3286ee4b89a7f579a08d7d0fb Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 21:26:27 +0900 Subject: fsck: add root directory check Add root directory check Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index 4efa90a..c0764b1 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -148,6 +148,62 @@ static void free_exfat(struct exfat *exfat) } } +static inline bool exfat_invalid_clus(struct exfat *exfat, clus_t clus) +{ + return clus < EXFAT_FIRST_CLUSTER || + (clus - EXFAT_FIRST_CLUSTER) > le32_to_cpu(exfat->bs->bsx.clu_count); +} + +static int node_get_clus_next(struct exfat *exfat, struct exfat_node *node, + clus_t clus, clus_t *next) +{ + off_t offset; + + if (exfat_invalid_clus(exfat, clus)) + return -EINVAL; + + if (node->is_contiguous) { + *next = clus + 1; + return 0; + } + + offset = le32_to_cpu(exfat->bs->bsx.fat_offset) << + exfat->bs->bsx.sect_size_bits; + offset += sizeof(clus_t) * clus; + + if (exfat_read(exfat->blk_dev->dev_fd, next, sizeof(*next), offset) + != sizeof(*next)) + return -EIO; + *next = le32_to_cpu(*next); + return 0; +} + +static bool node_get_clus_count(struct exfat *exfat, struct exfat_node *node, + clus_t *clus_count) +{ + clus_t clus; + + clus = node->first_clus; + *clus_count = 0; + + do { + if (exfat_invalid_clus(exfat, clus)) { + exfat_err("bad cluster. 0x%x\n", clus); + return false; + } + + if (node_get_clus_next(exfat, node, clus, &clus) != 0) { + exfat_err( + "broken cluster chain. (previous cluster 0x%x)\n", + clus); + return false; + } + + (*clus_count)++; + } while (clus != EXFAT_EOF_CLUSTER); + return true; +} + static int boot_region_checksum(struct exfat *exfat) { __le32 checksum; @@ -265,6 +321,36 @@ err: return false; } +static bool exfat_root_dir_check(struct exfat *exfat) +{ + struct exfat_node *root; + int ret; + clus_t clus_count; + + root = alloc_exfat_node(ATTR_SUBDIR); + if (!root) { + exfat_err("failed to allocate memory\n"); + return false; + } + + root->first_clus = le32_to_cpu(exfat->bs->bsx.root_cluster); + if (!node_get_clus_count(exfat, root, &clus_count)) { + exfat_err("failed to follow the cluster chain of root. %d\n", + ret); + goto err; + } + root->size = clus_count * EXFAT_CLUSTER_SIZE(exfat->bs); + + exfat->root = root; + exfat_debug("root directory: start cluster[0x%x] size[0x%llx]\n", + root->first_clus, root->size); + return true; +err: + free_exfat_node(root); + exfat->root = NULL; + return false; +} + void exfat_show_info(struct exfat *exfat) { exfat_info("volume label [%s]\n", @@ -344,6 +430,13 @@ int main(int argc, char * const argv[]) exfat_show_info(exfat); + exfat_debug("verifying root directory...\n"); + if (!exfat_root_dir_check(exfat)) { + exfat_err("failed to verify root directory.\n"); + goto out; + } + +out: exfat_show_stat(exfat); err: free_exfat(exfat); -- cgit v1.2.3 From aa9662ff7fe64346fdfa56cb6cc57c5a3ce8b1f9 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 21:42:17 +0900 Subject: fsck: add getting the path of a file Add getting the path of a file Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 92 +++++++++++++++++++++ include/exfat_tools.h | 6 ++ lib/Makefile.am | 2 +- lib/utf.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 lib/utf.c diff --git a/fsck/fsck.c b/fsck/fsck.c index c0764b1..a610666 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -69,7 +69,14 @@ struct exfat_stat { long file_free_count; }; +struct path_resolve_ctx { + struct exfat_node *ancestors[255]; + __le16 utf16_path[sizeof(__le16) * (PATH_MAX + 2)]; + char utf8_path[PATH_MAX * 3 + 1]; +}; + struct exfat_stat exfat_stat; +struct path_resolve_ctx path_resolve_ctx; static struct option opts[] = { {"version", no_argument, NULL, 'V' }, @@ -321,6 +328,91 @@ err: return false; } +/* + * get references of ancestors that include @child until the count of + * ancesters is not larger than @count and the count of characters of + * their names is not larger than @max_char_len. + * return true if root is reached. + */ +bool get_ancestors(struct exfat_node *child, + struct exfat_node **ancestors, int count, + int max_char_len, + int *ancestor_count) +{ + struct exfat_node *dir; + int name_len, char_len; + int root_depth, depth, i; + + root_depth = 0; + char_len = 0; + max_char_len += 1; + + dir = child; + while (dir) { + name_len = utf16_length(dir->name); + if (char_len + name_len > max_char_len) + break; + + /* include '/' */ + char_len += name_len + 1; + root_depth++; + + dir = dir->parent; + } + + depth = MIN(root_depth, count); + + for (dir = child, i = depth - 1; i >= 0; dir = dir->parent, i--) + ancestors[i] = dir; + + *ancestor_count = depth; + return dir == NULL; +} + +static int resolve_path(struct path_resolve_ctx *ctx, + struct exfat_node *child) +{ + int ret = 0; + int depth, i; + int name_len, path_len; + __le16 *utf16_path; + + ctx->utf8_path[0] = '\0'; + + get_ancestors(child, + ctx->ancestors, + sizeof(ctx->ancestors) / sizeof(ctx->ancestors[0]), + PATH_MAX, + &depth); + + utf16_path = ctx->utf16_path; + for (i = 0; i < depth; i++) { + name_len = utf16_length(ctx->ancestors[i]->name); + memcpy((char *)utf16_path, (char *)ctx->ancestors[i]->name, + name_len * 2); + utf16_path += name_len; + memcpy((char *)utf16_path, u"/", 2); + utf16_path += 1; + } + + ret = utf16_to_utf8(ctx->utf8_path, ctx->utf16_path, + sizeof(ctx->utf8_path), utf16_path - ctx->utf16_path - 1); + return ret; +} + +static int resolve_path_parent(struct path_resolve_ctx *ctx, + struct exfat_node *parent, struct exfat_node *child) +{ + int ret; + struct exfat_node *old; + + old = child->parent; + child->parent = parent; + + ret = resolve_path(ctx, child); + child->parent = old; + return ret; +} static bool exfat_root_dir_check(struct exfat *exfat) { struct exfat_node *root; diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 8a6db0f..9366654 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -60,6 +60,12 @@ 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); +int utf16_to_utf8(char *output, const __le16 *input, size_t outsize, + size_t insize); +int utf8_to_utf16(__le16 *output, const char *input, size_t outsize, + size_t insize); +size_t utf16_length(const __le16 *str); + /* * Exfat Print */ diff --git a/lib/Makefile.am b/lib/Makefile.am index 1c952b4..8a78446 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -2,4 +2,4 @@ AM_CFLAGS = -I$(top_srcdir)/include -fno-common lib_LTLIBRARIES = libexfat.la -libexfat_la_SOURCES = libexfat.c +libexfat_la_SOURCES = libexfat.c utf.c diff --git a/lib/utf.c b/lib/utf.c new file mode 100644 index 0000000..2d3d264 --- /dev/null +++ b/lib/utf.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * 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. + */ + +#include +#include +#include "exfat_ondisk.h" +#include "exfat_tools.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 *utf16_to_wchar(const __le16 *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; + } + + *wc = le16_to_cpu(*input); + return input + 1; +} + +int utf16_to_utf8(char *output, const __le16 *input, size_t outsize, + size_t insize) +{ + const __le16 *iptr = input; + const __le16 *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_err("illegal UTF-16 sequence"); + return -EILSEQ; + } + optr = wchar_to_utf8(optr, wc, oend - optr); + if (optr == NULL) { + exfat_err("name is too long"); + return -ENAMETOOLONG; + } + if (wc == 0) + return 0; + } + if (optr >= oend) { + exfat_err("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) +{ + if ((input[0] & 0x80) == 0 && insize >= 1) { + *wc = (wchar_t) input[0]; + return input + 1; + } + if ((input[0] & 0xe0) == 0xc0 && insize >= 2) { + *wc = (((wchar_t) input[0] & 0x1f) << 6) | + ((wchar_t) input[1] & 0x3f); + return input + 2; + } + if ((input[0] & 0xf0) == 0xe0 && insize >= 3) { + *wc = (((wchar_t) input[0] & 0x0f) << 12) | + (((wchar_t) input[1] & 0x3f) << 6) | + ((wchar_t) input[2] & 0x3f); + return input + 3; + } + if ((input[0] & 0xf8) == 0xf0 && insize >= 4) { + *wc = (((wchar_t) input[0] & 0x07) << 18) | + (((wchar_t) input[1] & 0x3f) << 12) | + (((wchar_t) input[2] & 0x3f) << 6) | + ((wchar_t) input[3] & 0x3f); + return input + 4; + } + if ((input[0] & 0xfc) == 0xf8 && insize >= 5) { + *wc = (((wchar_t) input[0] & 0x03) << 24) | + (((wchar_t) input[1] & 0x3f) << 18) | + (((wchar_t) input[2] & 0x3f) << 12) | + (((wchar_t) input[3] & 0x3f) << 6) | + ((wchar_t) input[4] & 0x3f); + return input + 5; + } + if ((input[0] & 0xfe) == 0xfc && insize >= 6) { + *wc = (((wchar_t) input[0] & 0x01) << 30) | + (((wchar_t) input[1] & 0x3f) << 24) | + (((wchar_t) input[2] & 0x3f) << 18) | + (((wchar_t) input[3] & 0x3f) << 12) | + (((wchar_t) input[4] & 0x3f) << 6) | + ((wchar_t) input[5] & 0x3f); + return input + 6; + } + return NULL; +} + +static __le16 *wchar_to_utf16(__le16 *output, wchar_t wc, size_t outsize) +{ + /* if character is from BMP */ + if (wc <= 0xffff) { + 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 utf8_to_utf16(__le16 *output, const char *input, size_t outsize, + size_t insize) +{ + const char *iptr = input; + const char *iend = input + insize; + __le16 *optr = output; + const __le16 *oend = output + outsize; + wchar_t wc; + + while (iptr < iend) { + iptr = utf8_to_wchar(iptr, &wc, iend - iptr); + if (iptr == NULL) { + exfat_err("illegal UTF-8 sequence"); + return -EILSEQ; + } + optr = wchar_to_utf16(optr, wc, oend - optr); + if (optr == NULL) { + exfat_err("name is too long"); + return -ENAMETOOLONG; + } + if (wc == 0) + break; + } + if (optr >= oend) { + exfat_err("name is too long"); + return -ENAMETOOLONG; + } + *optr = cpu_to_le16(0); + return 0; +} + +size_t utf16_length(const __le16 *str) +{ + size_t i = 0; + + while (le16_to_cpu(str[i])) + i++; + return i; +} -- cgit v1.2.3 From a11c48d68cbcf6604eb478432ad87eac0b438b0b Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 21:46:29 +0900 Subject: fsck: travel directories and files Travel directories and files Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/exfat_tools.h | 2 + 2 files changed, 123 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index a610666..9ef29d9 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -131,6 +131,55 @@ static void free_exfat_node(struct exfat_node *node) free(node); } +static void node_free_children(struct exfat_node *dir, bool file_only) +{ + struct exfat_node *node, *i; + + list_for_each_entry_safe(node, i, &dir->children, sibling) { + if (file_only) { + if (!(node->attr & ATTR_SUBDIR)) { + list_del(&node->sibling); + free_exfat_node(node); + } + } else { + list_del(&node->sibling); + list_del(&node->list); + free_exfat_node(node); + } + } +} + +static void node_free_file_children(struct exfat_node *dir) +{ + node_free_children(dir, true); +} + +/* delete @child and all ancestors that does not have + * children + */ +static void node_free_ancestors(struct exfat_node *child) +{ + struct exfat_node *parent, *node; + + if (!list_empty(&child->children)) + return; + + do { + if (!(child->attr & ATTR_SUBDIR)) { + exfat_err("not directory.\n"); + return; + } + + parent = child->parent; + list_del(&child->sibling); + free_exfat_node(child); + + child = parent; + } while (child && list_empty(&child->children)); + + return; +} + static struct exfat *alloc_exfat(struct exfat_blk_dev *bd) { struct exfat *exfat; @@ -155,6 +204,17 @@ static void free_exfat(struct exfat *exfat) } } +static void exfat_free_dir_list(struct exfat *exfat) +{ + struct exfat_node *dir, *file, *i, *k; + + list_for_each_entry_safe(dir, i, &exfat->dir_list, list) { + node_free_file_children(dir); + list_del(&dir->list); + free_exfat_node(dir); + } +} + static inline bool exfat_invalid_clus(struct exfat *exfat, clus_t clus) { return clus < EXFAT_FIRST_CLUSTER || @@ -413,6 +473,59 @@ static int resolve_path_parent(struct path_resolve_ctx *ctx, child->parent = old; return ret; } + +static int read_children(struct exfat *exfat, struct exfat_node *dir) +{ + return -1; +} + +/* + * for each directory in @dir_list. + * 1. read all dentries and allocate exfat_nodes for files and directories. + * and append directory exfat_nodes to the head of @dir_list + * 2. free all of file exfat_nodes. + * 3. if the directory does not have children, free its exfat_node. + */ +static bool exfat_filesystem_check(struct exfat *exfat) +{ + struct exfat_node *dir; + int ret; + + if (!exfat->root) { + exfat_err("root is NULL\n"); + return false; + } + + list_add(&exfat->root->list, &exfat->dir_list); + + while (!list_empty(&exfat->dir_list)) { + dir = list_entry(exfat->dir_list.next, struct exfat_node, list); + + if (!(dir->attr & ATTR_SUBDIR)) { + resolve_path(&path_resolve_ctx, dir); + exfat_err("failed to travel directories. " + "the node is not directory: %s\n", + path_resolve_ctx.utf8_path); + goto out; + } + + if (read_children(exfat, dir)) { + resolve_path(&path_resolve_ctx, dir); + exfat_err("failed to check dentries: %s\n", + path_resolve_ctx.utf8_path); + goto out; + } + + list_del(&dir->list); + node_free_file_children(dir); + node_free_ancestors(dir); + } +out: + exfat_free_dir_list(exfat); + exfat->root = NULL; + return false; +} + static bool exfat_root_dir_check(struct exfat *exfat) { struct exfat_node *root; @@ -528,6 +641,14 @@ int main(int argc, char * const argv[]) goto out; } + exfat_debug("verifying directory entries...\n"); + ret = exfat_filesystem_check(exfat); + if (ret) { + exfat_err("failed to verify directory entries. %d\n", ret); + goto out; + } + + printf("%s: clean\n", ui.ei.dev_name); out: exfat_show_stat(exfat); err: diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 9366654..91ac1ff 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -15,6 +15,8 @@ #define __round_mask(x, y) ((__typeof__(x))((y)-1)) #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) /* Upcase tabel macro */ #define EXFAT_UPCASE_TABLE_SIZE (5836) -- cgit v1.2.3 From c45109d3c24f26fca0d86c586e8d200f5e768bd5 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 21:54:08 +0900 Subject: fsck: add reading directory entries Add reading directory entries Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++- include/exfat_tools.h | 2 + 2 files changed, 242 insertions(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 9ef29d9..d494b82 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -52,12 +52,23 @@ struct exfat_node { #define UTF16_NAME_BUFFER_SIZE ((EXFAT_NAME_MAX + 1) * sizeof(__le16)) #define UTF8_NAME_BUFFER_SIZE (EXFAT_NAME_MAX * 3 + 1) +struct exfat_de_iter { + struct exfat *exfat; + struct exfat_node *parent; + unsigned char *dentries; /* cluster * 2 allocated */ + unsigned int read_size; /* cluster size */ + off_t de_file_offset; /* offset in dentries buffer */ + off_t next_read_offset; + int max_skip_dentries; +}; + struct exfat { struct exfat_blk_dev *blk_dev; struct pbr *bs; char volume_label[VOLUME_LABEL_MAX_LEN*3+1]; struct exfat_node *root; struct list_head dir_list; + struct exfat_de_iter de_iter; __u32 *alloc_bitmap; __u64 bit_count; }; @@ -271,6 +282,74 @@ static bool node_get_clus_count(struct exfat *exfat, struct exfat_node *node, return true; } +static off_t exfat_s2o(struct exfat *exfat, off_t sect) +{ + return sect << exfat->bs->bsx.sect_size_bits; +} + +static off_t exfat_c2o(struct exfat *exfat, unsigned int clus) +{ + if (clus < EXFAT_FIRST_CLUSTER) + return ~0ULL; + + return exfat_s2o(exfat, le32_to_cpu(exfat->bs->bsx.clu_offset) + + ((clus - EXFAT_FIRST_CLUSTER) << + exfat->bs->bsx.sect_per_clus_bits)); +} + +ssize_t exfat_file_read(struct exfat *exfat, struct exfat_node *node, + void *buf, size_t total_size, off_t file_offset) +{ + size_t clus_size; + clus_t start_l_clus, l_clus, p_clus; + unsigned int clus_offset; + int ret; + off_t device_offset; + ssize_t read_size; + size_t remain_size; + + if (file_offset >= node->size) + return EOF; + + clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); + total_size = MIN(total_size, node->size - file_offset); + remain_size = total_size; + + if (remain_size == 0) + return 0; + + p_clus = node->first_clus; + clus_offset = file_offset % clus_size; + start_l_clus = file_offset / clus_size; + l_clus = 0; + + while (p_clus != EXFAT_EOF_CLUSTER) { + if (exfat_invalid_clus(exfat, p_clus)) + return -EINVAL; + if (l_clus < start_l_clus) + goto next_clus; + + read_size = MIN(remain_size, clus_size - clus_offset); + device_offset = exfat_c2o(exfat, p_clus) + clus_offset; + if (exfat_read(exfat->blk_dev->dev_fd, buf, read_size, + device_offset) != read_size) + return -EIO; + + clus_offset = 0; + buf += read_size; + remain_size -= read_size; + if (remain_size == 0) + return total_size; + +next_clus: + l_clus++; + ret = node_get_clus_next(exfat, node, p_clus, &p_clus); + if (ret) + return ret; + } + return total_size - remain_size; +} + static int boot_region_checksum(struct exfat *exfat) { __le32 checksum; @@ -474,9 +553,169 @@ static int resolve_path_parent(struct path_resolve_ctx *ctx, return ret; } +int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, + struct exfat_node *dir) +{ + ssize_t ret; + + if (!iter->dentries) { + iter->read_size = EXFAT_CLUSTER_SIZE(exfat->bs); + iter->dentries = malloc(iter->read_size * 2); + if (!iter->dentries) { + exfat_err("failed to allocate memory\n"); + return -ENOMEM; + } + } + + ret = exfat_file_read(exfat, dir, iter->dentries, iter->read_size, 0); + if (ret != iter->read_size) { + exfat_err("failed to read directory entries.\n"); + return -EIO; + } + + iter->exfat = exfat; + iter->parent = dir; + iter->de_file_offset = 0; + iter->next_read_offset = iter->read_size; + iter->max_skip_dentries = 0; + return 0; +} + +void exfat_de_iter_fini(struct exfat_de_iter *iter) +{ + free(iter->dentries); +} + +int exfat_de_iter_get(struct exfat_de_iter *iter, + int ith, struct exfat_dentry **dentry) +{ + off_t de_next_file_offset; + int de_offset, de_next_offset; + bool need_read_1_clus = false, need_read_2_clus = false; + int ret; + + de_next_file_offset = iter->de_file_offset + + ith * sizeof(struct exfat_dentry); + + if (de_next_file_offset + sizeof(struct exfat_dentry) > + round_down(iter->parent->size, sizeof(struct exfat_dentry))) + return EOF; + + /* + * dentry must be in current cluster, or next cluster which + * will be read + */ + if (de_next_file_offset - + (iter->de_file_offset / iter->read_size) * iter->read_size >= + iter->read_size * 2) + return -ERANGE; + + de_offset = iter->de_file_offset % (iter->read_size * 2); + de_next_offset = de_next_file_offset % (iter->read_size * 2); + + /* read a cluster if needed */ + if (de_next_file_offset >= iter->next_read_offset) { + void *buf; + + need_read_1_clus = de_next_offset < iter->read_size; + need_read_2_clus = de_next_offset >= iter->read_size; + buf = need_read_1_clus ? + iter->dentries : iter->dentries + iter->read_size; + + ret = exfat_file_read(iter->exfat, iter->parent, buf, + iter->read_size, iter->next_read_offset); + if (ret == EOF) { + return EOF; + } else if (ret <= 0) { + exfat_err("failed to read a cluster. %d\n", ret); + 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->dentries + de_next_offset); + 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; +} + static int read_children(struct exfat *exfat, struct exfat_node *dir) { - return -1; + int ret; + struct exfat_node *node; + struct exfat_dentry *dentry; + int dentry_count; + struct list_head sub_dir_list; + struct exfat_de_iter *de_iter; + + INIT_LIST_HEAD(&sub_dir_list); + + de_iter = &exfat->de_iter; + ret = exfat_de_iter_init(de_iter, exfat, dir); + if (ret == EOF) + return 0; + else if (ret) + return ret; + + while (1) { + ret = exfat_de_iter_get(de_iter, 0, &dentry); + if (ret == EOF) { + break; + } else if (ret) { + exfat_err("failed to get a dentry. %d\n", ret); + goto err; + } + + dentry_count = 1; + + switch (dentry->type) { + case EXFAT_FILE: + break; + case EXFAT_VOLUME: + break; + case EXFAT_BITMAP: + break; + case EXFAT_UPCASE: + break; + default: + if (IS_EXFAT_DELETED(dentry->type) || + (dentry->type == EXFAT_UNUSED)) + break; + exfat_err("unknown entry type. 0x%x\n", dentry->type); + ret = -EINVAL; + goto err; + } + + exfat_de_iter_advance(de_iter, dentry_count); + } +out: + list_splice(&sub_dir_list, &exfat->dir_list); + return 0; +err: + node_free_children(dir, false); + INIT_LIST_HEAD(&dir->children); + return ret; } /* diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 91ac1ff..86cff39 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -15,6 +15,8 @@ #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)) -- cgit v1.2.3 From 81f1df3740644286b953223c006279a0e1354c7c Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jan 2020 22:02:45 +0900 Subject: fsck: add file check Add file check Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++ include/exfat_ondisk.h | 5 ++ include/exfat_tools.h | 2 + 3 files changed, 233 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index d494b82..f663708 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -256,6 +256,30 @@ static int node_get_clus_next(struct exfat *exfat, struct exfat_node *node, return 0; } +static bool node_check_clus_chain(struct exfat *exfat, struct exfat_node *node) +{ + clus_t clus; + clus_t clus_count; + + clus = node->first_clus; + clus_count = DIV_ROUND_UP(node->size, EXFAT_CLUSTER_SIZE(exfat->bs)); + + while (clus_count--) { + if (exfat_invalid_clus(exfat, clus)) { + exfat_err("bad cluster. 0x%x\n", clus); + return false; + } + + if (node_get_clus_next(exfat, node, clus, &clus) != 0) { + exfat_err( + "broken cluster chain. (previous cluster 0x%x)\n", + clus); + return false; + } + } + return true; +} + static bool node_get_clus_count(struct exfat *exfat, struct exfat_node *node, clus_t *clus_count) { @@ -660,6 +684,198 @@ off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter) return iter->de_file_offset; } +static bool check_node(struct exfat *exfat, struct exfat_node *parent, + struct exfat_node *node) +{ + int clus_count; + bool ret = false; + + if (node->size == 0 && node->first_clus != EXFAT_FREE_CLUSTER) { + resolve_path_parent(&path_resolve_ctx, parent, node); + exfat_err("file is empty, but first cluster is %#x: %s\n", + node->first_clus, path_resolve_ctx.utf8_path); + ret = false; + } + + if (node->size > 0 && exfat_invalid_clus(exfat, node->first_clus)) { + resolve_path_parent(&path_resolve_ctx, parent, node); + exfat_err("first cluster %#x is invalid: %s\n", + node->first_clus, path_resolve_ctx.utf8_path); + ret = false; + } + + if (node->size > le32_to_cpu(exfat->bs->bsx.clu_count) * + EXFAT_CLUSTER_SIZE(exfat->bs)) { + resolve_path_parent(&path_resolve_ctx, parent, node); + exfat_err("size %llu is greater than cluster heap: %s\n", + node->size, path_resolve_ctx.utf8_path); + ret = false; + } + + if (node->size == 0 && node->is_contiguous) { + resolve_path_parent(&path_resolve_ctx, parent, node); + exfat_err("empty, but marked as contiguous: %s\n", + path_resolve_ctx.utf8_path); + ret = false; + } + + if ((node->attr & ATTR_SUBDIR) && + node->size % EXFAT_CLUSTER_SIZE(exfat->bs) != 0) { + resolve_path_parent(&path_resolve_ctx, parent, node); + exfat_err("directory size %llu is not divisible by %d: %s\n", + node->size, EXFAT_CLUSTER_SIZE(exfat->bs), + path_resolve_ctx.utf8_path); + ret = false; + } + + if (!node->is_contiguous && !node_check_clus_chain(exfat, node)) { + resolve_path_parent(&path_resolve_ctx, parent, node); + exfat_err("corrupted cluster chain: %s\n", + path_resolve_ctx.utf8_path); + ret = false; + } + + return ret; +} + +static void dentry_calc_checksum(struct exfat_dentry *dentry, + __le16 *checksum, bool primary) +{ + int i; + uint8_t *bytes; + + bytes = (uint8_t *)dentry; + + *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[0]; + *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[1]; + + i = primary ? 4 : 2; + for (; i < sizeof(*dentry); i++) { + *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[i]; + } +} + +static __le16 file_calc_checksum(struct exfat_de_iter *iter) +{ + __le16 checksum; + struct exfat_dentry *file_de, *de; + int i; + + checksum = 0; + exfat_de_iter_get(iter, 0, &file_de); + + dentry_calc_checksum(file_de, &checksum, true); + for (i = 1; i <= file_de->file_num_ext; i++) { + exfat_de_iter_get(iter, i, &de); + dentry_calc_checksum(de, &checksum, false); + } + + return checksum; +} + +static int read_file_dentries(struct exfat_de_iter *iter, + struct exfat_node **new_node, int *skip_dentries) +{ + struct exfat_dentry *file_de, *stream_de, *name_de; + struct exfat_node *node; + int i, ret; + __le16 checksum; + + /* TODO: mtime, atime, ... */ + + ret = exfat_de_iter_get(iter, 0, &file_de); + if (ret || file_de->type != EXFAT_FILE) { + exfat_err("failed to get file dentry. %d\n", ret); + return ret; + } + ret = exfat_de_iter_get(iter, 1, &stream_de); + if (ret || stream_de->type != EXFAT_STREAM) { + exfat_err("failed to get stream dentry. %d\n", ret); + return ret; + } + + *new_node = NULL; + node = alloc_exfat_node(le16_to_cpu(file_de->file_attr)); + if (!node) + return -ENOMEM; + + if (file_de->file_num_ext < 2) { + exfat_err("too few secondary count. %d\n", + file_de->file_num_ext); + free_exfat_node(node); + return -EINVAL; + } + + for (i = 2; i <= file_de->file_num_ext; i++) { + ret = exfat_de_iter_get(iter, i, &name_de); + if (ret || name_de->type != EXFAT_NAME) { + exfat_err("failed to get name dentry. %d\n", ret); + goto err; + } + + memcpy(node->name + + (i-2) * ENTRY_NAME_MAX, name_de->name_unicode, + sizeof(name_de->name_unicode)); + } + + checksum = file_calc_checksum(iter); + if (file_de->file_checksum != checksum) { + exfat_err("invalid checksum. 0x%x != 0x%x\n", + le16_to_cpu(file_de->file_checksum), + le16_to_cpu(checksum)); + ret = -EINVAL; + goto err; + } + + node->size = le64_to_cpu(stream_de->stream_size); + node->first_clus = le32_to_cpu(stream_de->stream_start_clu); + node->is_contiguous = + ((stream_de->stream_flags & EXFAT_SF_CONTIGUOUS) != 0); + + if (le64_to_cpu(stream_de->stream_valid_size) > node->size) { + resolve_path_parent(&path_resolve_ctx, iter->parent, node); + exfat_err("valid size %llu greater than size %llu: %s\n", + le64_to_cpu(stream_de->stream_valid_size), node->size, + path_resolve_ctx.utf8_path); + goto err; + } + + *skip_dentries = (file_de->file_num_ext + 1); + *new_node = node; + return 0; +err: + *skip_dentries = 0; + *new_node = NULL; + free_exfat_node(node); + return ret; +} + +static int read_child(struct exfat_de_iter *de_iter, + struct exfat_node **new_node, int *dentry_count) +{ + struct exfat_node *node; + int ret; + + *new_node = NULL; + + ret = read_file_dentries(de_iter, &node, dentry_count); + if (ret) { + exfat_err("corrupted file directory entries.\n"); + return ret; + } + + ret = check_node(de_iter->exfat, de_iter->parent, node); + if (ret) { + exfat_err("corrupted file directory entries.\n"); + free_exfat_node(node); + return ret; + } + + node->dentry_file_offset = exfat_de_iter_file_offset(de_iter); + *new_node = node; + return 0; +} + static int read_children(struct exfat *exfat, struct exfat_node *dir) { int ret; @@ -691,6 +907,16 @@ static int read_children(struct exfat *exfat, struct exfat_node *dir) switch (dentry->type) { case EXFAT_FILE: + ret = read_child(de_iter, &node, &dentry_count); + if (ret) { + exfat_err("failed to verify file. %d\n", ret); + goto err; + } + + node->parent = dir; + list_add_tail(&node->sibling, &dir->children); + if ((node->attr & ATTR_SUBDIR) && node->size) + list_add_tail(&node->list, &sub_dir_list); break; case EXFAT_VOLUME: break; diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index e9c2e1d..0957a53 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -85,6 +85,9 @@ #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) @@ -140,6 +143,8 @@ struct expbr { }; #define VOLUME_LABEL_MAX_LEN 22 +#define ENTRY_NAME_MAX 15 + struct exfat_dentry { __u8 type; union { diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 86cff39..2f88c86 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -20,6 +20,8 @@ #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)) + /* Upcase tabel macro */ #define EXFAT_UPCASE_TABLE_SIZE (5836) -- cgit v1.2.3 From 9ee927f74dbd365027dbb89433dc08e84f4d8b15 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Sat, 25 Jan 2020 12:17:19 +0900 Subject: fsck: add volume label check Add volume label check Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index f663708..e1387d4 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -49,6 +49,7 @@ struct exfat_node { }; #define EXFAT_NAME_MAX 255 +#define EXFAT_VOLUME_LABEL_MAX 11 #define UTF16_NAME_BUFFER_SIZE ((EXFAT_NAME_MAX + 1) * sizeof(__le16)) #define UTF8_NAME_BUFFER_SIZE (EXFAT_NAME_MAX * 3 + 1) @@ -65,7 +66,7 @@ struct exfat_de_iter { struct exfat { struct exfat_blk_dev *blk_dev; struct pbr *bs; - char volume_label[VOLUME_LABEL_MAX_LEN*3+1]; + char volume_label[EXFAT_VOLUME_LABEL_MAX*3+1]; struct exfat_node *root; struct list_head dir_list; struct exfat_de_iter de_iter; @@ -876,6 +877,33 @@ static int read_child(struct exfat_de_iter *de_iter, return 0; } +static bool read_volume_label(struct exfat_de_iter *iter) +{ + __le16 label_name[EXFAT_VOLUME_LABEL_MAX]; + struct exfat_dentry *dentry; + + if (exfat_de_iter_get(iter, 0, &dentry)) + return false; + + if (dentry->vol_char_cnt == 0) + return true; + + if (dentry->vol_char_cnt > EXFAT_VOLUME_LABEL_MAX) { + exfat_err("too long label. %d\n", dentry->vol_char_cnt); + return false; + } + + memcpy(label_name, dentry->vol_label, sizeof(label_name)); + if (utf16_to_utf8(iter->exfat->volume_label, label_name, + sizeof(iter->exfat->volume_label), + EXFAT_VOLUME_LABEL_MAX) != 0) { + exfat_err("error at conversion between utf16/utf8.\n"); + return false; + } + + return true; +} + static int read_children(struct exfat *exfat, struct exfat_node *dir) { int ret; @@ -919,6 +947,10 @@ static int read_children(struct exfat *exfat, struct exfat_node *dir) list_add_tail(&node->list, &sub_dir_list); break; case EXFAT_VOLUME: + if (read_volume_label(de_iter)) { + exfat_err("failed to verify volume label\n"); + goto err; + } break; case EXFAT_BITMAP: break; -- cgit v1.2.3 From b23711de841471e441a190ae971ae398433b971c Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Sat, 25 Jan 2020 12:20:44 +0900 Subject: fsck: add bitmap check Add bitmap check Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index e1387d4..e1eb7d2 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -74,6 +74,25 @@ struct exfat { __u64 bit_count; }; +#if __BYTE_ORDER == __LITTLE_ENDIAN +typedef __u32 bitmap_t; +#elif __BYTE_ORDER == __BIG_ENDIAN +typedef __u8 bitmap_t; +#else +#error "__BYTE_ORDER is not defined" +#endif + +#define BITS_PER (sizeof(bitmap_t) * 8) +#define BIT_MASK(__c) (1 << ((__c) % BITS_PER)) +#define BIT_ENTRY(__c) ((__c) / BITS_PER) + +#define EXFAT_BITMAP_SIZE(__c_count) \ + (DIV_ROUND_UP(__c_count, BITS_PER) * sizeof(bitmap_t)) +#define EXFAT_BITMAP_GET(__bmap, __c) \ + ((__bmap)[BIT_ENTRY(__c)] & BIT_MASK(__c)) +#define EXFAT_BITMAP_SET(__bmap, __c) \ + ((__bmap)[BIT_ENTRY(__c)] |= BIT_MASK(__c)) + struct exfat_stat { long dir_count; long file_count; @@ -271,6 +290,14 @@ static bool node_check_clus_chain(struct exfat *exfat, struct exfat_node *node) return false; } + if (!EXFAT_BITMAP_GET(exfat->alloc_bitmap, + clus - EXFAT_FIRST_CLUSTER)) { + exfat_err( + "cluster allocated, but not in bitmap. 0x%x\n", + clus); + return false; + } + if (node_get_clus_next(exfat, node, clus, &clus) != 0) { exfat_err( "broken cluster chain. (previous cluster 0x%x)\n", @@ -904,6 +931,56 @@ static bool read_volume_label(struct exfat_de_iter *iter) return true; } +static bool read_alloc_bitmap(struct exfat_de_iter *iter) +{ + struct exfat_dentry *dentry; + struct exfat *exfat; + size_t alloc_bitmap_size; + + exfat = iter->exfat; + if (exfat_de_iter_get(iter, 0, &dentry)) + return false; + + exfat->bit_count = le32_to_cpu(exfat->bs->bsx.clu_count); + + if (le64_to_cpu(dentry->bitmap_size) < + DIV_ROUND_UP(exfat->bit_count, 8)) { + exfat_err("invalid size of allocation bitmap. 0x%llx\n", + le64_to_cpu(dentry->bitmap_size)); + return false; + } + if (exfat_invalid_clus(exfat, le32_to_cpu(dentry->bitmap_start_clu))) { + exfat_err("invalid start cluster of allocate bitmap. 0x%x\n", + le32_to_cpu(dentry->bitmap_start_clu)); + return false; + } + + exfat_debug("start cluster %#x, size %#llx\n", + le32_to_cpu(dentry->bitmap_start_clu), + le64_to_cpu(dentry->bitmap_size)); + + /* TODO: bitmap could be very large. */ + alloc_bitmap_size = EXFAT_BITMAP_SIZE(exfat->bit_count); + exfat->alloc_bitmap = (__u32 *)malloc(alloc_bitmap_size); + if (!exfat->alloc_bitmap) { + exfat_err("failed to allocate bitmap\n"); + return false; + } + + if (exfat_read(exfat->blk_dev->dev_fd, + exfat->alloc_bitmap, alloc_bitmap_size, + exfat_c2o(exfat, + le32_to_cpu(dentry->bitmap_start_clu))) != + alloc_bitmap_size) { + exfat_err("failed to read bitmap\n"); + free(exfat->alloc_bitmap); + exfat->alloc_bitmap = NULL; + return false; + } + + return true; +} + static int read_children(struct exfat *exfat, struct exfat_node *dir) { int ret; @@ -953,6 +1030,11 @@ static int read_children(struct exfat *exfat, struct exfat_node *dir) } break; case EXFAT_BITMAP: + if (!read_alloc_bitmap(de_iter)) { + exfat_err( + "failed to verify allocation bitmap\n"); + goto err; + } break; case EXFAT_UPCASE: break; -- cgit v1.2.3 From e2f6856fc4d66250c5cb2a51e83d10b26bffcb15 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 26 Jan 2020 20:33:10 +0900 Subject: exfat-tools: use exfat-tools version instead of fsck Signed-off-by: Namjae Jeon --- fsck/fsck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index e1eb7d2..8f8a795 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1191,7 +1191,7 @@ int main(int argc, char * const argv[]) if (optind != argc - 1) usage(argv[0]); - printf("fsck.ext4 %s\n", EXFAT_TOOLS_VERSION); + printf("exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); strncpy(ui.ei.dev_name, argv[optind], sizeof(ui.ei.dev_name)); ret = exfat_get_blk_dev_info(&ui.ei, &bd); -- cgit v1.2.3 From 46911e8a32da17c8a8a1a82be63bc71c512fb3d1 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 26 Jan 2020 23:37:57 +0900 Subject: exfat-tools: add volume label option support in mkfs Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 3 +++ lib/Makefile.am | 2 +- lib/libexfat.c | 31 +++++++++++++++++++++++++++++++ mkfs/mkfs.c | 42 +++++++++--------------------------------- 4 files changed, 44 insertions(+), 34 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 2f88c86..3ee32c5 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -51,6 +51,7 @@ struct exfat_user_input { unsigned int sec_per_clu; bool quick; char volume_label[22]; + int volume_label_len; }; void show_version(void); @@ -71,6 +72,8 @@ int utf16_to_utf8(char *output, const __le16 *input, size_t outsize, int utf8_to_utf16(__le16 *output, const char *input, size_t outsize, size_t insize); size_t utf16_length(const __le16 *str); +int exfat_convert_char_to_utf16s(char *src, size_t src_len, char *dest, + size_t dest_len); /* * Exfat Print diff --git a/lib/Makefile.am b/lib/Makefile.am index 8a78446..d1bd278 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,5 +1,5 @@ AM_CFLAGS = -I$(top_srcdir)/include -fno-common - +LIBS = -lc lib_LTLIBRARIES = libexfat.la libexfat_la_SOURCES = libexfat.c utf.c diff --git a/lib/libexfat.c b/lib/libexfat.c index cbb4995..e048877 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #include "exfat_ondisk.h" #include "exfat_tools.h" @@ -178,3 +181,31 @@ ssize_t exfat_read(int fd, void *buf, size_t size, off_t offset) { return pread(fd, buf, size, offset); } + +int exfat_convert_char_to_utf16s(char *src, size_t src_len, char *dest, + size_t dest_len) +{ + iconv_t it; +// size_t ch_len = strlen(ch), label_left_len = VOLUME_LABEL_MAX_LEN; + int ret; + + it = iconv_open("UTF-16", "UTF-8"); + if (it == (iconv_t) -1) { + exfat_msg(EXFAT_ERROR, "iconv_open failed\n"); + return -1; + } + + ret = iconv(it, &src, &src_len, &dest, &dest_len); + if (ret < 0) { + exfat_msg(EXFAT_ERROR, "iconv failed : %d, errno : %d\n", + ret, errno); + if (errno == 7) + exfat_msg(EXFAT_ERROR, + "Volume label string is too long\n"); + return -1; + } + + iconv_close(it); + + return dest_len; +} diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index ca47b42..86d4bc1 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "exfat_ondisk.h" #include "exfat_tools.h" @@ -360,8 +361,9 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, /* Set volume label entry */ ed[0].type = EXFAT_VOLUME; - strcpy(ed[0].vol_label, ui->volume_label); - ed[0].vol_char_cnt = 0; + 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; /* Set bitmap entry */ ed[1].type = EXFAT_BITMAP; @@ -553,39 +555,13 @@ int main(int argc, char *argv[]) switch (c) { case 'l': { - int i; - size_t mbslen; - wchar_t label[22]; - - mbslen = mbstowcs(NULL, optarg, 0); - if (mbslen == (size_t) -1) { - exfat_msg(EXFAT_ERROR, - "mbstowcs return error(%d)\n", errno); - goto out; - } - - if (mbslen > VOLUME_LABEL_MAX_LEN - 1) { - exfat_msg(EXFAT_ERROR, - "Volume Label is too longer(MAX 21 characters)\n"); - goto out; - } - - if (mbstowcs(label, optarg, mbslen + 1) == - (size_t) -1) { - exfat_msg(EXFAT_ERROR, - "mbstowcs return error(%d)\n", errno); + ret = exfat_convert_char_to_utf16s(optarg, + strlen(optarg), ui.volume_label, + VOLUME_LABEL_MAX_LEN); + if (ret < 0) goto out; - } - - for (i = 0; i < VOLUME_LABEL_MAX_LEN; i++) { - if (exfat_bad_char(label[i])) { - exfat_msg(EXFAT_ERROR, - "bad char error(%x)\n", - label[i]); - goto out; - } - } + ui.volume_label_len = VOLUME_LABEL_MAX_LEN - ret; break; } case 'c': -- cgit v1.2.3 From 77a8540bc1ed6051340df74bc164ea49cdc7f410 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 27 Jan 2020 14:37:58 +0900 Subject: exfat-tools: add exfat_convert_utf16s_to_char() Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 2 ++ lib/libexfat.c | 28 +++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 3ee32c5..8de7e62 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -74,6 +74,8 @@ int utf8_to_utf16(__le16 *output, const char *input, size_t outsize, size_t utf16_length(const __le16 *str); int exfat_convert_char_to_utf16s(char *src, size_t src_len, char *dest, size_t dest_len); +int exfat_convert_utf16s_to_char(char *src, size_t src_len, char *dest, + size_t dest_len); /* * Exfat Print diff --git a/lib/libexfat.c b/lib/libexfat.c index e048877..480f8ab 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -186,7 +186,6 @@ int exfat_convert_char_to_utf16s(char *src, size_t src_len, char *dest, size_t dest_len) { iconv_t it; -// size_t ch_len = strlen(ch), label_left_len = VOLUME_LABEL_MAX_LEN; int ret; it = iconv_open("UTF-16", "UTF-8"); @@ -209,3 +208,30 @@ int exfat_convert_char_to_utf16s(char *src, size_t src_len, char *dest, return dest_len; } + +int exfat_convert_utf16s_to_char(char *src, size_t src_len, char *dest, + size_t dest_len) +{ + iconv_t it; + int ret; + + it = iconv_open("UTF-8", "UTF-16"); + if (it == (iconv_t) -1) { + exfat_msg(EXFAT_ERROR, "iconv_open failed\n"); + return -1; + } + + ret = iconv(it, &src, &src_len, &dest, &dest_len); + if (ret < 0) { + exfat_msg(EXFAT_ERROR, "iconv failed : %d, errno : %d\n", + ret, errno); + if (errno == 7) + exfat_msg(EXFAT_ERROR, + "Volume label string is too long\n"); + return -1; + } + + iconv_close(it); + + return dest_len; +} -- cgit v1.2.3 From a67cfcf071033c88c32b3ed6b99b84fe69df747f Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 28 Jan 2020 11:06:52 +0900 Subject: exfat-tools: move KB/MB/GB to exfat_tools.h Signed-off-by: Hyunchul Lee --- include/exfat_tools.h | 12 ++++++++---- include/mkfs.h | 4 ---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 3ee32c5..10827f9 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -8,10 +8,9 @@ #include #include -#define EXFAT_MIN_NUM_SEC_VOL (2048) -#define EXFAT_MAX_NUM_SEC_VOL ((2 << 64) - 1) - -#define EXFAT_MAX_NUM_CLUSTER (0xFFFFFFF5) +#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) @@ -22,6 +21,11 @@ #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) + /* Upcase tabel macro */ #define EXFAT_UPCASE_TABLE_SIZE (5836) diff --git a/include/mkfs.h b/include/mkfs.h index b35af2b..c208fa8 100644 --- a/include/mkfs.h +++ b/include/mkfs.h @@ -10,10 +10,6 @@ #define MIN_NUM_SECTOR (2048) #define EXFAT_MAX_CLUSTER_SIZE (32*1024*1024) -#define KB (1024) -#define MB (1024*1024) -#define GB (1024UL*1024UL*1024UL) - struct exfat_mkfs_info { unsigned int total_clu_cnt; unsigned int used_clu_cnt; -- cgit v1.2.3 From 2d99dc83265bcf63e63106c4773309acc1cdd4f1 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 28 Jan 2020 11:34:37 +0900 Subject: fsck: sector size must be not larger than 4KB Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 8f8a795..f9acf87 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -468,12 +468,13 @@ static bool exfat_boot_region_check(struct exfat *exfat) goto err; } - if (EXFAT_SECTOR_SIZE(bs) < 512) { - exfat_err("too small sector size: %d\n", EXFAT_SECTOR_SIZE(bs)); + if (EXFAT_SECTOR_SIZE(bs) < 512 || EXFAT_SECTOR_SIZE(bs) > 4 * KB) { + exfat_err("too small or big sector size: %d\n", + EXFAT_SECTOR_SIZE(bs)); goto err; } - if (EXFAT_CLUSTER_SIZE(bs) > 32U * 1024 * 1024) { + if (EXFAT_CLUSTER_SIZE(bs) > 32 * MB) { exfat_err("too big cluster size: %d\n", EXFAT_CLUSTER_SIZE(bs)); goto err; } -- cgit v1.2.3 From 9c05767c1ec53edb2ec251a577bf23ff42aa78a7 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 28 Jan 2020 13:12:05 +0900 Subject: fsck: rename exfat_node to exfat_inode Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 123 +++++++++++++++++++++++++++++------------------------------- 1 file changed, 59 insertions(+), 64 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index f9acf87..519e179 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -30,13 +30,8 @@ struct fsck_user_input { typedef __u32 clus_t; -enum exfat_file_attr { - EXFAT_FA_NONE = 0x00, - EXFAT_FA_DIR = 0x01, -}; - -struct exfat_node { - struct exfat_node *parent; +struct exfat_inode { + struct exfat_inode *parent; struct list_head children; struct list_head sibling; struct list_head list; @@ -55,7 +50,7 @@ struct exfat_node { struct exfat_de_iter { struct exfat *exfat; - struct exfat_node *parent; + struct exfat_inode *parent; unsigned char *dentries; /* cluster * 2 allocated */ unsigned int read_size; /* cluster size */ off_t de_file_offset; /* offset in dentries buffer */ @@ -67,7 +62,7 @@ struct exfat { struct exfat_blk_dev *blk_dev; struct pbr *bs; char volume_label[EXFAT_VOLUME_LABEL_MAX*3+1]; - struct exfat_node *root; + struct exfat_inode *root; struct list_head dir_list; struct exfat_de_iter de_iter; __u32 *alloc_bitmap; @@ -101,7 +96,7 @@ struct exfat_stat { }; struct path_resolve_ctx { - struct exfat_node *ancestors[255]; + struct exfat_inode *ancestors[255]; __le16 utf16_path[sizeof(__le16) * (PATH_MAX + 2)]; char utf8_path[PATH_MAX * 3 + 1]; }; @@ -128,13 +123,13 @@ static void usage(char *name) exit(EXIT_FAILURE); } -static struct exfat_node *alloc_exfat_node(__u16 attr) +static struct exfat_inode *alloc_exfat_inode(__u16 attr) { - struct exfat_node *node; + struct exfat_inode *node; int size; - size = offsetof(struct exfat_node, name) + UTF16_NAME_BUFFER_SIZE; - node = (struct exfat_node *)calloc(1, size); + size = offsetof(struct exfat_inode, name) + UTF16_NAME_BUFFER_SIZE; + node = (struct exfat_inode *)calloc(1, size); if (!node) { exfat_err("failed to allocate exfat_node\n"); return NULL; @@ -153,7 +148,7 @@ static struct exfat_node *alloc_exfat_node(__u16 attr) return node; } -static void free_exfat_node(struct exfat_node *node) +static void free_exfat_inode(struct exfat_inode *node) { if (node->attr & ATTR_SUBDIR) exfat_stat.dir_free_count++; @@ -162,35 +157,35 @@ static void free_exfat_node(struct exfat_node *node) free(node); } -static void node_free_children(struct exfat_node *dir, bool file_only) +static void inode_free_children(struct exfat_inode *dir, bool file_only) { - struct exfat_node *node, *i; + struct exfat_inode *node, *i; list_for_each_entry_safe(node, i, &dir->children, sibling) { if (file_only) { if (!(node->attr & ATTR_SUBDIR)) { list_del(&node->sibling); - free_exfat_node(node); + free_exfat_inode(node); } } else { list_del(&node->sibling); list_del(&node->list); - free_exfat_node(node); + free_exfat_inode(node); } } } -static void node_free_file_children(struct exfat_node *dir) +static void inode_free_file_children(struct exfat_inode *dir) { - node_free_children(dir, true); + inode_free_children(dir, true); } /* delete @child and all ancestors that does not have * children */ -static void node_free_ancestors(struct exfat_node *child) +static void inode_free_ancestors(struct exfat_inode *child) { - struct exfat_node *parent, *node; + struct exfat_inode *parent, *node; if (!list_empty(&child->children)) return; @@ -203,7 +198,7 @@ static void node_free_ancestors(struct exfat_node *child) parent = child->parent; list_del(&child->sibling); - free_exfat_node(child); + free_exfat_inode(child); child = parent; } while (child && list_empty(&child->children)); @@ -237,12 +232,12 @@ static void free_exfat(struct exfat *exfat) static void exfat_free_dir_list(struct exfat *exfat) { - struct exfat_node *dir, *file, *i, *k; + struct exfat_inode *dir, *file, *i, *k; list_for_each_entry_safe(dir, i, &exfat->dir_list, list) { - node_free_file_children(dir); + inode_free_file_children(dir); list_del(&dir->list); - free_exfat_node(dir); + free_exfat_inode(dir); } } @@ -252,7 +247,7 @@ static inline bool exfat_invalid_clus(struct exfat *exfat, clus_t clus) (clus - EXFAT_FIRST_CLUSTER) > le32_to_cpu(exfat->bs->bsx.clu_count); } -static int node_get_clus_next(struct exfat *exfat, struct exfat_node *node, +static int inode_get_clus_next(struct exfat *exfat, struct exfat_inode *node, clus_t clus, clus_t *next) { off_t offset; @@ -276,7 +271,7 @@ static int node_get_clus_next(struct exfat *exfat, struct exfat_node *node, return 0; } -static bool node_check_clus_chain(struct exfat *exfat, struct exfat_node *node) +static bool inode_check_clus_chain(struct exfat *exfat, struct exfat_inode *node) { clus_t clus; clus_t clus_count; @@ -298,7 +293,7 @@ static bool node_check_clus_chain(struct exfat *exfat, struct exfat_node *node) return false; } - if (node_get_clus_next(exfat, node, clus, &clus) != 0) { + if (inode_get_clus_next(exfat, node, clus, &clus) != 0) { exfat_err( "broken cluster chain. (previous cluster 0x%x)\n", clus); @@ -308,7 +303,7 @@ static bool node_check_clus_chain(struct exfat *exfat, struct exfat_node *node) return true; } -static bool node_get_clus_count(struct exfat *exfat, struct exfat_node *node, +static bool inode_get_clus_count(struct exfat *exfat, struct exfat_inode *node, clus_t *clus_count) { clus_t clus; @@ -322,7 +317,7 @@ static bool node_get_clus_count(struct exfat *exfat, struct exfat_node *node, return false; } - if (node_get_clus_next(exfat, node, clus, &clus) != 0) { + if (inode_get_clus_next(exfat, node, clus, &clus) != 0) { exfat_err( "broken cluster chain. (previous cluster 0x%x)\n", clus); @@ -349,7 +344,7 @@ static off_t exfat_c2o(struct exfat *exfat, unsigned int clus) exfat->bs->bsx.sect_per_clus_bits)); } -ssize_t exfat_file_read(struct exfat *exfat, struct exfat_node *node, +static ssize_t exfat_file_read(struct exfat *exfat, struct exfat_inode *node, void *buf, size_t total_size, off_t file_offset) { size_t clus_size; @@ -395,7 +390,7 @@ ssize_t exfat_file_read(struct exfat *exfat, struct exfat_node *node, next_clus: l_clus++; - ret = node_get_clus_next(exfat, node, p_clus, &p_clus); + ret = inode_get_clus_next(exfat, node, p_clus, &p_clus); if (ret) return ret; } @@ -526,12 +521,12 @@ err: * their names is not larger than @max_char_len. * return true if root is reached. */ -bool get_ancestors(struct exfat_node *child, - struct exfat_node **ancestors, int count, +bool get_ancestors(struct exfat_inode *child, + struct exfat_inode **ancestors, int count, int max_char_len, int *ancestor_count) { - struct exfat_node *dir; + struct exfat_inode *dir; int name_len, char_len; int root_depth, depth, i; @@ -562,7 +557,7 @@ bool get_ancestors(struct exfat_node *child, } static int resolve_path(struct path_resolve_ctx *ctx, - struct exfat_node *child) + struct exfat_inode *child) { int ret = 0; int depth, i; @@ -593,10 +588,10 @@ static int resolve_path(struct path_resolve_ctx *ctx, } static int resolve_path_parent(struct path_resolve_ctx *ctx, - struct exfat_node *parent, struct exfat_node *child) + struct exfat_inode *parent, struct exfat_inode *child) { int ret; - struct exfat_node *old; + struct exfat_inode *old; old = child->parent; child->parent = parent; @@ -607,7 +602,7 @@ static int resolve_path_parent(struct path_resolve_ctx *ctx, } int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, - struct exfat_node *dir) + struct exfat_inode *dir) { ssize_t ret; @@ -713,8 +708,8 @@ off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter) return iter->de_file_offset; } -static bool check_node(struct exfat *exfat, struct exfat_node *parent, - struct exfat_node *node) +static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, + struct exfat_inode *node) { int clus_count; bool ret = false; @@ -757,7 +752,7 @@ static bool check_node(struct exfat *exfat, struct exfat_node *parent, ret = false; } - if (!node->is_contiguous && !node_check_clus_chain(exfat, node)) { + if (!node->is_contiguous && !inode_check_clus_chain(exfat, node)) { resolve_path_parent(&path_resolve_ctx, parent, node); exfat_err("corrupted cluster chain: %s\n", path_resolve_ctx.utf8_path); @@ -803,10 +798,10 @@ static __le16 file_calc_checksum(struct exfat_de_iter *iter) } static int read_file_dentries(struct exfat_de_iter *iter, - struct exfat_node **new_node, int *skip_dentries) + struct exfat_inode **new_node, int *skip_dentries) { struct exfat_dentry *file_de, *stream_de, *name_de; - struct exfat_node *node; + struct exfat_inode *node; int i, ret; __le16 checksum; @@ -824,14 +819,14 @@ static int read_file_dentries(struct exfat_de_iter *iter, } *new_node = NULL; - node = alloc_exfat_node(le16_to_cpu(file_de->file_attr)); + node = alloc_exfat_inode(le16_to_cpu(file_de->file_attr)); if (!node) return -ENOMEM; if (file_de->file_num_ext < 2) { exfat_err("too few secondary count. %d\n", file_de->file_num_ext); - free_exfat_node(node); + free_exfat_inode(node); return -EINVAL; } @@ -875,14 +870,14 @@ static int read_file_dentries(struct exfat_de_iter *iter, err: *skip_dentries = 0; *new_node = NULL; - free_exfat_node(node); + free_exfat_inode(node); return ret; } static int read_child(struct exfat_de_iter *de_iter, - struct exfat_node **new_node, int *dentry_count) + struct exfat_inode **new_node, int *dentry_count) { - struct exfat_node *node; + struct exfat_inode *node; int ret; *new_node = NULL; @@ -893,10 +888,10 @@ static int read_child(struct exfat_de_iter *de_iter, return ret; } - ret = check_node(de_iter->exfat, de_iter->parent, node); + ret = check_inode(de_iter->exfat, de_iter->parent, node); if (ret) { exfat_err("corrupted file directory entries.\n"); - free_exfat_node(node); + free_exfat_inode(node); return ret; } @@ -982,10 +977,10 @@ static bool read_alloc_bitmap(struct exfat_de_iter *iter) return true; } -static int read_children(struct exfat *exfat, struct exfat_node *dir) +static int read_children(struct exfat *exfat, struct exfat_inode *dir) { int ret; - struct exfat_node *node; + struct exfat_inode *node; struct exfat_dentry *dentry; int dentry_count; struct list_head sub_dir_list; @@ -1054,7 +1049,7 @@ out: list_splice(&sub_dir_list, &exfat->dir_list); return 0; err: - node_free_children(dir, false); + inode_free_children(dir, false); INIT_LIST_HEAD(&dir->children); return ret; } @@ -1068,7 +1063,7 @@ err: */ static bool exfat_filesystem_check(struct exfat *exfat) { - struct exfat_node *dir; + struct exfat_inode *dir; int ret; if (!exfat->root) { @@ -1079,7 +1074,7 @@ static bool exfat_filesystem_check(struct exfat *exfat) list_add(&exfat->root->list, &exfat->dir_list); while (!list_empty(&exfat->dir_list)) { - dir = list_entry(exfat->dir_list.next, struct exfat_node, list); + dir = list_entry(exfat->dir_list.next, struct exfat_inode, list); if (!(dir->attr & ATTR_SUBDIR)) { resolve_path(&path_resolve_ctx, dir); @@ -1097,8 +1092,8 @@ static bool exfat_filesystem_check(struct exfat *exfat) } list_del(&dir->list); - node_free_file_children(dir); - node_free_ancestors(dir); + inode_free_file_children(dir); + inode_free_ancestors(dir); } out: exfat_free_dir_list(exfat); @@ -1108,18 +1103,18 @@ out: static bool exfat_root_dir_check(struct exfat *exfat) { - struct exfat_node *root; + struct exfat_inode *root; int ret; clus_t clus_count; - root = alloc_exfat_node(ATTR_SUBDIR); + root = alloc_exfat_inode(ATTR_SUBDIR); if (!root) { exfat_err("failed to allocate memory\n"); return false; } root->first_clus = le32_to_cpu(exfat->bs->bsx.root_cluster); - if (!node_get_clus_count(exfat, root, &clus_count)) { + if (!inode_get_clus_count(exfat, root, &clus_count)) { exfat_err("failed to follow the cluster chain of root. %d\n", ret); goto err; @@ -1131,7 +1126,7 @@ static bool exfat_root_dir_check(struct exfat *exfat) root->first_clus, root->size); return true; err: - free_exfat_node(root); + free_exfat_inode(root); exfat->root = NULL; return false; } -- cgit v1.2.3 From 786204ba2858a4219fd6643b209764c859c028e9 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 28 Jan 2020 14:36:32 +0900 Subject: fsck: exit with the exit code in FSCK(8) fsck needs to follow the exit code in FSCK(8) manpage. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 519e179..0ae18b3 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -88,6 +88,15 @@ typedef __u8 bitmap_t; #define EXFAT_BITMAP_SET(__bmap, __c) \ ((__bmap)[BIT_ENTRY(__c)] |= BIT_MASK(__c)) +#define FSCK_EXIT_NO_ERRORS 0x00 +#define FSCK_EXIT_CORRECTED 0x01 +#define FSCK_EXIT_NEED_REBOOT 0x02 +#define FSCK_EXIT_ERRORS_LEFT 0x04 +#define FSCK_EXIT_OPERATION_ERROR 0x08 +#define FSCK_EXIT_SYNTAX_ERROR 0x10 +#define FSCK_EXIT_USER_CANCEL 0x20 +#define FSCK_EXIT_LIBRARY_ERROR 0x80 + struct exfat_stat { long dir_count; long file_count; @@ -120,7 +129,7 @@ static void usage(char *name) fprintf(stderr, "\t-v | --verbose Print debug\n"); fprintf(stderr, "\t-h | --help Show help\n"); - exit(EXIT_FAILURE); + exit(FSCK_EXIT_SYNTAX_ERROR); } static struct exfat_inode *alloc_exfat_inode(__u16 attr) @@ -1193,18 +1202,19 @@ int main(int argc, char * const argv[]) ret = exfat_get_blk_dev_info(&ui.ei, &bd); if (ret < 0) { exfat_err("failed to open %s. %d\n", ui.ei.dev_name, ret); - return ret; + return FSCK_EXIT_OPERATION_ERROR; } exfat = alloc_exfat(&bd); if (!exfat) { - ret = -ENOMEM; + ret = FSCK_EXIT_OPERATION_ERROR; goto err; } exfat_debug("verifying boot regions...\n"); if (!exfat_boot_region_check(exfat)) { exfat_err("failed to verify boot regions.\n"); + ret = FSCK_EXIT_ERRORS_LEFT; goto err; } @@ -1213,6 +1223,7 @@ int main(int argc, char * const argv[]) exfat_debug("verifying root directory...\n"); if (!exfat_root_dir_check(exfat)) { exfat_err("failed to verify root directory.\n"); + ret = FSCK_EXIT_ERRORS_LEFT; goto out; } @@ -1220,10 +1231,12 @@ int main(int argc, char * const argv[]) ret = exfat_filesystem_check(exfat); if (ret) { exfat_err("failed to verify directory entries. %d\n", ret); + ret = FSCK_EXIT_ERRORS_LEFT; goto out; } printf("%s: clean\n", ui.ei.dev_name); + ret = FSCK_EXIT_NO_ERRORS; out: exfat_show_stat(exfat); err: -- cgit v1.2.3 From df6000833e775be188d0c336efdfe6240dad1eac Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 28 Jan 2020 15:02:11 +0900 Subject: fsck: free exfat_inode immediately if file does not have children, verify the file and free its exfat_inode immediately. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 0ae18b3..0b2d576 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1023,10 +1023,12 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) goto err; } - node->parent = dir; - list_add_tail(&node->sibling, &dir->children); - if ((node->attr & ATTR_SUBDIR) && node->size) + if ((node->attr & ATTR_SUBDIR) && node->size) { + node->parent = dir; + list_add_tail(&node->sibling, &dir->children); list_add_tail(&node->list, &sub_dir_list); + } else + free_exfat_inode(node); break; case EXFAT_VOLUME: if (read_volume_label(de_iter)) { -- cgit v1.2.3 From 90f5ce310d86104944bdcabf7c9371f17a15c312 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 28 Jan 2020 17:59:24 +0900 Subject: tools: remove duplicate "exfat-tools version: ..." message Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 7 +++++-- lib/libexfat.c | 1 - mkfs/mkfs.c | 8 ++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 0b2d576..b4f741e 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1173,6 +1173,7 @@ int main(int argc, char * const argv[]) struct fsck_user_input ui = {0,}; struct exfat_blk_dev bd = {0,}; struct exfat *exfat = NULL; + bool version_only = false; opterr = 0; while ((c = getopt_long(argc, argv, "Vvh", opts, NULL)) != EOF) { @@ -1182,7 +1183,7 @@ int main(int argc, char * const argv[]) ui.ei.writeable = true; break; case 'V': - show_version(); + version_only = true; break; case 'v': if (print_level < EXFAT_DEBUG) @@ -1198,7 +1199,9 @@ int main(int argc, char * const argv[]) if (optind != argc - 1) usage(argv[0]); - printf("exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); + show_version(); + if (version_only) + exit(FSCK_EXIT_SYNTAX_ERROR); strncpy(ui.ei.dev_name, argv[optind], sizeof(ui.ei.dev_name)); ret = exfat_get_blk_dev_info(&ui.ei, &bd); diff --git a/lib/libexfat.c b/lib/libexfat.c index e048877..de761f0 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -106,7 +106,6 @@ void boot_calc_checksum(unsigned char *sector, unsigned short size, void show_version(void) { printf("exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); - exit(EXIT_FAILURE); } static inline unsigned int sector_size_bits(unsigned int size) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 86d4bc1..8623c02 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -547,6 +547,7 @@ int main(int argc, char *argv[]) char *blk_dev_name; struct exfat_blk_dev bd; struct exfat_user_input ui; + bool version_only = false; init_user_input(&ui); @@ -577,7 +578,7 @@ int main(int argc, char *argv[]) ui.quick = false; break; case 'V': - show_version(); + version_only = true; break; case 'v': print_level = EXFAT_DEBUG; @@ -591,10 +592,13 @@ int main(int argc, char *argv[]) if (argc - optind != 1) usage(); + show_version(); + if (version_only) + exit(EXIT_FAILURE); + memset(ui.dev_name, 0, 255); strncpy(ui.dev_name, argv[optind], 255); - printf("exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); ret = exfat_get_blk_dev_info(&ui, &bd); if (ret < 0) goto out; -- cgit v1.2.3 From cfbcc164d35b1da7375122b664c208773da5627f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 28 Jan 2020 22:12:05 +0900 Subject: exfat-tools: add -l volume label option in README file Signed-off-by: Namjae Jeon --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d56fec5..003c565 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ Usage example: mkfs.exfat -c 128 /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 - fsck.exfat(Preparing): Check the consistency of your exfat filesystem and optinally repair a corrupted device formatted by exfat. -- cgit v1.2.3 From 2f713c2a34349d0226d423f253da6ff28a618992 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 31 Jan 2020 11:19:29 +0900 Subject: tools: implement character conversion library Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 58 ++++++++----- include/exfat_iconv.h | 31 +++++++ include/exfat_ondisk.h | 4 +- include/exfat_tools.h | 10 --- include/list.h | 2 - lib/Makefile.am | 2 +- lib/exfat_iconv.c | 82 ++++++++++++++++++ lib/libexfat.c | 54 ------------ lib/utf.c | 219 ------------------------------------------------- mkfs/mkfs.c | 23 ++++-- 10 files changed, 169 insertions(+), 316 deletions(-) create mode 100644 include/exfat_iconv.h create mode 100644 lib/exfat_iconv.c delete mode 100644 lib/utf.c diff --git a/fsck/fsck.c b/fsck/fsck.c index b4f741e..4d3e29d 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -13,6 +13,7 @@ #include "exfat_ondisk.h" #include "exfat_tools.h" +#include "exfat_iconv.h" #include "list.h" #define EXFAT_CLUSTER_SIZE(pbr) (1 << ((pbr)->bsx.sect_size_bits + \ @@ -43,10 +44,11 @@ struct exfat_inode { __le16 name[0]; /* only for directory */ }; -#define EXFAT_NAME_MAX 255 -#define EXFAT_VOLUME_LABEL_MAX 11 -#define UTF16_NAME_BUFFER_SIZE ((EXFAT_NAME_MAX + 1) * sizeof(__le16)) -#define UTF8_NAME_BUFFER_SIZE (EXFAT_NAME_MAX * 3 + 1) +#define EXFAT_NAME_MAX 255 +#define VOLUME_LABEL_BUFFER_SIZE (EXFAT_DECSTR_MAX_BUFSIZE( \ + VOLUME_LABEL_MAX_LEN)) +#define NAME_BUFFER_SIZE (EXFAT_ENCSTR_MAX_BUFSIZE( \ + EXFAT_NAME_MAX)) struct exfat_de_iter { struct exfat *exfat; @@ -61,7 +63,7 @@ struct exfat_de_iter { struct exfat { struct exfat_blk_dev *blk_dev; struct pbr *bs; - char volume_label[EXFAT_VOLUME_LABEL_MAX*3+1]; + char volume_label[VOLUME_LABEL_BUFFER_SIZE]; struct exfat_inode *root; struct list_head dir_list; struct exfat_de_iter de_iter; @@ -112,6 +114,7 @@ struct path_resolve_ctx { struct exfat_stat exfat_stat; struct path_resolve_ctx path_resolve_ctx; +struct exfat_iconv exfat_iconv; static struct option opts[] = { {"version", no_argument, NULL, 'V' }, @@ -137,7 +140,7 @@ static struct exfat_inode *alloc_exfat_inode(__u16 attr) struct exfat_inode *node; int size; - size = offsetof(struct exfat_inode, name) + UTF16_NAME_BUFFER_SIZE; + size = offsetof(struct exfat_inode, name) + NAME_BUFFER_SIZE; node = (struct exfat_inode *)calloc(1, size); if (!node) { exfat_err("failed to allocate exfat_node\n"); @@ -545,7 +548,8 @@ bool get_ancestors(struct exfat_inode *child, dir = child; while (dir) { - name_len = utf16_length(dir->name); + name_len = exfat_iconv_encstr_len((char *)dir->name, + NAME_BUFFER_SIZE); if (char_len + name_len > max_char_len) break; @@ -565,13 +569,13 @@ bool get_ancestors(struct exfat_inode *child, return dir == NULL; } -static int resolve_path(struct path_resolve_ctx *ctx, - struct exfat_inode *child) +static int resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child) { int ret = 0; int depth, i; int name_len, path_len; __le16 *utf16_path; + size_t in_size; ctx->utf8_path[0] = '\0'; @@ -583,17 +587,22 @@ static int resolve_path(struct path_resolve_ctx *ctx, utf16_path = ctx->utf16_path; for (i = 0; i < depth; i++) { - name_len = utf16_length(ctx->ancestors[i]->name); + name_len = exfat_iconv_encstr_len( + (char *)ctx->ancestors[i]->name, + NAME_BUFFER_SIZE); memcpy((char *)utf16_path, (char *)ctx->ancestors[i]->name, name_len * 2); utf16_path += name_len; memcpy((char *)utf16_path, u"/", 2); - utf16_path += 1; + utf16_path++; } - ret = utf16_to_utf8(ctx->utf8_path, ctx->utf16_path, - sizeof(ctx->utf8_path), utf16_path - ctx->utf16_path - 1); - return ret; + if (depth > 0) + utf16_path--; + in_size = (utf16_path - ctx->utf16_path) * sizeof(__le16); + return exfat_iconv_dec(&exfat_iconv, + (char *)ctx->utf16_path, in_size, + (char *)ctx->utf8_path, sizeof(ctx->utf8_path)); } static int resolve_path_parent(struct path_resolve_ctx *ctx, @@ -911,28 +920,27 @@ static int read_child(struct exfat_de_iter *de_iter, static bool read_volume_label(struct exfat_de_iter *iter) { - __le16 label_name[EXFAT_VOLUME_LABEL_MAX]; + struct exfat *exfat; struct exfat_dentry *dentry; + exfat = iter->exfat; if (exfat_de_iter_get(iter, 0, &dentry)) return false; if (dentry->vol_char_cnt == 0) return true; - if (dentry->vol_char_cnt > EXFAT_VOLUME_LABEL_MAX) { + if (dentry->vol_char_cnt > VOLUME_LABEL_MAX_LEN) { exfat_err("too long label. %d\n", dentry->vol_char_cnt); return false; } - memcpy(label_name, dentry->vol_label, sizeof(label_name)); - if (utf16_to_utf8(iter->exfat->volume_label, label_name, - sizeof(iter->exfat->volume_label), - EXFAT_VOLUME_LABEL_MAX) != 0) { - exfat_err("error at conversion between utf16/utf8.\n"); + if (exfat_iconv_dec(&exfat_iconv, + (char *)dentry->vol_label, sizeof(dentry->vol_label), + (char *)exfat->volume_label, sizeof(exfat->volume_label))) { + exfat_err("failed to decode volume label\n"); return false; } - return true; } @@ -1203,6 +1211,11 @@ int main(int argc, char * const argv[]) if (version_only) exit(FSCK_EXIT_SYNTAX_ERROR); + if (exfat_iconv_open(&exfat_iconv) < 0) { + exfat_err("failed to init iconv\n"); + return FSCK_EXIT_OPERATION_ERROR; + } + strncpy(ui.ei.dev_name, argv[optind], sizeof(ui.ei.dev_name)); ret = exfat_get_blk_dev_info(&ui.ei, &bd); if (ret < 0) { @@ -1247,5 +1260,6 @@ out: err: free_exfat(exfat); close(bd.dev_fd); + exfat_iconv_close(&exfat_iconv); return ret; } diff --git a/include/exfat_iconv.h b/include/exfat_iconv.h new file mode 100644 index 0000000..a97bf80 --- /dev/null +++ b/include/exfat_iconv.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Hyunchul Lee + */ +#ifndef _EXFAT_ICONV_H +#define _EXFAT_ICONV_H + +#include + +/* length to byte size */ +#define EXFAT_ENCSTR_MAX_BUFSIZE(__len) (((__len) + 1) * 2) /* UTF-16 */ +#define EXFAT_DECSTR_MAX_BUFSIZE(__len) ((__len) * 3 + 1) /* UTF-8 */ + +struct exfat_iconv { + iconv_t enc_cd; + iconv_t dec_cd; + const char *enc_charset; + const char *dec_charset; +}; + +int exfat_iconv_open(struct exfat_iconv *ei); +void exfat_iconv_close(struct exfat_iconv *ei); + +int exfat_iconv_enc(struct exfat_iconv *ei, char *in_str, size_t in_size, + char *out_str, size_t out_size); +int exfat_iconv_dec(struct exfat_iconv *ei, char *in_str, size_t in_size, + char *out_str, size_t out_size); + +int exfat_iconv_encstr_len(char *in_str, size_t in_size); + +#endif diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index 0957a53..422d494 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -142,7 +142,7 @@ struct expbr { struct exbs eb[8]; }; -#define VOLUME_LABEL_MAX_LEN 22 +#define VOLUME_LABEL_MAX_LEN 11 #define ENTRY_NAME_MAX 15 struct exfat_dentry { @@ -150,7 +150,7 @@ struct exfat_dentry { union { struct { __u8 character_count; - __u8 volume_label[22]; + __le16 volume_label[VOLUME_LABEL_MAX_LEN]; __u8 reserved[8]; } __attribute__((packed)) vol; /* file directory entry */ diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 8b23e51..2ab9599 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -71,16 +71,6 @@ 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); -int utf16_to_utf8(char *output, const __le16 *input, size_t outsize, - size_t insize); -int utf8_to_utf16(__le16 *output, const char *input, size_t outsize, - size_t insize); -size_t utf16_length(const __le16 *str); -int exfat_convert_char_to_utf16s(char *src, size_t src_len, char *dest, - size_t dest_len); -int exfat_convert_utf16s_to_char(char *src, size_t src_len, char *dest, - size_t dest_len); - /* * Exfat Print */ diff --git a/include/list.h b/include/list.h index 6d887e4..7fc3d64 100644 --- a/include/list.h +++ b/include/list.h @@ -9,8 +9,6 @@ const typeof(((type *)0)->member) * __mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); \ }) -/*@}*/ - /* * These are non-NULL pointers that will result in page faults diff --git a/lib/Makefile.am b/lib/Makefile.am index d1bd278..ebd7485 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -2,4 +2,4 @@ AM_CFLAGS = -I$(top_srcdir)/include -fno-common LIBS = -lc lib_LTLIBRARIES = libexfat.la -libexfat_la_SOURCES = libexfat.c utf.c +libexfat_la_SOURCES = libexfat.c exfat_iconv.c diff --git a/lib/exfat_iconv.c b/lib/exfat_iconv.c new file mode 100644 index 0000000..b0838bf --- /dev/null +++ b/lib/exfat_iconv.c @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Hyunchul Lee + */ + +#include +#include +#include + +#include "exfat_ondisk.h" +#include "exfat_tools.h" +#include "exfat_iconv.h" + +int exfat_iconv_open(struct exfat_iconv *ei) +{ + ei->enc_charset = "UTF-16LE"; + ei->dec_charset = "UTF-8"; + + ei->enc_cd = iconv_open(ei->enc_charset, ei->dec_charset); + if (ei->enc_cd == (iconv_t)-1) + goto err; + + ei->dec_cd = iconv_open(ei->dec_charset, ei->enc_charset); + if (ei->dec_cd == (iconv_t)-1) { + iconv_close(ei->enc_cd); + goto err; + } + + return 0; +err: + if (errno == EINVAL) + exfat_err("conversion between %s and %s is not avaiable\n", + ei->enc_charset, ei->dec_charset); + else + exfat_err("error at iconv_open: %d\n", -errno); + return -errno; +} + +void exfat_iconv_close(struct exfat_iconv *ei) +{ + iconv_close(ei->enc_cd); + iconv_close(ei->dec_cd); +} + +static int iconv_conv(iconv_t cd, char *in_str, size_t in_size, + char *out_str, size_t out_size) +{ + size_t size = out_size; + + if (iconv(cd, &in_str, &in_size, &out_str, &size) < 0) { + if (errno == E2BIG) + exfat_err("input string is too long\n"); + else if (errno == EINVAL || errno == EILSEQ) + exfat_err("invaild character sequence\n"); + return -errno; + } + if (size > 0) + *out_str = '\0'; + return out_size - size; +} + +int exfat_iconv_enc(struct exfat_iconv *ei, char *in_str, size_t in_size, + char *out_str, size_t out_size) +{ + return iconv_conv(ei->enc_cd, in_str, in_size, out_str, out_size); +} + +int exfat_iconv_dec(struct exfat_iconv *ei, char *in_str, size_t in_size, + char *out_str, size_t out_size) +{ + return iconv_conv(ei->dec_cd, in_str, in_size, out_str, out_size); +} + +int exfat_iconv_encstr_len(char *in_str, size_t in_size) +{ + size_t i = 0; + __le16 *str = (__le16 *)in_str; + + while (le16_to_cpu(str[i]) && i < in_size/2) + i++; + return i; +} diff --git a/lib/libexfat.c b/lib/libexfat.c index 8babf31..854241f 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -180,57 +180,3 @@ ssize_t exfat_read(int fd, void *buf, size_t size, off_t offset) { return pread(fd, buf, size, offset); } - -int exfat_convert_char_to_utf16s(char *src, size_t src_len, char *dest, - size_t dest_len) -{ - iconv_t it; - int ret; - - it = iconv_open("UTF-16", "UTF-8"); - if (it == (iconv_t) -1) { - exfat_msg(EXFAT_ERROR, "iconv_open failed\n"); - return -1; - } - - ret = iconv(it, &src, &src_len, &dest, &dest_len); - if (ret < 0) { - exfat_msg(EXFAT_ERROR, "iconv failed : %d, errno : %d\n", - ret, errno); - if (errno == 7) - exfat_msg(EXFAT_ERROR, - "Volume label string is too long\n"); - return -1; - } - - iconv_close(it); - - return dest_len; -} - -int exfat_convert_utf16s_to_char(char *src, size_t src_len, char *dest, - size_t dest_len) -{ - iconv_t it; - int ret; - - it = iconv_open("UTF-8", "UTF-16"); - if (it == (iconv_t) -1) { - exfat_msg(EXFAT_ERROR, "iconv_open failed\n"); - return -1; - } - - ret = iconv(it, &src, &src_len, &dest, &dest_len); - if (ret < 0) { - exfat_msg(EXFAT_ERROR, "iconv failed : %d, errno : %d\n", - ret, errno); - if (errno == 7) - exfat_msg(EXFAT_ERROR, - "Volume label string is too long\n"); - return -1; - } - - iconv_close(it); - - return dest_len; -} diff --git a/lib/utf.c b/lib/utf.c deleted file mode 100644 index 2d3d264..0000000 --- a/lib/utf.c +++ /dev/null @@ -1,219 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * 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. - */ - -#include -#include -#include "exfat_ondisk.h" -#include "exfat_tools.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 *utf16_to_wchar(const __le16 *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; - } - - *wc = le16_to_cpu(*input); - return input + 1; -} - -int utf16_to_utf8(char *output, const __le16 *input, size_t outsize, - size_t insize) -{ - const __le16 *iptr = input; - const __le16 *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_err("illegal UTF-16 sequence"); - return -EILSEQ; - } - optr = wchar_to_utf8(optr, wc, oend - optr); - if (optr == NULL) { - exfat_err("name is too long"); - return -ENAMETOOLONG; - } - if (wc == 0) - return 0; - } - if (optr >= oend) { - exfat_err("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) -{ - if ((input[0] & 0x80) == 0 && insize >= 1) { - *wc = (wchar_t) input[0]; - return input + 1; - } - if ((input[0] & 0xe0) == 0xc0 && insize >= 2) { - *wc = (((wchar_t) input[0] & 0x1f) << 6) | - ((wchar_t) input[1] & 0x3f); - return input + 2; - } - if ((input[0] & 0xf0) == 0xe0 && insize >= 3) { - *wc = (((wchar_t) input[0] & 0x0f) << 12) | - (((wchar_t) input[1] & 0x3f) << 6) | - ((wchar_t) input[2] & 0x3f); - return input + 3; - } - if ((input[0] & 0xf8) == 0xf0 && insize >= 4) { - *wc = (((wchar_t) input[0] & 0x07) << 18) | - (((wchar_t) input[1] & 0x3f) << 12) | - (((wchar_t) input[2] & 0x3f) << 6) | - ((wchar_t) input[3] & 0x3f); - return input + 4; - } - if ((input[0] & 0xfc) == 0xf8 && insize >= 5) { - *wc = (((wchar_t) input[0] & 0x03) << 24) | - (((wchar_t) input[1] & 0x3f) << 18) | - (((wchar_t) input[2] & 0x3f) << 12) | - (((wchar_t) input[3] & 0x3f) << 6) | - ((wchar_t) input[4] & 0x3f); - return input + 5; - } - if ((input[0] & 0xfe) == 0xfc && insize >= 6) { - *wc = (((wchar_t) input[0] & 0x01) << 30) | - (((wchar_t) input[1] & 0x3f) << 24) | - (((wchar_t) input[2] & 0x3f) << 18) | - (((wchar_t) input[3] & 0x3f) << 12) | - (((wchar_t) input[4] & 0x3f) << 6) | - ((wchar_t) input[5] & 0x3f); - return input + 6; - } - return NULL; -} - -static __le16 *wchar_to_utf16(__le16 *output, wchar_t wc, size_t outsize) -{ - /* if character is from BMP */ - if (wc <= 0xffff) { - 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 utf8_to_utf16(__le16 *output, const char *input, size_t outsize, - size_t insize) -{ - const char *iptr = input; - const char *iend = input + insize; - __le16 *optr = output; - const __le16 *oend = output + outsize; - wchar_t wc; - - while (iptr < iend) { - iptr = utf8_to_wchar(iptr, &wc, iend - iptr); - if (iptr == NULL) { - exfat_err("illegal UTF-8 sequence"); - return -EILSEQ; - } - optr = wchar_to_utf16(optr, wc, oend - optr); - if (optr == NULL) { - exfat_err("name is too long"); - return -ENAMETOOLONG; - } - if (wc == 0) - break; - } - if (optr >= oend) { - exfat_err("name is too long"); - return -ENAMETOOLONG; - } - *optr = cpu_to_le16(0); - return 0; -} - -size_t utf16_length(const __le16 *str) -{ - size_t i = 0; - - while (le16_to_cpu(str[i])) - i++; - return i; -} diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 8623c02..db003eb 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -20,6 +20,7 @@ #include "exfat_ondisk.h" #include "exfat_tools.h" #include "mkfs.h" +#include "exfat_iconv.h" struct exfat_mkfs_info finfo; @@ -363,7 +364,8 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, 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; + ed[0].vol_char_cnt = exfat_iconv_encstr_len(ui->volume_label, + ui->volume_label_len); /* Set bitmap entry */ ed[1].type = EXFAT_BITMAP; @@ -548,21 +550,27 @@ int main(int argc, char *argv[]) struct exfat_blk_dev bd; struct exfat_user_input ui; bool version_only = false; + struct exfat_iconv exfat_iconv; init_user_input(&ui); + if (exfat_iconv_open(&exfat_iconv) < 0) { + exfat_msg(EXFAT_ERROR, "failed to init iconv\n"); + return EXIT_FAILURE; + } + opterr = 0; while ((c = getopt_long(argc, argv, "l:c:fVvh", opts, NULL)) != EOF) switch (c) { case 'l': { - ret = exfat_convert_char_to_utf16s(optarg, - strlen(optarg), ui.volume_label, - VOLUME_LABEL_MAX_LEN); + ret = exfat_iconv_enc(&exfat_iconv, optarg, + strlen(optarg), ui.volume_label, + sizeof(ui.volume_label)); if (ret < 0) goto out; - ui.volume_label_len = VOLUME_LABEL_MAX_LEN - ret; + ui.volume_label_len = ret; break; } case 'c': @@ -589,8 +597,10 @@ int main(int argc, char *argv[]) usage(); } - if (argc - optind != 1) + if (argc - optind != 1) { + exfat_iconv_close(&exfat_iconv); usage(); + } show_version(); if (version_only) @@ -622,6 +632,7 @@ out: exfat_msg(EXFAT_INFO, "\nexFAT format complete!\n"); else exfat_msg(EXFAT_INFO, "\nexFAT format fail!\n"); + exfat_iconv_close(&exfat_iconv); close(bd.dev_fd); return ret; } -- cgit v1.2.3 From ba251030f27869685c9c657fe6136ac122e6d6bb Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 1 Feb 2020 11:26:07 +0900 Subject: exfat-utils: rename repo name to exfat-utils Signed-off-by: Namjae Jeon --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 003c565..f04c913 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -## exfat-tools ? -Exfat-tools is mkfs(format)/fsck(repair) implementation for exfat filesystem under GNU GPL version 2. +## exfat-utils ? +Exfat-utils is mkfs(format)/fsck(repair) implementation for exfat filesystem under GNU GPL version 2. ## Maintainers * Namjae Jeon * Hyunchul Lee -## Buidling exfat tools +## Buidling exfat-utils Install preprequisite packages: ``` For Ubuntu: @@ -18,14 +18,14 @@ Install preprequisite packages: Build steps: ``` - cd into the exfat-tools directory + cd into the exfat-utils directory ./autogen.sh ./configure make make install ``` -## Using exFAT tools +## Using exfat-utils ``` - mkfs.exfat: Build a exfat filesystem on a device or partition(e.g. /dev/hda1, dev/sda1). -- cgit v1.2.3 From c8e7fea346c57faca8432c4dc193e558b6231f0a Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 3 Feb 2020 10:53:53 +0900 Subject: fsck: fix volume label check Fix volume label check Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 4d3e29d..d92088a 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -937,10 +937,12 @@ static bool read_volume_label(struct exfat_de_iter *iter) if (exfat_iconv_dec(&exfat_iconv, (char *)dentry->vol_label, sizeof(dentry->vol_label), - (char *)exfat->volume_label, sizeof(exfat->volume_label))) { + (char *)exfat->volume_label, sizeof(exfat->volume_label)) < 0) { exfat_err("failed to decode volume label\n"); return false; } + + exfat_info("volume label [%s]\n", exfat->volume_label); return true; } @@ -1039,7 +1041,7 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) free_exfat_inode(node); break; case EXFAT_VOLUME: - if (read_volume_label(de_iter)) { + if (!read_volume_label(de_iter)) { exfat_err("failed to verify volume label\n"); goto err; } @@ -1152,8 +1154,6 @@ err: void exfat_show_info(struct exfat *exfat) { - exfat_info("volume label [%s]\n", - exfat->volume_label); exfat_info("Bytes per sector: %d\n", 1 << le32_to_cpu(exfat->bs->bsx.sect_size_bits)); exfat_info("Sectors per cluster: %d\n", -- cgit v1.2.3 From cc58e9286572ae57d05ab04b6e2eaa5e3d311d34 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 3 Feb 2020 11:00:45 +0900 Subject: fsck: set default print level to EXFAT_ERROR Set default print level to EXFAT_ERROR Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index d92088a..73f4156 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1183,6 +1183,8 @@ int main(int argc, char * const argv[]) struct exfat *exfat = NULL; bool version_only = false; + print_level = EXFAT_ERROR; + opterr = 0; while ((c = getopt_long(argc, argv, "Vvh", opts, NULL)) != EOF) { switch (c) { -- cgit v1.2.3 From a802951f2973870b2b054a35271db5ec9f5cf48b Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 3 Feb 2020 17:28:24 +0900 Subject: tools: add exfat_write function Add exfat_write function. Signed-off-by: Hyunchul Lee --- include/exfat_tools.h | 1 + lib/libexfat.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 2ab9599..45de4aa 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -70,6 +70,7 @@ void boot_calc_checksum(unsigned char *sector, unsigned short size, 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); /* * Exfat Print diff --git a/lib/libexfat.c b/lib/libexfat.c index 854241f..1177cf0 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -180,3 +180,8 @@ 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); +} -- cgit v1.2.3 From 7601682f291345b66f445f8eb5b4e4ae054a0d90 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 3 Feb 2020 17:31:27 +0900 Subject: fsck: move structures to fsck.h Move structures to fsck.h Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 48 +----------------------------------------------- fsck/fsck.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 47 deletions(-) create mode 100644 fsck/fsck.h diff --git a/fsck/fsck.c b/fsck/fsck.c index 73f4156..ba567a6 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -14,11 +14,7 @@ #include "exfat_ondisk.h" #include "exfat_tools.h" #include "exfat_iconv.h" -#include "list.h" - -#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) +#include "fsck.h" enum fsck_ui_options { FSCK_OPTS_REPAIR = 0x01, @@ -29,48 +25,6 @@ struct fsck_user_input { enum fsck_ui_options options; }; -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; - __u16 attr; - __u64 size; - bool is_contiguous; - off_t dentry_file_offset; - __le16 name[0]; /* only for directory */ -}; - -#define EXFAT_NAME_MAX 255 -#define VOLUME_LABEL_BUFFER_SIZE (EXFAT_DECSTR_MAX_BUFSIZE( \ - VOLUME_LABEL_MAX_LEN)) -#define NAME_BUFFER_SIZE (EXFAT_ENCSTR_MAX_BUFSIZE( \ - EXFAT_NAME_MAX)) - -struct exfat_de_iter { - struct exfat *exfat; - struct exfat_inode *parent; - unsigned char *dentries; /* cluster * 2 allocated */ - unsigned int read_size; /* cluster size */ - off_t de_file_offset; /* offset in dentries buffer */ - off_t next_read_offset; - int max_skip_dentries; -}; - -struct exfat { - 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; - struct exfat_de_iter de_iter; - __u32 *alloc_bitmap; - __u64 bit_count; -}; - #if __BYTE_ORDER == __LITTLE_ENDIAN typedef __u32 bitmap_t; #elif __BYTE_ORDER == __BIG_ENDIAN diff --git a/fsck/fsck.h b/fsck/fsck.h new file mode 100644 index 0000000..6d4279f --- /dev/null +++ b/fsck/fsck.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Hyunchul Lee + */ +#ifndef _FSCK_H +#define _FSCK_H + +#include "exfat_iconv.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; + __u16 attr; + __u64 size; + bool is_contiguous; + off_t dentry_file_offset; + __le16 name[0]; /* only for directory */ +}; + +#define EXFAT_NAME_MAX 255 +#define VOLUME_LABEL_BUFFER_SIZE (EXFAT_DECSTR_MAX_BUFSIZE( \ + VOLUME_LABEL_MAX_LEN)) +#define NAME_BUFFER_SIZE (EXFAT_ENCSTR_MAX_BUFSIZE( \ + EXFAT_NAME_MAX)) + +struct exfat_de_iter { + struct exfat *exfat; + struct exfat_inode *parent; + unsigned char *dentries; /* cluster * 2 allocated */ + unsigned int read_size; /* cluster size */ + off_t de_file_offset; /* offset in dentries buffer */ + off_t next_read_offset; + int max_skip_dentries; +}; + +struct exfat { + 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; + struct exfat_de_iter de_iter; + __u32 *alloc_bitmap; + __u64 bit_count; +}; + +#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) + +#endif -- cgit v1.2.3 From eb404de32942d414fd859a66960cb59b70a18e44 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 3 Feb 2020 17:32:43 +0900 Subject: fsck: repair the incorrect checksum of a boot region Repair the incorrect checksum of a boot region Signed-off-by: Hyunchul Lee --- fsck/Makefile.am | 2 +- fsck/fsck.c | 17 ++++++++--- fsck/repair.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fsck/repair.h | 22 ++++++++++++++ 4 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 fsck/repair.c create mode 100644 fsck/repair.h diff --git a/fsck/Makefile.am b/fsck/Makefile.am index 6397dbe..d75e3c5 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -3,4 +3,4 @@ fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = fsck.exfat -fsck_exfat_SOURCES = fsck.c +fsck_exfat_SOURCES = fsck.c repair.c diff --git a/fsck/fsck.c b/fsck/fsck.c index ba567a6..a6f5e1d 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -15,6 +15,7 @@ #include "exfat_tools.h" #include "exfat_iconv.h" #include "fsck.h" +#include "repair.h" enum fsck_ui_options { FSCK_OPTS_REPAIR = 0x01, @@ -71,6 +72,7 @@ struct path_resolve_ctx path_resolve_ctx; struct exfat_iconv exfat_iconv; static struct option opts[] = { + {"repair", no_argument, NULL, 'r' }, {"version", no_argument, NULL, 'V' }, {"verbose", no_argument, NULL, 'v' }, {"help", no_argument, NULL, 'h' }, @@ -394,10 +396,16 @@ static int boot_region_checksum(struct exfat *exfat) } for (i = 0; i < size/sizeof(checksum); i++) { if (le32_to_cpu(((__le32 *)sect)[i]) != checksum) { - exfat_err("invalid checksum. 0x%x\n", + union exfat_repair_context rctx = { + .bs_checksum.checksum = checksum, + .bs_checksum.checksum_sect = sect, + }; + if (!exfat_repair(exfat, ER_BS_CHECKSUM, &rctx)) { + exfat_err("invalid checksum. 0x%x\n", le32_to_cpu(((__le32 *)sect)[i])); - free(sect); - return -EIO; + free(sect); + return -EIO; + } } } @@ -1140,7 +1148,7 @@ int main(int argc, char * const argv[]) print_level = EXFAT_ERROR; opterr = 0; - while ((c = getopt_long(argc, argv, "Vvh", opts, NULL)) != EOF) { + while ((c = getopt_long(argc, argv, "rVvh", opts, NULL)) != EOF) { switch (c) { case 'r': ui.options |= FSCK_OPTS_REPAIR; @@ -1209,6 +1217,7 @@ int main(int argc, char * const argv[]) goto out; } + fsync(bd.dev_fd); printf("%s: clean\n", ui.ei.dev_name); ret = FSCK_EXIT_NO_ERRORS; out: diff --git a/fsck/repair.c b/fsck/repair.c new file mode 100644 index 0000000..e8574fe --- /dev/null +++ b/fsck/repair.c @@ -0,0 +1,93 @@ +#include +#include + +#include "exfat_ondisk.h" +#include "exfat_tools.h" +#include "fsck.h" +#include "repair.h" + +struct exfat_repair_problem { + er_problem_code_t prcode; + const char *description; + bool (*fix_problem)(struct exfat *exfat, + struct exfat_repair_problem *pr, + union exfat_repair_context *rctx); +}; + +static bool fix_bs_checksum(struct exfat *exfat, + struct exfat_repair_problem *pr, + union exfat_repair_context *rctx) +{ + unsigned int size; + int i; + + size = EXFAT_SECTOR_SIZE(exfat->bs); + for (i = 0; i < size/sizeof(__le32); i++) { + ((__le32 *)rctx->bs_checksum.checksum_sect)[i] = + rctx->bs_checksum.checksum; + } + + if (exfat_write(exfat->blk_dev->dev_fd, + rctx->bs_checksum.checksum_sect, + size, size * 11) != size) { + exfat_err("failed to write checksum sector\n"); + return false; + } + + return true; +} + +static struct exfat_repair_problem problems[] = { + {ER_BS_CHECKSUM, + "the checksum of boot sector is not correct", + fix_bs_checksum}, +}; + +static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) +{ + 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) +{ + char answer[8]; + + do { + printf("%s: Fix (y/N)?", pr->description); + 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); + + return false; +} + +bool exfat_repair(struct exfat *exfat, er_problem_code_t prcode, + union exfat_repair_context *rctx) +{ + struct exfat_repair_problem *pr = NULL; + int need_repair; + + pr = find_problem(prcode); + if (!pr) { + exfat_err("unknown problem code. %#x\n", prcode); + return false; + } + + need_repair = ask_repair(exfat, pr); + if (need_repair) + return pr->fix_problem(exfat, pr, rctx); +} diff --git a/fsck/repair.h b/fsck/repair.h new file mode 100644 index 0000000..4c56763 --- /dev/null +++ b/fsck/repair.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Hyunchul Lee + */ +#ifndef _REPAIR_H +#define _REPAIR_H + +#define ER_BS_CHECKSUM 0x00000001 + +typedef unsigned int er_problem_code_t; + +union exfat_repair_context { + struct { + __le32 checksum; + void *checksum_sect; + } bs_checksum; +}; + +bool exfat_repair(struct exfat *exfat, er_problem_code_t prcode, + union exfat_repair_context *rctx); + +#endif -- cgit v1.2.3 From 8ac552891bbbe91c2ed41b6e736fc1ebd6812cd9 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 10 Feb 2020 14:15:34 +0900 Subject: fsck: add repair options Add repair options, "-y" and "-n". Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 38 +++++++++++++++++++++++++++----------- fsck/fsck.h | 8 ++++++++ fsck/repair.c | 43 +++++++++++++++++++++++++++---------------- 3 files changed, 62 insertions(+), 27 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index a6f5e1d..eb31a53 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -17,10 +17,6 @@ #include "fsck.h" #include "repair.h" -enum fsck_ui_options { - FSCK_OPTS_REPAIR = 0x01, -}; - struct fsck_user_input { struct exfat_user_input ei; enum fsck_ui_options options; @@ -73,6 +69,8 @@ struct exfat_iconv exfat_iconv; static struct option opts[] = { {"repair", no_argument, NULL, 'r' }, + {"repair-yes", no_argument, NULL, 'y' }, + {"repair-no", no_argument, NULL, 'n' }, {"version", no_argument, NULL, 'V' }, {"verbose", no_argument, NULL, 'v' }, {"help", no_argument, NULL, 'h' }, @@ -83,10 +81,12 @@ static struct option opts[] = { static void usage(char *name) { fprintf(stderr, "Usage: %s\n", name); - fprintf(stderr, "\t-r | --repair Repair\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"); + fprintf(stderr, "\t-r | --repair Repair interactively\n"); + fprintf(stderr, "\t-y | --repair-yes Repair without ask\n"); + fprintf(stderr, "\t-n | --repair-no No repair\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(FSCK_EXIT_SYNTAX_ERROR); } @@ -1148,10 +1148,24 @@ int main(int argc, char * const argv[]) print_level = EXFAT_ERROR; opterr = 0; - while ((c = getopt_long(argc, argv, "rVvh", opts, NULL)) != EOF) { + while ((c = getopt_long(argc, argv, "rynVvh", opts, NULL)) != EOF) { switch (c) { + case 'n': + if (ui.options & FSCK_OPTS_REPAIR) + usage(argv[0]); + ui.options |= FSCK_OPTS_REPAIR_NO; + ui.ei.writeable = false; + break; case 'r': - ui.options |= FSCK_OPTS_REPAIR; + if (ui.options & FSCK_OPTS_REPAIR) + usage(argv[0]); + ui.options |= FSCK_OPTS_REPAIR_ASK; + ui.ei.writeable = true; + break; + case 'y': + if (ui.options & FSCK_OPTS_REPAIR) + usage(argv[0]); + ui.options |= FSCK_OPTS_REPAIR_YES; ui.ei.writeable = true; break; case 'V': @@ -1192,6 +1206,7 @@ int main(int argc, char * const argv[]) ret = FSCK_EXIT_OPERATION_ERROR; goto err; } + exfat->options = ui.options; exfat_debug("verifying boot regions...\n"); if (!exfat_boot_region_check(exfat)) { @@ -1217,7 +1232,8 @@ int main(int argc, char * const argv[]) goto out; } - fsync(bd.dev_fd); + if (ui.ei.writeable) + fsync(bd.dev_fd); printf("%s: clean\n", ui.ei.dev_name); ret = FSCK_EXIT_NO_ERRORS; out: diff --git a/fsck/fsck.h b/fsck/fsck.h index 6d4279f..4e8e5f8 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -39,7 +39,15 @@ struct exfat_de_iter { 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 = 0x07, +}; + struct exfat { + enum fsck_ui_options options; struct exfat_blk_dev *blk_dev; struct pbr *bs; char volume_label[VOLUME_LABEL_BUFFER_SIZE]; diff --git a/fsck/repair.c b/fsck/repair.c index e8574fe..40bec17 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -59,19 +59,28 @@ static bool ask_repair(struct exfat *exfat, struct exfat_repair_problem *pr) { char answer[8]; - do { - printf("%s: Fix (y/N)?", pr->description); - 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); - + switch (exfat->options & FSCK_OPTS_REPAIR) { + case FSCK_OPTS_REPAIR_ASK: + do { + printf("%s: Fix (y/N)?", pr->description); + 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); + return false; + case FSCK_OPTS_REPAIR_YES: + return true; + case FSCK_OPTS_REPAIR_NO: + case 0: + default: + return false; + } return false; } @@ -81,13 +90,15 @@ bool exfat_repair(struct exfat *exfat, er_problem_code_t prcode, struct exfat_repair_problem *pr = NULL; int need_repair; + need_repair = ask_repair(exfat, pr); + if (!need_repair) + return false; + pr = find_problem(prcode); if (!pr) { exfat_err("unknown problem code. %#x\n", prcode); return false; } - need_repair = ask_repair(exfat, pr); - if (need_repair) - return pr->fix_problem(exfat, pr, rctx); + return pr->fix_problem(exfat, pr, rctx); } -- cgit v1.2.3 From 2e0aeb0f43dffa4b60a524362e3cc6b140765f16 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 26 Feb 2020 21:39:51 +0900 Subject: exfat-utils: add support for cluster size data unit(KB,MB) Signed-off-by: Namjae Jeon --- README.md | 6 ++++-- mkfs/mkfs.c | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f04c913..feccd81 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,10 @@ Build steps: 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) user want - mkfs.exfat -c 128 /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. diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index db003eb..fbd89f2 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -542,6 +542,23 @@ static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui) return 0; } +static long long parse_cluster_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 <<= 10; + case 'K': + case 'k': + byte_size <<= 10; + } + + return byte_size; +} + int main(int argc, char *argv[]) { int c; @@ -574,7 +591,7 @@ int main(int argc, char *argv[]) break; } case 'c': - ui.cluster_size = atoi(optarg) * KB; + ui.cluster_size = parse_cluster_size(optarg); if (ui.cluster_size > EXFAT_MAX_CLUSTER_SIZE) { exfat_msg(EXFAT_ERROR, "cluster size(%d) exceeds max cluster size(%d)\n", -- cgit v1.2.3 From 526cefe395f461e329cf3261a200eca051f5226f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 26 Feb 2020 21:54:59 +0900 Subject: exfat-utils: update fsck.exfat usage in README Signed-off-by: Namjae Jeon --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index feccd81..1798cbf 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,11 @@ Usage example: 4. For set volume label, use -l option with string user want. mkfs.exfat -l "my usb" /dev/sda1 -- fsck.exfat(Preparing): +- fsck.exfat: Check the consistency of your exfat filesystem and optinally repair a corrupted device formatted by exfat. + +Usage example: + 1. check the consistency. + fsck.exfat /dev/sda1 + 2. repair and fix.(preparing) ``` -- cgit v1.2.3 From adb51e39743405032e7d47665f5d55568e610e5e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 26 Feb 2020 22:06:01 +0900 Subject: update README Signed-off-by: Namjae Jeon --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1798cbf..ef89522 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -## exfat-utils ? -Exfat-utils is mkfs(format)/fsck(repair) implementation for exfat filesystem under GNU GPL version 2. +## exfat-utils +exfat-utils is mkfs(format)/fsck(repair) implementation for exfat filesystem under GNU GPL version 2. ## Maintainers * Namjae Jeon -- cgit v1.2.3 From 22370791bc3441989bd0029fe0896cb99f3c3356 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 28 Feb 2020 11:48:27 +0900 Subject: exfat-utils: return error when getting wrong unit input for cluster size Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index fbd89f2..6b50081 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -554,6 +554,10 @@ static long long parse_cluster_size(const char *size) case 'K': case 'k': byte_size <<= 10; + break; + default: + exfat_msg(EXFAT_ERROR, "Wrong unit input('%c') for cluster size\n", *data_unit); + return -EINVAL; } return byte_size; @@ -591,13 +595,16 @@ int main(int argc, char *argv[]) break; } case 'c': - ui.cluster_size = parse_cluster_size(optarg); - if (ui.cluster_size > EXFAT_MAX_CLUSTER_SIZE) { + ret = parse_cluster_size(optarg); + if (ret < 0) + goto out; + else if (ret > EXFAT_MAX_CLUSTER_SIZE) { exfat_msg(EXFAT_ERROR, "cluster size(%d) exceeds max cluster size(%d)\n", ui.cluster_size, EXFAT_MAX_CLUSTER_SIZE); goto out; } + ui.cluster_size = ret; break; case 'f': ui.quick = false; -- cgit v1.2.3 From 902b09640add982da3c6fe66403e2b69ecfc58c0 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 28 Feb 2020 11:48:27 +0900 Subject: exfat-utils: update info print Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 6b50081..bef66aa4 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -499,7 +499,7 @@ static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui) int ret; exfat_msg(EXFAT_INFO, - "Creating exFAT filesystem(%s) with %u cluster size\n\n", + "Creating exFAT filesystem(%s, cluster size=%u)\n\n", ui->dev_name, ui->cluster_size); exfat_msg(EXFAT_INFO, "Writing volume boot record: "); -- cgit v1.2.3 From 26362a852e39eeeea25939664a215db4af57fe22 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Thu, 12 Mar 2020 18:44:19 +0900 Subject: fsck: add upcase table check Add upcase table check Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index eb31a53..0a78fcb 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -22,6 +22,8 @@ struct fsck_user_input { enum fsck_ui_options options; }; +#define EXFAT_MAX_UPCASE_CHARS 0x10000 + #if __BYTE_ORDER == __LITTLE_ENDIAN typedef __u32 bitmap_t; #elif __BYTE_ORDER == __BIG_ENDIAN @@ -958,6 +960,60 @@ static bool read_alloc_bitmap(struct exfat_de_iter *iter) return true; } +static bool read_upcase_table(struct exfat_de_iter *iter) +{ + struct exfat_dentry *dentry; + struct exfat *exfat; + size_t size; + __le16 *upcase; + __le32 checksum; + + exfat = iter->exfat; + + if (exfat_de_iter_get(iter, 0, &dentry)) + return false; + + if (exfat_invalid_clus(exfat, le32_to_cpu(dentry->upcase_start_clu))) { + exfat_err("invalid start cluster of upcase table. 0x%x\n", + le32_to_cpu(dentry->upcase_start_clu)); + return false; + } + + size = (size_t)le64_to_cpu(dentry->upcase_size); + if (size > EXFAT_MAX_UPCASE_CHARS * sizeof(__le16) || + size == 0 || size % sizeof(__le16)) { + exfat_err("invalid size of upcase table. 0x%llx\n", + le64_to_cpu(dentry->upcase_size)); + return false; + } + + upcase = (__le16 *)malloc(size); + if (!upcase) { + exfat_err("failed to allocate upcase table\n"); + return false; + } + + if (exfat_read(exfat->blk_dev->dev_fd, upcase, size, + exfat_c2o(exfat, + le32_to_cpu(dentry->upcase_start_clu))) != size) { + exfat_err("failed to read upcase table\n"); + free(upcase); + return false; + } + + checksum = 0; + boot_calc_checksum((unsigned char *)upcase, size, false, &checksum); + if (le32_to_cpu(dentry->upcase_checksum) == checksum) { + exfat_err("corrupted upcase table %#x (expected: %#x)\n", + checksum, le32_to_cpu(dentry->upcase_checksum)); + free(upcase); + return false; + } + + free(upcase); + return true; +} + static int read_children(struct exfat *exfat, struct exfat_inode *dir) { int ret; @@ -1005,6 +1061,7 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) case EXFAT_VOLUME: if (!read_volume_label(de_iter)) { exfat_err("failed to verify volume label\n"); + ret = -EINVAL; goto err; } break; @@ -1012,10 +1069,17 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) if (!read_alloc_bitmap(de_iter)) { exfat_err( "failed to verify allocation bitmap\n"); + ret = -EINVAL; goto err; } break; case EXFAT_UPCASE: + if (!read_upcase_table(de_iter)) { + exfat_err( + "failed to verify upcase table\n"); + ret = -EINVAL; + goto err; + } break; default: if (IS_EXFAT_DELETED(dentry->type) || -- cgit v1.2.3 From fb74913d81cd17a27e4320eb987ca66f54796803 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Thu, 12 Mar 2020 18:45:45 +0900 Subject: fsck: fix check of exfat_filesystem_check return value Fix check of exfat_filesystem_check return value Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 0a78fcb..13d2473 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1111,7 +1111,7 @@ err: static bool exfat_filesystem_check(struct exfat *exfat) { struct exfat_inode *dir; - int ret; + bool ret = true; if (!exfat->root) { exfat_err("root is NULL\n"); @@ -1125,6 +1125,7 @@ static bool exfat_filesystem_check(struct exfat *exfat) if (!(dir->attr & ATTR_SUBDIR)) { resolve_path(&path_resolve_ctx, dir); + ret = false; exfat_err("failed to travel directories. " "the node is not directory: %s\n", path_resolve_ctx.utf8_path); @@ -1133,6 +1134,7 @@ static bool exfat_filesystem_check(struct exfat *exfat) if (read_children(exfat, dir)) { resolve_path(&path_resolve_ctx, dir); + ret = false; exfat_err("failed to check dentries: %s\n", path_resolve_ctx.utf8_path); goto out; @@ -1145,7 +1147,7 @@ static bool exfat_filesystem_check(struct exfat *exfat) out: exfat_free_dir_list(exfat); exfat->root = NULL; - return false; + return ret; } static bool exfat_root_dir_check(struct exfat *exfat) @@ -1289,9 +1291,8 @@ int main(int argc, char * const argv[]) } exfat_debug("verifying directory entries...\n"); - ret = exfat_filesystem_check(exfat); - if (ret) { - exfat_err("failed to verify directory entries. %d\n", ret); + if (!exfat_filesystem_check(exfat)) { + exfat_err("failed to verify directory entries.\n"); ret = FSCK_EXIT_ERRORS_LEFT; goto out; } -- cgit v1.2.3 From 377add7ae5578b990c86ea3a255abfa37d1f4dbb Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 13 Mar 2020 13:58:24 +0900 Subject: mkfs: Fix an usage message Short options do not need '=' for arguments and change tab spaces to white spaces. Signed-off-by: Hyunchul Lee --- mkfs/mkfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index bef66aa4..70dc928 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -394,12 +394,12 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, static void usage(void) { fprintf(stderr, "Usage: mkfs.exfat\n"); - fprintf(stderr, "\t-l=string | --volume-label=string Set volume label\n"); - fprintf(stderr, "\t-c=KB size | --cluster-size=KB size Set cluster size\n"); - fprintf(stderr, "\t-f | --full-format Full format\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"); + fprintf(stderr, "\t-l string | --volume-label=string Set volume label\n"); + fprintf(stderr, "\t-c KB size | --cluster-size=KB size Set cluster size\n"); + fprintf(stderr, "\t-f | --full-format Full format\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); } -- cgit v1.2.3 From 157dda7ed21d553c48e2fc7c3bf9668b72dbf050 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 6 Apr 2020 15:28:05 +0900 Subject: exfat-utils: fix wrong upcase checksum check Signed-off-by: Namjae Jeon --- fsck/fsck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 13d2473..91aa961 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1003,7 +1003,7 @@ static bool read_upcase_table(struct exfat_de_iter *iter) checksum = 0; boot_calc_checksum((unsigned char *)upcase, size, false, &checksum); - if (le32_to_cpu(dentry->upcase_checksum) == checksum) { + if (le32_to_cpu(dentry->upcase_checksum) != checksum) { exfat_err("corrupted upcase table %#x (expected: %#x)\n", checksum, le32_to_cpu(dentry->upcase_checksum)); free(upcase); -- cgit v1.2.3 From f000d56768ef9309b52ea9c69624e13eb164725e Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Thu, 9 Apr 2020 09:28:55 +0900 Subject: fsck: Add copyright in repair.c Signed-off-by: Hyunchul Lee --- fsck/repair.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fsck/repair.c b/fsck/repair.c index 40bec17..6a0e912 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -1,3 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Hyunchul Lee + */ #include #include -- cgit v1.2.3 From c0d547e15cdd15d948664fcdcb94d065b75c53f2 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 9 Apr 2020 09:47:24 +0900 Subject: exfat-utils: update cluster size print in usage The cluster size unit is changed with B,KB,MB. The usage print can mislead users to specify cluster size. Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 70dc928..56f21fc 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -395,7 +395,7 @@ static void usage(void) { fprintf(stderr, "Usage: mkfs.exfat\n"); fprintf(stderr, "\t-l string | --volume-label=string Set volume label\n"); - fprintf(stderr, "\t-c KB size | --cluster-size=KB size Set cluster size\n"); + fprintf(stderr, "\t-c | --cluster-size Set cluster size\n"); fprintf(stderr, "\t-f | --full-format Full format\n"); fprintf(stderr, "\t-V | --version Show version\n"); fprintf(stderr, "\t-v | --verbose Print debug\n"); -- cgit v1.2.3 From d21a082635374bbfbc8cee577f916a15e7e2273b Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 9 Apr 2020 10:05:54 +0900 Subject: exfat-utils: move show_version to above optind index check This patch fix the issue that mkfs/fsck -V option doesn't work Signed-off-by: Namjae Jeon --- fsck/fsck.c | 6 +++--- mkfs/mkfs.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 91aa961..239fa30 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1248,13 +1248,13 @@ int main(int argc, char * const argv[]) } } - if (optind != argc - 1) - usage(argv[0]); - show_version(); if (version_only) exit(FSCK_EXIT_SYNTAX_ERROR); + if (optind != argc - 1) + usage(argv[0]); + if (exfat_iconv_open(&exfat_iconv) < 0) { exfat_err("failed to init iconv\n"); return FSCK_EXIT_OPERATION_ERROR; diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 56f21fc..1b0e906 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -621,15 +621,15 @@ int main(int argc, char *argv[]) usage(); } + show_version(); + if (version_only) + exit(EXIT_FAILURE); + if (argc - optind != 1) { exfat_iconv_close(&exfat_iconv); usage(); } - show_version(); - if (version_only) - exit(EXIT_FAILURE); - memset(ui.dev_name, 0, 255); strncpy(ui.dev_name, argv[optind], 255); -- cgit v1.2.3 From 14d33f6e3ebb99a5bbca406a20031fad290b61bf Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 9 Apr 2020 10:06:31 +0900 Subject: exfat-utils: release 1.0.1 version The major changes in this release: * mkfs.exfat: quick/full format support * mkfs.exfat: specify cluster size * mkfs.exfat: set volume label * fsck.exfat: consistency check support Signed-off-by: Namjae Jeon --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b5ff039..9012f30 100755 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.68]) m4_define([exfat_tools_major_ver], [1]) m4_define([exfat_tools_minor_ver], [0]) -m4_define([exfat_tools_micro_ver], [0]) +m4_define([exfat_tools_micro_ver], [1]) m4_define([exfat_tools_version], [exfat_tools_major_ver.exfat_tools_minor_ver.exfat_tools_micro_ver]) -- cgit v1.2.3 From aa15575ed98f55d9de65dbd3ae068d413d6ad718 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 9 Apr 2020 13:40:06 +0900 Subject: exfat-utils: fix memleak in exfat_zero_out_disk Dexter static analysis tools alarm memleak: Memory leak: buf in exfat_zero_out_disk Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 1b0e906..4bea722 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -488,6 +488,7 @@ static int exfat_zero_out_disk(struct exfat_blk_dev *bd, total_written += nbytes; } while (total_written <= size); + free(buf); exfat_msg(EXFAT_DEBUG, "zero out written size : %llu, disk size : %llu\n", total_written, bd->size); -- cgit v1.2.3 From 002f4f32d2c9898c690073b2e21adbaa04128e3b Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 10 Apr 2020 08:52:54 +0900 Subject: exfat-utils: make -n option fallthrough to -l option for backward compatibility with old utils Vojtech Trefny concern about backwards compatibility with the fuse exfat userspace utilities. The difference is in command line options for mkfs.exfat that are using -l for label, the exfat fuse mkfs is using -n. This patch make -n option fallthrough to -l option for backward compatibility with old utils. Reported-by: Vojtech Trefny Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 4bea722..1a03501 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -582,8 +582,13 @@ int main(int argc, char *argv[]) } opterr = 0; - while ((c = getopt_long(argc, argv, "l:c:fVvh", opts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "n:l:c: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_iconv_enc(&exfat_iconv, optarg, -- cgit v1.2.3 From 94940766c99541cf59fde8730cd3366cc9e42163 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 10 Apr 2020 10:59:05 +0900 Subject: exfat-tools: add large file support for 32-bit system Signed-off-by: Hyunchul Lee --- configure.ac | 1 + fsck/Makefile.am | 2 +- lib/Makefile.am | 2 +- lib/libexfat.c | 6 +++--- mkfs/Makefile.am | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 9012f30..0513f61 100755 --- a/configure.ac +++ b/configure.ac @@ -23,6 +23,7 @@ AC_PROG_CC AC_PROG_CC_STDC AM_SILENT_RULES([yes]) AC_PROG_LIBTOOL +AC_SYS_LARGEFILE PKG_PROG_PKG_CONFIG([0.9]) diff --git a/fsck/Makefile.am b/fsck/Makefile.am index d75e3c5..8d8a863 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = fsck.exfat diff --git a/lib/Makefile.am b/lib/Makefile.am index ebd7485..7e0f013 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lc lib_LTLIBRARIES = libexfat.la diff --git a/lib/libexfat.c b/lib/libexfat.c index 1177cf0..2d7b3b6 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -135,7 +135,7 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, struct exfat_blk_dev *bd) { int fd, ret = -1; - long long blk_dev_size; + off_t blk_dev_size; fd = open(ui->dev_name, ui->writeable ? O_RDWR : O_RDONLY); if (fd < 0) @@ -144,8 +144,8 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, blk_dev_size = lseek(fd, 0, SEEK_END); if (blk_dev_size <= 0) { exfat_msg(EXFAT_ERROR, - "invalid block device size(%s) : %lld\n", - ui->dev_name, blk_dev_size); + "invalid block device size(%s)\n", + ui->dev_name); ret = blk_dev_size; close(fd); goto out; diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index 535ea9b..5dd1d16 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lm mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.la -- cgit v1.2.3 From 46b8d144e70b9218979721216f69dee20f84bfd5 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 10 Apr 2020 11:07:10 +0900 Subject: exfat-tools: fix -Wshift-count-overflow Signed-off-by: Hyunchul Lee --- include/exfat_ondisk.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index 422d494..e4c1e23 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -23,7 +23,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(x) << 32) | cpu_to_le32((x) >> 32)) +#define cpu_to_le64(x) (cpu_to_le32((uint64_t)(x)) << 32 | \ + cpu_to_le32((uint64_t)(x) >> 32)) #endif #define le64_to_cpu(x) cpu_to_le64(x) -- cgit v1.2.3 From eeb69fd834f37d7c908e9cb67147b774fc2f5220 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 10 Apr 2020 11:10:18 +0900 Subject: fsck: fix printing wrong sector in exfat_show_info Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 239fa30..22e37e7 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1183,9 +1183,9 @@ err: void exfat_show_info(struct exfat *exfat) { exfat_info("Bytes per sector: %d\n", - 1 << le32_to_cpu(exfat->bs->bsx.sect_size_bits)); + 1 << exfat->bs->bsx.sect_size_bits); exfat_info("Sectors per cluster: %d\n", - 1 << le32_to_cpu(exfat->bs->bsx.sect_per_clus_bits)); + 1 << exfat->bs->bsx.sect_per_clus_bits); exfat_info("Cluster heap count: %d(0x%x)\n", le32_to_cpu(exfat->bs->bsx.clu_count), le32_to_cpu(exfat->bs->bsx.clu_count)); -- cgit v1.2.3 From bd2d053cfb83e11ccba111dd31f6c2c2c33af0ec Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 10 Apr 2020 11:12:53 +0900 Subject: mkfs: fix printing wrong values in exfat_setup_boot_sector Signed-off-by: Hyunchul Lee --- mkfs/mkfs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 1a03501..72e04a7 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -59,21 +59,21 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, ppbr->signature = cpu_to_le16(PBR_SIGNATURE); exfat_msg(EXFAT_DEBUG, "Volume Length(sectors) : %llu\n", - cpu_to_le64(pbsx->vol_length)); + le64_to_cpu(pbsx->vol_length)); exfat_msg(EXFAT_DEBUG, "FAT Offset(sector offset) : %u\n", - cpu_to_le64(pbsx->fat_offset)); + le32_to_cpu(pbsx->fat_offset)); exfat_msg(EXFAT_DEBUG, "FAT Length(sectors) : %u\n", - cpu_to_le32(pbsx->fat_length)); + le32_to_cpu(pbsx->fat_length)); exfat_msg(EXFAT_DEBUG, "Cluster Heap Offset (sector offset) : %u\n", - cpu_to_le32(pbsx->clu_offset)); + le32_to_cpu(pbsx->clu_offset)); exfat_msg(EXFAT_DEBUG, "Cluster Count (sectors) : %u\n", - cpu_to_le32(pbsx->clu_count)); + le32_to_cpu(pbsx->clu_count)); exfat_msg(EXFAT_DEBUG, "Root Cluster (cluster offset) : %u\n", - cpu_to_le32(pbsx->root_cluster)); + le32_to_cpu(pbsx->root_cluster)); exfat_msg(EXFAT_DEBUG, "Sector Size Bits : %u\n", - cpu_to_le32(pbsx->sect_size_bits)); + pbsx->sect_size_bits); exfat_msg(EXFAT_DEBUG, "Sector per Cluster bits : %u\n", - cpu_to_le32(pbsx->sect_per_clus_bits)); + pbsx->sect_per_clus_bits); } static int exfat_write_sector(struct exfat_blk_dev *bd, void *buf, -- cgit v1.2.3 From 2ade4f5fe4215412c95c8ab4ffffdaf7d60c0e09 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 10 Apr 2020 11:21:53 +0900 Subject: mkfs: fix wrong assignment for upcase size in exfat_create_root_dir Signed-off-by: Hyunchul Lee --- mkfs/mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 72e04a7..29ce51b 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -377,7 +377,7 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, 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_le32(EXFAT_UPCASE_TABLE_SIZE); + ed[2].upcase_size = cpu_to_le64(EXFAT_UPCASE_TABLE_SIZE); lseek(bd->dev_fd, finfo.root_byte_off, SEEK_SET); nbytes = write(bd->dev_fd, ed, dentries_len); -- cgit v1.2.3 From 3badc8da0b201c9e3e0f1aa1c69a979c289c5a6a Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 10 Apr 2020 13:54:32 +0900 Subject: exfat-tools: fix bitwise operations on big endian Signed-off-by: Hyunchul Lee --- lib/libexfat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/libexfat.c b/lib/libexfat.c index 2d7b3b6..a493a09 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -18,9 +18,9 @@ #include "exfat_tools.h" #include "mkfs.h" -#if defined(__LITTLE_ENDIAN) +#if __BYTE_ORDER == __LITTLE_ENDIAN #define BITOP_LE_SWIZZLE 0 -#elif defined(__BIG_ENDIAN) +#else #define BITOP_LE_SWIZZLE (~0x7) #endif -- cgit v1.2.3 From b94aa6711d4474cdcb1a92c4b63bba411ca65a61 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 10 Apr 2020 14:15:35 +0900 Subject: fsck: print bitmap information before checking bitmap Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 22e37e7..1285f5b 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -920,6 +920,10 @@ static bool read_alloc_bitmap(struct exfat_de_iter *iter) if (exfat_de_iter_get(iter, 0, &dentry)) return false; + exfat_debug("start cluster %#x, size %#llx\n", + le32_to_cpu(dentry->bitmap_start_clu), + le64_to_cpu(dentry->bitmap_size)); + exfat->bit_count = le32_to_cpu(exfat->bs->bsx.clu_count); if (le64_to_cpu(dentry->bitmap_size) < @@ -934,10 +938,6 @@ static bool read_alloc_bitmap(struct exfat_de_iter *iter) return false; } - exfat_debug("start cluster %#x, size %#llx\n", - le32_to_cpu(dentry->bitmap_start_clu), - le64_to_cpu(dentry->bitmap_size)); - /* TODO: bitmap could be very large. */ alloc_bitmap_size = EXFAT_BITMAP_SIZE(exfat->bit_count); exfat->alloc_bitmap = (__u32 *)malloc(alloc_bitmap_size); -- cgit v1.2.3 From f3016e5768c25e79f74877804fd4a09e323b13a4 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Sat, 11 Apr 2020 12:28:03 +0900 Subject: fsck: call le16_to_cpu to get directory entry checksum Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 1285f5b..2f738c1 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -825,7 +825,7 @@ static int read_file_dentries(struct exfat_de_iter *iter, } checksum = file_calc_checksum(iter); - if (file_de->file_checksum != checksum) { + if (le16_to_cpu(file_de->file_checksum) != checksum) { exfat_err("invalid checksum. 0x%x != 0x%x\n", le16_to_cpu(file_de->file_checksum), le16_to_cpu(checksum)); -- cgit v1.2.3 From 18f026a23149dc5d9a6df7bd76dda5de43aba979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 13 Apr 2020 02:38:21 +0200 Subject: exfat-utils: Replace iconv library by standard C functions mbstowcs() and wcrtomb() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Via standard C functions mbstowcs() and wcrtomb() is implemented conversion of strings between exfat's UTF-16LE and multibyte char* in current locale. There is also standard C macro MB_LEN_MAX which contains maximal length of one multibyte character. After this change conversion is not done explicitly to UTF-8, but rather to encoding this user defined for current locale/codeset. This is also encoding used by all wide string function in C and also encoding in which user has configured terminal. Nowadays it is UTF-8, but older systems could use e.g. Latin1 (or anything other which can be configured by system). So basically it is encoding which user expects. iconv library has a problem that cannot be easily used in static linked binaries or in cross-compiled environments. Moreover iconv() function has different APIs SUSv2 or POSIX.1-2001/POSIX.1-2008 which differs in input argument, if is const or not. To somehow workaround this problem, there is autoconf macro AM_ICONV which defines C macro ICONV_CONST suitable for type of input argument. But apparently this autoconf macro is broken for projects which do not use gettext. As exfat needs only UTF-16LE encoding, it is easier to provide its own conversion functions implemented via standard C functions, instead of trying to workaround those iconv problems. Also code before this commit for handling UTF-8 was incorrect as it expected that maximal length of UTF-8 sequence is 3 bytes. Signed-off-by: Pali Rohár --- fsck/fsck.c | 65 +++++++++++++------------- fsck/fsck.h | 9 ++-- include/exfat_iconv.h | 31 ------------- include/exfat_tools.h | 6 ++- lib/Makefile.am | 2 +- lib/exfat_iconv.c | 82 --------------------------------- lib/libexfat.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++- mkfs/mkfs.c | 20 +++----- 8 files changed, 171 insertions(+), 167 deletions(-) delete mode 100644 include/exfat_iconv.h delete mode 100644 lib/exfat_iconv.c diff --git a/fsck/fsck.c b/fsck/fsck.c index 239fa30..191b02d 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -10,10 +10,10 @@ #include #include #include +#include #include "exfat_ondisk.h" #include "exfat_tools.h" -#include "exfat_iconv.h" #include "fsck.h" #include "repair.h" @@ -61,13 +61,12 @@ struct exfat_stat { struct path_resolve_ctx { struct exfat_inode *ancestors[255]; - __le16 utf16_path[sizeof(__le16) * (PATH_MAX + 2)]; - char utf8_path[PATH_MAX * 3 + 1]; + __le16 utf16_path[PATH_MAX + 2]; + char local_path[PATH_MAX * MB_LEN_MAX + 1]; }; struct exfat_stat exfat_stat; struct path_resolve_ctx path_resolve_ctx; -struct exfat_iconv exfat_iconv; static struct option opts[] = { {"repair", no_argument, NULL, 'r' }, @@ -491,6 +490,15 @@ err: return false; } +static size_t 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; +} + /* * get references of ancestors that include @child until the count of * ancesters is not larger than @count and the count of characters of @@ -512,8 +520,7 @@ bool get_ancestors(struct exfat_inode *child, dir = child; while (dir) { - name_len = exfat_iconv_encstr_len((char *)dir->name, - NAME_BUFFER_SIZE); + name_len = utf16_len(dir->name, NAME_BUFFER_SIZE); if (char_len + name_len > max_char_len) break; @@ -539,9 +546,10 @@ static int resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child) int depth, i; int name_len, path_len; __le16 *utf16_path; + const __le16 utf16_slash = cpu_to_le16(0x002F); size_t in_size; - ctx->utf8_path[0] = '\0'; + ctx->local_path[0] = '\0'; get_ancestors(child, ctx->ancestors, @@ -551,22 +559,19 @@ static int resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child) utf16_path = ctx->utf16_path; for (i = 0; i < depth; i++) { - name_len = exfat_iconv_encstr_len( - (char *)ctx->ancestors[i]->name, - NAME_BUFFER_SIZE); + name_len = utf16_len(ctx->ancestors[i]->name, NAME_BUFFER_SIZE); memcpy((char *)utf16_path, (char *)ctx->ancestors[i]->name, name_len * 2); utf16_path += name_len; - memcpy((char *)utf16_path, u"/", 2); + memcpy((char *)utf16_path, &utf16_slash, sizeof(utf16_slash)); utf16_path++; } if (depth > 0) utf16_path--; in_size = (utf16_path - ctx->utf16_path) * sizeof(__le16); - return exfat_iconv_dec(&exfat_iconv, - (char *)ctx->utf16_path, in_size, - (char *)ctx->utf8_path, sizeof(ctx->utf8_path)); + return exfat_utf16_dec(ctx->utf16_path, in_size, + ctx->local_path, sizeof(ctx->local_path)); } static int resolve_path_parent(struct path_resolve_ctx *ctx, @@ -699,14 +704,14 @@ static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, if (node->size == 0 && node->first_clus != EXFAT_FREE_CLUSTER) { resolve_path_parent(&path_resolve_ctx, parent, node); exfat_err("file is empty, but first cluster is %#x: %s\n", - node->first_clus, path_resolve_ctx.utf8_path); + node->first_clus, path_resolve_ctx.local_path); ret = false; } if (node->size > 0 && exfat_invalid_clus(exfat, node->first_clus)) { resolve_path_parent(&path_resolve_ctx, parent, node); exfat_err("first cluster %#x is invalid: %s\n", - node->first_clus, path_resolve_ctx.utf8_path); + node->first_clus, path_resolve_ctx.local_path); ret = false; } @@ -714,14 +719,14 @@ static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, EXFAT_CLUSTER_SIZE(exfat->bs)) { resolve_path_parent(&path_resolve_ctx, parent, node); exfat_err("size %llu is greater than cluster heap: %s\n", - node->size, path_resolve_ctx.utf8_path); + node->size, path_resolve_ctx.local_path); ret = false; } if (node->size == 0 && node->is_contiguous) { resolve_path_parent(&path_resolve_ctx, parent, node); exfat_err("empty, but marked as contiguous: %s\n", - path_resolve_ctx.utf8_path); + path_resolve_ctx.local_path); ret = false; } @@ -730,14 +735,14 @@ static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, resolve_path_parent(&path_resolve_ctx, parent, node); exfat_err("directory size %llu is not divisible by %d: %s\n", node->size, EXFAT_CLUSTER_SIZE(exfat->bs), - path_resolve_ctx.utf8_path); + path_resolve_ctx.local_path); ret = false; } if (!node->is_contiguous && !inode_check_clus_chain(exfat, node)) { resolve_path_parent(&path_resolve_ctx, parent, node); exfat_err("corrupted cluster chain: %s\n", - path_resolve_ctx.utf8_path); + path_resolve_ctx.local_path); ret = false; } @@ -842,7 +847,7 @@ static int read_file_dentries(struct exfat_de_iter *iter, resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("valid size %llu greater than size %llu: %s\n", le64_to_cpu(stream_de->stream_valid_size), node->size, - path_resolve_ctx.utf8_path); + path_resolve_ctx.local_path); goto err; } @@ -899,9 +904,8 @@ static bool read_volume_label(struct exfat_de_iter *iter) return false; } - if (exfat_iconv_dec(&exfat_iconv, - (char *)dentry->vol_label, sizeof(dentry->vol_label), - (char *)exfat->volume_label, sizeof(exfat->volume_label)) < 0) { + if (exfat_utf16_dec(dentry->vol_label, dentry->vol_char_cnt*2, + exfat->volume_label, sizeof(exfat->volume_label)) < 0) { exfat_err("failed to decode volume label\n"); return false; } @@ -1128,7 +1132,7 @@ static bool exfat_filesystem_check(struct exfat *exfat) ret = false; exfat_err("failed to travel directories. " "the node is not directory: %s\n", - path_resolve_ctx.utf8_path); + path_resolve_ctx.local_path); goto out; } @@ -1136,7 +1140,7 @@ static bool exfat_filesystem_check(struct exfat *exfat) resolve_path(&path_resolve_ctx, dir); ret = false; exfat_err("failed to check dentries: %s\n", - path_resolve_ctx.utf8_path); + path_resolve_ctx.local_path); goto out; } @@ -1213,6 +1217,9 @@ int main(int argc, char * const argv[]) print_level = EXFAT_ERROR; + if (!setlocale(LC_CTYPE, "")) + exfat_err("failed to init locale/codeset\n"); + opterr = 0; while ((c = getopt_long(argc, argv, "rynVvh", opts, NULL)) != EOF) { switch (c) { @@ -1255,11 +1262,6 @@ int main(int argc, char * const argv[]) if (optind != argc - 1) usage(argv[0]); - if (exfat_iconv_open(&exfat_iconv) < 0) { - exfat_err("failed to init iconv\n"); - return FSCK_EXIT_OPERATION_ERROR; - } - strncpy(ui.ei.dev_name, argv[optind], sizeof(ui.ei.dev_name)); ret = exfat_get_blk_dev_info(&ui.ei, &bd); if (ret < 0) { @@ -1306,6 +1308,5 @@ out: err: free_exfat(exfat); close(bd.dev_fd); - exfat_iconv_close(&exfat_iconv); return ret; } diff --git a/fsck/fsck.h b/fsck/fsck.h index 4e8e5f8..ffbf79f 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -5,7 +5,8 @@ #ifndef _FSCK_H #define _FSCK_H -#include "exfat_iconv.h" +#include + #include "list.h" typedef __u32 clus_t; @@ -24,10 +25,8 @@ struct exfat_inode { }; #define EXFAT_NAME_MAX 255 -#define VOLUME_LABEL_BUFFER_SIZE (EXFAT_DECSTR_MAX_BUFSIZE( \ - VOLUME_LABEL_MAX_LEN)) -#define NAME_BUFFER_SIZE (EXFAT_ENCSTR_MAX_BUFSIZE( \ - EXFAT_NAME_MAX)) +#define VOLUME_LABEL_BUFFER_SIZE (VOLUME_LABEL_MAX_LEN*MB_LEN_MAX+1) +#define NAME_BUFFER_SIZE ((EXFAT_NAME_MAX+1)*2) struct exfat_de_iter { struct exfat *exfat; diff --git a/include/exfat_iconv.h b/include/exfat_iconv.h deleted file mode 100644 index a97bf80..0000000 --- a/include/exfat_iconv.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2020 Hyunchul Lee - */ -#ifndef _EXFAT_ICONV_H -#define _EXFAT_ICONV_H - -#include - -/* length to byte size */ -#define EXFAT_ENCSTR_MAX_BUFSIZE(__len) (((__len) + 1) * 2) /* UTF-16 */ -#define EXFAT_DECSTR_MAX_BUFSIZE(__len) ((__len) * 3 + 1) /* UTF-8 */ - -struct exfat_iconv { - iconv_t enc_cd; - iconv_t dec_cd; - const char *enc_charset; - const char *dec_charset; -}; - -int exfat_iconv_open(struct exfat_iconv *ei); -void exfat_iconv_close(struct exfat_iconv *ei); - -int exfat_iconv_enc(struct exfat_iconv *ei, char *in_str, size_t in_size, - char *out_str, size_t out_size); -int exfat_iconv_dec(struct exfat_iconv *ei, char *in_str, size_t in_size, - char *out_str, size_t out_size); - -int exfat_iconv_encstr_len(char *in_str, size_t in_size); - -#endif diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 45de4aa..9e442d9 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -54,7 +54,7 @@ struct exfat_user_input { unsigned int cluster_size; unsigned int sec_per_clu; bool quick; - char volume_label[22]; + __u16 volume_label[11]; int volume_label_len; }; @@ -72,6 +72,10 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, 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); +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); + /* * Exfat Print */ diff --git a/lib/Makefile.am b/lib/Makefile.am index ebd7485..f9295cd 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -2,4 +2,4 @@ AM_CFLAGS = -I$(top_srcdir)/include -fno-common LIBS = -lc lib_LTLIBRARIES = libexfat.la -libexfat_la_SOURCES = libexfat.c exfat_iconv.c +libexfat_la_SOURCES = libexfat.c diff --git a/lib/exfat_iconv.c b/lib/exfat_iconv.c deleted file mode 100644 index b0838bf..0000000 --- a/lib/exfat_iconv.c +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2020 Hyunchul Lee - */ - -#include -#include -#include - -#include "exfat_ondisk.h" -#include "exfat_tools.h" -#include "exfat_iconv.h" - -int exfat_iconv_open(struct exfat_iconv *ei) -{ - ei->enc_charset = "UTF-16LE"; - ei->dec_charset = "UTF-8"; - - ei->enc_cd = iconv_open(ei->enc_charset, ei->dec_charset); - if (ei->enc_cd == (iconv_t)-1) - goto err; - - ei->dec_cd = iconv_open(ei->dec_charset, ei->enc_charset); - if (ei->dec_cd == (iconv_t)-1) { - iconv_close(ei->enc_cd); - goto err; - } - - return 0; -err: - if (errno == EINVAL) - exfat_err("conversion between %s and %s is not avaiable\n", - ei->enc_charset, ei->dec_charset); - else - exfat_err("error at iconv_open: %d\n", -errno); - return -errno; -} - -void exfat_iconv_close(struct exfat_iconv *ei) -{ - iconv_close(ei->enc_cd); - iconv_close(ei->dec_cd); -} - -static int iconv_conv(iconv_t cd, char *in_str, size_t in_size, - char *out_str, size_t out_size) -{ - size_t size = out_size; - - if (iconv(cd, &in_str, &in_size, &out_str, &size) < 0) { - if (errno == E2BIG) - exfat_err("input string is too long\n"); - else if (errno == EINVAL || errno == EILSEQ) - exfat_err("invaild character sequence\n"); - return -errno; - } - if (size > 0) - *out_str = '\0'; - return out_size - size; -} - -int exfat_iconv_enc(struct exfat_iconv *ei, char *in_str, size_t in_size, - char *out_str, size_t out_size) -{ - return iconv_conv(ei->enc_cd, in_str, in_size, out_str, out_size); -} - -int exfat_iconv_dec(struct exfat_iconv *ei, char *in_str, size_t in_size, - char *out_str, size_t out_size) -{ - return iconv_conv(ei->dec_cd, in_str, in_size, out_str, out_size); -} - -int exfat_iconv_encstr_len(char *in_str, size_t in_size) -{ - size_t i = 0; - __le16 *str = (__le16 *)in_str; - - while (le16_to_cpu(str[i]) && i < in_size/2) - i++; - return i; -} diff --git a/lib/libexfat.c b/lib/libexfat.c index 1177cf0..6a6d975 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -12,7 +12,8 @@ #include #include #include -#include +#include +#include #include "exfat_ondisk.h" #include "exfat_tools.h" @@ -185,3 +186,123 @@ ssize_t exfat_write(int fd, void *buf, size_t size, off_t offset) { return pwrite(fd, buf, size, offset); } + +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"); + 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 mbs_len, 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] != 0) { + exfat_err("invalid UTF-16 sequence\n"); + return -errno; + } + + return out_len-1; +} diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 1a03501..bec8faa 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -15,12 +15,11 @@ #include #include #include -#include +#include #include "exfat_ondisk.h" #include "exfat_tools.h" #include "mkfs.h" -#include "exfat_iconv.h" struct exfat_mkfs_info finfo; @@ -364,8 +363,7 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, 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 = exfat_iconv_encstr_len(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; @@ -572,14 +570,11 @@ int main(int argc, char *argv[]) struct exfat_blk_dev bd; struct exfat_user_input ui; bool version_only = false; - struct exfat_iconv exfat_iconv; init_user_input(&ui); - if (exfat_iconv_open(&exfat_iconv) < 0) { - exfat_msg(EXFAT_ERROR, "failed to init iconv\n"); - return EXIT_FAILURE; - } + if (!setlocale(LC_CTYPE, "")) + exfat_msg(EXFAT_ERROR, "failed to init locale/codeset\n"); opterr = 0; while ((c = getopt_long(argc, argv, "n:l:c:fVvh", opts, NULL)) != EOF) @@ -591,9 +586,8 @@ int main(int argc, char *argv[]) case 'n': case 'l': { - ret = exfat_iconv_enc(&exfat_iconv, optarg, - strlen(optarg), ui.volume_label, - sizeof(ui.volume_label)); + ret = exfat_utf16_enc(optarg, + ui.volume_label, sizeof(ui.volume_label)); if (ret < 0) goto out; @@ -632,7 +626,6 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); if (argc - optind != 1) { - exfat_iconv_close(&exfat_iconv); usage(); } @@ -662,7 +655,6 @@ out: exfat_msg(EXFAT_INFO, "\nexFAT format complete!\n"); else exfat_msg(EXFAT_INFO, "\nexFAT format fail!\n"); - exfat_iconv_close(&exfat_iconv); close(bd.dev_fd); return ret; } -- cgit v1.2.3 From 10e10a79b298d852df82988db828ae13dff0ecdb Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Thu, 9 Apr 2020 14:37:02 +0200 Subject: exfat-utils: Fix -Wuninitialized and -Wformat errors Signed-off-by: Luca Stefani --- fsck/fsck.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 5f00509..67ed7c7 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -429,7 +429,7 @@ static bool exfat_boot_region_check(struct exfat *exfat) ret = exfat_read(exfat->blk_dev->dev_fd, bs, sizeof(*bs), 0); if (ret != sizeof(*bs)) { - exfat_err("failed to read a boot sector. %ld\n", ret); + exfat_err("failed to read a boot sector. %zd\n", ret); goto err; } @@ -451,7 +451,7 @@ static bool exfat_boot_region_check(struct exfat *exfat) ret = boot_region_checksum(exfat); if (ret) { - exfat_err("failed to verify the checksum of a boot region. %ld\n", + exfat_err("failed to verify the checksum of a boot region. %zd\n", ret); goto err; } @@ -1157,7 +1157,6 @@ out: static bool exfat_root_dir_check(struct exfat *exfat) { struct exfat_inode *root; - int ret; clus_t clus_count; root = alloc_exfat_inode(ATTR_SUBDIR); @@ -1168,8 +1167,7 @@ static bool exfat_root_dir_check(struct exfat *exfat) root->first_clus = le32_to_cpu(exfat->bs->bsx.root_cluster); if (!inode_get_clus_count(exfat, root, &clus_count)) { - exfat_err("failed to follow the cluster chain of root. %d\n", - ret); + exfat_err("failed to follow the cluster chain of root\n"); goto err; } root->size = clus_count * EXFAT_CLUSTER_SIZE(exfat->bs); -- cgit v1.2.3 From 4b12fd91688d0aea2c2667135f2c898dd9105440 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Mon, 13 Apr 2020 14:55:58 +0900 Subject: exfat-utils: Fix -Wunused-parameter and -Wunused-variable errors Signed-off-by: Luca Stefani --- fsck/fsck.c | 14 ++++++-------- include/mkfs.h | 3 +-- mkfs/mkfs.c | 12 +++++------- mkfs/upcase.c | 5 ++--- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 67ed7c7..6db647a 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -154,7 +154,7 @@ static void inode_free_file_children(struct exfat_inode *dir) */ static void inode_free_ancestors(struct exfat_inode *child) { - struct exfat_inode *parent, *node; + struct exfat_inode *parent; if (!list_empty(&child->children)) return; @@ -201,7 +201,7 @@ static void free_exfat(struct exfat *exfat) static void exfat_free_dir_list(struct exfat *exfat) { - struct exfat_inode *dir, *file, *i, *k; + struct exfat_inode *dir, *i; list_for_each_entry_safe(dir, i, &exfat->dir_list, list) { inode_free_file_children(dir); @@ -306,7 +306,7 @@ static off_t exfat_s2o(struct exfat *exfat, off_t sect) static off_t exfat_c2o(struct exfat *exfat, unsigned int clus) { if (clus < EXFAT_FIRST_CLUSTER) - return ~0ULL; + return ~0L; return exfat_s2o(exfat, le32_to_cpu(exfat->bs->bsx.clu_offset) + ((clus - EXFAT_FIRST_CLUSTER) << @@ -542,9 +542,8 @@ bool get_ancestors(struct exfat_inode *child, static int resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child) { - int ret = 0; int depth, i; - int name_len, path_len; + int name_len; __le16 *utf16_path; const __le16 utf16_slash = cpu_to_le16(0x002F); size_t in_size; @@ -698,7 +697,6 @@ off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter) static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, struct exfat_inode *node) { - int clus_count; bool ret = false; if (node->size == 0 && node->first_clus != EXFAT_FREE_CLUSTER) { @@ -1195,7 +1193,7 @@ void exfat_show_info(struct exfat *exfat) le32_to_cpu(exfat->bs->bsx.clu_offset)); } -void exfat_show_stat(struct exfat *exfat) +void exfat_show_stat(void) { exfat_debug("Found directories: %ld\n", exfat_stat.dir_count); exfat_debug("Found files: %ld\n", exfat_stat.file_count); @@ -1302,7 +1300,7 @@ int main(int argc, char * const argv[]) printf("%s: clean\n", ui.ei.dev_name); ret = FSCK_EXIT_NO_ERRORS; out: - exfat_show_stat(exfat); + exfat_show_stat(); err: free_exfat(exfat); close(bd.dev_fd); diff --git a/include/mkfs.h b/include/mkfs.h index c208fa8..1841ce1 100644 --- a/include/mkfs.h +++ b/include/mkfs.h @@ -29,7 +29,6 @@ struct exfat_mkfs_info { extern struct exfat_mkfs_info finfo; -int exfat_create_upcase_table(struct exfat_blk_dev *bd, - struct exfat_user_input *ui); +int exfat_create_upcase_table(struct exfat_blk_dev *bd); #endif /* !_MKFS_H */ diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index bc1e0c3..aa1dad4 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -286,7 +286,7 @@ static int write_fat_entries(struct exfat_user_input *ui, int fd, static int exfat_create_fat_table(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - int ret, clu, count; + int ret, clu; /* fat entry 0 should be media type field(0xF8) */ ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xfffffff8), 0); @@ -327,8 +327,7 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, return ret; } -static int exfat_create_bitmap(struct exfat_blk_dev *bd, - struct exfat_user_input *ui) +static int exfat_create_bitmap(struct exfat_blk_dev *bd) { char *bitmap; int i, nbytes; @@ -357,7 +356,7 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, { struct exfat_dentry ed[3]; int dentries_len = sizeof(struct exfat_dentry) * 3; - int nbytes, vol_len; + int nbytes; /* Set volume label entry */ ed[0].type = EXFAT_VOLUME; @@ -521,13 +520,13 @@ static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui) return ret; exfat_msg(EXFAT_INFO, "Allocation bitmap creation: "); - ret = exfat_create_bitmap(bd, ui); + ret = exfat_create_bitmap(bd); exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); if (ret) return ret; exfat_msg(EXFAT_INFO, "Upcate table creation: "); - ret = exfat_create_upcase_table(bd, ui); + ret = exfat_create_upcase_table(bd); exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); if (ret) return ret; @@ -566,7 +565,6 @@ int main(int argc, char *argv[]) { int c; int ret = EXIT_FAILURE; - char *blk_dev_name; struct exfat_blk_dev bd; struct exfat_user_input ui; bool version_only = false; diff --git a/mkfs/upcase.c b/mkfs/upcase.c index 230d975..4b98282 100644 --- a/mkfs/upcase.c +++ b/mkfs/upcase.c @@ -502,10 +502,9 @@ static const unsigned char upcase_table[EXFAT_UPCASE_TABLE_SIZE] = { 0xFE, 0xFF, 0xFF, 0xFF }; -int exfat_create_upcase_table(struct exfat_blk_dev *bd, - struct exfat_user_input *ui) +int exfat_create_upcase_table(struct exfat_blk_dev *bd) { - int ut_off, nbytes; + int nbytes; lseek(bd->dev_fd, finfo.ut_byte_off, SEEK_SET); nbytes = write(bd->dev_fd, upcase_table, EXFAT_UPCASE_TABLE_SIZE); -- cgit v1.2.3 From d867925f4b1a4fcafe0228d458f5d5fae5509867 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Mon, 13 Apr 2020 14:56:39 +0900 Subject: exfat-utils: Fix -Wunused-but-set-variable errors Signed-off-by: Luca Stefani --- fsck/fsck.c | 6 ++---- lib/libexfat.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 6db647a..443515d 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -624,8 +624,8 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, int ith, struct exfat_dentry **dentry) { off_t de_next_file_offset; - int de_offset, de_next_offset; - bool need_read_1_clus = false, need_read_2_clus = false; + int de_next_offset; + bool need_read_1_clus = false; int ret; de_next_file_offset = iter->de_file_offset + @@ -644,7 +644,6 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, iter->read_size * 2) return -ERANGE; - de_offset = iter->de_file_offset % (iter->read_size * 2); de_next_offset = de_next_file_offset % (iter->read_size * 2); /* read a cluster if needed */ @@ -652,7 +651,6 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, void *buf; need_read_1_clus = de_next_offset < iter->read_size; - need_read_2_clus = de_next_offset >= iter->read_size; buf = need_read_1_clus ? iter->dentries : iter->dentries + iter->read_size; diff --git a/lib/libexfat.c b/lib/libexfat.c index 1a651d8..6cc4eca 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -57,9 +57,8 @@ static inline void clear_bit_le(int nr, void *addr) void exfat_set_bit(struct exfat_blk_dev *bd, char *bitmap, unsigned int clu) { - int i, b; + int b; - i = clu >> (bd->sector_size_bits + 3); b = clu & ((bd->sector_size << 3) - 1); set_bit_le(b, bitmap); @@ -68,9 +67,8 @@ void exfat_set_bit(struct exfat_blk_dev *bd, char *bitmap, void exfat_clear_bit(struct exfat_blk_dev *bd, char *bitmap, unsigned int clu) { - int i, b; + int b; - i = clu >> (bd->sector_size_bits + 3); b = clu & ((bd->sector_size << 3) - 1); clear_bit_le(b, bitmap); -- cgit v1.2.3 From 35ecc79d1a6d9b004778c8bb9f7a19244fed478f Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Mon, 13 Apr 2020 14:57:12 +0900 Subject: exfat-utils: Fix -Wpointer-arith errors Signed-off-by: Luca Stefani --- fsck/fsck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 443515d..eb473d9 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -352,7 +352,7 @@ static ssize_t exfat_file_read(struct exfat *exfat, struct exfat_inode *node, return -EIO; clus_offset = 0; - buf += read_size; + buf = (char *)buf + read_size; remain_size -= read_size; if (remain_size == 0) return total_size; -- cgit v1.2.3 From f996fc226fb34f5bff45ca1bc11bc42abc90f13e Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Mon, 13 Apr 2020 14:57:58 +0900 Subject: exfat-utils: Define offsetof only if undefined Signed-off-by: Luca Stefani --- include/list.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/list.h b/include/list.h index 7fc3d64..30a32de 100644 --- a/include/list.h +++ b/include/list.h @@ -3,7 +3,9 @@ #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); \ -- cgit v1.2.3 From c4ab96c20138acd05911b8521f019966bfb78a27 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Mon, 13 Apr 2020 14:58:28 +0900 Subject: exfat-utils: Remove unused goto labels Signed-off-by: Luca Stefani --- fsck/fsck.c | 1 - mkfs/mkfs.c | 1 - 2 files changed, 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index eb473d9..8b093e0 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1092,7 +1092,6 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) exfat_de_iter_advance(de_iter, dentry_count); } -out: list_splice(&sub_dir_list, &exfat->dir_list); return 0; err: diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index aa1dad4..646df65 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -152,7 +152,6 @@ static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, false, checksum); } -out: return 0; } -- cgit v1.2.3 From 1eedb5a6e2b9cbf8ff59d52253e2ab4c24a6c278 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 13 Apr 2020 15:09:21 +0900 Subject: exfat-utils: move print_level variable declare to libexfat.c Signed-off-by: Luca Stefani Signed-off-by: Namjae Jeon --- include/exfat_tools.h | 2 +- lib/libexfat.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/exfat_tools.h b/include/exfat_tools.h index 9e442d9..8112b2d 100644 --- a/include/exfat_tools.h +++ b/include/exfat_tools.h @@ -80,7 +80,7 @@ ssize_t exfat_utf16_dec(const __u16 *in_str, size_t in_len, * Exfat Print */ -static unsigned int print_level = 1; +extern unsigned int print_level; #define EXFAT_ERROR (0) #define EXFAT_INFO (1) diff --git a/lib/libexfat.c b/lib/libexfat.c index 6cc4eca..1a04640 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -28,6 +28,8 @@ #define BIT_MASK(nr) ((1) << ((nr) % 32)) #define BIT_WORD(nr) ((nr) / 32) +unsigned int print_level = EXFAT_INFO; + static inline void set_bit(int nr, unsigned int *addr) { unsigned long mask = BIT_MASK(nr); -- cgit v1.2.3 From b21813da75d2472300a4e9d797930c26ac3c6231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 13 Apr 2020 12:30:01 +0200 Subject: exfat-utils: Use standard autoconf m4 macro AC_C_BIGENDIAN for detecting endianity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It sets C macro WORDS_BIGENDIAN on big endian platforms. Signed-off-by: Pali Rohár --- configure.ac | 1 + fsck/fsck.c | 6 ++---- include/exfat_ondisk.h | 11 +++++------ lib/libexfat.c | 6 +++--- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 0513f61..43df955 100755 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,7 @@ AC_PROG_CC_STDC AM_SILENT_RULES([yes]) AC_PROG_LIBTOOL AC_SYS_LARGEFILE +AC_C_BIGENDIAN PKG_PROG_PKG_CONFIG([0.9]) diff --git a/fsck/fsck.c b/fsck/fsck.c index 8b093e0..a167a96 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -24,12 +24,10 @@ struct fsck_user_input { #define EXFAT_MAX_UPCASE_CHARS 0x10000 -#if __BYTE_ORDER == __LITTLE_ENDIAN -typedef __u32 bitmap_t; -#elif __BYTE_ORDER == __BIG_ENDIAN +#ifdef WORDS_BIGENDIAN typedef __u8 bitmap_t; #else -#error "__BYTE_ORDER is not defined" +typedef __u32 bitmap_t; #endif #define BITS_PER (sizeof(bitmap_t) * 8) diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index e4c1e23..5dca178 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -6,7 +6,6 @@ #ifndef _EXFAT_H #define _EXFAT_H -#include #include #include @@ -14,17 +13,17 @@ #include #endif -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define cpu_to_le16(x) (x) -#define cpu_to_le32(x) (x) -#define cpu_to_le64(x) (x) -#else +#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) cpu_to_le64(x) diff --git a/lib/libexfat.c b/lib/libexfat.c index 1a04640..1d0722a 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -19,10 +19,10 @@ #include "exfat_tools.h" #include "mkfs.h" -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define BITOP_LE_SWIZZLE 0 -#else +#ifdef WORDS_BIGENDIAN #define BITOP_LE_SWIZZLE (~0x7) +#else +#define BITOP_LE_SWIZZLE 0 #endif #define BIT_MASK(nr) ((1) << ((nr) % 32)) -- cgit v1.2.3 From 5f963599c755211cc4d31828aaf36b6afec514d7 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 13 Apr 2020 21:11:14 +0900 Subject: fsck: remove unused variable in repair callback Signed-off-by: Hyunchul Lee --- fsck/repair.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fsck/repair.c b/fsck/repair.c index 6a0e912..f254d92 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -14,12 +14,10 @@ struct exfat_repair_problem { er_problem_code_t prcode; const char *description; bool (*fix_problem)(struct exfat *exfat, - struct exfat_repair_problem *pr, union exfat_repair_context *rctx); }; static bool fix_bs_checksum(struct exfat *exfat, - struct exfat_repair_problem *pr, union exfat_repair_context *rctx) { unsigned int size; @@ -104,5 +102,5 @@ bool exfat_repair(struct exfat *exfat, er_problem_code_t prcode, return false; } - return pr->fix_problem(exfat, pr, rctx); + return pr->fix_problem(exfat, rctx); } -- cgit v1.2.3 From 4b29e2f273285938da70d157e521d495d42fabfb Mon Sep 17 00:00:00 2001 From: Chris Clayton Date: Tue, 14 Apr 2020 08:29:32 +0900 Subject: mkfs: don't write beyond end of file Find that an error message is produced when the -f option is passed to mkfs.exfat. exfat-tools version : 1.0.1 [exfat_zero_out_disk: 484] write failed(errno : 28) [exfat_zero_out_disk: 491] zero out written size : 15517876224, disk size : 15517876224 [make_exfat: 501] Creating exFAT filesystem(/dev/sdb1, cluster size=32768) Signed-off-by: Chris Clayton Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 646df65..50a75ef 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -482,7 +482,7 @@ static int exfat_zero_out_disk(struct exfat_blk_dev *bd, break; } total_written += nbytes; - } while (total_written <= size); + } while (total_written < size); free(buf); exfat_msg(EXFAT_DEBUG, -- cgit v1.2.3 From 005cee3098e4a521220ddc8d50377a91fe3fe5de Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 14 Apr 2020 10:07:18 +0900 Subject: exfat-utils: add -Wall -Werror -Wunused-parameter to cflags Signed-off-by: Namjae Jeon --- fsck/Makefile.am | 2 +- mkfs/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fsck/Makefile.am b/fsck/Makefile.am index 8d8a863..e9cdc58 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -Wall -Werror -Wunused-parameter -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = fsck.exfat diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index 5dd1d16..b083363 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -Wall -Werror -Wunused-parameter -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lm mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.la -- cgit v1.2.3 From 5580eb5589737a9f2f12e142fbff63384592c788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Jel=C3=ADnek?= Date: Tue, 14 Apr 2020 10:53:30 +0200 Subject: exfat-utils: update README file: Fixed typos. Replaces tabs with spaces. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Adam Jelínek --- README.md | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index ef89522..0c0098a 100644 --- a/README.md +++ b/README.md @@ -6,47 +6,47 @@ exfat-utils is mkfs(format)/fsck(repair) implementation for exfat filesystem und * Namjae Jeon * Hyunchul Lee -## Buidling exfat-utils -Install preprequisite packages: +## Building exfat-utils +Install prerequisite packages: ``` - For Ubuntu: - sudo apt-get install autoconf libtool pkg-config +For Ubuntu: + sudo apt-get install autoconf libtool pkg-config - For Fedora, RHEL: - sudo yum install autoconf automake libtool +For Fedora, RHEL: + sudo yum install autoconf automake libtool ``` Build steps: ``` - cd into the exfat-utils directory - ./autogen.sh - ./configure - make - make install + cd into the exfat-utils directory: + ./autogen.sh + ./configure + make + make install ``` ## Using exfat-utils ``` - mkfs.exfat: - Build a exfat filesystem on a device or partition(e.g. /dev/hda1, dev/sda1). + Build a exfat filesystem on a device or partition(e.g. /dev/hda1, dev/sda1). 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 + 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 - fsck.exfat: - Check the consistency of your exfat filesystem and optinally repair a corrupted device formatted by exfat. + Check the consistency of your exfat filesystem and optionally repair a corrupted device formatted by exfat. Usage example: - 1. check the consistency. - fsck.exfat /dev/sda1 - 2. repair and fix.(preparing) + 1. check the consistency. + fsck.exfat /dev/sda1 + 2. repair and fix.(preparing) ``` -- cgit v1.2.3 From a716859d2e7111d11865eefd533f9189efd4381d Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 15 Apr 2020 10:35:07 +0900 Subject: =?UTF-8?q?exfat-utils:=20fix=20error=20=E2=80=98=5F=5Fbuiltin=5Fs?= =?UTF-8?q?trncpy=E2=80=99=20specified=20bound=20255=20equals=20destinatio?= =?UTF-8?q?n=20size?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In function ‘strncpy’, inlined from ‘main’ at fsck.c:1256:2: /usr/include/x86_64-linux-gnu/bits/string_fortified.h:106:10: error: ‘__builtin_strncpy’ specified bound 255 equals destination size [-Werror=stringop-truncation] 106 | return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors Signed-off-by: Namjae Jeon --- fsck/fsck.c | 2 +- mkfs/mkfs.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index a167a96..4091c94 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1253,7 +1253,7 @@ int main(int argc, char * const argv[]) if (optind != argc - 1) usage(argv[0]); - strncpy(ui.ei.dev_name, argv[optind], sizeof(ui.ei.dev_name)); + snprintf(ui.ei.dev_name, sizeof(ui.ei.dev_name), "%s", argv[optind]); ret = exfat_get_blk_dev_info(&ui.ei, &bd); if (ret < 0) { exfat_err("failed to open %s. %d\n", ui.ei.dev_name, ret); diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 50a75ef..3a1bc33 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -626,8 +626,8 @@ int main(int argc, char *argv[]) usage(); } - memset(ui.dev_name, 0, 255); - strncpy(ui.dev_name, argv[optind], 255); + 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) -- cgit v1.2.3 From 1d0b464fa862755ffa2b5e9a88072505716c06d5 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 15 Apr 2020 10:46:30 +0900 Subject: exfat-utils: disable warning with gcc 9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In file included from fsck.c:15: fsck.c: In function ‘read_volume_label’: ../include/exfat_ondisk.h:205:31: error: taking address of packed member of ‘struct ’ may result in an unaligned pointer value [-Werror=address-of-packed-member] 205 | #define vol_label dentry.vol.volume_label fsck.c:901:30: note: in expansion of macro ‘vol_label’ 901 | if (exfat_utf16_dec(dentry->vol_label, dentry->vol_char_cnt*2, | ^~~~~~~~~ cc1: all warnings being treated as errors Signed-off-by: Namjae Jeon --- fsck/Makefile.am | 4 +++- mkfs/Makefile.am | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fsck/Makefile.am b/fsck/Makefile.am index e9cdc58..b8fa647 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -1,4 +1,6 @@ -AM_CFLAGS = -Wall -Werror -Wunused-parameter -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -Wall -Werror -Wunused-parameter \ + -Wno-address-of-packed-member \ + -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = fsck.exfat diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index b083363..5220911 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,4 +1,6 @@ -AM_CFLAGS = -Wall -Werror -Wunused-parameter -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -Wall -Werror -Wunused-parameter \ + -Wno-address-of-packed-member \ + -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lm mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.la -- cgit v1.2.3 From 2e736177d3e2000b53be655cd41be42324ec1f55 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 15 Apr 2020 11:11:01 +0900 Subject: exfat-utils: add simple format/repair test in travis-CI script Signed-off-by: Namjae Jeon --- .travis.yml | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index cecd184..d71dcc9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,34 @@ 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 + - export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH + - export PATH=/usr/local/lib:$PATH + script: - # Compilation - - ./autogen.sh - - ./configure - - make + - ./autogen.sh > /dev/null + - ./configure > /dev/null + - make -j$((`nproc`+1)) > /dev/null + - sudo make install > /dev/null + - sudo cp lib/.libs/libexfat.so* /lib/ + - 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 file$i;if [ $? != 0 ]; then exit 1; fi; i=$(($i + 1));done + - sync + - sudo rm -rf * + - sudo fsck.exfat /dev/loop22 + - cd - -- cgit v1.2.3 From 55b44250a61b89ca75f846adc8cc967c780c79a6 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Mon, 13 Apr 2020 11:16:31 +0200 Subject: exfat-utils: Remove unused variable --- lib/libexfat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libexfat.c b/lib/libexfat.c index 1d0722a..bba42d7 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -236,7 +236,7 @@ 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) { - size_t mbs_len, wcs_len, out_len, c_len, i; + size_t wcs_len, out_len, c_len, i; char c_str[MB_LEN_MAX]; wchar_t *wcs; mbstate_t ps; -- cgit v1.2.3 From 2de9ad30374d7b3bd4a27a3bbcd96a7e9689388b Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Thu, 9 Apr 2020 21:50:34 +0200 Subject: exfat-utils: Add Android.bp --- Android.bp | 20 ++++++++++++++++++++ fsck/Android.bp | 12 ++++++++++++ lib/Android.bp | 10 ++++++++++ mkfs/Android.bp | 12 ++++++++++++ 4 files changed, 54 insertions(+) create mode 100644 Android.bp create mode 100644 fsck/Android.bp create mode 100644 lib/Android.bp create mode 100644 mkfs/Android.bp diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..8547f6c --- /dev/null +++ b/Android.bp @@ -0,0 +1,20 @@ +// Copyright 2020 The Android Open Source Project + +cc_library_headers { + name: "libexfat-utils-headers", + export_include_dirs: [ + "include", + "mkfs", + "fsck", + ], +} + +cc_defaults { + name: "exfat-utils-defaults", + + cflags: [ + "-DEXFAT_TOOLS_VERSION=\"1.0.1\"", + ], + header_libs: ["libexfat-utils-headers"], + export_header_lib_headers: ["libexfat-utils-headers"], +} diff --git a/fsck/Android.bp b/fsck/Android.bp new file mode 100644 index 0000000..bd7e530 --- /dev/null +++ b/fsck/Android.bp @@ -0,0 +1,12 @@ +// Copyright 2020 The Android Open Source Project + +cc_binary { + name: "fsck.exfat", + + srcs: [ + "fsck.c", + "repair.c", + ], + defaults: ["exfat-utils-defaults"], + static_libs: ["libexfat"], +} diff --git a/lib/Android.bp b/lib/Android.bp new file mode 100644 index 0000000..a964f77 --- /dev/null +++ b/lib/Android.bp @@ -0,0 +1,10 @@ +// Copyright 2020 The Android Open Source Project + +cc_library_static { + name: "libexfat", + + srcs: [ + "libexfat.c", + ], + defaults: ["exfat-utils-defaults"], +} diff --git a/mkfs/Android.bp b/mkfs/Android.bp new file mode 100644 index 0000000..5d45d1d --- /dev/null +++ b/mkfs/Android.bp @@ -0,0 +1,12 @@ +// Copyright 2020 The Android Open Source Project + +cc_binary { + name: "mkfs.exfat", + + srcs: [ + "mkfs.c", + "upcase.c", + ], + defaults: ["exfat-utils-defaults"], + static_libs: ["libexfat"], +} -- cgit v1.2.3 From c7cd61e1414436ad051e2d14ff48675bef8e86e6 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Wed, 15 Apr 2020 16:26:15 +0200 Subject: exfat-utils: Move EXFAT_TOOLS_VERSION definition to an header --- Android.bp | 4 ---- configure.ac | 9 --------- include/version.h | 10 ++++++++++ lib/libexfat.c | 1 + 4 files changed, 11 insertions(+), 13 deletions(-) create mode 100644 include/version.h diff --git a/Android.bp b/Android.bp index 8547f6c..1c44183 100644 --- a/Android.bp +++ b/Android.bp @@ -11,10 +11,6 @@ cc_library_headers { cc_defaults { name: "exfat-utils-defaults", - - cflags: [ - "-DEXFAT_TOOLS_VERSION=\"1.0.1\"", - ], header_libs: ["libexfat-utils-headers"], export_header_lib_headers: ["libexfat-utils-headers"], } diff --git a/configure.ac b/configure.ac index 43df955..dfaeb68 100755 --- a/configure.ac +++ b/configure.ac @@ -1,17 +1,8 @@ AC_PREREQ([2.68]) -m4_define([exfat_tools_major_ver], [1]) -m4_define([exfat_tools_minor_ver], [0]) -m4_define([exfat_tools_micro_ver], [1]) - -m4_define([exfat_tools_version], - [exfat_tools_major_ver.exfat_tools_minor_ver.exfat_tools_micro_ver]) - AC_INIT([CIFSD tools], [exfat_tools_version], [linkinjeon@gmail.com]) -AC_DEFINE([EXFAT_TOOLS_VERSION], "exfat_tools_version", [exfat-tools version]) - AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADER([config.h]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/include/version.h b/include/version.h new file mode 100644 index 0000000..174a41c --- /dev/null +++ b/include/version.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Namjae Jeon + */ + +#ifndef _VERSION_H + +#define EXFAT_TOOLS_VERSION "1.0.1" + +#endif /* !_VERSION_H */ diff --git a/lib/libexfat.c b/lib/libexfat.c index bba42d7..c21c132 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -18,6 +18,7 @@ #include "exfat_ondisk.h" #include "exfat_tools.h" #include "mkfs.h" +#include "version.h" #ifdef WORDS_BIGENDIAN #define BITOP_LE_SWIZZLE (~0x7) -- cgit v1.2.3 From f0da5495278ca395e0c23169a035d70ec324efc7 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 17 Apr 2020 08:47:17 +0900 Subject: exfatprogs: rename exfat_tools.h to libexfat.h As the project name is renamed, rename the exfat-tools.h to libexfat.h. Signed-off-by: Namjae Jeon --- fsck/fsck.c | 2 +- fsck/repair.c | 2 +- include/exfat_tools.h | 104 -------------------------------------------------- include/libexfat.h | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/libexfat.c | 2 +- mkfs/mkfs.c | 2 +- mkfs/upcase.c | 2 +- 7 files changed, 109 insertions(+), 109 deletions(-) delete mode 100644 include/exfat_tools.h create mode 100644 include/libexfat.h diff --git a/fsck/fsck.c b/fsck/fsck.c index 4091c94..99fe449 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -13,7 +13,7 @@ #include #include "exfat_ondisk.h" -#include "exfat_tools.h" +#include "libexfat.h" #include "fsck.h" #include "repair.h" diff --git a/fsck/repair.c b/fsck/repair.c index f254d92..2c90299 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -6,7 +6,7 @@ #include #include "exfat_ondisk.h" -#include "exfat_tools.h" +#include "libexfat.h" #include "fsck.h" #include "repair.h" diff --git a/include/exfat_tools.h b/include/exfat_tools.h deleted file mode 100644 index 8112b2d..0000000 --- a/include/exfat_tools.h +++ /dev/null @@ -1,104 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019 Namjae Jeon - */ - -#ifndef _EXFAT_TOOLS_H - -#include -#include - -#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) - -/* Upcase tabel macro */ -#define EXFAT_UPCASE_TABLE_SIZE (5836) - -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 size; - unsigned int sector_size; - unsigned int sector_size_bits; - unsigned long long num_sectors; - unsigned int num_clusters; -}; - -struct exfat_user_input { - char dev_name[255]; - bool writeable; - unsigned int cluster_size; - unsigned int sec_per_clu; - bool quick; - __u16 volume_label[11]; - int volume_label_len; -}; - -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); -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); - -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); - -/* - * Exfat Print - */ - -extern unsigned int print_level; - -#define EXFAT_ERROR (0) -#define EXFAT_INFO (1) -#define EXFAT_DEBUG (2) - -#define exfat_msg(level, fmt, ...) \ - do { \ - if (print_level >= level) { \ - if (print_level == EXFAT_INFO) \ - printf(fmt, ##__VA_ARGS__); \ - else \ - printf("[%s:%4d] " fmt, \ - __func__, __LINE__, ##__VA_ARGS__); \ - } \ - } while (0) \ - -#define exfat_err(fmt, ...) exfat_msg(EXFAT_ERROR, fmt, ##__VA_ARGS__) -#define exfat_info(fmt, ...) exfat_msg(EXFAT_INFO, fmt, ##__VA_ARGS__) -#define exfat_debug(fmt, ...) exfat_msg(EXFAT_DEBUG, fmt, ##__VA_ARGS__) - -#endif /* !_EXFA_TOOLS_H */ diff --git a/include/libexfat.h b/include/libexfat.h new file mode 100644 index 0000000..30d749c --- /dev/null +++ b/include/libexfat.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019 Namjae Jeon + */ + +#ifndef _LIBEXFAT_H + +#include +#include + +#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) + +/* Upcase tabel macro */ +#define EXFAT_UPCASE_TABLE_SIZE (5836) + +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 size; + unsigned int sector_size; + unsigned int sector_size_bits; + unsigned long long num_sectors; + unsigned int num_clusters; +}; + +struct exfat_user_input { + char dev_name[255]; + bool writeable; + unsigned int cluster_size; + unsigned int sec_per_clu; + bool quick; + __u16 volume_label[11]; + int volume_label_len; +}; + +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); +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); + +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); + +/* + * Exfat Print + */ + +extern unsigned int print_level; + +#define EXFAT_ERROR (0) +#define EXFAT_INFO (1) +#define EXFAT_DEBUG (2) + +#define exfat_msg(level, fmt, ...) \ + do { \ + if (print_level >= level) { \ + if (print_level == EXFAT_INFO) \ + printf(fmt, ##__VA_ARGS__); \ + else \ + printf("[%s:%4d] " fmt, \ + __func__, __LINE__, ##__VA_ARGS__); \ + } \ + } while (0) \ + +#define exfat_err(fmt, ...) exfat_msg(EXFAT_ERROR, fmt, ##__VA_ARGS__) +#define exfat_info(fmt, ...) exfat_msg(EXFAT_INFO, fmt, ##__VA_ARGS__) +#define exfat_debug(fmt, ...) exfat_msg(EXFAT_DEBUG, fmt, ##__VA_ARGS__) + +#endif /* !_LIBEXFAT_H */ diff --git a/lib/libexfat.c b/lib/libexfat.c index c21c132..6eebfc5 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -16,7 +16,7 @@ #include #include "exfat_ondisk.h" -#include "exfat_tools.h" +#include "libexfat.h" #include "mkfs.h" #include "version.h" diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 3a1bc33..4a12c29 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -18,7 +18,7 @@ #include #include "exfat_ondisk.h" -#include "exfat_tools.h" +#include "libexfat.h" #include "mkfs.h" struct exfat_mkfs_info finfo; diff --git a/mkfs/upcase.c b/mkfs/upcase.c index 4b98282..797488d 100644 --- a/mkfs/upcase.c +++ b/mkfs/upcase.c @@ -9,7 +9,7 @@ #include #include "exfat_ondisk.h" -#include "exfat_tools.h" +#include "libexfat.h" #include "mkfs.h" static const unsigned char upcase_table[EXFAT_UPCASE_TABLE_SIZE] = { -- cgit v1.2.3 From 24be0bc61b8a680b7ba1a219cb7321a064082a46 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 17 Apr 2020 08:48:14 +0900 Subject: exfatprogs: rename version info to exfatprogs As the project name is renamed, show version info with efatprogs. Signed-off-by: Namjae Jeon --- configure.ac | 2 +- include/version.h | 2 +- lib/libexfat.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index dfaeb68..266aefa 100755 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ([2.68]) -AC_INIT([CIFSD tools], [exfat_tools_version], +AC_INIT([exfatprogs], [exfatprogs_version], [linkinjeon@gmail.com]) AC_CONFIG_SRCDIR([config.h.in]) diff --git a/include/version.h b/include/version.h index 174a41c..ffec9f4 100644 --- a/include/version.h +++ b/include/version.h @@ -5,6 +5,6 @@ #ifndef _VERSION_H -#define EXFAT_TOOLS_VERSION "1.0.1" +#define EXFAT_PROGS_VERSION "1.0.1" #endif /* !_VERSION_H */ diff --git a/lib/libexfat.c b/lib/libexfat.c index 6eebfc5..815fd0e 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -107,7 +107,7 @@ void boot_calc_checksum(unsigned char *sector, unsigned short size, void show_version(void) { - printf("exfat-tools version : %s\n", EXFAT_TOOLS_VERSION); + printf("exfatprogs version : %s\n", EXFAT_PROGS_VERSION); } static inline unsigned int sector_size_bits(unsigned int size) -- cgit v1.2.3 From 501ccac0a6d0f7b983850d76e6efcbcaa917e47b Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 17 Apr 2020 08:49:13 +0900 Subject: exfatprogs: rename exfat-utils to exfatprogs in README rename exfat-utils to exfatprogs in README. Signed-off-by: Namjae Jeon --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0c0098a..0b5cde9 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -## exfat-utils -exfat-utils is mkfs(format)/fsck(repair) implementation for exfat filesystem under GNU GPL version 2. +## exfatprogs +exfatprogs is userspace utilities for exfat filesystem under GNU GPL version 2. ## Maintainers * Namjae Jeon * Hyunchul Lee -## Building exfat-utils +## Building exfatprogs Install prerequisite packages: ``` For Ubuntu: @@ -18,14 +18,14 @@ For Fedora, RHEL: Build steps: ``` - cd into the exfat-utils directory: + cd into the exfatprogs directory: ./autogen.sh ./configure make make install ``` -## Using exfat-utils +## Using exfatprogs ``` - mkfs.exfat: Build a exfat filesystem on a device or partition(e.g. /dev/hda1, dev/sda1). -- cgit v1.2.3 From c0091463a1823a49d9bf427e314dbab29130e6c4 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 17 Apr 2020 08:50:15 +0900 Subject: exfatprogs: update my mail address Update my own email address to linkinjeon@kernel.org Signed-off-by: Namjae Jeon --- README.md | 2 +- configure.ac | 2 +- fsck/fsck.c | 2 +- include/exfat_ondisk.h | 2 +- include/libexfat.h | 2 +- include/mkfs.h | 2 +- include/version.h | 2 +- lib/libexfat.c | 2 +- mkfs/mkfs.c | 2 +- mkfs/upcase.c | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0b5cde9..20e2a5b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ exfatprogs is userspace utilities for exfat filesystem under GNU GPL version 2. ## Maintainers -* Namjae Jeon +* Namjae Jeon * Hyunchul Lee ## Building exfatprogs diff --git a/configure.ac b/configure.ac index 266aefa..7edd3a5 100755 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_PREREQ([2.68]) AC_INIT([exfatprogs], [exfatprogs_version], - [linkinjeon@gmail.com]) + [linkinjeon@kernel.org]) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADER([config.h]) diff --git a/fsck/fsck.c b/fsck/fsck.c index 99fe449..bd1b818 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2019 Namjae Jeon + * Copyright (C) 2019 Namjae Jeon * Copyright (C) 2020 Hyunchul Lee */ diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index 5dca178..ae2827b 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright (C) 2019 Namjae Jeon + * Copyright (C) 2019 Namjae Jeon */ #ifndef _EXFAT_H diff --git a/include/libexfat.h b/include/libexfat.h index 30d749c..4662920 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright (C) 2019 Namjae Jeon + * Copyright (C) 2019 Namjae Jeon */ #ifndef _LIBEXFAT_H diff --git a/include/mkfs.h b/include/mkfs.h index 1841ce1..013ea77 100644 --- a/include/mkfs.h +++ b/include/mkfs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright (C) 2019 Namjae Jeon + * Copyright (C) 2019 Namjae Jeon */ #ifndef _MKFS_H diff --git a/include/version.h b/include/version.h index ffec9f4..bc8ddaa 100644 --- a/include/version.h +++ b/include/version.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright (C) 2020 Namjae Jeon + * Copyright (C) 2020 Namjae Jeon */ #ifndef _VERSION_H diff --git a/lib/libexfat.c b/lib/libexfat.c index 815fd0e..bfe73b2 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2019 Namjae Jeon + * Copyright (C) 2019 Namjae Jeon */ #include diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 4a12c29..748204d 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2019 Namjae Jeon + * Copyright (C) 2019 Namjae Jeon */ #include diff --git a/mkfs/upcase.c b/mkfs/upcase.c index 797488d..8d5ef1a 100644 --- a/mkfs/upcase.c +++ b/mkfs/upcase.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2019 Namjae Jeon + * Copyright (C) 2019 Namjae Jeon */ #include -- cgit v1.2.3 From 864f66a2d3b187453bd6f2525192cee24bd657ef Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 17 Apr 2020 13:25:11 +0900 Subject: exfatprogs: get version from versio.h in configure.ac Signed-off-by: Hyunchul Lee --- configure.ac | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 7edd3a5..43a516a 100755 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,14 @@ AC_PREREQ([2.68]) -AC_INIT([exfatprogs], [exfatprogs_version], - [linkinjeon@kernel.org]) +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]) -- cgit v1.2.3 From f6241b1efbd7043c0a7e9df59487edc33ae0aa2f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 18 Apr 2020 23:10:33 +0900 Subject: exfaprogs: add missing warning options in lib/Makefile.am Signed-off-by: Namjae Jeon --- lib/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index da30483..2a53293 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,4 +1,6 @@ -AM_CFLAGS = -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -Wall -Werror -Wunused-parameter \ + -Wno-address-of-packed-member \ + -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lc lib_LTLIBRARIES = libexfat.la -- cgit v1.2.3 From 27573291c4127395849a664ee5737138cfcf3bdc Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 20 Apr 2020 11:21:56 +0900 Subject: fsck: free buffer for reading directory entries Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index bd1b818..96f0af2 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -193,6 +193,8 @@ static void free_exfat(struct exfat *exfat) if (exfat) { if (exfat->bs) free(exfat->bs); + if (exfat->de_iter.dentries) + free(exfat->de_iter.dentries); free(exfat); } } @@ -613,11 +615,6 @@ int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, return 0; } -void exfat_de_iter_fini(struct exfat_de_iter *iter) -{ - free(iter->dentries); -} - int exfat_de_iter_get(struct exfat_de_iter *iter, int ith, struct exfat_dentry **dentry) { -- cgit v1.2.3 From 6ca550ea92d8bd909ae47a1233de1c2eaaf8b184 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 20 Apr 2020 13:28:53 +0900 Subject: fsck: declare functions as static Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 96f0af2..9bef870 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -587,7 +587,7 @@ static int resolve_path_parent(struct path_resolve_ctx *ctx, return ret; } -int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, +static int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, struct exfat_inode *dir) { ssize_t ret; @@ -615,8 +615,8 @@ int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, return 0; } -int exfat_de_iter_get(struct exfat_de_iter *iter, - int ith, struct exfat_dentry **dentry) +static int exfat_de_iter_get(struct exfat_de_iter *iter, + int ith, struct exfat_dentry **dentry) { off_t de_next_file_offset; int de_next_offset; @@ -671,7 +671,7 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, * @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) +static int exfat_de_iter_advance(struct exfat_de_iter *iter, int skip_dentries) { if (skip_dentries != iter->max_skip_dentries) return -EINVAL; @@ -682,7 +682,7 @@ int exfat_de_iter_advance(struct exfat_de_iter *iter, int skip_dentries) return 0; } -off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter) +static off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter) { return iter->de_file_offset; } -- cgit v1.2.3 From 34d9d31652299bab3ae116f6e3e4626282dd0bef Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 20 Apr 2020 13:39:40 +0900 Subject: fsck: free in-memory bitmap Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index 9bef870..ebcb167 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -195,6 +195,8 @@ static void free_exfat(struct exfat *exfat) free(exfat->bs); if (exfat->de_iter.dentries) free(exfat->de_iter.dentries); + if (exfat->alloc_bitmap) + free(exfat->alloc_bitmap); free(exfat); } } -- cgit v1.2.3 From c7daf3a710cd672158aafa7cc4e8268ba6d1da63 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 20 Apr 2020 14:42:02 +0900 Subject: fsck: fix maybe-uninitialized warning in read_children Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index ebcb167..0a8aca8 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1014,7 +1014,7 @@ static bool read_upcase_table(struct exfat_de_iter *iter) static int read_children(struct exfat *exfat, struct exfat_inode *dir) { int ret; - struct exfat_inode *node; + struct exfat_inode *node = NULL; struct exfat_dentry *dentry; int dentry_count; struct list_head sub_dir_list; -- cgit v1.2.3 From 9fad0dca7af652755582f436bc07d870ab2e3aff Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 20 Apr 2020 21:17:16 +0900 Subject: mkfs: fix typo in option opts Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 748204d..fcdadd6 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -401,7 +401,7 @@ static void usage(void) } static struct option opts[] = { - {"volme-label", required_argument, NULL, 'l' }, + {"volume-label", required_argument, NULL, 'l' }, {"cluster-size", required_argument, NULL, 'c' }, {"full-format", no_argument, NULL, 'f' }, {"version", no_argument, NULL, 'V' }, -- cgit v1.2.3 From 226d160d23c160845d2e340760514c70356ea197 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 20 Apr 2020 21:18:30 +0900 Subject: mkfs: fix typo in make_exfat Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index fcdadd6..180ea70 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -524,7 +524,7 @@ static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui) if (ret) return ret; - exfat_msg(EXFAT_INFO, "Upcate table creation: "); + exfat_msg(EXFAT_INFO, "Upcase table creation: "); ret = exfat_create_upcase_table(bd); exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); if (ret) -- cgit v1.2.3 From b2205767a814bd250ee9730798335316139b2283 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 21 Apr 2020 16:39:56 +0900 Subject: mkfs: move init_user_input to libexfat Move init_user_input to libexfat.c. Signed-off-by: Namjae Jeon --- include/libexfat.h | 1 + lib/libexfat.c | 7 +++++++ mkfs/mkfs.c | 7 ------- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/libexfat.h b/include/libexfat.h index 4662920..ed1fb4c 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -67,6 +67,7 @@ void exfat_clear_bit(struct exfat_blk_dev *bd, char *bitmap, 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); diff --git a/lib/libexfat.c b/lib/libexfat.c index bfe73b2..56f71ac 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -133,6 +133,13 @@ static void exfat_set_default_cluster_size(struct exfat_blk_dev *bd, 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) { diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 180ea70..efaf5d8 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -410,13 +410,6 @@ static struct option opts[] = { {NULL, 0, NULL, 0 } }; -static void init_user_input(struct exfat_user_input *ui) -{ - memset(ui, 0, sizeof(struct exfat_user_input)); - ui->writeable = true; - ui->quick = true; -} - static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { -- cgit v1.2.3 From 8d1422804e1e0488eab037a72dd0046a596c6bee Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 21 Apr 2020 17:11:25 +0900 Subject: exfatprogs: add label.exfat Add label.exfat in exfatprogs. Get or set volume label from a given device. Usage example: 1. get volume label. label.exfat -g /dev/sda1 2. set new volume label. label.exfat -s "new label" /dev/sda1 Signed-off-by: Namjae Jeon --- Makefile.am | 2 +- configure.ac | 1 + label/Makefile.am | 8 +++ label/label.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 label/Makefile.am create mode 100644 label/label.c diff --git a/Makefile.am b/Makefile.am index 21676de..e9c2626 100755 --- a/Makefile.am +++ b/Makefile.am @@ -2,4 +2,4 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = lib mkfs fsck +SUBDIRS = lib mkfs fsck label diff --git a/configure.ac b/configure.ac index 43a516a..d9f6115 100755 --- a/configure.ac +++ b/configure.ac @@ -31,6 +31,7 @@ AC_CONFIG_FILES([ lib/Makefile mkfs/Makefile fsck/Makefile + label/Makefile ]) AC_OUTPUT diff --git a/label/Makefile.am b/label/Makefile.am new file mode 100644 index 0000000..ebe962a --- /dev/null +++ b/label/Makefile.am @@ -0,0 +1,8 @@ +AM_CFLAGS = -Wall -Werror -Wunused-parameter \ + -Wno-address-of-packed-member \ + -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +label_exfat_LDADD = $(top_builddir)/lib/libexfat.la + +sbin_PROGRAMS = label.exfat + +label_exfat_SOURCES = label.c diff --git a/label/label.c b/label/label.c new file mode 100644 index 0000000..9e5a592 --- /dev/null +++ b/label/label.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Namjae Jeon + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "exfat_ondisk.h" +#include "libexfat.h" + +static void usage(void) +{ + fprintf(stderr, "Usage: label.exfat\n"); + fprintf(stderr, "\t-g | --get-label Get volume label\n"); + fprintf(stderr, "\t-s | --set-label Set volume label\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[] = { + {"get-label", no_argument, NULL, 'g' }, + {"set-label", required_argument, NULL, 's' }, + {"version", no_argument, NULL, 'V' }, + {"verbose", no_argument, NULL, 'v' }, + {"help", no_argument, NULL, 'h' }, + {"?", no_argument, NULL, '?' }, + {NULL, 0, NULL, 0 } +}; + +static off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) +{ + struct pbr *bs; + int nbytes; + unsigned int cluster_size; + off_t root_clu_off; + + bs = (struct pbr *)malloc(sizeof(struct pbr)); + if (!bs) { + exfat_err("failed to allocate memory\n"); + return -ENOMEM; + } + + nbytes = exfat_read(bd->dev_fd, bs, sizeof(struct pbr), 0); + if (nbytes != sizeof(struct pbr)) { + exfat_err("boot sector read failed: %d\n", errno); + return -1; + } + + cluster_size = (1 << bs->bsx.sect_per_clus_bits) * bd->sector_size; + root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * bd->sector_size + + le32_to_cpu(bs->bsx.root_cluster - EXFAT_REVERVED_CLUSTERS) + * cluster_size; + free(bs); + + exfat_debug("root cluster offset : %ld\n", root_clu_off); + return root_clu_off; +} + +static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) +{ + struct exfat_dentry *vol_entry; + char volume_label[11]; + 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); + return -1; + } + + if (exfat_utf16_dec(vol_entry->vol_label, vol_entry->vol_char_cnt*2, + volume_label, sizeof(volume_label)) < 0) { + exfat_err("failed to decode volume label\n"); + return -1; + } + + exfat_msg(EXFAT_INFO, "label: %s\n", volume_label); + return 0; +} + +static 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[11]; + 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, 22); + 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_msg(EXFAT_INFO, "new label: %s\n", label_input); + return 0; +} + +#define EXFAT_GET_LABEL 0x1 +#define EXFAT_SET_LABEL 0x2 + +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[11]; + off_t root_clu_off; + + init_user_input(&ui); + + if (!setlocale(LC_CTYPE, "")) + exfat_msg(EXFAT_ERROR, "failed to init locale/codeset\n"); + + opterr = 0; + while ((c = getopt_long(argc, argv, "s:gVvh", opts, NULL)) != EOF) + switch (c) { + case 'g': + flags = EXFAT_GET_LABEL; + break; + case 's': + strncpy(label_input, optarg, 11); + flags = EXFAT_SET_LABEL; + 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; + + root_clu_off = exfat_get_root_entry_offset(&bd); + if (root_clu_off < 0) + goto out; + + if (flags == EXFAT_GET_LABEL) + ret = exfat_get_volume_label(&bd, root_clu_off); + else if (flags == EXFAT_SET_LABEL) + ret = exfat_set_volume_label(&bd, label_input, root_clu_off); + +out: + return ret; +} -- cgit v1.2.3 From 98e70828b23d68b6853fec15c0f032aff0f1bfa4 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 21 Apr 2020 16:42:43 +0900 Subject: label: add Android.bp file Add Android.bp file for label. Signed-off-by: Namjae Jeon --- label/Android.bp | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 label/Android.bp diff --git a/label/Android.bp b/label/Android.bp new file mode 100644 index 0000000..846423e --- /dev/null +++ b/label/Android.bp @@ -0,0 +1,11 @@ +// Copyright 2020 The Android Open Source Project + +cc_binary { + name: "label.exfat", + + srcs: [ + "label.c", + ], + defaults: ["exfat-utils-defaults"], + static_libs: ["libexfat"], +} -- cgit v1.2.3 From 076da32100a658035c8736db2770323ae611a967 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 21 Apr 2020 16:46:08 +0900 Subject: exfatprogs: rename old name to exfatprogs in Android.bp files Rename old name to exfatprogs in Android.bp. Signed-off-by: Namjae Jeon --- Android.bp | 8 ++++---- fsck/Android.bp | 2 +- label/Android.bp | 2 +- lib/Android.bp | 2 +- mkfs/Android.bp | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Android.bp b/Android.bp index 1c44183..6982941 100644 --- a/Android.bp +++ b/Android.bp @@ -1,7 +1,7 @@ // Copyright 2020 The Android Open Source Project cc_library_headers { - name: "libexfat-utils-headers", + name: "libexfatprogs-headers", export_include_dirs: [ "include", "mkfs", @@ -10,7 +10,7 @@ cc_library_headers { } cc_defaults { - name: "exfat-utils-defaults", - header_libs: ["libexfat-utils-headers"], - export_header_lib_headers: ["libexfat-utils-headers"], + name: "exfatprogs-defaults", + header_libs: ["libexfatprogs-headers"], + export_header_lib_headers: ["libexfatprogs-headers"], } diff --git a/fsck/Android.bp b/fsck/Android.bp index bd7e530..7473fea 100644 --- a/fsck/Android.bp +++ b/fsck/Android.bp @@ -7,6 +7,6 @@ cc_binary { "fsck.c", "repair.c", ], - defaults: ["exfat-utils-defaults"], + defaults: ["exfatprogs-defaults"], static_libs: ["libexfat"], } diff --git a/label/Android.bp b/label/Android.bp index 846423e..87d0e83 100644 --- a/label/Android.bp +++ b/label/Android.bp @@ -6,6 +6,6 @@ cc_binary { srcs: [ "label.c", ], - defaults: ["exfat-utils-defaults"], + defaults: ["exfatprogs-defaults"], static_libs: ["libexfat"], } diff --git a/lib/Android.bp b/lib/Android.bp index a964f77..0ccf6aa 100644 --- a/lib/Android.bp +++ b/lib/Android.bp @@ -6,5 +6,5 @@ cc_library_static { srcs: [ "libexfat.c", ], - defaults: ["exfat-utils-defaults"], + defaults: ["exfatprogs-defaults"], } diff --git a/mkfs/Android.bp b/mkfs/Android.bp index 5d45d1d..90e2e7f 100644 --- a/mkfs/Android.bp +++ b/mkfs/Android.bp @@ -7,6 +7,6 @@ cc_binary { "mkfs.c", "upcase.c", ], - defaults: ["exfat-utils-defaults"], + defaults: ["exfatprogs-defaults"], static_libs: ["libexfat"], } -- cgit v1.2.3 From 695b1aba2f92d036d78c3f98ae37bbbc6d19f3ec Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 21 Apr 2020 17:13:43 +0900 Subject: libexfat: add error print in device open add error print in device open. Signed-off-by: Namjae Jeon --- lib/libexfat.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/libexfat.c b/lib/libexfat.c index 56f71ac..7830bbd 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -147,9 +147,11 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, off_t blk_dev_size; fd = open(ui->dev_name, ui->writeable ? O_RDWR : O_RDONLY); - if (fd < 0) + if (fd < 0) { + exfat_err("open failed : %s, errno : %d\n", ui->dev_name, + errno); return -1; - + } blk_dev_size = lseek(fd, 0, SEEK_END); if (blk_dev_size <= 0) { exfat_msg(EXFAT_ERROR, -- cgit v1.2.3 From 5ac693a49d495a2c8836780643afd0c247714f96 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 21 Apr 2020 16:49:20 +0900 Subject: mkfs: add missing verbose in option add missing verbose in mkfs option. Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index efaf5d8..6d36f70 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -405,6 +405,7 @@ static struct option opts[] = { {"cluster-size", required_argument, NULL, 'c' }, {"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 } -- cgit v1.2.3 From 766c2e59c91ae975e8accdce591619894d0902ce Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 21 Apr 2020 16:55:42 +0900 Subject: exfatprogs: add label.exfat usage in README add label.exfat usage in README. Signed-off-by: Namjae Jeon --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 20e2a5b..c41e40b 100644 --- a/README.md +++ b/README.md @@ -49,4 +49,13 @@ Usage example: 1. check the consistency. fsck.exfat /dev/sda1 2. repair and fix.(preparing) + +- label.exfat: + Get or set volume label from a given device that formatted by exfat filesystem. + +Usage example: + 1. get volume label. + label.exfat -g /dev/sda1 + 2. set new volume label. + label.exfat -s "new label" /dev/sda1 ``` -- cgit v1.2.3 From 0d3ab1169bbcfbe6d0a9a9bfe060f982fdb45023 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 21 Apr 2020 21:31:25 +0900 Subject: exfatprogs: replace exfat_ with EXFAT_ Replace exfat_ with EXFAT_. Signed-off-by: Namjae Jeon --- label/label.c | 8 ++--- lib/libexfat.c | 13 ++++---- mkfs/mkfs.c | 100 +++++++++++++++++++++++++-------------------------------- 3 files changed, 54 insertions(+), 67 deletions(-) diff --git a/label/label.c b/label/label.c index 9e5a592..ec02680 100644 --- a/label/label.c +++ b/label/label.c @@ -90,7 +90,7 @@ static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) return -1; } - exfat_msg(EXFAT_INFO, "label: %s\n", volume_label); + exfat_info("label: %s\n", volume_label); return 0; } @@ -122,7 +122,7 @@ static int exfat_set_volume_label(struct exfat_blk_dev *bd, } fsync(bd->dev_fd); - exfat_msg(EXFAT_INFO, "new label: %s\n", label_input); + exfat_info("new label: %s\n", label_input); return 0; } @@ -143,7 +143,7 @@ int main(int argc, char *argv[]) init_user_input(&ui); if (!setlocale(LC_CTYPE, "")) - exfat_msg(EXFAT_ERROR, "failed to init locale/codeset\n"); + exfat_err("failed to init locale/codeset\n"); opterr = 0; while ((c = getopt_long(argc, argv, "s:gVvh", opts, NULL)) != EOF) @@ -152,7 +152,7 @@ int main(int argc, char *argv[]) flags = EXFAT_GET_LABEL; break; case 's': - strncpy(label_input, optarg, 11); + snprintf(label_input, 11, "%s", optarg); flags = EXFAT_SET_LABEL; break; case 'V': diff --git a/lib/libexfat.c b/lib/libexfat.c index 7830bbd..f90eedd 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -154,8 +154,7 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, } blk_dev_size = lseek(fd, 0, SEEK_END); if (blk_dev_size <= 0) { - exfat_msg(EXFAT_ERROR, - "invalid block device size(%s)\n", + exfat_err("invalid block device size(%s)\n", ui->dev_name); ret = blk_dev_size; close(fd); @@ -173,12 +172,12 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, bd->num_sectors = blk_dev_size / DEFAULT_SECTOR_SIZE; bd->num_clusters = blk_dev_size / ui->cluster_size; - exfat_msg(EXFAT_DEBUG, "Block device name : %s\n", ui->dev_name); - exfat_msg(EXFAT_DEBUG, "Block device size : %lld\n", bd->size); - exfat_msg(EXFAT_DEBUG, "Block sector size : %u\n", bd->sector_size); - exfat_msg(EXFAT_DEBUG, "Number of the sectors : %llu\n", + exfat_debug("Block device name : %s\n", ui->dev_name); + exfat_debug("Block device size : %lld\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_msg(EXFAT_DEBUG, "Number of the clusters : %u\n", + exfat_debug("Number of the clusters : %u\n", bd->num_clusters); ret = 0; diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 6d36f70..021a51a 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -57,21 +57,21 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, memset(ppbr->boot_code, 0, 390); ppbr->signature = cpu_to_le16(PBR_SIGNATURE); - exfat_msg(EXFAT_DEBUG, "Volume Length(sectors) : %llu\n", + exfat_debug("Volume Length(sectors) : %llu\n", le64_to_cpu(pbsx->vol_length)); - exfat_msg(EXFAT_DEBUG, "FAT Offset(sector offset) : %u\n", + exfat_debug("FAT Offset(sector offset) : %u\n", le32_to_cpu(pbsx->fat_offset)); - exfat_msg(EXFAT_DEBUG, "FAT Length(sectors) : %u\n", + exfat_debug("FAT Length(sectors) : %u\n", le32_to_cpu(pbsx->fat_length)); - exfat_msg(EXFAT_DEBUG, "Cluster Heap Offset (sector offset) : %u\n", + exfat_debug("Cluster Heap Offset (sector offset) : %u\n", le32_to_cpu(pbsx->clu_offset)); - exfat_msg(EXFAT_DEBUG, "Cluster Count (sectors) : %u\n", + exfat_debug("Cluster Count (sectors) : %u\n", le32_to_cpu(pbsx->clu_count)); - exfat_msg(EXFAT_DEBUG, "Root Cluster (cluster offset) : %u\n", + exfat_debug("Root Cluster (cluster offset) : %u\n", le32_to_cpu(pbsx->root_cluster)); - exfat_msg(EXFAT_DEBUG, "Sector Size Bits : %u\n", + exfat_debug("Sector Size Bits : %u\n", pbsx->sect_size_bits); - exfat_msg(EXFAT_DEBUG, "Sector per Cluster bits : %u\n", + exfat_debug("Sector per Cluster bits : %u\n", pbsx->sect_per_clus_bits); } @@ -84,8 +84,7 @@ static int exfat_write_sector(struct exfat_blk_dev *bd, void *buf, lseek(bd->dev_fd, offset, SEEK_SET); bytes = write(bd->dev_fd, buf, bd->sector_size); if (bytes != bd->sector_size) { - exfat_msg(EXFAT_ERROR, - "write failed, sec_off : %u, bytes : %d\n", sec_off, + exfat_err("write failed, sec_off : %u, bytes : %d\n", sec_off, bytes); return -1; } @@ -105,7 +104,7 @@ static int exfat_write_boot_sector(struct exfat_blk_dev *bd, ppbr = malloc(sizeof(struct pbr)); if (!ppbr) { - exfat_msg(EXFAT_ERROR, "Cannot allocate pbr: out of memory\n"); + exfat_err("Cannot allocate pbr: out of memory\n"); return -1; } memset(ppbr, 0, sizeof(struct pbr)); @@ -115,8 +114,7 @@ static int exfat_write_boot_sector(struct exfat_blk_dev *bd, /* write main boot sector */ ret = exfat_write_sector(bd, ppbr, sec_idx); if (ret < 0) { - exfat_msg(EXFAT_ERROR, - "main boot sector write failed\n"); + exfat_err("main boot sector write failed\n"); ret = -1; goto free_ppbr; } @@ -143,8 +141,7 @@ static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd, eb.signature = cpu_to_le16(PBR_SIGNATURE); for (i = 0; i < EXBOOT_SEC_NUM; i++) { if (exfat_write_sector(bd, &eb, sec_idx++)) { - exfat_msg(EXFAT_ERROR, - "extended boot sector write failed\n"); + exfat_err("extended boot sector write failed\n"); return -1; } @@ -172,7 +169,7 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, memset(oem, 0xFF, bd->sector_size); ret = exfat_write_sector(bd, oem, sec_idx); if (ret) { - exfat_msg(EXFAT_ERROR, "oem sector write failed\n"); + exfat_err("oem sector write failed\n"); ret = -1; goto free_oem; } @@ -184,7 +181,7 @@ static int exfat_write_oem_sector(struct exfat_blk_dev *bd, memset(oem, 0, bd->sector_size); ret = exfat_write_sector(bd, oem, sec_idx + 1); if (ret) { - exfat_msg(EXFAT_ERROR, "reserved sector write failed\n"); + exfat_err("reserved sector write failed\n"); ret = -1; goto free_oem; } @@ -216,7 +213,7 @@ static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, ret = exfat_write_sector(bd, checksum_buf, sec_idx); if (ret) { - exfat_msg(EXFAT_ERROR, "checksum sector write failed\n"); + exfat_err("checksum sector write failed\n"); goto free; } @@ -252,8 +249,7 @@ static int write_fat_entry(int fd, __le32 clu, lseek(fd, finfo.fat_byte_off + (offset * sizeof(__le32)), SEEK_SET); nbyte = write(fd, (__u8 *) &clu, sizeof(__le32)); if (nbyte != sizeof(int)) { - exfat_msg(EXFAT_ERROR, - "write failed, offset : %llu, clu : %x\n", + exfat_err("write failed, offset : %llu, clu : %x\n", offset, clu); return -1; } @@ -290,16 +286,14 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, /* fat entry 0 should be media type field(0xF8) */ ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xfffffff8), 0); if (ret) { - exfat_msg(EXFAT_ERROR, - "fat 0 entry write failed\n"); + 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_msg(EXFAT_ERROR, - "fat 1 entry write failed\n"); + exfat_err("fat 1 entry write failed\n"); return ret; } @@ -320,8 +314,7 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, return ret; finfo.used_clu_cnt = clu + 1; - exfat_msg(EXFAT_DEBUG, "Total used cluster count : %d\n", - finfo.used_clu_cnt); + exfat_debug("Total used cluster count : %d\n", finfo.used_clu_cnt); return ret; } @@ -341,8 +334,7 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd) lseek(bd->dev_fd, finfo.bitmap_byte_off, SEEK_SET); nbytes = write(bd->dev_fd, bitmap, finfo.bitmap_byte_len); if (nbytes != finfo.bitmap_byte_len) { - exfat_msg(EXFAT_ERROR, - "write failed, nbytes : %d, bitmap_len : %d\n", + exfat_err("write failed, nbytes : %d, bitmap_len : %d\n", nbytes, finfo.bitmap_byte_len); return -1; } @@ -378,8 +370,7 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, lseek(bd->dev_fd, finfo.root_byte_off, SEEK_SET); nbytes = write(bd->dev_fd, ed, dentries_len); if (nbytes != dentries_len) { - exfat_msg(EXFAT_ERROR, - "write failed, nbytes : %d, dentries_len : %d\n", + exfat_err("write failed, nbytes : %d, dentries_len : %d\n", nbytes, dentries_len); return -1; } @@ -425,7 +416,7 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; if (finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) { - exfat_msg(EXFAT_ERROR, "cluster size is too small\n"); + exfat_err("cluster size is too small\n"); return -1; } @@ -471,16 +462,14 @@ static int exfat_zero_out_disk(struct exfat_blk_dev *bd, nbytes = write(bd->dev_fd, buf, chunk_size); if (nbytes <= 0) { if (nbytes < 0) - exfat_msg(EXFAT_ERROR, - "write failed(errno : %d)\n", errno); + exfat_err("write failed(errno : %d)\n", errno); break; } total_written += nbytes; } while (total_written < size); free(buf); - exfat_msg(EXFAT_DEBUG, - "zero out written size : %llu, disk size : %llu\n", + exfat_debug("zero out written size : %llu, disk size : %llu\n", total_written, bd->size); return 0; } @@ -489,44 +478,43 @@ static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { int ret; - exfat_msg(EXFAT_INFO, - "Creating exFAT filesystem(%s, cluster size=%u)\n\n", + exfat_info("Creating exFAT filesystem(%s, cluster size=%u)\n\n", ui->dev_name, ui->cluster_size); - exfat_msg(EXFAT_INFO, "Writing volume boot record: "); + exfat_info("Writing volume boot record: "); ret = exfat_create_volume_boot_record(bd, ui, 0); - exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + exfat_info("%s\n", ret ? "failed" : "done"); if (ret) return ret; - exfat_msg(EXFAT_INFO, "Writing backup volume boot record: "); + exfat_info("Writing backup volume boot record: "); /* backup sector */ ret = exfat_create_volume_boot_record(bd, ui, 1); - exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + exfat_info("%s\n", ret ? "failed" : "done"); if (ret) return ret; - exfat_msg(EXFAT_INFO, "Fat table creation: "); + exfat_info("Fat table creation: "); ret = exfat_create_fat_table(bd, ui); - exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + exfat_info("%s\n", ret ? "failed" : "done"); if (ret) return ret; - exfat_msg(EXFAT_INFO, "Allocation bitmap creation: "); + exfat_info("Allocation bitmap creation: "); ret = exfat_create_bitmap(bd); - exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + exfat_info("%s\n", ret ? "failed" : "done"); if (ret) return ret; - exfat_msg(EXFAT_INFO, "Upcase table creation: "); + exfat_info("Upcase table creation: "); ret = exfat_create_upcase_table(bd); - exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + exfat_info("%s\n", ret ? "failed" : "done"); if (ret) return ret; - exfat_msg(EXFAT_INFO, "Writing root directory entry: "); + exfat_info("Writing root directory entry: "); ret = exfat_create_root_dir(bd, ui); - exfat_msg(EXFAT_INFO, "%s\n", ret ? "failed" : "done"); + exfat_info("%s\n", ret ? "failed" : "done"); if (ret) return ret; @@ -547,7 +535,8 @@ static long long parse_cluster_size(const char *size) byte_size <<= 10; break; default: - exfat_msg(EXFAT_ERROR, "Wrong unit input('%c') for cluster size\n", *data_unit); + exfat_err("Wrong unit input('%c') for cluster size\n", + *data_unit); return -EINVAL; } @@ -565,7 +554,7 @@ int main(int argc, char *argv[]) init_user_input(&ui); if (!setlocale(LC_CTYPE, "")) - exfat_msg(EXFAT_ERROR, "failed to init locale/codeset\n"); + exfat_err("failed to init locale/codeset\n"); opterr = 0; while ((c = getopt_long(argc, argv, "n:l:c:fVvh", opts, NULL)) != EOF) @@ -590,8 +579,7 @@ int main(int argc, char *argv[]) if (ret < 0) goto out; else if (ret > EXFAT_MAX_CLUSTER_SIZE) { - exfat_msg(EXFAT_ERROR, - "cluster size(%d) exceeds max cluster size(%d)\n", + exfat_err("cluster size(%d) exceeds max cluster size(%d)\n", ui.cluster_size, EXFAT_MAX_CLUSTER_SIZE); goto out; } @@ -639,13 +627,13 @@ int main(int argc, char *argv[]) if (ret) goto out; - exfat_msg(EXFAT_INFO, "Synchronizing... \n"); + exfat_info("Synchronizing...\n"); ret = fsync(bd.dev_fd); out: if (!ret) - exfat_msg(EXFAT_INFO, "\nexFAT format complete!\n"); + exfat_info("\nexFAT format complete!\n"); else - exfat_msg(EXFAT_INFO, "\nexFAT format fail!\n"); + exfat_info("\nexFAT format fail!\n"); close(bd.dev_fd); return ret; } -- cgit v1.2.3 From 4fcd00d1543579e348177ea766f7f635d78d9bcb Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 22 Apr 2020 10:05:45 +0900 Subject: fsck: cache the last read cluster to speed up sequential read fsck reads files sequentially, So fsck can avoid to read cluster chain from the beginning. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 20 +++++++++++++++----- fsck/fsck.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 0a8aca8..b0e3c47 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -107,11 +107,12 @@ static struct exfat_inode *alloc_exfat_inode(__u16 attr) INIT_LIST_HEAD(&node->sibling); INIT_LIST_HEAD(&node->list); + node->last_pclus = EXFAT_EOF_CLUSTER; + node->attr = attr; if (attr & ATTR_SUBDIR) exfat_stat.dir_count++; else exfat_stat.file_count++; - node->attr = attr; return node; } @@ -336,10 +337,16 @@ static ssize_t exfat_file_read(struct exfat *exfat, struct exfat_inode *node, if (remain_size == 0) return 0; - p_clus = node->first_clus; - clus_offset = file_offset % clus_size; start_l_clus = file_offset / clus_size; - l_clus = 0; + clus_offset = file_offset % clus_size; + if (start_l_clus >= node->last_lclus && + node->last_pclus != EXFAT_EOF_CLUSTER) { + l_clus = node->last_lclus; + p_clus = node->last_pclus; + } else { + l_clus = 0; + p_clus = node->first_clus; + } while (p_clus != EXFAT_EOF_CLUSTER) { if (exfat_invalid_clus(exfat, p_clus)) @@ -357,7 +364,7 @@ static ssize_t exfat_file_read(struct exfat *exfat, struct exfat_inode *node, buf = (char *)buf + read_size; remain_size -= read_size; if (remain_size == 0) - return total_size; + goto out; next_clus: l_clus++; @@ -365,6 +372,9 @@ next_clus: if (ret) return ret; } +out: + node->last_lclus = l_clus; + node->last_pclus = p_clus; return total_size - remain_size; } diff --git a/fsck/fsck.h b/fsck/fsck.h index ffbf79f..e04d199 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -17,6 +17,8 @@ struct exfat_inode { struct list_head sibling; struct list_head list; clus_t first_clus; + clus_t last_lclus; + clus_t last_pclus; __u16 attr; __u64 size; bool is_contiguous; -- cgit v1.2.3 From 08890f53a1d1390b6c465b2dbf28c65d07616a45 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 22 Apr 2020 10:40:51 +0900 Subject: fsck: rename read_child to read_file Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index b0e3c47..9e04407 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -864,7 +864,7 @@ err: return ret; } -static int read_child(struct exfat_de_iter *de_iter, +static int read_file(struct exfat_de_iter *de_iter, struct exfat_inode **new_node, int *dentry_count) { struct exfat_inode *node; @@ -1052,7 +1052,7 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) switch (dentry->type) { case EXFAT_FILE: - ret = read_child(de_iter, &node, &dentry_count); + ret = read_file(de_iter, &node, &dentry_count); if (ret) { exfat_err("failed to verify file. %d\n", ret); goto err; -- cgit v1.2.3 From 1c7c0bfc32ea2f892c48969f8e702a5fe6aa9c79 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 24 Apr 2020 15:48:01 +0900 Subject: label: remove unneeded debug print Signed-off-by: Namjae Jeon --- label/label.c | 1 - 1 file changed, 1 deletion(-) diff --git a/label/label.c b/label/label.c index ec02680..f7b5958 100644 --- a/label/label.c +++ b/label/label.c @@ -61,7 +61,6 @@ static off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) * cluster_size; free(bs); - exfat_debug("root cluster offset : %ld\n", root_clu_off); return root_clu_off; } -- cgit v1.2.3 From cac9f32c1352986723e7b8eb7c094299d0d611fa Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 23 Apr 2020 17:19:13 +0900 Subject: exfatprogs: release 1.0.2 version The major changes in this release: * Rename project name to exfatprogs. * label.exfat: Add support for label.exfat to set/get exfat volume label. * Replace iconv library by standard C functions mbstowcs() and wcrtomb(). * 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. * Add support for Android build system. Signed-off-by: Namjae Jeon --- include/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/version.h b/include/version.h index bc8ddaa..7a3f8d4 100644 --- a/include/version.h +++ b/include/version.h @@ -5,6 +5,6 @@ #ifndef _VERSION_H -#define EXFAT_PROGS_VERSION "1.0.1" +#define EXFAT_PROGS_VERSION "1.0.2" #endif /* !_VERSION_H */ -- cgit v1.2.3 From ad6699575658874a08aa034f42f7649f7e427690 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 24 Apr 2020 15:48:01 +0900 Subject: label: remove unneeded debug print Signed-off-by: Namjae Jeon --- label/label.c | 1 - 1 file changed, 1 deletion(-) diff --git a/label/label.c b/label/label.c index ec02680..f7b5958 100644 --- a/label/label.c +++ b/label/label.c @@ -61,7 +61,6 @@ static off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) * cluster_size; free(bs); - exfat_debug("root cluster offset : %ld\n", root_clu_off); return root_clu_off; } -- cgit v1.2.3 From 4f2b9649f0334d39a085fc177ec7513d79dd3c9a Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 23 Apr 2020 17:19:13 +0900 Subject: exfatprogs: release 1.0.2 version The major changes in this release: * Rename project name to exfatprogs. * label.exfat: Add support for label.exfat to set/get exfat volume label. * Replace iconv library by standard C functions mbstowcs() and wcrtomb(). * 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. * Add support for Android build system. Signed-off-by: Namjae Jeon --- include/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/version.h b/include/version.h index bc8ddaa..7a3f8d4 100644 --- a/include/version.h +++ b/include/version.h @@ -5,6 +5,6 @@ #ifndef _VERSION_H -#define EXFAT_PROGS_VERSION "1.0.1" +#define EXFAT_PROGS_VERSION "1.0.2" #endif /* !_VERSION_H */ -- cgit v1.2.3 From 27cacf4aa1e16ebcbefee40ff14d854670d6c874 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Fri, 24 Apr 2020 10:47:19 -0500 Subject: Do not install libraries Since we are not building anything against libexfat, disable installation of the library. Fixes Issue #61 by not installing the library. Signed-off-by: Goldwyn Rodrigues --- lib/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index 2a53293..f6a9085 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -2,6 +2,6 @@ AM_CFLAGS = -Wall -Werror -Wunused-parameter \ -Wno-address-of-packed-member \ -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lc -lib_LTLIBRARIES = libexfat.la +noinst_LTLIBRARIES = libexfat.la libexfat_la_SOURCES = libexfat.c -- cgit v1.2.3 From faeff188f2bda93360b650c4da1aa2fe7f9c0942 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Thu, 23 Apr 2020 11:58:35 -0500 Subject: Fix permissions: remove executable permissions Remove executable permissions from COPYING, Makefile.am and configure.ac Signed-off-by: Goldwyn Rodrigues --- COPYING | 0 Makefile.am | 0 configure.ac | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 COPYING mode change 100755 => 100644 Makefile.am mode change 100755 => 100644 configure.ac diff --git a/COPYING b/COPYING old mode 100755 new mode 100644 diff --git a/Makefile.am b/Makefile.am old mode 100755 new mode 100644 diff --git a/configure.ac b/configure.ac old mode 100755 new mode 100644 -- cgit v1.2.3 From a48ab040c15ffa08937aa0cabcad5e4fb31534b4 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Thu, 23 Apr 2020 17:25:53 -0500 Subject: mkfs: Add man page Signed-off-by: Goldwyn Rodrigues --- mkfs/Makefile.am | 2 ++ mkfs/mkfs.exfat.8 | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 mkfs/mkfs.exfat.8 diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index 5220911..14716c1 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -7,3 +7,5 @@ mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = mkfs.exfat mkfs_exfat_SOURCES = mkfs.c upcase.c + +man_MANS = mkfs.exfat.8 diff --git a/mkfs/mkfs.exfat.8 b/mkfs/mkfs.exfat.8 new file mode 100644 index 0000000..e3952d7 --- /dev/null +++ b/mkfs/mkfs.exfat.8 @@ -0,0 +1,60 @@ +.TH mkfs.exfat 8 +.SH NAME +mkfs.exfat \- create an exFAT filesystem +.SH SYNOPSIS +.B mkfs.exfat +[ +.B \-c +.I cluster_size +] [ +.B \-f +] [ +.B \-h +] [ +.B \-l +.I volume_label +] [ +.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 +.BI \-c " cluster_size" +Specify the cluster size. Cluster size can be specified in m/M for megabytes +and k/K for kilobytes. +.TP +.BI \-f +Performs a full format. This zeros the entire disk device while +creating the exFAT filesystem. +.TP +.BI \-h +Prints the help and exit. +.TP +.BI \-l " volume_label" +Specifies the volume label associated with the exFAT filesystem. +.TP +.BI \-v +Prints verbose debugging information while creating the exFAT filesystem. +.TP +.B \-V +Prints the version number and exits. +.SH SEE ALSO +.BR mkfs (8), +.BR mount (8), -- cgit v1.2.3 From 0cd173008888dc35d8e8f05dd338f09b9f06c1df Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Thu, 23 Apr 2020 21:49:05 -0500 Subject: fsck: Add man page Signed-off-by: Goldwyn Rodrigues --- fsck/Makefile.am | 2 ++ fsck/fsck.exfat.8 | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 fsck/fsck.exfat.8 diff --git a/fsck/Makefile.am b/fsck/Makefile.am index b8fa647..c768fbc 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -6,3 +6,5 @@ fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = fsck.exfat fsck_exfat_SOURCES = fsck.c repair.c + +man_MANS = fsck.exfat.8 diff --git a/fsck/fsck.exfat.8 b/fsck/fsck.exfat.8 new file mode 100644 index 0000000..b6cf3c8 --- /dev/null +++ b/fsck/fsck.exfat.8 @@ -0,0 +1,44 @@ +.TH fsck.exfat 8 +.SH NAME +fsck.exfat \- check an exFAT filesystem +.SH SYNOPSIS +.B fsck.exfat +[ +.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 filesytem +depending on the options passed. +.PP +.SH OPTIONS +.TP +.BI \-n +Check the filesystem but do not attempt to repair the filesystem. +.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. +.TP +.SH SEE ALSO +.BR fsck (8), +.BR fstab (5), -- cgit v1.2.3 From 55264596d3e6e2158d0ca39998d309ed083c9091 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Fri, 24 Apr 2020 09:08:14 -0500 Subject: label: Add man page Signed-off-by: Goldwyn Rodrigues --- label/Makefile.am | 2 ++ label/label.exfat.8 | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 label/label.exfat.8 diff --git a/label/Makefile.am b/label/Makefile.am index ebe962a..cec1db6 100644 --- a/label/Makefile.am +++ b/label/Makefile.am @@ -6,3 +6,5 @@ label_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = label.exfat label_exfat_SOURCES = label.c + +man_MANS = label.exfat.8 diff --git a/label/label.exfat.8 b/label/label.exfat.8 new file mode 100644 index 0000000..2f7446f --- /dev/null +++ b/label/label.exfat.8 @@ -0,0 +1,35 @@ +.TH label.exfat 8 +.SH NAME +label.exfat \- get or change the volume label of an exFAT filesystem +.SH SYNOPSIS +.B label.exfat +[ +.B \-g +] [ +.B \-s volume_label +.I volume_label +] [ +.B \-v +] +.I device +.br +.B label.exfat \-V +.SH DESCRIPTION +.B label.exfat +changes or gets the volume label of an existing exFAT filesystem. +.PP +.SH OPTIONS +.TP +.BI \-g +Print the volume label of the exFAT filesystem. +.TP +.BI \-s " volume_label" +Set the volume label of the filesystem to the provided argument. +.TP +.BI \-v +Prints verbose debugging information while extracting or setting the volume +label of the exFAT filesystem. +.TP +.B \-V +Prints the version number and exits. +.TP -- cgit v1.2.3 From f280a74800e49906be2e446f81505ce19448869d Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 25 Apr 2020 10:03:01 +0900 Subject: travis: remove manual copy library Signed-off-by: Namjae Jeon --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d71dcc9..c192747 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,6 @@ script: - ./configure > /dev/null - make -j$((`nproc`+1)) > /dev/null - sudo make install > /dev/null - - sudo cp lib/.libs/libexfat.so* /lib/ - cd exfat_oot - make > /dev/null - sudo make install > /dev/null -- cgit v1.2.3 From 860326c6aa86ef65693533d45ba158b324bb359b Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Fri, 17 Apr 2020 13:10:49 -0600 Subject: exfatprogs: add missing #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: ../include/libexfat.h:72:1: error: unknown type name ‘ssize_t’ ssize_t exfat_read(int fd, void *buf, size_t size, off_t offset); ^ ../include/libexfat.h:72:52: error: unknown type name ‘off_t’ ssize_t exfat_read(int fd, void *buf, size_t size, off_t offset); ^ ../include/libexfat.h:73:1: error: unknown type name ‘ssize_t’ ssize_t exfat_write(int fd, void *buf, size_t size, off_t offset); ^ ../include/libexfat.h:73:53: error: unknown type name ‘off_t’ ssize_t exfat_write(int fd, void *buf, size_t size, off_t offset); ^ ../include/libexfat.h:75:1: error: unknown type name ‘ssize_t’ ssize_t exfat_utf16_enc(const char *in_str, __u16 *out_str, size_t out_size); ^ ../include/libexfat.h:76:1: error: unknown type name ‘ssize_t’ ssize_t exfat_utf16_dec(const __u16 *in_str, size_t in_len, ^ Signed-off-by: James Hilliard --- include/libexfat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/libexfat.h b/include/libexfat.h index ed1fb4c..36c8bdd 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -6,6 +6,7 @@ #ifndef _LIBEXFAT_H #include +#include #include #define KB (1024) -- cgit v1.2.3 From 1ed530e5e68eeaaeb0764c3831a59aacfdd7ced8 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 25 Apr 2020 23:40:36 +0900 Subject: exfatprogs: remove -Werror to avoid build break There is some warning option which is reconized by only gcc version(gcc-9) like -Wno-address-of-packed-member. To avoid the build break, remove it and leave only -Wall. Signed-off-by: Namjae Jeon --- fsck/Makefile.am | 4 +--- mkfs/Makefile.am | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/fsck/Makefile.am b/fsck/Makefile.am index b8fa647..44d4066 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -1,6 +1,4 @@ -AM_CFLAGS = -Wall -Werror -Wunused-parameter \ - -Wno-address-of-packed-member \ - -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -Wall -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.la sbin_PROGRAMS = fsck.exfat diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index 5220911..cc8a422 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,6 +1,4 @@ -AM_CFLAGS = -Wall -Werror -Wunused-parameter \ - -Wno-address-of-packed-member \ - -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -Wall -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lm mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.la -- cgit v1.2.3 From b0519f4fa7ce513d65d0f94c4d5a05be42730e7d Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sun, 26 Apr 2020 15:28:21 +0200 Subject: fsck: Zero-init using memset * Clang 9.0 incorrectly issues the -Wmissing-braces warning --- fsck/fsck.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 9e04407..ae463f9 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1210,11 +1210,14 @@ void exfat_show_stat(void) int main(int argc, char * const argv[]) { int c, ret; - struct fsck_user_input ui = {0,}; - struct exfat_blk_dev bd = {0,}; + struct fsck_user_input ui; + struct exfat_blk_dev bd; struct exfat *exfat = NULL; bool version_only = false; + memset(&ui, 0, sizeof(ui)); + memset(&bd, 0, sizeof(bd)); + print_level = EXFAT_ERROR; if (!setlocale(LC_CTYPE, "")) -- cgit v1.2.3 From 1fcc8d56b4c832880ecf385d7436a1b68267b50f Mon Sep 17 00:00:00 2001 From: Nicolas Boos Date: Mon, 27 Apr 2020 12:31:33 +0900 Subject: fix incomplete 'make dist' generated tarball Signed-off-by: Nicolas Boos Signed-off-by: Namjae Jeon --- Makefile.am | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Makefile.am b/Makefile.am index e9c2626..1ff4bde 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,3 +3,19 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = lib mkfs fsck label + +# manpages +dist_man8_MANS = \ + fsck/fsck.exfat.8 \ + label/label.exfat.8 \ + mkfs/mkfs.exfat.8 + +# other stuff +EXTRA_DIST = \ + include \ + Android.bp \ + lib/Android.bp \ + mkfs/Android.bp \ + label/Android.bp \ + fsck/Android.bp \ + README.md -- cgit v1.2.3 From 389852847d6dcda53bfc7a94ebbb0780b940507d Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 27 Apr 2020 17:02:32 +0900 Subject: exfatprogs: rename label.exfat to tune.exfat Goldwyn suggest label.exfat to be changed to tune.exfat. This patch rename label.exfat to tune.exfat. Signed-off-by: Namjae Jeon --- Makefile.am | 6 +- README.md | 10 +-- configure.ac | 2 +- label/Android.bp | 11 --- label/Makefile.am | 10 --- label/label.c | 195 ---------------------------------------------------- label/label.exfat.8 | 35 ---------- tune/Android.bp | 11 +++ tune/Makefile.am | 8 +++ tune/tune.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tune/tune.exfat.8 | 34 +++++++++ 11 files changed, 257 insertions(+), 260 deletions(-) delete mode 100644 label/Android.bp delete mode 100644 label/Makefile.am delete mode 100644 label/label.c delete mode 100644 label/label.exfat.8 create mode 100644 tune/Android.bp create mode 100644 tune/Makefile.am create mode 100644 tune/tune.c create mode 100644 tune/tune.exfat.8 diff --git a/Makefile.am b/Makefile.am index 1ff4bde..3d9c2c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,12 +2,12 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = lib mkfs fsck label +SUBDIRS = lib mkfs fsck tune # manpages dist_man8_MANS = \ fsck/fsck.exfat.8 \ - label/label.exfat.8 \ + tune/tune.exfat.8 \ mkfs/mkfs.exfat.8 # other stuff @@ -16,6 +16,6 @@ EXTRA_DIST = \ Android.bp \ lib/Android.bp \ mkfs/Android.bp \ - label/Android.bp \ + tune/Android.bp \ fsck/Android.bp \ README.md diff --git a/README.md b/README.md index c41e40b..de06874 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,12 @@ Usage example: fsck.exfat /dev/sda1 2. repair and fix.(preparing) -- label.exfat: - Get or set volume label from a given device that formatted by exfat filesystem. +- tune.exfat: + Adjust tunable filesystem parameters on an exFAT filesystem Usage example: - 1. get volume label. - label.exfat -g /dev/sda1 + 1. print current volume label. + tune.exfat -l /dev/sda1 2. set new volume label. - label.exfat -s "new label" /dev/sda1 + tune.exfat -l"new label" /dev/sda1 ``` diff --git a/configure.ac b/configure.ac index d9f6115..8dcd02c 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ AC_CONFIG_FILES([ lib/Makefile mkfs/Makefile fsck/Makefile - label/Makefile + tune/Makefile ]) AC_OUTPUT diff --git a/label/Android.bp b/label/Android.bp deleted file mode 100644 index 87d0e83..0000000 --- a/label/Android.bp +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2020 The Android Open Source Project - -cc_binary { - name: "label.exfat", - - srcs: [ - "label.c", - ], - defaults: ["exfatprogs-defaults"], - static_libs: ["libexfat"], -} diff --git a/label/Makefile.am b/label/Makefile.am deleted file mode 100644 index cec1db6..0000000 --- a/label/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -AM_CFLAGS = -Wall -Werror -Wunused-parameter \ - -Wno-address-of-packed-member \ - -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common -label_exfat_LDADD = $(top_builddir)/lib/libexfat.la - -sbin_PROGRAMS = label.exfat - -label_exfat_SOURCES = label.c - -man_MANS = label.exfat.8 diff --git a/label/label.c b/label/label.c deleted file mode 100644 index f7b5958..0000000 --- a/label/label.c +++ /dev/null @@ -1,195 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2019 Namjae Jeon - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "exfat_ondisk.h" -#include "libexfat.h" - -static void usage(void) -{ - fprintf(stderr, "Usage: label.exfat\n"); - fprintf(stderr, "\t-g | --get-label Get volume label\n"); - fprintf(stderr, "\t-s | --set-label Set volume label\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[] = { - {"get-label", no_argument, NULL, 'g' }, - {"set-label", required_argument, NULL, 's' }, - {"version", no_argument, NULL, 'V' }, - {"verbose", no_argument, NULL, 'v' }, - {"help", no_argument, NULL, 'h' }, - {"?", no_argument, NULL, '?' }, - {NULL, 0, NULL, 0 } -}; - -static off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) -{ - struct pbr *bs; - int nbytes; - unsigned int cluster_size; - off_t root_clu_off; - - bs = (struct pbr *)malloc(sizeof(struct pbr)); - if (!bs) { - exfat_err("failed to allocate memory\n"); - return -ENOMEM; - } - - nbytes = exfat_read(bd->dev_fd, bs, sizeof(struct pbr), 0); - if (nbytes != sizeof(struct pbr)) { - exfat_err("boot sector read failed: %d\n", errno); - return -1; - } - - cluster_size = (1 << bs->bsx.sect_per_clus_bits) * bd->sector_size; - root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * bd->sector_size + - le32_to_cpu(bs->bsx.root_cluster - EXFAT_REVERVED_CLUSTERS) - * cluster_size; - free(bs); - - return root_clu_off; -} - -static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) -{ - struct exfat_dentry *vol_entry; - char volume_label[11]; - 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); - return -1; - } - - if (exfat_utf16_dec(vol_entry->vol_label, vol_entry->vol_char_cnt*2, - volume_label, sizeof(volume_label)) < 0) { - exfat_err("failed to decode volume label\n"); - return -1; - } - - exfat_info("label: %s\n", volume_label); - return 0; -} - -static 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[11]; - 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, 22); - 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; -} - -#define EXFAT_GET_LABEL 0x1 -#define EXFAT_SET_LABEL 0x2 - -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[11]; - 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, "s:gVvh", opts, NULL)) != EOF) - switch (c) { - case 'g': - flags = EXFAT_GET_LABEL; - break; - case 's': - snprintf(label_input, 11, "%s", optarg); - flags = EXFAT_SET_LABEL; - 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; - - root_clu_off = exfat_get_root_entry_offset(&bd); - if (root_clu_off < 0) - goto out; - - if (flags == EXFAT_GET_LABEL) - ret = exfat_get_volume_label(&bd, root_clu_off); - else if (flags == EXFAT_SET_LABEL) - ret = exfat_set_volume_label(&bd, label_input, root_clu_off); - -out: - return ret; -} diff --git a/label/label.exfat.8 b/label/label.exfat.8 deleted file mode 100644 index 2f7446f..0000000 --- a/label/label.exfat.8 +++ /dev/null @@ -1,35 +0,0 @@ -.TH label.exfat 8 -.SH NAME -label.exfat \- get or change the volume label of an exFAT filesystem -.SH SYNOPSIS -.B label.exfat -[ -.B \-g -] [ -.B \-s volume_label -.I volume_label -] [ -.B \-v -] -.I device -.br -.B label.exfat \-V -.SH DESCRIPTION -.B label.exfat -changes or gets the volume label of an existing exFAT filesystem. -.PP -.SH OPTIONS -.TP -.BI \-g -Print the volume label of the exFAT filesystem. -.TP -.BI \-s " volume_label" -Set the volume label of the filesystem to the provided argument. -.TP -.BI \-v -Prints verbose debugging information while extracting or setting the volume -label of the exFAT filesystem. -.TP -.B \-V -Prints the version number and exits. -.TP diff --git a/tune/Android.bp b/tune/Android.bp new file mode 100644 index 0000000..6f88e33 --- /dev/null +++ b/tune/Android.bp @@ -0,0 +1,11 @@ +// Copyright 2020 The Android Open Source Project + +cc_binary { + name: "tune.exfat", + + srcs: [ + "tune.c", + ], + defaults: ["exfatprogs-defaults"], + static_libs: ["libexfat"], +} diff --git a/tune/Makefile.am b/tune/Makefile.am new file mode 100644 index 0000000..fe3da5c --- /dev/null +++ b/tune/Makefile.am @@ -0,0 +1,8 @@ +AM_CFLAGS = -Wall -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +tune_exfat_LDADD = $(top_builddir)/lib/libexfat.la + +sbin_PROGRAMS = tune.exfat + +tune_exfat_SOURCES = tune.c + +man_MANS = tune.exfat.8 diff --git a/tune/tune.c b/tune/tune.c new file mode 100644 index 0000000..bfd4649 --- /dev/null +++ b/tune/tune.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Namjae Jeon + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "exfat_ondisk.h" +#include "libexfat.h" + +static void usage(void) +{ + fprintf(stderr, "Usage: tune.exfat\n"); + fprintf(stderr, "\t-g | --get-label Get volume label\n"); + fprintf(stderr, "\t-s | --set-label Set volume label\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[] = { + {"get-label", no_argument, NULL, 'g' }, + {"set-label", required_argument, NULL, 's' }, + {"version", no_argument, NULL, 'V' }, + {"verbose", no_argument, NULL, 'v' }, + {"help", no_argument, NULL, 'h' }, + {"?", no_argument, NULL, '?' }, + {NULL, 0, NULL, 0 } +}; + +static off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) +{ + struct pbr *bs; + int nbytes; + unsigned int cluster_size; + off_t root_clu_off; + + bs = (struct pbr *)malloc(sizeof(struct pbr)); + if (!bs) { + exfat_err("failed to allocate memory\n"); + return -ENOMEM; + } + + nbytes = exfat_read(bd->dev_fd, bs, sizeof(struct pbr), 0); + if (nbytes != sizeof(struct pbr)) { + exfat_err("boot sector read failed: %d\n", errno); + return -1; + } + + cluster_size = (1 << bs->bsx.sect_per_clus_bits) * bd->sector_size; + root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * bd->sector_size + + le32_to_cpu(bs->bsx.root_cluster - EXFAT_REVERVED_CLUSTERS) + * cluster_size; + free(bs); + + return root_clu_off; +} + +static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) +{ + struct exfat_dentry *vol_entry; + char volume_label[11]; + 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); + return -1; + } + + if (exfat_utf16_dec(vol_entry->vol_label, vol_entry->vol_char_cnt*2, + volume_label, sizeof(volume_label)) < 0) { + exfat_err("failed to decode volume label\n"); + return -1; + } + + exfat_info("label: %s\n", volume_label); + return 0; +} + +static 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[11]; + 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, 22); + 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; +} + +#define EXFAT_GET_LABEL 0x1 +#define EXFAT_SET_LABEL 0x2 + +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[11]; + 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, "s:gVvh", opts, NULL)) != EOF) + switch (c) { + case 'g': + flags = EXFAT_GET_LABEL; + break; + case 's': + snprintf(label_input, 11, "%s", optarg); + flags = EXFAT_SET_LABEL; + 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; + + root_clu_off = exfat_get_root_entry_offset(&bd); + if (root_clu_off < 0) + goto out; + + if (flags == EXFAT_GET_LABEL) + ret = exfat_get_volume_label(&bd, root_clu_off); + else if (flags == EXFAT_SET_LABEL) + ret = exfat_set_volume_label(&bd, label_input, root_clu_off); + +out: + return ret; +} diff --git a/tune/tune.exfat.8 b/tune/tune.exfat.8 new file mode 100644 index 0000000..4608f7c --- /dev/null +++ b/tune/tune.exfat.8 @@ -0,0 +1,34 @@ +.TH tune.exfat 8 +.SH NAME +tune.exfat \- adjust tunable filesystem parameters on an exFAT filesystem +.SH SYNOPSIS +.B tune.exfat +[ +.B \-l +] [ +.B \-l volume_label +.I volume_label +] [ +.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 the volume label of the exFAT filesystem. +.TP +.BI \-l" volume_label" +Set the volume label 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. +.TP -- cgit v1.2.3 From 616bdaca520e8a82f0d9f1e40bfa466370087c1d Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 27 Apr 2020 16:10:58 +0900 Subject: tune: change argument style Goldwyn suggest This would require changing the argument style to use -l for setting or getting the label depending on if the argument was passed. User can command tune.exfat option like the following ones. 1. print current volume label tune.exfat -l /dev/sda1 2. set new volume label tune.exfat -l "new label" /dev/sda1 Signed-off-by: Namjae Jeon --- tune/tune.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/tune/tune.c b/tune/tune.c index bfd4649..7070b12 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -17,8 +17,7 @@ static void usage(void) { fprintf(stderr, "Usage: tune.exfat\n"); - fprintf(stderr, "\t-g | --get-label Get volume label\n"); - fprintf(stderr, "\t-s | --set-label Set volume label\n"); + fprintf(stderr, "\t-l | --label Set/Get volume label\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"); @@ -27,8 +26,7 @@ static void usage(void) } static struct option opts[] = { - {"get-label", no_argument, NULL, 'g' }, - {"set-label", required_argument, NULL, 's' }, + {"label", optional_argument, NULL, 'l' }, {"version", no_argument, NULL, 'V' }, {"verbose", no_argument, NULL, 'v' }, {"help", no_argument, NULL, 'h' }, @@ -145,14 +143,14 @@ int main(int argc, char *argv[]) exfat_err("failed to init locale/codeset\n"); opterr = 0; - while ((c = getopt_long(argc, argv, "s:gVvh", opts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "l::Vvh", opts, NULL)) != EOF) switch (c) { - case 'g': - flags = EXFAT_GET_LABEL; - break; - case 's': - snprintf(label_input, 11, "%s", optarg); - flags = EXFAT_SET_LABEL; + case 'l': + if (optarg) { + snprintf(label_input, 11, "%s", optarg); + flags = EXFAT_SET_LABEL; + } else + flags = EXFAT_GET_LABEL; break; case 'V': version_only = true; @@ -170,12 +168,11 @@ int main(int argc, char *argv[]) if (version_only) exit(EXIT_FAILURE); - if (argc - optind != 1) { + if (argc < 3) usage(); - } memset(ui.dev_name, 0, sizeof(ui.dev_name)); - snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[optind]); + snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[argc - 1]); ret = exfat_get_blk_dev_info(&ui, &bd); if (ret < 0) -- cgit v1.2.3 From 1db7cf789437dfd7b7fe189868cb72a6a5ec8ef3 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 27 Apr 2020 16:12:13 +0900 Subject: tune: initialize volume_label array as zero for null terminator, Need to memset volume label array. Signed-off-by: Namjae Jeon --- tune/tune.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tune/tune.c b/tune/tune.c index 7070b12..0601946 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -81,6 +81,7 @@ static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) return -1; } + memset(volume_label, 0, 11); if (exfat_utf16_dec(vol_entry->vol_label, vol_entry->vol_char_cnt*2, volume_label, sizeof(volume_label)) < 0) { exfat_err("failed to decode volume label\n"); -- cgit v1.2.3 From 47ad5d6491fafd67fc4fe59e9fcac6982447e3b6 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 29 Apr 2020 11:21:21 +0900 Subject: exfatprogs: update paragraph Update paragraph by rubyFeedback request. Signed-off-by: Namjae Jeon --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index de06874..a6e7793 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ ## exfatprogs -exfatprogs is userspace utilities for exfat filesystem under GNU GPL version 2. +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. exfatprogress is the goal of providing high performance and windows +level outstanding utils compared to old utils. And this software is +licensed under the GNU General Public License Version 2. ## Maintainers * Namjae Jeon -- cgit v1.2.3 From 7165385db2ab61fded031e52e8f660c3b85211c2 Mon Sep 17 00:00:00 2001 From: Nicolas Boos Date: Wed, 29 Apr 2020 12:19:49 +0900 Subject: exfatprogs: remove xz tarball generation As gzip is deployed everywhere and the archive is small, removed xz tarball generation. Signed-off-by: Nicolas Boos Signed-off-by: Namjae Jeon --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8dcd02c..216483a 100644 --- a/configure.ac +++ b/configure.ac @@ -14,7 +14,7 @@ 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]) +AM_INIT_AUTOMAKE([foreign tar-pax subdir-objects]) AC_LANG([C]) AC_PROG_CC -- cgit v1.2.3 From 843124cd9a2087281e00bd1b9d710db59acfbced Mon Sep 17 00:00:00 2001 From: Nicolas Boos Date: Wed, 29 Apr 2020 12:20:31 +0900 Subject: exfatprogs: removed unneeded pkg-config dependency Signed-off-by: Nicolas Boos Signed-off-by: Namjae Jeon --- configure.ac | 2 -- 1 file changed, 2 deletions(-) diff --git a/configure.ac b/configure.ac index 216483a..f515511 100644 --- a/configure.ac +++ b/configure.ac @@ -24,8 +24,6 @@ AC_PROG_LIBTOOL AC_SYS_LARGEFILE AC_C_BIGENDIAN -PKG_PROG_PKG_CONFIG([0.9]) - AC_CONFIG_FILES([ Makefile lib/Makefile -- cgit v1.2.3 From 5bdd4de9f9230a89071ed321c77b06cded73c184 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 29 Apr 2020 14:29:31 +0900 Subject: exfatprogs: Add feedback section in README.md Signed-off-by: Hyunchul Lee --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index de06874..e84b970 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,6 @@ ## exfatprogs exfatprogs is userspace utilities for exfat filesystem under GNU GPL version 2. -## Maintainers -* Namjae Jeon -* Hyunchul Lee - ## Building exfatprogs Install prerequisite packages: ``` @@ -59,3 +55,11 @@ Usage example: 2. set new volume label. tune.exfat -l"new label" /dev/sda1 ``` + +## 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 -- cgit v1.2.3 From d4482453d97e3d5cff4d39269c803b7550089cef Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 29 Apr 2020 16:33:42 +0900 Subject: exfatprogs: replace tabs with whitespaces in usage Signed-off-by: Hyunchul Lee --- mkfs/mkfs.c | 2 +- tune/tune.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 021a51a..42fd5d0 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -382,7 +382,7 @@ static void usage(void) { fprintf(stderr, "Usage: mkfs.exfat\n"); fprintf(stderr, "\t-l string | --volume-label=string Set volume label\n"); - fprintf(stderr, "\t-c | --cluster-size Set cluster size\n"); + fprintf(stderr, "\t-c | --cluster-size Set cluster size\n"); fprintf(stderr, "\t-f | --full-format Full format\n"); fprintf(stderr, "\t-V | --version Show version\n"); fprintf(stderr, "\t-v | --verbose Print debug\n"); diff --git a/tune/tune.c b/tune/tune.c index 0601946..29156d0 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -17,10 +17,10 @@ static void usage(void) { fprintf(stderr, "Usage: tune.exfat\n"); - fprintf(stderr, "\t-l | --label Set/Get volume label\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"); + fprintf(stderr, "\t-l | --label Set/Get volume label\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); } -- cgit v1.2.3 From 9d5bb880e3c310012c75f590f53e0f70a8173cef Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 29 Apr 2020 16:28:45 +0900 Subject: exfatprogs: link utilies statically with libexfat.a There is no plan to export APIs for now, and Utilities are already linked statically with libexfat. So specify static linking in Makefile.am Signed-off-by: Hyunchul Lee --- fsck/Makefile.am | 2 +- lib/Makefile.am | 2 +- mkfs/Makefile.am | 2 +- tune/Makefile.am | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fsck/Makefile.am b/fsck/Makefile.am index 52b8405..99bd226 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -1,5 +1,5 @@ AM_CFLAGS = -Wall -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common -fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.la +fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = fsck.exfat diff --git a/lib/Makefile.am b/lib/Makefile.am index f6a9085..f0af4c9 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -2,6 +2,6 @@ AM_CFLAGS = -Wall -Werror -Wunused-parameter \ -Wno-address-of-packed-member \ -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lc -noinst_LTLIBRARIES = libexfat.la +noinst_LIBRARIES = libexfat.a libexfat_la_SOURCES = libexfat.c diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index 4e9ee00..32d7b7c 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = -Wall -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lm -mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.la +mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = mkfs.exfat diff --git a/tune/Makefile.am b/tune/Makefile.am index fe3da5c..01efb7d 100644 --- a/tune/Makefile.am +++ b/tune/Makefile.am @@ -1,5 +1,5 @@ AM_CFLAGS = -Wall -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common -tune_exfat_LDADD = $(top_builddir)/lib/libexfat.la +tune_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = tune.exfat -- cgit v1.2.3 From 37ff97685a1faf9d03264c2598f4a5d12a95d81e Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 29 Apr 2020 17:06:12 +0900 Subject: fsck: add fsck.h in Makefile.am SOURCES variable Signed-off-by: Hyunchul Lee --- fsck/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/Makefile.am b/fsck/Makefile.am index 99bd226..d73a558 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -3,6 +3,6 @@ fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = fsck.exfat -fsck_exfat_SOURCES = fsck.c repair.c +fsck_exfat_SOURCES = fsck.c repair.c fsck.h man_MANS = fsck.exfat.8 -- cgit v1.2.3 From dbf74fe0e37ad5c2fa14098e5eb0ed3280d74a41 Mon Sep 17 00:00:00 2001 From: Nicolas Boos Date: Thu, 30 Apr 2020 10:57:47 +0900 Subject: exfatprogs: replace la_SOURCES with a_SOURCES in lib Makefile.am Signed-off-by: Nicolas Boos Signed-off-by: Hyunchul Lee --- lib/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index f0af4c9..eb8fff4 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -4,4 +4,4 @@ AM_CFLAGS = -Wall -Werror -Wunused-parameter \ LIBS = -lc noinst_LIBRARIES = libexfat.a -libexfat_la_SOURCES = libexfat.c +libexfat_a_SOURCES = libexfat.c -- cgit v1.2.3 From 3ed11e2a88534e267645b5823105f15428e9f8d3 Mon Sep 17 00:00:00 2001 From: Nicolas Boos Date: Thu, 30 Apr 2020 11:15:57 +0900 Subject: exfatprogs: replace top_srcdir with top_builddir for config.h in Makefile.am Signed-off-by: Nicolas Boos Signed-off-by: Hyunchul Lee --- fsck/Makefile.am | 2 +- lib/Makefile.am | 2 +- mkfs/Makefile.am | 2 +- tune/Makefile.am | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fsck/Makefile.am b/fsck/Makefile.am index d73a558..16cef7f 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = -Wall -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = fsck.exfat diff --git a/lib/Makefile.am b/lib/Makefile.am index eb8fff4..6277665 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = -Wall -Werror -Wunused-parameter \ -Wno-address-of-packed-member \ - -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common + -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lc noinst_LIBRARIES = libexfat.a diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index 32d7b7c..8ff1e86 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = -Wall -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common LIBS = -lm mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.a diff --git a/tune/Makefile.am b/tune/Makefile.am index 01efb7d..2ca7f90 100644 --- a/tune/Makefile.am +++ b/tune/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = -Wall -include $(top_srcdir)/config.h -I$(top_srcdir)/include -fno-common +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 -- cgit v1.2.3 From 0fefa8a1eb92bb95be3756693b58f55af9b18bee Mon Sep 17 00:00:00 2001 From: Nicolas Boos Date: Sat, 2 May 2020 22:19:12 +0900 Subject: libexfat: remove unneeded -Werror and adding -lc Signed-off-by: Nicolas Boos Signed-off-by: Namjae Jeon --- lib/Makefile.am | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index 6277665..5ea12db 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,7 +1,4 @@ -AM_CFLAGS = -Wall -Werror -Wunused-parameter \ - -Wno-address-of-packed-member \ - -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common -LIBS = -lc +AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common noinst_LIBRARIES = libexfat.a libexfat_a_SOURCES = libexfat.c -- cgit v1.2.3 From 001a33621b61190a09b0ae63ed2d678de2f8c7bb Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 2 May 2020 22:41:31 +0900 Subject: mkfs: move include/mkfs.h to /mkfs/ Suggested-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- include/libexfat.h | 2 ++ include/mkfs.h | 34 ---------------------------------- lib/libexfat.c | 1 - mkfs/Makefile.am | 2 +- mkfs/mkfs.h | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 36 insertions(+), 36 deletions(-) delete mode 100644 include/mkfs.h create mode 100644 mkfs/mkfs.h diff --git a/include/libexfat.h b/include/libexfat.h index 36c8bdd..e804352 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -27,6 +27,8 @@ #define EXFAT_MAX_NUM_CLUSTER (0xFFFFFFF5) +#define DEFAULT_SECTOR_SIZE (512) + /* Upcase tabel macro */ #define EXFAT_UPCASE_TABLE_SIZE (5836) diff --git a/include/mkfs.h b/include/mkfs.h deleted file mode 100644 index 013ea77..0000000 --- a/include/mkfs.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019 Namjae Jeon - */ - -#ifndef _MKFS_H - -#define DEFAULT_CLUSTER_SIZE (1024*1024) -#define DEFAULT_SECTOR_SIZE (512) -#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; -}; - -extern struct exfat_mkfs_info finfo; - -int exfat_create_upcase_table(struct exfat_blk_dev *bd); - -#endif /* !_MKFS_H */ diff --git a/lib/libexfat.c b/lib/libexfat.c index f90eedd..d01fe29 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -17,7 +17,6 @@ #include "exfat_ondisk.h" #include "libexfat.h" -#include "mkfs.h" #include "version.h" #ifdef WORDS_BIGENDIAN diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index 8ff1e86..b0c4c27 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -4,6 +4,6 @@ mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = mkfs.exfat -mkfs_exfat_SOURCES = mkfs.c upcase.c +mkfs_exfat_SOURCES = mkfs.c upcase.c mkfs.h man_MANS = mkfs.exfat.8 diff --git a/mkfs/mkfs.h b/mkfs/mkfs.h new file mode 100644 index 0000000..df31894 --- /dev/null +++ b/mkfs/mkfs.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019 Namjae Jeon + */ + +#ifndef _MKFS_H + +#define DEFAULT_CLUSTER_SIZE (1024*1024) +#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; +}; + +extern struct exfat_mkfs_info finfo; + +int exfat_create_upcase_table(struct exfat_blk_dev *bd); + +#endif /* !_MKFS_H */ -- cgit v1.2.3 From 76405cdb67402d74ad24ff1c92d4f1202c8baea6 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 2 May 2020 23:21:04 +0900 Subject: tune.exfat: use '-L' to set label and '-l' to print label Like e2fsprogs and xfsprogs, tune.exfat use similar pattern for printing and setting label. Suggested-by : Nicolas Boos Signed-off-by: Namjae Jeon --- README.md | 2 +- tune/tune.c | 18 ++++++++++-------- tune/tune.exfat.8 | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b76a3e3..c3489d9 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Usage example: 1. print current volume label. tune.exfat -l /dev/sda1 2. set new volume label. - tune.exfat -l"new label" /dev/sda1 + tune.exfat -L "new label" /dev/sda1 ``` ## Sending feedback diff --git a/tune/tune.c b/tune/tune.c index 29156d0..2561667 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -17,7 +17,8 @@ static void usage(void) { fprintf(stderr, "Usage: tune.exfat\n"); - fprintf(stderr, "\t-l | --label Set/Get volume label\n"); + fprintf(stderr, "\t-l | --print-label Print volume label\n"); + fprintf(stderr, "\t-L | --set-label Set volume label\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"); @@ -26,7 +27,8 @@ static void usage(void) } static struct option opts[] = { - {"label", optional_argument, NULL, 'l' }, + {"print-label", no_argument, NULL, 'l' }, + {"set-label", required_argument, NULL, 'L' }, {"version", no_argument, NULL, 'V' }, {"verbose", no_argument, NULL, 'v' }, {"help", no_argument, NULL, 'h' }, @@ -144,14 +146,14 @@ int main(int argc, char *argv[]) exfat_err("failed to init locale/codeset\n"); opterr = 0; - while ((c = getopt_long(argc, argv, "l::Vvh", opts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "L:lVvh", opts, NULL)) != EOF) switch (c) { case 'l': - if (optarg) { - snprintf(label_input, 11, "%s", optarg); - flags = EXFAT_SET_LABEL; - } else - flags = EXFAT_GET_LABEL; + flags = EXFAT_GET_LABEL; + break; + case 'L': + snprintf(label_input, 11, "%s", optarg); + flags = EXFAT_SET_LABEL; break; case 'V': version_only = true; diff --git a/tune/tune.exfat.8 b/tune/tune.exfat.8 index 4608f7c..12dd6d2 100644 --- a/tune/tune.exfat.8 +++ b/tune/tune.exfat.8 @@ -6,7 +6,7 @@ tune.exfat \- adjust tunable filesystem parameters on an exFAT filesystem [ .B \-l ] [ -.B \-l volume_label +.B \-L volume_label .I volume_label ] [ .B \-v @@ -23,7 +23,7 @@ adjust tunable ondisk parameters of an existing exFAT filesystem. .BI \-l Print the volume label of the exFAT filesystem. .TP -.BI \-l" volume_label" +.BI \-L" volume_label" Set the volume label of the filesystem to the provided argument. .TP .BI \-v -- cgit v1.2.3 From a6ed9c5563e5f49b073cbdaf14dac3270b1a8d71 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 2 May 2020 23:24:46 +0900 Subject: mkfs.exfat: use '-L' option to set volume label As set-label option is changed in tune.exfat, mkfs.exfat use same option. Signed-off-by: Namjae Jeon --- README.md | 2 +- mkfs/mkfs.c | 8 ++++---- mkfs/mkfs.exfat.8 | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c3489d9..b545025 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Usage example: 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 + mkfs.exfat -L "my usb" /dev/sda1 - fsck.exfat: Check the consistency of your exfat filesystem and optionally repair a corrupted device formatted by exfat. diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 42fd5d0..af3cabb 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -381,7 +381,7 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, static void usage(void) { fprintf(stderr, "Usage: mkfs.exfat\n"); - fprintf(stderr, "\t-l string | --volume-label=string Set volume label\n"); + fprintf(stderr, "\t-L string | --volume-label=string Set volume label\n"); fprintf(stderr, "\t-c | --cluster-size Set cluster size\n"); fprintf(stderr, "\t-f | --full-format Full format\n"); fprintf(stderr, "\t-V | --version Show version\n"); @@ -392,7 +392,7 @@ static void usage(void) } static struct option opts[] = { - {"volume-label", required_argument, NULL, 'l' }, + {"volume-label", required_argument, NULL, 'L' }, {"cluster-size", required_argument, NULL, 'c' }, {"full-format", no_argument, NULL, 'f' }, {"version", no_argument, NULL, 'V' }, @@ -557,14 +557,14 @@ int main(int argc, char *argv[]) exfat_err("failed to init locale/codeset\n"); opterr = 0; - while ((c = getopt_long(argc, argv, "n:l:c:fVvh", opts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "n:L:c:fVvh", opts, NULL)) != EOF) switch (c) { /* * Make 'n' option fallthrough to 'l' option for for backward * compatibility with old utils. */ case 'n': - case 'l': + case 'L': { ret = exfat_utf16_enc(optarg, ui.volume_label, sizeof(ui.volume_label)); diff --git a/mkfs/mkfs.exfat.8 b/mkfs/mkfs.exfat.8 index e3952d7..bc7ab4d 100644 --- a/mkfs/mkfs.exfat.8 +++ b/mkfs/mkfs.exfat.8 @@ -11,7 +11,7 @@ mkfs.exfat \- create an exFAT filesystem ] [ .B \-h ] [ -.B \-l +.B \-L .I volume_label ] [ .B \-v @@ -47,7 +47,7 @@ creating the exFAT filesystem. .BI \-h Prints the help and exit. .TP -.BI \-l " volume_label" +.BI \-L " volume_label" Specifies the volume label associated with the exFAT filesystem. .TP .BI \-v -- cgit v1.2.3 From 2563706e8292c52fe4c1e3afe865bd90fdd82134 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 4 May 2020 00:06:10 +0900 Subject: exfatprogs: open writable device O_EXCL Currently, exfat utilities will open and operate on a device while it is mounted. This will likely lead to corruption if the device is mkfs'd or fsck'd while mounted. Open using O_EXCL to prevent this, and log a more user-friendly error string if it happens. Signed-off-by: Eric Sandeen Signed-off-by: Namjae Jeon --- lib/libexfat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/libexfat.c b/lib/libexfat.c index d01fe29..24f682b 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -145,10 +145,10 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, int fd, ret = -1; off_t blk_dev_size; - fd = open(ui->dev_name, ui->writeable ? O_RDWR : O_RDONLY); + fd = open(ui->dev_name, ui->writeable ? O_RDWR|O_EXCL : O_RDONLY); if (fd < 0) { - exfat_err("open failed : %s, errno : %d\n", ui->dev_name, - errno); + exfat_err("open failed : %s, %s\n", ui->dev_name, + strerror(errno)); return -1; } blk_dev_size = lseek(fd, 0, SEEK_END); -- cgit v1.2.3 From 5a8f2ad7825b01b49f9a164bbef786108d049875 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Tue, 5 May 2020 06:41:08 +0900 Subject: exfatprogs: Stop hardcoding max volume size Signed-off-by: Luca Stefani Signed-off-by: Namjae Jeon --- include/libexfat.h | 2 +- tune/tune.c | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/libexfat.h b/include/libexfat.h index e804352..6d4f729 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -57,7 +57,7 @@ struct exfat_user_input { unsigned int cluster_size; unsigned int sec_per_clu; bool quick; - __u16 volume_label[11]; + __u16 volume_label[VOLUME_LABEL_MAX_LEN]; int volume_label_len; }; diff --git a/tune/tune.c b/tune/tune.c index 2561667..29c69e9 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -67,7 +67,7 @@ static off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) { struct exfat_dentry *vol_entry; - char volume_label[11]; + char volume_label[VOLUME_LABEL_MAX_LEN]; int nbytes; vol_entry = malloc(sizeof(struct exfat_dentry)); @@ -83,7 +83,7 @@ static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) return -1; } - memset(volume_label, 0, 11); + memset(volume_label, 0, sizeof(volume_label)); if (exfat_utf16_dec(vol_entry->vol_label, vol_entry->vol_char_cnt*2, volume_label, sizeof(volume_label)) < 0) { exfat_err("failed to decode volume label\n"); @@ -99,7 +99,7 @@ static int exfat_set_volume_label(struct exfat_blk_dev *bd, { struct exfat_dentry vol; int nbytes; - __u16 volume_label[11]; + __u16 volume_label[VOLUME_LABEL_MAX_LEN]; int volume_label_len; volume_label_len = exfat_utf16_enc(label_input, @@ -110,7 +110,7 @@ static int exfat_set_volume_label(struct exfat_blk_dev *bd, } vol.type = EXFAT_VOLUME; - memset(vol.vol_label, 0, 22); + 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; @@ -137,7 +137,7 @@ int main(int argc, char *argv[]) struct exfat_user_input ui; bool version_only = false; int flags = 0; - char label_input[11]; + char label_input[VOLUME_LABEL_MAX_LEN]; off_t root_clu_off; init_user_input(&ui); @@ -152,7 +152,8 @@ int main(int argc, char *argv[]) flags = EXFAT_GET_LABEL; break; case 'L': - snprintf(label_input, 11, "%s", optarg); + snprintf(label_input, sizeof(label_input), "%s", + optarg); flags = EXFAT_SET_LABEL; break; case 'V': -- cgit v1.2.3 From f5d11cac94d425e8b9b2b6d4e9610c5b8c3fa8c6 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Tue, 5 May 2020 06:47:39 +0900 Subject: tune: Fix volume label array size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Pali Rohár Signed-off-by: Luca Stefani Signed-off-by: Namjae Jeon --- fsck/fsck.h | 3 --- include/libexfat.h | 3 +++ tune/tune.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fsck/fsck.h b/fsck/fsck.h index e04d199..cc2a1b2 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -5,8 +5,6 @@ #ifndef _FSCK_H #define _FSCK_H -#include - #include "list.h" typedef __u32 clus_t; @@ -27,7 +25,6 @@ struct exfat_inode { }; #define EXFAT_NAME_MAX 255 -#define VOLUME_LABEL_BUFFER_SIZE (VOLUME_LABEL_MAX_LEN*MB_LEN_MAX+1) #define NAME_BUFFER_SIZE ((EXFAT_NAME_MAX+1)*2) struct exfat_de_iter { diff --git a/include/libexfat.h b/include/libexfat.h index 6d4f729..853b78c 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -8,6 +8,7 @@ #include #include #include +#include #define KB (1024) #define MB (1024*1024) @@ -29,6 +30,8 @@ #define DEFAULT_SECTOR_SIZE (512) +#define VOLUME_LABEL_BUFFER_SIZE (VOLUME_LABEL_MAX_LEN*MB_LEN_MAX+1) + /* Upcase tabel macro */ #define EXFAT_UPCASE_TABLE_SIZE (5836) diff --git a/tune/tune.c b/tune/tune.c index 29c69e9..6e5ec89 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -67,7 +67,7 @@ static off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) { struct exfat_dentry *vol_entry; - char volume_label[VOLUME_LABEL_MAX_LEN]; + char volume_label[VOLUME_LABEL_BUFFER_SIZE]; int nbytes; vol_entry = malloc(sizeof(struct exfat_dentry)); @@ -137,7 +137,7 @@ int main(int argc, char *argv[]) struct exfat_user_input ui; bool version_only = false; int flags = 0; - char label_input[VOLUME_LABEL_MAX_LEN]; + char label_input[VOLUME_LABEL_BUFFER_SIZE]; off_t root_clu_off; init_user_input(&ui); -- cgit v1.2.3 From cbc34e9fc440e025d188aa3ab71243cc21247b6b Mon Sep 17 00:00:00 2001 From: Ilya Ponetayev Date: Tue, 5 May 2020 06:56:53 +0900 Subject: mkfs: exfat_create_bitmap: fix garbage in allocated bitmap Allocating memory without zeroing leads to garbage in bitmap and lost "preallocated" clusters Signed-off-by: Ilya Ponetayev Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index af3cabb..231dffc 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -324,7 +324,7 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd) char *bitmap; int i, nbytes; - bitmap = malloc(finfo.bitmap_byte_len); + bitmap = calloc(finfo.bitmap_byte_len, sizeof(*bitmap)); if (!bitmap) return -1; @@ -336,9 +336,11 @@ static int exfat_create_bitmap(struct exfat_blk_dev *bd) 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; } -- cgit v1.2.3 From 476b5c664bd9b5be691456b859bf16f3a14cbf92 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 5 May 2020 07:03:17 +0900 Subject: mkfs: fix -L option comment Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 231dffc..e718633 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -562,7 +562,7 @@ int main(int argc, char *argv[]) while ((c = getopt_long(argc, argv, "n:L:c:fVvh", opts, NULL)) != EOF) switch (c) { /* - * Make 'n' option fallthrough to 'l' option for for backward + * Make 'n' option fallthrough to 'L' option for for backward * compatibility with old utils. */ case 'n': -- cgit v1.2.3 From 30c0100525069cc8b3ac7f20779973b6afec184f Mon Sep 17 00:00:00 2001 From: Nicolas Boos Date: Wed, 6 May 2020 07:59:53 +0900 Subject: add missing repair.h from dist generated tarball CC fsck.o ../../../fsck/fsck.c:18:20: fatal error: repair.h: No such file or directory #include repair.h ^ compilation terminated. Makefile:424: recipe for target 'fsck.o' failed make[3]: *** [fsck.o] Error 1 Signed-off-by: Nicolas Boos Signed-off-by: Namjae Jeon --- fsck/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/Makefile.am b/fsck/Makefile.am index 16cef7f..c8ae3c7 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -3,6 +3,6 @@ fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = fsck.exfat -fsck_exfat_SOURCES = fsck.c repair.c fsck.h +fsck_exfat_SOURCES = fsck.c repair.c fsck.h repair.h man_MANS = fsck.exfat.8 -- cgit v1.2.3 From 3dfd19a3180be929750ad95c88c4cf2b90213637 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 6 May 2020 12:51:24 +0900 Subject: exfatprogs: fix typo and update paragraph in README Signed-off-by: Namjae Jeon --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b545025..48861d9 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ 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. exfatprogress is the goal of providing high performance and windows -level outstanding utils compared to old utils. And this software is -licensed under the GNU General Public License Version 2. +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. ## Building exfatprogs Install prerequisite packages: -- cgit v1.2.3 From fa1dd88450fa66f23987b964908bb2fa00ba55a6 Mon Sep 17 00:00:00 2001 From: Nicolas Boos Date: Wed, 6 May 2020 14:39:31 +0900 Subject: exfatprogs: add NEWS file Add NEWS file with changes of the two releases. Signed-off-by: Nicolas Boos Signed-off-by: Namjae Jeon --- NEWS | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 NEWS diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..5857f11 --- /dev/null +++ b/NEWS @@ -0,0 +1,26 @@ +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 -- cgit v1.2.3 From 59500bc68be059641af2f008e005a11e816e139e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 9 May 2020 13:36:43 +0900 Subject: exfatprogs: harmonize set volume label option between tune.exfat and mkfs.exfat Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 12 ++++++------ tune/tune.c | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index e718633..c9e04b0 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -383,12 +383,12 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, static void usage(void) { fprintf(stderr, "Usage: mkfs.exfat\n"); - fprintf(stderr, "\t-L string | --volume-label=string Set volume label\n"); - fprintf(stderr, "\t-c | --cluster-size Set cluster size\n"); - fprintf(stderr, "\t-f | --full-format Full format\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"); + fprintf(stderr, "\t-L | --volume-label=label Set volume label\n"); + fprintf(stderr, "\t-c | --cluster-size=size(or suffixed by 'K' or 'M') Specify cluster size\n"); + fprintf(stderr, "\t-f | --full-format Full format\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); } diff --git a/tune/tune.c b/tune/tune.c index 6e5ec89..340aed4 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -17,11 +17,11 @@ 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 Set volume label\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"); + fprintf(stderr, "\t-l | --print-label Print volume label\n"); + fprintf(stderr, "\t-L | --volume-label=label Set volume label\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); } -- cgit v1.2.3 From 21cda02a88e3f570ebb33177f753b749da7a16d8 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 10 May 2020 09:03:26 +0900 Subject: manpages: move each manpages to manpages directory Signed-off-by: Namjae Jeon --- Makefile.am | 8 +++---- fsck/Makefile.am | 2 -- fsck/fsck.exfat.8 | 44 ------------------------------------- manpages/fsck.exfat.8 | 44 +++++++++++++++++++++++++++++++++++++ manpages/mkfs.exfat.8 | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ manpages/tune.exfat.8 | 34 +++++++++++++++++++++++++++++ mkfs/Makefile.am | 2 -- mkfs/mkfs.exfat.8 | 60 --------------------------------------------------- tune/Makefile.am | 2 -- tune/tune.exfat.8 | 34 ----------------------------- 10 files changed, 142 insertions(+), 148 deletions(-) delete mode 100644 fsck/fsck.exfat.8 create mode 100644 manpages/fsck.exfat.8 create mode 100644 manpages/mkfs.exfat.8 create mode 100644 manpages/tune.exfat.8 delete mode 100644 mkfs/mkfs.exfat.8 delete mode 100644 tune/tune.exfat.8 diff --git a/Makefile.am b/Makefile.am index 3d9c2c6..f4f4cbc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,9 +6,9 @@ SUBDIRS = lib mkfs fsck tune # manpages dist_man8_MANS = \ - fsck/fsck.exfat.8 \ - tune/tune.exfat.8 \ - mkfs/mkfs.exfat.8 + manpages/fsck.exfat.8 \ + manpages/tune.exfat.8 \ + manpages/mkfs.exfat.8 # other stuff EXTRA_DIST = \ @@ -16,6 +16,6 @@ EXTRA_DIST = \ Android.bp \ lib/Android.bp \ mkfs/Android.bp \ - tune/Android.bp \ + tune/Android.bp \ fsck/Android.bp \ README.md diff --git a/fsck/Makefile.am b/fsck/Makefile.am index c8ae3c7..31b0b70 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -4,5 +4,3 @@ fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = fsck.exfat fsck_exfat_SOURCES = fsck.c repair.c fsck.h repair.h - -man_MANS = fsck.exfat.8 diff --git a/fsck/fsck.exfat.8 b/fsck/fsck.exfat.8 deleted file mode 100644 index b6cf3c8..0000000 --- a/fsck/fsck.exfat.8 +++ /dev/null @@ -1,44 +0,0 @@ -.TH fsck.exfat 8 -.SH NAME -fsck.exfat \- check an exFAT filesystem -.SH SYNOPSIS -.B fsck.exfat -[ -.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 filesytem -depending on the options passed. -.PP -.SH OPTIONS -.TP -.BI \-n -Check the filesystem but do not attempt to repair the filesystem. -.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. -.TP -.SH SEE ALSO -.BR fsck (8), -.BR fstab (5), diff --git a/manpages/fsck.exfat.8 b/manpages/fsck.exfat.8 new file mode 100644 index 0000000..b6cf3c8 --- /dev/null +++ b/manpages/fsck.exfat.8 @@ -0,0 +1,44 @@ +.TH fsck.exfat 8 +.SH NAME +fsck.exfat \- check an exFAT filesystem +.SH SYNOPSIS +.B fsck.exfat +[ +.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 filesytem +depending on the options passed. +.PP +.SH OPTIONS +.TP +.BI \-n +Check the filesystem but do not attempt to repair the filesystem. +.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. +.TP +.SH SEE ALSO +.BR fsck (8), +.BR fstab (5), diff --git a/manpages/mkfs.exfat.8 b/manpages/mkfs.exfat.8 new file mode 100644 index 0000000..bc7ab4d --- /dev/null +++ b/manpages/mkfs.exfat.8 @@ -0,0 +1,60 @@ +.TH mkfs.exfat 8 +.SH NAME +mkfs.exfat \- create an exFAT filesystem +.SH SYNOPSIS +.B mkfs.exfat +[ +.B \-c +.I cluster_size +] [ +.B \-f +] [ +.B \-h +] [ +.B \-L +.I volume_label +] [ +.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 +.BI \-c " cluster_size" +Specify the cluster size. Cluster size can be specified in m/M for megabytes +and k/K for kilobytes. +.TP +.BI \-f +Performs a full format. This zeros the entire disk device while +creating the exFAT filesystem. +.TP +.BI \-h +Prints the help and exit. +.TP +.BI \-L " volume_label" +Specifies the volume label associated with the exFAT filesystem. +.TP +.BI \-v +Prints verbose debugging information while creating the exFAT filesystem. +.TP +.B \-V +Prints the version number and exits. +.SH SEE ALSO +.BR mkfs (8), +.BR mount (8), diff --git a/manpages/tune.exfat.8 b/manpages/tune.exfat.8 new file mode 100644 index 0000000..12dd6d2 --- /dev/null +++ b/manpages/tune.exfat.8 @@ -0,0 +1,34 @@ +.TH tune.exfat 8 +.SH NAME +tune.exfat \- adjust tunable filesystem parameters on an exFAT filesystem +.SH SYNOPSIS +.B tune.exfat +[ +.B \-l +] [ +.B \-L volume_label +.I volume_label +] [ +.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 the volume label of the exFAT filesystem. +.TP +.BI \-L" volume_label" +Set the volume label 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. +.TP diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index b0c4c27..201ba3b 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -5,5 +5,3 @@ mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = mkfs.exfat mkfs_exfat_SOURCES = mkfs.c upcase.c mkfs.h - -man_MANS = mkfs.exfat.8 diff --git a/mkfs/mkfs.exfat.8 b/mkfs/mkfs.exfat.8 deleted file mode 100644 index bc7ab4d..0000000 --- a/mkfs/mkfs.exfat.8 +++ /dev/null @@ -1,60 +0,0 @@ -.TH mkfs.exfat 8 -.SH NAME -mkfs.exfat \- create an exFAT filesystem -.SH SYNOPSIS -.B mkfs.exfat -[ -.B \-c -.I cluster_size -] [ -.B \-f -] [ -.B \-h -] [ -.B \-L -.I volume_label -] [ -.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 -.BI \-c " cluster_size" -Specify the cluster size. Cluster size can be specified in m/M for megabytes -and k/K for kilobytes. -.TP -.BI \-f -Performs a full format. This zeros the entire disk device while -creating the exFAT filesystem. -.TP -.BI \-h -Prints the help and exit. -.TP -.BI \-L " volume_label" -Specifies the volume label associated with the exFAT filesystem. -.TP -.BI \-v -Prints verbose debugging information while creating the exFAT filesystem. -.TP -.B \-V -Prints the version number and exits. -.SH SEE ALSO -.BR mkfs (8), -.BR mount (8), diff --git a/tune/Makefile.am b/tune/Makefile.am index 2ca7f90..1b3740b 100644 --- a/tune/Makefile.am +++ b/tune/Makefile.am @@ -4,5 +4,3 @@ tune_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = tune.exfat tune_exfat_SOURCES = tune.c - -man_MANS = tune.exfat.8 diff --git a/tune/tune.exfat.8 b/tune/tune.exfat.8 deleted file mode 100644 index 12dd6d2..0000000 --- a/tune/tune.exfat.8 +++ /dev/null @@ -1,34 +0,0 @@ -.TH tune.exfat 8 -.SH NAME -tune.exfat \- adjust tunable filesystem parameters on an exFAT filesystem -.SH SYNOPSIS -.B tune.exfat -[ -.B \-l -] [ -.B \-L volume_label -.I volume_label -] [ -.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 the volume label of the exFAT filesystem. -.TP -.BI \-L" volume_label" -Set the volume label 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. -.TP -- cgit v1.2.3 From 8f858ce1c8b881221704a4193892803308fe0d6d Mon Sep 17 00:00:00 2001 From: Peter Seiderer Date: Sat, 9 May 2020 15:05:46 +0200 Subject: fsck: fix node may be used uninitialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The complicated way of gcc to tell not all failure pathes set a return value != 0 in the calls before. Fixes: fsck.c:1063:18: error: ‘node’ may be used uninitialized in this function [-Werror=maybe-uninitialized] node->parent = dir; ^ fsck.c:871:22: note: ‘node’ was declared here struct exfat_inode *node; ^ Signed-off-by: Peter Seiderer --- fsck/fsck.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index ae463f9..b10f0ae 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -800,12 +800,12 @@ static int read_file_dentries(struct exfat_de_iter *iter, ret = exfat_de_iter_get(iter, 0, &file_de); if (ret || file_de->type != EXFAT_FILE) { exfat_err("failed to get file dentry. %d\n", ret); - return ret; + return -EINVAL; } ret = exfat_de_iter_get(iter, 1, &stream_de); if (ret || stream_de->type != EXFAT_STREAM) { exfat_err("failed to get stream dentry. %d\n", ret); - return ret; + return -EINVAL; } *new_node = NULL; @@ -824,6 +824,7 @@ static int read_file_dentries(struct exfat_de_iter *iter, ret = exfat_de_iter_get(iter, i, &name_de); if (ret || name_de->type != EXFAT_NAME) { exfat_err("failed to get name dentry. %d\n", ret); + ret = -EINVAL; goto err; } @@ -851,6 +852,7 @@ static int read_file_dentries(struct exfat_de_iter *iter, exfat_err("valid size %llu greater than size %llu: %s\n", le64_to_cpu(stream_de->stream_valid_size), node->size, path_resolve_ctx.local_path); + ret = -EINVAL; goto err; } -- cgit v1.2.3 From de76150b25daf6522441caacda066904eee16530 Mon Sep 17 00:00:00 2001 From: Peter Seiderer Date: Sat, 9 May 2020 13:43:37 +0200 Subject: mkfs/fsck: use PRIu64/PRIx64 to print 64-bit types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change cpu_to_le64()/cpu_to_le32()/cpu_to_le16() defines to return determined types (instead of __le64/__le32/__le16) and use PRIu64/PRIx64 to print 64-bit types. Fixes: mkfs.c:60:14: error: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] exfat_debug("Volume Length(sectors) : %llu\n", ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ fsck.c:484:13: error: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] exfat_err("too large sector count: %llu\n, expected: %llu\n", ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ fsck.c:851:13: error: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] exfat_err("valid size %llu greater than size %llu: %s\n", ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ fsck.c:930:14: error: format ‘%llx’ expects argument of type ‘long long unsigned int’, but argument 3 has type ‘long unsigned int’ [-Werror=format=] exfat_debug("start cluster %#x, size %#llx\n", ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ fsck.c:938:13: error: format ‘%llx’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] exfat_err("invalid size of allocation bitmap. 0x%llx\n", ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ fsck.c:992:13: error: format ‘%llx’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] exfat_err("invalid size of upcase table. 0x%llx\n", ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Peter Seiderer --- fsck/fsck.c | 11 ++++++----- include/exfat_ondisk.h | 6 +++--- mkfs/mkfs.c | 3 ++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index ae463f9..67d7946 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -481,7 +482,7 @@ static bool exfat_boot_region_check(struct exfat *exfat) if (le64_to_cpu(bs->bsx.vol_length) * EXFAT_SECTOR_SIZE(bs) > exfat->blk_dev->size) { - exfat_err("too large sector count: %llu\n, expected: %llu\n", + exfat_err("too large sector count: %" PRIu64 "\n, expected: %llu\n", le64_to_cpu(bs->bsx.vol_length), exfat->blk_dev->num_sectors); goto err; @@ -848,7 +849,7 @@ static int read_file_dentries(struct exfat_de_iter *iter, if (le64_to_cpu(stream_de->stream_valid_size) > node->size) { resolve_path_parent(&path_resolve_ctx, iter->parent, node); - exfat_err("valid size %llu greater than size %llu: %s\n", + exfat_err("valid size %" PRIu64 " greater than size %llu: %s\n", le64_to_cpu(stream_de->stream_valid_size), node->size, path_resolve_ctx.local_path); goto err; @@ -927,7 +928,7 @@ static bool read_alloc_bitmap(struct exfat_de_iter *iter) if (exfat_de_iter_get(iter, 0, &dentry)) return false; - exfat_debug("start cluster %#x, size %#llx\n", + exfat_debug("start cluster %#x, size %#" PRIx64 "\n", le32_to_cpu(dentry->bitmap_start_clu), le64_to_cpu(dentry->bitmap_size)); @@ -935,7 +936,7 @@ static bool read_alloc_bitmap(struct exfat_de_iter *iter) if (le64_to_cpu(dentry->bitmap_size) < DIV_ROUND_UP(exfat->bit_count, 8)) { - exfat_err("invalid size of allocation bitmap. 0x%llx\n", + exfat_err("invalid size of allocation bitmap. 0x%" PRIx64 "\n", le64_to_cpu(dentry->bitmap_size)); return false; } @@ -989,7 +990,7 @@ static bool read_upcase_table(struct exfat_de_iter *iter) size = (size_t)le64_to_cpu(dentry->upcase_size); if (size > EXFAT_MAX_UPCASE_CHARS * sizeof(__le16) || size == 0 || size % sizeof(__le16)) { - exfat_err("invalid size of upcase table. 0x%llx\n", + exfat_err("invalid size of upcase table. 0x%" PRIx64 "\n", le64_to_cpu(dentry->upcase_size)); return false; } diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index ae2827b..70546a3 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -26,9 +26,9 @@ #define cpu_to_le64(x) (x) #endif -#define le64_to_cpu(x) cpu_to_le64(x) -#define le32_to_cpu(x) cpu_to_le32(x) -#define le16_to_cpu(x) cpu_to_le16(x) +#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 diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index e718633..e539be4 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -57,7 +58,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, memset(ppbr->boot_code, 0, 390); ppbr->signature = cpu_to_le16(PBR_SIGNATURE); - exfat_debug("Volume Length(sectors) : %llu\n", + 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)); -- cgit v1.2.3 From f0f0eb6355a6edaea34125058f979a750238d5d5 Mon Sep 17 00:00:00 2001 From: Peter Seiderer Date: Sat, 9 May 2020 18:06:52 +0200 Subject: fsck: use PRIu64/PRIx64 to printf 64-bit types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: fsck.c:725:13: error: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘__u64 {aka long unsigned int}’ [-Werror=format=] exfat_err("size %llu is greater than cluster heap: %s\n", ^ fsck.c:740:13: error: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘__u64 {aka long unsigned int}’ [-Werror=format=] exfat_err("directory size %llu is not divisible by %d: %s\n", ^ fsck.c:853:13: error: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 3 has type ‘__u64 {aka long unsigned int}’ [-Werror=format=] exfat_err("valid size %" PRIu64 " greater than size %llu: %s\n", ^ fsck.c:1181:14: error: format ‘%llx’ expects argument of type ‘long long unsigned int’, but argument 3 has type ‘__u64 {aka long unsigned int}’ [-Werror=format=] exfat_debug("root directory: start cluster[0x%x] size[0x%llx]\n", ^ Signed-off-by: Peter Seiderer --- Changes v1 -> v2: - rebase on branch exfat-next - change node data type from __u64 to uint64_t to avoid duplicated casts --- fsck/fsck.c | 8 ++++---- fsck/fsck.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 67d7946..2bb4285 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -722,7 +722,7 @@ static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, if (node->size > le32_to_cpu(exfat->bs->bsx.clu_count) * EXFAT_CLUSTER_SIZE(exfat->bs)) { resolve_path_parent(&path_resolve_ctx, parent, node); - exfat_err("size %llu is greater than cluster heap: %s\n", + exfat_err("size %" PRIu64 " is greater than cluster heap: %s\n", node->size, path_resolve_ctx.local_path); ret = false; } @@ -737,7 +737,7 @@ static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, if ((node->attr & ATTR_SUBDIR) && node->size % EXFAT_CLUSTER_SIZE(exfat->bs) != 0) { resolve_path_parent(&path_resolve_ctx, parent, node); - exfat_err("directory size %llu is not divisible by %d: %s\n", + exfat_err("directory size %" PRIu64 " is not divisible by %d: %s\n", node->size, EXFAT_CLUSTER_SIZE(exfat->bs), path_resolve_ctx.local_path); ret = false; @@ -849,7 +849,7 @@ static int read_file_dentries(struct exfat_de_iter *iter, if (le64_to_cpu(stream_de->stream_valid_size) > node->size) { resolve_path_parent(&path_resolve_ctx, iter->parent, node); - exfat_err("valid size %" PRIu64 " greater than size %llu: %s\n", + exfat_err("valid size %" PRIu64 " greater than size %" PRIu64 ": %s\n", le64_to_cpu(stream_de->stream_valid_size), node->size, path_resolve_ctx.local_path); goto err; @@ -1176,7 +1176,7 @@ static bool exfat_root_dir_check(struct exfat *exfat) root->size = clus_count * EXFAT_CLUSTER_SIZE(exfat->bs); exfat->root = root; - exfat_debug("root directory: start cluster[0x%x] size[0x%llx]\n", + exfat_debug("root directory: start cluster[0x%x] size[0x%" PRIx64 "]\n", root->first_clus, root->size); return true; err: diff --git a/fsck/fsck.h b/fsck/fsck.h index cc2a1b2..ef46fa7 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -18,7 +18,7 @@ struct exfat_inode { clus_t last_lclus; clus_t last_pclus; __u16 attr; - __u64 size; + uint64_t size; bool is_contiguous; off_t dentry_file_offset; __le16 name[0]; /* only for directory */ -- cgit v1.2.3 From c705c66a740bf5b56fc3fb49c36fc897b765776d Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sat, 2 May 2020 21:20:29 +0200 Subject: exfatprogs: Fix -Wsign-compare warnings * clang-10 is now able to build with -Werror -Wall -Wextra Signed-off-by: Luca Stefani Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 16 ++++++++-------- fsck/repair.c | 4 ++-- mkfs/mkfs.c | 7 ++++--- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 5631dc3..499fa11 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -328,7 +328,7 @@ static ssize_t exfat_file_read(struct exfat *exfat, struct exfat_inode *node, ssize_t read_size; size_t remain_size; - if (file_offset >= node->size) + if (file_offset >= (off_t)node->size) return EOF; clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); @@ -384,7 +384,7 @@ static int boot_region_checksum(struct exfat *exfat) __le32 checksum; unsigned short size; void *sect; - int i; + unsigned int i; size = EXFAT_SECTOR_SIZE(exfat->bs); sect = malloc(size); @@ -632,7 +632,7 @@ static int exfat_de_iter_get(struct exfat_de_iter *iter, int ith, struct exfat_dentry **dentry) { off_t de_next_file_offset; - int de_next_offset; + unsigned int de_next_offset; bool need_read_1_clus = false; int ret; @@ -756,7 +756,7 @@ static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, static void dentry_calc_checksum(struct exfat_dentry *dentry, __le16 *checksum, bool primary) { - int i; + unsigned int i; uint8_t *bytes; bytes = (uint8_t *)dentry; @@ -924,7 +924,7 @@ static bool read_alloc_bitmap(struct exfat_de_iter *iter) { struct exfat_dentry *dentry; struct exfat *exfat; - size_t alloc_bitmap_size; + ssize_t alloc_bitmap_size; exfat = iter->exfat; if (exfat_de_iter_get(iter, 0, &dentry)) @@ -974,7 +974,7 @@ static bool read_upcase_table(struct exfat_de_iter *iter) { struct exfat_dentry *dentry; struct exfat *exfat; - size_t size; + ssize_t size; __le16 *upcase; __le32 checksum; @@ -989,8 +989,8 @@ static bool read_upcase_table(struct exfat_de_iter *iter) return false; } - size = (size_t)le64_to_cpu(dentry->upcase_size); - if (size > EXFAT_MAX_UPCASE_CHARS * sizeof(__le16) || + size = (ssize_t)le64_to_cpu(dentry->upcase_size); + if (size > (ssize_t)(EXFAT_MAX_UPCASE_CHARS * sizeof(__le16)) || size == 0 || size % sizeof(__le16)) { exfat_err("invalid size of upcase table. 0x%" PRIx64 "\n", le64_to_cpu(dentry->upcase_size)); diff --git a/fsck/repair.c b/fsck/repair.c index 2c90299..bbfb75d 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -21,7 +21,7 @@ static bool fix_bs_checksum(struct exfat *exfat, union exfat_repair_context *rctx) { unsigned int size; - int i; + unsigned int i; size = EXFAT_SECTOR_SIZE(exfat->bs); for (i = 0; i < size/sizeof(__le32); i++) { @@ -47,7 +47,7 @@ static struct exfat_repair_problem problems[] = { static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) { - int i; + unsigned int i; for (i = 0; i < sizeof(problems)/sizeof(problems[0]); i++) { if (problems[i].prcode == prcode) { diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 199ba73..1f82f44 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -84,7 +84,7 @@ static int exfat_write_sector(struct exfat_blk_dev *bd, void *buf, lseek(bd->dev_fd, offset, SEEK_SET); bytes = write(bd->dev_fd, buf, bd->sector_size); - if (bytes != bd->sector_size) { + if (bytes != (int)bd->sector_size) { exfat_err("write failed, sec_off : %u, bytes : %d\n", sec_off, bytes); return -1; @@ -199,7 +199,8 @@ static int exfat_write_checksum_sector(struct exfat_blk_dev *bd, unsigned int checksum, bool is_backup) { __le32 *checksum_buf; - int i, ret = 0; + int ret = 0; + unsigned int i; unsigned int sec_idx = CHECKSUM_SEC_IDX; checksum_buf = malloc(bd->sector_size); @@ -323,7 +324,7 @@ static int exfat_create_fat_table(struct exfat_blk_dev *bd, static int exfat_create_bitmap(struct exfat_blk_dev *bd) { char *bitmap; - int i, nbytes; + unsigned int i, nbytes; bitmap = calloc(finfo.bitmap_byte_len, sizeof(*bitmap)); if (!bitmap) -- cgit v1.2.3 From a1a8db25f0a30a04fe380d79ddd268c0d5de2df5 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 12 May 2020 10:20:43 +0900 Subject: exfatprogs: fix -Wtype-limits warnings Fixes: ../include/libexfat.h:98:19: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits] 98 | if (print_level >= level) { \ Signed-off-by: Hyunchul Lee --- include/libexfat.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/libexfat.h b/include/libexfat.h index 853b78c..56053b4 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -89,9 +89,9 @@ ssize_t exfat_utf16_dec(const __u16 *in_str, size_t in_len, extern unsigned int print_level; -#define EXFAT_ERROR (0) -#define EXFAT_INFO (1) -#define EXFAT_DEBUG (2) +#define EXFAT_ERROR (1) +#define EXFAT_INFO (2) +#define EXFAT_DEBUG (3) #define exfat_msg(level, fmt, ...) \ do { \ -- cgit v1.2.3 From ff4fd5bfea05d4f98e5316c5a54e40ab0907b42e Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 12 May 2020 10:47:46 +0900 Subject: exfatprogs: fix -Waddress-of-packed-member warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: ../include/exfat_ondisk.h:205:31: warning: taking address of packed member of ‘struct ’ may result in an unaligned pointer value [-Waddress-of-packed-member] 205 | #define vol_label dentry.vol.volume_label fsck.c:913:30: note: in expansion of macro ‘vol_label’ 913 | if (exfat_utf16_dec(dentry->vol_label, dentry->vol_char_cnt*2, Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 4 +++- tune/tune.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 499fa11..2a13f43 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -897,6 +897,7 @@ static bool read_volume_label(struct exfat_de_iter *iter) { struct exfat *exfat; struct exfat_dentry *dentry; + __le16 disk_label[VOLUME_LABEL_MAX_LEN]; exfat = iter->exfat; if (exfat_de_iter_get(iter, 0, &dentry)) @@ -910,7 +911,8 @@ static bool read_volume_label(struct exfat_de_iter *iter) return false; } - if (exfat_utf16_dec(dentry->vol_label, dentry->vol_char_cnt*2, + memcpy(disk_label, dentry->vol_label, sizeof(disk_label)); + if (exfat_utf16_dec(disk_label, dentry->vol_char_cnt*2, exfat->volume_label, sizeof(exfat->volume_label)) < 0) { exfat_err("failed to decode volume label\n"); return false; diff --git a/tune/tune.c b/tune/tune.c index 340aed4..d160a37 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -68,6 +68,7 @@ static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) { struct exfat_dentry *vol_entry; char volume_label[VOLUME_LABEL_BUFFER_SIZE]; + __le16 disk_label[VOLUME_LABEL_MAX_LEN]; int nbytes; vol_entry = malloc(sizeof(struct exfat_dentry)); @@ -83,8 +84,9 @@ static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) return -1; } + memcpy(disk_label, vol_entry->vol_label, sizeof(disk_label)); memset(volume_label, 0, sizeof(volume_label)); - if (exfat_utf16_dec(vol_entry->vol_label, vol_entry->vol_char_cnt*2, + if (exfat_utf16_dec(disk_label, vol_entry->vol_char_cnt*2, volume_label, sizeof(volume_label)) < 0) { exfat_err("failed to decode volume label\n"); return -1; -- cgit v1.2.3 From 5fa017ee27874a088952f5ffc7079dd07ab3669a Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 12 May 2020 11:19:45 +0900 Subject: mkfs: fix -Wimplicit-fallthrough warning Fixes: mkfs.c:536:13: warning: this statement may fall through [-Wimplicit-fallthrough=] 536 | byte_size <<= 10; Signed-off-by: Hyunchul Lee --- mkfs/mkfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 1f82f44..4cafb3e 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -533,7 +533,8 @@ static long long parse_cluster_size(const char *size) switch (*data_unit) { case 'M': case 'm': - byte_size <<= 10; + byte_size <<= 20; + break; case 'K': case 'k': byte_size <<= 10; -- cgit v1.2.3 From 269e40e63f7d1833562185d5a8e582f5082f9ac1 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 12 May 2020 13:23:28 +0900 Subject: exfatprogs: release 1.0.3 version 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. Signed-off-by: Namjae Jeon --- include/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/version.h b/include/version.h index 7a3f8d4..1ec8a63 100644 --- a/include/version.h +++ b/include/version.h @@ -5,6 +5,6 @@ #ifndef _VERSION_H -#define EXFAT_PROGS_VERSION "1.0.2" +#define EXFAT_PROGS_VERSION "1.0.3" #endif /* !_VERSION_H */ -- cgit v1.2.3 From ee68b78681b00c7f6f5ccab65114bf462fa515e0 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 12 May 2020 14:29:27 +0900 Subject: exfatprogs: update NEWS file Signed-off-by: Namjae Jeon --- NEWS | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/NEWS b/NEWS index 5857f11..064ba7b 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,23 @@ +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 ====================================== -- cgit v1.2.3 From a850d0a9053b741b764ad306a9c206e46c873a21 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Wed, 13 May 2020 16:50:45 +0200 Subject: libexfat: Fix memory leak * We were returning without freeing the wcs variable Signed-off-by: Luca Stefani --- lib/libexfat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libexfat.c b/lib/libexfat.c index 24f682b..f5bc5c0 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -215,6 +215,7 @@ ssize_t exfat_utf16_enc(const char *in_str, __u16 *out_str, size_t out_size) 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; } -- cgit v1.2.3 From 5d487af8ec2a306eb56fd0b3d8f372b0d53437ad Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Wed, 13 May 2020 16:58:57 +0200 Subject: fsck: Fix possible UAF * The code was inverted and pr ( the problem ) was initialized only after the user was asked to fix it Signed-off-by: Luca Stefani --- fsck/repair.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fsck/repair.c b/fsck/repair.c index bbfb75d..40f20bc 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -92,15 +92,15 @@ bool exfat_repair(struct exfat *exfat, er_problem_code_t prcode, struct exfat_repair_problem *pr = NULL; int need_repair; - need_repair = ask_repair(exfat, pr); - if (!need_repair) - return false; - pr = find_problem(prcode); if (!pr) { exfat_err("unknown problem code. %#x\n", prcode); return false; } + need_repair = ask_repair(exfat, pr); + if (!need_repair) + return false; + return pr->fix_problem(exfat, rctx); } -- cgit v1.2.3 From ee921d8c79f002200e2701d3adb5666dc5426748 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Wed, 13 May 2020 17:02:56 +0200 Subject: mkfs: Don't attempt to close uninitialized fd * While checking for executable options we use the go-to out call which closes the yet-unopened file descriptor, close it properly Signed-off-by: Luca Stefani --- mkfs/mkfs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 4cafb3e..2edd1c5 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -622,23 +622,24 @@ int main(int argc, char *argv[]) ret = exfat_build_mkfs_info(&bd, &ui); if (ret) - goto out; + goto close; ret = exfat_zero_out_disk(&bd, &ui); if (ret) - goto out; + goto close; ret = make_exfat(&bd, &ui); if (ret) - goto out; + 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"); - close(bd.dev_fd); return ret; } -- cgit v1.2.3 From d73405702845b9122885eac0fa946d67ee57c250 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 10:38:34 +0900 Subject: fsck: fix invalid retrun value in check_inode if file dentries are corrupted, check_inode should return false. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 2a13f43..8a646a9 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -703,7 +703,7 @@ static off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter) static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, struct exfat_inode *node) { - bool ret = false; + bool ret = true; if (node->size == 0 && node->first_clus != EXFAT_FREE_CLUSTER) { resolve_path_parent(&path_resolve_ctx, parent, node); @@ -882,7 +882,7 @@ static int read_file(struct exfat_de_iter *de_iter, } ret = check_inode(de_iter->exfat, de_iter->parent, node); - if (ret) { + if (!ret) { exfat_err("corrupted file directory entries.\n"); free_exfat_inode(node); return ret; -- cgit v1.2.3 From 4a9ea79b331b930f262b33d329c791f749888095 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 10:41:45 +0900 Subject: fsck: continue to check other files even if some are corrupted if files are corrupted in a directory, continue to check other files in different directories. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 8a646a9..194c36c 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1148,7 +1148,6 @@ static bool exfat_filesystem_check(struct exfat *exfat) ret = false; exfat_err("failed to check dentries: %s\n", path_resolve_ctx.local_path); - goto out; } list_del(&dir->list); -- cgit v1.2.3 From 1fe093dcfb841a3f0b2feb2ac34ebed90e646684 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 11:04:54 +0900 Subject: fsck: move exfat_de_iter functions to de_iter.c Signed-off-by: Hyunchul Lee --- fsck/Makefile.am | 2 +- fsck/de_iter.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fsck/fsck.c | 168 +----------------------------------------------------- fsck/fsck.h | 14 +++++ 4 files changed, 187 insertions(+), 166 deletions(-) create mode 100644 fsck/de_iter.c diff --git a/fsck/Makefile.am b/fsck/Makefile.am index 31b0b70..57a0ede 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -3,4 +3,4 @@ fsck_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = fsck.exfat -fsck_exfat_SOURCES = fsck.c repair.c fsck.h repair.h +fsck_exfat_SOURCES = fsck.c repair.c fsck.h de_iter.c repair.h diff --git a/fsck/de_iter.c b/fsck/de_iter.c new file mode 100644 index 0000000..d392313 --- /dev/null +++ b/fsck/de_iter.c @@ -0,0 +1,169 @@ +#include +#include +#include + +#include "exfat_ondisk.h" +#include "libexfat.h" +#include "fsck.h" + +static ssize_t exfat_file_read(struct exfat *exfat, struct exfat_inode *node, + void *buf, size_t total_size, off_t file_offset) +{ + size_t clus_size; + clus_t start_l_clus, l_clus, p_clus; + unsigned int clus_offset; + int ret; + off_t device_offset; + ssize_t read_size; + size_t remain_size; + + if (file_offset >= (off_t)node->size) + return EOF; + + clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); + total_size = MIN(total_size, node->size - file_offset); + remain_size = total_size; + + if (remain_size == 0) + return 0; + + start_l_clus = file_offset / clus_size; + clus_offset = file_offset % clus_size; + if (start_l_clus >= node->last_lclus && + node->last_pclus != EXFAT_EOF_CLUSTER) { + l_clus = node->last_lclus; + p_clus = node->last_pclus; + } else { + l_clus = 0; + p_clus = node->first_clus; + } + + while (p_clus != EXFAT_EOF_CLUSTER) { + if (exfat_invalid_clus(exfat, p_clus)) + return -EINVAL; + if (l_clus < start_l_clus) + goto next_clus; + + read_size = MIN(remain_size, clus_size - clus_offset); + device_offset = exfat_c2o(exfat, p_clus) + clus_offset; + if (exfat_read(exfat->blk_dev->dev_fd, buf, read_size, + device_offset) != read_size) + return -EIO; + + clus_offset = 0; + buf = (char *)buf + read_size; + remain_size -= read_size; + if (remain_size == 0) + goto out; + +next_clus: + l_clus++; + ret = inode_get_clus_next(exfat, node, p_clus, &p_clus); + if (ret) + return ret; + } +out: + node->last_lclus = l_clus; + node->last_pclus = p_clus; + return total_size - remain_size; +} + +int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, + struct exfat_inode *dir) +{ + ssize_t ret; + + if (!iter->dentries) { + iter->read_size = EXFAT_CLUSTER_SIZE(exfat->bs); + iter->dentries = malloc(iter->read_size * 2); + if (!iter->dentries) { + exfat_err("failed to allocate memory\n"); + return -ENOMEM; + } + } + + ret = exfat_file_read(exfat, dir, iter->dentries, iter->read_size, 0); + if (ret != iter->read_size) { + exfat_err("failed to read directory entries.\n"); + return -EIO; + } + + iter->exfat = exfat; + iter->parent = dir; + 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 de_next_file_offset; + unsigned int de_next_offset; + bool need_read_1_clus = false; + int ret; + + de_next_file_offset = iter->de_file_offset + + ith * sizeof(struct exfat_dentry); + + if (de_next_file_offset + sizeof(struct exfat_dentry) > + round_down(iter->parent->size, sizeof(struct exfat_dentry))) + return EOF; + + /* + * dentry must be in current cluster, or next cluster which + * will be read + */ + if (de_next_file_offset - + (iter->de_file_offset / iter->read_size) * iter->read_size >= + iter->read_size * 2) + return -ERANGE; + + de_next_offset = de_next_file_offset % (iter->read_size * 2); + + /* read a cluster if needed */ + if (de_next_file_offset >= iter->next_read_offset) { + void *buf; + + need_read_1_clus = de_next_offset < iter->read_size; + buf = need_read_1_clus ? + iter->dentries : iter->dentries + iter->read_size; + + ret = exfat_file_read(iter->exfat, iter->parent, buf, + iter->read_size, iter->next_read_offset); + if (ret == EOF) { + return EOF; + } else if (ret <= 0) { + exfat_err("failed to read a cluster. %d\n", ret); + 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->dentries + de_next_offset); + 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; +} diff --git a/fsck/fsck.c b/fsck/fsck.c index 194c36c..9c5f683 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -214,13 +214,13 @@ static void exfat_free_dir_list(struct exfat *exfat) } } -static inline bool exfat_invalid_clus(struct exfat *exfat, clus_t clus) +bool exfat_invalid_clus(struct exfat *exfat, clus_t clus) { return clus < EXFAT_FIRST_CLUSTER || (clus - EXFAT_FIRST_CLUSTER) > le32_to_cpu(exfat->bs->bsx.clu_count); } -static int inode_get_clus_next(struct exfat *exfat, struct exfat_inode *node, +int inode_get_clus_next(struct exfat *exfat, struct exfat_inode *node, clus_t clus, clus_t *next) { off_t offset; @@ -307,7 +307,7 @@ static off_t exfat_s2o(struct exfat *exfat, off_t sect) return sect << exfat->bs->bsx.sect_size_bits; } -static off_t exfat_c2o(struct exfat *exfat, unsigned int clus) +off_t exfat_c2o(struct exfat *exfat, unsigned int clus) { if (clus < EXFAT_FIRST_CLUSTER) return ~0L; @@ -317,68 +317,6 @@ static off_t exfat_c2o(struct exfat *exfat, unsigned int clus) exfat->bs->bsx.sect_per_clus_bits)); } -static ssize_t exfat_file_read(struct exfat *exfat, struct exfat_inode *node, - void *buf, size_t total_size, off_t file_offset) -{ - size_t clus_size; - clus_t start_l_clus, l_clus, p_clus; - unsigned int clus_offset; - int ret; - off_t device_offset; - ssize_t read_size; - size_t remain_size; - - if (file_offset >= (off_t)node->size) - return EOF; - - clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); - total_size = MIN(total_size, node->size - file_offset); - remain_size = total_size; - - if (remain_size == 0) - return 0; - - start_l_clus = file_offset / clus_size; - clus_offset = file_offset % clus_size; - if (start_l_clus >= node->last_lclus && - node->last_pclus != EXFAT_EOF_CLUSTER) { - l_clus = node->last_lclus; - p_clus = node->last_pclus; - } else { - l_clus = 0; - p_clus = node->first_clus; - } - - while (p_clus != EXFAT_EOF_CLUSTER) { - if (exfat_invalid_clus(exfat, p_clus)) - return -EINVAL; - if (l_clus < start_l_clus) - goto next_clus; - - read_size = MIN(remain_size, clus_size - clus_offset); - device_offset = exfat_c2o(exfat, p_clus) + clus_offset; - if (exfat_read(exfat->blk_dev->dev_fd, buf, read_size, - device_offset) != read_size) - return -EIO; - - clus_offset = 0; - buf = (char *)buf + read_size; - remain_size -= read_size; - if (remain_size == 0) - goto out; - -next_clus: - l_clus++; - ret = inode_get_clus_next(exfat, node, p_clus, &p_clus); - if (ret) - return ret; - } -out: - node->last_lclus = l_clus; - node->last_pclus = p_clus; - return total_size - remain_size; -} - static int boot_region_checksum(struct exfat *exfat) { __le32 checksum; @@ -600,106 +538,6 @@ static int resolve_path_parent(struct path_resolve_ctx *ctx, return ret; } -static int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, - struct exfat_inode *dir) -{ - ssize_t ret; - - if (!iter->dentries) { - iter->read_size = EXFAT_CLUSTER_SIZE(exfat->bs); - iter->dentries = malloc(iter->read_size * 2); - if (!iter->dentries) { - exfat_err("failed to allocate memory\n"); - return -ENOMEM; - } - } - - ret = exfat_file_read(exfat, dir, iter->dentries, iter->read_size, 0); - if (ret != iter->read_size) { - exfat_err("failed to read directory entries.\n"); - return -EIO; - } - - iter->exfat = exfat; - iter->parent = dir; - iter->de_file_offset = 0; - iter->next_read_offset = iter->read_size; - iter->max_skip_dentries = 0; - return 0; -} - -static int exfat_de_iter_get(struct exfat_de_iter *iter, - int ith, struct exfat_dentry **dentry) -{ - off_t de_next_file_offset; - unsigned int de_next_offset; - bool need_read_1_clus = false; - int ret; - - de_next_file_offset = iter->de_file_offset + - ith * sizeof(struct exfat_dentry); - - if (de_next_file_offset + sizeof(struct exfat_dentry) > - round_down(iter->parent->size, sizeof(struct exfat_dentry))) - return EOF; - - /* - * dentry must be in current cluster, or next cluster which - * will be read - */ - if (de_next_file_offset - - (iter->de_file_offset / iter->read_size) * iter->read_size >= - iter->read_size * 2) - return -ERANGE; - - de_next_offset = de_next_file_offset % (iter->read_size * 2); - - /* read a cluster if needed */ - if (de_next_file_offset >= iter->next_read_offset) { - void *buf; - - need_read_1_clus = de_next_offset < iter->read_size; - buf = need_read_1_clus ? - iter->dentries : iter->dentries + iter->read_size; - - ret = exfat_file_read(iter->exfat, iter->parent, buf, - iter->read_size, iter->next_read_offset); - if (ret == EOF) { - return EOF; - } else if (ret <= 0) { - exfat_err("failed to read a cluster. %d\n", ret); - 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->dentries + de_next_offset); - return 0; -} - -/* - * @skip_dentries must be the largest @ith + 1 of exfat_de_iter_get - * since the last call of exfat_de_iter_advance - */ -static 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; -} - -static off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter) -{ - return iter->de_file_offset; -} - static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, struct exfat_inode *node) { diff --git a/fsck/fsck.h b/fsck/fsck.h index ef46fa7..e31c367 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -60,4 +60,18 @@ struct exfat { (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); +bool exfat_invalid_clus(struct exfat *exfat, clus_t clus); +int inode_get_clus_next(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_advance(struct exfat_de_iter *iter, int skip_dentries); +off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter); + #endif -- cgit v1.2.3 From d85d14e3e2358637c7e47c2803a68f0ce6b6c947 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 11:28:44 +0900 Subject: fsck: read directory entries without file offset fsck reads directory entries sequentially in cluster unit. So we don't have to read the entries with file offset. it causes unncessary FAT table scan and consumes more memory. Signed-off-by: Hyunchul Lee --- fsck/de_iter.c | 160 ++++++++++++++++++++++++--------------------------------- fsck/fsck.c | 29 +++++++++-- fsck/fsck.h | 17 ++++-- 3 files changed, 105 insertions(+), 101 deletions(-) diff --git a/fsck/de_iter.c b/fsck/de_iter.c index d392313..f812156 100644 --- a/fsck/de_iter.c +++ b/fsck/de_iter.c @@ -6,90 +6,72 @@ #include "libexfat.h" #include "fsck.h" -static ssize_t exfat_file_read(struct exfat *exfat, struct exfat_inode *node, - void *buf, size_t total_size, off_t file_offset) +static ssize_t write_clus(struct exfat_de_iter *iter, int bufidx) { - size_t clus_size; - clus_t start_l_clus, l_clus, p_clus; - unsigned int clus_offset; - int ret; off_t device_offset; - ssize_t read_size; - size_t remain_size; + struct exfat *exfat = iter->exfat; + struct buffer_desc *desc; + unsigned int i; + + desc = &iter->buffer_desc[bufidx]; + device_offset = exfat_c2o(exfat, desc->p_clus); + + 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; +} - if (file_offset >= (off_t)node->size) - return EOF; +static ssize_t read_next_clus(struct exfat_de_iter *iter, clus_t l_clus) +{ + struct exfat *exfat = iter->exfat; + struct buffer_desc *desc; + off_t device_offset; + int ret; - clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); - total_size = MIN(total_size, node->size - file_offset); - remain_size = total_size; - - if (remain_size == 0) - return 0; - - start_l_clus = file_offset / clus_size; - clus_offset = file_offset % clus_size; - if (start_l_clus >= node->last_lclus && - node->last_pclus != EXFAT_EOF_CLUSTER) { - l_clus = node->last_lclus; - p_clus = node->last_pclus; - } else { - l_clus = 0; - p_clus = node->first_clus; - } + desc = &iter->buffer_desc[l_clus & 0x01]; + if (l_clus == 0) + desc->p_clus = iter->parent->first_clus; - while (p_clus != EXFAT_EOF_CLUSTER) { - if (exfat_invalid_clus(exfat, p_clus)) - return -EINVAL; - if (l_clus < start_l_clus) - goto next_clus; - - read_size = MIN(remain_size, clus_size - clus_offset); - device_offset = exfat_c2o(exfat, p_clus) + clus_offset; - if (exfat_read(exfat->blk_dev->dev_fd, buf, read_size, - device_offset) != read_size) - return -EIO; - - clus_offset = 0; - buf = (char *)buf + read_size; - remain_size -= read_size; - if (remain_size == 0) - goto out; - -next_clus: - l_clus++; - ret = inode_get_clus_next(exfat, node, p_clus, &p_clus); + if (write_clus(iter, l_clus & 0x01)) + return -EIO; + + if (l_clus > 0) { + ret = inode_get_clus_next(exfat, iter->parent, + iter->buffer_desc[(l_clus - 1) & 0x01].p_clus, + &desc->p_clus); if (ret) return ret; } -out: - node->last_lclus = l_clus; - node->last_pclus = p_clus; - return total_size - remain_size; + device_offset = exfat_c2o(exfat, desc->p_clus); + return exfat_read(exfat->blk_dev->dev_fd, desc->buffer, + iter->read_size, device_offset); } int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, - struct exfat_inode *dir) + struct exfat_inode *dir) { - ssize_t ret; + iter->exfat = exfat; + iter->parent = dir; + iter->read_size = EXFAT_CLUSTER_SIZE(exfat->bs); + iter->write_size = EXFAT_SECTOR_SIZE(exfat->bs); - if (!iter->dentries) { - iter->read_size = EXFAT_CLUSTER_SIZE(exfat->bs); - iter->dentries = malloc(iter->read_size * 2); - if (!iter->dentries) { - exfat_err("failed to allocate memory\n"); - return -ENOMEM; - } - } + if (!iter->buffer_desc) + iter->buffer_desc = exfat->buffer_desc; - ret = exfat_file_read(exfat, dir, iter->dentries, iter->read_size, 0); - if (ret != iter->read_size) { + if (read_next_clus(iter, 0) != (ssize_t)iter->read_size) { exfat_err("failed to read directory entries.\n"); return -EIO; } - iter->exfat = exfat; - iter->parent = dir; iter->de_file_offset = 0; iter->next_read_offset = iter->read_size; iter->max_skip_dentries = 0; @@ -97,45 +79,33 @@ int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, } int exfat_de_iter_get(struct exfat_de_iter *iter, - int ith, struct exfat_dentry **dentry) + int ith, struct exfat_dentry **dentry) { - off_t de_next_file_offset; - unsigned int de_next_offset; - bool need_read_1_clus = false; - int ret; + off_t next_de_file_offset; + ssize_t ret; + clus_t next_l_clus; - de_next_file_offset = iter->de_file_offset + + next_de_file_offset = iter->de_file_offset + ith * sizeof(struct exfat_dentry); + next_l_clus = (clus_t) (next_de_file_offset / iter->read_size); - if (de_next_file_offset + sizeof(struct exfat_dentry) > - round_down(iter->parent->size, sizeof(struct exfat_dentry))) + if (next_de_file_offset + sizeof(struct exfat_dentry) > + iter->parent->size) return EOF; - /* - * dentry must be in current cluster, or next cluster which + * desired dentry must be in current, or next cluster which * will be read */ - if (de_next_file_offset - - (iter->de_file_offset / iter->read_size) * iter->read_size >= - iter->read_size * 2) + if (next_l_clus > iter->de_file_offset / iter->read_size + 1) return -ERANGE; - de_next_offset = de_next_file_offset % (iter->read_size * 2); - - /* read a cluster if needed */ - if (de_next_file_offset >= iter->next_read_offset) { - void *buf; - - need_read_1_clus = de_next_offset < iter->read_size; - buf = need_read_1_clus ? - iter->dentries : iter->dentries + iter->read_size; - - ret = exfat_file_read(iter->exfat, iter->parent, buf, - iter->read_size, iter->next_read_offset); + /* read next cluster if needed */ + if (next_de_file_offset >= iter->next_read_offset) { + ret = read_next_clus(iter, next_l_clus); if (ret == EOF) { return EOF; - } else if (ret <= 0) { - exfat_err("failed to read a cluster. %d\n", ret); + } else if (ret != (ssize_t)iter->read_size) { + exfat_err("failed to read a cluster. %zd\n", ret); return ret; } iter->next_read_offset += iter->read_size; @@ -144,7 +114,9 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, if (ith + 1 > iter->max_skip_dentries) iter->max_skip_dentries = ith + 1; - *dentry = (struct exfat_dentry *) (iter->dentries + de_next_offset); + *dentry = (struct exfat_dentry *) + (iter->buffer_desc[next_l_clus & 0x01].buffer + + next_de_file_offset % iter->read_size); return 0; } diff --git a/fsck/fsck.c b/fsck/fsck.c index 9c5f683..5173625 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -192,13 +192,19 @@ static struct exfat *alloc_exfat(struct exfat_blk_dev *bd) static void free_exfat(struct exfat *exfat) { + int i; + if (exfat) { if (exfat->bs) free(exfat->bs); - if (exfat->de_iter.dentries) - free(exfat->de_iter.dentries); if (exfat->alloc_bitmap) free(exfat->alloc_bitmap); + for (i = 0; i < 2; i++) { + if (exfat->buffer_desc[i].buffer) + free(exfat->buffer_desc[i].buffer); + if (exfat->buffer_desc[i].dirty) + free(exfat->buffer_desc[i].dirty); + } free(exfat); } } @@ -214,7 +220,7 @@ static void exfat_free_dir_list(struct exfat *exfat) } } -bool exfat_invalid_clus(struct exfat *exfat, clus_t clus) +static bool exfat_invalid_clus(struct exfat *exfat, clus_t clus) { return clus < EXFAT_FIRST_CLUSTER || (clus - EXFAT_FIRST_CLUSTER) > le32_to_cpu(exfat->bs->bsx.clu_count); @@ -1002,6 +1008,23 @@ static bool exfat_root_dir_check(struct exfat *exfat) { struct exfat_inode *root; clus_t clus_count; + int i; + + exfat->clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); + exfat->sect_size = EXFAT_SECTOR_SIZE(exfat->bs); + + /* allocate cluster buffers */ + for (i = 0; i < 2; i++) { + exfat->buffer_desc[i].buffer = + (char *)malloc(exfat->clus_size); + if (!exfat->buffer_desc[i].buffer) + return false; + exfat->buffer_desc[i].dirty = + (char *)calloc( + (exfat->clus_size / exfat->sect_size), 1); + if (!exfat->buffer_desc[i].dirty) + return false; + } root = alloc_exfat_inode(ATTR_SUBDIR); if (!root) { diff --git a/fsck/fsck.h b/fsck/fsck.h index e31c367..e5fe1a8 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -27,12 +27,19 @@ struct exfat_inode { #define EXFAT_NAME_MAX 255 #define NAME_BUFFER_SIZE ((EXFAT_NAME_MAX+1)*2) +struct buffer_desc { + clus_t p_clus; + char *buffer; + char *dirty; +}; + struct exfat_de_iter { struct exfat *exfat; struct exfat_inode *parent; - unsigned char *dentries; /* cluster * 2 allocated */ - unsigned int read_size; /* cluster size */ - off_t de_file_offset; /* offset in dentries buffer */ + struct buffer_desc *buffer_desc; /* cluster * 2 */ + 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; }; @@ -51,7 +58,10 @@ struct exfat { char volume_label[VOLUME_LABEL_BUFFER_SIZE]; struct exfat_inode *root; struct list_head dir_list; + unsigned int clus_size; + unsigned int sect_size; struct exfat_de_iter de_iter; + struct buffer_desc buffer_desc[2]; /* cluster * 2 */ __u32 *alloc_bitmap; __u64 bit_count; }; @@ -62,7 +72,6 @@ struct exfat { /* fsck.c */ off_t exfat_c2o(struct exfat *exfat, unsigned int clus); -bool exfat_invalid_clus(struct exfat *exfat, clus_t clus); int inode_get_clus_next(struct exfat *exfat, struct exfat_inode *node, clus_t clus, clus_t *next); -- cgit v1.2.3 From f3988842ecaf53e9a22f9f98ea3fc603e870f0ff Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 11:46:20 +0900 Subject: fsck: add exfat_de_iter_get_dirty function fsck can get directory entries by exfat_de_iter_get_dirty and modify the entries. Signed-off-by: Hyunchul Lee --- fsck/de_iter.c | 27 +++++++++++++++++++++++++++ fsck/fsck.c | 2 ++ fsck/fsck.h | 3 +++ 3 files changed, 32 insertions(+) diff --git a/fsck/de_iter.c b/fsck/de_iter.c index f812156..2573550 100644 --- a/fsck/de_iter.c +++ b/fsck/de_iter.c @@ -120,6 +120,33 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, return 0; } +int exfat_de_iter_get_dirty(struct exfat_de_iter *iter, + int ith, struct exfat_dentry **dentry) +{ + off_t next_file_offset; + clus_t l_clus; + 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); + l_clus = (clus_t)(next_file_offset / iter->read_size); + sect_idx = (int)(next_file_offset / iter->write_size); + iter->buffer_desc[l_clus & 0x01].dirty[sect_idx] = 1; + } + + return ret; +} + +int exfat_de_iter_flush(struct exfat_de_iter *iter) +{ + if (write_clus(iter, 0) || + write_clus(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 diff --git a/fsck/fsck.c b/fsck/fsck.c index 5173625..856ecb5 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -949,10 +949,12 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) exfat_de_iter_advance(de_iter, dentry_count); } list_splice(&sub_dir_list, &exfat->dir_list); + exfat_de_iter_flush(de_iter); return 0; err: inode_free_children(dir, false); INIT_LIST_HEAD(&dir->children); + exfat_de_iter_flush(de_iter); return ret; } diff --git a/fsck/fsck.h b/fsck/fsck.h index e5fe1a8..3f11eb6 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -80,6 +80,9 @@ 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); -- cgit v1.2.3 From 6ac77fa9ed9ed30bf96eb71af20187d7b1f7f4de Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 12:11:59 +0900 Subject: fsck: repair: replace exfat_repair with exfat_repair_ask Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 46 +++++++++++++++--------- fsck/fsck.h | 5 ++- fsck/repair.c | 110 ++++++++++++++++++++++++++++++---------------------------- fsck/repair.h | 11 ++---- 4 files changed, 92 insertions(+), 80 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 856ecb5..8550478 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -325,10 +325,11 @@ off_t exfat_c2o(struct exfat *exfat, unsigned int clus) static int boot_region_checksum(struct exfat *exfat) { - __le32 checksum; - unsigned short size; void *sect; unsigned int i; + uint32_t checksum; + int ret = 0; + unsigned short size; size = EXFAT_SECTOR_SIZE(exfat->bs); sect = malloc(size); @@ -341,32 +342,45 @@ static int boot_region_checksum(struct exfat *exfat) for (i = 1; i < 11; i++) { if (exfat_read(exfat->blk_dev->dev_fd, sect, size, i * size) != (ssize_t)size) { - free(sect); - return -EIO; + ret = -EIO; + goto out; } boot_calc_checksum(sect, size, false, &checksum); } - if (exfat_read(exfat->blk_dev->dev_fd, sect, size, i * size) != + if (exfat_read(exfat->blk_dev->dev_fd, sect, size, 11 * size) != (ssize_t)size) { - free(sect); - return -EIO; + ret = -EIO; + goto out; } + for (i = 0; i < size/sizeof(checksum); i++) { if (le32_to_cpu(((__le32 *)sect)[i]) != checksum) { - union exfat_repair_context rctx = { - .bs_checksum.checksum = checksum, - .bs_checksum.checksum_sect = sect, - }; - if (!exfat_repair(exfat, ER_BS_CHECKSUM, &rctx)) { - exfat_err("invalid checksum. 0x%x\n", - le32_to_cpu(((__le32 *)sect)[i])); - free(sect); - return -EIO; + if (exfat_repair_ask(exfat, ER_BS_CHECKSUM, + "checksums of boot sector are not correct. " + "%#x, but expected %#x", + le32_to_cpu(((__le32 *)sect)[i]), checksum)) { + goto out_write; + } else { + ret = -EINVAL; + goto out; } } } +out: + free(sect); + return ret; +out_write: + for (i = 0; i < size/sizeof(checksum); i++) + ((__le32 *)sect)[i] = cpu_to_le32(checksum); + + if (exfat_write(exfat->blk_dev->dev_fd, + sect, size, size * 11) != size) { + exfat_err("failed to write checksum sector\n"); + free(sect); + return -EIO; + } free(sect); return 0; } diff --git a/fsck/fsck.h b/fsck/fsck.h index 3f11eb6..5f4d17f 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -48,11 +48,14 @@ enum fsck_ui_options { FSCK_OPTS_REPAIR_ASK = 0x01, FSCK_OPTS_REPAIR_YES = 0x02, FSCK_OPTS_REPAIR_NO = 0x04, - FSCK_OPTS_REPAIR = 0x07, + FSCK_OPTS_REPAIR_AUTO = 0x08, + FSCK_OPTS_REPAIR = 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]; diff --git a/fsck/repair.c b/fsck/repair.c index 40f20bc..d6b8189 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -4,6 +4,7 @@ */ #include #include +#include #include "exfat_ondisk.h" #include "libexfat.h" @@ -12,37 +13,26 @@ struct exfat_repair_problem { er_problem_code_t prcode; - const char *description; - bool (*fix_problem)(struct exfat *exfat, - union exfat_repair_context *rctx); + unsigned int flags; + unsigned int prompt_type; }; -static bool fix_bs_checksum(struct exfat *exfat, - union exfat_repair_context *rctx) -{ - unsigned int size; - unsigned int i; - - size = EXFAT_SECTOR_SIZE(exfat->bs); - for (i = 0; i < size/sizeof(__le32); i++) { - ((__le32 *)rctx->bs_checksum.checksum_sect)[i] = - rctx->bs_checksum.checksum; - } +/* Problem flags */ +#define ERF_PREEN_YES 0x00000001 +#define ERF_DEFAULT_YES 0x00000002 - if (exfat_write(exfat->blk_dev->dev_fd, - rctx->bs_checksum.checksum_sect, - size, size * 11) != size) { - exfat_err("failed to write checksum sector\n"); - return false; - } +/* Prompt types */ +#define ERP_FIX 0x00000001 +#define ERP_TRUNCATE 0x00000002 - return true; -} +static const char *prompts[] = { + "Repair", + "Fix", + "Truncate", +}; static struct exfat_repair_problem problems[] = { - {ER_BS_CHECKSUM, - "the checksum of boot sector is not correct", - fix_bs_checksum}, + {ER_BS_CHECKSUM, ERF_PREEN_YES | ERF_DEFAULT_YES, ERP_FIX}, }; static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) @@ -59,38 +49,44 @@ static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) static bool ask_repair(struct exfat *exfat, struct exfat_repair_problem *pr) { + bool repair = false; char answer[8]; - switch (exfat->options & FSCK_OPTS_REPAIR) { - case FSCK_OPTS_REPAIR_ASK: - do { - printf("%s: Fix (y/N)?", pr->description); - 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); - return false; - case FSCK_OPTS_REPAIR_YES: - return true; - case FSCK_OPTS_REPAIR_NO: - case 0: - default: - return false; + if (exfat->options & FSCK_OPTS_REPAIR_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; } - return false; + + printf(". %s (y/N)? %c\n", prompts[pr->prompt_type], + repair ? 'y' : 'n'); + return repair; } -bool exfat_repair(struct exfat *exfat, er_problem_code_t prcode, - union exfat_repair_context *rctx) +bool exfat_repair_ask(struct exfat *exfat, er_problem_code_t prcode, + const char *desc, ...) { struct exfat_repair_problem *pr = NULL; - int need_repair; + va_list ap; pr = find_problem(prcode); if (!pr) { @@ -98,9 +94,15 @@ bool exfat_repair(struct exfat *exfat, er_problem_code_t prcode, return false; } - need_repair = ask_repair(exfat, pr); - if (!need_repair) - return false; + va_start(ap, desc); + vprintf(desc, ap); + va_end(ap); - return pr->fix_problem(exfat, rctx); + if (ask_repair(exfat, pr)) { + if (pr->prompt_type & ERP_TRUNCATE) + exfat->dirty_fat = true; + exfat->dirty = true; + return true; + } else + return false; } diff --git a/fsck/repair.h b/fsck/repair.h index 4c56763..197e94e 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -9,14 +9,7 @@ typedef unsigned int er_problem_code_t; -union exfat_repair_context { - struct { - __le32 checksum; - void *checksum_sect; - } bs_checksum; -}; - -bool exfat_repair(struct exfat *exfat, er_problem_code_t prcode, - union exfat_repair_context *rctx); +bool exfat_repair_ask(struct exfat *exfat, er_problem_code_t prcode, + const char *fmt, ...); #endif -- cgit v1.2.3 From 2da3469dd9eac5c009b750e6047a70c6f739979b Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 12:15:16 +0900 Subject: fsck: exit with 0x01 if error are corrected Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 8550478..9047f08 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1186,7 +1186,10 @@ int main(int argc, char * const argv[]) if (ui.ei.writeable) fsync(bd.dev_fd); printf("%s: clean\n", ui.ei.dev_name); - ret = FSCK_EXIT_NO_ERRORS; + if (exfat->dirty) + ret = FSCK_EXIT_CORRECTED; + else + ret = FSCK_EXIT_NO_ERRORS; out: exfat_show_stat(); err: -- cgit v1.2.3 From 8a8278ce806b5a6126ef28bf711828632281cf10 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 12:17:53 +0900 Subject: fsck: repair: add --repair-auto option with this option, fsck repairs the file system problems which may be corrected safely without an user action. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 9047f08..09187ba 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -71,6 +71,7 @@ static struct option opts[] = { {"repair", no_argument, NULL, 'r' }, {"repair-yes", no_argument, NULL, 'y' }, {"repair-no", no_argument, NULL, 'n' }, + {"repair-auto", no_argument, NULL, 'p' }, {"version", no_argument, NULL, 'V' }, {"verbose", no_argument, NULL, 'v' }, {"help", no_argument, NULL, 'h' }, @@ -84,6 +85,7 @@ static void usage(char *name) fprintf(stderr, "\t-r | --repair Repair interactively\n"); fprintf(stderr, "\t-y | --repair-yes Repair without ask\n"); fprintf(stderr, "\t-n | --repair-no No repair\n"); + fprintf(stderr, "\t-p | --repair-auto Repair automatically\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"); @@ -1105,7 +1107,7 @@ int main(int argc, char * const argv[]) exfat_err("failed to init locale/codeset\n"); opterr = 0; - while ((c = getopt_long(argc, argv, "rynVvh", opts, NULL)) != EOF) { + while ((c = getopt_long(argc, argv, "rynpVvh", opts, NULL)) != EOF) { switch (c) { case 'n': if (ui.options & FSCK_OPTS_REPAIR) @@ -1125,6 +1127,12 @@ int main(int argc, char * const argv[]) ui.options |= FSCK_OPTS_REPAIR_YES; ui.ei.writeable = true; break; + case 'p': + if (ui.options & FSCK_OPTS_REPAIR) + usage(argv[0]); + ui.options |= FSCK_OPTS_REPAIR_AUTO; + ui.ei.writeable = true; + break; case 'V': version_only = true; break; -- cgit v1.2.3 From 2e2d4eb16d6d223e5645345695d75b5b8b964afb Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 12:36:49 +0900 Subject: fsck: repair: add test for the bad checksum of boot region Signed-off-by: Hyunchul Lee --- tests/bs_bad_csum/exfat.img.xz | Bin 0 -> 3716 bytes tests/test_fsck.sh | 56 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/bs_bad_csum/exfat.img.xz create mode 100755 tests/test_fsck.sh diff --git a/tests/bs_bad_csum/exfat.img.xz b/tests/bs_bad_csum/exfat.img.xz new file mode 100644 index 0000000..e3fba3f Binary files /dev/null and b/tests/bs_bad_csum/exfat.img.xz differ diff --git a/tests/test_fsck.sh b/tests/test_fsck.sh new file mode 100755 index 0000000..c1bb6ce --- /dev/null +++ b/tests/test_fsck.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +TESTCASE_DIR=$1 +IMAGE_FILE=exfat.img +FSCK_PROG=../build/sbin/fsck.exfat +FSCK_OPTS=-y + +echo "Running $TESTCASE_DIR" +echo "-----------------------------------" + +if [ "$EUID" -ne "0" ]; then + echo "This script should be ran as root" + exit +fi + +# Set up image file as loop device +unxz -cfk $TESTCASE_DIR/$IMAGE_FILE.xz > $IMAGE_FILE +sudo losetup -f $IMAGE_FILE +DEV_FILE=`losetup -j $IMAGE_FILE | awk '{print $1}' | sed 's/://g'` + +# 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 + exit +fi + +# Run fsck again +$FSCK_PROG -n $DEV_FILE +if [ "$?" -ne "0" ]; then + echo "" + echo "Failed, corrupted $TESTCASE_DIR" + losetup -d $DEV_FILE + exit +fi + +if [ -e "$TESTCASE_DIR/exfat.img.expected.xz" ]; then + EXPECTED_FILE=$IMAGE_FILE.expected + unxz -cfk "$TESTCASE_DIR/$EXPECTED_FILE.xz" > $EXPECTED_FILE + xxd $IMAGE_FILE > $IMAGE_FILE.hex + xxd $EXPECTED_FILE > $EXPECTED_FILE.hex + diff $IMAGE_FILE.hex $EXPECTED_FILE.hex + if [ "$?" -ne "0" ]; then + echo "" + echo "Failed $TESTCASE_DIR" + losetup -d $DEV_FILE + exit + fi +fi + +echo "" +echo "Passed $TESTCASE_DIR" + +losetup -d $DEV_FILE -- cgit v1.2.3 From 8290055040b79736024221faedf529096a1a8357 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 15:04:04 +0900 Subject: fsck: repair: the bad checksum of file dentries Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 291 +++++++++++++++++++++++++++++++--------------------------- fsck/repair.c | 3 +- fsck/repair.h | 1 + 3 files changed, 157 insertions(+), 138 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 09187ba..1e81932 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -222,6 +222,117 @@ static void exfat_free_dir_list(struct exfat *exfat) } } +static size_t 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; +} + +/* + * get references of ancestors that include @child until the count of + * ancesters is not larger than @count and the count of characters of + * their names is not larger than @max_char_len. + * return true if root is reached. + */ +bool get_ancestors(struct exfat_inode *child, + struct exfat_inode **ancestors, int count, + int max_char_len, + int *ancestor_count) +{ + struct exfat_inode *dir; + int name_len, char_len; + int root_depth, depth, i; + + root_depth = 0; + char_len = 0; + max_char_len += 1; + + dir = child; + while (dir) { + name_len = utf16_len(dir->name, NAME_BUFFER_SIZE); + if (char_len + name_len > max_char_len) + break; + + /* include '/' */ + char_len += name_len + 1; + root_depth++; + + dir = dir->parent; + } + + depth = MIN(root_depth, count); + + for (dir = child, i = depth - 1; i >= 0; dir = dir->parent, i--) + ancestors[i] = dir; + + *ancestor_count = depth; + return dir == NULL; +} + +static int resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child) +{ + int depth, i; + int name_len; + __le16 *utf16_path; + static const __le16 utf16_slash = cpu_to_le16(0x002F); + static const __le16 utf16_null = cpu_to_le16(0x0000); + size_t in_size; + + ctx->local_path[0] = '\0'; + + get_ancestors(child, + ctx->ancestors, + sizeof(ctx->ancestors) / sizeof(ctx->ancestors[0]), + PATH_MAX, + &depth); + + utf16_path = ctx->utf16_path; + for (i = 0; i < depth; i++) { + name_len = utf16_len(ctx->ancestors[i]->name, NAME_BUFFER_SIZE); + memcpy((char *)utf16_path, (char *)ctx->ancestors[i]->name, + name_len * 2); + utf16_path += name_len; + memcpy((char *)utf16_path, &utf16_slash, sizeof(utf16_slash)); + utf16_path++; + } + + if (depth > 0) + utf16_path--; + memcpy((char *)utf16_path, &utf16_null, sizeof(utf16_null)); + utf16_path++; + + in_size = (utf16_path - ctx->utf16_path) * sizeof(__le16); + return exfat_utf16_dec(ctx->utf16_path, in_size, + ctx->local_path, sizeof(ctx->local_path)); +} + +static int resolve_path_parent(struct path_resolve_ctx *ctx, + struct exfat_inode *parent, struct exfat_inode *child) +{ + int ret; + struct exfat_inode *old; + + old = child->parent; + child->parent = parent; + + ret = resolve_path(ctx, child); + child->parent = old; + return ret; +} + +#define repair_file_ask(iter, inode, code, fmt, ...) \ +({ \ + resolve_path_parent(&path_resolve_ctx, \ + (iter)->parent, inode); \ + exfat_repair_ask((iter)->exfat, code, \ + "%s: " fmt, \ + path_resolve_ctx.local_path, \ + ##__VA_ARGS__); \ +}) + static bool exfat_invalid_clus(struct exfat *exfat, clus_t clus) { return clus < EXFAT_FIRST_CLUSTER || @@ -463,117 +574,57 @@ err: return false; } -static size_t 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; -} - -/* - * get references of ancestors that include @child until the count of - * ancesters is not larger than @count and the count of characters of - * their names is not larger than @max_char_len. - * return true if root is reached. - */ -bool get_ancestors(struct exfat_inode *child, - struct exfat_inode **ancestors, int count, - int max_char_len, - int *ancestor_count) +static void dentry_calc_checksum(struct exfat_dentry *dentry, + __le16 *checksum, bool primary) { - struct exfat_inode *dir; - int name_len, char_len; - int root_depth, depth, i; - - root_depth = 0; - char_len = 0; - max_char_len += 1; + unsigned int i; + uint8_t *bytes; - dir = child; - while (dir) { - name_len = utf16_len(dir->name, NAME_BUFFER_SIZE); - if (char_len + name_len > max_char_len) - break; + bytes = (uint8_t *)dentry; - /* include '/' */ - char_len += name_len + 1; - root_depth++; + *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[0]; + *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[1]; - dir = dir->parent; + i = primary ? 4 : 2; + for (; i < sizeof(*dentry); i++) { + *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[i]; } - - depth = MIN(root_depth, count); - - for (dir = child, i = depth - 1; i >= 0; dir = dir->parent, i--) - ancestors[i] = dir; - - *ancestor_count = depth; - return dir == NULL; } -static int resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child) +static __le16 file_calc_checksum(struct exfat_de_iter *iter) { - int depth, i; - int name_len; - __le16 *utf16_path; - const __le16 utf16_slash = cpu_to_le16(0x002F); - size_t in_size; - - ctx->local_path[0] = '\0'; + __le16 checksum; + struct exfat_dentry *file_de, *de; + int i; - get_ancestors(child, - ctx->ancestors, - sizeof(ctx->ancestors) / sizeof(ctx->ancestors[0]), - PATH_MAX, - &depth); + checksum = 0; + exfat_de_iter_get(iter, 0, &file_de); - utf16_path = ctx->utf16_path; - for (i = 0; i < depth; i++) { - name_len = utf16_len(ctx->ancestors[i]->name, NAME_BUFFER_SIZE); - memcpy((char *)utf16_path, (char *)ctx->ancestors[i]->name, - name_len * 2); - utf16_path += name_len; - memcpy((char *)utf16_path, &utf16_slash, sizeof(utf16_slash)); - utf16_path++; + dentry_calc_checksum(file_de, &checksum, true); + for (i = 1; i <= file_de->file_num_ext; i++) { + exfat_de_iter_get(iter, i, &de); + dentry_calc_checksum(de, &checksum, false); } - if (depth > 0) - utf16_path--; - in_size = (utf16_path - ctx->utf16_path) * sizeof(__le16); - return exfat_utf16_dec(ctx->utf16_path, in_size, - ctx->local_path, sizeof(ctx->local_path)); -} - -static int resolve_path_parent(struct path_resolve_ctx *ctx, - struct exfat_inode *parent, struct exfat_inode *child) -{ - int ret; - struct exfat_inode *old; - - old = child->parent; - child->parent = parent; - - ret = resolve_path(ctx, child); - child->parent = old; - return ret; + return checksum; } -static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, - struct exfat_inode *node) +static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) { + struct exfat *exfat = iter->exfat; + struct exfat_dentry *dentry; bool ret = true; + uint16_t checksum; if (node->size == 0 && node->first_clus != EXFAT_FREE_CLUSTER) { - resolve_path_parent(&path_resolve_ctx, parent, node); + resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("file is empty, but first cluster is %#x: %s\n", node->first_clus, path_resolve_ctx.local_path); ret = false; } if (node->size > 0 && exfat_invalid_clus(exfat, node->first_clus)) { - resolve_path_parent(&path_resolve_ctx, parent, node); + resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("first cluster %#x is invalid: %s\n", node->first_clus, path_resolve_ctx.local_path); ret = false; @@ -581,14 +632,14 @@ static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, if (node->size > le32_to_cpu(exfat->bs->bsx.clu_count) * EXFAT_CLUSTER_SIZE(exfat->bs)) { - resolve_path_parent(&path_resolve_ctx, parent, node); + resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("size %" PRIu64 " is greater than cluster heap: %s\n", node->size, path_resolve_ctx.local_path); ret = false; } if (node->size == 0 && node->is_contiguous) { - resolve_path_parent(&path_resolve_ctx, parent, node); + resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("empty, but marked as contiguous: %s\n", path_resolve_ctx.local_path); ret = false; @@ -596,7 +647,7 @@ static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, if ((node->attr & ATTR_SUBDIR) && node->size % EXFAT_CLUSTER_SIZE(exfat->bs) != 0) { - resolve_path_parent(&path_resolve_ctx, parent, node); + resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("directory size %" PRIu64 " is not divisible by %d: %s\n", node->size, EXFAT_CLUSTER_SIZE(exfat->bs), path_resolve_ctx.local_path); @@ -604,48 +655,24 @@ static bool check_inode(struct exfat *exfat, struct exfat_inode *parent, } if (!node->is_contiguous && !inode_check_clus_chain(exfat, node)) { - resolve_path_parent(&path_resolve_ctx, parent, node); + resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("corrupted cluster chain: %s\n", path_resolve_ctx.local_path); ret = false; } - return ret; -} - -static void dentry_calc_checksum(struct exfat_dentry *dentry, - __le16 *checksum, bool primary) -{ - unsigned int i; - uint8_t *bytes; - - bytes = (uint8_t *)dentry; - - *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[0]; - *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[1]; - - i = primary ? 4 : 2; - for (; i < sizeof(*dentry); i++) { - *checksum = ((*checksum << 15) | (*checksum >> 1)) + bytes[i]; - } -} - -static __le16 file_calc_checksum(struct exfat_de_iter *iter) -{ - __le16 checksum; - struct exfat_dentry *file_de, *de; - int i; - - checksum = 0; - exfat_de_iter_get(iter, 0, &file_de); - - dentry_calc_checksum(file_de, &checksum, true); - for (i = 1; i <= file_de->file_num_ext; i++) { - exfat_de_iter_get(iter, i, &de); - dentry_calc_checksum(de, &checksum, false); + checksum = file_calc_checksum(iter); + exfat_de_iter_get(iter, 0, &dentry); + if (checksum != le16_to_cpu(dentry->file_checksum)) { + if (repair_file_ask(iter, node, ER_DE_CHECKSUM, + "the checksum of a file is wrong")) { + exfat_de_iter_get_dirty(iter, 0, &dentry); + dentry->file_checksum = cpu_to_le16(checksum); + } else + ret = false; } - return checksum; + return ret; } static int read_file_dentries(struct exfat_de_iter *iter, @@ -654,7 +681,6 @@ static int read_file_dentries(struct exfat_de_iter *iter, struct exfat_dentry *file_de, *stream_de, *name_de; struct exfat_inode *node; int i, ret; - __le16 checksum; /* TODO: mtime, atime, ... */ @@ -694,19 +720,10 @@ static int read_file_dentries(struct exfat_de_iter *iter, sizeof(name_de->name_unicode)); } - checksum = file_calc_checksum(iter); - if (le16_to_cpu(file_de->file_checksum) != checksum) { - exfat_err("invalid checksum. 0x%x != 0x%x\n", - le16_to_cpu(file_de->file_checksum), - le16_to_cpu(checksum)); - ret = -EINVAL; - goto err; - } - - node->size = le64_to_cpu(stream_de->stream_size); node->first_clus = le32_to_cpu(stream_de->stream_start_clu); node->is_contiguous = ((stream_de->stream_flags & EXFAT_SF_CONTIGUOUS) != 0); + node->size = le64_to_cpu(stream_de->stream_size); if (le64_to_cpu(stream_de->stream_valid_size) > node->size) { resolve_path_parent(&path_resolve_ctx, iter->parent, node); @@ -741,7 +758,7 @@ static int read_file(struct exfat_de_iter *de_iter, return ret; } - ret = check_inode(de_iter->exfat, de_iter->parent, node); + ret = check_inode(de_iter, node); if (!ret) { exfat_err("corrupted file directory entries.\n"); free_exfat_inode(node); diff --git a/fsck/repair.c b/fsck/repair.c index d6b8189..b0beea6 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -32,7 +32,8 @@ static const char *prompts[] = { }; static struct exfat_repair_problem problems[] = { - {ER_BS_CHECKSUM, ERF_PREEN_YES | ERF_DEFAULT_YES, ERP_FIX}, + {ER_BS_CHECKSUM, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, + {ER_DE_CHECKSUM, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, }; static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) diff --git a/fsck/repair.h b/fsck/repair.h index 197e94e..3d72d3e 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -6,6 +6,7 @@ #define _REPAIR_H #define ER_BS_CHECKSUM 0x00000001 +#define ER_DE_CHECKSUM 0x00001001 typedef unsigned int er_problem_code_t; -- cgit v1.2.3 From 6db9a062b88ba042ec9d5d34c7c27b5685380bcc Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 15:04:42 +0900 Subject: fsck: repair: add test for the bad checksum of file dentries Signed-off-by: Hyunchul Lee --- tests/de_bad_csum/exfat.img.xz | Bin 0 -> 3872 bytes tests/test_fsck.sh | 4 +--- 2 files changed, 1 insertion(+), 3 deletions(-) create mode 100644 tests/de_bad_csum/exfat.img.xz diff --git a/tests/de_bad_csum/exfat.img.xz b/tests/de_bad_csum/exfat.img.xz new file mode 100644 index 0000000..7c5dc64 Binary files /dev/null and b/tests/de_bad_csum/exfat.img.xz differ diff --git a/tests/test_fsck.sh b/tests/test_fsck.sh index c1bb6ce..c842789 100755 --- a/tests/test_fsck.sh +++ b/tests/test_fsck.sh @@ -39,9 +39,7 @@ fi if [ -e "$TESTCASE_DIR/exfat.img.expected.xz" ]; then EXPECTED_FILE=$IMAGE_FILE.expected unxz -cfk "$TESTCASE_DIR/$EXPECTED_FILE.xz" > $EXPECTED_FILE - xxd $IMAGE_FILE > $IMAGE_FILE.hex - xxd $EXPECTED_FILE > $EXPECTED_FILE.hex - diff $IMAGE_FILE.hex $EXPECTED_FILE.hex + diff <(xxd $IMAGE_FILE) <(xxd $EXPECTED_FILE) if [ "$?" -ne "0" ]; then echo "" echo "Failed $TESTCASE_DIR" -- cgit v1.2.3 From 42690c82eb57813df0ba7637a4cf88f0335954f5 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 15:36:22 +0900 Subject: fsck: repair: vaild size of a file is greater than it's size Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 19 ++++++++++++------- fsck/repair.c | 1 + fsck/repair.h | 1 + 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 1e81932..1145d6c 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -725,13 +725,18 @@ static int read_file_dentries(struct exfat_de_iter *iter, ((stream_de->stream_flags & EXFAT_SF_CONTIGUOUS) != 0); node->size = le64_to_cpu(stream_de->stream_size); - if (le64_to_cpu(stream_de->stream_valid_size) > node->size) { - resolve_path_parent(&path_resolve_ctx, iter->parent, node); - exfat_err("valid size %" PRIu64 " greater than size %" PRIu64 ": %s\n", - le64_to_cpu(stream_de->stream_valid_size), node->size, - path_resolve_ctx.local_path); - ret = -EINVAL; - goto err; + if (node->size < le64_to_cpu(stream_de->stream_valid_size)) { + if (repair_file_ask(iter, node, ER_FILE_VALID_SIZE, + "valid size %" PRIu64 " greater than size %" PRIu64, + le64_to_cpu(stream_de->stream_valid_size), + node->size)) { + exfat_de_iter_get_dirty(iter, 1, &stream_de); + stream_de->stream_valid_size = + stream_de->stream_size; + } else { + ret = -EINVAL; + goto err; + } } *skip_dentries = (file_de->file_num_ext + 1); diff --git a/fsck/repair.c b/fsck/repair.c index b0beea6..83749cf 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -34,6 +34,7 @@ static const char *prompts[] = { static struct exfat_repair_problem problems[] = { {ER_BS_CHECKSUM, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, {ER_DE_CHECKSUM, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, + {ER_FILE_VALID_SIZE, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, }; static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) diff --git a/fsck/repair.h b/fsck/repair.h index 3d72d3e..f6d14ee 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -7,6 +7,7 @@ #define ER_BS_CHECKSUM 0x00000001 #define ER_DE_CHECKSUM 0x00001001 +#define ER_FILE_VALID_SIZE 0x00002001 typedef unsigned int er_problem_code_t; -- cgit v1.2.3 From 24c2cf5f194a09d1a2905e4638e6b74f04d2448f Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 16:09:06 +0900 Subject: fsck: allocate bitmap to mark clusters as allocated Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 71 ++++++++++++++++++++++++++++++++++++++++++------------------- fsck/fsck.h | 7 ++++-- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 1145d6c..5b8fd45 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -201,6 +201,8 @@ static void free_exfat(struct exfat *exfat) free(exfat->bs); if (exfat->alloc_bitmap) free(exfat->alloc_bitmap); + if (exfat->disk_bitmap) + free(exfat->disk_bitmap); for (i = 0; i < 2; i++) { if (exfat->buffer_desc[i].buffer) free(exfat->buffer_desc[i].buffer); @@ -804,11 +806,27 @@ static bool read_volume_label(struct exfat_de_iter *iter) return true; } -static bool read_alloc_bitmap(struct exfat_de_iter *iter) +static void exfat_bitmap_set_range(struct exfat *exfat, + clus_t start_clus, clus_t count) +{ + clus_t clus; + + if (exfat_invalid_clus(exfat, start_clus) || + exfat_invalid_clus(exfat, start_clus + count)) + return; + + clus = start_clus; + while (clus < start_clus + count) { + EXFAT_BITMAP_SET(exfat->alloc_bitmap, + clus - EXFAT_FIRST_CLUSTER); + clus++; + } +} + +static bool read_bitmap(struct exfat_de_iter *iter) { struct exfat_dentry *dentry; struct exfat *exfat; - ssize_t alloc_bitmap_size; exfat = iter->exfat; if (exfat_de_iter_get(iter, 0, &dentry)) @@ -818,10 +836,8 @@ static bool read_alloc_bitmap(struct exfat_de_iter *iter) le32_to_cpu(dentry->bitmap_start_clu), le64_to_cpu(dentry->bitmap_size)); - exfat->bit_count = le32_to_cpu(exfat->bs->bsx.clu_count); - if (le64_to_cpu(dentry->bitmap_size) < - DIV_ROUND_UP(exfat->bit_count, 8)) { + DIV_ROUND_UP(exfat->clus_count, 8)) { exfat_err("invalid size of allocation bitmap. 0x%" PRIx64 "\n", le64_to_cpu(dentry->bitmap_size)); return false; @@ -832,24 +848,22 @@ static bool read_alloc_bitmap(struct exfat_de_iter *iter) return false; } - /* TODO: bitmap could be very large. */ - alloc_bitmap_size = EXFAT_BITMAP_SIZE(exfat->bit_count); - exfat->alloc_bitmap = (__u32 *)malloc(alloc_bitmap_size); - if (!exfat->alloc_bitmap) { - exfat_err("failed to allocate bitmap\n"); - return false; - } + exfat->disk_bitmap_clus = le32_to_cpu(dentry->bitmap_start_clu); + exfat->disk_bitmap_size = DIV_ROUND_UP(exfat->clus_count, 8); - if (exfat_read(exfat->blk_dev->dev_fd, - exfat->alloc_bitmap, alloc_bitmap_size, - exfat_c2o(exfat, - le32_to_cpu(dentry->bitmap_start_clu))) != - alloc_bitmap_size) { - exfat_err("failed to read bitmap\n"); - free(exfat->alloc_bitmap); - exfat->alloc_bitmap = NULL; + exfat_bitmap_set_range(exfat, le64_to_cpu(dentry->bitmap_start_clu), + DIV_ROUND_UP(exfat->disk_bitmap_size, + EXFAT_CLUSTER_SIZE(exfat->bs))); + + exfat->disk_bitmap = (char *)malloc( + EXFAT_BITMAP_SIZE(exfat->clus_count)); + if (!exfat->disk_bitmap) + return false; + if (exfat_read(exfat->blk_dev->dev_fd, exfat->disk_bitmap, + exfat->disk_bitmap_size, + exfat_c2o(exfat, exfat->disk_bitmap_clus)) != + (ssize_t)exfat->disk_bitmap_size) return false; - } return true; } @@ -904,6 +918,10 @@ static bool read_upcase_table(struct exfat_de_iter *iter) return false; } + exfat_bitmap_set_range(exfat, le32_to_cpu(dentry->upcase_start_clu), + DIV_ROUND_UP(le64_to_cpu(dentry->upcase_size), + EXFAT_CLUSTER_SIZE(exfat->bs))); + free(upcase); return true; } @@ -960,7 +978,7 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) } break; case EXFAT_BITMAP: - if (!read_alloc_bitmap(de_iter)) { + if (!read_bitmap(de_iter)) { exfat_err( "failed to verify allocation bitmap\n"); ret = -EINVAL; @@ -1050,6 +1068,15 @@ static bool exfat_root_dir_check(struct exfat *exfat) clus_t clus_count; int i; + /* TODO: bitmap could be very large. */ + exfat->clus_count = le32_to_cpu(exfat->bs->bsx.clu_count); + exfat->alloc_bitmap = (char *)calloc(1, + EXFAT_BITMAP_SIZE(exfat->clus_count)); + if (!exfat->alloc_bitmap) { + exfat_err("failed to allocate bitmap\n"); + return false; + } + exfat->clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); exfat->sect_size = EXFAT_SECTOR_SIZE(exfat->bs); diff --git a/fsck/fsck.h b/fsck/fsck.h index 5f4d17f..5a40fa1 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -61,12 +61,15 @@ struct exfat { 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 */ - __u32 *alloc_bitmap; - __u64 bit_count; + 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 + \ -- cgit v1.2.3 From cc41ce92b43ef273459568ffe832a5d44e815ec1 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 16:14:18 +0900 Subject: fsck: type casting for EXFAT_BITMAP_SET/GET This type casting is needed because of declaring bitmap as pointer to char. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 5b8fd45..69c0c26 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -38,9 +38,10 @@ typedef __u32 bitmap_t; #define EXFAT_BITMAP_SIZE(__c_count) \ (DIV_ROUND_UP(__c_count, BITS_PER) * sizeof(bitmap_t)) #define EXFAT_BITMAP_GET(__bmap, __c) \ - ((__bmap)[BIT_ENTRY(__c)] & BIT_MASK(__c)) + (((bitmap_t *)(__bmap))[BIT_ENTRY(__c)] & BIT_MASK(__c)) #define EXFAT_BITMAP_SET(__bmap, __c) \ - ((__bmap)[BIT_ENTRY(__c)] |= BIT_MASK(__c)) + (((bitmap_t *)(__bmap))[BIT_ENTRY(__c)] |= \ + BIT_MASK(__c)) #define FSCK_EXIT_NO_ERRORS 0x00 #define FSCK_EXIT_CORRECTED 0x01 -- cgit v1.2.3 From 91750240f23660b5b29ebdb07ec74759eed1512b Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 1 Jun 2020 16:22:20 +0900 Subject: exfatprogs: fix invalid utf-16 sequence in exfat_utf16_dec A null character should be decoded to a multi-byte character Signed-off-by: Hyunchul Lee --- lib/libexfat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/libexfat.c b/lib/libexfat.c index f5bc5c0..563cbf8 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -279,7 +279,7 @@ ssize_t exfat_utf16_dec(const __u16 *in_str, size_t in_len, 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++) { + 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 @@ -308,7 +308,7 @@ ssize_t exfat_utf16_dec(const __u16 *in_str, size_t in_len, free(wcs); /* Last iteration of above loop should have produced null byte */ - if (c_len == 0 || out_str[out_len] != 0) { + if (c_len == 0 || out_str[out_len-1] != 0) { exfat_err("invalid UTF-16 sequence\n"); return -errno; } -- cgit v1.2.3 From e2b384d6b135497b070aa1af0e21edcb1b83d791 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 08:48:44 +0900 Subject: exfatprogs: move utf16_len function to libexfat.c Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 14 +++----------- include/libexfat.h | 1 + lib/libexfat.c | 9 +++++++++ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 69c0c26..5148773 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -225,15 +225,6 @@ static void exfat_free_dir_list(struct exfat *exfat) } } -static size_t 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; -} - /* * get references of ancestors that include @child until the count of * ancesters is not larger than @count and the count of characters of @@ -255,7 +246,7 @@ bool get_ancestors(struct exfat_inode *child, dir = child; while (dir) { - name_len = utf16_len(dir->name, NAME_BUFFER_SIZE); + name_len = exfat_utf16_len(dir->name, NAME_BUFFER_SIZE); if (char_len + name_len > max_char_len) break; @@ -294,7 +285,8 @@ static int resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child) utf16_path = ctx->utf16_path; for (i = 0; i < depth; i++) { - name_len = utf16_len(ctx->ancestors[i]->name, NAME_BUFFER_SIZE); + name_len = exfat_utf16_len(ctx->ancestors[i]->name, + NAME_BUFFER_SIZE); memcpy((char *)utf16_path, (char *)ctx->ancestors[i]->name, name_len * 2); utf16_path += name_len; diff --git a/include/libexfat.h b/include/libexfat.h index 56053b4..601eab4 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -79,6 +79,7 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, 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); diff --git a/lib/libexfat.c b/lib/libexfat.c index 563cbf8..cc840ec 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -195,6 +195,15 @@ 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; -- cgit v1.2.3 From 383b9ae81e0caceff3f2a64a586cc7ad61a94221 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 08:59:05 +0900 Subject: fsck: replace exfat_invalid_clus with heap_clus Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 5148773..f49e3cd 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -328,10 +328,10 @@ static int resolve_path_parent(struct path_resolve_ctx *ctx, ##__VA_ARGS__); \ }) -static bool exfat_invalid_clus(struct exfat *exfat, clus_t clus) +static inline bool heap_clus(struct exfat *exfat, clus_t clus) { - return clus < EXFAT_FIRST_CLUSTER || - (clus - EXFAT_FIRST_CLUSTER) > le32_to_cpu(exfat->bs->bsx.clu_count); + return clus >= EXFAT_FIRST_CLUSTER && + (clus - EXFAT_FIRST_CLUSTER) < exfat->clus_count; } int inode_get_clus_next(struct exfat *exfat, struct exfat_inode *node, @@ -339,7 +339,7 @@ int inode_get_clus_next(struct exfat *exfat, struct exfat_inode *node, { off_t offset; - if (exfat_invalid_clus(exfat, clus)) + if (!heap_clus(exfat, clus)) return -EINVAL; if (node->is_contiguous) { @@ -367,7 +367,7 @@ static bool inode_check_clus_chain(struct exfat *exfat, struct exfat_inode *node clus_count = DIV_ROUND_UP(node->size, EXFAT_CLUSTER_SIZE(exfat->bs)); while (clus_count--) { - if (exfat_invalid_clus(exfat, clus)) { + if (!heap_clus(exfat, clus)) { exfat_err("bad cluster. 0x%x\n", clus); return false; } @@ -399,7 +399,7 @@ static bool inode_get_clus_count(struct exfat *exfat, struct exfat_inode *node, *clus_count = 0; do { - if (exfat_invalid_clus(exfat, clus)) { + if (!heap_clus(exfat, clus)) { exfat_err("bad cluster. 0x%x\n", clus); return false; } @@ -562,6 +562,10 @@ static bool exfat_boot_region_check(struct exfat *exfat) goto err; } + exfat->clus_count = le32_to_cpu(exfat->bs->bsx.clu_count); + exfat->clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); + exfat->sect_size = EXFAT_SECTOR_SIZE(exfat->bs); + return true; err: free(bs); @@ -618,7 +622,7 @@ static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) ret = false; } - if (node->size > 0 && exfat_invalid_clus(exfat, node->first_clus)) { + if (node->size > 0 && !heap_clus(exfat, node->first_clus)) { resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("first cluster %#x is invalid: %s\n", node->first_clus, path_resolve_ctx.local_path); @@ -804,8 +808,8 @@ static void exfat_bitmap_set_range(struct exfat *exfat, { clus_t clus; - if (exfat_invalid_clus(exfat, start_clus) || - exfat_invalid_clus(exfat, start_clus + count)) + if (!heap_clus(exfat, start_clus) || + !heap_clus(exfat, start_clus + count)) return; clus = start_clus; @@ -835,7 +839,7 @@ static bool read_bitmap(struct exfat_de_iter *iter) le64_to_cpu(dentry->bitmap_size)); return false; } - if (exfat_invalid_clus(exfat, le32_to_cpu(dentry->bitmap_start_clu))) { + if (!heap_clus(exfat, le32_to_cpu(dentry->bitmap_start_clu))) { exfat_err("invalid start cluster of allocate bitmap. 0x%x\n", le32_to_cpu(dentry->bitmap_start_clu)); return false; @@ -874,7 +878,7 @@ static bool read_upcase_table(struct exfat_de_iter *iter) if (exfat_de_iter_get(iter, 0, &dentry)) return false; - if (exfat_invalid_clus(exfat, le32_to_cpu(dentry->upcase_start_clu))) { + if (!heap_clus(exfat, le32_to_cpu(dentry->upcase_start_clu))) { exfat_err("invalid start cluster of upcase table. 0x%x\n", le32_to_cpu(dentry->upcase_start_clu)); return false; @@ -1062,7 +1066,6 @@ static bool exfat_root_dir_check(struct exfat *exfat) int i; /* TODO: bitmap could be very large. */ - exfat->clus_count = le32_to_cpu(exfat->bs->bsx.clu_count); exfat->alloc_bitmap = (char *)calloc(1, EXFAT_BITMAP_SIZE(exfat->clus_count)); if (!exfat->alloc_bitmap) { @@ -1070,9 +1073,6 @@ static bool exfat_root_dir_check(struct exfat *exfat) return false; } - exfat->clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); - exfat->sect_size = EXFAT_SECTOR_SIZE(exfat->bs); - /* allocate cluster buffers */ for (i = 0; i < 2; i++) { exfat->buffer_desc[i].buffer = -- cgit v1.2.3 From a0fa02a4d67e64254ffa78a282d443e6f59429d0 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 09:33:27 +0900 Subject: fsck: check cluster are already allocated in root_get_clus_count Signed-off-by: Hyunchul Lee --- fsck/de_iter.c | 2 +- fsck/fsck.c | 33 ++++++++++++++++++++++----------- fsck/fsck.h | 2 +- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/fsck/de_iter.c b/fsck/de_iter.c index 2573550..f0358f0 100644 --- a/fsck/de_iter.c +++ b/fsck/de_iter.c @@ -45,7 +45,7 @@ static ssize_t read_next_clus(struct exfat_de_iter *iter, clus_t l_clus) return -EIO; if (l_clus > 0) { - ret = inode_get_clus_next(exfat, iter->parent, + ret = get_next_clus(exfat, iter->parent, iter->buffer_desc[(l_clus - 1) & 0x01].p_clus, &desc->p_clus); if (ret) diff --git a/fsck/fsck.c b/fsck/fsck.c index f49e3cd..dfad796 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -334,11 +334,13 @@ static inline bool heap_clus(struct exfat *exfat, clus_t clus) (clus - EXFAT_FIRST_CLUSTER) < exfat->clus_count; } -int inode_get_clus_next(struct exfat *exfat, struct exfat_inode *node, +int get_next_clus(struct exfat *exfat, struct exfat_inode *node, clus_t clus, clus_t *next) { off_t offset; + *next = EXFAT_EOF_CLUSTER; + if (!heap_clus(exfat, clus)) return -EINVAL; @@ -358,7 +360,7 @@ int inode_get_clus_next(struct exfat *exfat, struct exfat_inode *node, return 0; } -static bool inode_check_clus_chain(struct exfat *exfat, struct exfat_inode *node) +static bool check_clus_chain(struct exfat *exfat, struct exfat_inode *node) { clus_t clus; clus_t clus_count; @@ -380,7 +382,7 @@ static bool inode_check_clus_chain(struct exfat *exfat, struct exfat_inode *node return false; } - if (inode_get_clus_next(exfat, node, clus, &clus) != 0) { + if (get_next_clus(exfat, node, clus, &clus) != 0) { exfat_err( "broken cluster chain. (previous cluster 0x%x)\n", clus); @@ -390,7 +392,7 @@ static bool inode_check_clus_chain(struct exfat *exfat, struct exfat_inode *node return true; } -static bool inode_get_clus_count(struct exfat *exfat, struct exfat_inode *node, +static bool root_get_clus_count(struct exfat *exfat, struct exfat_inode *node, clus_t *clus_count) { clus_t clus; @@ -400,14 +402,23 @@ static bool inode_get_clus_count(struct exfat *exfat, struct exfat_inode *node, do { if (!heap_clus(exfat, clus)) { - exfat_err("bad cluster. 0x%x\n", clus); + exfat_err("/: bad cluster. 0x%x\n", clus); return false; } - if (inode_get_clus_next(exfat, node, clus, &clus) != 0) { - exfat_err( - "broken cluster chain. (previous cluster 0x%x)\n", - clus); + if (EXFAT_BITMAP_GET(exfat->alloc_bitmap, + clus - EXFAT_FIRST_CLUSTER)) { + resolve_path(&path_resolve_ctx, node); + exfat_err("/: cluster is already allocated, or " + "there is a loop in cluster chain\n"); + return false; + } + + EXFAT_BITMAP_SET(exfat->alloc_bitmap, + clus - EXFAT_FIRST_CLUSTER); + + if (get_next_clus(exfat, node, clus, &clus) != 0) { + exfat_err("/: broken cluster chain\n"); return false; } @@ -653,7 +664,7 @@ static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) ret = false; } - if (!node->is_contiguous && !inode_check_clus_chain(exfat, node)) { + if (!node->is_contiguous && !check_clus_chain(exfat, node)) { resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("corrupted cluster chain: %s\n", path_resolve_ctx.local_path); @@ -1093,7 +1104,7 @@ static bool exfat_root_dir_check(struct exfat *exfat) } root->first_clus = le32_to_cpu(exfat->bs->bsx.root_cluster); - if (!inode_get_clus_count(exfat, root, &clus_count)) { + if (!root_get_clus_count(exfat, root, &clus_count)) { exfat_err("failed to follow the cluster chain of root\n"); goto err; } diff --git a/fsck/fsck.h b/fsck/fsck.h index 5a40fa1..3e7f2e5 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -78,7 +78,7 @@ struct exfat { /* fsck.c */ off_t exfat_c2o(struct exfat *exfat, unsigned int clus); -int inode_get_clus_next(struct exfat *exfat, struct exfat_inode *node, +int get_next_clus(struct exfat *exfat, struct exfat_inode *node, clus_t clus, clus_t *next); /* de_iter.c */ -- cgit v1.2.3 From 8419ee924d8c128c97afcf9f75d01daf76b6954f Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 09:46:41 +0900 Subject: fsck: repair: cluster not included in Cluster Heap While checking the cluster chain of a file, if fsck finds the cluster not included in Cluster Heap, it sets EOF and decrement the file size. Currently make this feature disabled. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++------------ fsck/repair.c | 5 ++- fsck/repair.h | 1 + 3 files changed, 110 insertions(+), 28 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index dfad796..85b9ef5 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -360,36 +360,118 @@ int get_next_clus(struct exfat *exfat, struct exfat_inode *node, return 0; } -static bool check_clus_chain(struct exfat *exfat, struct exfat_inode *node) +static int set_fat(struct exfat *exfat, clus_t clus, clus_t next_clus) { - clus_t clus; - clus_t clus_count; + off_t offset; + + offset = le32_to_cpu(exfat->bs->bsx.fat_offset) << + exfat->bs->bsx.sect_size_bits; + offset += sizeof(clus_t) * clus; + + if (exfat_write(exfat->blk_dev->dev_fd, &next_clus, sizeof(next_clus), + offset) != sizeof(next_clus)) + return -EIO; + return 0; +} + +static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) +{ + struct exfat_dentry *stream_de; + clus_t clus, prev, next; + clus_t count, max_count; clus = node->first_clus; - clus_count = DIV_ROUND_UP(node->size, EXFAT_CLUSTER_SIZE(exfat->bs)); + prev = EXFAT_EOF_CLUSTER; + count = 0; + max_count = DIV_ROUND_UP(node->size, exfat->clus_size); - while (clus_count--) { - if (!heap_clus(exfat, clus)) { - exfat_err("bad cluster. 0x%x\n", clus); - return false; + if (node->size == 0 && node->first_clus == EXFAT_FREE_CLUSTER) + return 0; + + /* the first cluster is wrong */ + if ((node->size == 0 && node->first_clus != EXFAT_FREE_CLUSTER) || + (node->size > 0 && !heap_clus(exfat, node->first_clus))) { + return -EINVAL; + } + + while (clus != EXFAT_EOF_CLUSTER) { + if (count >= max_count) { + if (node->is_contiguous) + break; + return -EINVAL; } - if (!EXFAT_BITMAP_GET(exfat->alloc_bitmap, - clus - EXFAT_FIRST_CLUSTER)) { - exfat_err( - "cluster allocated, but not in bitmap. 0x%x\n", - clus); - return false; + /* + * This cluster is already allocated. it may be shared with + * the other file, or there is a loop in cluster chain. + */ + if (EXFAT_BITMAP_GET(exfat->alloc_bitmap, + clus - EXFAT_FIRST_CLUSTER)) { + return -EINVAL; } - if (get_next_clus(exfat, node, clus, &clus) != 0) { - exfat_err( - "broken cluster chain. (previous cluster 0x%x)\n", - clus); - return false; + /* This cluster is allocated or not */ + if (get_next_clus(exfat, node, clus, &next)) + goto truncate_file; + if (!node->is_contiguous) { + if (!heap_clus(exfat, next) && + next != EXFAT_EOF_CLUSTER) { + if (repair_file_ask(&exfat->de_iter, node, + ER_FILE_INVALID_CLUS, + "broken cluster chain. " + "truncate to %u bytes", + count * + EXFAT_CLUSTER_SIZE(exfat->bs))) + goto truncate_file; + + else + return -EINVAL; + } + } else { + if (!EXFAT_BITMAP_GET(exfat->disk_bitmap, + clus - EXFAT_FIRST_CLUSTER)) { + if (repair_file_ask(&exfat->de_iter, node, + ER_FILE_INVALID_CLUS, + "cluster is marked as free. " + "truncate to %u bytes", + count * + EXFAT_CLUSTER_SIZE(exfat->bs))) + goto truncate_file; + + else + return -EINVAL; + } } + + count++; + EXFAT_BITMAP_SET(exfat->alloc_bitmap, + clus - EXFAT_FIRST_CLUSTER); + prev = clus; + clus = next; } - return true; + + return 0; +truncate_file: + node->size = count * EXFAT_CLUSTER_SIZE(exfat->bs); + if (!heap_clus(exfat, prev)) + node->first_clus = EXFAT_FREE_CLUSTER; + + exfat_de_iter_get_dirty(&exfat->de_iter, 1, &stream_de); + if (count * EXFAT_CLUSTER_SIZE(exfat->bs) < + le64_to_cpu(stream_de->stream_valid_size)) + stream_de->stream_valid_size = cpu_to_le64( + count * EXFAT_CLUSTER_SIZE(exfat->bs)); + if (!heap_clus(exfat, prev)) + stream_de->stream_start_clu = EXFAT_FREE_CLUSTER; + stream_de->stream_size = cpu_to_le64( + count * EXFAT_CLUSTER_SIZE(exfat->bs)); + + /* remaining clusters will be freed while FAT is compared with + * alloc_bitmap. + */ + if (!node->is_contiguous && heap_clus(exfat, prev)) + return set_fat(exfat, prev, EXFAT_EOF_CLUSTER); + return 0; } static bool root_get_clus_count(struct exfat *exfat, struct exfat_inode *node, @@ -640,6 +722,9 @@ static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) ret = false; } + if (check_clus_chain(exfat, node)) + return false; + if (node->size > le32_to_cpu(exfat->bs->bsx.clu_count) * EXFAT_CLUSTER_SIZE(exfat->bs)) { resolve_path_parent(&path_resolve_ctx, iter->parent, node); @@ -664,13 +749,6 @@ static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) ret = false; } - if (!node->is_contiguous && !check_clus_chain(exfat, node)) { - resolve_path_parent(&path_resolve_ctx, iter->parent, node); - exfat_err("corrupted cluster chain: %s\n", - path_resolve_ctx.local_path); - ret = false; - } - checksum = file_calc_checksum(iter); exfat_de_iter_get(iter, 0, &dentry); if (checksum != le16_to_cpu(dentry->file_checksum)) { diff --git a/fsck/repair.c b/fsck/repair.c index 83749cf..56c0d22 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -20,6 +20,7 @@ struct exfat_repair_problem { /* Problem flags */ #define ERF_PREEN_YES 0x00000001 #define ERF_DEFAULT_YES 0x00000002 +#define ERF_DEFAULT_NO 0x00000004 /* Prompt types */ #define ERP_FIX 0x00000001 @@ -35,6 +36,7 @@ static struct exfat_repair_problem problems[] = { {ER_BS_CHECKSUM, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, {ER_DE_CHECKSUM, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, {ER_FILE_VALID_SIZE, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, + {ER_FILE_INVALID_CLUS, ERF_DEFAULT_NO, ERP_TRUNCATE}, }; static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) @@ -54,7 +56,8 @@ 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) + 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) diff --git a/fsck/repair.h b/fsck/repair.h index f6d14ee..5957663 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -8,6 +8,7 @@ #define ER_BS_CHECKSUM 0x00000001 #define ER_DE_CHECKSUM 0x00001001 #define ER_FILE_VALID_SIZE 0x00002001 +#define ER_FILE_INVALID_CLUS 0x00002002 typedef unsigned int er_problem_code_t; -- cgit v1.2.3 From 2488e1f50abc1691c661c26be9c89d85b49612f0 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 10:56:59 +0900 Subject: fsck: repair: reclaim free clusters if fsck finds clusters which are marked as allocated but actually not, it make these clusters free. Currently make this feature disabled. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index 85b9ef5..8977746 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1100,6 +1100,127 @@ err: return ret; } +static int write_dirty_fat(struct exfat *exfat) +{ + struct buffer_desc *bd; + off_t offset; + ssize_t len; + size_t read_size, write_size; + clus_t clus, last_clus, clus_count, i; + unsigned int idx; + + clus = 0; + last_clus = le32_to_cpu(exfat->bs->bsx.clu_count) + 2; + bd = exfat->buffer_desc; + idx = 0; + offset = le32_to_cpu(exfat->bs->bsx.fat_offset) * + exfat->sect_size; + read_size = exfat->clus_size; + write_size = exfat->sect_size; + + while (clus < last_clus) { + clus_count = MIN(read_size / sizeof(clus_t), last_clus - clus); + len = exfat_read(exfat->blk_dev->dev_fd, bd[idx].buffer, + clus_count * sizeof(clus_t), offset); + if (len != (ssize_t)(sizeof(clus_t) * clus_count)) { + exfat_err("failed to read fat entries, %zd\n", len); + return -EIO; + } + + /* TODO: read ahead */ + + for (i = clus ? clus : EXFAT_FIRST_CLUSTER; + i < clus + clus_count; i++) { + if (!EXFAT_BITMAP_GET(exfat->alloc_bitmap, + i - EXFAT_FIRST_CLUSTER) && + ((clus_t *)bd[idx].buffer)[i - clus] != + EXFAT_FREE_CLUSTER) { + ((clus_t *)bd[idx].buffer)[i - clus] = + EXFAT_FREE_CLUSTER; + bd[idx].dirty[(i - clus) / + (write_size / sizeof(clus_t))] = true; + } + } + + for (i = 0; i < read_size; i += write_size) { + if (bd[idx].dirty[i / write_size]) { + if (exfat_write(exfat->blk_dev->dev_fd, + &bd[idx].buffer[i], write_size, + offset + i) != + (ssize_t)write_size) { + exfat_err("failed to write " + "fat entries\n"); + return -EIO; + + } + bd[idx].dirty[i / write_size] = false; + } + } + + idx ^= 0x01; + clus = clus + clus_count; + offset += len; + } + return 0; +} + +static int write_dirty_bitmap(struct exfat *exfat) +{ + struct buffer_desc *bd; + off_t offset, last_offset, bitmap_offset; + ssize_t len; + ssize_t read_size, write_size, i, size; + int idx; + + offset = exfat_c2o(exfat, exfat->disk_bitmap_clus); + last_offset = offset + exfat->disk_bitmap_size; + bitmap_offset = 0; + read_size = exfat->clus_size; + write_size = exfat->sect_size; + + bd = exfat->buffer_desc; + idx = 0; + + while (offset < last_offset) { + len = MIN(read_size, last_offset - offset); + if (exfat_read(exfat->blk_dev->dev_fd, bd[idx].buffer, + len, offset) != (ssize_t)len) + return -EIO; + + /* TODO: read-ahead */ + + for (i = 0; i < len; i += write_size) { + size = MIN(write_size, len - i); + if (memcmp(&bd[idx].buffer[i], + exfat->alloc_bitmap + bitmap_offset + i, + size)) { + if (exfat_write(exfat->blk_dev->dev_fd, + exfat->alloc_bitmap + bitmap_offset + i, + size, offset + i) != size) + return -EIO; + } + } + + idx ^= 0x01; + offset += len; + bitmap_offset += len; + } + return 0; +} + +static int reclaim_free_clusters(struct exfat *exfat) +{ + if (write_dirty_fat(exfat)) { + exfat_err("failed to write fat entries\n"); + return -EIO; + } + if (write_dirty_bitmap(exfat)) { + exfat_err("failed to write bitmap\n"); + return -EIO; + } + return 0; +} + /* * for each directory in @dir_list. * 1. read all dentries and allocate exfat_nodes for files and directories. @@ -1145,6 +1266,9 @@ static bool exfat_filesystem_check(struct exfat *exfat) out: exfat_free_dir_list(exfat); exfat->root = NULL; + if (exfat->dirty_fat) + if (reclaim_free_clusters(exfat)) + return false; return ret; } -- cgit v1.2.3 From 6fb7bee8b0e33930f7159cadc1b3c476605c8fc3 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 10:27:30 +0900 Subject: fsck: repair: the first cluster is wrong if the file size is equal to 0 but the first cluster is not free, and if the size is greater than 0 but the first cluster is free, fsck sets the size to 0 and the first cluster to free. Currently make this feature disabled. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 20 +++++--------------- fsck/repair.c | 1 + fsck/repair.h | 1 + 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 8977746..273c716 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -391,7 +391,11 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) /* the first cluster is wrong */ if ((node->size == 0 && node->first_clus != EXFAT_FREE_CLUSTER) || (node->size > 0 && !heap_clus(exfat, node->first_clus))) { - return -EINVAL; + if (repair_file_ask(&exfat->de_iter, node, + ER_FILE_FIRST_CLUS, "first cluster is wrong")) + goto truncate_file; + else + return -EINVAL; } while (clus != EXFAT_EOF_CLUSTER) { @@ -708,20 +712,6 @@ static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) bool ret = true; uint16_t checksum; - if (node->size == 0 && node->first_clus != EXFAT_FREE_CLUSTER) { - resolve_path_parent(&path_resolve_ctx, iter->parent, node); - exfat_err("file is empty, but first cluster is %#x: %s\n", - node->first_clus, path_resolve_ctx.local_path); - ret = false; - } - - if (node->size > 0 && !heap_clus(exfat, node->first_clus)) { - resolve_path_parent(&path_resolve_ctx, iter->parent, node); - exfat_err("first cluster %#x is invalid: %s\n", - node->first_clus, path_resolve_ctx.local_path); - ret = false; - } - if (check_clus_chain(exfat, node)) return false; diff --git a/fsck/repair.c b/fsck/repair.c index 56c0d22..de87a05 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -37,6 +37,7 @@ static struct exfat_repair_problem problems[] = { {ER_DE_CHECKSUM, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, {ER_FILE_VALID_SIZE, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, {ER_FILE_INVALID_CLUS, ERF_DEFAULT_NO, ERP_TRUNCATE}, + {ER_FILE_FIRST_CLUS, ERF_DEFAULT_NO, ERP_TRUNCATE}, }; static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) diff --git a/fsck/repair.h b/fsck/repair.h index 5957663..7169d24 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -9,6 +9,7 @@ #define ER_DE_CHECKSUM 0x00001001 #define ER_FILE_VALID_SIZE 0x00002001 #define ER_FILE_INVALID_CLUS 0x00002002 +#define ER_FILE_FIRST_CLUS 0x00002003 typedef unsigned int er_problem_code_t; -- cgit v1.2.3 From d82135722a5c5ac20ac7c8905d91c3d4245fb10a Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 10:47:57 +0900 Subject: fsck: repair: more cluster are allocated for a file if the total size of allocated clusters is greater than the file size, fsck sets EOF and frees the remaining clusters. Currnetly make this feature disabled. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 9 ++++++++- fsck/repair.c | 1 + fsck/repair.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 273c716..3457b19 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -402,7 +402,14 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) if (count >= max_count) { if (node->is_contiguous) break; - return -EINVAL; + if (repair_file_ask(&exfat->de_iter, node, + ER_FILE_SMALLER_SIZE, + "more clusters are allocated. " + "truncate to %u bytes", + count * EXFAT_CLUSTER_SIZE(exfat->bs))) + goto truncate_file; + else + return -EINVAL; } /* diff --git a/fsck/repair.c b/fsck/repair.c index de87a05..b0b8709 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -38,6 +38,7 @@ static struct exfat_repair_problem problems[] = { {ER_FILE_VALID_SIZE, ERF_DEFAULT_YES | 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}, }; static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) diff --git a/fsck/repair.h b/fsck/repair.h index 7169d24..eba4ea5 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -10,6 +10,7 @@ #define ER_FILE_VALID_SIZE 0x00002001 #define ER_FILE_INVALID_CLUS 0x00002002 #define ER_FILE_FIRST_CLUS 0x00002003 +#define ER_FILE_SMALLER_SIZE 0x00002004 typedef unsigned int er_problem_code_t; -- cgit v1.2.3 From 62601b53ec261eb13fb1ade852d99e644dfcbe33 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 11:06:16 +0900 Subject: fsck: repair: clusters allocated already Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 9 ++++++++- fsck/repair.c | 1 + fsck/repair.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 3457b19..05fa088 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -418,7 +418,14 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) */ if (EXFAT_BITMAP_GET(exfat->alloc_bitmap, clus - EXFAT_FIRST_CLUSTER)) { - return -EINVAL; + if (repair_file_ask(&exfat->de_iter, node, + ER_FILE_DUPLICATED_CLUS, + "cluster is already allocated for " + "the other file. truncated to %u bytes", + count * EXFAT_CLUSTER_SIZE(exfat->bs))) + goto truncate_file; + else + return -EINVAL; } /* This cluster is allocated or not */ diff --git a/fsck/repair.c b/fsck/repair.c index b0b8709..f430de5 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -39,6 +39,7 @@ static struct exfat_repair_problem problems[] = { {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_DUPLICATED_CLUS, ERF_DEFAULT_NO, ERP_TRUNCATE}, }; static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) diff --git a/fsck/repair.h b/fsck/repair.h index eba4ea5..a84a1ef 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -11,6 +11,7 @@ #define ER_FILE_INVALID_CLUS 0x00002002 #define ER_FILE_FIRST_CLUS 0x00002003 #define ER_FILE_SMALLER_SIZE 0x00002004 +#define ER_FILE_DUPLICATED_CLUS 0x00002006 typedef unsigned int er_problem_code_t; -- cgit v1.2.3 From 5d29cc9888b2e9a8e9ac1aadbf6a47ed16dcfcc0 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 12:30:02 +0900 Subject: fsck: repair: less clusters are allocated if the total size of allocated clusters is less than the file size, fsck decrements the size. Currently make this feature disabled. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 10 ++++++++++ fsck/repair.c | 1 + fsck/repair.h | 1 + 3 files changed, 12 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index 05fa088..7b7d6de 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -468,6 +468,16 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) clus = next; } + if (count < max_count) { + if (repair_file_ask(&exfat->de_iter, node, + ER_FILE_LARGER_SIZE, "less clusters are allocated. " + "truncates to %u bytes", + count * EXFAT_CLUSTER_SIZE(exfat->bs))) + goto truncate_file; + else + return -EINVAL; + } + return 0; truncate_file: node->size = count * EXFAT_CLUSTER_SIZE(exfat->bs); diff --git a/fsck/repair.c b/fsck/repair.c index f430de5..1440ef8 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -39,6 +39,7 @@ static struct exfat_repair_problem problems[] = { {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}, }; diff --git a/fsck/repair.h b/fsck/repair.h index a84a1ef..781736a 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -11,6 +11,7 @@ #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 typedef unsigned int er_problem_code_t; -- cgit v1.2.3 From 10136210199493f29efbc5adfacc57e227725a36 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 13:46:42 +0900 Subject: fsck: return -EINVAL if file dentries are corrupted Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 7b7d6de..d0e41fa 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -869,7 +869,7 @@ static int read_file(struct exfat_de_iter *de_iter, if (!ret) { exfat_err("corrupted file directory entries.\n"); free_exfat_inode(node); - return ret; + return -EINVAL; } node->dentry_file_offset = exfat_de_iter_file_offset(de_iter); -- cgit v1.2.3 From 880f8b23da09922509bab747050300ea112c0bdc Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 2 Jun 2020 14:06:04 +0900 Subject: fsck: add test for broken cluster chain and invalid size This test has the following corrupted files. * zero-byte file of which the first cluster is wrong. * file which has an invalid cluster number in its cluster chain. * file which has a cluster that is already allocated to the other file. * files of which size are less or greater when compared with allocated clusters. Signed-off-by: Hyunchul Lee --- tests/file_invalid_clus/exfat.img.expected.xz | Bin 0 -> 4048 bytes tests/file_invalid_clus/exfat.img.xz | Bin 0 -> 4064 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/file_invalid_clus/exfat.img.expected.xz create mode 100644 tests/file_invalid_clus/exfat.img.xz diff --git a/tests/file_invalid_clus/exfat.img.expected.xz b/tests/file_invalid_clus/exfat.img.expected.xz new file mode 100644 index 0000000..08e992e Binary files /dev/null and b/tests/file_invalid_clus/exfat.img.expected.xz differ diff --git a/tests/file_invalid_clus/exfat.img.xz b/tests/file_invalid_clus/exfat.img.xz new file mode 100644 index 0000000..47097e3 Binary files /dev/null and b/tests/file_invalid_clus/exfat.img.xz differ -- cgit v1.2.3 From 671d643b902b90240547f158e383b85d58ce4d46 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 3 Jun 2020 09:47:37 +0900 Subject: fsck: repair: set/clear VolumeDirty flag Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 57 +++++++++++++++++++++++++++++++++++++++++++++------------ fsck/fsck.h | 3 ++- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index d0e41fa..03075af 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -614,6 +614,33 @@ out_write: return 0; } +static int exfat_mark_volume_dirty(struct exfat *exfat, bool dirty) +{ + uint16_t flags; + + if (!(exfat->options & FSCK_OPTS_REPAIR_WRITE)) + return 0; + + flags = le16_to_cpu(exfat->bs->bsx.vol_flags); + if (dirty) + flags |= 0x02; + else + flags &= ~0x02; + + exfat->bs->bsx.vol_flags = cpu_to_le16(flags); + if (exfat_write(exfat->blk_dev->dev_fd, exfat->bs, + sizeof(struct pbr), 0) != (ssize_t)sizeof(struct pbr)) { + exfat_err("failed to set VolumeDirty\n"); + return -EIO; + } + + if (fsync(exfat->blk_dev->dev_fd) != 0) { + exfat_err("failed to set VolumeDirty\n"); + return -EIO; + } + return 0; +} + static bool exfat_boot_region_check(struct exfat *exfat) { struct pbr *bs; @@ -649,13 +676,6 @@ static bool exfat_boot_region_check(struct exfat *exfat) goto err; } - ret = boot_region_checksum(exfat); - if (ret) { - exfat_err("failed to verify the checksum of a boot region. %zd\n", - ret); - goto err; - } - if (bs->bsx.fs_version[1] != 1 || bs->bsx.fs_version[0] != 0) { exfat_err("unsupported exfat version: %d.%d\n", bs->bsx.fs_version[1], bs->bsx.fs_version[0]); @@ -683,10 +703,21 @@ static bool exfat_boot_region_check(struct exfat *exfat) goto err; } + if (exfat_mark_volume_dirty(exfat, true)) { + exfat_err("failed to set VolumeDirty\n"); + goto err; + } + + ret = boot_region_checksum(exfat); + if (ret) { + exfat_err("failed to verify the checksum of a boot region. %zd\n", + ret); + goto err; + } + exfat->clus_count = le32_to_cpu(exfat->bs->bsx.clu_count); exfat->clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); exfat->sect_size = EXFAT_SECTOR_SIZE(exfat->bs); - return true; err: free(bs); @@ -1379,25 +1410,25 @@ int main(int argc, char * const argv[]) while ((c = getopt_long(argc, argv, "rynpVvh", opts, NULL)) != EOF) { switch (c) { case 'n': - if (ui.options & FSCK_OPTS_REPAIR) + if (ui.options & FSCK_OPTS_REPAIR_ALL) usage(argv[0]); ui.options |= FSCK_OPTS_REPAIR_NO; ui.ei.writeable = false; break; case 'r': - if (ui.options & FSCK_OPTS_REPAIR) + if (ui.options & FSCK_OPTS_REPAIR_ALL) usage(argv[0]); ui.options |= FSCK_OPTS_REPAIR_ASK; ui.ei.writeable = true; break; case 'y': - if (ui.options & FSCK_OPTS_REPAIR) + if (ui.options & FSCK_OPTS_REPAIR_ALL) usage(argv[0]); ui.options |= FSCK_OPTS_REPAIR_YES; ui.ei.writeable = true; break; case 'p': - if (ui.options & FSCK_OPTS_REPAIR) + if (ui.options & FSCK_OPTS_REPAIR_ALL) usage(argv[0]); ui.options |= FSCK_OPTS_REPAIR_AUTO; ui.ei.writeable = true; @@ -1462,6 +1493,8 @@ int main(int argc, char * const argv[]) if (ui.ei.writeable) fsync(bd.dev_fd); + exfat_mark_volume_dirty(exfat, false); + printf("%s: clean\n", ui.ei.dev_name); if (exfat->dirty) ret = FSCK_EXIT_CORRECTED; diff --git a/fsck/fsck.h b/fsck/fsck.h index 3e7f2e5..40b7b1c 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -49,7 +49,8 @@ enum fsck_ui_options { FSCK_OPTS_REPAIR_YES = 0x02, FSCK_OPTS_REPAIR_NO = 0x04, FSCK_OPTS_REPAIR_AUTO = 0x08, - FSCK_OPTS_REPAIR = 0x0f, + FSCK_OPTS_REPAIR_WRITE = 0x0b, + FSCK_OPTS_REPAIR_ALL = 0x0f, }; struct exfat { -- cgit v1.2.3 From 18371fc7411191cbfdff62953941f34dbd577133 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 3 Jun 2020 10:36:24 +0900 Subject: fsck: change return value of exfat_boot_region_check instead of boolean, make this function return error codes. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 03075af..40ebb83 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -641,7 +641,7 @@ static int exfat_mark_volume_dirty(struct exfat *exfat, bool dirty) return 0; } -static bool exfat_boot_region_check(struct exfat *exfat) +static int exfat_boot_region_check(struct exfat *exfat) { struct pbr *bs; ssize_t ret; @@ -649,7 +649,7 @@ static bool exfat_boot_region_check(struct exfat *exfat) bs = (struct pbr *)malloc(sizeof(struct pbr)); if (!bs) { exfat_err("failed to allocate memory\n"); - return false; + return -ENOMEM; } exfat->bs = bs; @@ -657,9 +657,11 @@ static bool exfat_boot_region_check(struct exfat *exfat) ret = exfat_read(exfat->blk_dev->dev_fd, bs, sizeof(*bs), 0); if (ret != sizeof(*bs)) { exfat_err("failed to read a boot sector. %zd\n", ret); + ret = -EIO; goto err; } + ret = -EINVAL; if (memcmp(bs->bpb.oem_name, "EXFAT ", 8) != 0) { exfat_err("failed to find exfat file system.\n"); goto err; @@ -705,6 +707,7 @@ static bool exfat_boot_region_check(struct exfat *exfat) if (exfat_mark_volume_dirty(exfat, true)) { exfat_err("failed to set VolumeDirty\n"); + ret = -EIO; goto err; } @@ -718,11 +721,11 @@ static bool exfat_boot_region_check(struct exfat *exfat) exfat->clus_count = le32_to_cpu(exfat->bs->bsx.clu_count); exfat->clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); exfat->sect_size = EXFAT_SECTOR_SIZE(exfat->bs); - return true; + return 0; err: free(bs); exfat->bs = NULL; - return false; + return (int)ret; } static void dentry_calc_checksum(struct exfat_dentry *dentry, @@ -1392,10 +1395,10 @@ void exfat_show_stat(void) int main(int argc, char * const argv[]) { - int c, ret; struct fsck_user_input ui; struct exfat_blk_dev bd; struct exfat *exfat = NULL; + int c, ret, exit_code; bool version_only = false; memset(&ui, 0, sizeof(ui)); @@ -1463,15 +1466,15 @@ int main(int argc, char * const argv[]) exfat = alloc_exfat(&bd); if (!exfat) { - ret = FSCK_EXIT_OPERATION_ERROR; + ret = -ENOMEM; goto err; } exfat->options = ui.options; exfat_debug("verifying boot regions...\n"); - if (!exfat_boot_region_check(exfat)) { + ret = exfat_boot_region_check(exfat); + if (ret) { exfat_err("failed to verify boot regions.\n"); - ret = FSCK_EXIT_ERRORS_LEFT; goto err; } @@ -1480,30 +1483,36 @@ int main(int argc, char * const argv[]) exfat_debug("verifying root directory...\n"); if (!exfat_root_dir_check(exfat)) { exfat_err("failed to verify root directory.\n"); - ret = FSCK_EXIT_ERRORS_LEFT; + ret = -EINVAL; goto out; } exfat_debug("verifying directory entries...\n"); if (!exfat_filesystem_check(exfat)) { exfat_err("failed to verify directory entries.\n"); - ret = FSCK_EXIT_ERRORS_LEFT; + ret = -EINVAL; goto out; } - if (ui.ei.writeable) - fsync(bd.dev_fd); + if (ui.ei.writeable && fsync(bd.dev_fd)) { + ret = -EIO; + goto err; + } exfat_mark_volume_dirty(exfat, false); printf("%s: clean\n", ui.ei.dev_name); - if (exfat->dirty) - ret = FSCK_EXIT_CORRECTED; - else - ret = FSCK_EXIT_NO_ERRORS; out: exfat_show_stat(); err: + if (ret == -EINVAL) + exit_code = FSCK_EXIT_ERRORS_LEFT; + else if (ret) + exit_code = FSCK_EXIT_OPERATION_ERROR; + else if (exfat->dirty) + exit_code = FSCK_EXIT_CORRECTED; + else + exit_code = FSCK_EXIT_NO_ERRORS; free_exfat(exfat); close(bd.dev_fd); - return ret; + return exit_code; } -- cgit v1.2.3 From a9808ce0b7c5b420157cb30f049806b7a20dedfe Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 3 Jun 2020 10:59:56 +0900 Subject: fsck: change return value of exfat_filesystem_check Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 40ebb83..897e343 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1276,14 +1276,14 @@ static int reclaim_free_clusters(struct exfat *exfat) * 2. free all of file exfat_nodes. * 3. if the directory does not have children, free its exfat_node. */ -static bool exfat_filesystem_check(struct exfat *exfat) +static int exfat_filesystem_check(struct exfat *exfat) { struct exfat_inode *dir; - bool ret = true; + int ret = 0, dir_errors; if (!exfat->root) { exfat_err("root is NULL\n"); - return false; + return -ENOENT; } list_add(&exfat->root->list, &exfat->dir_list); @@ -1293,18 +1293,19 @@ static bool exfat_filesystem_check(struct exfat *exfat) if (!(dir->attr & ATTR_SUBDIR)) { resolve_path(&path_resolve_ctx, dir); - ret = false; exfat_err("failed to travel directories. " "the node is not directory: %s\n", path_resolve_ctx.local_path); + ret = -EINVAL; goto out; } - if (read_children(exfat, dir)) { + dir_errors = read_children(exfat, dir); + if (dir_errors) { resolve_path(&path_resolve_ctx, dir); - ret = false; exfat_err("failed to check dentries: %s\n", path_resolve_ctx.local_path); + ret = dir_errors; } list_del(&dir->list); @@ -1314,9 +1315,8 @@ static bool exfat_filesystem_check(struct exfat *exfat) out: exfat_free_dir_list(exfat); exfat->root = NULL; - if (exfat->dirty_fat) - if (reclaim_free_clusters(exfat)) - return false; + if (exfat->dirty_fat && reclaim_free_clusters(exfat)) + return -EIO; return ret; } @@ -1488,9 +1488,9 @@ int main(int argc, char * const argv[]) } exfat_debug("verifying directory entries...\n"); - if (!exfat_filesystem_check(exfat)) { + ret = exfat_filesystem_check(exfat); + if (ret) { exfat_err("failed to verify directory entries.\n"); - ret = -EINVAL; goto out; } -- cgit v1.2.3 From 1f08eb8fa9281b406b44d7068e4330563975b2c6 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 3 Jun 2020 11:00:43 +0900 Subject: fsck: change return value of exfat_root_dir_check Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 897e343..60260ce 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1320,7 +1320,7 @@ out: return ret; } -static bool exfat_root_dir_check(struct exfat *exfat) +static int exfat_root_dir_check(struct exfat *exfat) { struct exfat_inode *root; clus_t clus_count; @@ -1331,7 +1331,7 @@ static bool exfat_root_dir_check(struct exfat *exfat) EXFAT_BITMAP_SIZE(exfat->clus_count)); if (!exfat->alloc_bitmap) { exfat_err("failed to allocate bitmap\n"); - return false; + return -ENOMEM; } /* allocate cluster buffers */ @@ -1339,35 +1339,32 @@ static bool exfat_root_dir_check(struct exfat *exfat) exfat->buffer_desc[i].buffer = (char *)malloc(exfat->clus_size); if (!exfat->buffer_desc[i].buffer) - return false; + return -ENOMEM; exfat->buffer_desc[i].dirty = (char *)calloc( (exfat->clus_size / exfat->sect_size), 1); if (!exfat->buffer_desc[i].dirty) - return false; + return -ENOMEM; } root = alloc_exfat_inode(ATTR_SUBDIR); if (!root) { exfat_err("failed to allocate memory\n"); - return false; + return -ENOMEM; } root->first_clus = le32_to_cpu(exfat->bs->bsx.root_cluster); if (!root_get_clus_count(exfat, root, &clus_count)) { exfat_err("failed to follow the cluster chain of root\n"); - goto err; + free_exfat_inode(root); + return -EINVAL; } root->size = clus_count * EXFAT_CLUSTER_SIZE(exfat->bs); exfat->root = root; exfat_debug("root directory: start cluster[0x%x] size[0x%" PRIx64 "]\n", root->first_clus, root->size); - return true; -err: - free_exfat_inode(root); - exfat->root = NULL; - return false; + return 0; } void exfat_show_info(struct exfat *exfat) @@ -1481,9 +1478,9 @@ int main(int argc, char * const argv[]) exfat_show_info(exfat); exfat_debug("verifying root directory...\n"); - if (!exfat_root_dir_check(exfat)) { + ret = exfat_root_dir_check(exfat); + if (ret) { exfat_err("failed to verify root directory.\n"); - ret = -EINVAL; goto out; } -- cgit v1.2.3 From 616095fe4a825c0a26e23835314926fa40b63939 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 3 Jun 2020 14:49:13 +0900 Subject: exfatprogs: improve exfat_msg macro remove an if statement and, make exfat_err write an output to standard error. Signed-off-by: Hyunchul Lee --- include/libexfat.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/libexfat.h b/include/libexfat.h index 601eab4..9c25b7e 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -94,19 +94,19 @@ extern unsigned int print_level; #define EXFAT_INFO (2) #define EXFAT_DEBUG (3) -#define exfat_msg(level, fmt, ...) \ - do { \ - if (print_level >= level) { \ - if (print_level == EXFAT_INFO) \ - printf(fmt, ##__VA_ARGS__); \ - else \ - printf("[%s:%4d] " fmt, \ - __func__, __LINE__, ##__VA_ARGS__); \ - } \ - } while (0) \ - -#define exfat_err(fmt, ...) exfat_msg(EXFAT_ERROR, fmt, ##__VA_ARGS__) -#define exfat_info(fmt, ...) exfat_msg(EXFAT_INFO, fmt, ##__VA_ARGS__) -#define exfat_debug(fmt, ...) exfat_msg(EXFAT_DEBUG, fmt, ##__VA_ARGS__) +#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 */ -- cgit v1.2.3 From b0d96686d29065ecfaf883a83394610f7b92e8e8 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Thu, 4 Jun 2020 10:41:33 +0900 Subject: fsck: make --repair-no default option Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 60260ce..b7d01d0 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1413,25 +1413,21 @@ int main(int argc, char * const argv[]) if (ui.options & FSCK_OPTS_REPAIR_ALL) usage(argv[0]); ui.options |= FSCK_OPTS_REPAIR_NO; - ui.ei.writeable = false; break; case 'r': if (ui.options & FSCK_OPTS_REPAIR_ALL) usage(argv[0]); ui.options |= FSCK_OPTS_REPAIR_ASK; - ui.ei.writeable = true; break; case 'y': if (ui.options & FSCK_OPTS_REPAIR_ALL) usage(argv[0]); ui.options |= FSCK_OPTS_REPAIR_YES; - ui.ei.writeable = true; break; case 'p': if (ui.options & FSCK_OPTS_REPAIR_ALL) usage(argv[0]); ui.options |= FSCK_OPTS_REPAIR_AUTO; - ui.ei.writeable = true; break; case 'V': version_only = true; @@ -1448,12 +1444,18 @@ int main(int argc, char * const argv[]) } show_version(); - if (version_only) - exit(FSCK_EXIT_SYNTAX_ERROR); - if (optind != argc - 1) usage(argv[0]); + if (version_only) + exit(FSCK_EXIT_SYNTAX_ERROR); + if (ui.options & FSCK_OPTS_REPAIR_WRITE) + ui.ei.writeable = true; + else { + ui.options |= FSCK_OPTS_REPAIR_NO; + ui.ei.writeable = false; + } + snprintf(ui.ei.dev_name, sizeof(ui.ei.dev_name), "%s", argv[optind]); ret = exfat_get_blk_dev_info(&ui.ei, &bd); if (ret < 0) { -- cgit v1.2.3 From facb4b2439f0fb00e17675e60cad728aba22fc0f Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Thu, 4 Jun 2020 20:39:34 +0900 Subject: fsck: split exfat_boot_region_check function seperate reading boot region from this function into read_boot_region. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 169 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 91 insertions(+), 78 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index b7d01d0..23897a2 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -178,21 +178,6 @@ static void inode_free_ancestors(struct exfat_inode *child) return; } -static struct exfat *alloc_exfat(struct exfat_blk_dev *bd) -{ - struct exfat *exfat; - - exfat = (struct exfat *)calloc(1, sizeof(*exfat)); - if (!exfat) { - exfat_err("failed to allocate exfat\n"); - return NULL; - } - - exfat->blk_dev = bd; - INIT_LIST_HEAD(&exfat->dir_list); - return exfat; -} - static void free_exfat(struct exfat *exfat) { int i; @@ -214,6 +199,58 @@ static void free_exfat(struct exfat *exfat) } } +static struct exfat *alloc_exfat(struct exfat_blk_dev *bd, struct pbr *bs) +{ + struct exfat *exfat; + int i; + + exfat = (struct exfat *)calloc(1, sizeof(*exfat)); + if (!exfat) { + free(bs); + exfat_err("failed to allocate exfat\n"); + return NULL; + } + + INIT_LIST_HEAD(&exfat->dir_list); + exfat->blk_dev = bd; + exfat->bs = bs; + exfat->clus_count = le32_to_cpu(bs->bsx.clu_count); + exfat->clus_size = EXFAT_CLUSTER_SIZE(bs); + exfat->sect_size = EXFAT_SECTOR_SIZE(bs); + + /* TODO: bitmap could be very large. */ + exfat->alloc_bitmap = (char *)calloc(1, + EXFAT_BITMAP_SIZE(exfat->clus_count)); + if (!exfat->alloc_bitmap) { + exfat_err("failed to allocate bitmap\n"); + goto err; + } + + exfat->disk_bitmap = (char *)malloc( + EXFAT_BITMAP_SIZE(exfat->clus_count)); + if (!exfat->disk_bitmap) { + exfat_err("failed to allocate bitmap\n"); + goto err; + } + + /* allocate cluster buffers */ + for (i = 0; i < 2; i++) { + exfat->buffer_desc[i].buffer = + (char *)malloc(exfat->clus_size); + if (!exfat->buffer_desc[i].buffer) + goto err; + exfat->buffer_desc[i].dirty = + (char *)calloc( + (exfat->clus_size / exfat->sect_size), 1); + if (!exfat->buffer_desc[i].dirty) + goto err; + } + return exfat; +err: + free_exfat(exfat); + return NULL; +} + static void exfat_free_dir_list(struct exfat *exfat) { struct exfat_inode *dir, *i; @@ -641,10 +678,9 @@ static int exfat_mark_volume_dirty(struct exfat *exfat, bool dirty) return 0; } -static int exfat_boot_region_check(struct exfat *exfat) +static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr) { struct pbr *bs; - ssize_t ret; bs = (struct pbr *)malloc(sizeof(struct pbr)); if (!bs) { @@ -652,41 +688,50 @@ static int exfat_boot_region_check(struct exfat *exfat) return -ENOMEM; } - exfat->bs = bs; - - ret = exfat_read(exfat->blk_dev->dev_fd, bs, sizeof(*bs), 0); - if (ret != sizeof(*bs)) { - exfat_err("failed to read a boot sector. %zd\n", ret); - ret = -EIO; - goto err; + if (exfat_read(bd->dev_fd, bs, sizeof(*bs), 0) != + (ssize_t)sizeof(*bs)) { + exfat_err("failed to read a boot sector\n"); + free(bs); + return -EIO; } - ret = -EINVAL; + *pbr = bs; + return 0; +} + +static int exfat_boot_region_check(struct exfat *exfat) +{ + struct pbr *bs; + int ret; + + + bs = exfat->bs; + if (memcmp(bs->bpb.oem_name, "EXFAT ", 8) != 0) { exfat_err("failed to find exfat file system.\n"); - goto err; + return -EINVAL; } if (EXFAT_SECTOR_SIZE(bs) < 512 || EXFAT_SECTOR_SIZE(bs) > 4 * KB) { exfat_err("too small or big sector size: %d\n", EXFAT_SECTOR_SIZE(bs)); - goto err; + return -EINVAL; } if (EXFAT_CLUSTER_SIZE(bs) > 32 * MB) { exfat_err("too big cluster size: %d\n", EXFAT_CLUSTER_SIZE(bs)); - goto err; + return -EINVAL; } if (bs->bsx.fs_version[1] != 1 || bs->bsx.fs_version[0] != 0) { exfat_err("unsupported exfat version: %d.%d\n", bs->bsx.fs_version[1], bs->bsx.fs_version[0]); - goto err; + return -EINVAL; } if (bs->bsx.num_fats != 1) { exfat_err("unsupported FAT count: %d\n", bs->bsx.num_fats); - goto err; + return -EINVAL; } if (le64_to_cpu(bs->bsx.vol_length) * EXFAT_SECTOR_SIZE(bs) > @@ -694,7 +739,7 @@ static int exfat_boot_region_check(struct exfat *exfat) exfat_err("too large sector count: %" PRIu64 "\n, expected: %llu\n", le64_to_cpu(bs->bsx.vol_length), exfat->blk_dev->num_sectors); - goto err; + return -EINVAL; } if (le32_to_cpu(bs->bsx.clu_count) * EXFAT_CLUSTER_SIZE(bs) > @@ -702,30 +747,16 @@ static int exfat_boot_region_check(struct exfat *exfat) exfat_err("too large cluster count: %u, expected: %u\n", le32_to_cpu(bs->bsx.clu_count), exfat->blk_dev->num_clusters); - goto err; - } - - if (exfat_mark_volume_dirty(exfat, true)) { - exfat_err("failed to set VolumeDirty\n"); - ret = -EIO; - goto err; + return -EINVAL; } ret = boot_region_checksum(exfat); if (ret) { - exfat_err("failed to verify the checksum of a boot region. %zd\n", + exfat_err("failed to verify the checksum of a boot region. %d\n", ret); - goto err; + return ret; } - - exfat->clus_count = le32_to_cpu(exfat->bs->bsx.clu_count); - exfat->clus_size = EXFAT_CLUSTER_SIZE(exfat->bs); - exfat->sect_size = EXFAT_SECTOR_SIZE(exfat->bs); return 0; -err: - free(bs); - exfat->bs = NULL; - return (int)ret; } static void dentry_calc_checksum(struct exfat_dentry *dentry, @@ -989,10 +1020,6 @@ static bool read_bitmap(struct exfat_de_iter *iter) DIV_ROUND_UP(exfat->disk_bitmap_size, EXFAT_CLUSTER_SIZE(exfat->bs))); - exfat->disk_bitmap = (char *)malloc( - EXFAT_BITMAP_SIZE(exfat->clus_count)); - if (!exfat->disk_bitmap) - return false; if (exfat_read(exfat->blk_dev->dev_fd, exfat->disk_bitmap, exfat->disk_bitmap_size, exfat_c2o(exfat, exfat->disk_bitmap_clus)) != @@ -1324,28 +1351,6 @@ static int exfat_root_dir_check(struct exfat *exfat) { struct exfat_inode *root; clus_t clus_count; - int i; - - /* TODO: bitmap could be very large. */ - exfat->alloc_bitmap = (char *)calloc(1, - EXFAT_BITMAP_SIZE(exfat->clus_count)); - if (!exfat->alloc_bitmap) { - exfat_err("failed to allocate bitmap\n"); - return -ENOMEM; - } - - /* allocate cluster buffers */ - for (i = 0; i < 2; i++) { - exfat->buffer_desc[i].buffer = - (char *)malloc(exfat->clus_size); - if (!exfat->buffer_desc[i].buffer) - return -ENOMEM; - exfat->buffer_desc[i].dirty = - (char *)calloc( - (exfat->clus_size / exfat->sect_size), 1); - if (!exfat->buffer_desc[i].dirty) - return -ENOMEM; - } root = alloc_exfat_inode(ATTR_SUBDIR); if (!root) { @@ -1395,6 +1400,7 @@ int main(int argc, char * const argv[]) struct fsck_user_input ui; struct exfat_blk_dev bd; struct exfat *exfat = NULL; + struct pbr *bs = NULL; int c, ret, exit_code; bool version_only = false; @@ -1463,13 +1469,22 @@ int main(int argc, char * const argv[]) return FSCK_EXIT_OPERATION_ERROR; } - exfat = alloc_exfat(&bd); + ret = read_boot_region(&bd, &bs); + if (ret) + goto err; + + exfat = alloc_exfat(&bd, bs); if (!exfat) { ret = -ENOMEM; goto err; } exfat->options = ui.options; + if (exfat_mark_volume_dirty(exfat, true)) { + ret = -EIO; + goto err; + } + exfat_debug("verifying boot regions...\n"); ret = exfat_boot_region_check(exfat); if (ret) { @@ -1477,8 +1492,6 @@ int main(int argc, char * const argv[]) goto err; } - exfat_show_info(exfat); - exfat_debug("verifying root directory...\n"); ret = exfat_root_dir_check(exfat); if (ret) { @@ -1495,7 +1508,7 @@ int main(int argc, char * const argv[]) if (ui.ei.writeable && fsync(bd.dev_fd)) { ret = -EIO; - goto err; + goto out; } exfat_mark_volume_dirty(exfat, false); -- cgit v1.2.3 From 94e260db6706e6986b50d03ab7ab153e2a8691f6 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Thu, 4 Jun 2020 21:39:43 +0900 Subject: fsck: repair: add test for large file with broken cluster chain this has a 192MB file which has an invalid cluster number at the end of its clustr chain. fsck should decrement the file size and reclaim some clusters. Signed-off-by: Hyunchul Lee --- tests/large_file_invalid_clus/exfat.img.expected.xz | Bin 0 -> 48520 bytes tests/large_file_invalid_clus/exfat.img.xz | Bin 0 -> 48516 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/large_file_invalid_clus/exfat.img.expected.xz create mode 100644 tests/large_file_invalid_clus/exfat.img.xz diff --git a/tests/large_file_invalid_clus/exfat.img.expected.xz b/tests/large_file_invalid_clus/exfat.img.expected.xz new file mode 100644 index 0000000..b31e710 Binary files /dev/null and b/tests/large_file_invalid_clus/exfat.img.expected.xz differ diff --git a/tests/large_file_invalid_clus/exfat.img.xz b/tests/large_file_invalid_clus/exfat.img.xz new file mode 100644 index 0000000..476c109 Binary files /dev/null and b/tests/large_file_invalid_clus/exfat.img.xz differ -- cgit v1.2.3 From ff46b78b3c5d6e3dba82b8bf6cc5808b3dd5b18e Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 5 Jun 2020 09:28:04 +0900 Subject: fsck: use clus_size member of struct exfat for getting the cluster size Signed-off-by: Hyunchul Lee --- fsck/de_iter.c | 4 ++-- fsck/fsck.c | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/fsck/de_iter.c b/fsck/de_iter.c index f0358f0..ecd7bcf 100644 --- a/fsck/de_iter.c +++ b/fsck/de_iter.c @@ -61,8 +61,8 @@ int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, { iter->exfat = exfat; iter->parent = dir; - iter->read_size = EXFAT_CLUSTER_SIZE(exfat->bs); - iter->write_size = EXFAT_SECTOR_SIZE(exfat->bs); + iter->read_size = exfat->clus_size; + iter->write_size = exfat->sect_size; if (!iter->buffer_desc) iter->buffer_desc = exfat->buffer_desc; diff --git a/fsck/fsck.c b/fsck/fsck.c index 23897a2..99b3375 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -443,7 +443,7 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) ER_FILE_SMALLER_SIZE, "more clusters are allocated. " "truncate to %u bytes", - count * EXFAT_CLUSTER_SIZE(exfat->bs))) + count * exfat->clus_size)) goto truncate_file; else return -EINVAL; @@ -459,7 +459,7 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) ER_FILE_DUPLICATED_CLUS, "cluster is already allocated for " "the other file. truncated to %u bytes", - count * EXFAT_CLUSTER_SIZE(exfat->bs))) + count * exfat->clus_size)) goto truncate_file; else return -EINVAL; @@ -476,7 +476,7 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) "broken cluster chain. " "truncate to %u bytes", count * - EXFAT_CLUSTER_SIZE(exfat->bs))) + exfat->clus_size)) goto truncate_file; else @@ -490,7 +490,7 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) "cluster is marked as free. " "truncate to %u bytes", count * - EXFAT_CLUSTER_SIZE(exfat->bs))) + exfat->clus_size)) goto truncate_file; else @@ -509,7 +509,7 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) if (repair_file_ask(&exfat->de_iter, node, ER_FILE_LARGER_SIZE, "less clusters are allocated. " "truncates to %u bytes", - count * EXFAT_CLUSTER_SIZE(exfat->bs))) + count * exfat->clus_size)) goto truncate_file; else return -EINVAL; @@ -517,19 +517,19 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) return 0; truncate_file: - node->size = count * EXFAT_CLUSTER_SIZE(exfat->bs); + node->size = count * exfat->clus_size; if (!heap_clus(exfat, prev)) node->first_clus = EXFAT_FREE_CLUSTER; exfat_de_iter_get_dirty(&exfat->de_iter, 1, &stream_de); - if (count * EXFAT_CLUSTER_SIZE(exfat->bs) < + if (count * exfat->clus_size < le64_to_cpu(stream_de->stream_valid_size)) stream_de->stream_valid_size = cpu_to_le64( - count * EXFAT_CLUSTER_SIZE(exfat->bs)); + count * exfat->clus_size); if (!heap_clus(exfat, prev)) stream_de->stream_start_clu = EXFAT_FREE_CLUSTER; stream_de->stream_size = cpu_to_le64( - count * EXFAT_CLUSTER_SIZE(exfat->bs)); + count * exfat->clus_size); /* remaining clusters will be freed while FAT is compared with * alloc_bitmap. @@ -805,7 +805,7 @@ static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) return false; if (node->size > le32_to_cpu(exfat->bs->bsx.clu_count) * - EXFAT_CLUSTER_SIZE(exfat->bs)) { + exfat->clus_size) { resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("size %" PRIu64 " is greater than cluster heap: %s\n", node->size, path_resolve_ctx.local_path); @@ -820,10 +820,10 @@ static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) } if ((node->attr & ATTR_SUBDIR) && - node->size % EXFAT_CLUSTER_SIZE(exfat->bs) != 0) { + node->size % exfat->clus_size != 0) { resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("directory size %" PRIu64 " is not divisible by %d: %s\n", - node->size, EXFAT_CLUSTER_SIZE(exfat->bs), + node->size, exfat->clus_size, path_resolve_ctx.local_path); ret = false; } @@ -1018,7 +1018,7 @@ static bool read_bitmap(struct exfat_de_iter *iter) exfat_bitmap_set_range(exfat, le64_to_cpu(dentry->bitmap_start_clu), DIV_ROUND_UP(exfat->disk_bitmap_size, - EXFAT_CLUSTER_SIZE(exfat->bs))); + exfat->clus_size)); if (exfat_read(exfat->blk_dev->dev_fd, exfat->disk_bitmap, exfat->disk_bitmap_size, @@ -1081,7 +1081,7 @@ static bool read_upcase_table(struct exfat_de_iter *iter) exfat_bitmap_set_range(exfat, le32_to_cpu(dentry->upcase_start_clu), DIV_ROUND_UP(le64_to_cpu(dentry->upcase_size), - EXFAT_CLUSTER_SIZE(exfat->bs))); + exfat->clus_size)); free(upcase); return true; @@ -1364,7 +1364,7 @@ static int exfat_root_dir_check(struct exfat *exfat) free_exfat_inode(root); return -EINVAL; } - root->size = clus_count * EXFAT_CLUSTER_SIZE(exfat->bs); + root->size = clus_count * exfat->clus_size; exfat->root = root; exfat_debug("root directory: start cluster[0x%x] size[0x%" PRIx64 "]\n", -- cgit v1.2.3 From e2251284d69a652a91d98861ab2dabbd126495f4 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 5 Jun 2020 09:50:50 +0900 Subject: fsck: check boot region right after reading it Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 51 +++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 99b3375..b894892 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -695,68 +695,54 @@ static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr) return -EIO; } - *pbr = bs; - return 0; -} - -static int exfat_boot_region_check(struct exfat *exfat) -{ - struct pbr *bs; - int ret; - - - bs = exfat->bs; - if (memcmp(bs->bpb.oem_name, "EXFAT ", 8) != 0) { exfat_err("failed to find exfat file system.\n"); - return -EINVAL; + goto err; } if (EXFAT_SECTOR_SIZE(bs) < 512 || EXFAT_SECTOR_SIZE(bs) > 4 * KB) { exfat_err("too small or big sector size: %d\n", EXFAT_SECTOR_SIZE(bs)); - return -EINVAL; + goto err; } if (EXFAT_CLUSTER_SIZE(bs) > 32 * MB) { exfat_err("too big cluster size: %d\n", EXFAT_CLUSTER_SIZE(bs)); - return -EINVAL; + goto err; } if (bs->bsx.fs_version[1] != 1 || bs->bsx.fs_version[0] != 0) { exfat_err("unsupported exfat version: %d.%d\n", bs->bsx.fs_version[1], bs->bsx.fs_version[0]); - return -EINVAL; + goto err; } if (bs->bsx.num_fats != 1) { exfat_err("unsupported FAT count: %d\n", bs->bsx.num_fats); - return -EINVAL; + goto err; } if (le64_to_cpu(bs->bsx.vol_length) * EXFAT_SECTOR_SIZE(bs) > - exfat->blk_dev->size) { + bd->size) { exfat_err("too large sector count: %" PRIu64 "\n, expected: %llu\n", le64_to_cpu(bs->bsx.vol_length), - exfat->blk_dev->num_sectors); - return -EINVAL; + bd->num_sectors); + goto err; } if (le32_to_cpu(bs->bsx.clu_count) * EXFAT_CLUSTER_SIZE(bs) > - exfat->blk_dev->size) { + bd->size) { exfat_err("too large cluster count: %u, expected: %u\n", le32_to_cpu(bs->bsx.clu_count), - exfat->blk_dev->num_clusters); - return -EINVAL; + bd->num_clusters); + goto err; } - ret = boot_region_checksum(exfat); - if (ret) { - exfat_err("failed to verify the checksum of a boot region. %d\n", - ret); - return ret; - } + *pbr = bs; return 0; +err: + free(bs); + return -EINVAL; } static void dentry_calc_checksum(struct exfat_dentry *dentry, @@ -1485,12 +1471,9 @@ int main(int argc, char * const argv[]) goto err; } - exfat_debug("verifying boot regions...\n"); - ret = exfat_boot_region_check(exfat); - if (ret) { - exfat_err("failed to verify boot regions.\n"); + ret = boot_region_checksum(exfat); + if (ret) goto err; - } exfat_debug("verifying root directory...\n"); ret = exfat_root_dir_check(exfat); -- cgit v1.2.3 From ebe29977c5dd5e54caa2f34df444e2eaef8adc44 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 5 Jun 2020 09:52:18 +0900 Subject: fsck: call missing exfat_show_info Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index b894892..5132687 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1358,7 +1358,7 @@ static int exfat_root_dir_check(struct exfat *exfat) return 0; } -void exfat_show_info(struct exfat *exfat) +static void exfat_show_info(struct exfat *exfat) { exfat_info("Bytes per sector: %d\n", 1 << exfat->bs->bsx.sect_size_bits); @@ -1371,7 +1371,7 @@ void exfat_show_info(struct exfat *exfat) le32_to_cpu(exfat->bs->bsx.clu_offset)); } -void exfat_show_stat(void) +static void exfat_show_stat(void) { exfat_debug("Found directories: %ld\n", exfat_stat.dir_count); exfat_debug("Found files: %ld\n", exfat_stat.file_count); @@ -1475,6 +1475,8 @@ int main(int argc, char * const argv[]) if (ret) goto err; + exfat_show_info(exfat); + exfat_debug("verifying root directory...\n"); ret = exfat_root_dir_check(exfat); if (ret) { -- cgit v1.2.3 From c1f48157c38df8d958ab81012abae2470750a785 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Sun, 7 Jun 2020 17:54:28 +0900 Subject: fsck: fix integer overflow in calculating size The size must be 64-bit integer Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 5132687..0e8f2f0 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -415,7 +415,7 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) { struct exfat_dentry *stream_de; clus_t clus, prev, next; - clus_t count, max_count; + uint64_t count, max_count; clus = node->first_clus; prev = EXFAT_EOF_CLUSTER; @@ -442,7 +442,7 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) if (repair_file_ask(&exfat->de_iter, node, ER_FILE_SMALLER_SIZE, "more clusters are allocated. " - "truncate to %u bytes", + "truncate to %" PRIu64 " bytes", count * exfat->clus_size)) goto truncate_file; else @@ -458,7 +458,8 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) if (repair_file_ask(&exfat->de_iter, node, ER_FILE_DUPLICATED_CLUS, "cluster is already allocated for " - "the other file. truncated to %u bytes", + "the other file. truncated to %" + PRIu64 " bytes", count * exfat->clus_size)) goto truncate_file; else @@ -474,9 +475,9 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) if (repair_file_ask(&exfat->de_iter, node, ER_FILE_INVALID_CLUS, "broken cluster chain. " - "truncate to %u bytes", - count * - exfat->clus_size)) + "truncate to %" + PRIu64 " bytes", + count * exfat->clus_size)) goto truncate_file; else @@ -488,9 +489,9 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) if (repair_file_ask(&exfat->de_iter, node, ER_FILE_INVALID_CLUS, "cluster is marked as free. " - "truncate to %u bytes", - count * - exfat->clus_size)) + "truncate to %" + PRIu64 " bytes", + count * exfat->clus_size)) goto truncate_file; else @@ -508,7 +509,7 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) if (count < max_count) { if (repair_file_ask(&exfat->de_iter, node, ER_FILE_LARGER_SIZE, "less clusters are allocated. " - "truncates to %u bytes", + "truncates to %" PRIu64 " bytes", count * exfat->clus_size)) goto truncate_file; else @@ -791,7 +792,7 @@ static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) return false; if (node->size > le32_to_cpu(exfat->bs->bsx.clu_count) * - exfat->clus_size) { + (uint64_t)exfat->clus_size) { resolve_path_parent(&path_resolve_ctx, iter->parent, node); exfat_err("size %" PRIu64 " is greater than cluster heap: %s\n", node->size, path_resolve_ctx.local_path); -- cgit v1.2.3 From c1431c3316326a8f86a99ccce80ba26b3151cc3f Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 8 Jun 2020 11:54:02 +0900 Subject: fsck: add copyright in de_iter.c Signed-off-by: Hyunchul Lee --- fsck/de_iter.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fsck/de_iter.c b/fsck/de_iter.c index ecd7bcf..4b75e12 100644 --- a/fsck/de_iter.c +++ b/fsck/de_iter.c @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Hyunchul Lee + */ #include #include #include -- cgit v1.2.3 From 6fe32f883c16d88659d626cbf9779536af63083c Mon Sep 17 00:00:00 2001 From: Ethan Sommer Date: Thu, 18 Jun 2020 09:36:18 -0400 Subject: mkfs: replace log2 with manual calculation The only use of the math library is in mkfs for log2(), which is easily replaced by dividing the input number by 2 until it is reaches 1 or less, and incrementing the output variable on each division, so remove use of the math library. Signed-off-by: Ethan Sommer --- mkfs/Makefile.am | 1 - mkfs/mkfs.c | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am index 201ba3b..7b3e35b 100644 --- a/mkfs/Makefile.am +++ b/mkfs/Makefile.am @@ -1,5 +1,4 @@ AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common -LIBS = -lm mkfs_exfat_LDADD = $(top_builddir)/lib/libexfat.a sbin_PROGRAMS = mkfs.exfat diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 2edd1c5..7625cee 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "exfat_ondisk.h" @@ -29,6 +28,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, { struct bpb64 *pbpb = &ppbr->bpb; struct bsx64 *pbsx = &ppbr->bsx; + unsigned int i; /* Fill exfat BIOS paramemter block */ pbpb->jmp_boot[0] = 0xeb; @@ -48,7 +48,10 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, pbsx->vol_serial = cpu_to_le32(1234); pbsx->vol_flags = 0; pbsx->sect_size_bits = bd->sector_size_bits; - pbsx->sect_per_clus_bits = log2(ui->cluster_size / bd->sector_size); + 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; -- cgit v1.2.3 From 4ac18e12d1890decef853ada26b8732bb0f574da Mon Sep 17 00:00:00 2001 From: Hyeongseok Kim Date: Tue, 16 Jun 2020 07:55:40 +0900 Subject: mkfs: make unique serial number while creating filesystem combine time values for generating the serial number Signed-off-by: Hyeongseok Kim --- mkfs/mkfs.c | 18 +++++++++++++++++- mkfs/mkfs.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 2edd1c5..313b1e6 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "exfat_ondisk.h" #include "libexfat.h" @@ -24,6 +25,20 @@ 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) { @@ -45,7 +60,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, 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(1234); + 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 = log2(ui->cluster_size / bd->sector_size); @@ -437,6 +452,7 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.root_byte_off = round_up(finfo.ut_byte_off + finfo.ut_byte_len, ui->cluster_size); finfo.root_byte_len = sizeof(struct exfat_dentry) * 3; + finfo.volume_serial = get_new_serial(); return 0; } diff --git a/mkfs/mkfs.h b/mkfs/mkfs.h index df31894..e425a14 100644 --- a/mkfs/mkfs.h +++ b/mkfs/mkfs.h @@ -24,6 +24,7 @@ struct exfat_mkfs_info { 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; -- cgit v1.2.3 From ca6b2370d880a3896f04b358b8069ebbbed68b67 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 23 Jun 2020 13:44:25 +0900 Subject: mkfs: rename DEFAULT_CLUSTER_SIZE macro to DEFAULT_BOUNDARY_ALIGNMENT Rename DEFAULT_CLUSTER_SIZE macro to DEFAULT_BOUNDARY_ALIGNMENT. If needed, we can add the option to adjust boundary alignment so that writes to these areas will happen in as few flash blocks as possible. Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 6 +++--- mkfs/mkfs.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 2edd1c5..e917293 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -409,14 +409,14 @@ static struct option opts[] = { static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - if (ui->cluster_size > DEFAULT_CLUSTER_SIZE) + if (ui->cluster_size > DEFAULT_BOUNDARY_ALIGNMENT) finfo.fat_byte_off = ui->cluster_size; else - finfo.fat_byte_off = DEFAULT_CLUSTER_SIZE; + finfo.fat_byte_off = DEFAULT_BOUNDARY_ALIGNMENT; finfo.fat_byte_len = round_up((bd->num_clusters * sizeof(int)), ui->cluster_size); finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len, - DEFAULT_CLUSTER_SIZE); + DEFAULT_BOUNDARY_ALIGNMENT); finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; if (finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) { diff --git a/mkfs/mkfs.h b/mkfs/mkfs.h index df31894..9011d6b 100644 --- a/mkfs/mkfs.h +++ b/mkfs/mkfs.h @@ -5,9 +5,9 @@ #ifndef _MKFS_H -#define DEFAULT_CLUSTER_SIZE (1024*1024) -#define MIN_NUM_SECTOR (2048) -#define EXFAT_MAX_CLUSTER_SIZE (32*1024*1024) +#define DEFAULT_BOUNDARY_ALIGNMENT (1024*1024) +#define MIN_NUM_SECTOR (2048) +#define EXFAT_MAX_CLUSTER_SIZE (32*1024*1024) struct exfat_mkfs_info { unsigned int total_clu_cnt; -- cgit v1.2.3 From e330c27d834a48bfe67e655726f3f9f1e34c814e Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sun, 28 Jun 2020 14:36:41 +0200 Subject: fsck: Add missing file to Android build Signed-off-by: Luca Stefani --- fsck/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/fsck/Android.bp b/fsck/Android.bp index 7473fea..f267ad4 100644 --- a/fsck/Android.bp +++ b/fsck/Android.bp @@ -4,6 +4,7 @@ cc_binary { name: "fsck.exfat", srcs: [ + "de_iter.c", "fsck.c", "repair.c", ], -- cgit v1.2.3 From 41e35156ec9ab481ca002bc873c50433a6ba79b4 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 1 Jul 2020 13:34:34 +0900 Subject: Revert "exfatprogs: remove xz tarball generation" This reverts commit 7165385db2ab61fded031e52e8f660c3b85211c2. Signed-off-by: Namjae Jeon --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f515511..692faf6 100644 --- a/configure.ac +++ b/configure.ac @@ -14,7 +14,7 @@ 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 subdir-objects]) +AM_INIT_AUTOMAKE([foreign tar-pax dist-xz subdir-objects]) AC_LANG([C]) AC_PROG_CC -- cgit v1.2.3 From e6bfc739db50aaf0916b4f3376211055d61f8e2f Mon Sep 17 00:00:00 2001 From: Sven Hoexter Date: Sun, 5 Jul 2020 21:55:42 +0200 Subject: manpages: remove spurious .TP at the end of man 8 tune.exfat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes $ LC_ALL=en_US.UTF-8 MANROFFSEQ='' MANWIDTH=80 \ man --warnings -E UTF-8 -l -Tutf8 -Z tune.exfat.8 >/dev/null troff: automatically ending diversion 'an-div' on exit as reported by lintian the Debian package linter. Reported-by: Sedat Dilek sedat.dilek@gmail.com Signed-off-by: Sven Höxter --- manpages/tune.exfat.8 | 1 - 1 file changed, 1 deletion(-) diff --git a/manpages/tune.exfat.8 b/manpages/tune.exfat.8 index 12dd6d2..c834ed9 100644 --- a/manpages/tune.exfat.8 +++ b/manpages/tune.exfat.8 @@ -31,4 +31,3 @@ Prints verbose debugging information while extracting or tuning parameters of th .TP .B \-V Prints the version number and exits. -.TP -- cgit v1.2.3 From 677079d0015bf438e74730f480c22ca0f813d8d0 Mon Sep 17 00:00:00 2001 From: Sven Hoexter Date: Sun, 5 Jul 2020 21:57:43 +0200 Subject: manpages: spelling fix in man 8 fsck.exfat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported by lintian the Debian package linter. Signed-off-by: Sven Höxter --- manpages/fsck.exfat.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manpages/fsck.exfat.8 b/manpages/fsck.exfat.8 index b6cf3c8..b02a056 100644 --- a/manpages/fsck.exfat.8 +++ b/manpages/fsck.exfat.8 @@ -19,7 +19,7 @@ fsck.exfat \- check an exFAT filesystem .B fsck.exfat \-V .SH DESCRIPTION .B fsck.exfat -checks an exFAT filesystem and repairs the filesytem +checks an exFAT filesystem and repairs the filesystem depending on the options passed. .PP .SH OPTIONS -- cgit v1.2.3 From ce2552b927550345826296f8b09694844e62443c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20H=C3=B6xter?= Date: Mon, 6 Jul 2020 09:44:16 +0200 Subject: README: add basic contributor information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stating that the development actually happens outside the master branch and Signed-Off lines are required. Signed-off-by: Sven Höxter --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 48861d9..958fe48 100644 --- a/README.md +++ b/README.md @@ -68,3 +68,7 @@ If you have any issues, please create [issues][1] or contact to [Namjae Jeon](ma [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`). \ No newline at end of file -- cgit v1.2.3 From 674481d5cb8b81fadcfd0f27e5c1a1ef04e336df Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Thu, 16 Jul 2020 00:08:56 +0200 Subject: mkfs : allow to pass cluster size without unit This match the README Signed-off-by: Matthieu CASTET --- mkfs/mkfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 81e6a56..de5c081 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -558,6 +558,8 @@ static long long parse_cluster_size(const char *size) case 'k': byte_size <<= 10; break; + case '\0': + break; default: exfat_err("Wrong unit input('%c') for cluster size\n", *data_unit); -- cgit v1.2.3 From aa13762e3067a419e207156f2508a3ebde388fc4 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Thu, 16 Jul 2020 00:17:28 +0200 Subject: mkfs : check that cluster size is a power of two Signed-off-by: Matthieu CASTET --- mkfs/mkfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index de5c081..4abcc41 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -604,7 +604,11 @@ int main(int argc, char *argv[]) ret = parse_cluster_size(optarg); if (ret < 0) goto out; - else if (ret > EXFAT_MAX_CLUSTER_SIZE) { + 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; -- cgit v1.2.3 From 1f1d635ff9e9d5b14e1a93abfbae7abe60804fed Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Wed, 15 Jul 2020 14:39:10 +0200 Subject: mkfs : add boundary-align option This allow to align fat and start of cluster on a boundary. This may usefull for some media like sdcard. Signed-off-by: Matthieu CASTET --- README.md | 4 ++++ include/libexfat.h | 3 +++ lib/libexfat.c | 3 +++ manpages/mkfs.exfat.8 | 9 +++++++++ mkfs/mkfs.c | 56 ++++++++++++++++++++++++++++++++++----------------- mkfs/mkfs.h | 1 - 6 files changed, 57 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 958fe48..2e5f2dc 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,10 @@ Usage example: 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 alignement(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 - fsck.exfat: Check the consistency of your exfat filesystem and optionally repair a corrupted device formatted by exfat. diff --git a/include/libexfat.h b/include/libexfat.h index 9c25b7e..6a3ecb8 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -28,6 +28,8 @@ #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) @@ -59,6 +61,7 @@ struct exfat_user_input { bool writeable; unsigned int cluster_size; unsigned int sec_per_clu; + unsigned int boundary_align; bool quick; __u16 volume_label[VOLUME_LABEL_MAX_LEN]; int volume_label_len; diff --git a/lib/libexfat.c b/lib/libexfat.c index cc840ec..1c0bbc0 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -165,6 +165,9 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, 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); diff --git a/manpages/mkfs.exfat.8 b/manpages/mkfs.exfat.8 index bc7ab4d..0c28f03 100644 --- a/manpages/mkfs.exfat.8 +++ b/manpages/mkfs.exfat.8 @@ -4,6 +4,9 @@ mkfs.exfat \- create an exFAT filesystem .SH SYNOPSIS .B mkfs.exfat [ +.B \-b +.I boundary_alignement +] [ .B \-c .I cluster_size ] [ @@ -36,6 +39,12 @@ SCSI disk, use: .PP .SH OPTIONS .TP +.BI \-b " boundary_alignement" +Specify the aligment for FAT and start of cluster. +Boundary alignement can be specified in m/M for megabytes +and k/K for kilobytes. It should be a power of two. +Some media like sdcard need this. +.TP .BI \-c " cluster_size" Specify the cluster size. Cluster size can be specified in m/M for megabytes and k/K for kilobytes. diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 4abcc41..60999b1 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -405,6 +405,7 @@ static void usage(void) fprintf(stderr, "Usage: mkfs.exfat\n"); fprintf(stderr, "\t-L | --volume-label=label Set volume label\n"); fprintf(stderr, "\t-c | --cluster-size=size(or suffixed by 'K' or 'M') Specify cluster size\n"); + fprintf(stderr, "\t-b | --boundary-align=size(or suffixed by 'K' or 'M') Specify boundary alignement\n"); fprintf(stderr, "\t-f | --full-format Full format\n"); fprintf(stderr, "\t-V | --version Show version\n"); fprintf(stderr, "\t-v | --verbose Print debug\n"); @@ -416,6 +417,7 @@ static void usage(void) static struct option opts[] = { {"volume-label", required_argument, NULL, 'L' }, {"cluster-size", required_argument, NULL, 'c' }, + {"boundary-align", required_argument, NULL, 'b' }, {"full-format", no_argument, NULL, 'f' }, {"version", no_argument, NULL, 'V' }, {"verbose", no_argument, NULL, 'v' }, @@ -427,14 +429,22 @@ static struct option opts[] = { static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { - if (ui->cluster_size > DEFAULT_BOUNDARY_ALIGNMENT) - finfo.fat_byte_off = ui->cluster_size; - else - finfo.fat_byte_off = DEFAULT_BOUNDARY_ALIGNMENT; + int clu_len; + if (ui->boundary_align < bd->sector_size) { + exfat_err("boundary alignement is too small (min %d)\n", + bd->sector_size); + return -1; + } + finfo.fat_byte_off = round_up(24 * bd->sector_size, + ui->boundary_align); finfo.fat_byte_len = round_up((bd->num_clusters * sizeof(int)), ui->cluster_size); finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len, - DEFAULT_BOUNDARY_ALIGNMENT); + ui->boundary_align); + if (bd->size <= finfo.clu_byte_off) { + exfat_err("boundary alignement is too big\n"); + return -1; + } finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size; if (finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) { @@ -444,16 +454,15 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.bitmap_byte_off = finfo.clu_byte_off; finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8; - finfo.ut_start_clu = round_up(EXFAT_REVERVED_CLUSTERS * - ui->cluster_size + finfo.bitmap_byte_len, ui->cluster_size) / - ui->cluster_size; - finfo.ut_byte_off = round_up(finfo.bitmap_byte_off + - finfo.bitmap_byte_len, ui->cluster_size); + 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; - finfo.root_start_clu = round_up(finfo.ut_start_clu * ui->cluster_size - + finfo.ut_byte_len, ui->cluster_size) / ui->cluster_size; - finfo.root_byte_off = round_up(finfo.ut_byte_off + finfo.ut_byte_len, - ui->cluster_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(); @@ -544,7 +553,7 @@ static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui) return 0; } -static long long parse_cluster_size(const char *size) +static long long parse_size(const char *size) { char *data_unit; unsigned long long byte_size = strtoull(size, &data_unit, 0); @@ -561,7 +570,7 @@ static long long parse_cluster_size(const char *size) case '\0': break; default: - exfat_err("Wrong unit input('%c') for cluster size\n", + exfat_err("Wrong unit input('%c') for size\n", *data_unit); return -EINVAL; } @@ -583,7 +592,7 @@ int main(int argc, char *argv[]) exfat_err("failed to init locale/codeset\n"); opterr = 0; - while ((c = getopt_long(argc, argv, "n:L:c:fVvh", opts, NULL)) != EOF) + 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 @@ -601,7 +610,7 @@ int main(int argc, char *argv[]) break; } case 'c': - ret = parse_cluster_size(optarg); + ret = parse_size(optarg); if (ret < 0) goto out; else if (ret & (ret - 1)) { @@ -615,6 +624,17 @@ int main(int argc, char *argv[]) } 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 'f': ui.quick = false; break; diff --git a/mkfs/mkfs.h b/mkfs/mkfs.h index e4724ea..ffd56e3 100644 --- a/mkfs/mkfs.h +++ b/mkfs/mkfs.h @@ -5,7 +5,6 @@ #ifndef _MKFS_H -#define DEFAULT_BOUNDARY_ALIGNMENT (1024*1024) #define MIN_NUM_SECTOR (2048) #define EXFAT_MAX_CLUSTER_SIZE (32*1024*1024) -- cgit v1.2.3 From 9a3f49e2b4185b6faf90ebdb88d9c06364c656c1 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 7 Jul 2020 14:20:28 +0900 Subject: fsck: fix the bug that cannot access space beyond 2TB Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 0e8f2f0..abc0d84 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -386,7 +386,7 @@ int get_next_clus(struct exfat *exfat, struct exfat_inode *node, return 0; } - offset = le32_to_cpu(exfat->bs->bsx.fat_offset) << + offset = (off_t)le32_to_cpu(exfat->bs->bsx.fat_offset) << exfat->bs->bsx.sect_size_bits; offset += sizeof(clus_t) * clus; @@ -586,7 +586,7 @@ off_t exfat_c2o(struct exfat *exfat, unsigned int clus) return ~0L; return exfat_s2o(exfat, le32_to_cpu(exfat->bs->bsx.clu_offset) + - ((clus - EXFAT_FIRST_CLUSTER) << + ((off_t)(clus - EXFAT_FIRST_CLUSTER) << exfat->bs->bsx.sect_per_clus_bits)); } -- cgit v1.2.3 From 9a55e55c908832940e9066916862231ceb7d1a5e Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 7 Jul 2020 14:15:12 +0900 Subject: fsck: tests: make test_fsck.sh run multiple test cases Signed-off-by: Hyunchul Lee --- tests/test_fsck.sh | 89 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/tests/test_fsck.sh b/tests/test_fsck.sh index c842789..3819c81 100755 --- a/tests/test_fsck.sh +++ b/tests/test_fsck.sh @@ -4,51 +4,76 @@ TESTCASE_DIR=$1 IMAGE_FILE=exfat.img FSCK_PROG=../build/sbin/fsck.exfat FSCK_OPTS=-y +PASS_COUNT=0 -echo "Running $TESTCASE_DIR" -echo "-----------------------------------" +function 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 if [ "$EUID" -ne "0" ]; then echo "This script should be ran as root" exit fi -# Set up image file as loop device -unxz -cfk $TESTCASE_DIR/$IMAGE_FILE.xz > $IMAGE_FILE -sudo losetup -f $IMAGE_FILE -DEV_FILE=`losetup -j $IMAGE_FILE | awk '{print $1}' | sed 's/://g'` +for TESTCASE_DIR in $TESTCASE_DIRS +do + if [ ! -e ${TESTCASE_DIR}/${IMAGE_FILE}.tar.xz ]; then + TEST_COUNT=$((TEST_COUNT - 1)) + continue + fi -# 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 - exit -fi + echo "Running $TESTCASE_DIR" + echo "-----------------------------------" -# Run fsck again -$FSCK_PROG -n $DEV_FILE -if [ "$?" -ne "0" ]; then - echo "" - echo "Failed, corrupted $TESTCASE_DIR" - losetup -d $DEV_FILE - exit -fi + # Set up image file as loop device + unxz -cfk $TESTCASE_DIR/$IMAGE_FILE.xz > $IMAGE_FILE + sudo losetup -f $IMAGE_FILE + DEV_FILE=`losetup -j $IMAGE_FILE | awk '{print $1}' | sed 's/://g'` + + # 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 -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) + echo "" + # Run fsck again + $FSCK_PROG -n $DEV_FILE if [ "$?" -ne "0" ]; then echo "" - echo "Failed $TESTCASE_DIR" + echo "Failed, corrupted $TESTCASE_DIR" losetup -d $DEV_FILE - exit + cleanup fi -fi -echo "" -echo "Passed $TESTCASE_DIR" + 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 -losetup -d $DEV_FILE + echo "" + echo "Passed $TESTCASE_DIR" + PASS_COUNT=$((PASS_COUNT + 1)) + + losetup -d $DEV_FILE +done +cleanup -- cgit v1.2.3 From ac7436a707f316a2ad6af1d942bfec56e5bf78a7 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 8 Jul 2020 09:30:50 +0900 Subject: fsck: tests: compress filesystem images with tar Compress image files with tar to reduce the compression sizes for sparse files. Signed-off-by: Hyunchul Lee --- tests/bs_bad_csum/exfat.img.tar.xz | Bin 0 -> 3036 bytes tests/bs_bad_csum/exfat.img.xz | Bin 3716 -> 0 bytes tests/de_bad_csum/exfat.img.tar.xz | Bin 0 -> 3196 bytes tests/de_bad_csum/exfat.img.xz | Bin 3872 -> 0 bytes tests/file_invalid_clus/exfat.img.tar.xz | Bin 0 -> 3392 bytes tests/file_invalid_clus/exfat.img.xz | Bin 4064 -> 0 bytes tests/large_file_invalid_clus/exfat.img.tar.xz | Bin 0 -> 17280 bytes tests/large_file_invalid_clus/exfat.img.xz | Bin 48516 -> 0 bytes tests/test_fsck.sh | 8 ++------ 9 files changed, 2 insertions(+), 6 deletions(-) create mode 100644 tests/bs_bad_csum/exfat.img.tar.xz delete mode 100644 tests/bs_bad_csum/exfat.img.xz create mode 100644 tests/de_bad_csum/exfat.img.tar.xz delete mode 100644 tests/de_bad_csum/exfat.img.xz create mode 100644 tests/file_invalid_clus/exfat.img.tar.xz delete mode 100644 tests/file_invalid_clus/exfat.img.xz create mode 100644 tests/large_file_invalid_clus/exfat.img.tar.xz delete mode 100644 tests/large_file_invalid_clus/exfat.img.xz diff --git a/tests/bs_bad_csum/exfat.img.tar.xz b/tests/bs_bad_csum/exfat.img.tar.xz new file mode 100644 index 0000000..cbcc5c0 Binary files /dev/null and b/tests/bs_bad_csum/exfat.img.tar.xz differ diff --git a/tests/bs_bad_csum/exfat.img.xz b/tests/bs_bad_csum/exfat.img.xz deleted file mode 100644 index e3fba3f..0000000 Binary files a/tests/bs_bad_csum/exfat.img.xz and /dev/null differ diff --git a/tests/de_bad_csum/exfat.img.tar.xz b/tests/de_bad_csum/exfat.img.tar.xz new file mode 100644 index 0000000..f753e82 Binary files /dev/null and b/tests/de_bad_csum/exfat.img.tar.xz differ diff --git a/tests/de_bad_csum/exfat.img.xz b/tests/de_bad_csum/exfat.img.xz deleted file mode 100644 index 7c5dc64..0000000 Binary files a/tests/de_bad_csum/exfat.img.xz and /dev/null differ diff --git a/tests/file_invalid_clus/exfat.img.tar.xz b/tests/file_invalid_clus/exfat.img.tar.xz new file mode 100644 index 0000000..830edf2 Binary files /dev/null and b/tests/file_invalid_clus/exfat.img.tar.xz differ diff --git a/tests/file_invalid_clus/exfat.img.xz b/tests/file_invalid_clus/exfat.img.xz deleted file mode 100644 index 47097e3..0000000 Binary files a/tests/file_invalid_clus/exfat.img.xz and /dev/null differ diff --git a/tests/large_file_invalid_clus/exfat.img.tar.xz b/tests/large_file_invalid_clus/exfat.img.tar.xz new file mode 100644 index 0000000..5e3dbef Binary files /dev/null and b/tests/large_file_invalid_clus/exfat.img.tar.xz differ diff --git a/tests/large_file_invalid_clus/exfat.img.xz b/tests/large_file_invalid_clus/exfat.img.xz deleted file mode 100644 index 476c109..0000000 Binary files a/tests/large_file_invalid_clus/exfat.img.xz and /dev/null differ diff --git a/tests/test_fsck.sh b/tests/test_fsck.sh index 3819c81..3a59d7f 100755 --- a/tests/test_fsck.sh +++ b/tests/test_fsck.sh @@ -19,10 +19,6 @@ else TESTCASE_DIRS=$@ TEST_COUNT=$# fi -if [ "$EUID" -ne "0" ]; then - echo "This script should be ran as root" - exit -fi for TESTCASE_DIR in $TESTCASE_DIRS do @@ -35,8 +31,8 @@ do echo "-----------------------------------" # Set up image file as loop device - unxz -cfk $TESTCASE_DIR/$IMAGE_FILE.xz > $IMAGE_FILE - sudo losetup -f $IMAGE_FILE + tar -C . -xf $TESTCASE_DIR/$IMAGE_FILE.tar.xz + losetup -f $IMAGE_FILE DEV_FILE=`losetup -j $IMAGE_FILE | awk '{print $1}' | sed 's/://g'` # Run fsck for repair -- cgit v1.2.3 From 522005f9f443594fabb13c68dfb28d289a26155b Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 8 Jul 2020 09:34:40 +0900 Subject: fsck: tests: add test case for access beyond 2TB the root directory is located at 2TB byte offset, and it has the file which has an invalid checksum and a corrupted chain of clusters. Signed-off-by: Hyunchul Lee --- tests/2tb_disk/exfat.img.tar.xz | Bin 0 -> 13368 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/2tb_disk/exfat.img.tar.xz diff --git a/tests/2tb_disk/exfat.img.tar.xz b/tests/2tb_disk/exfat.img.tar.xz new file mode 100644 index 0000000..f979bde Binary files /dev/null and b/tests/2tb_disk/exfat.img.tar.xz differ -- cgit v1.2.3 From 6bd5c4287bbba96ba2f9aec583e729033ffcce78 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 6 Jul 2020 14:47:05 +0900 Subject: fsck: read directory entries by 4KB unit. Though Exfat allocates space in a cluster unit for directories, Directories could have a little entries. So Reading them in a cluster unit could make fsck slow in the case that there are many directories. Signed-off-by: Hyunchul Lee Reported-by: Hyeongseok Kim --- fsck/de_iter.c | 83 ++++++++++++++++++++++++++++++++-------------------------- fsck/fsck.h | 1 + 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/fsck/de_iter.c b/fsck/de_iter.c index 4b75e12..9fa841e 100644 --- a/fsck/de_iter.c +++ b/fsck/de_iter.c @@ -10,15 +10,15 @@ #include "libexfat.h" #include "fsck.h" -static ssize_t write_clus(struct exfat_de_iter *iter, int bufidx) +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[bufidx]; - device_offset = exfat_c2o(exfat, desc->p_clus); + 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]) { @@ -34,28 +34,44 @@ static ssize_t write_clus(struct exfat_de_iter *iter, int bufidx) return 0; } -static ssize_t read_next_clus(struct exfat_de_iter *iter, clus_t l_clus) +static ssize_t read_block(struct exfat_de_iter *iter, unsigned int block) { struct exfat *exfat = iter->exfat; - struct buffer_desc *desc; + struct buffer_desc *desc, *prev_desc; off_t device_offset; int ret; - desc = &iter->buffer_desc[l_clus & 0x01]; - if (l_clus == 0) + desc = &iter->buffer_desc[block & 0x01]; + if (block == 0) { desc->p_clus = iter->parent->first_clus; + desc->offset = 0; + } - if (write_clus(iter, l_clus & 0x01)) + /* if the buffer already contains dirty dentries, write it */ + if (write_block(iter, block)) return -EIO; - if (l_clus > 0) { - ret = get_next_clus(exfat, iter->parent, - iter->buffer_desc[(l_clus - 1) & 0x01].p_clus, - &desc->p_clus); - if (ret) - return ret; + 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); + + device_offset = exfat_c2o(exfat, desc->p_clus) + desc->offset; return exfat_read(exfat->blk_dev->dev_fd, desc->buffer, iter->read_size, device_offset); } @@ -65,13 +81,13 @@ int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, { iter->exfat = exfat; iter->parent = dir; - iter->read_size = exfat->clus_size; iter->write_size = exfat->sect_size; + iter->read_size = exfat->clus_size <= 4*KB ? exfat->clus_size : 4 * KB; if (!iter->buffer_desc) iter->buffer_desc = exfat->buffer_desc; - if (read_next_clus(iter, 0) != (ssize_t)iter->read_size) { + if (read_block(iter, 0) != (ssize_t)iter->read_size) { exfat_err("failed to read directory entries.\n"); return -EIO; } @@ -87,31 +103,24 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, { off_t next_de_file_offset; ssize_t ret; - clus_t next_l_clus; + unsigned int block; next_de_file_offset = iter->de_file_offset + ith * sizeof(struct exfat_dentry); - next_l_clus = (clus_t) (next_de_file_offset / iter->read_size); + block = (unsigned int)(next_de_file_offset / iter->read_size); if (next_de_file_offset + sizeof(struct exfat_dentry) > iter->parent->size) return EOF; - /* - * desired dentry must be in current, or next cluster which - * will be read - */ - if (next_l_clus > iter->de_file_offset / iter->read_size + 1) + /* 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_next_clus(iter, next_l_clus); - if (ret == EOF) { - return EOF; - } else if (ret != (ssize_t)iter->read_size) { - exfat_err("failed to read a cluster. %zd\n", ret); + ret = read_block(iter, block); + if (ret != (ssize_t)iter->read_size) return ret; - } iter->next_read_offset += iter->read_size; } @@ -119,7 +128,7 @@ int exfat_de_iter_get(struct exfat_de_iter *iter, iter->max_skip_dentries = ith + 1; *dentry = (struct exfat_dentry *) - (iter->buffer_desc[next_l_clus & 0x01].buffer + + (iter->buffer_desc[block & 0x01].buffer + next_de_file_offset % iter->read_size); return 0; } @@ -128,16 +137,17 @@ int exfat_de_iter_get_dirty(struct exfat_de_iter *iter, int ith, struct exfat_dentry **dentry) { off_t next_file_offset; - clus_t l_clus; + 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); - l_clus = (clus_t)(next_file_offset / iter->read_size); - sect_idx = (int)(next_file_offset / iter->write_size); - iter->buffer_desc[l_clus & 0x01].dirty[sect_idx] = 1; + 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; @@ -145,8 +155,7 @@ int exfat_de_iter_get_dirty(struct exfat_de_iter *iter, int exfat_de_iter_flush(struct exfat_de_iter *iter) { - if (write_clus(iter, 0) || - write_clus(iter, 1)) + if (write_block(iter, 0) || write_block(iter, 1)) return -EIO; return 0; } diff --git a/fsck/fsck.h b/fsck/fsck.h index 40b7b1c..8fc45e0 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -29,6 +29,7 @@ struct exfat_inode { struct buffer_desc { clus_t p_clus; + unsigned int offset; char *buffer; char *dirty; }; -- cgit v1.2.3 From 6763b53048075e7bd2f1329f7023fac9b3546de1 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 10 Jul 2020 17:13:34 +0900 Subject: fsck: stop scanning dentries when the end of directory is met fsck doesn't fix unknown or invalid directory entries Currently. So make fsck stop scanning dentries when the end of directory is met. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 6 ++++-- include/exfat_ondisk.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index abc0d84..6d89fa4 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1141,9 +1141,10 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) goto err; } break; + case EXFAT_LAST: + goto out; default: - if (IS_EXFAT_DELETED(dentry->type) || - (dentry->type == EXFAT_UNUSED)) + if (IS_EXFAT_DELETED(dentry->type)) break; exfat_err("unknown entry type. 0x%x\n", dentry->type); ret = -EINVAL; @@ -1152,6 +1153,7 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) exfat_de_iter_advance(de_iter, dentry_count); } +out: list_splice(&sub_dir_list, &exfat->dir_list); exfat_de_iter_flush(de_iter); return 0; diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index 70546a3..163bef0 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -44,7 +44,7 @@ #define MSDOS_DELETED 0xE5 /* deleted mark */ #define MSDOS_UNUSED 0x00 /* end of directory */ -#define EXFAT_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 */ -- cgit v1.2.3 From 0c92c998f6f97c60c35add422392b22e539dd454 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 13 Jul 2020 19:24:01 +0900 Subject: fsck: read directory entries ahead of time This commit reads directory entries ahead of accessing those. If they are at the last cluster, read the half or quarter cluster, otherwise read the whole cluster. Signed-off-by: Hyunchul Lee --- fsck/de_iter.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- fsck/fsck.h | 3 ++ 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/fsck/de_iter.c b/fsck/de_iter.c index 9fa841e..daa3aa5 100644 --- a/fsck/de_iter.c +++ b/fsck/de_iter.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "exfat_ondisk.h" #include "libexfat.h" @@ -34,6 +35,88 @@ static ssize_t write_block(struct exfat_de_iter *iter, unsigned int block) 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 = MAX((int)exfat->clus_size - + iter->ra_partial_size, 0); + iter->ra_next_clus = 1; + size = exfat->clus_size; + } else { + iter->ra_begin_offset = iter->ra_partial_size; + 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, ra_offset; + 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 { + ra_offset = offset + iter->ra_partial_size; + if (ra_offset >= iter->ra_begin_offset && + ra_offset + iter->ra_partial_size <= + exfat->clus_size) { + device_offset = exfat_c2o(exfat, p_clus) + ra_offset; + ret = posix_fadvise(exfat->blk_dev->dev_fd, + device_offset, iter->ra_partial_size, + POSIX_FADV_WILLNEED); + + iter->ra_begin_offset = + ra_offset + iter->ra_partial_size; + /* TODO: read blocks of the first child directory */ + } + } + + return ret; +#else + return -ENOTSUP; +#endif +} + static ssize_t read_block(struct exfat_de_iter *iter, unsigned int block) { struct exfat *exfat = iter->exfat; @@ -71,6 +154,11 @@ static ssize_t read_block(struct exfat_de_iter *iter, unsigned int block) } } + read_ahead_next_blocks(iter, + (block * iter->read_size) / exfat->clus_size, + (block * iter->read_size) % exfat->clus_size, + desc->p_clus); + device_offset = exfat_c2o(exfat, desc->p_clus) + desc->offset; return exfat_read(exfat->blk_dev->dev_fd, desc->buffer, iter->read_size, device_offset); @@ -82,11 +170,16 @@ int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, 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; + 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; if (!iter->buffer_desc) iter->buffer_desc = exfat->buffer_desc; + 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; diff --git a/fsck/fsck.h b/fsck/fsck.h index 8fc45e0..3214d62 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -38,6 +38,9 @@ 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; -- cgit v1.2.3 From e02c06f6014b38c5569de4eb497eb1d37efdcc6e Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 15 Jul 2020 12:31:18 +0900 Subject: fsck: refine print messages This commit make fsck print the following messages. exfatprogs version : 1.0.3 ERROR: /l0_dir_00: the checksum of a file is wrong. Fix (y/N)? y ERROR: /l0_dir_00/l1_file_01: the checksum of a file is wrong. Fix (y/N)? y /dev/loop28: clean. directories 2, files 6 /dev/loop28: errors 2, fixed 2 Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 121 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 63 insertions(+), 58 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 6d89fa4..4712f6c 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -55,8 +55,8 @@ typedef __u32 bitmap_t; struct exfat_stat { long dir_count; long file_count; - long dir_free_count; - long file_free_count; + long error_count; + long fixed_count; }; struct path_resolve_ctx { @@ -94,6 +94,15 @@ static void usage(char *name) exit(FSCK_EXIT_SYNTAX_ERROR); } +#define fsck_err(parent, inode, fmt, ...) \ +({ \ + resolve_path_parent(&path_resolve_ctx, \ + parent, inode); \ + exfat_err("ERROR: %s: " fmt, \ + path_resolve_ctx.local_path, \ + ##__VA_ARGS__); \ +}) + static struct exfat_inode *alloc_exfat_inode(__u16 attr) { struct exfat_inode *node; @@ -122,10 +131,6 @@ static struct exfat_inode *alloc_exfat_inode(__u16 attr) static void free_exfat_inode(struct exfat_inode *node) { - if (node->attr & ATTR_SUBDIR) - exfat_stat.dir_free_count++; - else - exfat_stat.file_free_count++; free(node); } @@ -360,7 +365,7 @@ static int resolve_path_parent(struct path_resolve_ctx *ctx, resolve_path_parent(&path_resolve_ctx, \ (iter)->parent, inode); \ exfat_repair_ask((iter)->exfat, code, \ - "%s: " fmt, \ + "ERROR: %s: " fmt, \ path_resolve_ctx.local_path, \ ##__VA_ARGS__); \ }) @@ -537,7 +542,7 @@ truncate_file: */ if (!node->is_contiguous && heap_clus(exfat, prev)) return set_fat(exfat, prev, EXFAT_EOF_CLUSTER); - return 0; + return 1; } static bool root_get_clus_count(struct exfat *exfat, struct exfat_inode *node, @@ -556,7 +561,6 @@ static bool root_get_clus_count(struct exfat *exfat, struct exfat_inode *node, if (EXFAT_BITMAP_GET(exfat->alloc_bitmap, clus - EXFAT_FIRST_CLUSTER)) { - resolve_path(&path_resolve_ctx, node); exfat_err("/: cluster is already allocated, or " "there is a loop in cluster chain\n"); return false; @@ -609,6 +613,7 @@ static int boot_region_checksum(struct exfat *exfat) for (i = 1; i < 11; i++) { if (exfat_read(exfat->blk_dev->dev_fd, sect, size, i * size) != (ssize_t)size) { + exfat_err("failed to read boot regions\n"); ret = -EIO; goto out; } @@ -617,6 +622,7 @@ static int boot_region_checksum(struct exfat *exfat) if (exfat_read(exfat->blk_dev->dev_fd, sect, size, 11 * size) != (ssize_t)size) { + exfat_err("failed to read a boot checksum sector\n"); ret = -EIO; goto out; } @@ -781,38 +787,41 @@ static __le16 file_calc_checksum(struct exfat_de_iter *iter) return checksum; } -static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) +/* + * return 0 if there are no errors, or 1 if errors are fixed, or + * an error code + */ +static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) { struct exfat *exfat = iter->exfat; struct exfat_dentry *dentry; - bool ret = true; + int ret = 0; uint16_t checksum; - if (check_clus_chain(exfat, node)) - return false; + ret = check_clus_chain(exfat, node); + if (ret < 0) + return ret; if (node->size > le32_to_cpu(exfat->bs->bsx.clu_count) * (uint64_t)exfat->clus_size) { - resolve_path_parent(&path_resolve_ctx, iter->parent, node); - exfat_err("size %" PRIu64 " is greater than cluster heap: %s\n", - node->size, path_resolve_ctx.local_path); - ret = false; + fsck_err(iter->parent, node, + "size %" PRIu64 " is greater than cluster heap\n", + node->size); + ret = -EINVAL; } if (node->size == 0 && node->is_contiguous) { - resolve_path_parent(&path_resolve_ctx, iter->parent, node); - exfat_err("empty, but marked as contiguous: %s\n", - path_resolve_ctx.local_path); - ret = false; + fsck_err(iter->parent, node, + "empty, but marked as contiguous\n"); + ret = -EINVAL; } if ((node->attr & ATTR_SUBDIR) && node->size % exfat->clus_size != 0) { - resolve_path_parent(&path_resolve_ctx, iter->parent, node); - exfat_err("directory size %" PRIu64 " is not divisible by %d: %s\n", - node->size, exfat->clus_size, - path_resolve_ctx.local_path); - ret = false; + fsck_err(iter->parent, node, + "directory size %" PRIu64 " is not divisible by %d\n", + node->size, exfat->clus_size); + ret = -EINVAL; } checksum = file_calc_checksum(iter); @@ -822,8 +831,9 @@ static bool check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) "the checksum of a file is wrong")) { exfat_de_iter_get_dirty(iter, 0, &dentry); dentry->file_checksum = cpu_to_le16(checksum); + ret = 1; } else - ret = false; + ret = -EINVAL; } return ret; @@ -912,21 +922,18 @@ static int read_file(struct exfat_de_iter *de_iter, *new_node = NULL; ret = read_file_dentries(de_iter, &node, dentry_count); - if (ret) { - exfat_err("corrupted file directory entries.\n"); + if (ret) return ret; - } ret = check_inode(de_iter, node); - if (!ret) { - exfat_err("corrupted file directory entries.\n"); + if (ret < 0) { free_exfat_inode(node); return -EINVAL; } node->dentry_file_offset = exfat_de_iter_file_offset(de_iter); *new_node = node; - return 0; + return ret; } static bool read_volume_label(struct exfat_de_iter *iter) @@ -1097,7 +1104,8 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) if (ret == EOF) { break; } else if (ret) { - exfat_err("failed to get a dentry. %d\n", ret); + fsck_err(dir->parent, dir, + "failed to get a dentry. %d\n", ret); goto err; } @@ -1106,9 +1114,12 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) switch (dentry->type) { case EXFAT_FILE: ret = read_file(de_iter, &node, &dentry_count); - if (ret) { - exfat_err("failed to verify file. %d\n", ret); + if (ret < 0) { + exfat_stat.error_count++; goto err; + } else if (ret) { + exfat_stat.error_count++; + exfat_stat.fixed_count++; } if ((node->attr & ATTR_SUBDIR) && node->size) { @@ -1308,10 +1319,9 @@ static int exfat_filesystem_check(struct exfat *exfat) dir = list_entry(exfat->dir_list.next, struct exfat_inode, list); if (!(dir->attr & ATTR_SUBDIR)) { - resolve_path(&path_resolve_ctx, dir); - exfat_err("failed to travel directories. " - "the node is not directory: %s\n", - path_resolve_ctx.local_path); + fsck_err(dir->parent, dir, + "failed to travel directories. " + "the node is not directory\n"); ret = -EINVAL; goto out; } @@ -1319,7 +1329,7 @@ static int exfat_filesystem_check(struct exfat *exfat) dir_errors = read_children(exfat, dir); if (dir_errors) { resolve_path(&path_resolve_ctx, dir); - exfat_err("failed to check dentries: %s\n", + exfat_debug("failed to check dentries: %s\n", path_resolve_ctx.local_path); ret = dir_errors; } @@ -1361,7 +1371,8 @@ static int exfat_root_dir_check(struct exfat *exfat) return 0; } -static void exfat_show_info(struct exfat *exfat) +static void exfat_show_info(struct exfat *exfat, const char *dev_name, + int errors) { exfat_info("Bytes per sector: %d\n", 1 << exfat->bs->bsx.sect_size_bits); @@ -1372,16 +1383,13 @@ static void exfat_show_info(struct exfat *exfat) le32_to_cpu(exfat->bs->bsx.clu_count)); exfat_info("Cluster heap offset: %#x\n", le32_to_cpu(exfat->bs->bsx.clu_offset)); -} -static void exfat_show_stat(void) -{ - exfat_debug("Found directories: %ld\n", exfat_stat.dir_count); - exfat_debug("Found files: %ld\n", exfat_stat.file_count); - exfat_debug("Found leak directories: %ld\n", - exfat_stat.dir_count - exfat_stat.dir_free_count); - exfat_debug("Found leak files: %ld\n", - exfat_stat.file_count - exfat_stat.file_free_count); + printf("%s: %s. directories %ld, files %ld\n", dev_name, + errors ? "checking stopped" : "clean", + exfat_stat.dir_count, exfat_stat.file_count); + if (errors || exfat->dirty) + printf("%s: errors %ld, fixed %ld\n", dev_name, + exfat_stat.error_count, exfat_stat.fixed_count); } int main(int argc, char * const argv[]) @@ -1478,8 +1486,6 @@ int main(int argc, char * const argv[]) if (ret) goto err; - exfat_show_info(exfat); - exfat_debug("verifying root directory...\n"); ret = exfat_root_dir_check(exfat); if (ret) { @@ -1489,20 +1495,18 @@ int main(int argc, char * const argv[]) exfat_debug("verifying directory entries...\n"); ret = exfat_filesystem_check(exfat); - if (ret) { - exfat_err("failed to verify directory entries.\n"); + if (ret) goto out; - } if (ui.ei.writeable && fsync(bd.dev_fd)) { + exfat_err("failed to sync\n"); ret = -EIO; goto out; } exfat_mark_volume_dirty(exfat, false); - printf("%s: clean\n", ui.ei.dev_name); out: - exfat_show_stat(); + exfat_show_info(exfat, ui.ei.dev_name, ret); err: if (ret == -EINVAL) exit_code = FSCK_EXIT_ERRORS_LEFT; @@ -1512,6 +1516,7 @@ err: exit_code = FSCK_EXIT_CORRECTED; else exit_code = FSCK_EXIT_NO_ERRORS; + free_exfat(exfat); close(bd.dev_fd); return exit_code; -- cgit v1.2.3 From 00ff69a087a27495c23af687231a25aeee5b78ed Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 15 Jul 2020 17:21:26 +0900 Subject: fsck: print volume size in the human-readable format print sizes in the human-readable format. exfatprogs version : 1.0.3 sector size: 512.00 B cluster size: 32.00 KB volume size: 1.00 GB /dev/loop28: clean. directories 149, files 1332 Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 4712f6c..167bbc3 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1371,18 +1371,40 @@ static int exfat_root_dir_check(struct exfat *exfat) return 0; } +static char *bytes_to_human_readable(size_t bytes) +{ + static const char * const units[] = {"B", "KB", "MB", "GB", "TB", "PB"}; + static char buf[15*4]; + unsigned int i, shift, quoti, remain; + + shift = 0; + for (i = 0; i < sizeof(units)/sizeof(units[0]); i++) { + if (bytes / (1ULL << (shift + 10)) == 0) + break; + shift += 10; + } + + quoti = (unsigned int)(bytes / (1ULL << shift)); + remain = 0; + if (shift > 0) { + remain = (unsigned int) + ((bytes & ((1ULL << shift) - 1)) >> (shift - 10)); + remain = (remain * 100) / 1024; + } + + snprintf(buf, sizeof(buf), "%u.%02u %s", quoti, remain, units[i]); + return buf; +} + static void exfat_show_info(struct exfat *exfat, const char *dev_name, int errors) { - exfat_info("Bytes per sector: %d\n", - 1 << exfat->bs->bsx.sect_size_bits); - exfat_info("Sectors per cluster: %d\n", - 1 << exfat->bs->bsx.sect_per_clus_bits); - exfat_info("Cluster heap count: %d(0x%x)\n", - le32_to_cpu(exfat->bs->bsx.clu_count), - le32_to_cpu(exfat->bs->bsx.clu_count)); - exfat_info("Cluster heap offset: %#x\n", - le32_to_cpu(exfat->bs->bsx.clu_offset)); + exfat_info("sector size: %s\n", + bytes_to_human_readable(1 << exfat->bs->bsx.sect_size_bits)); + exfat_info("cluster size: %s\n", + bytes_to_human_readable(exfat->clus_size)); + exfat_info("volume size: %s\n", + bytes_to_human_readable(exfat->blk_dev->size)); printf("%s: %s. directories %ld, files %ld\n", dev_name, errors ? "checking stopped" : "clean", -- cgit v1.2.3 From 31711bda99eb49cda85ab2e55e6b0f005bd8c968 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 15 Jul 2020 17:28:47 +0900 Subject: fsck: remove unnecessary fields of struct exfat_inode Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 1 - fsck/fsck.h | 1 - 2 files changed, 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 167bbc3..be88cba 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -931,7 +931,6 @@ static int read_file(struct exfat_de_iter *de_iter, return -EINVAL; } - node->dentry_file_offset = exfat_de_iter_file_offset(de_iter); *new_node = node; return ret; } diff --git a/fsck/fsck.h b/fsck/fsck.h index 3214d62..6c91fac 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -20,7 +20,6 @@ struct exfat_inode { __u16 attr; uint64_t size; bool is_contiguous; - off_t dentry_file_offset; __le16 name[0]; /* only for directory */ }; -- cgit v1.2.3 From bf1fb149aff1d4335bd173eec5267f200eeb7a19 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Thu, 16 Jul 2020 08:32:55 +0900 Subject: fsck: repair: zero-byte file which has NotFatChain attribute If a file is zero-byte and the file has the NotFatChain" attribute, clear the attribute from the file. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 10 +++++++--- fsck/repair.c | 1 + fsck/repair.h | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index be88cba..8c49532 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -811,9 +811,13 @@ static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) } if (node->size == 0 && node->is_contiguous) { - fsck_err(iter->parent, node, - "empty, but marked as contiguous\n"); - ret = -EINVAL; + if (repair_file_ask(iter, node, ER_FILE_ZERO_NOFAT, + "empty, but has no Fat chain\n")) { + exfat_de_iter_get_dirty(iter, 1, &dentry); + dentry->stream_flags &= ~EXFAT_SF_CONTIGUOUS; + ret = 1; + } else + ret = -EINVAL; } if ((node->attr & ATTR_SUBDIR) && diff --git a/fsck/repair.c b/fsck/repair.c index 1440ef8..ca55722 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -41,6 +41,7 @@ static struct exfat_repair_problem problems[] = { {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_DEFAULT_NO, ERP_FIX}, }; static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) diff --git a/fsck/repair.h b/fsck/repair.h index 781736a..6a34b9b 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -13,6 +13,7 @@ #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; -- cgit v1.2.3 From 97ced29e3495c055f01a92cdb99c03a9d635255f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 16 Jul 2020 20:42:36 +0900 Subject: exfatprogs: fix typos in 'mkfs : add boundary-align option' Signed-off-by: Namjae Jeon --- README.md | 4 ++-- manpages/mkfs.exfat.8 | 8 ++++---- mkfs/mkfs.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2e5f2dc..f9b7f23 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Usage example: 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 alignement(KB or MB or Byte) user want + 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 @@ -75,4 +75,4 @@ If you have any issues, please create [issues][1] or contact to [Namjae Jeon](ma ## 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`). \ No newline at end of file +* Make sure you add 'Signed-Off' information to your commits (e. g. `git commit --signoff`). diff --git a/manpages/mkfs.exfat.8 b/manpages/mkfs.exfat.8 index 0c28f03..0bd8ffc 100644 --- a/manpages/mkfs.exfat.8 +++ b/manpages/mkfs.exfat.8 @@ -5,7 +5,7 @@ mkfs.exfat \- create an exFAT filesystem .B mkfs.exfat [ .B \-b -.I boundary_alignement +.I boundary_alignment ] [ .B \-c .I cluster_size @@ -39,9 +39,9 @@ SCSI disk, use: .PP .SH OPTIONS .TP -.BI \-b " boundary_alignement" -Specify the aligment for FAT and start of cluster. -Boundary alignement can be specified in m/M for megabytes +.BI \-b " boundary_alignment" +Specify the alignment for FAT and start of cluster. +Boundary alignment can be specified in m/M for megabytes and k/K for kilobytes. It should be a power of two. Some media like sdcard need this. .TP diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 60999b1..f75a287 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -405,7 +405,7 @@ static void usage(void) fprintf(stderr, "Usage: mkfs.exfat\n"); fprintf(stderr, "\t-L | --volume-label=label Set volume label\n"); fprintf(stderr, "\t-c | --cluster-size=size(or suffixed by 'K' or 'M') Specify cluster size\n"); - fprintf(stderr, "\t-b | --boundary-align=size(or suffixed by 'K' or 'M') Specify boundary alignement\n"); + fprintf(stderr, "\t-b | --boundary-align=size(or suffixed by 'K' or 'M') Specify boundary alignment\n"); fprintf(stderr, "\t-f | --full-format Full format\n"); fprintf(stderr, "\t-V | --version Show version\n"); fprintf(stderr, "\t-v | --verbose Print debug\n"); @@ -431,7 +431,7 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, { int clu_len; if (ui->boundary_align < bd->sector_size) { - exfat_err("boundary alignement is too small (min %d)\n", + exfat_err("boundary alignment is too small (min %d)\n", bd->sector_size); return -1; } @@ -442,7 +442,7 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len, ui->boundary_align); if (bd->size <= finfo.clu_byte_off) { - exfat_err("boundary alignement is too big\n"); + exfat_err("boundary alignment is too big\n"); return -1; } finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / -- cgit v1.2.3 From 00576e3b737794115a991bff7969ef89587d08e4 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 16 Jul 2020 20:35:33 +0900 Subject: mkfs: fix WARNING: Missing a blank line after declarations Signed-off-by: Namjae Jeon --- mkfs/mkfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index f75a287..9fff978 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -430,6 +430,7 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, struct exfat_user_input *ui) { int clu_len; + if (ui->boundary_align < bd->sector_size) { exfat_err("boundary alignment is too small (min %d)\n", bd->sector_size); -- cgit v1.2.3 From efaf770382115569fdf90aeb7725599d40f0fe84 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 17 Jul 2020 09:20:12 +0900 Subject: exfatprogs: run checkpatch.pl on patches run checkpatch.pl on patches in a pull request. Signed-off-by: Namjae Jeon --- .travis.yml | 5 +++++ .travis_get_mainline_kernel | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100755 .travis_get_mainline_kernel diff --git a/.travis.yml b/.travis.yml index c192747..6ab3cc2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,10 +8,15 @@ notifications: 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 diff --git a/.travis_get_mainline_kernel b/.travis_get_mainline_kernel new file mode 100755 index 0000000..3356d15 --- /dev/null +++ b/.travis_get_mainline_kernel @@ -0,0 +1,37 @@ +#!/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 + +wget https://cdn.kernel.org/pub/linux/kernel/v5.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 -- cgit v1.2.3 From 454d3dbb1e6033cc16953b65d0fba96c61d4d7b7 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jul 2020 11:45:13 +0900 Subject: fsck: improve readahead if a buffer isn't filled with directory entries, this commit makes fsck not read blocks ahead of time. and if fsck reads the last, this commit makes fsck read blocks of the next direcotry in advance. 64GB Samsung Class10 UHS-I Pro sdcard is filled with 9947 directories and 16504 files by fsstress. After this patch, the elpased time decreases from 24.95 secs to 11.61 secs by about 46%. Signed-off-by: Hyunchul Lee --- fsck/de_iter.c | 75 ++++++++++++++++++++++++++++++++++++++++++++-------------- fsck/fsck.c | 6 +---- 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/fsck/de_iter.c b/fsck/de_iter.c index daa3aa5..bc95c49 100644 --- a/fsck/de_iter.c +++ b/fsck/de_iter.c @@ -45,12 +45,11 @@ static int read_ahead_first_blocks(struct exfat_de_iter *iter) clus_count = iter->parent->size / exfat->clus_size; if (clus_count > 1) { - iter->ra_begin_offset = MAX((int)exfat->clus_size - - iter->ra_partial_size, 0); + iter->ra_begin_offset = 0; iter->ra_next_clus = 1; size = exfat->clus_size; } else { - iter->ra_begin_offset = iter->ra_partial_size; + iter->ra_begin_offset = 0; iter->ra_next_clus = 0; size = iter->ra_partial_size; } @@ -73,7 +72,7 @@ static int read_ahead_next_blocks(struct exfat_de_iter *iter, struct exfat *exfat = iter->exfat; off_t device_offset; clus_t clus_count, ra_clus, ra_p_clus; - unsigned int size, ra_offset; + unsigned int size; int ret = 0; clus_count = iter->parent->size / exfat->clus_size; @@ -96,18 +95,16 @@ static int read_ahead_next_blocks(struct exfat_de_iter *iter, iter->ra_begin_offset = 0; } } else { - ra_offset = offset + iter->ra_partial_size; - if (ra_offset >= iter->ra_begin_offset && - ra_offset + iter->ra_partial_size <= + if (offset >= iter->ra_begin_offset && + offset + iter->ra_partial_size <= exfat->clus_size) { - device_offset = exfat_c2o(exfat, p_clus) + ra_offset; + 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 = - ra_offset + iter->ra_partial_size; - /* TODO: read blocks of the first child directory */ + offset + iter->ra_partial_size; } } @@ -117,12 +114,40 @@ static int read_ahead_next_blocks(struct exfat_de_iter *iter, #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; - int ret; + ssize_t ret; desc = &iter->buffer_desc[block & 0x01]; if (block == 0) { @@ -154,14 +179,24 @@ static ssize_t read_block(struct exfat_de_iter *iter, unsigned int block) } } - read_ahead_next_blocks(iter, - (block * iter->read_size) / exfat->clus_size, - (block * iter->read_size) % exfat->clus_size, - desc->p_clus); - device_offset = exfat_c2o(exfat, desc->p_clus) + desc->offset; - return exfat_read(exfat->blk_dev->dev_fd, desc->buffer, + 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, @@ -175,10 +210,14 @@ int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat, 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"); diff --git a/fsck/fsck.c b/fsck/fsck.c index 8c49532..32944fe 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1090,11 +1090,8 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) struct exfat_inode *node = NULL; struct exfat_dentry *dentry; int dentry_count; - struct list_head sub_dir_list; struct exfat_de_iter *de_iter; - INIT_LIST_HEAD(&sub_dir_list); - de_iter = &exfat->de_iter; ret = exfat_de_iter_init(de_iter, exfat, dir); if (ret == EOF) @@ -1128,7 +1125,7 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) if ((node->attr & ATTR_SUBDIR) && node->size) { node->parent = dir; list_add_tail(&node->sibling, &dir->children); - list_add_tail(&node->list, &sub_dir_list); + list_add_tail(&node->list, &exfat->dir_list); } else free_exfat_inode(node); break; @@ -1168,7 +1165,6 @@ static int read_children(struct exfat *exfat, struct exfat_inode *dir) exfat_de_iter_advance(de_iter, dentry_count); } out: - list_splice(&sub_dir_list, &exfat->dir_list); exfat_de_iter_flush(de_iter); return 0; err: -- cgit v1.2.3 From bf40e883e412982377d2d82e898c4024125fa5b3 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jul 2020 12:14:45 +0900 Subject: fsck: improve log messages fsck prints the number of files corrupted and the number of files fixed. the previous message could make users confused. So modity the message as below. /dev/loop29: files corrupted 2, files fixed 2 Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 32944fe..1104fcc 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1409,7 +1409,7 @@ static void exfat_show_info(struct exfat *exfat, const char *dev_name, errors ? "checking stopped" : "clean", exfat_stat.dir_count, exfat_stat.file_count); if (errors || exfat->dirty) - printf("%s: errors %ld, fixed %ld\n", dev_name, + printf("%s: files corrupted %ld, files fixed %ld\n", dev_name, exfat_stat.error_count, exfat_stat.fixed_count); } -- cgit v1.2.3 From 7d273bcb138a37db483c928e3e83d4a9f49f9f21 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 24 Jul 2020 15:26:12 +0900 Subject: fsck: repair: enable fsck to fix zero-byte file which has NoFatChain Enable fsck to fix a zero-byte file which has the NotFatChain attribute. Signed-off-by: Hyunchul Lee --- fsck/repair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/repair.c b/fsck/repair.c index ca55722..19a2b0d 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -41,7 +41,7 @@ static struct exfat_repair_problem problems[] = { {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_DEFAULT_NO, ERP_FIX}, + {ER_FILE_ZERO_NOFAT, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, }; static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) -- cgit v1.2.3 From 532b75ce75b5a9b4fa3830e8ced142c68a25e98e Mon Sep 17 00:00:00 2001 From: Devidas Jadhav Date: Sun, 26 Jul 2020 21:12:56 +0530 Subject: exfatprogs: Parsing VER to get major number Signed-off-by: evidas Jadhav --- .travis_get_mainline_kernel | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis_get_mainline_kernel b/.travis_get_mainline_kernel index 3356d15..76b3a3a 100755 --- a/.travis_get_mainline_kernel +++ b/.travis_get_mainline_kernel @@ -22,7 +22,9 @@ if [ "z$VER" = "z" ]; then exit 1 fi -wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-"$VER".tar.gz +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 -- cgit v1.2.3 From dd0c36e5d070eaf29b776ccb3c053b54d05b2147 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 31 Jul 2020 08:32:04 +0900 Subject: fsck: check bitmap for each allocated cluster always Because repairing bitmap is not enabled, fsck must always check bitmap for each allocated clusters. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 1104fcc..9732afb 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -471,6 +471,18 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) return -EINVAL; } + if (!EXFAT_BITMAP_GET(exfat->disk_bitmap, + clus - EXFAT_FIRST_CLUSTER)) { + if (repair_file_ask(&exfat->de_iter, node, + ER_FILE_INVALID_CLUS, + "cluster is marked as free. truncate to %" PRIu64 " bytes", + count * exfat->clus_size)) + goto truncate_file; + + else + return -EINVAL; + } + /* This cluster is allocated or not */ if (get_next_clus(exfat, node, clus, &next)) goto truncate_file; @@ -485,20 +497,6 @@ static int check_clus_chain(struct exfat *exfat, struct exfat_inode *node) count * exfat->clus_size)) goto truncate_file; - else - return -EINVAL; - } - } else { - if (!EXFAT_BITMAP_GET(exfat->disk_bitmap, - clus - EXFAT_FIRST_CLUSTER)) { - if (repair_file_ask(&exfat->de_iter, node, - ER_FILE_INVALID_CLUS, - "cluster is marked as free. " - "truncate to %" - PRIu64 " bytes", - count * exfat->clus_size)) - goto truncate_file; - else return -EINVAL; } -- cgit v1.2.3 From 7181a4260d747b0a035ab66554b2474d6a90693e Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 31 Jul 2020 09:59:29 +0900 Subject: exfatprogs: add the execution time comparisons among fsck implementations Signed-off-by: Hyunchul Lee --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index f9b7f23..af6a32c 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,23 @@ Usage example: tune.exfat -L "new label" /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). -- cgit v1.2.3 From d9fbffd53e2e1ec89584b8c6931d8984e9894f4b Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 27 Jul 2020 09:57:31 +0900 Subject: exfatprogs: release 1.0.4 version 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. Signed-off-by: Hyunchul Lee --- NEWS | 18 ++++++++++++++++++ include/version.h | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 064ba7b..dd48c5f 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,21 @@ +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 ====================================== diff --git a/include/version.h b/include/version.h index 1ec8a63..e463903 100644 --- a/include/version.h +++ b/include/version.h @@ -5,6 +5,6 @@ #ifndef _VERSION_H -#define EXFAT_PROGS_VERSION "1.0.3" +#define EXFAT_PROGS_VERSION "1.0.4" #endif /* !_VERSION_H */ -- cgit v1.2.3 From 4051b6a604c4e7d35a61e2784e16dffada1e08ab Mon Sep 17 00:00:00 2001 From: Alexander Tsoy Date: Wed, 5 Aug 2020 05:02:11 +0300 Subject: manpages: remove spurious .TP from man 8 fsck.exfat Signed-off-by: Alexander Tsoy --- manpages/fsck.exfat.8 | 1 - 1 file changed, 1 deletion(-) diff --git a/manpages/fsck.exfat.8 b/manpages/fsck.exfat.8 index b02a056..b30072c 100644 --- a/manpages/fsck.exfat.8 +++ b/manpages/fsck.exfat.8 @@ -38,7 +38,6 @@ Prints the version number and exits. .TP .B \-y Repair the filesystem answering yes to all questions. -.TP .SH SEE ALSO .BR fsck (8), .BR fstab (5), -- cgit v1.2.3 From a96c562ae373bad98e3c8a11532bf281a94ea2c0 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Tue, 11 Aug 2020 15:14:56 +0900 Subject: fsck: repair: prevents from repairing some cases without user permits This patch prevents from repairing some cases without user permits. Signed-off-by: Hyunchul Lee --- fsck/repair.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fsck/repair.c b/fsck/repair.c index 19a2b0d..fa6cdfb 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -33,15 +33,15 @@ static const char *prompts[] = { }; static struct exfat_repair_problem problems[] = { - {ER_BS_CHECKSUM, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, - {ER_DE_CHECKSUM, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, - {ER_FILE_VALID_SIZE, ERF_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, + {ER_BS_CHECKSUM, ERF_PREEN_YES, 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_DEFAULT_YES | ERF_PREEN_YES, ERP_FIX}, + {ER_FILE_ZERO_NOFAT, ERF_PREEN_YES, ERP_FIX}, }; static struct exfat_repair_problem *find_problem(er_problem_code_t prcode) -- cgit v1.2.3 From 5a2896138e260265588c19167963eb8de96567cd Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 24 Aug 2020 15:24:21 +0900 Subject: fsck: repair: restore boot region from backup boot region if the boot region is corrupted, restore it from the backup boot region. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 150 ++++++++++++++++++++++++++++++++++++---------------------- fsck/repair.c | 1 + fsck/repair.h | 1 + 3 files changed, 95 insertions(+), 57 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 9732afb..981d6ab 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -204,20 +204,11 @@ static void free_exfat(struct exfat *exfat) } } -static struct exfat *alloc_exfat(struct exfat_blk_dev *bd, struct pbr *bs) +static int init_exfat(struct exfat *exfat, struct pbr *bs) { - struct exfat *exfat; int i; - exfat = (struct exfat *)calloc(1, sizeof(*exfat)); - if (!exfat) { - free(bs); - exfat_err("failed to allocate exfat\n"); - return NULL; - } - INIT_LIST_HEAD(&exfat->dir_list); - exfat->blk_dev = bd; exfat->bs = bs; exfat->clus_count = le32_to_cpu(bs->bsx.clu_count); exfat->clus_size = EXFAT_CLUSTER_SIZE(bs); @@ -250,10 +241,10 @@ static struct exfat *alloc_exfat(struct exfat_blk_dev *bd, struct pbr *bs) if (!exfat->buffer_desc[i].dirty) goto err; } - return exfat; + return 0; err: free_exfat(exfat); - return NULL; + return -ENOMEM; } static void exfat_free_dir_list(struct exfat *exfat) @@ -592,33 +583,33 @@ off_t exfat_c2o(struct exfat *exfat, unsigned int clus) exfat->bs->bsx.sect_per_clus_bits)); } -static int boot_region_checksum(struct exfat *exfat) +static int boot_region_checksum(struct exfat_blk_dev *bd, int bs_offset) { void *sect; unsigned int i; uint32_t checksum; int ret = 0; - unsigned short size; + unsigned int size; - size = EXFAT_SECTOR_SIZE(exfat->bs); + size = bd->sector_size; sect = malloc(size); if (!sect) return -ENOMEM; checksum = 0; - - boot_calc_checksum((unsigned char *)exfat->bs, size, true, &checksum); - for (i = 1; i < 11; i++) { - if (exfat_read(exfat->blk_dev->dev_fd, sect, size, i * size) != + for (i = 0; i < 11; i++) { + if (exfat_read(bd->dev_fd, sect, size, + bs_offset * size + i * size) != (ssize_t)size) { - exfat_err("failed to read boot regions\n"); + exfat_err("failed to read boot region\n"); ret = -EIO; goto out; } - boot_calc_checksum(sect, size, false, &checksum); + boot_calc_checksum(sect, size, i == 0, &checksum); } - if (exfat_read(exfat->blk_dev->dev_fd, sect, size, 11 * size) != + if (exfat_read(bd->dev_fd, sect, size, + bs_offset * size + 11 * size) != (ssize_t)size) { exfat_err("failed to read a boot checksum sector\n"); ret = -EIO; @@ -627,33 +618,15 @@ static int boot_region_checksum(struct exfat *exfat) for (i = 0; i < size/sizeof(checksum); i++) { if (le32_to_cpu(((__le32 *)sect)[i]) != checksum) { - if (exfat_repair_ask(exfat, ER_BS_CHECKSUM, - "checksums of boot sector are not correct. " - "%#x, but expected %#x", - le32_to_cpu(((__le32 *)sect)[i]), checksum)) { - goto out_write; - } else { - ret = -EINVAL; - goto out; - } + exfat_err("checksum of boot region is not correct. %#x, but expected %#x\n", + le32_to_cpu(((__le32 *)sect)[i]), checksum); + ret = -EINVAL; + goto out; } } out: free(sect); return ret; - -out_write: - for (i = 0; i < size/sizeof(checksum); i++) - ((__le32 *)sect)[i] = cpu_to_le32(checksum); - - if (exfat_write(exfat->blk_dev->dev_fd, - sect, size, size * 11) != size) { - exfat_err("failed to write checksum sector\n"); - free(sect); - return -EIO; - } - free(sect); - return 0; } static int exfat_mark_volume_dirty(struct exfat *exfat, bool dirty) @@ -683,18 +656,21 @@ static int exfat_mark_volume_dirty(struct exfat *exfat, bool dirty) return 0; } -static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr) +static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr, + int bs_offset) { struct pbr *bs; + int ret = -EINVAL; + *pbr = NULL; bs = (struct pbr *)malloc(sizeof(struct pbr)); if (!bs) { exfat_err("failed to allocate memory\n"); return -ENOMEM; } - if (exfat_read(bd->dev_fd, bs, sizeof(*bs), 0) != - (ssize_t)sizeof(*bs)) { + if (exfat_read(bd->dev_fd, bs, sizeof(*bs), + bs_offset * bd->sector_size) != (ssize_t)sizeof(*bs)) { exfat_err("failed to read a boot sector\n"); free(bs); return -EIO; @@ -705,6 +681,10 @@ static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr) goto err; } + ret = boot_region_checksum(bd, bs_offset); + if (ret < 0) + goto err; + if (EXFAT_SECTOR_SIZE(bs) < 512 || EXFAT_SECTOR_SIZE(bs) > 4 * KB) { exfat_err("too small or big sector size: %d\n", EXFAT_SECTOR_SIZE(bs)); @@ -747,7 +727,61 @@ static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr) return 0; err: free(bs); - return -EINVAL; + return ret; +} + +static int restore_boot_region(struct exfat_blk_dev *bd) +{ + int i; + char *sector; + + sector = malloc(bd->sector_size); + if (!sector) + return -ENOMEM; + + for (i = 0; i < 12; i++) { + if (exfat_read(bd->dev_fd, sector, bd->sector_size, + BACKUP_BOOT_SEC_IDX * bd->sector_size + + i * bd->sector_size) != + (ssize_t)bd->sector_size) + return -EIO; + if (i == 0) + ((struct pbr *)sector)->bsx.perc_in_use = 0xff; + + if (exfat_write(bd->dev_fd, sector, bd->sector_size, + BOOT_SEC_IDX * bd->sector_size + + i * bd->sector_size) != + (ssize_t)bd->sector_size) + return -EIO; + } + if (fsync(bd->dev_fd)) + return -EIO; + free(sector); + return 0; +} + +static int exfat_boot_region_check(struct exfat *exfat, struct pbr **bs) +{ + int ret; + + ret = read_boot_region(exfat->blk_dev, bs, BOOT_SEC_IDX); + if (ret == -EINVAL && exfat_repair_ask(exfat, ER_BS_BOOT_REGION, + "boot region is corrupted. try to restore the region from backup" + )) { + ret = read_boot_region(exfat->blk_dev, bs, BACKUP_BOOT_SEC_IDX); + if (ret < 0) { + exfat_err("backup boot region is also corrupted"); + return ret; + } + ret = restore_boot_region(exfat->blk_dev); + if (ret < 0) { + exfat_err("failed to restore boot region from backup"); + free(*bs); + *bs = NULL; + return ret; + } + } + return ret; } static void dentry_calc_checksum(struct exfat_dentry *dentry, @@ -1485,26 +1519,28 @@ int main(int argc, char * const argv[]) return FSCK_EXIT_OPERATION_ERROR; } - ret = read_boot_region(&bd, &bs); - if (ret) - goto err; - - exfat = alloc_exfat(&bd, bs); + exfat = (struct exfat *)calloc(1, sizeof(*exfat)); if (!exfat) { + exfat_err("failed to allocate exfat\n"); ret = -ENOMEM; goto err; } + exfat->blk_dev = &bd; exfat->options = ui.options; - if (exfat_mark_volume_dirty(exfat, true)) { - ret = -EIO; + ret = exfat_boot_region_check(exfat, &bs); + if (ret) goto err; - } - ret = boot_region_checksum(exfat); + ret = init_exfat(exfat, bs); if (ret) goto err; + if (exfat_mark_volume_dirty(exfat, true)) { + ret = -EIO; + goto err; + } + exfat_debug("verifying root directory...\n"); ret = exfat_root_dir_check(exfat); if (ret) { diff --git a/fsck/repair.c b/fsck/repair.c index fa6cdfb..c79d379 100644 --- a/fsck/repair.c +++ b/fsck/repair.c @@ -34,6 +34,7 @@ static const char *prompts[] = { 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}, diff --git a/fsck/repair.h b/fsck/repair.h index 6a34b9b..f7286b9 100644 --- a/fsck/repair.h +++ b/fsck/repair.h @@ -6,6 +6,7 @@ #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 -- cgit v1.2.3 From ea3ca90b53ea6c370fda7f893b3ac061a041aa50 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Mon, 24 Aug 2020 16:10:45 +0900 Subject: fsck: fix return value of check_inode even if files cannot be repaired, check_inode could return the value which means files are valid. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 981d6ab..3618b0d 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -829,6 +829,7 @@ static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) struct exfat_dentry *dentry; int ret = 0; uint16_t checksum; + bool valid = true; ret = check_clus_chain(exfat, node); if (ret < 0) @@ -839,7 +840,7 @@ static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) fsck_err(iter->parent, node, "size %" PRIu64 " is greater than cluster heap\n", node->size); - ret = -EINVAL; + valid = false; } if (node->size == 0 && node->is_contiguous) { @@ -849,7 +850,7 @@ static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) dentry->stream_flags &= ~EXFAT_SF_CONTIGUOUS; ret = 1; } else - ret = -EINVAL; + valid = false; } if ((node->attr & ATTR_SUBDIR) && @@ -857,7 +858,7 @@ static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) fsck_err(iter->parent, node, "directory size %" PRIu64 " is not divisible by %d\n", node->size, exfat->clus_size); - ret = -EINVAL; + valid = false; } checksum = file_calc_checksum(iter); @@ -869,10 +870,10 @@ static int check_inode(struct exfat_de_iter *iter, struct exfat_inode *node) dentry->file_checksum = cpu_to_le16(checksum); ret = 1; } else - ret = -EINVAL; + valid = false; } - return ret; + return valid ? ret : -EINVAL; } static int read_file_dentries(struct exfat_de_iter *iter, -- cgit v1.2.3 From 4c43c7488c5deebf06756aa09771d4dde0bef72b Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Thu, 27 Aug 2020 16:47:03 +0900 Subject: fsck: fix return value of read_boot_region even if boot sector is invalid, read_boot_region could return valid value. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 3618b0d..39c193d 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -672,8 +672,8 @@ static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr, if (exfat_read(bd->dev_fd, bs, sizeof(*bs), bs_offset * bd->sector_size) != (ssize_t)sizeof(*bs)) { exfat_err("failed to read a boot sector\n"); - free(bs); - return -EIO; + ret = -EIO; + goto err; } if (memcmp(bs->bpb.oem_name, "EXFAT ", 8) != 0) { @@ -685,6 +685,7 @@ static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr, if (ret < 0) goto err; + ret = -EINVAL; if (EXFAT_SECTOR_SIZE(bs) < 512 || EXFAT_SECTOR_SIZE(bs) > 4 * KB) { exfat_err("too small or big sector size: %d\n", EXFAT_SECTOR_SIZE(bs)); -- cgit v1.2.3 From facad7764036e885b0fce9427a5d5d467298ce93 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Thu, 27 Aug 2020 16:48:34 +0900 Subject: fsck: fix an error message in read_boot_region Remove a new line in the error message. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 39c193d..a2ca143 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -710,7 +710,7 @@ static int read_boot_region(struct exfat_blk_dev *bd, struct pbr **pbr, if (le64_to_cpu(bs->bsx.vol_length) * EXFAT_SECTOR_SIZE(bs) > bd->size) { - exfat_err("too large sector count: %" PRIu64 "\n, expected: %llu\n", + exfat_err("too large sector count: %" PRIu64 ", expected: %llu\n", le64_to_cpu(bs->bsx.vol_length), bd->num_sectors); goto err; -- cgit v1.2.3 From 7c0f6847d62e0970ae5e9e1a0ce94e42d909d78e Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Thu, 27 Aug 2020 17:01:27 +0900 Subject: fsck: fix error messages in exfat_boot_region_check Add new line characters. Signed-off-by: Hyunchul Lee --- fsck/fsck.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index a2ca143..2485d2e 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -771,12 +771,12 @@ static int exfat_boot_region_check(struct exfat *exfat, struct pbr **bs) )) { ret = read_boot_region(exfat->blk_dev, bs, BACKUP_BOOT_SEC_IDX); if (ret < 0) { - exfat_err("backup boot region is also corrupted"); + exfat_err("backup boot region is also corrupted\n"); return ret; } ret = restore_boot_region(exfat->blk_dev); if (ret < 0) { - exfat_err("failed to restore boot region from backup"); + exfat_err("failed to restore boot region from backup\n"); free(*bs); *bs = NULL; return ret; -- cgit v1.2.3 From 04617ad5f30914aa70893ae5d81d8546c62f4ca6 Mon Sep 17 00:00:00 2001 From: pablomh Date: Mon, 5 Oct 2020 09:26:36 +0200 Subject: fsck.exfat: Document "-p" option Based on feedback provided in https://github.com/exfatprogs/exfatprogs/issues/132. Signed-off-by: Pablo Mendez Hernandez --- manpages/fsck.exfat.8 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/manpages/fsck.exfat.8 b/manpages/fsck.exfat.8 index b30072c..ca551d3 100644 --- a/manpages/fsck.exfat.8 +++ b/manpages/fsck.exfat.8 @@ -27,6 +27,9 @@ depending on the options passed. .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 -- cgit v1.2.3 From db968f6eb501d0e8261641fae9f9e9e598ca3b0f Mon Sep 17 00:00:00 2001 From: "Kevin F. Haggerty" Date: Wed, 11 Nov 2020 21:44:21 -0700 Subject: exfatprogs: Set _FILE_OFFSET_BITS=64 for Android build * Most platforms targeted by exfatprogs make use of autoconf to set, or not, _FILE_OFFSET_BITS appropriately. Android is not one of those platforms. * As of API 15, setting _FILE_OFFSET_BITS=64 is allowed on 32-bit ABI, and by API 24 all expected methods are enabled. 64-bit ABI natively has a 64-bit off_t, but _FILE_OFFSET_BITS=64 does not have a negative effect. Furthermore, Android build compat here is via blueprint files for the soong build system; it just so happens that soong was made available in Android 7.0 (API 24). * In order to minimize changes to broader codebase, we will set this to 64 on all Android targets via the blueprint version of CFLAGS. Signed-off-by: Kevin F. Haggerty Signed-off-by: Luca Stefani --- Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/Android.bp b/Android.bp index 6982941..78b7780 100644 --- a/Android.bp +++ b/Android.bp @@ -13,4 +13,5 @@ cc_defaults { name: "exfatprogs-defaults", header_libs: ["libexfatprogs-headers"], export_header_lib_headers: ["libexfatprogs-headers"], + cflags: ["-D_FILE_OFFSET_BITS=64"], } -- cgit v1.2.3 From 7c9e7926ca2e3938dde883128845fbd8533e89e4 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 8 Dec 2020 16:24:22 +0900 Subject: exfatprogs: add exfatlabel Leonidas request exfatlabel to support it in exfatprogs for compatibility with the existing exfatlabel of exfat-utils. 1. Get volume label. #./exfatlabel /dev/sdb exfatprogs version : 1.0.3 label: abc 1. Get volume label. #./exfatlabel /dev/sdb def exfatprogs version : 1.0.3 new label: def Signed-off-by: Namjae Jeon --- Makefile.am | 3 +- configure.ac | 1 + include/libexfat.h | 4 +++ label/Android.bp | 11 +++++++ label/Makefile.am | 6 ++++ label/label.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/libexfat.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tune/tune.c | 92 ------------------------------------------------------ 8 files changed, 200 insertions(+), 93 deletions(-) create mode 100644 label/Android.bp create mode 100644 label/Makefile.am create mode 100644 label/label.c diff --git a/Makefile.am b/Makefile.am index f4f4cbc..cabe336 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = lib mkfs fsck tune +SUBDIRS = lib mkfs fsck tune label # manpages dist_man8_MANS = \ @@ -18,4 +18,5 @@ EXTRA_DIST = \ mkfs/Android.bp \ tune/Android.bp \ fsck/Android.bp \ + label/Android.bp \ README.md diff --git a/configure.ac b/configure.ac index 692faf6..687c569 100644 --- a/configure.ac +++ b/configure.ac @@ -30,6 +30,7 @@ AC_CONFIG_FILES([ mkfs/Makefile fsck/Makefile tune/Makefile + label/Makefile ]) AC_OUTPUT diff --git a/include/libexfat.h b/include/libexfat.h index 6a3ecb8..702ea7a 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -86,6 +86,10 @@ 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_get_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); /* * Exfat Print diff --git a/label/Android.bp b/label/Android.bp new file mode 100644 index 0000000..05bed67 --- /dev/null +++ b/label/Android.bp @@ -0,0 +1,11 @@ +// Copyright 2020 The Android Open Source Project + +cc_binary { + name: "exfatlabel", + + srcs: [ + "label.c", + ], + defaults: ["exfatprogs-defaults"], + static_libs: ["libexfat"], +} diff --git a/label/Makefile.am b/label/Makefile.am new file mode 100644 index 0000000..3f980bb --- /dev/null +++ b/label/Makefile.am @@ -0,0 +1,6 @@ +AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common +exfatlabel_LDADD = $(top_builddir)/lib/libexfat.a + +sbin_PROGRAMS = exfatlabel + +exfatlabel_SOURCES = label.c diff --git a/label/label.c b/label/label.c new file mode 100644 index 0000000..cf4cd46 --- /dev/null +++ b/label/label.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Namjae Jeon + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "exfat_ondisk.h" +#include "libexfat.h" + +static void usage(void) +{ + fprintf(stderr, "Usage: exfatlabel\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 } +}; + +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; + + init_user_input(&ui); + + if (!setlocale(LC_CTYPE, "")) + exfat_err("failed to init locale/codeset\n"); + + opterr = 0; + while ((c = getopt_long(argc, argv, "Vh", 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; + + root_clu_off = exfat_get_root_entry_offset(&bd); + if (root_clu_off < 0) + goto out; + + if (argc == 2) + ret = exfat_get_volume_label(&bd, root_clu_off); + else + ret = exfat_set_volume_label(&bd, argv[2], root_clu_off); + +out: + return ret; +} diff --git a/lib/libexfat.c b/lib/libexfat.c index 1c0bbc0..92a6264 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -327,3 +327,95 @@ ssize_t exfat_utf16_dec(const __u16 *in_str, size_t in_len, 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; + off_t root_clu_off; + + bs = (struct pbr *)malloc(sizeof(struct pbr)); + if (!bs) { + exfat_err("failed to allocate memory\n"); + return -ENOMEM; + } + + nbytes = exfat_read(bd->dev_fd, bs, sizeof(struct pbr), 0); + if (nbytes != sizeof(struct pbr)) { + exfat_err("boot sector read failed: %d\n", errno); + return -1; + } + + cluster_size = (1 << bs->bsx.sect_per_clus_bits) * bd->sector_size; + root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * bd->sector_size + + le32_to_cpu(bs->bsx.root_cluster - EXFAT_REVERVED_CLUSTERS) + * cluster_size; + free(bs); + + return root_clu_off; +} + +int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) +{ + struct exfat_dentry *vol_entry; + char volume_label[VOLUME_LABEL_BUFFER_SIZE]; + __le16 disk_label[VOLUME_LABEL_MAX_LEN]; + 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); + return -1; + } + + memcpy(disk_label, vol_entry->vol_label, sizeof(disk_label)); + memset(volume_label, 0, sizeof(volume_label)); + if (exfat_utf16_dec(disk_label, vol_entry->vol_char_cnt*2, + volume_label, sizeof(volume_label)) < 0) { + exfat_err("failed to decode volume label\n"); + return -1; + } + + exfat_info("label: %s\n", volume_label); + 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; +} diff --git a/tune/tune.c b/tune/tune.c index d160a37..5a4d029 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -36,98 +36,6 @@ static struct option opts[] = { {NULL, 0, NULL, 0 } }; -static off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) -{ - struct pbr *bs; - int nbytes; - unsigned int cluster_size; - off_t root_clu_off; - - bs = (struct pbr *)malloc(sizeof(struct pbr)); - if (!bs) { - exfat_err("failed to allocate memory\n"); - return -ENOMEM; - } - - nbytes = exfat_read(bd->dev_fd, bs, sizeof(struct pbr), 0); - if (nbytes != sizeof(struct pbr)) { - exfat_err("boot sector read failed: %d\n", errno); - return -1; - } - - cluster_size = (1 << bs->bsx.sect_per_clus_bits) * bd->sector_size; - root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * bd->sector_size + - le32_to_cpu(bs->bsx.root_cluster - EXFAT_REVERVED_CLUSTERS) - * cluster_size; - free(bs); - - return root_clu_off; -} - -static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) -{ - struct exfat_dentry *vol_entry; - char volume_label[VOLUME_LABEL_BUFFER_SIZE]; - __le16 disk_label[VOLUME_LABEL_MAX_LEN]; - 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); - return -1; - } - - memcpy(disk_label, vol_entry->vol_label, sizeof(disk_label)); - memset(volume_label, 0, sizeof(volume_label)); - if (exfat_utf16_dec(disk_label, vol_entry->vol_char_cnt*2, - volume_label, sizeof(volume_label)) < 0) { - exfat_err("failed to decode volume label\n"); - return -1; - } - - exfat_info("label: %s\n", volume_label); - return 0; -} - -static 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; -} - #define EXFAT_GET_LABEL 0x1 #define EXFAT_SET_LABEL 0x2 -- cgit v1.2.3 From 37e30a7e37b41e3709dac7bd30e1089916dd1132 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 8 Dec 2020 16:36:59 +0900 Subject: exfatprogs: update README to guide how to use exfatlabel Signed-off-by: Namjae Jeon --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index f9b7f23..22a7deb 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,15 @@ Usage example: tune.exfat -l /dev/sda1 2. set new volume label. tune.exfat -L "new label" /dev/sda1 + +- exfatlabel: + Get or Set volume label + +Usage example: + 1. get current volume label. + exfatlabel /dev/sda1 + 2. set new volume label. + exfatlabel "new label" /dev/sda1 ``` ## Sending feedback -- cgit v1.2.3 From cf4d3465f22263c87447f1bc51dba58afd3b1c0d Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 8 Dec 2020 17:10:58 +0900 Subject: manpage: add exfatlabel Signed-off-by: Namjae Jeon --- Makefile.am | 3 ++- manpages/exfatlabel.8 | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 manpages/exfatlabel.8 diff --git a/Makefile.am b/Makefile.am index cabe336..a8b66d5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,7 +8,8 @@ SUBDIRS = lib mkfs fsck tune label dist_man8_MANS = \ manpages/fsck.exfat.8 \ manpages/tune.exfat.8 \ - manpages/mkfs.exfat.8 + manpages/mkfs.exfat.8 \ + manpages/exfatlabel.8 # other stuff EXTRA_DIST = \ diff --git a/manpages/exfatlabel.8 b/manpages/exfatlabel.8 new file mode 100644 index 0000000..9fd73e9 --- /dev/null +++ b/manpages/exfatlabel.8 @@ -0,0 +1,28 @@ +.TH exfatlabel 8 +.SH NAME +exfatlabel \- Get or Set volume label of an exFAT filesystem +.SH SYNOPSIS +.B exfatlabel +[ +.B \-v +] +.I device +[ +.I label_string +] +.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. +.PP +.SH OPTIONS +.TP +.B \-V +Prints the version number and exits. -- cgit v1.2.3 From b4d9c9eeb5c28b503e103e2c4ec22bc146446d9f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 2 Feb 2021 19:35:31 +0900 Subject: exfatlabel: add get/set volume serial option Add get/set volume serial option in exfatlabel and tune.exfat $ sudo exfatlabel -i /dev/sdb1 0x1234 exfatprogs version : 1.0.4 New volume serial : 0x1234 $ sudo exfatlabel -i /dev/sdb1 exfatprogs version : 1.0.4 volume serial : 0x1234 Signed-off-by: Namjae Jeon --- README.md | 13 +++- include/libexfat.h | 17 +++++ label/label.c | 48 ++++++++++--- lib/libexfat.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++ manpages/exfatlabel.8 | 14 +++- manpages/tune.exfat.8 | 21 ++++-- mkfs/mkfs.c | 46 +------------ tune/tune.c | 35 +++++++--- 8 files changed, 306 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index f9b0010..b847f6e 100644 --- a/README.md +++ b/README.md @@ -63,15 +63,24 @@ Usage example: 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 "new serial" /dev/sda1 - exfatlabel: - Get or Set volume label + Get or Set volume label or serial Usage example: 1. get current volume label. exfatlabel /dev/sda1 2. set new volume label. - exfatlabel "new label" /dev/sda1 + exfatlabel /dev/sda1 "new label" + 3. get current volume serial. + exfatlabel -i /dev/sda1 + 4. set new volume serial. + exfatlabel -i /dev/sda1 "new serial" + ``` ## Benchmarks diff --git a/include/libexfat.h b/include/libexfat.h index 702ea7a..089b1c1 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -37,6 +37,12 @@ /* Upcase tabel 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 + enum { BOOT_SEC_IDX = 0, EXBOOT_SEC_IDX, @@ -65,6 +71,7 @@ struct exfat_user_input { bool quick; __u16 volume_label[VOLUME_LABEL_MAX_LEN]; int volume_label_len; + unsigned int volume_serial; }; void show_version(void); @@ -90,6 +97,16 @@ off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd); int exfat_get_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); +int exfat_show_volume_serial(struct exfat_blk_dev *bd, + struct exfat_user_input *ui); +int exfat_set_volume_serial(struct exfat_blk_dev *bd, + struct exfat_user_input *ui); /* * Exfat Print diff --git a/label/label.c b/label/label.c index cf4cd46..67e71ec 100644 --- a/label/label.c +++ b/label/label.c @@ -17,6 +17,7 @@ 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"); @@ -24,6 +25,7 @@ static void usage(void) } static struct option opts[] = { + {"volume-serial", no_argument, NULL, 'i' }, {"version", no_argument, NULL, 'V' }, {"help", no_argument, NULL, 'h' }, {"?", no_argument, NULL, '?' }, @@ -38,15 +40,30 @@ int main(int argc, char *argv[]) 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, "Vh", opts, NULL)) != EOF) + 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; @@ -64,20 +81,31 @@ int main(int argc, char *argv[]) usage(); memset(ui.dev_name, 0, sizeof(ui.dev_name)); - snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[1]); + 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; - root_clu_off = exfat_get_root_entry_offset(&bd); - if (root_clu_off < 0) - goto out; - - if (argc == 2) - ret = exfat_get_volume_label(&bd, root_clu_off); - else - ret = exfat_set_volume_label(&bd, argv[2], root_clu_off); + if (serial_mode) { + /* Mode to change or display volume serial */ + if (flags == EXFAT_GET_VOLUME_SERIAL) { + ret = exfat_show_volume_serial(&bd, &ui); + } 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 out; + + if (flags == EXFAT_GET_VOLUME_LABEL) + ret = exfat_get_volume_label(&bd, root_clu_off); + else if (flags == EXFAT_SET_VOLUME_LABEL) + ret = exfat_set_volume_label(&bd, argv[2], root_clu_off); + } out: return ret; diff --git a/lib/libexfat.c b/lib/libexfat.c index 92a6264..0833933 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -419,3 +419,188 @@ int exfat_set_volume_label(struct exfat_blk_dev *bd, 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; + + lseek(bd->dev_fd, offset, SEEK_SET); + ret = read(bd->dev_fd, buf, bd->sector_size); + 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; + + lseek(bd->dev_fd, offset, SEEK_SET); + bytes = write(bd->dev_fd, buf, bd->sector_size); + 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(struct exfat_blk_dev *bd, + struct exfat_user_input *ui) +{ + struct pbr *ppbr; + int ret; + + ppbr = malloc(bd->sector_size); + if (!ppbr) { + exfat_err("Cannot allocate pbr: out of memory\n"); + return -1; + } + + /* read main boot sector */ + ret = exfat_read_sector(bd, (char *)ppbr, BOOT_SEC_IDX); + 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; + int sector_size = bd->sector_size; + 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; + sector_size = sizeof(struct pbr); + } else if (sec_idx >= EXBOOT_SEC_IDX && sec_idx < OEM_SEC_IDX) + sector_size = sizeof(struct exbs); + + boot_calc_checksum(buf, 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(bd->sector_size); + if (!ppbr) { + exfat_err("Cannot allocate pbr: out of memory\n"); + return -1; + } + + /* read main boot sector */ + ret = exfat_read_sector(bd, (char *)ppbr, BOOT_SEC_IDX); + if (ret < 0) { + exfat_err("main boot sector read failed\n"); + ret = -1; + goto free_ppbr; + } + + 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; +} diff --git a/manpages/exfatlabel.8 b/manpages/exfatlabel.8 index 9fd73e9..f3274bb 100644 --- a/manpages/exfatlabel.8 +++ b/manpages/exfatlabel.8 @@ -1,14 +1,17 @@ .TH exfatlabel 8 .SH NAME -exfatlabel \- Get or Set volume label of an exFAT filesystem +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 +.I label_string or serial_value ] .br .B exfatlabel \-V @@ -20,9 +23,14 @@ 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. +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. diff --git a/manpages/tune.exfat.8 b/manpages/tune.exfat.8 index c834ed9..2816f45 100644 --- a/manpages/tune.exfat.8 +++ b/manpages/tune.exfat.8 @@ -5,9 +5,16 @@ tune.exfat \- adjust tunable filesystem parameters on an exFAT filesystem .B tune.exfat [ .B \-l +.I print-label ] [ -.B \-L volume_label -.I volume_label +.B \-L +.I set-label +] [ +.B \-i +.I print-serial +] [ +.B \-I +.I set-serial ] [ .B \-v ] @@ -20,12 +27,18 @@ adjust tunable ondisk parameters of an existing exFAT filesystem. .PP .SH OPTIONS .TP -.BI \-l +.BI \-l " print-label" Print the volume label of the exFAT filesystem. .TP -.BI \-L" volume_label" +.BI \-L " set-label" Set the volume label of the filesystem to the provided argument. .TP +.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. .BI \-v Prints verbose debugging information while extracting or tuning parameters of the exFAT filesystem. .TP diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 9fff978..6b77638 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -88,28 +88,13 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, 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_sector(struct exfat_blk_dev *bd, void *buf, - unsigned int sec_off) -{ - int bytes; - unsigned long long offset = sec_off * bd->sector_size; - - lseek(bd->dev_fd, offset, SEEK_SET); - bytes = write(bd->dev_fd, buf, bd->sector_size); - if (bytes != (int)bd->sector_size) { - exfat_err("write failed, sec_off : %u, bytes : %d\n", sec_off, - bytes); - return -1; - } - return 0; -} - static int exfat_write_boot_sector(struct exfat_blk_dev *bd, struct exfat_user_input *ui, unsigned int *checksum, bool is_backup) @@ -213,35 +198,6 @@ free_oem: return ret; } -static 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; -} - static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd, struct exfat_user_input *ui, bool is_backup) { diff --git a/tune/tune.c b/tune/tune.c index 5a4d029..79c343d 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -18,7 +18,9 @@ static void usage(void) { fprintf(stderr, "Usage: tune.exfat\n"); fprintf(stderr, "\t-l | --print-label Print volume label\n"); - fprintf(stderr, "\t-L | --volume-label=label Set 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-L | --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"); @@ -29,6 +31,8 @@ static void usage(void) 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' }, @@ -36,9 +40,6 @@ static struct option opts[] = { {NULL, 0, NULL, 0 } }; -#define EXFAT_GET_LABEL 0x1 -#define EXFAT_SET_LABEL 0x2 - int main(int argc, char *argv[]) { int c; @@ -56,15 +57,22 @@ int main(int argc, char *argv[]) exfat_err("failed to init locale/codeset\n"); opterr = 0; - while ((c = getopt_long(argc, argv, "L:lVvh", opts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "I:iL:lVvh", opts, NULL)) != EOF) switch (c) { case 'l': - flags = EXFAT_GET_LABEL; + flags = EXFAT_GET_VOLUME_LABEL; break; case 'L': snprintf(label_input, sizeof(label_input), "%s", optarg); - flags = EXFAT_SET_LABEL; + 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; @@ -92,13 +100,22 @@ int main(int argc, char *argv[]) if (ret < 0) goto out; + /* Mode to change or display volume serial */ + if (flags == EXFAT_GET_VOLUME_SERIAL) { + ret = exfat_show_volume_serial(&bd, &ui); + goto out; + } else if (flags == EXFAT_SET_VOLUME_SERIAL) { + ret = exfat_set_volume_serial(&bd, &ui); + goto out; + } + root_clu_off = exfat_get_root_entry_offset(&bd); if (root_clu_off < 0) goto out; - if (flags == EXFAT_GET_LABEL) + if (flags == EXFAT_GET_VOLUME_LABEL) ret = exfat_get_volume_label(&bd, root_clu_off); - else if (flags == EXFAT_SET_LABEL) + else if (flags == EXFAT_SET_VOLUME_LABEL) ret = exfat_set_volume_label(&bd, label_input, root_clu_off); out: -- cgit v1.2.3 From 1dd457744bdd79889631b8efc37880e409afe6c3 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 3 Feb 2021 16:31:12 +0900 Subject: libexfat: rename exfat_get_volume_label to exfat_show_volume_label exfat_get_volume_label() print volume label string, It doesn't return volume label string. So rename it to exfat_show_volume_label(). Signed-off-by: Namjae Jeon --- include/libexfat.h | 2 +- label/label.c | 2 +- lib/libexfat.c | 2 +- tune/tune.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/libexfat.h b/include/libexfat.h index 089b1c1..e4e1597 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -94,7 +94,7 @@ 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_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off); +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, diff --git a/label/label.c b/label/label.c index 67e71ec..40442b1 100644 --- a/label/label.c +++ b/label/label.c @@ -102,7 +102,7 @@ int main(int argc, char *argv[]) goto out; if (flags == EXFAT_GET_VOLUME_LABEL) - ret = exfat_get_volume_label(&bd, root_clu_off); + 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); } diff --git a/lib/libexfat.c b/lib/libexfat.c index 0833933..277e9bb 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -356,7 +356,7 @@ off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) return root_clu_off; } -int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) +int exfat_show_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) { struct exfat_dentry *vol_entry; char volume_label[VOLUME_LABEL_BUFFER_SIZE]; diff --git a/tune/tune.c b/tune/tune.c index 79c343d..ef147ea 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -114,7 +114,7 @@ int main(int argc, char *argv[]) goto out; if (flags == EXFAT_GET_VOLUME_LABEL) - ret = exfat_get_volume_label(&bd, root_clu_off); + 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); -- cgit v1.2.3 From ec8c3e9da6c64ef51b02ef555f5654cbe955980b Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 4 Feb 2021 15:02:47 +0900 Subject: exfatprogs: add missing tune and label in Android.bp Signed-off-by: Namjae Jeon --- Android.bp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Android.bp b/Android.bp index 78b7780..e78b794 100644 --- a/Android.bp +++ b/Android.bp @@ -6,6 +6,8 @@ cc_library_headers { "include", "mkfs", "fsck", + "tune", + "label", ], } -- cgit v1.2.3 From 7ce9b2336b06e76521f7e041d8f0712b2d98a15b Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 8 Feb 2021 15:02:34 +0900 Subject: exfatprogs: add dump.exfat Add a dump.exfat util to show ondisk information from given device which formatted by exfat filesystem. $dump.exfat /dev/sdb1 exfatprogs version : 1.0.4 -------------- Dump Boot sector region -------------- Volume Length(sectors): 1134319616 FAT Offset(sector offset): 2048 FAT Length(sectors): 34816 Cluster Heap Offset (sector offset): 36864 Cluster Count: 4430792 Root Cluster (cluster offset): 8 Volume Serial: 0x12345678 Sector Size Bits: 9 Sector per Cluster bits: 8 ----------------- Dump Root entries ----------------- Volume entry type: 0x83 Volume label: new Volume label character count: 3 Bitmap entry type: 0x81 Bitmap start cluster: 2 Bitmap size: 553849 Upcase table entry type: 0x82 Upcase table start cluster: 7 Upcase table size: 5836 ---------------- Show the statistics ---------------- Cluster size: 131072 Total Clusters: 4430792 Free Clusters: 4336453 Signed-off-by: Namjae Jeon --- Android.bp | 1 + Makefile.am | 6 +- README.md | 6 ++ configure.ac | 1 + dump/Android.bp | 11 +++ dump/Makefile.am | 6 ++ dump/dump.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/libexfat.h | 5 + lib/libexfat.c | 42 +++++++-- manpages/dump.exfat.8 | 17 ++++ mkfs/mkfs.c | 2 +- 11 files changed, 339 insertions(+), 12 deletions(-) create mode 100644 dump/Android.bp create mode 100644 dump/Makefile.am create mode 100644 dump/dump.c create mode 100644 manpages/dump.exfat.8 diff --git a/Android.bp b/Android.bp index e78b794..9f8716b 100644 --- a/Android.bp +++ b/Android.bp @@ -8,6 +8,7 @@ cc_library_headers { "fsck", "tune", "label", + "dump", ], } diff --git a/Makefile.am b/Makefile.am index a8b66d5..44f8635 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,14 +2,15 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = lib mkfs fsck tune label +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/exfatlabel.8 \ + manpages/dump.exfat.8 # other stuff EXTRA_DIST = \ @@ -20,4 +21,5 @@ EXTRA_DIST = \ tune/Android.bp \ fsck/Android.bp \ label/Android.bp \ + dump/Android.bp \ README.md diff --git a/README.md b/README.md index b847f6e..cf8b605 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,12 @@ Usage example: 4. set new volume serial. exfatlabel -i /dev/sda1 "new serial" +- dump.exfat: + Show on-disk information + +Usage example: + dump.exfat /dev/sda1 + ``` ## Benchmarks diff --git a/configure.ac b/configure.ac index 687c569..0544309 100644 --- a/configure.ac +++ b/configure.ac @@ -31,6 +31,7 @@ AC_CONFIG_FILES([ fsck/Makefile tune/Makefile label/Makefile + dump/Makefile ]) AC_OUTPUT diff --git a/dump/Android.bp b/dump/Android.bp new file mode 100644 index 0000000..a39b245 --- /dev/null +++ b/dump/Android.bp @@ -0,0 +1,11 @@ +// Copyright 2021 The Android Open Source Project + +cc_binary { + name: "dump.exfat", + + srcs: [ + "dump.c", + ], + defaults: ["exfatprogs-defaults"], + static_libs: ["libexfat"], +} diff --git a/dump/Makefile.am b/dump/Makefile.am new file mode 100644 index 0000000..29c966e --- /dev/null +++ b/dump/Makefile.am @@ -0,0 +1,6 @@ +AM_CFLAGS = -Wall -include $(top_builddir)/config.h -I$(top_srcdir)/include -fno-common +dump_exfat_LDADD = $(top_builddir)/lib/libexfat.a + +sbin_PROGRAMS = dump.exfat + +dump_exfat_SOURCES = dump.c diff --git a/dump/dump.c b/dump/dump.c new file mode 100644 index 0000000..1bd6ab2 --- /dev/null +++ b/dump/dump.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 Namjae Jeon + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} + +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(bd->sector_size); + if (!ppbr) { + exfat_err("Cannot allocate pbr: out of memory\n"); + return -1; + } + + /* read main boot sector */ + ret = exfat_read_sector(bd, (char *)ppbr, BOOT_SEC_IDX); + if (ret < 0) { + exfat_err("main boot sector read failed\n"); + ret = -1; + 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); + return -EINVAL; + } + + 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); + return -EINVAL; + } + + if (bd->sector_size != 1 << pbsx->sect_size_bits) { + exfat_err("bogus sectors size : %u(sector size bits : %u)\n", + bd->sector_size, 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_serial(&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"); + 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); + + 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; +} diff --git a/include/libexfat.h b/include/libexfat.h index e4e1597..c21dc06 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -60,6 +60,7 @@ struct exfat_blk_dev { unsigned int sector_size_bits; unsigned long long num_sectors; unsigned int num_clusters; + unsigned int cluster_size; }; struct exfat_user_input { @@ -103,10 +104,14 @@ 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_serial(struct exfat_dentry *vol_entry); int exfat_show_volume_serial(struct exfat_blk_dev *bd, struct exfat_user_input *ui); 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 diff --git a/lib/libexfat.c b/lib/libexfat.c index 277e9bb..bb1226d 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -356,11 +356,30 @@ off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) return root_clu_off; } +char *exfat_conv_volume_serial(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"); + 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[VOLUME_LABEL_BUFFER_SIZE]; - __le16 disk_label[VOLUME_LABEL_MAX_LEN]; + char *volume_label; int nbytes; vol_entry = malloc(sizeof(struct exfat_dentry)); @@ -376,15 +395,13 @@ int exfat_show_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) return -1; } - memcpy(disk_label, vol_entry->vol_label, sizeof(disk_label)); - memset(volume_label, 0, sizeof(volume_label)); - if (exfat_utf16_dec(disk_label, vol_entry->vol_char_cnt*2, - volume_label, sizeof(volume_label)) < 0) { - exfat_err("failed to decode volume label\n"); - return -1; - } + volume_label = exfat_conv_volume_serial(vol_entry); + if (!volume_label) + return -EINVAL; exfat_info("label: %s\n", volume_label); + + free(volume_label); return 0; } @@ -604,3 +621,10 @@ free_ppbr: 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_REVERVED_CLUSTERS) * bd->cluster_size; +} diff --git a/manpages/dump.exfat.8 b/manpages/dump.exfat.8 new file mode 100644 index 0000000..4c6f589 --- /dev/null +++ b/manpages/dump.exfat.8 @@ -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. diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 6b77638..4f9616d 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -84,7 +84,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, 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 (sectors) : %u\n", + 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)); -- cgit v1.2.3 From 1e2c1d68cc361ac923b2a96df2d2d96d7ab45b10 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 5 Feb 2021 11:09:56 +0900 Subject: README: replace "new serial" with 0x12345678 Replace "new serial" with 0x12345678 Signed-off-by: Namjae Jeon --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cf8b605..4db98fd 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Usage example: 3. print current volume serial. tune.exfat -i /dev/sda1 4. set new volume serial. - tune.exfat -I "new serial" /dev/sda1 + tune.exfat -I 0x12345678 /dev/sda1 - exfatlabel: Get or Set volume label or serial @@ -79,7 +79,7 @@ Usage example: 3. get current volume serial. exfatlabel -i /dev/sda1 4. set new volume serial. - exfatlabel -i /dev/sda1 "new serial" + exfatlabel -i /dev/sda1 0x12345678 - dump.exfat: Show on-disk information -- cgit v1.2.3 From 015e0c4f12e6edee15df94e1e4a6efa190217665 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 8 Feb 2021 14:14:55 +0900 Subject: exfatlabel: add missing closing dev_fd descriptor Add missing closing dev_fd descriptor for exfatlabel and tune.exfat Signed-off-by: Namjae Jeon --- label/label.c | 4 +++- tune/tune.c | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/label/label.c b/label/label.c index 40442b1..fd77a54 100644 --- a/label/label.c +++ b/label/label.c @@ -99,7 +99,7 @@ int main(int argc, char *argv[]) /* Mode to change or display volume label */ root_clu_off = exfat_get_root_entry_offset(&bd); if (root_clu_off < 0) - goto out; + goto close_fd_out; if (flags == EXFAT_GET_VOLUME_LABEL) ret = exfat_show_volume_label(&bd, root_clu_off); @@ -107,6 +107,8 @@ int main(int argc, char *argv[]) ret = exfat_set_volume_label(&bd, argv[2], root_clu_off); } +close_fd_out: + close(bd.dev_fd); out: return ret; } diff --git a/tune/tune.c b/tune/tune.c index ef147ea..7989e95 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -103,21 +103,22 @@ int main(int argc, char *argv[]) /* Mode to change or display volume serial */ if (flags == EXFAT_GET_VOLUME_SERIAL) { ret = exfat_show_volume_serial(&bd, &ui); - goto out; + goto close_fd_out; } else if (flags == EXFAT_SET_VOLUME_SERIAL) { ret = exfat_set_volume_serial(&bd, &ui); - goto out; + goto close_fd_out; } root_clu_off = exfat_get_root_entry_offset(&bd); if (root_clu_off < 0) - goto out; + 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; } -- cgit v1.2.3 From e0818e5f5ec626345d033ac115014134e7f99034 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 9 Feb 2021 08:57:53 +0900 Subject: exfatprogs: release 1.1.0 version 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. Signed-off-by: Namjae Jeon --- NEWS | 13 +++++++++++++ include/version.h | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index dd48c5f..d8bd4e4 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,16 @@ +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 ====================================== diff --git a/include/version.h b/include/version.h index e463903..e444145 100644 --- a/include/version.h +++ b/include/version.h @@ -5,6 +5,6 @@ #ifndef _VERSION_H -#define EXFAT_PROGS_VERSION "1.0.4" +#define EXFAT_PROGS_VERSION "1.1.0" #endif /* !_VERSION_H */ -- cgit v1.2.3 From 761f15d4373a2e39a57c6184e3f3f8a64f882f5e Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Fri, 5 Feb 2021 16:34:39 -0500 Subject: mkfs: avoid integer truncation when bounds checking cluster count Prior to this commit, the bounds check on the number of data clusters was subject to an integer truncation that would in most cases prevent the check from catching an out-of-bounds cluster count. This commit fixes the bounds check by moving the truncation to after the check. Signed-off-by: Matt Whitlock --- mkfs/mkfs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 4f9616d..434c81f 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -385,6 +385,7 @@ static struct option opts[] = { 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->boundary_align < bd->sector_size) { @@ -402,12 +403,12 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, exfat_err("boundary alignment is too big\n"); return -1; } - finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) / - ui->cluster_size; - if (finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) { + 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; -- cgit v1.2.3 From 5d7b665ae5448e1f8ed66a25e35b80fb5db0ef87 Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Fri, 5 Feb 2021 03:27:47 -0500 Subject: mkfs: set vol_offset field and compensate for volume offset in alignment The vol_offset field of the exFAT superblock is supposed to contain the number of sectors preceding the exFAT volume on the storage medium. This will rightly be zero only if the exFAT file system is being created on an unpartitioned block device. When created on a partition, though, the actual volume offset will be non-zero, and this ought to be reflected in the vol_offset field of the exFAT superblock. The Linux kernel exposes a partition's offset through sysfs at /sys/dev/block/:/start. This commit teaches mkfs to attempt to read that file and, if successful, to set the vol_offset field of the exFAT superblock accordingly. Additionally, this commit adjusts the boundary alignment calculations to compensate for the volume offset. This corrects the placement of the FAT and data regions so that they are located at multiples of the boundary alignment on the *medium* even when the *partition* does not begin at a multiple of the boundary alignment. Take as a common example a flash drive with a partition beginning at sector 2048 (1 MiB) and with a 4-MiB allocation unit. Prior to this commit, when run with a boundary alignment of 4M, mkfs would place the FAT region at sector 8192 of the *partition* device, corresponding to sector 10240 of the whole drive -- not a multiple of the 4-MiB allocation unit! As of this commit, mkfs would place the FAT region at sector 6144 of the partition device, corresponding to sector 8192 of the drive. Signed-off-by: Matt Whitlock --- include/libexfat.h | 1 + lib/libexfat.c | 23 ++++++++++++++++++++++- mkfs/mkfs.c | 12 +++++++----- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/include/libexfat.h b/include/libexfat.h index c21dc06..29cb5df 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -55,6 +55,7 @@ enum { struct exfat_blk_dev { int dev_fd; + unsigned long long offset; unsigned long long size; unsigned int sector_size; unsigned int sector_size_bits; diff --git a/lib/libexfat.c b/lib/libexfat.c index bb1226d..f72628c 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -144,6 +145,8 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, { 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) { @@ -160,7 +163,24 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, goto out; } + if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)) { + char pathname[43]; + FILE *fp; + snprintf(pathname, sizeof pathname, "/sys/dev/block/%u:%u/start", + major(st.st_rdev), minor(st.st_rdev)); + if ((fp = fopen(pathname, "r")) != 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); @@ -175,7 +195,8 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, bd->num_clusters = blk_dev_size / ui->cluster_size; exfat_debug("Block device name : %s\n", ui->dev_name); - exfat_debug("Block device size : %lld\n", bd->size); + 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); diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 434c81f..f9147a1 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -53,7 +53,7 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, memset(pbpb->res_zero, 0, 53); /* Fill exfat extend BIOS paramemter block */ - pbsx->vol_offset = 0; + 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); @@ -76,6 +76,8 @@ static void exfat_setup_boot_sector(struct pbr *ppbr, 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", @@ -393,12 +395,12 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, bd->sector_size); return -1; } - finfo.fat_byte_off = round_up(24 * bd->sector_size, - ui->boundary_align); + finfo.fat_byte_off = round_up(bd->offset + 24 * bd->sector_size, + ui->boundary_align) - bd->offset; finfo.fat_byte_len = round_up((bd->num_clusters * sizeof(int)), ui->cluster_size); - finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len, - ui->boundary_align); + 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; -- cgit v1.2.3 From 07e46fa12f7a40737e48d1ac326a5aa19a6bca09 Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Fri, 5 Feb 2021 16:39:32 -0500 Subject: mkfs: place bitmap immediately before alignment boundary if possible Prior to this commit, when the boundary alignment is set to the allocation unit of flash media, then the FAT and the bitmap end up in different AUs. This can have a deleterious effect on performance and endurance of some flash media. This commit adds an opportunistic attempt to move the bitmap to just before the alignment boundary (instead of just after it) to allow the FAT and the bitmap to share an allocation unit where possible. Signed-off-by: Matt Whitlock --- mkfs/mkfs.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index f9147a1..0cbe043 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -384,6 +384,37 @@ static struct option opts[] = { {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) { @@ -414,6 +445,7 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.bitmap_byte_off = finfo.clu_byte_off; finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8; + 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; -- cgit v1.2.3 From 35015679f62fb17b39031627ca805f20e9071925 Mon Sep 17 00:00:00 2001 From: Mike Fleetwood Date: Fri, 12 Feb 2021 10:53:33 +0000 Subject: tune.exfat: fix -I in help text Signed-off-by: Mike Fleetwood --- tune/tune.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tune/tune.c b/tune/tune.c index 7989e95..ab04e69 100644 --- a/tune/tune.c +++ b/tune/tune.c @@ -20,7 +20,7 @@ static void usage(void) 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-L | --set-serial=value Set 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"); -- cgit v1.2.3 From 4e7d533d8a53a8c83356b06eab672c41097616d9 Mon Sep 17 00:00:00 2001 From: Mike Fleetwood Date: Sun, 14 Feb 2021 14:39:40 +0000 Subject: tune.exfat.8: markup -v option as a separate paragraph Signed-off-by: Mike Fleetwood --- manpages/tune.exfat.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manpages/tune.exfat.8 b/manpages/tune.exfat.8 index 2816f45..865dc07 100644 --- a/manpages/tune.exfat.8 +++ b/manpages/tune.exfat.8 @@ -33,12 +33,12 @@ Print the volume label of the exFAT filesystem. .BI \-L " set-label" Set the volume label of the filesystem to the provided argument. .TP -.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 -- cgit v1.2.3 From 99c7f018d7bd991280b669035ba55e886a9ce8e5 Mon Sep 17 00:00:00 2001 From: Mike Fleetwood Date: Sun, 14 Feb 2021 15:09:31 +0000 Subject: dump.exfat: exit with status 0 on success ... rather than the number of bytes read when reading the exfat bitmap, truncated to the least significant 8-bits to become an exit status. # dump.exfat /dev/sdb1 exfatprogs version : 1.1.0 ... Bitmap size: 8128 ... # echo $? 192 # echo $(( 8128 & 255 )) 192 Signed-off-by: Mike Fleetwood --- dump/dump.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dump/dump.c b/dump/dump.c index 1bd6ab2..4dbd370 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -195,6 +195,7 @@ int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd) 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); -- cgit v1.2.3 From 64ddd700ce685ba59faafdb7f1b1783c9b96a798 Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Sat, 20 Feb 2021 16:11:55 +0100 Subject: exfatprogs: rename exfat_conv_volume_serial() to exfat_conv_volume_label() Signed-off-by: Christophe Vu-Brugier --- dump/dump.c | 2 +- include/libexfat.h | 2 +- lib/libexfat.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index 4dbd370..dfc9900 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -148,7 +148,7 @@ int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd) goto free_entry; } - volume_label = exfat_conv_volume_serial(&ed[0]); + volume_label = exfat_conv_volume_label(&ed[0]); if (!volume_label) { ret = -EINVAL; goto free_entry; diff --git a/include/libexfat.h b/include/libexfat.h index c21dc06..b4537c3 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -104,7 +104,7 @@ 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_serial(struct exfat_dentry *vol_entry); +char *exfat_conv_volume_label(struct exfat_dentry *vol_entry); int exfat_show_volume_serial(struct exfat_blk_dev *bd, struct exfat_user_input *ui); int exfat_set_volume_serial(struct exfat_blk_dev *bd, diff --git a/lib/libexfat.c b/lib/libexfat.c index bb1226d..3c49083 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -356,7 +356,7 @@ off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) return root_clu_off; } -char *exfat_conv_volume_serial(struct exfat_dentry *vol_entry) +char *exfat_conv_volume_label(struct exfat_dentry *vol_entry) { char *volume_label; __le16 disk_label[VOLUME_LABEL_MAX_LEN]; @@ -395,7 +395,7 @@ int exfat_show_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) return -1; } - volume_label = exfat_conv_volume_serial(vol_entry); + volume_label = exfat_conv_volume_label(vol_entry); if (!volume_label) return -EINVAL; -- cgit v1.2.3 From 4dfc224bc6dbd88463ad6a2850bb78b6a8d7ab3b Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Sat, 20 Feb 2021 16:28:05 +0100 Subject: exfatprogs: fix memory leak in exfat_conv_volume_label() This memory leak was spotted by Clang scan-build. Signed-off-by: Christophe Vu-Brugier --- lib/libexfat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libexfat.c b/lib/libexfat.c index 3c49083..f1a7d0c 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -370,6 +370,7 @@ char *exfat_conv_volume_label(struct exfat_dentry *vol_entry) 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; } -- cgit v1.2.3 From 258d61f5f5a424bf02daa6ee9bedb7cfd7bc7fed Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Sat, 20 Feb 2021 16:55:10 +0100 Subject: exfatprogs: fix memory leaks in exfat_show_volume_label() Signed-off-by: Christophe Vu-Brugier --- lib/libexfat.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/libexfat.c b/lib/libexfat.c index f1a7d0c..7250801 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -393,16 +393,20 @@ int exfat_show_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off) 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) + if (!volume_label) { + free(vol_entry); return -EINVAL; + } exfat_info("label: %s\n", volume_label); free(volume_label); + free(vol_entry); return 0; } -- cgit v1.2.3 From 30ac59b1b3de28b28e7704fcd960b08348f988e9 Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Tue, 23 Feb 2021 22:33:12 -0500 Subject: manpages/mkfs.exfat.8: add SD card boundary unit table; misc cleanups * Break lines at sentence boundaries to allow troff to better typeset end-of-sentence whitespace. * Document long versions of options alongside their short equivalents. * Explain why --boundary-align= is important to use on SD cards and how to determine an appropriate value for the alignment argument. * Insert a table of recommended cluster sizes and boundary units for SD cards of various capacity ranges. * Document that the m/M and k/K size suffixes specify *binary* mebibytes and kibibytes, not megabytes and kilobytes of ambiguous radix. * Other trivial grammatical tweaks. Signed-off-by: Matt Whitlock --- manpages/mkfs.exfat.8 | 55 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/manpages/mkfs.exfat.8 b/manpages/mkfs.exfat.8 index 0bd8ffc..d251f5e 100644 --- a/manpages/mkfs.exfat.8 +++ b/manpages/mkfs.exfat.8 @@ -39,30 +39,53 @@ SCSI disk, use: .PP .SH OPTIONS .TP -.BI \-b " boundary_alignment" -Specify the alignment for FAT and start of cluster. -Boundary alignment can be specified in m/M for megabytes -and k/K for kilobytes. It should be a power of two. -Some media like sdcard need this. +.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 -.BI \-c " cluster_size" -Specify the cluster size. Cluster size can be specified in m/M for megabytes -and k/K for kilobytes. +.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 -.BI \-f -Performs a full format. This zeros the entire disk device while -creating the exFAT filesystem. +.BR \-f ", " \-\-full\-format +Performs a full format. +This zeros the entire disk device while creating the exFAT filesystem. .TP -.BI \-h +.BR \-h ", " \-\-help Prints the help and exit. .TP -.BI \-L " volume_label" -Specifies the volume label associated with the exFAT filesystem. +.BR \-L ", " \-\-volume\-label =\fIlabel\fR +Specifies the volume label to be associated with the exFAT filesystem. .TP -.BI \-v +.BR \-v ", " \-\-verbose Prints verbose debugging information while creating the exFAT filesystem. .TP -.B \-V +.BR \-V ", " \-\-version Prints the version number and exits. .SH SEE ALSO .BR mkfs (8), -- cgit v1.2.3 From c62ad8d1f9f816c570807fc846a1fa2752d321f0 Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Tue, 23 Feb 2021 23:00:28 -0500 Subject: mkfs: add --pack-bitmap option to control bitmap packing Also document the new option in the manpage. Signed-off-by: Matt Whitlock --- include/libexfat.h | 1 + manpages/mkfs.exfat.8 | 19 +++++++++++++++++++ mkfs/mkfs.c | 32 ++++++++++++++++++++++---------- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/include/libexfat.h b/include/libexfat.h index 29cb5df..69501e0 100644 --- a/include/libexfat.h +++ b/include/libexfat.h @@ -70,6 +70,7 @@ struct exfat_user_input { 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; diff --git a/manpages/mkfs.exfat.8 b/manpages/mkfs.exfat.8 index d251f5e..9f867d3 100644 --- a/manpages/mkfs.exfat.8 +++ b/manpages/mkfs.exfat.8 @@ -17,6 +17,8 @@ mkfs.exfat \- create an exFAT filesystem .B \-L .I volume_label ] [ +.B \-\-pack\-bitmap +] [ .B \-v ] .I device @@ -82,6 +84,23 @@ Prints the help and exit. .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 diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 0cbe043..c60dfe3 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -360,22 +361,29 @@ static int exfat_create_root_dir(struct exfat_blk_dev *bd, static void usage(void) { - fprintf(stderr, "Usage: mkfs.exfat\n"); - fprintf(stderr, "\t-L | --volume-label=label Set volume label\n"); - fprintf(stderr, "\t-c | --cluster-size=size(or suffixed by 'K' or 'M') Specify cluster size\n"); - fprintf(stderr, "\t-b | --boundary-align=size(or suffixed by 'K' or 'M') Specify boundary alignment\n"); - fprintf(stderr, "\t-f | --full-format Full format\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"); + 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); } -static struct option opts[] = { +enum LongOption { + 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' }, @@ -445,7 +453,8 @@ static int exfat_build_mkfs_info(struct exfat_blk_dev *bd, finfo.bitmap_byte_off = finfo.clu_byte_off; finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8; - exfat_pack_bitmap(ui); + 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; @@ -627,6 +636,9 @@ int main(int argc, char *argv[]) } ui.boundary_align = ret; break; + case PACK_BITMAP: + ui.pack_bitmap = true; + break; case 'f': ui.quick = false; break; -- cgit v1.2.3 From ec0934b8b45da91ea84322a57ade49a68594c259 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Thu, 25 Feb 2021 17:13:31 +0100 Subject: fsck: add -a option This is for backwards compatibility. It does the same as -p. Signed-off-by: Matthieu CASTET --- fsck/fsck.c | 4 +++- manpages/fsck.exfat.8 | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 2485d2e..46c8943 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -87,6 +87,7 @@ static void usage(char *name) fprintf(stderr, "\t-y | --repair-yes Repair without ask\n"); fprintf(stderr, "\t-n | --repair-no No repair\n"); fprintf(stderr, "\t-p | --repair-auto Repair automatically\n"); + fprintf(stderr, "\t-a Repair automatically\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"); @@ -1465,7 +1466,7 @@ int main(int argc, char * const argv[]) exfat_err("failed to init locale/codeset\n"); opterr = 0; - while ((c = getopt_long(argc, argv, "rynpVvh", opts, NULL)) != EOF) { + while ((c = getopt_long(argc, argv, "arynpVvh", opts, NULL)) != EOF) { switch (c) { case 'n': if (ui.options & FSCK_OPTS_REPAIR_ALL) @@ -1482,6 +1483,7 @@ int main(int argc, char * const argv[]) usage(argv[0]); ui.options |= FSCK_OPTS_REPAIR_YES; break; + case 'a': case 'p': if (ui.options & FSCK_OPTS_REPAIR_ALL) usage(argv[0]); diff --git a/manpages/fsck.exfat.8 b/manpages/fsck.exfat.8 index ca551d3..83f7815 100644 --- a/manpages/fsck.exfat.8 +++ b/manpages/fsck.exfat.8 @@ -4,6 +4,8 @@ fsck.exfat \- check an exFAT filesystem .SH SYNOPSIS .B fsck.exfat [ +.B \-a +] [ .B \-n ] [ .B \-r @@ -24,6 +26,9 @@ 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 -- cgit v1.2.3 From b86c147b3048766b2c07446e9fb0380dcb2dba3c Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Thu, 25 Feb 2021 19:39:16 -0500 Subject: stylistic tweaks (no semantic changes) Signed-off-by: Matt Whitlock --- lib/libexfat.c | 11 +++++++---- mkfs/mkfs.c | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/libexfat.c b/lib/libexfat.c index f72628c..081cfd8 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -164,17 +164,20 @@ int exfat_get_blk_dev_info(struct exfat_user_input *ui, } if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)) { - char pathname[43]; + char pathname[sizeof("/sys/dev/block/4294967295:4294967295/start")]; FILE *fp; - snprintf(pathname, sizeof pathname, "/sys/dev/block/%u:%u/start", + + snprintf(pathname, sizeof(pathname), "/sys/dev/block/%u:%u/start", major(st.st_rdev), minor(st.st_rdev)); - if ((fp = fopen(pathname, "r")) != NULL) { - if (fscanf(fp, "%llu", &blk_dev_offset) == 1) + 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); } } diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index c60dfe3..1837669 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -375,9 +375,7 @@ static void usage(void) exit(EXIT_FAILURE); } -enum LongOption { - PACK_BITMAP = CHAR_MAX + 1, -}; +#define PACK_BITMAP (CHAR_MAX + 1) static const struct option opts[] = { {"volume-label", required_argument, NULL, 'L' }, @@ -398,11 +396,13 @@ static const struct option opts[] = { * 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) { +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 || -- cgit v1.2.3 From 2a589efe73ce5a2a98d0ed8f9840080fb3749b5b Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Fri, 26 Feb 2021 22:51:36 +0100 Subject: exfatprogs: fix typo: EXFAT_REVERVED_CLUSTERS -> EXFAT_RESERVED_CLUSTERS Signed-off-by: Christophe Vu-Brugier --- include/exfat_ondisk.h | 2 +- lib/libexfat.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h index 163bef0..74e3fb3 100644 --- a/include/exfat_ondisk.h +++ b/include/exfat_ondisk.h @@ -93,7 +93,7 @@ #define EXFAT_BAD_CLUSTER (0xFFFFFFF7U) #define EXFAT_FREE_CLUSTER (0) #define EXFAT_FIRST_CLUSTER (2) -#define EXFAT_REVERVED_CLUSTERS (2) +#define EXFAT_RESERVED_CLUSTERS (2) /* EXFAT BIOS parameter block (64 bytes) */ diff --git a/lib/libexfat.c b/lib/libexfat.c index f0de968..0d12d66 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -373,7 +373,7 @@ off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) cluster_size = (1 << bs->bsx.sect_per_clus_bits) * bd->sector_size; root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * bd->sector_size + - le32_to_cpu(bs->bsx.root_cluster - EXFAT_REVERVED_CLUSTERS) + le32_to_cpu(bs->bsx.root_cluster - EXFAT_RESERVED_CLUSTERS) * cluster_size; free(bs); @@ -655,5 +655,5 @@ 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_REVERVED_CLUSTERS) * bd->cluster_size; + (clu - EXFAT_RESERVED_CLUSTERS) * bd->cluster_size; } -- cgit v1.2.3 From 4a3314f0e1ddaa05106d21428ce409c8f0d17d09 Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Fri, 26 Feb 2021 22:48:48 +0100 Subject: libexfat: fix memory leak in exfat_get_root_entry_offset() Signed-off-by: Christophe Vu-Brugier --- lib/libexfat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libexfat.c b/lib/libexfat.c index 0d12d66..61a0778 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -368,6 +368,7 @@ off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd) nbytes = exfat_read(bd->dev_fd, bs, sizeof(struct pbr), 0); if (nbytes != sizeof(struct pbr)) { exfat_err("boot sector read failed: %d\n", errno); + free(bs); return -1; } -- cgit v1.2.3 From 3c54d0d58dc7a9c817c0974412995e8040c8ddda Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Fri, 26 Feb 2021 23:08:18 +0100 Subject: dump: make exfat_show_ondisk_all_info() static Signed-off-by: Christophe Vu-Brugier --- dump/dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dump/dump.c b/dump/dump.c index dfc9900..d2cf928 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -64,7 +64,7 @@ static unsigned int exfat_count_used_clusters(unsigned char *bitmap, return count; } -int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd) +static int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd) { struct pbr *ppbr; struct bsx64 *pbsx; -- cgit v1.2.3 From 214ed3e0272f17a246c15165c6ca38fdb633ef48 Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Fri, 26 Feb 2021 23:10:09 +0100 Subject: dump: fix memory leaks in error paths Signed-off-by: Christophe Vu-Brugier --- dump/dump.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index d2cf928..292e1fa 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -96,13 +96,15 @@ static int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd) pbsx->sect_size_bits > EXFAT_MAX_SECT_SIZE_BITS) { exfat_err("bogus sector size bits : %u\n", pbsx->sect_size_bits); - return -EINVAL; + 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); - return -EINVAL; + ret = -EINVAL; + goto free_ppbr; } if (bd->sector_size != 1 << pbsx->sect_size_bits) { -- cgit v1.2.3 From 94a4717c36d336608f27cd8fa4fbccf914769a3f Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Fri, 26 Feb 2021 23:16:38 +0100 Subject: dump: return -EINVAL in case of bogus sector size To be consistent with previous checks that return -EINVAL. Signed-off-by: Christophe Vu-Brugier --- dump/dump.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index 292e1fa..f6798ff 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -108,9 +108,10 @@ static int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd) } if (bd->sector_size != 1 << pbsx->sect_size_bits) { - exfat_err("bogus sectors size : %u(sector size bits : %u)\n", + exfat_err("bogus sector size : %u (sector size bits : %u)\n", bd->sector_size, pbsx->sect_size_bits); - + ret = -EINVAL; + goto free_ppbr; } clu_offset = le32_to_cpu(pbsx->clu_offset); -- cgit v1.2.3 From 9ce00e31b6e71c0335315baee75f78a95d74714f Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Fri, 26 Feb 2021 23:23:04 +0100 Subject: dump: return a more specific error than -1 In exfat_show_ondisk_all_info(), instead of returning -1, return: * -ENOMEM when a memory allocation fails * -EIO when exfat_read_sector() fails Also set the "ret" variable to -ENOMEM when the bitmap allocation fails because the variable was not initialized. Signed-off-by: Christophe Vu-Brugier --- dump/dump.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dump/dump.c b/dump/dump.c index f6798ff..85d5101 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -79,14 +79,14 @@ static int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd) ppbr = malloc(bd->sector_size); if (!ppbr) { exfat_err("Cannot allocate pbr: out of memory\n"); - return -1; + return -ENOMEM; } /* read main boot sector */ ret = exfat_read_sector(bd, (char *)ppbr, BOOT_SEC_IDX); if (ret < 0) { exfat_err("main boot sector read failed\n"); - ret = -1; + ret = -EIO; goto free_ppbr; } @@ -180,6 +180,7 @@ static int exfat_show_ondisk_all_info(struct exfat_blk_dev *bd) bitmap = malloc(bitmap_len); if (!bitmap) { exfat_err("bitmap allocation failed\n"); + ret = -ENOMEM; goto free_volume_label; } -- cgit v1.2.3 From 0ab362327a775cd71549fba9c9ef53e4320f4a97 Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Sat, 27 Feb 2021 10:55:38 +0100 Subject: fsck: fix memory leaks in restore_boot_region() error paths Signed-off-by: Christophe Vu-Brugier --- fsck/fsck.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 46c8943..747a771 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -736,6 +736,7 @@ static int restore_boot_region(struct exfat_blk_dev *bd) { int i; char *sector; + int ret; sector = malloc(bd->sector_size); if (!sector) @@ -745,21 +746,31 @@ static int restore_boot_region(struct exfat_blk_dev *bd) if (exfat_read(bd->dev_fd, sector, bd->sector_size, BACKUP_BOOT_SEC_IDX * bd->sector_size + i * bd->sector_size) != - (ssize_t)bd->sector_size) - return -EIO; + (ssize_t)bd->sector_size) { + ret = -EIO; + goto free_sector; + } if (i == 0) ((struct pbr *)sector)->bsx.perc_in_use = 0xff; if (exfat_write(bd->dev_fd, sector, bd->sector_size, BOOT_SEC_IDX * bd->sector_size + i * bd->sector_size) != - (ssize_t)bd->sector_size) - return -EIO; + (ssize_t)bd->sector_size) { + ret = -EIO; + goto free_sector; + } } - if (fsync(bd->dev_fd)) - return -EIO; + + if (fsync(bd->dev_fd)) { + ret = -EIO; + goto free_sector; + } + ret = 0; + +free_sector: free(sector); - return 0; + return ret; } static int exfat_boot_region_check(struct exfat *exfat, struct pbr **bs) -- cgit v1.2.3 From 53e575bb646422860b85299cd93a80659d5a2189 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Wed, 31 Mar 2021 21:40:54 +0900 Subject: exfatprogs: libexfat: make set_bit_le() 64-bit compatible Eric found that bitmap data is not written normally in bitmap location on s390x(64bit big endian system). This patch make set_bit_le() etc 64-bit compatible, something like this does seem to put the bits in the right place in the allocation bitmap at mkfs time. Signed-off-by: Eric Sandeen Signed-off-by: Namjae Jeon --- lib/libexfat.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/libexfat.c b/lib/libexfat.c index 61a0778..13dfbaf 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -20,18 +20,20 @@ #include "libexfat.h" #include "version.h" +#define BITS_PER_LONG (sizeof(long) * CHAR_BIT) + #ifdef WORDS_BIGENDIAN -#define BITOP_LE_SWIZZLE (~0x7) +#define BITOP_LE_SWIZZLE ((BITS_PER_LONG - 1) & ~0x7) #else #define BITOP_LE_SWIZZLE 0 #endif -#define BIT_MASK(nr) ((1) << ((nr) % 32)) -#define BIT_WORD(nr) ((nr) / 32) +#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, unsigned int *addr) +static inline void set_bit(int nr, void *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); @@ -39,7 +41,7 @@ static inline void set_bit(int nr, unsigned int *addr) *p |= mask; } -static inline void clear_bit(int nr, unsigned int *addr) +static inline void clear_bit(int nr, void *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); -- cgit v1.2.3 From 682a4ced21a598117e47b947d34e4d1d0fa82e46 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 31 Mar 2021 11:13:41 +0900 Subject: exfatprogs: release 1.1.1 version 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. Signed-off-by: Hyunchul Lee --- NEWS | 16 ++++++++++++++++ include/version.h | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index d8bd4e4..9c4e72b 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,19 @@ +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 ====================================== diff --git a/include/version.h b/include/version.h index e444145..ae6291f 100644 --- a/include/version.h +++ b/include/version.h @@ -5,6 +5,6 @@ #ifndef _VERSION_H -#define EXFAT_PROGS_VERSION "1.1.0" +#define EXFAT_PROGS_VERSION "1.1.1" #endif /* !_VERSION_H */ -- cgit v1.2.3