Skip to content

Commit

Permalink
Merge pull request exfatprogs#271 from exfatprogs/exfat-next
Browse files Browse the repository at this point in the history
Merge patches in exfat-next branch to master for 1.2.5 release
  • Loading branch information
namjaejeon authored Aug 5, 2024
2 parents 262f69b + 13d7fc8 commit d5ace3a
Show file tree
Hide file tree
Showing 18 changed files with 148 additions and 99 deletions.
15 changes: 12 additions & 3 deletions .github/workflows/c-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ jobs:
- uses: actions/checkout@v4
- name: before test
run: |
sudo apt-get install linux-headers-$(uname -r)
sudo apt-get install xz-utils
sudo apt-get install linux-headers-$(uname -r) xz-utils \
gcc-mips-linux-gnu qemu-system-mips \
qemu-user
git clone https://github.com/namjaejeon/linux-exfat-oot
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export PATH=/usr/local/lib:$PATH
Expand All @@ -30,10 +31,18 @@ jobs:
./configure > /dev/null
make -j$((`nproc`+1)) > /dev/null
sudo make install > /dev/null
make distclean > /dev/null
./configure --host=mips-linux-gnu CFLAGS=--static > /dev/null
make -j$((`nproc`+1)) > /dev/null
- name: run fsck repair testcases
run: |
cd tests
sudo ./test_fsck.sh
export FSCK1="qemu-mips ../fsck/fsck.exfat"
export FSCK2="fsck.exfat"
sudo -E ./test_fsck.sh
export FSCK1="fsck.exfat"
export FSCK2="qemu-mips ../fsck/fsck.exfat"
sudo -E ./test_fsck.sh
- name: create file/director test
run: |
cd linux-exfat-oot
Expand Down
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ notifications:
- email: true

before_script:
- sudo apt-get install linux-headers-$(uname -r)
- sudo apt-get install xz-utils
- sudo apt-get install linux-headers-$(uname -r) xz-utils
- 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
Expand Down
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dist_man8_MANS = \
# other stuff
EXTRA_DIST = \
include \
tests \
Android.bp \
lib/Android.bp \
mkfs/Android.bp \
Expand Down
5 changes: 2 additions & 3 deletions dump/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,11 +244,10 @@ int main(int argc, char *argv[])
if (version_only)
exit(EXIT_FAILURE);

if (argc < 2)
if (argc - optind != 1)
usage();

memset(ui.dev_name, 0, sizeof(ui.dev_name));
snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[1]);
ui.dev_name = argv[1];

ret = exfat_get_blk_dev_info(&ui, &bd);
if (ret < 0)
Expand Down
2 changes: 1 addition & 1 deletion exfat2img/exfat2img.c
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ int main(int argc, char * const argv[])
}

