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