📄 namei.c
字号:
* 2) File name is 8.3 format, but it contain the uppercase and * lowercase char, muliti bytes char, etc. In this case numtail is not * added, but Longfilename is stored. * * 3) When the one except for the above, or the following special * character are contained: * . [ ] ; , + = * numtail is added, and Longfilename must be stored in disk . */struct shortname_info { unsigned char lower:1, upper:1, valid:1;};#define INIT_SHORTNAME_INFO(x) do { \ (x)->lower = 1; \ (x)->upper = 1; \ (x)->valid = 1; \} while (0);static inline unsigned charshortname_info_to_lcase(struct shortname_info *base, struct shortname_info *ext){ unsigned char lcase = 0; if (base->valid && ext->valid) { if (!base->upper && base->lower && (ext->lower || ext->upper)) lcase |= CASE_LOWER_BASE; if (!ext->upper && ext->lower && (base->lower || base->upper)) lcase |= CASE_LOWER_EXT; } return lcase;}static inline int to_shortname_char(struct nls_table *nls, char *buf, int buf_size, wchar_t *src, struct shortname_info *info){ int len; if (IS_SKIPCHAR(*src)) { info->valid = 0; return 0; } if (IS_REPLACECHAR(*src)) { info->valid = 0; buf[0] = '_'; return 1; } len = nls->uni2char(*src, buf, buf_size); if (len <= 0) { info->valid = 0; buf[0] = '_'; len = 1; } else if (len == 1) { unsigned char prev = buf[0]; if (buf[0] >= 0x7F) { info->lower = 0; info->upper = 0; } buf[0] = vfat_toupper(nls, buf[0]); if (isalpha(buf[0])) { if (buf[0] == prev) info->lower = 0; else info->upper = 0; } } else { info->lower = 0; info->upper = 0; } return len;}/* * Given a valid longname, create a unique shortname. Make sure the * shortname does not exist * Returns negative number on error, 0 for a normal * return, and 1 for valid shortname */static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, wchar_t *uname, int ulen, char *name_res, unsigned char *lcase){ wchar_t *ip, *ext_start, *end, *name_start; unsigned char base[9], ext[4], buf[8], *p; unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; int chl, chi; int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen; int is_shortname; struct shortname_info base_info, ext_info; unsigned short opt_shortname = MSDOS_SB(dir->i_sb)->options.shortname; is_shortname = 1; INIT_SHORTNAME_INFO(&base_info); INIT_SHORTNAME_INFO(&ext_info); /* Now, we need to create a shortname from the long name */ ext_start = end = &uname[ulen]; while (--ext_start >= uname) { if (*ext_start == 0x002E) { /* is `.' */ if (ext_start == end - 1) { sz = ulen; ext_start = NULL; } break; } } if (ext_start == uname - 1) { sz = ulen; 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 = &uname[0]; while (name_start < ext_start) { if (!IS_SKIPCHAR(*name_start)) break; name_start++; } if (name_start != ext_start) { sz = ext_start - uname; ext_start++; } else { sz = ulen; ext_start=NULL; } } numtail_baselen = 6; numtail2_baselen = 2; for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++) { chl = to_shortname_char(nls, charbuf, sizeof(charbuf), ip, &base_info); if (chl == 0) continue; if (baselen < 2 && (baselen + chl) > 2) numtail2_baselen = baselen; if (baselen < 6 && (baselen + chl) > 6) numtail_baselen = baselen; for (chi = 0; chi < chl; chi++){ *p++ = charbuf[chi]; baselen++; if (baselen >= 8) break; } if (baselen >= 8) { if ((chi < chl - 1) || (ip + 1) - uname < sz) is_shortname = 0; break; } } if (baselen == 0) { return -EINVAL; } extlen = 0; if (ext_start) { for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) { chl = to_shortname_char(nls, charbuf, sizeof(charbuf), ip, &ext_info); if (chl == 0) continue; if ((extlen + chl) > 3) { is_shortname = 0; break; } for (chi = 0; chi < chl; chi++) { *p++ = charbuf[chi]; extlen++; } if (extlen >= 3) { if (ip + 1 != end) is_shortname = 0; break; } } } ext[extlen] = '\0'; base[baselen] = '\0'; /* Yes, it can happen. ".\xe5" would do it. */ if (base[0] == DELETED_FLAG) base[0] = 0x05; /* 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); *lcase = 0; if (is_shortname && base_info.valid && ext_info.valid) { if (vfat_find_form(dir, name_res) == 0) return -EEXIST; if (opt_shortname & VFAT_SFN_CREATE_WIN95) { return (base_info.upper && ext_info.upper); } else if (opt_shortname & VFAT_SFN_CREATE_WINNT) { if ((base_info.upper || base_info.lower) && (ext_info.upper || ext_info.lower)) { *lcase = shortname_info_to_lcase(&base_info, &ext_info); return 1; } return 0; } else { BUG(); } } 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 = numtail_baselen; name_res[7] = ' '; } 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 = numtail2_baselen; name_res[7] = ' '; } 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 is_dir, 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, lcase; char *uniname, msdos_name[MSDOS_NAME]; int res, utf8, slot, ulen, unilen, i; loff_t offset; *slots = 0; 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; res = vfat_is_used_badchars(uname, ulen); if (res < 0) goto out_free; res = vfat_create_shortname(dir, nls_disk, uname, ulen, msdos_name, &lcase); if (res < 0) goto out_free; else if (res == 1) { de = (struct msdos_dir_entry *)ds; res = 0; goto shortname; } /* build the entry of long file name */ *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; ps->alias_checksum = cksum; ps->start = 0; offset = (slot - 1) * 13; fatwchar_to16(ps->name0_4, uname + offset, 5); fatwchar_to16(ps->name5_10, uname + offset + 5, 6); fatwchar_to16(ps->name11_12, uname + offset + 11, 2); } ds[0].id |= 0x40; de = (struct msdos_dir_entry *) ps;shortname: PRINTK3(("vfat_fill_slots 9\n")); /* build the entry of 8.3 alias name */ (*slots)++; strncpy(de->name, msdos_name, MSDOS_NAME); de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; de->lcase = lcase; de->adate = de->cdate = de->date = 0; de->ctime_ms = de->ctime = de->time = 0; de->start = 0; de->starthi = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -