summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 20:16:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 20:16:44 +0000
commit367f23a94b60c40f76716e2e50566b686baf36b8 (patch)
tree3b6280f7c05bee0df7f9109958a44bfbc54d7639 /include
parentInitial commit. (diff)
downloadexfatprogs-367f23a94b60c40f76716e2e50566b686baf36b8.tar.xz
exfatprogs-367f23a94b60c40f76716e2e50566b686baf36b8.zip
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'include')
-rw-r--r--include/exfat_dir.h100
-rw-r--r--include/exfat_fs.h88
-rw-r--r--include/exfat_ondisk.h234
-rw-r--r--include/libexfat.h213
-rw-r--r--include/list.h333
-rw-r--r--include/version.h10
6 files changed, 978 insertions, 0 deletions
diff --git a/include/exfat_dir.h b/include/exfat_dir.h
new file mode 100644
index 0000000..d450c61
--- /dev/null
+++ b/include/exfat_dir.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2021 LG Electronics.
+ *
+ * Author(s): Hyunchul Lee <hyc.lee@gmail.com>
+ */
+
+#ifndef _DIR_H_
+#define _DIR_H_
+
+struct exfat;
+struct exfat_inode;
+struct exfat_dentry_loc;
+struct buffer_desc;
+
+struct exfat_de_iter {
+ struct exfat *exfat;
+ struct exfat_inode *parent;
+ struct buffer_desc *buffer_desc; /* cluster * 2 */
+ __u32 ra_next_clus;
+ unsigned int ra_begin_offset;
+ unsigned int ra_partial_size;
+ unsigned int read_size; /* cluster size */
+ unsigned int write_size; /* sector size */
+ off_t de_file_offset;
+ off_t next_read_offset;
+ int max_skip_dentries;
+#define INVALID_NAME_NUM_MAX 9999999
+ unsigned int invalid_name_num;
+
+ char *name_hash_bitmap; /* bitmap of children's name hashes */
+};
+
+struct exfat_lookup_filter {
+ struct {
+ uint8_t type;
+ int dentry_count;
+ /* return 0 if matched, return 1 if not matched,
+ * otherwise return errno
+ */
+ int (*filter)(struct exfat_de_iter *iter,
+ void *param, int *dentry_count);
+ void *param;
+ } in;
+ struct {
+ struct exfat_dentry *dentry_set;
+ int dentry_count;
+ off_t file_offset;
+ /*
+ * If the dentry_set found:
+ * - device offset where the dentry_set locates.
+ * If the dentry_set not found:
+ * - device offset where the first empty dentry_set locates
+ * if in.dentry_count > 0 and there are enough empty dentry.
+ * - device offset where the last empty dentry_set locates
+ * if in.dentry_count = 0 or no enough empty dentry.
+ * - EOF if no empty dentry_set.
+ */
+ off_t dev_offset;
+ } out;
+};
+
+int exfat_de_iter_init(struct exfat_de_iter *iter, struct exfat *exfat,
+ struct exfat_inode *dir, struct buffer_desc *bd);
+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_device_offset(struct exfat_de_iter *iter);
+off_t exfat_de_iter_file_offset(struct exfat_de_iter *iter);
+
+int exfat_lookup_dentry_set(struct exfat *exfat, struct exfat_inode *parent,
+ struct exfat_lookup_filter *filter);
+int exfat_lookup_file(struct exfat *exfat, struct exfat_inode *parent,
+ const char *name, struct exfat_lookup_filter *filter_out);
+int exfat_lookup_file_by_utf16name(struct exfat *exfat,
+ struct exfat_inode *parent,
+ __le16 *utf16_name,
+ struct exfat_lookup_filter *filter_out);
+
+int exfat_create_file(struct exfat *exfat, struct exfat_inode *parent,
+ const char *name, unsigned short attr);
+int exfat_update_file_dentry_set(struct exfat *exfat,
+ struct exfat_dentry *dset, int dcount,
+ const char *name,
+ clus_t start_clu, clus_t ccount);
+int exfat_build_file_dentry_set(struct exfat *exfat, const char *name,
+ unsigned short attr, struct exfat_dentry **dentry_set,
+ int *dentry_count);
+int exfat_add_dentry_set(struct exfat *exfat, struct exfat_dentry_loc *loc,
+ struct exfat_dentry *dset, int dcount,
+ bool need_next_loc);
+void exfat_calc_dentry_checksum(struct exfat_dentry *dentry,
+ uint16_t *checksum, bool primary);
+uint16_t exfat_calc_name_hash(struct exfat *exfat,
+ __le16 *name, int len);
+
+#endif
diff --git a/include/exfat_fs.h b/include/exfat_fs.h
new file mode 100644
index 0000000..d35b12c
--- /dev/null
+++ b/include/exfat_fs.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2021 LG Electronics.
+ *
+ * Author(s): Hyunchul Lee <hyc.lee@gmail.com>
+ */
+#ifndef _EXFAT_FS_H_
+#define _EXFAT_FS_H_
+
+#include "list.h"
+
+struct exfat_dentry;
+
+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;
+ uint64_t size;
+ bool is_contiguous;
+ struct exfat_dentry *dentry_set;
+ int dentry_count;
+ off_t dev_offset;
+ __le16 name[0]; /* only for directory */
+};
+
+#define EXFAT_NAME_MAX 255
+#define NAME_BUFFER_SIZE ((EXFAT_NAME_MAX + 1) * 2)
+
+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;
+ clus_t clus_count;
+ unsigned int clus_size;
+ unsigned int sect_size;
+ char *disk_bitmap;
+ char *alloc_bitmap;
+ char *ohead_bitmap;
+ clus_t disk_bitmap_clus;
+ unsigned int disk_bitmap_size;
+ __u16 *upcase_table;
+ clus_t start_clu;
+ char *zero_cluster;
+};
+
+struct exfat_dentry_loc {
+ struct exfat_inode *parent;
+ off_t file_offset;
+ off_t dev_offset;
+};
+
+struct path_resolve_ctx {
+ struct exfat_inode *ancestors[255];
+ __le16 utf16_path[PATH_MAX + 2];
+ char local_path[PATH_MAX * MB_LEN_MAX + 1];
+};
+
+struct buffer_desc {
+ __u32 p_clus;
+ unsigned int offset;
+ char *buffer;
+ char *dirty;
+};
+
+struct exfat *exfat_alloc_exfat(struct exfat_blk_dev *blk_dev, struct pbr *bs);
+void exfat_free_exfat(struct exfat *exfat);
+
+struct exfat_inode *exfat_alloc_inode(__u16 attr);
+void exfat_free_inode(struct exfat_inode *node);
+
+void exfat_free_children(struct exfat_inode *dir, bool file_only);
+void exfat_free_file_children(struct exfat_inode *dir);
+void exfat_free_ancestors(struct exfat_inode *child);
+void exfat_free_dir_list(struct exfat *exfat);
+
+int exfat_resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child);
+int exfat_resolve_path_parent(struct path_resolve_ctx *ctx,
+ struct exfat_inode *parent, struct exfat_inode *child);
+
+struct buffer_desc *exfat_alloc_buffer(int count,
+ unsigned int clu_size, unsigned int sect_size);
+void exfat_free_buffer(struct buffer_desc *bd, int count);
+#endif
diff --git a/include/exfat_ondisk.h b/include/exfat_ondisk.h
new file mode 100644
index 0000000..42cdadf
--- /dev/null
+++ b/include/exfat_ondisk.h
@@ -0,0 +1,234 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
+ */
+
+#ifndef _EXFAT_H
+#define _EXFAT_H
+
+#include <stdint.h>
+#include <linux/fs.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WORDS_BIGENDIAN
+#define cpu_to_le16(x) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))
+#define cpu_to_le32(x) \
+ ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | \
+ (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24))
+#define cpu_to_le64(x) (cpu_to_le32((uint64_t)(x)) << 32 | \
+ cpu_to_le32((uint64_t)(x) >> 32))
+#else
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le64(x) (x)
+#endif
+
+#define le64_to_cpu(x) ((uint64_t)cpu_to_le64(x))
+#define le32_to_cpu(x) ((uint32_t)cpu_to_le32(x))
+#define le16_to_cpu(x) ((uint16_t)cpu_to_le16(x))
+
+#define PBR_SIGNATURE 0xAA55
+
+#define VOL_CLEAN 0x0000
+#define VOL_DIRTY 0x0002
+
+#define DENTRY_SIZE 32 /* directory entry size */
+#define DENTRY_SIZE_BITS 5
+/* exFAT allows 8388608(256MB) directory entries */
+#define MAX_EXFAT_DENTRIES 8388608
+#define MIN_FILE_DENTRIES 3
+#define MAX_NAME_DENTRIES 17
+
+/* dentry types */
+#define MSDOS_DELETED 0xE5 /* deleted mark */
+#define MSDOS_UNUSED 0x00 /* end of directory */
+
+#define EXFAT_LAST 0x00 /* end of directory */
+#define EXFAT_DELETE ~(0x80)
+#define IS_EXFAT_DELETED(x) ((x) < 0x80) /* deleted file (0x01~0x7F) */
+#define EXFAT_INVAL 0x80 /* invalid value */
+#define EXFAT_BITMAP 0x81 /* allocation bitmap */
+#define EXFAT_UPCASE 0x82 /* upcase table */
+#define EXFAT_VOLUME 0x83 /* volume label */
+#define EXFAT_FILE 0x85 /* file or dir */
+#define EXFAT_GUID 0xA0
+#define EXFAT_PADDING 0xA1
+#define EXFAT_ACLTAB 0xA2
+#define EXFAT_STREAM 0xC0 /* stream entry */
+#define EXFAT_NAME 0xC1 /* file name entry */
+#define EXFAT_ACL 0xC2 /* stream entry */
+
+/* checksum types */
+#define CS_DIR_ENTRY 0
+#define CS_PBR_SECTOR 1
+#define CS_DEFAULT 2
+
+/* file attributes */
+#define ATTR_READONLY 0x0001
+#define ATTR_HIDDEN 0x0002
+#define ATTR_SYSTEM 0x0004
+#define ATTR_VOLUME 0x0008
+#define ATTR_SUBDIR 0x0010
+#define ATTR_ARCHIVE 0x0020
+#define ATTR_EXTEND (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | \
+ ATTR_VOLUME) /* 0x000F */
+
+#define ATTR_EXTEND_MASK (ATTR_EXTEND | ATTR_SUBDIR | ATTR_ARCHIVE)
+#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \
+ ATTR_SUBDIR | ATTR_ARCHIVE)
+
+#define ATTR_READONLY_LE cpu_to_le16(0x0001)
+#define ATTR_HIDDEN_LE cpu_to_le16(0x0002)
+#define ATTR_SYSTEM_LE cpu_to_le16(0x0004)
+#define ATTR_VOLUME_LE cpu_to_le16(0x0008)
+#define ATTR_SUBDIR_LE cpu_to_le16(0x0010)
+#define ATTR_ARCHIVE_LE cpu_to_le16(0x0020)
+
+/* stream flags */
+#define EXFAT_SF_CONTIGUOUS 0x02
+
+#define CLUSTER_32(x) ((unsigned int)((x) & 0xFFFFFFFFU))
+#define EXFAT_EOF_CLUSTER CLUSTER_32(~0)
+#define EXFAT_BAD_CLUSTER (0xFFFFFFF7U)
+#define EXFAT_FREE_CLUSTER (0)
+#define EXFAT_FIRST_CLUSTER (2)
+#define EXFAT_RESERVED_CLUSTERS (2)
+
+
+/* EXFAT BIOS parameter block (64 bytes) */
+struct bpb64 {
+ __u8 jmp_boot[3];
+ __u8 oem_name[8];
+ __u8 res_zero[53];
+};
+
+/* EXFAT EXTEND BIOS parameter block (56 bytes) */
+struct bsx64 {
+ __le64 vol_offset;
+ __le64 vol_length;
+ __le32 fat_offset;
+ __le32 fat_length;
+ __le32 clu_offset;
+ __le32 clu_count;
+ __le32 root_cluster;
+ __le32 vol_serial;
+ __u8 fs_version[2];
+ __le16 vol_flags;
+ __u8 sect_size_bits;
+ __u8 sect_per_clus_bits;
+ __u8 num_fats;
+ __u8 phy_drv_no;
+ __u8 perc_in_use;
+ __u8 reserved2[7];
+};
+
+/* Common PBR[Partition Boot Record] (512 bytes) */
+struct pbr {
+ struct bpb64 bpb;
+ struct bsx64 bsx;
+ __u8 boot_code[390];
+ __le16 signature;
+};
+
+#define VOLUME_LABEL_MAX_LEN 11
+#define VOLUME_GUID_LEN 16
+#define ENTRY_NAME_MAX 15
+
+struct exfat_dentry {
+ __u8 type;
+ union {
+ struct {
+ __u8 character_count;
+ __le16 volume_label[VOLUME_LABEL_MAX_LEN];
+ __u8 reserved[8];
+ } __attribute__((packed)) vol; /* file directory entry */
+
+ struct {
+ __u8 num_ext;
+ __le16 checksum;
+ __le16 attr;
+ __le16 reserved1;
+ __le16 create_time;
+ __le16 create_date;
+ __le16 modify_time;
+ __le16 modify_date;
+ __le16 access_time;
+ __le16 access_date;
+ __u8 create_time_ms;
+ __u8 modify_time_ms;
+ __u8 create_tz;
+ __u8 modify_tz;
+ __u8 access_tz;
+ __u8 reserved2[7];
+ } __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 */
+ struct {
+ __u8 num_ext;
+ __le16 checksum;
+ __u16 flags;
+ __u8 guid[VOLUME_GUID_LEN];
+ __u8 reserved[10];
+ } __attribute__((packed)) guid; /* volume GUID 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/libexfat.h b/include/libexfat.h
new file mode 100644
index 0000000..9e853a8
--- /dev/null
+++ b/include/libexfat.h
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
+ */
+
+#ifndef _LIBEXFAT_H
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <wchar.h>
+#include <limits.h>
+
+typedef __u32 clus_t;
+
+#define KB (1024)
+#define MB (1024*1024)
+#define GB (1024UL*1024UL*1024UL)
+
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
+#define round_down(x, y) ((x) & ~__round_mask(x, y))
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define DIV_ROUND_UP(__i, __d) (((__i) + (__d) - 1) / (__d))
+
+#define EXFAT_MIN_NUM_SEC_VOL (2048)
+#define EXFAT_MAX_NUM_SEC_VOL ((2 << 64) - 1)
+
+#define EXFAT_MAX_NUM_CLUSTER (0xFFFFFFF5)
+
+#define DEFAULT_BOUNDARY_ALIGNMENT (1024*1024)
+
+#define DEFAULT_SECTOR_SIZE (512)
+
+#define VOLUME_LABEL_BUFFER_SIZE (VOLUME_LABEL_MAX_LEN*MB_LEN_MAX+1)
+
+/* Upcase table macro */
+#define EXFAT_UPCASE_TABLE_CHARS (0x10000)
+#define EXFAT_UPCASE_TABLE_SIZE (5836)
+
+/* Flags for tune.exfat and exfatlabel */
+#define EXFAT_GET_VOLUME_LABEL 0x01
+#define EXFAT_SET_VOLUME_LABEL 0x02
+#define EXFAT_GET_VOLUME_SERIAL 0x03
+#define EXFAT_SET_VOLUME_SERIAL 0x04
+#define EXFAT_GET_VOLUME_GUID 0x05
+#define EXFAT_SET_VOLUME_GUID 0x06
+
+#define EXFAT_MAX_SECTOR_SIZE 4096
+
+#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)
+
+#define EXFAT_MAX_HASH_COUNT (UINT16_MAX + 1)
+
+enum {
+ BOOT_SEC_IDX = 0,
+ EXBOOT_SEC_IDX,
+ EXBOOT_SEC_NUM = 8,
+ OEM_SEC_IDX,
+ RESERVED_SEC_IDX,
+ CHECKSUM_SEC_IDX,
+ BACKUP_BOOT_SEC_IDX,
+};
+
+struct exfat_blk_dev {
+ int dev_fd;
+ unsigned long long offset;
+ unsigned long long size;
+ unsigned int sector_size;
+ unsigned int sector_size_bits;
+ unsigned long long num_sectors;
+ unsigned int num_clusters;
+ unsigned int cluster_size;
+};
+
+struct exfat_user_input {
+ char dev_name[255];
+ bool writeable;
+ unsigned int cluster_size;
+ unsigned int sec_per_clu;
+ unsigned int boundary_align;
+ bool pack_bitmap;
+ bool quick;
+ __u16 volume_label[VOLUME_LABEL_MAX_LEN];
+ int volume_label_len;
+ unsigned int volume_serial;
+ const char *guid;
+};
+
+struct exfat;
+struct exfat_inode;
+
+#ifdef WORDS_BIGENDIAN
+typedef __u8 bitmap_t;
+#else
+typedef __u32 bitmap_t;
+#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 BITMAP_GET(bmap, bit) \
+ (((bitmap_t *)(bmap))[BIT_ENTRY(bit)] & BIT_MASK(bit))
+
+#define BITMAP_SET(bmap, bit) \
+ (((bitmap_t *)(bmap))[BIT_ENTRY(bit)] |= BIT_MASK(bit))
+
+static inline bool exfat_bitmap_get(char *bmap, clus_t c)
+{
+ clus_t cc = c - EXFAT_FIRST_CLUSTER;
+
+ return BITMAP_GET(bmap, cc);
+}
+
+static inline void exfat_bitmap_set(char *bmap, clus_t c)
+{
+ clus_t cc = c - EXFAT_FIRST_CLUSTER;
+
+ BITMAP_SET(bmap, cc);
+}
+
+static inline void exfat_bitmap_clear(char *bmap, clus_t c)
+{
+ clus_t cc = c - EXFAT_FIRST_CLUSTER;
+ (((bitmap_t *)(bmap))[BIT_ENTRY(cc)] &= ~BIT_MASK(cc));
+}
+
+void exfat_bitmap_set_range(struct exfat *exfat, char *bitmap,
+ clus_t start_clus, clus_t count);
+int exfat_bitmap_find_zero(struct exfat *exfat, char *bmap,
+ clus_t start_clu, clus_t *next);
+int exfat_bitmap_find_one(struct exfat *exfat, char *bmap,
+ clus_t start_clu, clus_t *next);
+
+void show_version(void);
+
+wchar_t exfat_bad_char(wchar_t w);
+void boot_calc_checksum(unsigned char *sector, unsigned short size,
+ bool is_boot_sec, __le32 *checksum);
+void init_user_input(struct exfat_user_input *ui);
+int exfat_get_blk_dev_info(struct exfat_user_input *ui,
+ struct exfat_blk_dev *bd);
+ssize_t exfat_read(int fd, void *buf, size_t size, off_t offset);
+ssize_t exfat_write(int fd, void *buf, size_t size, off_t offset);
+
+size_t exfat_utf16_len(const __le16 *str, size_t max_size);
+ssize_t exfat_utf16_enc(const char *in_str, __u16 *out_str, size_t out_size);
+ssize_t exfat_utf16_dec(const __u16 *in_str, size_t in_len,
+ char *out_str, size_t out_size);
+off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd);
+int exfat_read_volume_label(struct exfat *exfat);
+int exfat_set_volume_label(struct exfat *exfat, char *label_input);
+int __exfat_set_volume_guid(struct exfat_dentry *dentry, const char *guid);
+int exfat_read_volume_guid(struct exfat *exfat);
+int exfat_set_volume_guid(struct exfat *exfat, const char *guid);
+int exfat_read_sector(struct exfat_blk_dev *bd, void *buf,
+ unsigned int sec_off);
+int exfat_write_sector(struct exfat_blk_dev *bd, void *buf,
+ unsigned int sec_off);
+int exfat_write_checksum_sector(struct exfat_blk_dev *bd,
+ unsigned int checksum, bool is_backup);
+char *exfat_conv_volume_label(struct exfat_dentry *vol_entry);
+int exfat_show_volume_serial(int fd);
+int exfat_set_volume_serial(struct exfat_blk_dev *bd,
+ struct exfat_user_input *ui);
+unsigned int exfat_clus_to_blk_dev_off(struct exfat_blk_dev *bd,
+ unsigned int clu_off, unsigned int clu);
+int exfat_get_next_clus(struct exfat *exfat, clus_t clus, clus_t *next);
+int exfat_get_inode_next_clus(struct exfat *exfat, struct exfat_inode *node,
+ clus_t clus, clus_t *next);
+int exfat_set_fat(struct exfat *exfat, clus_t clus, clus_t next_clus);
+off_t exfat_s2o(struct exfat *exfat, off_t sect);
+off_t exfat_c2o(struct exfat *exfat, unsigned int clus);
+int exfat_o2c(struct exfat *exfat, off_t device_offset,
+ unsigned int *clu, unsigned int *offset);
+bool exfat_heap_clus(struct exfat *exfat, clus_t clus);
+int exfat_root_clus_count(struct exfat *exfat);
+int read_boot_sect(struct exfat_blk_dev *bdev, struct pbr **bs);
+
+/*
+ * Exfat Print
+ */
+
+extern unsigned int print_level;
+
+#define EXFAT_ERROR (1)
+#define EXFAT_INFO (2)
+#define EXFAT_DEBUG (3)
+
+#define exfat_msg(level, dir, fmt, ...) \
+ do { \
+ if (print_level >= level) { \
+ fprintf(dir, fmt, ##__VA_ARGS__); \
+ } \
+ } while (0) \
+
+#define exfat_err(fmt, ...) exfat_msg(EXFAT_ERROR, stderr, \
+ fmt, ##__VA_ARGS__)
+#define exfat_info(fmt, ...) exfat_msg(EXFAT_INFO, stdout, \
+ fmt, ##__VA_ARGS__)
+#define exfat_debug(fmt, ...) exfat_msg(EXFAT_DEBUG, stdout, \
+ "[%s:%4d] " fmt, __func__, \
+ __LINE__, ##__VA_ARGS__)
+
+#endif /* !_LIBEXFAT_H */
diff --git a/include/list.h b/include/list.h
new file mode 100644
index 0000000..cc93668
--- /dev/null
+++ b/include/list.h
@@ -0,0 +1,333 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define container_of(ptr, type, member) ({ \
+ const typeof(((type *)0)->member) * __mptr = (ptr); \
+ (type *)((char *)__mptr - offsetof(type, member)); \
+ })
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/**
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+ pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ * list_for_each_entry_continue
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - iterate over list of given type
+ * continuing after existing point
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against
+ * removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue - iterate over list of given type
+ * continuing after existing point safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse - iterate backwards over list of given
+ * type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+#endif
diff --git a/include/version.h b/include/version.h
new file mode 100644
index 0000000..f3cf9e2
--- /dev/null
+++ b/include/version.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020 Namjae Jeon <linkinjeon@kernel.org>
+ */
+
+#ifndef _VERSION_H
+
+#define EXFAT_PROGS_VERSION "1.2.2"
+
+#endif /* !_VERSION_H */