linux/fs/fat/namei_msdos.c
<<
>>
Prefs
   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/iversion.h>
  11#include "fat.h"
  12
  13/* Characters that are undesirable in an MS-DOS file name */
  14static unsigned char bad_chars[] = "*?<>|\"";
  15static unsigned char bad_if_strict[] = "+=,; ";
  16
  17/***** Formats an MS-DOS file name. Rejects invalid names. */
  18static int msdos_format_name(const unsigned char *name, int len,
  19                             unsigned char *res, struct fat_mount_options *opts)
  20        /*
  21         * name is the proposed name, len is its length, res is
  22         * the resulting name, opts->name_check is either (r)elaxed,
  23         * (n)ormal or (s)trict, opts->dotsOK allows dots at the
  24         * beginning of name (for hidden files)
  25         */
  26{
  27        unsigned char *walk;
  28        unsigned char c;
  29        int space;
  30
  31        if (name[0] == '.') {   /* dotfile because . and .. already done */
  32                if (opts->dotsOK) {
  33                        /* Get rid of dot - test for it elsewhere */
  34                        name++;
  35                        len--;
  36                } else
  37                        return -EINVAL;
  38        }
  39        /*
  40         * disallow names that _really_ start with a dot
  41         */
  42        space = 1;
  43        c = 0;
  44        for (walk = res; len && walk - res < 8; walk++) {
  45                c = *name++;
  46                len--;
  47                if (opts->name_check != 'r' && strchr(bad_chars, c))
  48                        return -EINVAL;
  49                if (opts->name_check == 's' && strchr(bad_if_strict, c))
  50                        return -EINVAL;
  51                if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
  52                        return -EINVAL;
  53                if (c < ' ' || c == ':' || c == '\\')
  54                        return -EINVAL;
  55        /*
  56         * 0xE5 is legal as a first character, but we must substitute
  57         * 0x05 because 0xE5 marks deleted files.  Yes, DOS really
  58         * does this.
  59         * It seems that Microsoft hacked DOS to support non-US
  60         * characters after the 0xE5 character was already in use to
  61         * mark deleted files.
  62         */
  63                if ((res == walk) && (c == 0xE5))
  64                        c = 0x05;
  65                if (c == '.')
  66                        break;
  67                space = (c == ' ');
  68                *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c - 32 : c;
  69        }
  70        if (space)
  71                return -EINVAL;
  72        if (opts->name_check == 's' && len && c != '.') {
  73                c = *name++;
  74                len--;
  75                if (c != '.')
  76                        return -EINVAL;
  77        }
  78        while (c != '.' && len--)
  79                c = *name++;
  80        if (c == '.') {
  81                while (walk - res < 8)
  82                        *walk++ = ' ';
  83                while (len > 0 && walk - res < MSDOS_NAME) {
  84                        c = *name++;
  85                        len--;
  86                        if (opts->name_check != 'r' && strchr(bad_chars, c))
  87                                return -EINVAL;
  88                        if (opts->name_check == 's' &&
  89                            strchr(bad_if_strict, c))
  90                                return -EINVAL;
  91                        if (c < ' ' || c == ':' || c == '\\')
  92                                return -EINVAL;
  93                        if (c == '.') {
  94                                if (opts->name_check == 's')
  95                                        return -EINVAL;
  96                                break;
  97                        }
  98                        if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
  99                                return -EINVAL;
 100                        space = c == ' ';
 101                        if (!opts->nocase && c >= 'a' && c <= 'z')
 102                                *walk++ = c - 32;
 103                        else
 104                                *walk++ = c;
 105                }
 106                if (space)
 107                        return -EINVAL;
 108                if (opts->name_check == 's' && len)
 109                        return -EINVAL;
 110        }
 111        while (walk - res < MSDOS_NAME)
 112                *walk++ = ' ';
 113
 114        return 0;
 115}
 116
 117/***** Locates a directory entry.  Uses unformatted name. */
 118static int msdos_find(struct inode *dir, const unsigned char *name, int len,
 119                      struct fat_slot_info *sinfo)
 120{
 121        struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
 122        unsigned char msdos_name[MSDOS_NAME];
 123        int err;
 124
 125        err = msdos_format_name(name, len, msdos_name, &sbi->options);
 126        if (err)
 127                return -ENOENT;
 128
 129        err = fat_scan(dir, msdos_name, sinfo);
 130        if (!err && sbi->options.dotsOK) {
 131                if (name[0] == '.') {
 132                        if (!(sinfo->de->attr & ATTR_HIDDEN))
 133                                err = -ENOENT;
 134                } else {
 135                        if (sinfo->de->attr & ATTR_HIDDEN)
 136                                err = -ENOENT;
 137                }
 138                if (err)
 139                        brelse(sinfo->bh);
 140        }
 141        return err;
 142}
 143
 144/*
 145 * Compute the hash for the msdos name corresponding to the dentry.
 146 * Note: if the name is invalid, we leave the hash code unchanged so
 147 * that the existing dentry can be used. The msdos fs routines will
 148 * return ENOENT or EINVAL as appropriate.
 149 */
 150static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
 151{
 152        struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
 153        unsigned char msdos_name[MSDOS_NAME];
 154        int error;
 155
 156        error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
 157        if (!error)
 158                qstr->hash = full_name_hash(dentry, msdos_name, MSDOS_NAME);
 159        return 0;
 160}
 161
 162/*
 163 * Compare two msdos names. If either of the names are invalid,
 164 * we fall back to doing the standard name comparison.
 165 */
 166static int msdos_cmp(const struct dentry *dentry,
 167                unsigned int len, const char *str, const struct qstr *name)
 168{
 169        struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
 170        unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
 171        int error;
 172
 173        error = msdos_format_name(name->name, name->len, a_msdos_name, options);
 174        if (error)
 175                goto old_compare;
 176        error = msdos_format_name(str, len, b_msdos_name, options);
 177        if (error)
 178                goto old_compare;
 179        error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
 180out:
 181        return error;
 182
 183old_compare:
 184        error = 1;
 185        if (name->len == len)
 186                error = memcmp(name->name, str, len);
 187        goto out;
 188}
 189
 190static const struct dentry_operations msdos_dentry_operations = {
 191        .d_hash         = msdos_hash,
 192        .d_compare      = msdos_cmp,
 193};
 194
 195/*
 196 * AV. Wrappers for FAT sb operations. Is it wise?
 197 */
 198
 199/***** Get inode using directory and name */
 200static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
 201                                   unsigned int flags)
 202{
 203        struct super_block *sb = dir->i_sb;
 204        struct fat_slot_info sinfo;
 205        struct inode *inode;
 206        int err;
 207
 208        mutex_lock(&MSDOS_SB(sb)->s_lock);
 209        err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
 210        switch (err) {
 211        case -ENOENT:
 212                inode = NULL;
 213                break;
 214        case 0:
 215                inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 216                brelse(sinfo.bh);
 217                break;
 218        default:
 219                inode = ERR_PTR(err);
 220        }
 221        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 222        return d_splice_alias(inode, dentry);
 223}
 224
 225/***** Creates a directory entry (name is already formatted). */
 226static int msdos_add_entry(struct inode *dir, const unsigned char *name,
 227                           int is_dir, int is_hid, int cluster,
 228                           struct timespec *ts, struct fat_slot_info *sinfo)
 229{
 230        struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
 231        struct msdos_dir_entry de;
 232        __le16 time, date;
 233        int err;
 234
 235        memcpy(de.name, name, MSDOS_NAME);
 236        de.attr = is_dir ? ATTR_DIR : ATTR_ARCH;
 237        if (is_hid)
 238                de.attr |= ATTR_HIDDEN;
 239        de.lcase = 0;
 240        fat_time_unix2fat(sbi, ts, &time, &date, NULL);
 241        de.cdate = de.adate = 0;
 242        de.ctime = 0;
 243        de.ctime_cs = 0;
 244        de.time = time;
 245        de.date = date;
 246        fat_set_start(&de, cluster);
 247        de.size = 0;
 248
 249        err = fat_add_entries(dir, &de, 1, sinfo);
 250        if (err)
 251                return err;
 252
 253        dir->i_ctime = dir->i_mtime = *ts;
 254        if (IS_DIRSYNC(dir))
 255                (void)fat_sync_inode(dir);
 256        else
 257                mark_inode_dirty(dir);
 258
 259        return 0;
 260}
 261
 262/***** Create a file */
 263static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 264                        bool excl)
 265{
 266        struct super_block *sb = dir->i_sb;
 267        struct inode *inode = NULL;
 268        struct fat_slot_info sinfo;
 269        struct timespec ts;
 270        unsigned char msdos_name[MSDOS_NAME];
 271        int err, is_hid;
 272
 273        mutex_lock(&MSDOS_SB(sb)->s_lock);
 274
 275        err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
 276                                msdos_name, &MSDOS_SB(sb)->options);
 277        if (err)
 278                goto out;
 279        is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
 280        /* Have to do it due to foo vs. .foo conflicts */
 281        if (!fat_scan(dir, msdos_name, &sinfo)) {
 282                brelse(sinfo.bh);
 283                err = -EINVAL;
 284                goto out;
 285        }
 286
 287        ts = current_time(dir);
 288        err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
 289        if (err)
 290                goto out;
 291        inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 292        brelse(sinfo.bh);
 293        if (IS_ERR(inode)) {
 294                err = PTR_ERR(inode);
 295                goto out;
 296        }
 297        inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
 298        /* timestamp is already written, so mark_inode_dirty() is unneeded. */
 299
 300        d_instantiate(dentry, inode);
 301out:
 302        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 303        if (!err)
 304                err = fat_flush_inodes(sb, dir, inode);
 305        return err;
 306}
 307
 308/***** Remove a directory */
 309static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
 310{
 311        struct super_block *sb = dir->i_sb;
 312        struct inode *inode = d_inode(dentry);
 313        struct fat_slot_info sinfo;
 314        int err;
 315
 316        mutex_lock(&MSDOS_SB(sb)->s_lock);
 317        /*
 318         * Check whether the directory is not in use, then check
 319         * whether it is empty.
 320         */
 321        err = fat_dir_empty(inode);
 322        if (err)
 323                goto out;
 324        err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
 325        if (err)
 326                goto out;
 327
 328        err = fat_remove_entries(dir, &sinfo);  /* and releases bh */
 329        if (err)
 330                goto out;
 331        drop_nlink(dir);
 332
 333        clear_nlink(inode);
 334        inode->i_ctime = current_time(inode);
 335        fat_detach(inode);
 336out:
 337        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 338        if (!err)
 339                err = fat_flush_inodes(sb, dir, inode);
 340
 341        return err;
 342}
 343
 344/***** Make a directory */
 345static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 346{
 347        struct super_block *sb = dir->i_sb;
 348        struct fat_slot_info sinfo;
 349        struct inode *inode;
 350        unsigned char msdos_name[MSDOS_NAME];
 351        struct timespec ts;
 352        int err, is_hid, cluster;
 353
 354        mutex_lock(&MSDOS_SB(sb)->s_lock);
 355
 356        err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
 357                                msdos_name, &MSDOS_SB(sb)->options);
 358        if (err)
 359                goto out;
 360        is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
 361        /* foo vs .foo situation */
 362        if (!fat_scan(dir, msdos_name, &sinfo)) {
 363                brelse(sinfo.bh);
 364                err = -EINVAL;
 365                goto out;
 366        }
 367
 368        ts = current_time(dir);
 369        cluster = fat_alloc_new_dir(dir, &ts);
 370        if (cluster < 0) {
 371                err = cluster;
 372                goto out;
 373        }
 374        err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
 375        if (err)
 376                goto out_free;
 377        inc_nlink(dir);
 378
 379        inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 380        brelse(sinfo.bh);
 381        if (IS_ERR(inode)) {
 382                err = PTR_ERR(inode);
 383                /* the directory was completed, just return a error */
 384                goto out;
 385        }
 386        set_nlink(inode, 2);
 387        inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
 388        /* timestamp is already written, so mark_inode_dirty() is unneeded. */
 389
 390        d_instantiate(dentry, inode);
 391
 392        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 393        fat_flush_inodes(sb, dir, inode);
 394        return 0;
 395
 396out_free:
 397        fat_free_clusters(dir, cluster);
 398out:
 399        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 400        return err;
 401}
 402
 403/***** Unlink a file */
 404static int msdos_unlink(struct inode *dir, struct dentry *dentry)
 405{
 406        struct inode *inode = d_inode(dentry);
 407        struct super_block *sb = inode->i_sb;
 408        struct fat_slot_info sinfo;
 409        int err;
 410
 411        mutex_lock(&MSDOS_SB(sb)->s_lock);
 412        err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
 413        if (err)
 414                goto out;
 415
 416        err = fat_remove_entries(dir, &sinfo);  /* and releases bh */
 417        if (err)
 418                goto out;
 419        clear_nlink(inode);
 420        inode->i_ctime = current_time(inode);
 421        fat_detach(inode);
 422out:
 423        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 424        if (!err)
 425                err = fat_flush_inodes(sb, dir, inode);
 426
 427        return err;
 428}
 429
 430static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
 431                           struct dentry *old_dentry,
 432                           struct inode *new_dir, unsigned char *new_name,
 433                           struct dentry *new_dentry, int is_hid)
 434{
 435        struct buffer_head *dotdot_bh;
 436        struct msdos_dir_entry *dotdot_de;
 437        struct inode *old_inode, *new_inode;
 438        struct fat_slot_info old_sinfo, sinfo;
 439        struct timespec ts;
 440        loff_t new_i_pos;
 441        int err, old_attrs, is_dir, update_dotdot, corrupt = 0;
 442
 443        old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
 444        old_inode = d_inode(old_dentry);
 445        new_inode = d_inode(new_dentry);
 446
 447        err = fat_scan(old_dir, old_name, &old_sinfo);
 448        if (err) {
 449                err = -EIO;
 450                goto out;
 451        }
 452
 453        is_dir = S_ISDIR(old_inode->i_mode);
 454        update_dotdot = (is_dir && old_dir != new_dir);
 455        if (update_dotdot) {
 456                if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) {
 457                        err = -EIO;
 458                        goto out;
 459                }
 460        }
 461
 462        old_attrs = MSDOS_I(old_inode)->i_attrs;
 463        err = fat_scan(new_dir, new_name, &sinfo);
 464        if (!err) {
 465                if (!new_inode) {
 466                        /* "foo" -> ".foo" case. just change the ATTR_HIDDEN */
 467                        if (sinfo.de != old_sinfo.de) {
 468                                err = -EINVAL;
 469                                goto out;
 470                        }
 471                        if (is_hid)
 472                                MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
 473                        else
 474                                MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
 475                        if (IS_DIRSYNC(old_dir)) {
 476                                err = fat_sync_inode(old_inode);
 477                                if (err) {
 478                                        MSDOS_I(old_inode)->i_attrs = old_attrs;
 479                                        goto out;
 480                                }
 481                        } else
 482                                mark_inode_dirty(old_inode);
 483
 484                        inode_inc_iversion(old_dir);
 485                        old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
 486                        if (IS_DIRSYNC(old_dir))
 487                                (void)fat_sync_inode(old_dir);
 488                        else
 489                                mark_inode_dirty(old_dir);
 490                        goto out;
 491                }
 492        }
 493
 494        ts = current_time(old_inode);
 495        if (new_inode) {
 496                if (err)
 497                        goto out;
 498                if (is_dir) {
 499                        err = fat_dir_empty(new_inode);
 500                        if (err)
 501                                goto out;
 502                }
 503                new_i_pos = MSDOS_I(new_inode)->i_pos;
 504                fat_detach(new_inode);
 505        } else {
 506                err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0,
 507                                      &ts, &sinfo);
 508                if (err)
 509                        goto out;
 510                new_i_pos = sinfo.i_pos;
 511        }
 512        inode_inc_iversion(new_dir);
 513
 514        fat_detach(old_inode);
 515        fat_attach(old_inode, new_i_pos);
 516        if (is_hid)
 517                MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
 518        else
 519                MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
 520        if (IS_DIRSYNC(new_dir)) {
 521                err = fat_sync_inode(old_inode);
 522                if (err)
 523                        goto error_inode;
 524        } else
 525                mark_inode_dirty(old_inode);
 526
 527        if (update_dotdot) {
 528                fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart);
 529                mark_buffer_dirty_inode(dotdot_bh, old_inode);
 530                if (IS_DIRSYNC(new_dir)) {
 531                        err = sync_dirty_buffer(dotdot_bh);
 532                        if (err)
 533                                goto error_dotdot;
 534                }
 535                drop_nlink(old_dir);
 536                if (!new_inode)
 537                        inc_nlink(new_dir);
 538        }
 539
 540        err = fat_remove_entries(old_dir, &old_sinfo);  /* and releases bh */
 541        old_sinfo.bh = NULL;
 542        if (err)
 543                goto error_dotdot;
 544        inode_inc_iversion(old_dir);
 545        old_dir->i_ctime = old_dir->i_mtime = ts;
 546        if (IS_DIRSYNC(old_dir))
 547                (void)fat_sync_inode(old_dir);
 548        else
 549                mark_inode_dirty(old_dir);
 550
 551        if (new_inode) {
 552                drop_nlink(new_inode);
 553                if (is_dir)
 554                        drop_nlink(new_inode);
 555                new_inode->i_ctime = ts;
 556        }
 557out:
 558        brelse(sinfo.bh);
 559        brelse(dotdot_bh);
 560        brelse(old_sinfo.bh);
 561        return err;
 562
 563error_dotdot:
 564        /* data cluster is shared, serious corruption */
 565        corrupt = 1;
 566
 567        if (update_dotdot) {
 568                fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart);
 569                mark_buffer_dirty_inode(dotdot_bh, old_inode);
 570                corrupt |= sync_dirty_buffer(dotdot_bh);
 571        }
 572error_inode:
 573        fat_detach(old_inode);
 574        fat_attach(old_inode, old_sinfo.i_pos);
 575        MSDOS_I(old_inode)->i_attrs = old_attrs;
 576        if (new_inode) {
 577                fat_attach(new_inode, new_i_pos);
 578                if (corrupt)
 579                        corrupt |= fat_sync_inode(new_inode);
 580        } else {
 581                /*
 582                 * If new entry was not sharing the data cluster, it
 583                 * shouldn't be serious corruption.
 584                 */
 585                int err2 = fat_remove_entries(new_dir, &sinfo);
 586                if (corrupt)
 587                        corrupt |= err2;
 588                sinfo.bh = NULL;
 589        }
 590        if (corrupt < 0) {
 591                fat_fs_error(new_dir->i_sb,
 592                             "%s: Filesystem corrupted (i_pos %lld)",
 593                             __func__, sinfo.i_pos);
 594        }
 595        goto out;
 596}
 597
 598/***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
 599static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
 600                        struct inode *new_dir, struct dentry *new_dentry,
 601                        unsigned int flags)
 602{
 603        struct super_block *sb = old_dir->i_sb;
 604        unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
 605        int err, is_hid;
 606
 607        if (flags & ~RENAME_NOREPLACE)
 608                return -EINVAL;
 609
 610        mutex_lock(&MSDOS_SB(sb)->s_lock);
 611
 612        err = msdos_format_name(old_dentry->d_name.name,
 613                                old_dentry->d_name.len, old_msdos_name,
 614                                &MSDOS_SB(old_dir->i_sb)->options);
 615        if (err)
 616                goto out;
 617        err = msdos_format_name(new_dentry->d_name.name,
 618                                new_dentry->d_name.len, new_msdos_name,
 619                                &MSDOS_SB(new_dir->i_sb)->options);
 620        if (err)
 621                goto out;
 622
 623        is_hid =
 624             (new_dentry->d_name.name[0] == '.') && (new_msdos_name[0] != '.');
 625
 626        err = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
 627                              new_dir, new_msdos_name, new_dentry, is_hid);
 628out:
 629        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 630        if (!err)
 631                err = fat_flush_inodes(sb, old_dir, new_dir);
 632        return err;
 633}
 634
 635static const struct inode_operations msdos_dir_inode_operations = {
 636        .create         = msdos_create,
 637        .lookup         = msdos_lookup,
 638        .unlink         = msdos_unlink,
 639        .mkdir          = msdos_mkdir,
 640        .rmdir          = msdos_rmdir,
 641        .rename         = msdos_rename,
 642        .setattr        = fat_setattr,
 643        .getattr        = fat_getattr,
 644};
 645
 646static void setup(struct super_block *sb)
 647{
 648        MSDOS_SB(sb)->dir_ops = &msdos_dir_inode_operations;
 649        sb->s_d_op = &msdos_dentry_operations;
 650        sb->s_flags |= SB_NOATIME;
 651}
 652
 653static int msdos_fill_super(struct super_block *sb, void *data, int silent)
 654{
 655        return fat_fill_super(sb, data, silent, 0, setup);
 656}
 657
 658static struct dentry *msdos_mount(struct file_system_type *fs_type,
 659                        int flags, const char *dev_name,
 660                        void *data)
 661{
 662        return mount_bdev(fs_type, flags, dev_name, data, msdos_fill_super);
 663}
 664
 665static struct file_system_type msdos_fs_type = {
 666        .owner          = THIS_MODULE,
 667        .name           = "msdos",
 668        .mount          = msdos_mount,
 669        .kill_sb        = kill_block_super,
 670        .fs_flags       = FS_REQUIRES_DEV,
 671};
 672MODULE_ALIAS_FS("msdos");
 673
 674static int __init init_msdos_fs(void)
 675{
 676        return register_filesystem(&msdos_fs_type);
 677}
 678
 679static void __exit exit_msdos_fs(void)
 680{
 681        unregister_filesystem(&msdos_fs_type);
 682}
 683
 684MODULE_LICENSE("GPL");
 685MODULE_AUTHOR("Werner Almesberger");
 686MODULE_DESCRIPTION("MS-DOS filesystem support");
 687
 688module_init(init_msdos_fs)
 689module_exit(exit_msdos_fs)
 690