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