CTC++ Coverage Report - Execution Profile    #965/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: fs/msdos/namei.c
Instrumentation mode: function-decision-multicondition
TER: 1 % ( 2/385)

Start/ End/    
True False - Line Source

  1 /*
  2  *  linux/fs/msdos/namei.c
  3  *
  4  *  Written 1992,1993 by Werner Almesberger
  5  *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
  6  *  Rewritten for constant inumbers 1999 by Al Viro
  7  */
  8 
  9 #include <linux/module.h>
  10 #include <linux/time.h>
  11 #include <linux/buffer_head.h>
  12 #include <linux/msdos_fs.h>
  13 #include <linux/smp_lock.h>
  14 
  15 /* MS-DOS "device special files" */
  16 static const unsigned char *reserved_names[] = {
  17    "CON     ", "PRN     ", "NUL     ", "AUX     ",
  18    "LPT1    ", "LPT2    ", "LPT3    ", "LPT4    ",
  19    "COM1    ", "COM2    ", "COM3    ", "COM4    ",
  20    NULL
  21 };
  22 
  23 /* Characters that are undesirable in an MS-DOS file name */
  24 static unsigned char bad_chars[] = "*?<>|\"";
  25 static unsigned char bad_if_strict_pc[] = "+=,; ";
  26 /* GEMDOS is less restrictive */
  27 static unsigned char bad_if_strict_atari[] = " ";
  28 
  29 #define bad_if_strict(opts) \
  30    ((opts)->atari ? bad_if_strict_atari : bad_if_strict_pc)
  31 
  32 /***** Formats an MS-DOS file name. Rejects invalid names. */
 
- 33 static int msdos_format_name(const unsigned char *name, int len,
  34               unsigned char *res, struct fat_mount_options *opts)
  35    /*
  36     * name is the proposed name, len is its length, res is
  37     * the resulting name, opts->name_check is either (r)elaxed,
  38     * (n)ormal or (s)trict, opts->dotsOK allows dots at the
  39     * beginning of name (for hidden files)
  40     */
  41 {
  42    unsigned char *walk;
  43    const unsigned char **reserved;
  44    unsigned char c;
  45    int space;
  46 
- 47    if (name[0] == '.') {   /* dotfile because . and .. already done */
- 48       if (opts->dotsOK) {
  49          /* Get rid of dot - test for it elsewhere */
  50          name++;
  51          len--;
- 52       } else if (!opts->atari)
 - 53          return -EINVAL;
  54    }
  55    /*
  56     * disallow names that _really_ start with a dot for MS-DOS,
  57     * GEMDOS does not care
  58     */
  59    space = !opts->atari;
  60    c = 0;
- 61    for (walk = res; len && walk - res < 8; walk++) {
 - 61   T && T
 - 61   T && F
 - 61   F && _
  62       c = *name++;
  63       len--;
- 64       if (opts->name_check != 'r' && strchr(bad_chars, c))
 - 64     T && T
 - 64     T && F
 - 64     F && _
 - 65          return -EINVAL;
- 66       if (opts->name_check == 's' && strchr(bad_if_strict(opts), c))
 - 66     T && T
 - 66     T && F
 - 66     F && _
- 66   ternary-?: ( opts ) -> atari
 - 67          return -EINVAL;
- 68       if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
 - 68     T && T && T
 - 68     T && T && F
 - 68     T && F && _
 - 68     F && _ && _
 - 69          return -EINVAL;
- 70       if (c < ' ' || c == ':' || c == '\\')
 - 70     T || _ || _
 - 70     F || T || _
 - 70     F || F || T
 - 70     F || F || F
 - 71          return -EINVAL;
  72    /*
  73     * 0xE5 is legal as a first character, but we must substitute
  74     * 0x05 because 0xE5 marks deleted files.  Yes, DOS really
  75     * does this.
  76     * It seems that Microsoft hacked DOS to support non-US
  77     * characters after the 0xE5 character was already in use to
  78     * mark deleted files.
  79     */
- 80       if ((res == walk) && (c == 0xE5))
 - 80     (T) && (T)
 - 80     (T) && (F)
 - 80     (F) && (_)
  81          c = 0x05;
- 82       if (c == '.')
 - 83          break;
  84       space = (c == ' ');
    85       *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c - 32 : c;
- 85   ternary-?: ( ! opts -> nocase && c >= 'a' &&..
  86    }
- 87    if (space)
 - 88       return -EINVAL;
- 89    if (opts->name_check == 's' && len && c != '.') {
 - 89   T && T && T
 - 89   T && T && F
 - 89   T && F && _
 - 89   F && _ && _
  90       c = *name++;
  91       len--;
- 92       if (c != '.')
 - 93          return -EINVAL;
  94    }
- 95    while (c != '.' && len--)
 - 95   T && T
 - 95   T && F
 - 95   F && _
  96       c = *name++;
- 97    if (c == '.') {
- 98       while (walk - res < 8)
  99          *walk++ = ' ';
- 100       while (len > 0 && walk - res < MSDOS_NAME) {
 - 100     T && T
 - 100     T && F
 - 100     F && _
  101          c = *name++;
  102          len--;
- 103          if (opts->name_check != 'r' && strchr(bad_chars, c))
 - 103       T && T
 - 103       T && F
 - 103       F && _
 - 104             return -EINVAL;
  105          if (opts->name_check == 's' &&
- 106              strchr(bad_if_strict(opts), c))
 - 106       T && T
 - 106       T && F
 - 106       F && _
- 106     ternary-?: ( opts ) -> atari
 - 107             return -EINVAL;
- 108          if (c < ' ' || c == ':' || c == '\\')
 - 108       T || _ || _
 - 108       F || T || _
 - 108       F || F || T
 - 108       F || F || F
 - 109             return -EINVAL;
- 110          if (c == '.') {
- 111             if (opts->name_check == 's')
 - 112                return -EINVAL;
 - 113             break;
  114          }
- 115          if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
 - 115       T && T && T
 - 115       T && T && F
 - 115       T && F && _
 - 115       F && _ && _
 - 116             return -EINVAL;
  117          space = c == ' ';
- 118          if (!opts->nocase && c >= 'a' && c <= 'z')
 - 118       T && T && T
 - 118       T && T && F
 - 118       T && F && _
 - 118       F && _ && _
  119             *walk++ = c - 32;
    120          else
  121             *walk++ = c;
  122       }
- 123       if (space)
 - 124          return -EINVAL;
- 125       if (opts->name_check == 's' && len)
 - 125     T && T
 - 125     T && F
 - 125     F && _
 - 126          return -EINVAL;
  127    }
- 128    while (walk - res < MSDOS_NAME)
  129       *walk++ = ' ';
- 130    if (!opts->atari)
  131       /* GEMDOS is less stupid and has no reserved names */
- 132       for (reserved = reserved_names; *reserved; reserved++)
- 133          if (!strncmp(res, *reserved, 8))
 - 134             return -EINVAL;
 - 135    return 0;
  136 }
  137 
  138 /***** Locates a directory entry.  Uses unformatted name. */
 
- 139 static int msdos_find(struct inode *dir, const unsigned char *name, int len,
  140             struct fat_slot_info *sinfo)
  141 {
  142    struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
  143    unsigned char msdos_name[MSDOS_NAME];
  144    int err;
  145 
  146    err = msdos_format_name(name, len, msdos_name, &sbi->options);
- 147    if (err)
 - 148       return -ENOENT;
  149 
  150    err = fat_scan(dir, msdos_name, sinfo);
- 151    if (!err && sbi->options.dotsOK) {
 - 151   T && T
 - 151   T && F
 - 151   F && _
- 152       if (name[0] == '.') {
- 153          if (!(sinfo->de->attr & ATTR_HIDDEN))
  154             err = -ENOENT;
    155       } else {
- 156          if (sinfo->de->attr & ATTR_HIDDEN)
  157             err = -ENOENT;
  158       }
- 159       if (err)
  160          brelse(sinfo->bh);
  161    }
 - 162    return err;
  163 }
  164 
  165 /*
  166  * Compute the hash for the msdos name corresponding to the dentry.
  167  * Note: if the name is invalid, we leave the hash code unchanged so
  168  * that the existing dentry can be used. The msdos fs routines will
  169  * return ENOENT or EINVAL as appropriate.
  170  */
 
- 171 static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
  172 {
  173    struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
  174    unsigned char msdos_name[MSDOS_NAME];
  175    int error;
  176 
  177    error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
- 178    if (!error)
  179       qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
 - 180    return 0;
  181 }
  182 
  183 /*
  184  * Compare two msdos names. If either of the names are invalid,
  185  * we fall back to doing the standard name comparison.
  186  */
 
- 187 static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
  188 {
  189    struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
  190    unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
  191    int error;
  192 
  193    error = msdos_format_name(a->name, a->len, a_msdos_name, options);
- 194    if (error)
 - 195       goto old_compare;
  196    error = msdos_format_name(b->name, b->len, b_msdos_name, options);
- 197    if (error)
 - 198       goto old_compare;
  199    error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
  200 out:
 - 201    return error;
  202 
  203 old_compare:
  204    error = 1;
- 205    if (a->len == b->len)
  206       error = memcmp(a->name, b->name, a->len);
 - 207    goto out;
  208 }
  209 
  210 static struct dentry_operations msdos_dentry_operations = {
  211    .d_hash      = msdos_hash,
  212    .d_compare   = msdos_cmp,
  213 };
  214 
  215 /*
  216  * AV. Wrappers for FAT sb operations. Is it wise?
  217  */
  218 
  219 /***** Get inode using directory and name */
 
- 220 static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
  221                struct nameidata *nd)
  222 {
  223    struct super_block *sb = dir->i_sb;
  224    struct fat_slot_info sinfo;
  225    struct inode *inode = NULL;
  226    int res;
  227 
  228    dentry->d_op = &msdos_dentry_operations;
  229 
    230    lock_kernel();
- 230 do-while (0)
  231    res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
- 232    if (res == -ENOENT)
 - 233       goto add;
- 234    if (res < 0)
 - 235       goto out;
  236    inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
  237    brelse(sinfo.bh);
- 238    if (IS_ERR(inode)) {
  239       res = PTR_ERR(inode);
 - 240       goto out;
  241    }
  242 add:
  243    res = 0;
  244    dentry = d_splice_alias(inode, dentry);
- 245    if (dentry)
  246       dentry->d_op = &msdos_dentry_operations;
  247 out:
    248    unlock_kernel();
- 248 do-while (0)
- 249    if (!res)
 - 250       return dentry;
 - 251    return ERR_PTR(res);
  252 }
  253 
  254 /***** Creates a directory entry (name is already formatted). */
 
