The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/hfs/super.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * linux/fs/hfs/super.c
    3  *
    4  * Copyright (C) 1995-1997  Paul H. Hargrove
    5  * This file may be distributed under the terms of the GNU General Public License.
    6  *
    7  * This file contains hfs_read_super(), some of the super_ops and
    8  * init_module() and cleanup_module().  The remaining super_ops are in
    9  * inode.c since they deal with inodes.
   10  *
   11  * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
   12  *
   13  * "XXX" in a comment is a note to myself to consider changing something.
   14  *
   15  * In function preconditions the term "valid" applied to a pointer to
   16  * a structure means that the pointer is non-NULL and the structure it
   17  * points to has all fields initialized to consistent values.
   18  *
   19  * The code in this file initializes some structures which contain
   20  * pointers by calling memset(&foo, 0, sizeof(foo)).
   21  * This produces the desired behavior only due to the non-ANSI
   22  * assumption that the machine representation of NULL is all zeros.
   23  */
   24 
   25 #include "hfs.h"
   26 #include <linux/hfs_fs_sb.h>
   27 #include <linux/hfs_fs_i.h>
   28 #include <linux/hfs_fs.h>
   29 
   30 #include <linux/config.h> /* for CONFIG_MAC_PARTITION */
   31 #include <linux/blkdev.h>
   32 #include <linux/module.h>
   33 #include <linux/init.h>
   34 
   35 MODULE_LICENSE("GPL");
   36 
   37 /*================ Forward declarations ================*/
   38 
   39 static void hfs_read_inode(struct inode *);
   40 static void hfs_put_super(struct super_block *);
   41 static int hfs_statfs(struct super_block *, struct statfs *);
   42 static void hfs_write_super(struct super_block *);
   43 
   44 /*================ Global variables ================*/
   45 
   46 static struct super_operations hfs_super_operations = { 
   47         read_inode:     hfs_read_inode,
   48         put_inode:      hfs_put_inode,
   49         put_super:      hfs_put_super,
   50         write_super:    hfs_write_super,
   51         statfs:         hfs_statfs,
   52         remount_fs:     hfs_remount,
   53 };
   54 
   55 /*================ File-local variables ================*/
   56 
   57 static DECLARE_FSTYPE_DEV(hfs_fs, "hfs", hfs_read_super);
   58 
   59 /*================ File-local functions ================*/
   60 
   61 /* 
   62  * hfs_read_inode()
   63  *
   64  * this doesn't actually do much. hfs_iget actually fills in the 
   65  * necessary inode information.
   66  */
   67 static void hfs_read_inode(struct inode *inode)
   68 {
   69   inode->i_mode = 0;
   70 }
   71 
   72 /*
   73  * hfs_write_super()
   74  *
   75  * Description:
   76  *   This function is called by the VFS only. When the filesystem
   77  *   is mounted r/w it updates the MDB on disk.
   78  * Input Variable(s):
   79  *   struct super_block *sb: Pointer to the hfs superblock
   80  * Output Variable(s):
   81  *   NONE
   82  * Returns:
   83  *   void
   84  * Preconditions:
   85  *   'sb' points to a "valid" (struct super_block).
   86  * Postconditions:
   87  *   The MDB is marked 'unsuccessfully unmounted' by clearing bit 8 of drAtrb
   88  *   (hfs_put_super() must set this flag!). Some MDB fields are updated
   89  *   and the MDB buffer is written to disk by calling hfs_mdb_commit().
   90  */
   91 static void hfs_write_super(struct super_block *sb)
   92 {
   93         struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb;
   94 
   95         /* is this a valid hfs superblock? */
   96         if (!sb || sb->s_magic != HFS_SUPER_MAGIC) {
   97                 return;
   98         }
   99 
  100         if (!(sb->s_flags & MS_RDONLY)) {
  101                 /* sync everything to the buffers */
  102                 hfs_mdb_commit(mdb, 0);
  103         }
  104         sb->s_dirt = 0;
  105 }
  106 
  107 /*
  108  * hfs_put_super()
  109  *
  110  * This is the put_super() entry in the super_operations structure for
  111  * HFS filesystems.  The purpose is to release the resources
  112  * associated with the superblock sb.
  113  */
  114 static void hfs_put_super(struct super_block *sb)
  115 {
  116         struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb;
  117  
  118         if (!(sb->s_flags & MS_RDONLY)) {
  119                 hfs_mdb_commit(mdb, 0);
  120                 sb->s_dirt = 0;
  121         }
  122 
  123         /* release the MDB's resources */
  124         hfs_mdb_put(mdb, sb->s_flags & MS_RDONLY);
  125 
  126         /* restore default blocksize for the device */
  127         set_blocksize(sb->s_dev, BLOCK_SIZE);
  128 }
  129 
  130 /*
  131  * hfs_statfs()
  132  *
  133  * This is the statfs() entry in the super_operations structure for
  134  * HFS filesystems.  The purpose is to return various data about the
  135  * filesystem.
  136  *
  137  * changed f_files/f_ffree to reflect the fs_ablock/free_ablocks.
  138  */
  139 static int hfs_statfs(struct super_block *sb, struct statfs *buf)
  140 {
  141         struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb;
  142 
  143         buf->f_type = HFS_SUPER_MAGIC;
  144         buf->f_bsize = HFS_SECTOR_SIZE;
  145         buf->f_blocks = mdb->alloc_blksz * mdb->fs_ablocks;
  146         buf->f_bfree = mdb->alloc_blksz * mdb->free_ablocks;
  147         buf->f_bavail = buf->f_bfree;
  148         buf->f_files = mdb->fs_ablocks;  
  149         buf->f_ffree = mdb->free_ablocks;
  150         buf->f_namelen = HFS_NAMELEN;
  151 
  152         return 0;
  153 }
  154 
  155 /*
  156  * parse_options()
  157  * 
  158  * adapted from linux/fs/msdos/inode.c written 1992,93 by Werner Almesberger
  159  * This function is called by hfs_read_super() to parse the mount options.
  160  */
  161 static int parse_options(char *options, struct hfs_sb_info *hsb, int *part)
  162 {
  163         char *this_char, *value;
  164         char names, fork;
  165 
  166         if (hsb->magic != HFS_SB_MAGIC) {
  167                 /* initialize the sb with defaults */
  168                 hsb->magic = HFS_SB_MAGIC;
  169                 hsb->s_uid   = current->uid;
  170                 hsb->s_gid   = current->gid;
  171                 hsb->s_umask = current->fs->umask;
  172                 hsb->s_type    = 0x3f3f3f3f;    /* == '????' */
  173                 hsb->s_creator = 0x3f3f3f3f;    /* == '????' */
  174                 hsb->s_lowercase = 0;
  175                 hsb->s_quiet     = 0;
  176                 hsb->s_afpd      = 0;
  177                 /* default version. 0 just selects the defaults */
  178                 hsb->s_version   = 0; 
  179                 hsb->s_conv = 'b';
  180                 names = '?';
  181                 fork = '?';
  182                 *part = 0;
  183         }
  184 
  185         if (!options) {
  186                 goto done;
  187         }
  188         for (this_char = strtok(options,","); this_char;
  189              this_char = strtok(NULL,",")) {
  190                 if ((value = strchr(this_char,'=')) != NULL) {
  191                         *value++ = 0;
  192                 }
  193         /* Numeric-valued options */
  194                 if (!strcmp(this_char, "version")) {
  195                         if (!value || !*value) {
  196                                 return 0;
  197                         }
  198                         hsb->s_version = simple_strtoul(value,&value,0);
  199                         if (*value) {
  200                                 return 0;
  201                         }
  202                 } else if (!strcmp(this_char,"uid")) {
  203                         if (!value || !*value) {
  204                                 return 0;
  205                         }
  206                         hsb->s_uid = simple_strtoul(value,&value,0);
  207                         if (*value) {
  208                                 return 0;
  209                         }
  210                 } else if (!strcmp(this_char,"gid")) {
  211                         if (!value || !*value) {
  212                                 return 0;
  213                         }
  214                         hsb->s_gid = simple_strtoul(value,&value,0);
  215                         if (*value) {
  216                                 return 0;
  217                         }
  218                 } else if (!strcmp(this_char,"umask")) {
  219                         if (!value || !*value) {
  220                                 return 0;
  221                         }
  222                         hsb->s_umask = simple_strtoul(value,&value,8);
  223                         if (*value) {
  224                                 return 0;
  225                         }
  226                 } else if (!strcmp(this_char,"part")) {
  227                         if (!value || !*value) {
  228                                 return 0;
  229                         }
  230                         *part = simple_strtoul(value,&value,0);
  231                         if (*value) {
  232                                 return 0;
  233                         }
  234         /* String-valued options */
  235                 } else if (!strcmp(this_char,"type") && value) {
  236                         if (strlen(value) != 4) {
  237                                 return 0;
  238                         }
  239                         hsb->s_type = hfs_get_nl(value);
  240                 } else if (!strcmp(this_char,"creator") && value) {
  241                         if (strlen(value) != 4) {
  242                                 return 0;
  243                         }
  244                         hsb->s_creator = hfs_get_nl(value);
  245         /* Boolean-valued options */
  246                 } else if (!strcmp(this_char,"quiet")) {
  247                         if (value) {
  248                                 return 0;
  249                         }
  250                         hsb->s_quiet = 1;
  251                 } else if (!strcmp(this_char,"afpd")) {
  252                         if (value) {
  253                                 return 0;
  254                         }
  255                         hsb->s_afpd = 1;
  256         /* Multiple choice options */
  257                 } else if (!strcmp(this_char,"names") && value) {
  258                         if ((*value && !value[1] && strchr("ntal78c",*value)) ||
  259                             !strcmp(value,"netatalk") ||
  260                             !strcmp(value,"trivial") ||
  261                             !strcmp(value,"alpha") ||
  262                             !strcmp(value,"latin") ||
  263                             !strcmp(value,"7bit") ||
  264                             !strcmp(value,"8bit") ||
  265                             !strcmp(value,"cap")) {
  266                                 names = *value;
  267                         } else {
  268                                 return 0;
  269                         }
  270                 } else if (!strcmp(this_char,"fork") && value) {
  271                         if ((*value && !value[1] && strchr("nsdc",*value)) ||
  272                             !strcmp(value,"netatalk") ||
  273                             !strcmp(value,"single") ||
  274                             !strcmp(value,"double") ||
  275                             !strcmp(value,"cap")) {
  276                                 fork = *value;
  277                         } else {
  278                                 return 0;
  279                         }
  280                 } else if (!strcmp(this_char,"case") && value) {
  281                         if ((*value && !value[1] && strchr("la",*value)) ||
  282                             !strcmp(value,"lower") ||
  283                             !strcmp(value,"asis")) {
  284                                 hsb->s_lowercase = (*value == 'l');
  285                         } else {
  286                                 return 0;
  287                         }
  288                 } else if (!strcmp(this_char,"conv") && value) {
  289                         if ((*value && !value[1] && strchr("bta",*value)) ||
  290                             !strcmp(value,"binary") ||
  291                             !strcmp(value,"text") ||
  292                             !strcmp(value,"auto")) {
  293                                 hsb->s_conv = *value;
  294                         } else {
  295                                 return 0;
  296                         }
  297                 } else {
  298                         return 0;
  299                 }
  300         }
  301 
  302 done:
  303         /* Parse the "fork" and "names" options */
  304         if (fork == '?') {
  305                 fork = hsb->s_afpd ? 'n' : 'c';
  306         }
  307         switch (fork) {
  308         default:
  309         case 'c':
  310                 hsb->s_ifill = hfs_cap_ifill;
  311                 hsb->s_reserved1 = hfs_cap_reserved1;
  312                 hsb->s_reserved2 = hfs_cap_reserved2;
  313                 break;
  314 
  315         case 's':
  316                 hfs_warn("hfs_fs: AppleSingle not yet implemented.\n");
  317                 return 0;
  318                 /* break; */
  319         
  320         case 'd':
  321                 hsb->s_ifill = hfs_dbl_ifill;
  322                 hsb->s_reserved1 = hfs_dbl_reserved1;
  323                 hsb->s_reserved2 = hfs_dbl_reserved2;
  324                 break;
  325 
  326         case 'n':
  327                 hsb->s_ifill = hfs_nat_ifill;
  328                 hsb->s_reserved1 = hfs_nat_reserved1;
  329                 hsb->s_reserved2 = hfs_nat_reserved2;
  330                 break;
  331         }
  332 
  333         if (names == '?') {
  334                 names = fork;
  335         }
  336         switch (names) {
  337         default:
  338         case 'n':
  339                 hsb->s_nameout = hfs_colon2mac;
  340                 hsb->s_namein = hfs_mac2nat;
  341                 break;
  342 
  343         case 'c':
  344                 hsb->s_nameout = hfs_colon2mac;
  345                 hsb->s_namein = hfs_mac2cap;
  346                 break;
  347 
  348         case 't':
  349                 hsb->s_nameout = hfs_triv2mac;
  350                 hsb->s_namein = hfs_mac2triv;
  351                 break;
  352 
  353         case '7':
  354                 hsb->s_nameout = hfs_prcnt2mac;
  355                 hsb->s_namein = hfs_mac2seven;
  356                 break;
  357 
  358         case '8':
  359                 hsb->s_nameout = hfs_prcnt2mac;
  360                 hsb->s_namein = hfs_mac2eight;
  361                 break;
  362 
  363         case 'l':
  364                 hsb->s_nameout = hfs_latin2mac;
  365                 hsb->s_namein = hfs_mac2latin;
  366                 break;
  367 
  368         case 'a':       /* 's' and 'd' are unadvertised aliases for 'alpha', */
  369         case 's':       /* since 'alpha' is the default if fork=s or fork=d. */
  370         case 'd':       /* (It is also helpful for poor typists!)           */
  371                 hsb->s_nameout = hfs_prcnt2mac;
  372                 hsb->s_namein = hfs_mac2alpha;
  373                 break;
  374         }
  375 
  376         return 1;
  377 }
  378 
  379 /*================ Global functions ================*/
  380 
  381 /*
  382  * hfs_read_super()
  383  *
  384  * This is the function that is responsible for mounting an HFS
  385  * filesystem.  It performs all the tasks necessary to get enough data
  386  * from the disk to read the root inode.  This includes parsing the
  387  * mount options, dealing with Macintosh partitions, reading the
  388  * superblock and the allocation bitmap blocks, calling
  389  * hfs_btree_init() to get the necessary data about the extents and
  390  * catalog B-trees and, finally, reading the root inode into memory.
  391  */
  392 struct super_block *hfs_read_super(struct super_block *s, void *data,
  393                                    int silent)
  394 {
  395         struct hfs_mdb *mdb;
  396         struct hfs_cat_key key;
  397         kdev_t dev = s->s_dev;
  398         hfs_s32 part_size, part_start;
  399         struct inode *root_inode;
  400         int part;
  401 
  402         memset(HFS_SB(s), 0, sizeof(*(HFS_SB(s))));     
  403         if (!parse_options((char *)data, HFS_SB(s), &part)) {
  404                 hfs_warn("hfs_fs: unable to parse mount options.\n");
  405                 goto bail3;
  406         }
  407 
  408         /* set the device driver to 512-byte blocks */
  409         set_blocksize(dev, HFS_SECTOR_SIZE);
  410         s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS;
  411         s->s_blocksize = HFS_SECTOR_SIZE;
  412 
  413 #ifdef CONFIG_MAC_PARTITION
  414         /* check to see if we're in a partition */
  415         mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, 0);
  416 
  417         /* erk. try parsing the partition table ourselves */
  418         if (!mdb) {
  419                 if (hfs_part_find(s, part, silent, &part_size, &part_start)) {
  420                         goto bail2;
  421                 }
  422                 mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, part_start);
  423         }
  424 #else
  425         if (hfs_part_find(s, part, silent, &part_size, &part_start)) {
  426                 goto bail2;
  427         }
  428 
  429         mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, part_start);
  430 #endif
  431 
  432         if (!mdb) {
  433                 if (!silent) {
  434                         hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n",
  435                                kdevname(dev));
  436                 }
  437                 goto bail2;
  438         }
  439 
  440         if (mdb->attrib & (HFS_SB_ATTRIB_HLOCK | HFS_SB_ATTRIB_SLOCK)) {
  441                 if (!silent)
  442                         hfs_warn("hfs_fs: Filesystem is marked locked, mounting read-only.\n");
  443                 s->s_flags |= MS_RDONLY;
  444         }
  445 
  446         HFS_SB(s)->s_mdb = mdb;
  447         if (HFS_ITYPE(mdb->next_id) != 0) {
  448                 hfs_warn("hfs_fs: too many files.\n");
  449                 goto bail1;
  450         }
  451 
  452         s->s_magic = HFS_SUPER_MAGIC;
  453         s->s_op = &hfs_super_operations;
  454 
  455         /* try to get the root inode */
  456         hfs_cat_build_key(htonl(HFS_POR_CNID),
  457                           (struct hfs_name *)(mdb->vname), &key);
  458 
  459         root_inode = hfs_iget(hfs_cat_get(mdb, &key), HFS_ITYPE_NORM, NULL);
  460         if (!root_inode) 
  461                 goto bail_no_root;
  462           
  463         s->s_root = d_alloc_root(root_inode);
  464         if (!s->s_root) 
  465                 goto bail_no_root;
  466 
  467         /* fix up pointers. */
  468         HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] =
  469           s->s_root;
  470         s->s_root->d_op = &hfs_dentry_operations;
  471 
  472         /* everything's okay */
  473         return s;
  474 
  475 bail_no_root: 
  476         hfs_warn("hfs_fs: get root inode failed.\n");
  477         iput(root_inode);
  478 bail1:
  479         hfs_mdb_put(mdb, s->s_flags & MS_RDONLY);
  480 bail2:
  481         set_blocksize(dev, BLOCK_SIZE);
  482 bail3:
  483         return NULL;    
  484 }
  485 
  486 int hfs_remount(struct super_block *s, int *flags, char *data)
  487 {
  488         int part; /* ignored */
  489 
  490         if (!parse_options(data, HFS_SB(s), &part)) {
  491                 hfs_warn("hfs_fs: unable to parse mount options.\n");
  492                 return -EINVAL;
  493         }
  494 
  495         if ((*flags & MS_RDONLY) == (s->s_flags & MS_RDONLY))
  496                 return 0;
  497         if (!(*flags & MS_RDONLY)) {
  498                 if (HFS_SB(s)->s_mdb->attrib & (HFS_SB_ATTRIB_HLOCK | HFS_SB_ATTRIB_SLOCK)) {
  499                         hfs_warn("hfs_fs: Filesystem is marked locked, leaving it read-only.\n");
  500                         s->s_flags |= MS_RDONLY;
  501                         *flags |= MS_RDONLY;
  502                 }
  503         }
  504         return 0;
  505 }
  506 
  507 static int __init init_hfs_fs(void)
  508 {
  509         hfs_cat_init();
  510         return register_filesystem(&hfs_fs);
  511 }
  512 
  513 static void __exit exit_hfs_fs(void) {
  514         hfs_cat_free();
  515         unregister_filesystem(&hfs_fs);
  516 }
  517 
  518 module_init(init_hfs_fs)
  519 module_exit(exit_hfs_fs)
  520 
  521 #if defined(DEBUG_ALL) || defined(DEBUG_MEM)
  522 long int hfs_alloc = 0;
  523 #endif

Cache object: 021747a9ed8fdd671049c5ea52cd1381


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.