Loading fs/fat/Kconfig +21 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,27 @@ config VFAT_FS To compile this as a module, choose M here: the module will be called vfat. config VFAT_FS_NO_DUALNAMES bool "disable VFAT dual names support (patent workaround)" depends on VFAT_FS help This option disables support for dual filenames on VFAT filesystems. If this option is enabled then file creation will either put a short (8.3) name or a long name on the file, but never both. The field where a shortname would normally go is filled with invalid characters such that it cannot be considered a valid short filename. That means that long filenames created with this option disabled will not be accessible at all to operating systems that do not understand the FAT long filename extensions. Users considering disabling this option should consider the implications of any patents that may exist on dual filenames in VFAT. If unsure, say N config FAT_DEFAULT_CODEPAGE int "Default codepage for FAT" depends on MSDOS_FS || VFAT_FS Loading fs/fat/dir.c +14 −0 Original line number Diff line number Diff line Loading @@ -498,6 +498,13 @@ parse_record: goto end_of_dir; } /* * The FAT_NO_83NAME flag is used to mark files * created with no 8.3 short name */ if (de->lcase & FAT_NO_83NAME) goto compare_longname; /* 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 Loading @@ -511,6 +518,7 @@ parse_record: if (fat_name_match(sbi, name, name_len, bufname, len)) goto found; compare_longname: if (nr_slots) { void *longname = unicode + FAT_MAX_UNI_CHARS; int size = PATH_MAX - FAT_MAX_UNI_SIZE; Loading Loading @@ -602,6 +610,8 @@ parse_record: if (de->attr != ATTR_EXT && IS_FREE(de->name)) goto record_end; } else { if (de->lcase & FAT_NO_83NAME) goto record_end; if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) goto record_end; } Loading Loading @@ -960,6 +970,10 @@ int fat_scan(struct inode *dir, const unsigned char *name, sinfo->bh = NULL; while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh, &sinfo->de) >= 0) { /* skip files marked as having no 8.3 short name */ if (sinfo->de->lcase & FAT_NO_83NAME) continue; if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) { sinfo->slot_off -= sizeof(*sinfo->de); sinfo->nr_slots = 1; Loading fs/fat/namei_vfat.c +81 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <linux/slab.h> #include <linux/namei.h> #include "fat.h" #include <linux/random.h> /* * If new entry was created in the parent, it could create the 8.3 Loading Loading @@ -322,6 +323,17 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen; int is_shortname; struct shortname_info base_info, ext_info; unsigned opts_shortname = opts->shortname; #ifdef CONFIG_VFAT_FS_NO_DUALNAMES /* * When we do not have dualnames, we want to maximise the * chance that a file will be able to be represented with just * a 8.3 entry. We can do that by using the WINNT case * handling extensions to FAT. */ opts_shortname = VFAT_SFN_CREATE_WINNT; #endif is_shortname = 1; INIT_SHORTNAME_INFO(&base_info); Loading Loading @@ -434,9 +446,9 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, if (vfat_find_form(dir, name_res) == 0) return -EEXIST; if (opts->shortname & VFAT_SFN_CREATE_WIN95) { if (opts_shortname & VFAT_SFN_CREATE_WIN95) { return (base_info.upper && ext_info.upper); } else if (opts->shortname & VFAT_SFN_CREATE_WINNT) { } else if (opts_shortname & VFAT_SFN_CREATE_WINNT) { if ((base_info.upper || base_info.lower) && (ext_info.upper || ext_info.lower)) { if (!base_info.upper && base_info.lower) Loading Loading @@ -575,6 +587,66 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, return 0; } #ifdef CONFIG_VFAT_FS_NO_DUALNAMES /* * This function creates a dummy 8.3 entry which is as compatible as * possible with existing FAT devices, while not being a valid * filename under windows or Linux */ static void vfat_build_dummy_83_buffer(struct inode *dir, char *msdos_name, int is_dir) { /* * These characters are all invalid in 8.3 names, plus have * been shown to be harmless on all tested devices */ const char invalidchar[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0B, 0x0C, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x22, 0x2a, 0x3a, 0x3c, 0x3e, 0x3f, 0x5b, 0x5d, 0x7c }; int i, tilde_pos, slash_pos; u32 rand_num = prandom_u32(); /* We need a '~' in the prefix to make Win98 happy. */ tilde_pos = rand_num % 8; rand_num >>= 3; /* * the '/' makes sure that even unpatched Linux systems can't * get at files by the 8.3 entry. Don't put in a / in * directories as it can cause problems with some * photo frames */ if (is_dir) slash_pos = -1; else { slash_pos = (tilde_pos + 1 + rand_num % 7) % 8; rand_num >>= 3; } /* * fill in the first 8 bytes with invalid characters. Note * that we need to be careful not to run out of randomness. We * leave the 3 byte extension in place as some cheap MP3 * players need them. */ for (i = 0; i < 8; i++) { if (i == tilde_pos) msdos_name[i] = '~'; else if (i == slash_pos) msdos_name[i] = '/'; else { msdos_name[i] = invalidchar[rand_num % sizeof(invalidchar)]; rand_num /= sizeof(invalidchar); if (rand_num < sizeof(invalidchar)) rand_num = prandom_u32(); } } } #endif static int vfat_build_slots(struct inode *dir, const unsigned char *name, int len, int is_dir, int cluster, struct timespec *ts, Loading Loading @@ -617,6 +689,13 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name, goto shortname; } #ifdef CONFIG_VFAT_FS_NO_DUALNAMES printk_once(KERN_INFO "VFAT: not creating 8.3 short filenames for long names\n"); vfat_build_dummy_83_buffer(dir, msdos_name, is_dir); lcase = FAT_NO_83NAME; #endif /* build the entry of long file name */ cksum = fat_checksum(msdos_name); Loading include/uapi/linux/msdos_fs.h +1 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ #define CASE_LOWER_BASE 8 /* base is lower case */ #define CASE_LOWER_EXT 16 /* extension is lower case */ #define FAT_NO_83NAME 32 /* no 8.3 short filename for this file */ #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */ #define IS_FREE(n) (!*(n) || *(n) == DELETED_FLAG) Loading Loading
fs/fat/Kconfig +21 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,27 @@ config VFAT_FS To compile this as a module, choose M here: the module will be called vfat. config VFAT_FS_NO_DUALNAMES bool "disable VFAT dual names support (patent workaround)" depends on VFAT_FS help This option disables support for dual filenames on VFAT filesystems. If this option is enabled then file creation will either put a short (8.3) name or a long name on the file, but never both. The field where a shortname would normally go is filled with invalid characters such that it cannot be considered a valid short filename. That means that long filenames created with this option disabled will not be accessible at all to operating systems that do not understand the FAT long filename extensions. Users considering disabling this option should consider the implications of any patents that may exist on dual filenames in VFAT. If unsure, say N config FAT_DEFAULT_CODEPAGE int "Default codepage for FAT" depends on MSDOS_FS || VFAT_FS Loading
fs/fat/dir.c +14 −0 Original line number Diff line number Diff line Loading @@ -498,6 +498,13 @@ parse_record: goto end_of_dir; } /* * The FAT_NO_83NAME flag is used to mark files * created with no 8.3 short name */ if (de->lcase & FAT_NO_83NAME) goto compare_longname; /* 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 Loading @@ -511,6 +518,7 @@ parse_record: if (fat_name_match(sbi, name, name_len, bufname, len)) goto found; compare_longname: if (nr_slots) { void *longname = unicode + FAT_MAX_UNI_CHARS; int size = PATH_MAX - FAT_MAX_UNI_SIZE; Loading Loading @@ -602,6 +610,8 @@ parse_record: if (de->attr != ATTR_EXT && IS_FREE(de->name)) goto record_end; } else { if (de->lcase & FAT_NO_83NAME) goto record_end; if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) goto record_end; } Loading Loading @@ -960,6 +970,10 @@ int fat_scan(struct inode *dir, const unsigned char *name, sinfo->bh = NULL; while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh, &sinfo->de) >= 0) { /* skip files marked as having no 8.3 short name */ if (sinfo->de->lcase & FAT_NO_83NAME) continue; if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) { sinfo->slot_off -= sizeof(*sinfo->de); sinfo->nr_slots = 1; Loading
fs/fat/namei_vfat.c +81 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <linux/slab.h> #include <linux/namei.h> #include "fat.h" #include <linux/random.h> /* * If new entry was created in the parent, it could create the 8.3 Loading Loading @@ -322,6 +323,17 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen; int is_shortname; struct shortname_info base_info, ext_info; unsigned opts_shortname = opts->shortname; #ifdef CONFIG_VFAT_FS_NO_DUALNAMES /* * When we do not have dualnames, we want to maximise the * chance that a file will be able to be represented with just * a 8.3 entry. We can do that by using the WINNT case * handling extensions to FAT. */ opts_shortname = VFAT_SFN_CREATE_WINNT; #endif is_shortname = 1; INIT_SHORTNAME_INFO(&base_info); Loading Loading @@ -434,9 +446,9 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, if (vfat_find_form(dir, name_res) == 0) return -EEXIST; if (opts->shortname & VFAT_SFN_CREATE_WIN95) { if (opts_shortname & VFAT_SFN_CREATE_WIN95) { return (base_info.upper && ext_info.upper); } else if (opts->shortname & VFAT_SFN_CREATE_WINNT) { } else if (opts_shortname & VFAT_SFN_CREATE_WINNT) { if ((base_info.upper || base_info.lower) && (ext_info.upper || ext_info.lower)) { if (!base_info.upper && base_info.lower) Loading Loading @@ -575,6 +587,66 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, return 0; } #ifdef CONFIG_VFAT_FS_NO_DUALNAMES /* * This function creates a dummy 8.3 entry which is as compatible as * possible with existing FAT devices, while not being a valid * filename under windows or Linux */ static void vfat_build_dummy_83_buffer(struct inode *dir, char *msdos_name, int is_dir) { /* * These characters are all invalid in 8.3 names, plus have * been shown to be harmless on all tested devices */ const char invalidchar[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0B, 0x0C, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x22, 0x2a, 0x3a, 0x3c, 0x3e, 0x3f, 0x5b, 0x5d, 0x7c }; int i, tilde_pos, slash_pos; u32 rand_num = prandom_u32(); /* We need a '~' in the prefix to make Win98 happy. */ tilde_pos = rand_num % 8; rand_num >>= 3; /* * the '/' makes sure that even unpatched Linux systems can't * get at files by the 8.3 entry. Don't put in a / in * directories as it can cause problems with some * photo frames */ if (is_dir) slash_pos = -1; else { slash_pos = (tilde_pos + 1 + rand_num % 7) % 8; rand_num >>= 3; } /* * fill in the first 8 bytes with invalid characters. Note * that we need to be careful not to run out of randomness. We * leave the 3 byte extension in place as some cheap MP3 * players need them. */ for (i = 0; i < 8; i++) { if (i == tilde_pos) msdos_name[i] = '~'; else if (i == slash_pos) msdos_name[i] = '/'; else { msdos_name[i] = invalidchar[rand_num % sizeof(invalidchar)]; rand_num /= sizeof(invalidchar); if (rand_num < sizeof(invalidchar)) rand_num = prandom_u32(); } } } #endif static int vfat_build_slots(struct inode *dir, const unsigned char *name, int len, int is_dir, int cluster, struct timespec *ts, Loading Loading @@ -617,6 +689,13 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name, goto shortname; } #ifdef CONFIG_VFAT_FS_NO_DUALNAMES printk_once(KERN_INFO "VFAT: not creating 8.3 short filenames for long names\n"); vfat_build_dummy_83_buffer(dir, msdos_name, is_dir); lcase = FAT_NO_83NAME; #endif /* build the entry of long file name */ cksum = fat_checksum(msdos_name); Loading
include/uapi/linux/msdos_fs.h +1 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ #define CASE_LOWER_BASE 8 /* base is lower case */ #define CASE_LOWER_EXT 16 /* extension is lower case */ #define FAT_NO_83NAME 32 /* no 8.3 short filename for this file */ #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */ #define IS_FREE(n) (!*(n) || *(n) == DELETED_FLAG) Loading