- 255 static int msdos_add_entry(struct inode *dir, const unsigned char *name,
  256             int is_dir, int is_hid, int cluster,
  257             struct timespec *ts, struct fat_slot_info *sinfo)
  258 {
  259    struct msdos_dir_entry de;
  260    __le16 time, date;
  261    int err;
  262 
  263    memcpy(de.name, name, MSDOS_NAME);
    264    de.attr = is_dir ? ATTR_DIR : ATTR_ARCH;
- 264 ternary-?: is_dir
- 265    if (is_hid)
  266       de.attr |= ATTR_HIDDEN;
  267    de.lcase = 0;
  268    fat_date_unix2dos(ts->tv_sec, &time, &date);
  269    de.cdate = de.adate = 0;
  270    de.ctime = 0;
  271    de.ctime_cs = 0;
  272    de.time = time;
  273    de.date = date;
  274    de.start = cpu_to_le16(cluster);
  275    de.starthi = cpu_to_le16(cluster >> 16);
  276    de.size = 0;
  277 
  278    err = fat_add_entries(dir, &de, 1, sinfo);
- 279    if (err)
 - 280       return err;
  281 
  282    dir->i_ctime = dir->i_mtime = *ts;
- 283    if (IS_DIRSYNC(dir))
 - 283   ((T) || (_))
 - 283   ((F) || (T))
 - 283   ((F) || (F))
  284       (void)fat_sync_inode(dir);
    285    else
  286       mark_inode_dirty(dir);
  287 
 - 288    return 0;
  289 }
  290 
  291 /***** Create a file */
 