memset(&ui, 0, sizeof(ui));
snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", blkdev_path);
ui.dev_name = blkdev_path;
if (restore)
ui.writeable = true;
else
Expand Down
54 changes: 27 additions & 27 deletions fsck/fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,6 @@ static int handle_duplicated_filename(struct exfat_de_iter *iter,
{
int ret;
struct exfat_lookup_filter filter;
char filename[PATH_MAX + 1] = {0};

ret = exfat_lookup_file_by_utf16name(iter->exfat, iter->parent,
inode->name, &filter);
Expand All @@ -660,14 +659,7 @@ static int handle_duplicated_filename(struct exfat_de_iter *iter,
if (exfat_de_iter_device_offset(iter) == filter.out.dev_offset)
return 0;

ret = exfat_utf16_dec(inode->name, NAME_BUFFER_SIZE, filename,
PATH_MAX);
if (ret < 0) {
exfat_err("failed to decode filename\n");
return ret;
}

return exfat_repair_rename_ask(&exfat_fsck, iter, filename,
return exfat_repair_rename_ask(&exfat_fsck, iter, inode->name,
ER_DE_DUPLICATED_NAME, "filename is duplicated");
}

Expand All @@ -682,7 +674,7 @@ static int check_name_dentry_set(struct exfat_de_iter *iter,
exfat_de_iter_get(iter, 1, &stream_de);

name_len = exfat_utf16_len(inode->name, NAME_BUFFER_SIZE);
if (stream_de->stream_name_len != name_len) {
if (name_len && stream_de->stream_name_len != name_len) {
if (repair_file_ask(iter, NULL, ER_DE_NAME_LEN,
"the name length of a file is wrong")) {
exfat_de_iter_get_dirty(iter, 1, &stream_de);
Expand All @@ -693,6 +685,18 @@ static int check_name_dentry_set(struct exfat_de_iter *iter,
}
}

ret = exfat_check_name(inode->name, stream_de->stream_name_len);
if (ret != stream_de->stream_name_len) {
char err_msg[36];

snprintf(err_msg, sizeof(err_msg),
"filename has invalid character '%c'",
le16_to_cpu(inode->name[ret]));

return exfat_repair_rename_ask(&exfat_fsck, iter, inode->name,
ER_DE_INVALID_NAME, err_msg);
}

hash = exfat_calc_name_hash(iter->exfat, inode->name, (int)name_len);
if (cpu_to_le16(hash) != stream_de->stream_name_hash) {
if (repair_file_ask(iter, NULL, ER_DE_NAME_HASH,
Expand All @@ -713,21 +717,18 @@ static int check_name_dentry_set(struct exfat_de_iter *iter,
return ret;
}

const __le16 MSDOS_DOT[ENTRY_NAME_MAX] = {cpu_to_le16(46), 0, };
const __le16 MSDOS_DOTDOT[ENTRY_NAME_MAX] = {cpu_to_le16(46), cpu_to_le16(46), 0, };

static int handle_dot_dotdot_filename(struct exfat_de_iter *iter,
struct exfat_dentry *dentry,
__le16 *filename,
int strm_name_len)
{
char *filename;
int i;

if (!memcmp(dentry->name_unicode, MSDOS_DOT, strm_name_len * 2))
filename = ".";
else if (!memcmp(dentry->name_unicode, MSDOS_DOTDOT,
strm_name_len * 2))
filename = "..";
else
for (i = 0; i < strm_name_len; i++) {
if (filename[i] != UTF16_DOT)
return 0;
}

if (filename[i])
return 0;

return exfat_repair_rename_ask(&exfat_fsck, iter, filename,
Expand Down Expand Up @@ -817,7 +818,7 @@ static int read_file_dentry_set(struct exfat_de_iter *iter,
}

if (file_de->file_num_ext == 2 && stream_de->stream_name_len <= 2) {
ret = handle_dot_dotdot_filename(iter, dentry,
ret = handle_dot_dotdot_filename(iter, node->name,
stream_de->stream_name_len);
if (ret < 0) {
*skip_dentries = file_de->file_num_ext + 1;
Expand Down Expand Up @@ -1005,7 +1006,7 @@ static int read_bitmap(struct exfat *exfat)
exfat->disk_bitmap_size = DIV_ROUND_UP(exfat->clus_count, 8);

exfat_bitmap_set_range(exfat, exfat->alloc_bitmap,
le64_to_cpu(dentry->bitmap_start_clu),
le32_to_cpu(dentry->bitmap_start_clu),
DIV_ROUND_UP(exfat->disk_bitmap_size,
exfat->clus_size));
free(filter.out.dentry_set);
Expand Down Expand Up @@ -1034,9 +1035,8 @@ static int decompress_upcase_table(const __le16 *in_table, size_t in_len,
ch = le16_to_cpu(in_table[i]);

if (ch == 0xFFFF && i + 1 < in_len) {
uint16_t len = le16_to_cpu(in_table[++i]);

k += len;
++i;
k += le16_to_cpu(in_table[i]);
} else {
out_table[k++] = ch;
}
Expand Down Expand Up @@ -1616,7 +1616,7 @@ int main(int argc, char * const argv[])

exfat_fsck.options = ui.options;

snprintf(ui.ei.dev_name, sizeof(ui.ei.dev_name), "%s", argv[optind]);
ui.ei.dev_name = 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);
Expand Down
79 changes: 44 additions & 35 deletions fsck/repair.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ static struct exfat_repair_problem problems[] = {
{ER_DE_NAME_LEN, ERF_PREEN_YES, ERP_FIX, 0, 0, 0},
{ER_DE_DOT_NAME, ERF_PREEN_YES, ERP_RENAME, 2, 3, 4},
{ER_DE_DUPLICATED_NAME, ERF_PREEN_YES, ERP_RENAME, 2, 3, 4},
{ER_DE_INVALID_NAME, ERF_PREEN_YES, ERP_RENAME, 2, 3, 4},
{ER_FILE_VALID_SIZE, ERF_PREEN_YES, ERP_FIX, 0, 0, 0},
{ER_FILE_INVALID_CLUS, ERF_PREEN_YES, ERP_TRUNCATE, 0, 0, 0},
{ER_FILE_FIRST_CLUS, ERF_PREEN_YES, ERP_TRUNCATE, 0, 0, 0},
Expand Down Expand Up @@ -160,36 +161,37 @@ int exfat_repair_ask(struct exfat_fsck *fsck, er_problem_code_t prcode,
return repair;
}

static int check_bad_char(char w)
{
return (w < 0x0020) || (w == '*') || (w == '?') || (w == '<') ||
(w == '>') || (w == '|') || (w == '"') || (w == ':') ||
(w == '/') || (w == '\\');
}

static char *get_rename_from_user(struct exfat_de_iter *iter)
static int get_rename_from_user(struct exfat_de_iter *iter,
__le16 *utf16_name, int name_size)
{
int len = 0;
char *rename = malloc(ENTRY_NAME_MAX + 2);

if (!rename)
return NULL;
return -ENOMEM;

retry:
/* +2 means LF(Line Feed) and NULL terminator */
memset(rename, 0x1, ENTRY_NAME_MAX + 2);
printf("New name: ");
if (fgets(rename, ENTRY_NAME_MAX + 2, stdin)) {
int i, len, err;
int err;
struct exfat_lookup_filter filter;

len = strlen(rename);
/* Remove LF in filename */
rename[len - 1] = '\0';
for (i = 0; i < len - 1; i++) {
if (check_bad_char(rename[i])) {
printf("filename contain invalid character(%c)\n", rename[i]);
goto retry;
}

memset(utf16_name, 0, name_size);
len = exfat_utf16_enc(rename, utf16_name, name_size);
if (len < 0)
goto out;

err = exfat_check_name(utf16_name, len >> 1);
if (err != len >> 1) {
printf("filename contain invalid character(%c)\n",
le16_to_cpu(utf16_name[err]));
goto retry;
}

exfat_de_iter_flush(iter);
Expand All @@ -200,23 +202,27 @@ static char *get_rename_from_user(struct exfat_de_iter *iter)
}
}

return rename;
out:
free(rename);

return len;
}

static char *generate_rename(struct exfat_de_iter *iter)
static int generate_rename(struct exfat_de_iter *iter, __le16 *utf16_name,
int name_size)
{
int err;
char *rename;

if (iter->invalid_name_num > INVALID_NAME_NUM_MAX)
return NULL;
return -ERANGE;

rename = malloc(ENTRY_NAME_MAX + 1);
if (!rename)
return NULL;
return -ENOMEM;

while (1) {
struct exfat_lookup_filter filter;
int err;

snprintf(rename, ENTRY_NAME_MAX + 1, "FILE%07d.CHK",
iter->invalid_name_num++);
Expand All @@ -227,13 +233,23 @@ static char *generate_rename(struct exfat_de_iter *iter)
break;
}

return rename;
memset(utf16_name, 0, name_size);
err = exfat_utf16_enc(rename, utf16_name, name_size);
free(rename);

return err;
}

int exfat_repair_rename_ask(struct exfat_fsck *fsck, struct exfat_de_iter *iter,
char *old_name, er_problem_code_t prcode, char *error_msg)
__le16 *uname, er_problem_code_t prcode, char *error_msg)
{
int num;
char old_name[PATH_MAX + 1] = {0};

if (exfat_utf16_dec(uname, NAME_BUFFER_SIZE, old_name, PATH_MAX) <= 0) {
exfat_err("failed to decode filename\n");
return -EINVAL;
}

ask_again:
num = exfat_repair_ask(fsck, prcode, "ERROR: '%s' %s.\n%s",
Expand All @@ -243,38 +259,31 @@ int exfat_repair_rename_ask(struct exfat_fsck *fsck, struct exfat_de_iter *iter,
" [3] Bypass this check(No repair)\n");
if (num) {
__le16 utf16_name[ENTRY_NAME_MAX];
char *rename = NULL;
__u16 hash;
struct exfat_dentry *dentry;
int ret;

switch (num) {
case 1:
rename = get_rename_from_user(iter);
ret = get_rename_from_user(iter, utf16_name,
sizeof(utf16_name));
break;
case 2:
rename = generate_rename(iter);
ret = generate_rename(iter, utf16_name,
sizeof(utf16_name));
break;
case 3:
break;
return -EINVAL;
default:
exfat_info("select 1 or 2 number instead of %d\n", num);
goto ask_again;
}

if (!rename)
if (ret < 0)
return -EINVAL;

exfat_info("%s filename is renamed to %s\n", old_name, rename);

exfat_de_iter_get_dirty(iter, 2, &dentry);

memset(utf16_name, 0, sizeof(utf16_name));
ret = exfat_utf16_enc(rename, utf16_name, sizeof(utf16_name));
free(rename);
if (ret < 0)
return ret;

ret >>= 1;
memcpy(dentry->name_unicode, utf16_name, ENTRY_NAME_MAX * 2);
hash = exfat_calc_name_hash(iter->exfat, utf16_name, ret);
Expand Down
3 changes: 2 additions & 1 deletion fsck/repair.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define ER_DE_NAME_LEN 0x00001032
#define ER_DE_DOT_NAME 0x00001033
#define ER_DE_DUPLICATED_NAME 0x00001034
#define ER_DE_INVALID_NAME 0x00001035
#define ER_FILE_VALID_SIZE 0x00002001
#define ER_FILE_INVALID_CLUS 0x00002002
#define ER_FILE_FIRST_CLUS 0x00002003
Expand All @@ -35,5 +36,5 @@ int exfat_repair_ask(struct exfat_fsck *fsck, er_problem_code_t prcode,
const char *fmt, ...);

int exfat_repair_rename_ask(struct exfat_fsck *fsck, struct exfat_de_iter *iter,
char *old_name, er_problem_code_t prcode, char *error_msg);
__le16 *uname, er_problem_code_t prcode, char *error_msg);
#endif
Loading

0 comments on commit d5ace3a

Please sign in to comment.