📄 namei.c
字号:
if (chl < 0) return -EINVAL; for (chi = 0; chi < chl; chi++) { c = vfat_getupper(nls, charbuf[chi]); if (!c) return -EINVAL; if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; if (strchr(replace_chars,c)) return -EINVAL; if (c < ' '|| c==':') return -EINVAL; if (c == '.') goto dot; space = c == ' '; } }dot:; if (space) return -EINVAL; if (len && c != '.') { len--; if (vfat_uni2upper_short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE) == 1) { if (charbuf[0] != '.') return -EINVAL; } else return -EINVAL; c = '.'; } if (c == '.') { if (len >= 4) return -EINVAL; while (len > 0) { len--; chl = nls->uni2char(*walk++, charbuf, NLS_MAX_CHARSET_SIZE); if (chl < 0) return -EINVAL; for (chi = 0; chi < chl; chi++) { c = vfat_getupper(nls, charbuf[chi]); if (!c) return -EINVAL; if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; if (strchr(replace_chars,c)) return -EINVAL; if (c < ' ' || c == '.'|| c==':') return -EINVAL; space = c == ' '; } } if (space) return -EINVAL; } return 0;}static int vfat_find_form(struct inode *dir,char *name){ struct msdos_dir_entry *de; struct buffer_head *bh = NULL; int ino,res; res=fat_scan(dir,name,&bh,&de,&ino); fat_brelse(dir->i_sb, bh); if (res<0) return -ENOENT; return 0;}static int vfat_format_name(struct nls_table *nls, wchar_t *name, int len, char *res){ char *walk; unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; int chi, chl; int space; if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0) return -EINVAL; if (IS_FREE(charbuf)) return -EINVAL; space = 1; /* disallow names starting with a dot */ for (walk = res; len--; ) { chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); if (chl == 0) return -EINVAL; for (chi = 0; chi < chl; chi++){ if (charbuf[chi] == '.') goto dot; if (!charbuf[chi]) return -EINVAL; if (walk-res == 8) return -EINVAL; if (strchr(replace_chars,charbuf[chi])) return -EINVAL; if (charbuf[chi] < ' '|| charbuf[chi]==':') return -EINVAL; space = charbuf[chi] == ' '; *walk = charbuf[chi]; walk++; } }dot:; if (space) return -EINVAL; if (len >= 0) { while (walk-res < 8) *walk++ = ' '; while (len > 0 && walk-res < MSDOS_NAME) { chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE); if (len < chl) chl = len; len -= chl; for (chi = 0; chi < chl; chi++){ if (!charbuf[chi]) return -EINVAL; if (strchr(replace_chars,charbuf[chi])) return -EINVAL; if (charbuf[chi] < ' ' || charbuf[chi] == '.'|| charbuf[chi]==':') return -EINVAL; space = charbuf[chi] == ' '; *walk++ = charbuf[chi]; } } if (space) return -EINVAL; if (len) return -EINVAL; } while (walk-res < MSDOS_NAME) *walk++ = ' '; return 0;}static char skip_chars[] = ".:\"?<>| ";/* Given a valid longname, create a unique shortname. Make sure the * shortname does not exist */static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, wchar_t *name, int len, char *name_res){ wchar_t *ip, *op, *ext_start, *end, *name_start; wchar_t msdos_name[13]; char base[9], ext[4], buf[8], *p; unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; int chl, chi; int sz, extlen, baselen, i; PRINTK2(("Entering vfat_create_shortname\n")); chl = 0; sz = 0; /* Make compiler happy */ if (len <= 12) { /* Do a case insensitive search if the name would be a valid * shortname if is were all capitalized. However, do not * allow spaces in short names because Win95 scandisk does * not like that */ for (i = 0, op = &msdos_name[0], ip = name; ; i++, ip++, op++) { if (i == len) { if (vfat_format_name(nls, &msdos_name[0], len, name_res) < 0) break; PRINTK3(("vfat_create_shortname 1\n")); if (vfat_find_form(dir, name_res) < 0) return 0; return -EEXIST; } chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); for (chi = 0; chi < chl; chi++){ if (charbuf[chi] == ' ') break; } if (chi < chl) break; *op = *ip; } } PRINTK3(("vfat_create_shortname 3\n")); /* Now, we need to create a shortname from the long name */ ext_start = end = &name[len]; while (--ext_start >= name) { chl = vfat_uni2upper_short(nls, *ext_start, charbuf, NLS_MAX_CHARSET_SIZE); for (chi = 0; chi < chl; chi++) { if (charbuf[chi] == '.') { if (ext_start == end - 1) { sz = len; ext_start = NULL; } goto stop0; } } }stop0:; if (ext_start == name - 1) { sz = len; ext_start = NULL; } else if (ext_start) { /* * Names which start with a dot could be just * an extension eg. "...test". In this case Win95 * uses the extension as the name and sets no extension. */ name_start = &name[0]; while (name_start < ext_start) { chl = vfat_uni2upper_short(nls, *name_start, charbuf, NLS_MAX_CHARSET_SIZE); if (chl == 0) break; for (chi = 0; chi < chl; chi++) if (!strchr(skip_chars, charbuf[chi])) { goto stop1; } name_start++; }stop1:; if (name_start != ext_start) { sz = ext_start - name; ext_start++; } else { sz = len; ext_start=NULL; } } for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++, ip++) { chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); if (chl == 0){ *p++ = '_'; baselen++; continue; } for (chi = 0; chi < chl; chi++){ if (!strchr(skip_chars, charbuf[chi])){ if (strchr(replace_chars, charbuf[chi])) *p = '_'; else *p = charbuf[chi]; p++; baselen++; } } } if (baselen == 0) { return -EINVAL; } extlen = 0; if (ext_start) { for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) { chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE); if (chl == 0) { *p++ = '_'; extlen++; continue; } for (chi = 0; chi < chl; chi++) { if (!strchr(skip_chars, charbuf[chi])) { if (strchr(replace_chars, charbuf[chi])) *p = '_'; else *p = charbuf[chi]; p++; extlen++; } } } } ext[extlen] = '\0'; base[baselen] = '\0'; /* Yes, it can happen. ".\xe5" would do it. */ if (IS_FREE(base)) base[0]='_'; /* OK, at this point we know that base is not longer than 8 symbols, * ext is not longer than 3, base is nonempty, both don't contain * any bad symbols (lowercase transformed to uppercase). */ memset(name_res, ' ', MSDOS_NAME); memcpy(name_res,base,baselen); memcpy(name_res+8,ext,extlen); if (MSDOS_SB(dir->i_sb)->options.numtail == 0) if (vfat_find_form(dir, name_res) < 0) return 0; /* * Try to find a unique extension. This used to * iterate through all possibilities sequentially, * but that gave extremely bad performance. Windows * only tries a few cases before using random * values for part of the base. */ if (baselen>6) baselen = 6; name_res[baselen] = '~'; for (i = 1; i < 10; i++) { name_res[baselen+1] = i + '0'; if (vfat_find_form(dir, name_res) < 0) return 0; } i = jiffies & 0xffff; sz = (jiffies >> 16) & 0x7; if (baselen>2) baselen = 2; name_res[baselen+4] = '~'; name_res[baselen+5] = '1' + sz; while (1) { sprintf(buf, "%04X", i); memcpy(&name_res[baselen], buf, 4); if (vfat_find_form(dir, name_res) < 0) break; i -= 11; } return 0;}/* Translate a string, including coded sequences into Unicode */static intxlate_to_uni(const char *name, int len, char *outname, int *longlen, int *outlen, int escape, int utf8, struct nls_table *nls){ const unsigned char *ip; unsigned char nc; char *op; unsigned int ec; int i, k, fill; int charlen; if (utf8) { *outlen = utf8_mbstowcs((__u16 *) outname, name, PAGE_SIZE); if (name[len-1] == '.') *outlen-=2; op = &outname[*outlen * sizeof(__u16)]; } else { if (name[len-1] == '.') len--; if (nls) { for (i = 0, ip = name, op = outname, *outlen = 0; i < len && *outlen <= 260; *outlen += 1) { if (escape && (*ip == ':')) { if (i > len - 5) return -EINVAL; ec = 0; for (k = 1; k < 5; k++) { nc = ip[k]; ec <<= 4; if (nc >= '0' && nc <= '9') { ec |= nc - '0'; continue; } if (nc >= 'a' && nc <= 'f') { ec |= nc - ('a' - 10); continue; } if (nc >= 'A' && nc <= 'F') { ec |= nc - ('A' - 10); continue; } return -EINVAL; } *op++ = ec & 0xFF; *op++ = ec >> 8; ip += 5; i += 5; } else { if ((charlen = nls->char2uni(ip, len-i, (wchar_t *)op)) < 0) return -EINVAL; ip += charlen; i += charlen; op += 2; } } } else { for (i = 0, ip = name, op = outname, *outlen = 0; i < len && *outlen <= 260; i++, *outlen += 1) { *op++ = *ip++; *op++ = 0; } } } if (*outlen > 260) return -ENAMETOOLONG; *longlen = *outlen; if (*outlen % 13) { *op++ = 0; *op++ = 0; *outlen += 1; if (*outlen % 13) { fill = 13 - (*outlen % 13); for (i = 0; i < fill; i++) { *op++ = 0xff; *op++ = 0xff; } *outlen += fill; } } return 0;}static intvfat_fill_slots(struct inode *dir, struct msdos_dir_slot *ds, const char *name, int len, int *slots, int uni_xlate){ struct nls_table *nls_io, *nls_disk; wchar_t *uname; struct msdos_dir_slot *ps; struct msdos_dir_entry *de; unsigned long page; unsigned char cksum; const char *ip; char *uniname, msdos_name[MSDOS_NAME]; int res, utf8, slot, ulen, unilen, i; loff_t offset; de = (struct msdos_dir_entry *) ds; utf8 = MSDOS_SB(dir->i_sb)->options.utf8; nls_io = MSDOS_SB(dir->i_sb)->nls_io; nls_disk = MSDOS_SB(dir->i_sb)->nls_disk; if (name[len-1] == '.') len--; if(!(page = __get_free_page(GFP_KERNEL))) return -ENOMEM; uniname = (char *) page; res = xlate_to_uni(name, len, uniname, &ulen, &unilen, uni_xlate, utf8, nls_io); if (res < 0) goto out_free; uname = (wchar_t *) page; if (vfat_valid_shortname(nls_disk, uname, ulen) >= 0) { res = vfat_format_name(nls_disk, uname, ulen, de->name); if (!res) goto out_free; } res = vfat_create_shortname(dir, nls_disk, uname, ulen, msdos_name); if (res) goto out_free; *slots = unilen / 13; for (cksum = i = 0; i < 11; i++) { cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i]; } PRINTK3(("vfat_fill_slots 3: slots=%d\n",*slots)); for (ps = ds, slot = *slots; slot > 0; slot--, ps++) { ps->id = slot; ps->attr = ATTR_EXT; ps->reserved = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -