|
@@ -35,6 +35,11 @@
|
|
|
#define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1)
|
|
|
#define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t))
|
|
|
|
|
|
+static inline unsigned char fat_tolower(unsigned char c)
|
|
|
+{
|
|
|
+ return ((c >= 'A') && (c <= 'Z')) ? c+32 : c;
|
|
|
+}
|
|
|
+
|
|
|
static inline loff_t fat_make_i_pos(struct super_block *sb,
|
|
|
struct buffer_head *bh,
|
|
|
struct msdos_dir_entry *de)
|
|
@@ -333,6 +338,124 @@ parse_long:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * fat_parse_short - Parse MS-DOS (short) directory entry.
|
|
|
+ * @sb: superblock
|
|
|
+ * @de: directory entry to parse
|
|
|
+ * @name: FAT_MAX_SHORT_SIZE array in which to place extracted name
|
|
|
+ * @dot_hidden: Nonzero == prepend '.' to names with ATTR_HIDDEN
|
|
|
+ *
|
|
|
+ * Returns the number of characters extracted into 'name'.
|
|
|
+ */
|
|
|
+static int fat_parse_short(struct super_block *sb,
|
|
|
+ const struct msdos_dir_entry *de,
|
|
|
+ unsigned char *name, int dot_hidden)
|
|
|
+{
|
|
|
+ const struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
|
|
+ int isvfat = sbi->options.isvfat;
|
|
|
+ int nocase = sbi->options.nocase;
|
|
|
+ unsigned short opt_shortname = sbi->options.shortname;
|
|
|
+ struct nls_table *nls_disk = sbi->nls_disk;
|
|
|
+ wchar_t uni_name[14];
|
|
|
+ unsigned char c, work[MSDOS_NAME];
|
|
|
+ unsigned char *ptname = name;
|
|
|
+ int chi, chl, i, j, k;
|
|
|
+ int dotoffset = 0;
|
|
|
+ int name_len = 0, uni_len = 0;
|
|
|
+
|
|
|
+ if (!isvfat && dot_hidden && (de->attr & ATTR_HIDDEN)) {
|
|
|
+ *ptname++ = '.';
|
|
|
+ dotoffset = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy(work, de->name, sizeof(work));
|
|
|
+ /* see namei.c, msdos_format_name */
|
|
|
+ if (work[0] == 0x05)
|
|
|
+ work[0] = 0xE5;
|
|
|
+
|
|
|
+ /* Filename */
|
|
|
+ for (i = 0, j = 0; i < 8;) {
|
|
|
+ c = work[i];
|
|
|
+ if (!c)
|
|
|
+ break;
|
|
|
+ chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
|
|
|
+ &uni_name[j++], opt_shortname,
|
|
|
+ de->lcase & CASE_LOWER_BASE);
|
|
|
+ if (chl <= 1) {
|
|
|
+ if (!isvfat)
|
|
|
+ ptname[i] = nocase ? c : fat_tolower(c);
|
|
|
+ i++;
|
|
|
+ if (c != ' ') {
|
|
|
+ name_len = i;
|
|
|
+ uni_len = j;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ uni_len = j;
|
|
|
+ if (isvfat)
|
|
|
+ i += min(chl, 8-i);
|
|
|
+ else {
|
|
|
+ for (chi = 0; chi < chl && i < 8; chi++, i++)
|
|
|
+ ptname[i] = work[i];
|
|
|
+ }
|
|
|
+ if (chl)
|
|
|
+ name_len = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ i = name_len;
|
|
|
+ j = uni_len;
|
|
|
+ fat_short2uni(nls_disk, ".", 1, &uni_name[j++]);
|
|
|
+ if (!isvfat)
|
|
|
+ ptname[i] = '.';
|
|
|
+ i++;
|
|
|
+
|
|
|
+ /* Extension */
|
|
|
+ for (k = 8; k < MSDOS_NAME;) {
|
|
|
+ c = work[k];
|
|
|
+ if (!c)
|
|
|
+ break;
|
|
|
+ chl = fat_shortname2uni(nls_disk, &work[k], MSDOS_NAME - k,
|
|
|
+ &uni_name[j++], opt_shortname,
|
|
|
+ de->lcase & CASE_LOWER_EXT);
|
|
|
+ if (chl <= 1) {
|
|
|
+ k++;
|
|
|
+ if (!isvfat)
|
|
|
+ ptname[i] = nocase ? c : fat_tolower(c);
|
|
|
+ i++;
|
|
|
+ if (c != ' ') {
|
|
|
+ name_len = i;
|
|
|
+ uni_len = j;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ uni_len = j;
|
|
|
+ if (isvfat) {
|
|
|
+ int offset = min(chl, MSDOS_NAME-k);
|
|
|
+ k += offset;
|
|
|
+ i += offset;
|
|
|
+ } else {
|
|
|
+ for (chi = 0; chi < chl && k < MSDOS_NAME;
|
|
|
+ chi++, i++, k++) {
|
|
|
+ ptname[i] = work[k];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (chl)
|
|
|
+ name_len = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (name_len > 0) {
|
|
|
+ name_len += dotoffset;
|
|
|
+
|
|
|
+ if (sbi->options.isvfat) {
|
|
|
+ uni_name[uni_len] = 0x0000;
|
|
|
+ name_len = fat_uni_to_x8(sb, uni_name, name,
|
|
|
+ FAT_MAX_SHORT_SIZE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return name_len;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Return values: negative -> error, 0 -> not found, positive -> found,
|
|
|
* value is the total amount of slots, including the shortname entry.
|
|
@@ -344,15 +467,11 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
|
|
|
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
|
|
struct buffer_head *bh = NULL;
|
|
|
struct msdos_dir_entry *de;
|
|
|
- struct nls_table *nls_disk = sbi->nls_disk;
|
|
|
unsigned char nr_slots;
|
|
|
- wchar_t bufuname[14];
|
|
|
wchar_t *unicode = NULL;
|
|
|
- unsigned char work[MSDOS_NAME];
|
|
|
unsigned char bufname[FAT_MAX_SHORT_SIZE];
|
|
|
- unsigned short opt_shortname = sbi->options.shortname;
|
|
|
loff_t cpos = 0;
|
|
|
- int chl, i, j, last_u, err, len;
|
|
|
+ int err, len;
|
|
|
|
|
|
err = -ENOENT;
|
|
|
while (1) {
|
|
@@ -380,47 +499,16 @@ parse_record:
|
|
|
goto end_of_dir;
|
|
|
}
|
|
|
|
|
|
- memcpy(work, de->name, sizeof(de->name));
|
|
|
- /* see namei.c, msdos_format_name */
|
|
|
- if (work[0] == 0x05)
|
|
|
- work[0] = 0xE5;
|
|
|
- for (i = 0, j = 0, last_u = 0; i < 8;) {
|
|
|
- if (!work[i])
|
|
|
- break;
|
|
|
- chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
|
|
|
- &bufuname[j++], opt_shortname,
|
|
|
- de->lcase & CASE_LOWER_BASE);
|
|
|
- if (chl <= 1) {
|
|
|
- if (work[i] != ' ')
|
|
|
- last_u = j;
|
|
|
- } else {
|
|
|
- last_u = j;
|
|
|
- }
|
|
|
- i += chl;
|
|
|
- }
|
|
|
- j = last_u;
|
|
|
- fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
|
|
|
- for (i = 8; i < MSDOS_NAME;) {
|
|
|
- if (!work[i])
|
|
|
- break;
|
|
|
- chl = fat_shortname2uni(nls_disk, &work[i],
|
|
|
- MSDOS_NAME - i,
|
|
|
- &bufuname[j++], opt_shortname,
|
|
|
- de->lcase & CASE_LOWER_EXT);
|
|
|
- if (chl <= 1) {
|
|
|
- if (work[i] != ' ')
|
|
|
- last_u = j;
|
|
|
- } else {
|
|
|
- last_u = j;
|
|
|
- }
|
|
|
- i += chl;
|
|
|
- }
|
|
|
- if (!last_u)
|
|
|
+ /* Never prepend '.' to hidden files here.
|
|
|
+ * That is done only for msdos mounts (and only when
|
|
|
+ * 'dotsOK=yes'); if we are executing here, it is in the
|
|
|
+ * context of a vfat mount.
|
|
|
+ */
|
|
|
+ len = fat_parse_short(sb, de, bufname, 0);
|
|
|
+ if (len == 0)
|
|
|
continue;
|
|
|
|
|
|
/* Compare shortname */
|
|
|
- bufuname[last_u] = 0x0000;
|
|
|
- len = fat_uni_to_x8(sb, bufuname, bufname, sizeof(bufname));
|
|
|
if (fat_name_match(sbi, name, name_len, bufname, len))
|
|
|
goto found;
|
|
|
|
|
@@ -469,20 +557,15 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
|
|
|
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
|
|
struct buffer_head *bh;
|
|
|
struct msdos_dir_entry *de;
|
|
|
- struct nls_table *nls_disk = sbi->nls_disk;
|
|
|
unsigned char nr_slots;
|
|
|
- wchar_t bufuname[14];
|
|
|
wchar_t *unicode = NULL;
|
|
|
- unsigned char c, work[MSDOS_NAME];
|
|
|
- unsigned char bufname[FAT_MAX_SHORT_SIZE], *ptname = bufname;
|
|
|
- unsigned short opt_shortname = sbi->options.shortname;
|
|
|
+ unsigned char bufname[FAT_MAX_SHORT_SIZE];
|
|
|
int isvfat = sbi->options.isvfat;
|
|
|
- int nocase = sbi->options.nocase;
|
|
|
const char *fill_name = NULL;
|
|
|
unsigned long inum;
|
|
|
unsigned long lpos, dummy, *furrfu = &lpos;
|
|
|
loff_t cpos;
|
|
|
- int chi, chl, i, i2, j, last, last_u, dotoffset = 0, fill_len = 0;
|
|
|
+ int short_len = 0, fill_len = 0;
|
|
|
int ret = 0;
|
|
|
|
|
|
lock_super(sb);
|
|
@@ -556,74 +639,10 @@ parse_record:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (sbi->options.dotsOK) {
|
|
|
- ptname = bufname;
|
|
|
- dotoffset = 0;
|
|
|
- if (de->attr & ATTR_HIDDEN) {
|
|
|
- *ptname++ = '.';
|
|
|
- dotoffset = 1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- memcpy(work, de->name, sizeof(de->name));
|
|
|
- /* see namei.c, msdos_format_name */
|
|
|
- if (work[0] == 0x05)
|
|
|
- work[0] = 0xE5;
|
|
|
- for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) {
|
|
|
- if (!(c = work[i]))
|
|
|
- break;
|
|
|
- chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
|
|
|
- &bufuname[j++], opt_shortname,
|
|
|
- de->lcase & CASE_LOWER_BASE);
|
|
|
- if (chl <= 1) {
|
|
|
- ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
|
|
|
- if (c != ' ') {
|
|
|
- last = i;
|
|
|
- last_u = j;
|
|
|
- }
|
|
|
- } else {
|
|
|
- last_u = j;
|
|
|
- for (chi = 0; chi < chl && i < 8; chi++) {
|
|
|
- ptname[i] = work[i];
|
|
|
- i++; last = i;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- i = last;
|
|
|
- j = last_u;
|
|
|
- fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
|
|
|
- ptname[i++] = '.';
|
|
|
- for (i2 = 8; i2 < MSDOS_NAME;) {
|
|
|
- if (!(c = work[i2]))
|
|
|
- break;
|
|
|
- chl = fat_shortname2uni(nls_disk, &work[i2], MSDOS_NAME - i2,
|
|
|
- &bufuname[j++], opt_shortname,
|
|
|
- de->lcase & CASE_LOWER_EXT);
|
|
|
- if (chl <= 1) {
|
|
|
- i2++;
|
|
|
- ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
|
|
|
- if (c != ' ') {
|
|
|
- last = i;
|
|
|
- last_u = j;
|
|
|
- }
|
|
|
- } else {
|
|
|
- last_u = j;
|
|
|
- for (chi = 0; chi < chl && i2 < MSDOS_NAME; chi++) {
|
|
|
- ptname[i++] = work[i2++];
|
|
|
- last = i;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (!last)
|
|
|
+ short_len = fat_parse_short(sb, de, bufname, sbi->options.dotsOK);
|
|
|
+ if (short_len == 0)
|
|
|
goto record_end;
|
|
|
|
|
|
- i = last + dotoffset;
|
|
|
- j = last_u;
|
|
|
-
|
|
|
- if (isvfat) {
|
|
|
- bufuname[j] = 0x0000;
|
|
|
- i = fat_uni_to_x8(sb, bufuname, bufname, sizeof(bufname));
|
|
|
- }
|
|
|
if (nr_slots) {
|
|
|
/* hack for fat_ioctl_filldir() */
|
|
|
struct fat_ioctl_filldir_callback *p = dirent;
|
|
@@ -631,12 +650,12 @@ parse_record:
|
|
|
p->longname = fill_name;
|
|
|
p->long_len = fill_len;
|
|
|
p->shortname = bufname;
|
|
|
- p->short_len = i;
|
|
|
+ p->short_len = short_len;
|
|
|
fill_name = NULL;
|
|
|
fill_len = 0;
|
|
|
} else {
|
|
|
fill_name = bufname;
|
|
|
- fill_len = i;
|
|
|
+ fill_len = short_len;
|
|
|
}
|
|
|
|
|
|
start_filldir:
|