- 292 static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
  293          struct nameidata *nd)
  294 {
  295    struct super_block *sb = dir->i_sb;
  296    struct inode *inode;
  297    struct fat_slot_info sinfo;
  298    struct timespec ts;
  299    unsigned char msdos_name[MSDOS_NAME];
  300    int err, is_hid;
  301 
    302    lock_kernel();
- 302 do-while (0)
  303 
  304    err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
  305             msdos_name, &MSDOS_SB(sb)->options);
- 306    if (err)
 - 307       goto out;
  308    is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
  309    /* Have to do it due to foo vs. .foo conflicts */
- 310    if (!fat_scan(dir, msdos_name, &sinfo)) {
  311       brelse(sinfo.bh);
  312       err = -EINVAL;
 - 313       goto out;
  314    }
  315 
  316    ts = CURRENT_TIME_SEC;
  317    err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
- 318    if (err)
 - 319       goto out;
  320    inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
  321    brelse(sinfo.bh);
- 322    if (IS_ERR(inode)) {
  323       err = PTR_ERR(inode);
 - 324       goto out;
  325    }
  326    inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
  327    /* timestamp is already written, so mark_inode_dirty() is unneeded. */
  328 
  329    d_instantiate(dentry, inode);
  330 out:
    331    unlock_kernel();
- 331 do-while (0)
 - 332    return err;
  333 }
  334 
  335 /***** Remove a directory */
 
- 336 static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
  337 {
  338    struct inode *inode = dentry->d_inode;
  339    struct fat_slot_info sinfo;
  340    int err;
  341 
    342    lock_kernel();
- 342 do-while (0)
  343    /*
  344     * Check whether the directory is not in use, then check
  345     * whether it is empty.
  346     */
  347    err = fat_dir_empty(inode);
- 348    if (err)
 - 349       goto out;
  350    err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
- 351    if (err)
 - 352       goto out;
  353 
  354    err = fat_remove_entries(dir, &sinfo);   /* and releases bh */
- 355    if (err)
 - 356       goto out;
  357    dir->i_nlink--;
  358 
  359    inode->i_nlink = 0;
  360    inode->i_ctime = CURRENT_TIME_SEC;
  361    fat_detach(inode);
  362 out:
    363    unlock_kernel();
- 363 do-while (0)
  364 
 - 365    return err;
  366 }
  367 
  368 /***** Make a directory */
 
- 369 static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
  370 {
  371    struct super_block *sb = dir->i_sb;
  372    struct fat_slot_info sinfo;
  373    struct inode *inode;
  374    unsigned char msdos_name[MSDOS_NAME];
  375    struct timespec ts;
  376    int err, is_hid, cluster;
  377 
    378    lock_kernel();
- 378 do-while (0)
  379 
  380    err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
  381             msdos_name, &MSDOS_SB(sb)->options);
- 382    if (err)
 - 383       goto out;
  384    is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
  385    /* foo vs .foo situation */
- 386    if (!fat_scan(dir, msdos_name, &sinfo)) {
  387       brelse(sinfo.bh);
  388       err = -EINVAL;
 - 389       goto out;
  390    }
  391 
  392    ts = CURRENT_TIME_SEC;
  393    cluster = fat_alloc_new_dir(dir, &ts);
- 394    if (cluster < 0) {
  395       err = cluster;
 - 396       goto out;
  397    }
  398    err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
- 399    if (err)
 - 400       goto out_free;
  401    dir->i_nlink++;
  402 
  403    inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
  404    brelse(sinfo.bh);
- 405    if (IS_ERR(inode)) {
  406       err = PTR_ERR(inode);
  407       /* the directory was completed, just return a error */
 - 408       goto out;
  409    }
  410    inode->i_nlink = 2;
  411    inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
  412    /* timestamp is already written, so mark_inode_dirty() is unneeded. */
  413 
  414    d_instantiate(dentry, inode);
  415 
    416    unlock_kernel();
- 416 do-while (0)
 - 417    return 0;
  418 
  419&nb