LCOV - code coverage report
Current view: top level - lkbce/fs/fat - namei_vfat.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 639 648 98.6 %
Date: 2017-01-25 Functions: 28 29 96.6 %

          Line data    Source code
       1             : /*
       2             :  *  linux/fs/vfat/namei.c
       3             :  *
       4             :  *  Written 1992,1993 by Werner Almesberger
       5             :  *
       6             :  *  Windows95/Windows NT compatible extended MSDOS filesystem
       7             :  *    by Gordon Chaffee Copyright (C) 1995.  Send bug reports for the
       8             :  *    VFAT filesystem to <chaffee@cs.berkeley.edu>.  Specify
       9             :  *    what file operation caused you trouble and if you can duplicate
      10             :  *    the problem, send a script that demonstrates it.
      11             :  *
      12             :  *  Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
      13             :  *
      14             :  *  Support Multibyte characters and cleanup by
      15             :  *                              OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
      16             :  */
      17             : 
      18             : #include <linux/module.h>
      19             : #include <linux/jiffies.h>
      20             : #include <linux/ctype.h>
      21             : #include <linux/slab.h>
      22             : #include <linux/buffer_head.h>
      23             : #include <linux/namei.h>
      24             : #include "fat.h"
      25             : 
      26             : /*
      27             :  * If new entry was created in the parent, it could create the 8.3
      28             :  * alias (the shortname of logname).  So, the parent may have the
      29             :  * negative-dentry which matches the created 8.3 alias.
      30             :  *
      31             :  * If it happened, the negative dentry isn't actually negative
      32             :  * anymore.  So, drop it.
      33             :  */
      34             : static int vfat_revalidate_shortname(struct dentry *dentry)
      35             : {
      36           4 :         int ret = 1;
      37           4 :         spin_lock(&dentry->d_lock);
      38           6 :         if (dentry->d_time != dentry->d_parent->d_inode->i_version)
      39           2 :                 ret = 0;
      40           4 :         spin_unlock(&dentry->d_lock);
      41           2 :         return ret;
      42             : }
      43             : 
      44             : static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
      45             : {
      46           1 :         /* This is not negative dentry. Always valid. */
      47           3 :         if (dentry->d_inode)
      48           1 :                 return 1;
      49           3 :         return vfat_revalidate_shortname(dentry);
      50             : }
      51             : 
      52             : static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
      53             : {
      54           1 :         /*
      55             :          * This is not negative dentry. Always valid.
      56             :          *
      57             :          * Note, rename() to existing directory entry will have ->d_inode,
      58             :          * and will use existing name which isn't specified name by user.
      59             :          *
      60             :          * We may be able to drop this positive dentry here. But dropping
      61             :          * positive dentry isn't good idea. So it's unsupported like
      62             :          * rename("filename", "FILENAME") for now.
      63             :          */
      64           3 :         if (dentry->d_inode)
      65           1 :                 return 1;
      66             : 
      67             :         /*
      68             :          * This may be nfsd (or something), anyway, we can't see the
      69             :          * intent of this. So, since this can be for creation, drop it.
      70             :          */
      71           2 :         if (!nd)
      72           1 :                 return 0;
      73             : 
      74             :         /*
      75             :          * Drop the negative dentry, in order to make sure to use the
      76             :          * case sensitive name which is specified by user if this is
      77             :          * for creation.
      78             :          */
      79           2 :         if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) {
      80           2 :                 if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
      81           1 :                         return 0;
      82             :         }
      83             : 
      84           3 :         return vfat_revalidate_shortname(dentry);
      85             : }
      86             : 
      87             : /* returns the length of a struct qstr, ignoring trailing dots */
      88             : static unsigned int vfat_striptail_len(struct qstr *qstr)
      89             : {
      90          26 :         unsigned int len = qstr->len;
      91             : 
      92          65 :         while (len && qstr->name[len - 1] == '.')
      93          26 :                 len--;
      94          39 :         return len;
      95             : }
      96             : 
      97             : /*
      98             :  * Compute the hash for the vfat name corresponding to the dentry.
      99             :  * Note: if the name is invalid, we leave the hash code unchanged so
     100             :  * that the existing dentry can be used. The vfat fs routines will
     101             :  * return ENOENT or EINVAL as appropriate.
     102             :  */
     103             : static int vfat_hash(struct dentry *dentry, struct qstr *qstr)
     104             : {
     105           5 :         qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
     106           1 :         return 0;
     107             : }
     108             : 
     109             : /*
     110             :  * Compute the hash for the vfat name corresponding to the dentry.
     111             :  * Note: if the name is invalid, we leave the hash code unchanged so
     112             :  * that the existing dentry can be used. The vfat fs routines will
     113             :  * return ENOENT or EINVAL as appropriate.
     114             :  */
     115             : static int vfat_hashi(struct dentry *dentry, struct qstr *qstr)
     116             : {
     117           4 :         struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io;
     118           1 :         const unsigned char *name;
     119           1 :         unsigned int len;
     120           1 :         unsigned long hash;
     121           1 : 
     122           2 :         name = qstr->name;
     123           3 :         len = vfat_striptail_len(qstr);
     124           1 : 
     125           2 :         hash = init_name_hash();
     126           5 :         while (len--)
     127           7 :                 hash = partial_name_hash(nls_tolower(t, *name++), hash);
     128           4 :         qstr->hash = end_name_hash(hash);
     129           1 : 
     130           1 :         return 0;
     131             : }
     132             : 
     133             : /*
     134             :  * Case insensitive compare of two vfat names.
     135             :  */
     136             : static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b)
     137             : {
     138           4 :         struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io;
     139           1 :         unsigned int alen, blen;
     140           1 : 
     141           1 :         /* A filename cannot end in '.' or we treat it like it has none */
     142           3 :         alen = vfat_striptail_len(a);
     143           2 :         blen = vfat_striptail_len(b);
     144           2 :         if (alen == blen) {
     145           5 :                 if (nls_strnicmp(t, a->name, b->name, alen) == 0)
     146           1 :                         return 0;
     147             :         }
     148           2 :         return 1;
     149             : }
     150             : 
     151             : /*
     152             :  * Case sensitive compare of two vfat names.
     153             :  */
     154             : static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
     155             : {
     156           1 :         unsigned int alen, blen;
     157           1 : 
     158           1 :         /* A filename cannot end in '.' or we treat it like it has none */
     159           2 :         alen = vfat_striptail_len(a);
     160           2 :         blen = vfat_striptail_len(b);
     161           2 :         if (alen == blen) {
     162           5 :                 if (strncmp(a->name, b->name, alen) == 0)
     163           1 :                         return 0;
     164             :         }
     165           1 :         return 1;
     166             : }
     167             : 
     168           1 : static const struct dentry_operations vfat_ci_dentry_ops = {
     169             :         .d_revalidate   = vfat_revalidate_ci,
     170             :         .d_hash         = vfat_hashi,
     171             :         .d_compare      = vfat_cmpi,
     172             : };
     173             : 
     174           1 : static const struct dentry_operations vfat_dentry_ops = {
     175             :         .d_revalidate   = vfat_revalidate,
     176             :         .d_hash         = vfat_hash,
     177             :         .d_compare      = vfat_cmp,
     178             : };
     179             : 
     180             : /* Characters that are undesirable in an MS-DOS file name */
     181             : 
     182             : static inline wchar_t vfat_bad_char(wchar_t w)
     183             : {
     184          66 :         return (w < 0x0020)
     185             :             || (w == '*') || (w == '?') || (w == '<') || (w == '>')
     186             :             || (w == '|') || (w == '"') || (w == ':') || (w == '/')
     187             :             || (w == '\\');
     188             : }
     189             : 
     190             : static inline wchar_t vfat_replace_char(wchar_t w)
     191             : {
     192          84 :         return (w == '[') || (w == ']') || (w == ';') || (w == ',')
     193             :             || (w == '+') || (w == '=');
     194             : }
     195             : 
     196             : static wchar_t vfat_skip_char(wchar_t w)
     197             : {
     198          54 :         return (w == '.') || (w == ' ');
     199             : }
     200             : 
     201             : static inline int vfat_is_used_badchars(const wchar_t *s, int len)
     202             : {
     203           3 :         int i;
     204           3 : 
     205          15 :         for (i = 0; i < len; i++)
     206          18 :                 if (vfat_bad_char(s[i]))
     207           6 :                         return -EINVAL;
     208             : 
     209           6 :         if (s[i - 1] == ' ') /* last character cannot be space */
     210           3 :                 return -EINVAL;
     211             : 
     212           3 :         return 0;
     213             : }
     214             : 
     215             : static int vfat_find_form(struct inode *dir, unsigned char *name)
     216             : {
     217          39 :         struct fat_slot_info sinfo;
     218         117 :         int err = fat_scan(dir, name, &sinfo);
     219         117 :         if (err)
     220          39 :                 return -ENOENT;
     221          78 :         brelse(sinfo.bh);
     222          39 :         return 0;
     223             : }
     224           1 : 
     225             : /*
     226             :  * 1) Valid characters for the 8.3 format alias are any combination of
     227             :  * letters, uppercase alphabets, digits, any of the
     228             :  * following special characters:
     229             :  *     $ % ' ` - @ { } ~ ! # ( ) & _ ^
     230             :  * In this case Longfilename is not stored in disk.
     231             :  *
     232             :  * WinNT's Extension:
     233             :  * File name and extension name is contain uppercase/lowercase
     234             :  * only. And it is expressed by CASE_LOWER_BASE and CASE_LOWER_EXT.
     235             :  *
     236             :  * 2) File name is 8.3 format, but it contain the uppercase and
     237             :  * lowercase char, muliti bytes char, etc. In this case numtail is not
     238             :  * added, but Longfilename is stored.
     239             :  *
     240             :  * 3) When the one except for the above, or the following special
     241             :  * character are contained:
     242             :  *        .   [ ] ; , + =
     243             :  * numtail is added, and Longfilename must be stored in disk .
     244             :  */
     245             : struct shortname_info {
     246             :         unsigned char lower:1,
     247             :                       upper:1,
     248             :                       valid:1;
     249             : };
     250             : #define INIT_SHORTNAME_INFO(x)  do {            \
     251             :         (x)->lower = 1;                              \
     252             :         (x)->upper = 1;                              \
     253             :         (x)->valid = 1;                              \
     254             : } while (0)
     255             : 
     256             : static inline int to_shortname_char(struct nls_table *nls,
     257             :                                     unsigned char *buf, int buf_size,
     258             :                                     wchar_t *src, struct shortname_info *info)
     259           6 : {
     260           6 :         int len;
     261           6 : 
     262          30 :         if (vfat_skip_char(*src)) {
     263           6 :                 info->valid = 0;
     264           6 :                 return 0;
     265             :         }
     266          24 :         if (vfat_replace_char(*src)) {
     267           6 :                 info->valid = 0;
     268           6 :                 buf[0] = '_';
     269           6 :                 return 1;
     270             :         }
     271             : 
     272           6 :         len = nls->uni2char(*src, buf, buf_size);
     273          12 :         if (len <= 0) {
     274           6 :                 info->valid = 0;
     275           6 :                 buf[0] = '_';
     276           6 :                 len = 1;
     277          12 :         } else if (len == 1) {
     278           6 :                 unsigned char prev = buf[0];
     279             : 
     280          12 :                 if (buf[0] >= 0x7F) {
     281           6 :                         info->lower = 0;
     282           6 :                         info->upper = 0;
     283             :                 }
     284             : 
     285          12 :                 buf[0] = nls_toupper(nls, buf[0]);
     286          12 :                 if (isalpha(buf[0])) {
     287          12 :                         if (buf[0] == prev)
     288           6 :                                 info->lower = 0;
     289             :                         else
     290           6 :                                 info->upper = 0;
     291             :                 }
     292             :         } else {
     293           6 :                 info->lower = 0;
     294           6 :                 info->upper = 0;
     295             :         }
     296             : 
     297          12 :         return len;
     298             : }
     299             : 
     300             : /*
     301             :  * Given a valid longname, create a unique shortname.  Make sure the
     302             :  * shortname does not exist
     303             :  * Returns negative number on error, 0 for a normal
     304             :  * return, and 1 for valid shortname
     305             :  */
     306             : static int vfat_create_shortname(struct inode *dir, struct nls_table *nls,
     307             :                                  wchar_t *uname, int ulen,
     308             :                                  unsigned char *name_res, unsigned char *lcase)
     309           3 : {
     310          12 :         struct fat_mount_options *opts = &MSDOS_SB(dir->i_sb)->options;
     311           3 :         wchar_t *ip, *ext_start, *end, *name_start;
     312           3 :         unsigned char base[9], ext[4], buf[5], *p;
     313           3 :         unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
     314           3 :         int chl, chi;
     315           6 :         int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen;
     316           3 :         int is_shortname;
     317           3 :         struct shortname_info base_info, ext_info;
     318           3 : 
     319           6 :         is_shortname = 1;
     320          12 :         INIT_SHORTNAME_INFO(&base_info);
     321          12 :         INIT_SHORTNAME_INFO(&ext_info);
     322           3 : 
     323           3 :         /* Now, we need to create a shortname from the long name */
     324           9 :         ext_start = end = &uname[ulen];
     325          15 :         while (--ext_start >= uname) {
     326          12 :                 if (*ext_start == 0x002E) {     /* is `.' */
     327          12 :                         if (ext_start == end - 1) {
     328           6 :                                 sz = ulen;
     329           6 :                                 ext_start = NULL;
     330           3 :                         }
     331           9 :                         break;
     332           3 :                 }
     333           3 :         }
     334           3 : 
     335          12 :         if (ext_start == uname - 1) {
     336           6 :                 sz = ulen;
     337           6 :                 ext_start = NULL;
     338           6 :         } else if (ext_start) {
     339             :                 /*
     340             :                  * Names which start with a dot could be just
     341             :                  * an extension eg. "...test".  In this case Win95
     342             :                  * uses the extension as the name and sets no extension.
     343             :                  */
     344           3 :                 name_start = &uname[0];
     345           9 :                 while (name_start < ext_start) {
     346          15 :                         if (!vfat_skip_char(*name_start))
     347           6 :                                 break;
     348           3 :                         name_start++;
     349           3 :                 }
     350          12 :                 if (name_start != ext_start) {
     351           9 :                         sz = ext_start - uname;
     352           6 :                         ext_start++;
     353             :                 } else {
     354           6 :                         sz = ulen;
     355           6 :                         ext_start = NULL;
     356             :                 }
     357             :         }
     358             : 
     359           9 :         numtail_baselen = 6;
     360           9 :         numtail2_baselen = 2;
     361          63 :         for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++) {
     362          21 :                 chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
     363           3 :                                         ip, &base_info);
     364           6 :                 if (chl == 0)
     365           3 :                         continue;
     366             : 
     367          15 :                 if (baselen < 2 && (baselen + chl) > 2)
     368           3 :                         numtail2_baselen = baselen;
     369          12 :                 if (baselen < 6 && (baselen + chl) > 6)
     370           3 :                         numtail_baselen = baselen;
     371          15 :                 for (chi = 0; chi < chl; chi++) {
     372          15 :                         *p++ = charbuf[chi];
     373           6 :                         baselen++;
     374           6 :                         if (baselen >= 8)
     375           3 :                                 break;
     376             :                 }
     377           9 :                 if (baselen >= 8) {
     378          12 :                         if ((chi < chl - 1) || (ip + 1) - uname < sz)
     379           3 :                                 is_shortname = 0;
     380           3 :                         break;
     381             :                 }
     382             :         }
     383          12 :         if (baselen == 0) {
     384           9 :                 return -EINVAL;
     385             :         }
     386             : 
     387           6 :         extlen = 0;
     388          12 :         if (ext_start) {
     389          36 :                 for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
     390          21 :                         chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
     391           3 :                                                 ip, &ext_info);
     392           6 :                         if (chl == 0)
     393           3 :                                 continue;
     394             : 
     395           9 :                         if ((extlen + chl) > 3) {
     396           3 :                                 is_shortname = 0;
     397           3 :                                 break;
     398             :                         }
     399          15 :                         for (chi = 0; chi < chl; chi++) {
     400          15 :                                 *p++ = charbuf[chi];
     401           6 :                                 extlen++;
     402             :                         }
     403           6 :                         if (extlen >= 3) {
     404           6 :                                 if (ip + 1 != end)
     405           3 :                                         is_shortname = 0;
     406           3 :                                 break;
     407             :                         }
     408             :                 }
     409             :         }
     410          18 :         ext[extlen] = '\0';
     411          15 :         base[baselen] = '\0';
     412             : 
     413             :         /* Yes, it can happen. ".\xe5" would do it. */
     414          30 :         if (base[0] == DELETED_FLAG)
     415          15 :                 base[0] = 0x05;
     416             : 
     417             :         /* OK, at this point we know that base is not longer than 8 symbols,
     418             :          * ext is not longer than 3, base is nonempty, both don't contain
     419             :          * any bad symbols (lowercase transformed to uppercase).
     420             :          */
     421             : 
     422          15 :         memset(name_res, ' ', MSDOS_NAME);
     423          15 :         memcpy(name_res, base, baselen);
     424          15 :         memcpy(name_res + 8, ext, extlen);
     425          15 :         *lcase = 0;
     426          90 :         if (is_shortname && base_info.valid && ext_info.valid) {
     427          51 :                 if (vfat_find_form(dir, name_res) == 0)
     428           3 :                         return -EEXIST;
     429             : 
     430           9 :                 if (opts->shortname & VFAT_SFN_CREATE_WIN95) {
     431          18 :                         return (base_info.upper && ext_info.upper);
     432           9 :                 } else if (opts->shortname & VFAT_SFN_CREATE_WINNT) {
     433          12 :                         if ((base_info.upper || base_info.lower) &&
     434             :                             (ext_info.upper || ext_info.lower)) {
     435           6 :                                 if (!base_info.upper && base_info.lower)
     436           3 :                                         *lcase |= CASE_LOWER_BASE;
     437           6 :                                 if (!ext_info.upper && ext_info.lower)
     438           3 :                                         *lcase |= CASE_LOWER_EXT;
     439           3 :                                 return 1;
     440             :                         }
     441           3 :                         return 0;
     442             :                 } else {
     443           6 :                         BUG();
     444             :                 }
     445             :         }
     446             : 
     447          36 :         if (opts->numtail == 0)
     448          60 :                 if (vfat_find_form(dir, name_res) < 0)
     449           3 :                         return 0;
     450             : 
     451             :         /*
     452             :          * Try to find a unique extension.  This used to
     453             :          * iterate through all possibilities sequentially,
     454             :          * but that gave extremely bad performance.  Windows
     455             :          * only tries a few cases before using random
     456             :          * values for part of the base.
     457             :          */
     458             : 
     459          42 :         if (baselen > 6) {
     460          21 :                 baselen = numtail_baselen;
     461          21 :                 name_res[7] = ' ';
     462             :         }
     463          21 :         name_res[baselen] = '~';
     464          51 :         for (i = 1; i < 10; i++) {
     465           9 :                 name_res[baselen + 1] = i + '0';
     466          18 :                 if (vfat_find_form(dir, name_res) < 0)
     467           3 :                         return 0;
     468             :         }
     469             : 
     470           3 :         i = jiffies;
     471           3 :         sz = (jiffies >> 16) & 0x7;
     472           6 :         if (baselen > 2) {
     473           3 :                 baselen = numtail2_baselen;
     474           3 :                 name_res[7] = ' ';
     475             :         }
     476           3 :         name_res[baselen + 4] = '~';
     477           3 :         name_res[baselen + 5] = '1' + sz;
     478           3 :         while (1) {
     479           3 :                 snprintf(buf, sizeof(buf), "%04X", i & 0xffff);
     480           3 :                 memcpy(&name_res[baselen], buf, 4);
     481          15 :                 if (vfat_find_form(dir, name_res) < 0)
     482           3 :                         break;
     483           3 :                 i -= 11;
     484           3 :         }
     485           6 :         return 0;
     486             : }
     487             : 
     488             : /* Translate a string, including coded sequences into Unicode */
     489             : static int
     490             : xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
     491             :              int *longlen, int *outlen, int escape, int utf8,
     492             :              struct nls_table *nls)
     493           3 : {
     494           3 :         const unsigned char *ip;
     495           3 :         unsigned char nc;
     496           3 :         unsigned char *op;
     497           3 :         unsigned int ec;
     498           3 :         int i, k, fill;
     499           3 :         int charlen;
     500           3 : 
     501           9 :         if (utf8) {
     502           6 :                 *outlen = utf8s_to_utf16s(name, len, (wchar_t *)outname);
     503           9 :                 if (*outlen < 0)
     504           6 :                         return *outlen;
     505           9 :                 else if (*outlen > 255)
     506           6 :                         return -ENAMETOOLONG;
     507           3 : 
     508           6 :                 op = &outname[*outlen * sizeof(wchar_t)];
     509           3 :         } else {
     510           6 :                 if (nls) {
     511          27 :                         for (i = 0, ip = name, op = outname, *outlen = 0;
     512           3 :                              i < len && *outlen <= 255;
     513           6 :                              *outlen += 1)
     514           9 :                         {
     515          12 :                                 if (escape && (*ip == ':')) {
     516           6 :                                         if (i > len - 5)
     517           3 :                                                 return -EINVAL;
     518           3 :                                         ec = 0;
     519          15 :                                         for (k = 1; k < 5; k++) {
     520           9 :                                                 nc = ip[k];
     521           6 :                                                 ec <<= 4;
     522           6 :                                                 if (nc >= '0' && nc <= '9') {
     523           3 :                                                         ec |= nc - '0';
     524           3 :                                                         continue;
     525             :                                                 }
     526           6 :                                                 if (nc >= 'a' && nc <= 'f') {
     527           3 :                                                         ec |= nc - ('a' - 10);
     528           3 :                                                         continue;
     529             :                                                 }
     530           6 :                                                 if (nc >= 'A' && nc <= 'F') {
     531           3 :                                                         ec |= nc - ('A' - 10);
     532           3 :                                                         continue;
     533             :                                                 }
     534           3 :                                                 return -EINVAL;
     535           3 :                                         }
     536           9 :                                         *op++ = ec & 0xFF;
     537           9 :                                         *op++ = ec >> 8;
     538           3 :                                         ip += 5;
     539           3 :                                         i += 5;
     540             :                                 } else {
     541           9 :                                         if ((charlen = nls->char2uni(ip, len - i, (wchar_t *)op)) < 0)
     542           3 :                                                 return -EINVAL;
     543           3 :                                         ip += charlen;
     544           3 :                                         i += charlen;
     545           3 :                                         op += 2;
     546             :                                 }
     547             :                         }
     548           6 :                         if (i < len)
     549           3 :                                 return -ENAMETOOLONG;
     550             :                 } else {
     551          27 :                         for (i = 0, ip = name, op = outname, *outlen = 0;
     552           3 :                              i < len && *outlen <= 255;
     553           6 :                              i++, *outlen += 1)
     554           6 :                         {
     555          15 :                                 *op++ = *ip++;
     556           9 :                                 *op++ = 0;
     557             :                         }
     558           6 :                         if (i < len)
     559           3 :                                 return -ENAMETOOLONG;
     560             :                 }
     561             :         }
     562             : 
     563           9 :         *longlen = *outlen;
     564          18 :         if (*outlen % 13) {
     565          27 :                 *op++ = 0;
     566          27 :                 *op++ = 0;
     567           9 :                 *outlen += 1;
     568          18 :                 if (*outlen % 13) {
     569           9 :                         fill = 13 - (*outlen % 13);
     570          27 :                         for (i = 0; i < fill; i++) {
     571          15 :                                 *op++ = 0xff;
     572          12 :                                 *op++ = 0xff;
     573             :                         }
     574           3 :                         *outlen += fill;
     575             :                 }
     576             :         }
     577             : 
     578          12 :         return 0;
     579             : }
     580             : 
     581             : static int vfat_build_slots(struct inode *dir, const unsigned char *name,
     582             :                             int len, int is_dir, int cluster,
     583             :                             struct timespec *ts,
     584             :                             struct msdos_dir_slot *slots, int *nr_slots)
     585           3 : {
     586          12 :         struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
     587           6 :         struct fat_mount_options *opts = &sbi->options;
     588           3 :         struct msdos_dir_slot *ps;
     589           3 :         struct msdos_dir_entry *de;
     590           3 :         unsigned char cksum, lcase;
     591           3 :         unsigned char msdos_name[MSDOS_NAME];
     592           3 :         wchar_t *uname;
     593           3 :         __le16 time, date;
     594           3 :         u8 time_cs;
     595           3 :         int err, ulen, usize, i;
     596           3 :         loff_t offset;
     597           3 : 
     598           6 :         *nr_slots = 0;
     599           3 : 
     600           9 :         uname = __getname();
     601           9 :         if (!uname)
     602           6 :                 return -ENOMEM;
     603           3 : 
     604          27 :         err = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
     605           3 :                            opts->unicode_xlate, opts->utf8, sbi->nls_io);
     606           6 :         if (err)
     607           3 :                 goto out_free;
     608             : 
     609           9 :         err = vfat_is_used_badchars(uname, ulen);
     610           6 :         if (err)
     611           3 :                 goto out_free;
     612             : 
     613          21 :         err = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,
     614             :                                     msdos_name, &lcase);
     615           6 :         if (err < 0)
     616           3 :                 goto out_free;
     617           6 :         else if (err == 1) {
     618           3 :                 de = (struct msdos_dir_entry *)slots;
     619           3 :                 err = 0;
     620           3 :                 goto shortname;
     621             :         }
     622             : 
     623             :         /* build the entry of long file name */
     624           6 :         cksum = fat_checksum(msdos_name);
     625             : 
     626           3 :         *nr_slots = usize / 13;
     627          21 :         for (ps = slots, i = *nr_slots; i > 0; i--, ps++) {
     628           6 :                 ps->id = i;
     629           9 :                 ps->attr = ATTR_EXT;
     630           3 :                 ps->reserved = 0;
     631           3 :                 ps->alias_checksum = cksum;
     632           3 :                 ps->start = 0;
     633           3 :                 offset = (i - 1) * 13;
     634           6 :                 fatwchar_to16(ps->name0_4, uname + offset, 5);
     635           6 :                 fatwchar_to16(ps->name5_10, uname + offset + 5, 6);
     636           6 :                 fatwchar_to16(ps->name11_12, uname + offset + 11, 2);
     637             :         }
     638           6 :         slots[0].id |= 0x40;
     639           3 :         de = (struct msdos_dir_entry *)ps;
     640           3 : 
     641             : shortname:
     642             :         /* build the entry of 8.3 alias name */
     643           6 :         (*nr_slots)++;
     644           6 :         memcpy(de->name, msdos_name, MSDOS_NAME);
     645          36 :         de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
     646           6 :         de->lcase = lcase;
     647           6 :         fat_time_unix2fat(sbi, ts, &time, &date, &time_cs);
     648          18 :         de->time = de->ctime = time;
     649          30 :         de->date = de->cdate = de->adate = date;
     650           6 :         de->ctime_cs = time_cs;
     651           6 :         de->start = cpu_to_le16(cluster);
     652           6 :         de->starthi = cpu_to_le16(cluster >> 16);
     653           6 :         de->size = 0;
     654             : out_free:
     655          18 :         __putname(uname);
     656          12 :         return err;
     657             : }
     658             : 
     659             : static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
     660             :                           int cluster, struct timespec *ts,
     661             :                           struct fat_slot_info *sinfo)
     662           3 : {
     663           3 :         struct msdos_dir_slot *slots;
     664           3 :         unsigned int len;
     665           3 :         int err, nr_slots;
     666           3 : 
     667           9 :         len = vfat_striptail_len(qname);
     668           9 :         if (len == 0)
     669           3 :                 return -ENOENT;
     670             : 
     671           9 :         slots = kmalloc(sizeof(*slots) * MSDOS_SLOTS, GFP_NOFS);
     672           6 :         if (slots == NULL)
     673           3 :                 return -ENOMEM;
     674             : 
     675          18 :         err = vfat_build_slots(dir, qname->name, len, is_dir, cluster, ts,
     676             :                                slots, &nr_slots);
     677           6 :         if (err)
     678           3 :                 goto cleanup;
     679             : 
     680           3 :         err = fat_add_entries(dir, slots, nr_slots, sinfo);
     681           6 :         if (err)
     682           3 :                 goto cleanup;
     683             : 
     684             :         /* update timestamp */
     685          15 :         dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
     686          12 :         if (IS_DIRSYNC(dir))
     687           3 :                 (void)fat_sync_inode(dir);
     688             :         else
     689           6 :                 mark_inode_dirty(dir);
     690             : cleanup:
     691           6 :         kfree(slots);
     692          12 :         return err;
     693             : }
     694             : 
     695             : static int vfat_find(struct inode *dir, struct qstr *qname,
     696             :                      struct fat_slot_info *sinfo)
     697           4 : {
     698          16 :         unsigned int len = vfat_striptail_len(qname);
     699          12 :         if (len == 0)
     700           4 :                 return -ENOENT;
     701           8 :         return fat_search_long(dir, qname->name, len, sinfo);
     702             : }
     703             : 
     704             : static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
     705             :                                   struct nameidata *nd)
     706           1 : {
     707           2 :         struct super_block *sb = dir->i_sb;
     708           1 :         struct fat_slot_info sinfo;
     709           1 :         struct inode *inode;
     710           1 :         struct dentry *alias;
     711           1 :         int err;
     712           1 : 
     713           2 :         lock_super(sb);
     714           1 : 
     715           3 :         err = vfat_find(dir, &dentry->d_name, &sinfo);
     716           2 :         if (err) {
     717           2 :                 if (err == -ENOENT) {
     718           1 :                         inode = NULL;
     719           1 :                         goto out;
     720             :                 }
     721           1 :                 goto error;
     722             :         }
     723             : 
     724           1 :         inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
     725           2 :         brelse(sinfo.bh);
     726           4 :         if (IS_ERR(inode)) {
     727           3 :                 err = PTR_ERR(inode);
     728           1 :                 goto error;
     729             :         }
     730             : 
     731           1 :         alias = d_find_alias(inode);
     732           4 :         if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
     733             :                 /*
     734             :                  * This inode has non DCACHE_DISCONNECTED dentry. This
     735             :                  * means, the user did ->lookup() by an another name
     736             :                  * (longname vs 8.3 alias of it) in past.
     737             :                  *
     738             :                  * Switch to new one for reason of locality if possible.
     739             :                  */
     740           8 :                 BUG_ON(d_unhashed(alias));
     741           3 :                 if (!S_ISDIR(inode->i_mode))
     742           1 :                         d_move(alias, dentry);
     743           1 :                 iput(inode);
     744           1 :                 unlock_super(sb);
     745           1 :                 return alias;
     746             :         }
     747             : out:
     748           2 :         unlock_super(sb);
     749           3 :         dentry->d_op = sb->s_root->d_op;
     750           4 :         dentry->d_time = dentry->d_parent->d_inode->i_version;
     751           2 :         dentry = d_splice_alias(inode, dentry);
     752           4 :         if (dentry) {
     753           2 :                 dentry->d_op = sb->s_root->d_op;
     754           4 :                 dentry->d_time = dentry->d_parent->d_inode->i_version;
     755             :         }
     756           2 :         return dentry;
     757           2 : 
     758             : error:
     759           2 :         unlock_super(sb);
     760           5 :         return ERR_PTR(err);
     761             : }
     762             : 
     763             : static int vfat_create(struct inode *dir, struct dentry *dentry, int mode,
     764             :                        struct nameidata *nd)
     765           1 : {
     766           2 :         struct super_block *sb = dir->i_sb;
     767           1 :         struct inode *inode;
     768           1 :         struct fat_slot_info sinfo;
     769           1 :         struct timespec ts;
     770           1 :         int err;
     771           1 : 
     772           2 :         lock_super(sb);
     773           1 : 
     774           5 :         ts = CURRENT_TIME_SEC;
     775           6 :         err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);
     776           2 :         if (err)
     777           1 :                 goto out;
     778           1 :         dir->i_version++;
     779             : 
     780           1 :         inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
     781           2 :         brelse(sinfo.bh);
     782           4 :         if (IS_ERR(inode)) {
     783           3 :                 err = PTR_ERR(inode);
     784           1 :                 goto out;
     785             :         }
     786           1 :         inode->i_version++;
     787           5 :         inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
     788             :         /* timestamp is already written, so mark_inode_dirty() is unneeded. */
     789             : 
     790           2 :         dentry->d_time = dentry->d_parent->d_inode->i_version;
     791           1 :         d_instantiate(dentry, inode);
     792             : out:
     793           4 :         unlock_super(sb);
     794           3 :         return err;
     795             : }
     796             : 
     797             : static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
     798             : {
     799           2 :         struct inode *inode = dentry->d_inode;
     800           2 :         struct super_block *sb = dir->i_sb;
     801           1 :         struct fat_slot_info sinfo;
     802           1 :         int err;
     803           1 : 
     804           2 :         lock_super(sb);
     805           1 : 
     806           1 :         err = fat_dir_empty(inode);
     807           2 :         if (err)
     808           1 :                 goto out;
     809           2 :         err = vfat_find(dir, &dentry->d_name, &sinfo);
     810           2 :         if (err)
     811           1 :                 goto out;
     812             : 
     813           1 :         err = fat_remove_entries(dir, &sinfo);      /* and releases bh */
     814           2 :         if (err)
     815           1 :                 goto out;
     816           2 :         drop_nlink(dir);
     817             : 
     818           2 :         clear_nlink(inode);
     819           6 :         inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
     820           1 :         fat_detach(inode);
     821             : out:
     822           4 :         unlock_super(sb);
     823             : 
     824           3 :         return err;
     825             : }
     826             : 
     827             : static int vfat_unlink(struct inode *dir, struct dentry *dentry)
     828             : {
     829           2 :         struct inode *inode = dentry->d_inode;
     830           2 :         struct super_block *sb = dir->i_sb;
     831           1 :         struct fat_slot_info sinfo;
     832           1 :         int err;
     833           1 : 
     834           2 :         lock_super(sb);
     835           1 : 
     836           2 :         err = vfat_find(dir, &dentry->d_name, &sinfo);
     837           2 :         if (err)
     838           1 :                 goto out;
     839             : 
     840           1 :         err = fat_remove_entries(dir, &sinfo);      /* and releases bh */
     841           2 :         if (err)
     842           1 :                 goto out;
     843           2 :         clear_nlink(inode);
     844           6 :         inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
     845           1 :         fat_detach(inode);
     846             : out:
     847           3 :         unlock_super(sb);
     848             : 
     849           2 :         return err;
     850             : }
     851             : 
     852             : static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
     853             : {
     854           2 :         struct super_block *sb = dir->i_sb;
     855           1 :         struct inode *inode;
     856           1 :         struct fat_slot_info sinfo;
     857           1 :         struct timespec ts;
     858           1 :         int err, cluster;
     859           1 : 
     860           2 :         lock_super(sb);
     861           1 : 
     862           5 :         ts = CURRENT_TIME_SEC;
     863           2 :         cluster = fat_alloc_new_dir(dir, &ts);
     864           3 :         if (cluster < 0) {
     865           2 :                 err = cluster;
     866           1 :                 goto out;
     867             :         }
     868           5 :         err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &ts, &sinfo);
     869           2 :         if (err)
     870           1 :                 goto out_free;
     871           1 :         dir->i_version++;
     872           2 :         inc_nlink(dir);
     873             : 
     874           1 :         inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
     875           2 :         brelse(sinfo.bh);
     876           4 :         if (IS_ERR(inode)) {
     877           3 :                 err = PTR_ERR(inode);
     878             :                 /* the directory was completed, just return a error */
     879           1 :                 goto out;
     880             :         }
     881           1 :         inode->i_version++;
     882           1 :         inode->i_nlink = 2;
     883           5 :         inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
     884             :         /* timestamp is already written, so mark_inode_dirty() is unneeded. */
     885             : 
     886           2 :         dentry->d_time = dentry->d_parent->d_inode->i_version;
     887           1 :         d_instantiate(dentry, inode);
     888             : 
     889           1 :         unlock_super(sb);
     890           1 :         return 0;
     891           1 : 
     892             : out_free:
     893           1 :         fat_free_clusters(dir, cluster);
     894             : out:
     895           4 :         unlock_super(sb);
     896           3 :         return err;
     897             : }
     898             : 
     899             : static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
     900             :                        struct inode *new_dir, struct dentry *new_dentry)
     901             : {
     902           1 :         struct buffer_head *dotdot_bh;
     903           1 :         struct msdos_dir_entry *dotdot_de;
     904           1 :         struct inode *old_inode, *new_inode;
     905           1 :         struct fat_slot_info old_sinfo, sinfo;
     906           1 :         struct timespec ts;
     907           1 :         loff_t dotdot_i_pos, new_i_pos;
     908           2 :         int err, is_dir, update_dotdot, corrupt = 0;
     909           2 :         struct super_block *sb = old_dir->i_sb;
     910           1 : 
     911           4 :         old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
     912           2 :         old_inode = old_dentry->d_inode;
     913           2 :         new_inode = new_dentry->d_inode;
     914           2 :         lock_super(sb);
     915           3 :         err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
     916           3 :         if (err)
     917           2 :                 goto out;
     918           1 : 
     919           3 :         is_dir = S_ISDIR(old_inode->i_mode);
     920           7 :         update_dotdot = (is_dir && old_dir != new_dir);
     921           3 :         if (update_dotdot) {
     922           4 :                 if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
     923           1 :                                          &dotdot_i_pos) < 0) {
     924           2 :                         err = -EIO;
     925           2 :                         goto out;
     926           1 :                 }
     927           1 :         }
     928           1 : 
     929           4 :         ts = CURRENT_TIME_SEC;
     930           2 :         if (new_inode) {
     931           2 :                 if (is_dir) {
     932           1 :                         err = fat_dir_empty(new_inode);
     933           2 :                         if (err)
     934           1 :                                 goto out;
     935             :                 }
     936           3 :                 new_i_pos = MSDOS_I(new_inode)->i_pos;
     937           1 :                 fat_detach(new_inode);
     938             :         } else {
     939           5 :                 err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, 0,
     940             :                                      &ts, &sinfo);
     941           2 :                 if (err)
     942           1 :                         goto out;
     943           1 :                 new_i_pos = sinfo.i_pos;
     944             :         }
     945           2 :         new_dir->i_version++;
     946             : 
     947           2 :         fat_detach(old_inode);
     948           2 :         fat_attach(old_inode, new_i_pos);
     949           8 :         if (IS_DIRSYNC(new_dir)) {
     950           2 :                 err = fat_sync_inode(old_inode);
     951           4 :                 if (err)
     952           2 :                         goto error_inode;
     953             :         } else
     954           4 :                 mark_inode_dirty(old_inode);
     955             : 
     956           6 :         if (update_dotdot) {
     957           7 :                 int start = MSDOS_I(new_dir)->i_logstart;
     958           1 :                 dotdot_de->start = cpu_to_le16(start);
     959           1 :                 dotdot_de->starthi = cpu_to_le16(start >> 16);
     960           1 :                 mark_buffer_dirty_inode(dotdot_bh, old_inode);
     961           4 :                 if (IS_DIRSYNC(new_dir)) {
     962           1 :                         err = sync_dirty_buffer(dotdot_bh);
     963           2 :                         if (err)
     964           1 :                                 goto error_dotdot;
     965             :                 }
     966           2 :                 drop_nlink(old_dir);
     967           2 :                 if (!new_inode)
     968           2 :                         inc_nlink(new_dir);
     969             :         }
     970             : 
     971           5 :         err = fat_remove_entries(old_dir, &old_sinfo);      /* and releases bh */
     972           5 :         old_sinfo.bh = NULL;
     973          10 :         if (err)
     974           5 :                 goto error_dotdot;
     975           5 :         old_dir->i_version++;
     976          15 :         old_dir->i_ctime = old_dir->i_mtime = ts;
     977          20 :         if (IS_DIRSYNC(old_dir))
     978           5 :                 (void)fat_sync_inode(old_dir);
     979             :         else
     980          10 :                 mark_inode_dirty(old_dir);
     981             : 
     982          12 :         if (new_inode) {
     983          12 :                 drop_nlink(new_inode);
     984           2 :                 if (is_dir)
     985           2 :                         drop_nlink(new_inode);
     986           2 :                 new_inode->i_ctime = ts;
     987             :         }
     988             : out:
     989          22 :         brelse(sinfo.bh);
     990          10 :         brelse(dotdot_bh);
     991           2 :         brelse(old_sinfo.bh);
     992           1 :         unlock_super(sb);
     993             : 
     994           1 :         return err;
     995           6 : 
     996             : error_dotdot:
     997             :         /* data cluster is shared, serious corruption */
     998           6 :         corrupt = 1;
     999             : 
    1000          12 :         if (update_dotdot) {
    1001          13 :                 int start = MSDOS_I(old_dir)->i_logstart;
    1002           1 :                 dotdot_de->start = cpu_to_le16(start);
    1003           1 :                 dotdot_de->starthi = cpu_to_le16(start >> 16);
    1004           1 :                 mark_buffer_dirty_inode(dotdot_bh, old_inode);
    1005           2 :                 corrupt |= sync_dirty_buffer(dotdot_bh);
    1006             :         }
    1007             : error_inode:
    1008           7 :         fat_detach(old_inode);
    1009           7 :         fat_attach(old_inode, old_sinfo.i_pos);
    1010          21 :         if (new_inode) {
    1011           7 :                 fat_attach(new_inode, new_i_pos);
    1012          14 :                 if (corrupt)
    1013          14 :                         corrupt |= fat_sync_inode(new_inode);
    1014             :         } else {
    1015             :                 /*
    1016             :                  * If new entry was not sharing the data cluster, it
    1017             :                  * shouldn't be serious corruption.
    1018             :                  */
    1019          14 :                 int err2 = fat_remove_entries(new_dir, &sinfo);
    1020          14 :                 if (corrupt)
    1021           7 :                         corrupt |= err2;
    1022           7 :                 sinfo.bh = NULL;
    1023             :         }
    1024          14 :         if (corrupt < 0) {
    1025           7 :                 fat_fs_error(new_dir->i_sb,
    1026             :                              "%s: Filesystem corrupted (i_pos %lld)",
    1027             :                              __func__, sinfo.i_pos);
    1028             :         }
    1029           7 :         goto out;
    1030             : }
    1031             : 
    1032           1 : static const struct inode_operations vfat_dir_inode_operations = {
    1033             :         .create         = vfat_create,
    1034             :         .lookup         = vfat_lookup,
    1035             :         .unlink         = vfat_unlink,
    1036             :         .mkdir          = vfat_mkdir,
    1037             :         .rmdir          = vfat_rmdir,
    1038             :         .rename         = vfat_rename,
    1039             :         .setattr        = fat_setattr,
    1040             :         .getattr        = fat_getattr,
    1041             : };
    1042             : 
    1043             : static int vfat_fill_super(struct super_block *sb, void *data, int silent)
    1044             : {
    1045           0 :         int res;
    1046           0 : 
    1047           0 :         res = fat_fill_super(sb, data, silent, &vfat_dir_inode_operations, 1);
    1048           0 :         if (res)
    1049           0 :                 return res;
    1050             : 
    1051           0 :         if (MSDOS_SB(sb)->options.name_check != 's')
    1052           0 :                 sb->s_root->d_op = &vfat_ci_dentry_ops;
    1053             :         else
    1054           0 :                 sb->s_root->d_op = &vfat_dentry_ops;
    1055             : 
    1056           0 :         return 0;
    1057             : }
    1058             : 
    1059             : static int vfat_get_sb(struct file_system_type *fs_type,
    1060             :                        int flags, const char *dev_name,
    1061             :                        void *data, struct vfsmount *mnt)
    1062           1 : {
    1063           2 :         return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super,
    1064             :                            mnt);
    1065             : }
    1066             : 
    1067           1 : static struct file_system_type vfat_fs_type = {
    1068             :         .owner          = THIS_MODULE,
    1069             :         .name           = "vfat",
    1070             :         .get_sb         = vfat_get_sb,
    1071             :         .kill_sb        = kill_block_super,
    1072             :         .fs_flags       = FS_REQUIRES_DEV,
    1073             : };
    1074             : 
    1075             : static int __init init_vfat_fs(void)
    1076             : {
    1077           4 :         return register_filesystem(&vfat_fs_type);
    1078             : }
    1079             : 
    1080             : static void __exit exit_vfat_fs(void)
    1081             : {
    1082           4 :         unregister_filesystem(&vfat_fs_type);
    1083           2 : }
    1084             : 
    1085             : MODULE_LICENSE("GPL");
    1086             : MODULE_DESCRIPTION("VFAT filesystem support");
    1087             : MODULE_AUTHOR("Gordon Chaffee");
    1088             : 
    1089             : module_init(init_vfat_fs)
    1090             : module_exit(exit_vfat_fs)

Generated by: LCOV version 1.10