more changes on original files
[linux-2.4.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         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         int dev_blocksize;
399         hfs_s32 part_size, part_start;
400         struct inode *root_inode;
401         int part;
402
403         memset(HFS_SB(s), 0, sizeof(*(HFS_SB(s))));     
404         if (!parse_options((char *)data, HFS_SB(s), &part)) {
405                 hfs_warn("hfs_fs: unable to parse mount options.\n");
406                 goto bail3;
407         }
408
409         /* set the device driver to 512-byte blocks */
410         if (set_blocksize(dev, HFS_SECTOR_SIZE) < 0) {
411                 dev_blocksize = get_hardsect_size(dev);
412                 hfs_warn("hfs_fs: unsupported device block size: %d\n",
413                          dev_blocksize);
414                 goto bail3;
415         }
416         s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS;
417         s->s_blocksize = HFS_SECTOR_SIZE;
418
419 #ifdef CONFIG_MAC_PARTITION
420         /* check to see if we're in a partition */
421         mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, 0);
422
423         /* erk. try parsing the partition table ourselves */
424         if (!mdb) {
425                 if (hfs_part_find(s, part, silent, &part_size, &part_start)) {
426                         goto bail2;
427                 }
428                 mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, part_start);
429         }
430 #else
431         if (hfs_part_find(s, part, silent, &part_size, &part_start)) {
432                 goto bail2;
433         }
434
435         mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, part_start);
436 #endif
437
438         if (!mdb) {
439                 if (!silent) {
440                         hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n",
441                                kdevname(dev));
442                 }
443                 goto bail2;
444         }
445
446         if (mdb->attrib & (HFS_SB_ATTRIB_HLOCK | HFS_SB_ATTRIB_SLOCK)) {
447                 if (!silent)
448                         hfs_warn("hfs_fs: Filesystem is marked locked, mounting read-only.\n");
449                 s->s_flags |= MS_RDONLY;
450         }
451
452         HFS_SB(s)->s_mdb = mdb;
453         if (HFS_ITYPE(mdb->next_id) != 0) {
454                 hfs_warn("hfs_fs: too many files.\n");
455                 goto bail1;
456         }
457
458         s->s_magic = HFS_SUPER_MAGIC;
459         s->s_op = &hfs_super_operations;
460
461         /* try to get the root inode */
462         hfs_cat_build_key(htonl(HFS_POR_CNID),
463                           (struct hfs_name *)(mdb->vname), &key);
464
465         root_inode = hfs_iget(hfs_cat_get(mdb, &key), HFS_ITYPE_NORM, NULL);
466         if (!root_inode) 
467                 goto bail_no_root;
468           
469         s->s_root = d_alloc_root(root_inode);
470         if (!s->s_root) 
471                 goto bail_no_root;
472
473         /* fix up pointers. */
474         HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] =
475           s->s_root;
476         s->s_root->d_op = &hfs_dentry_operations;
477
478         /* everything's okay */
479         return s;
480
481 bail_no_root: 
482         hfs_warn("hfs_fs: get root inode failed.\n");
483         iput(root_inode);
484 bail1:
485         hfs_mdb_put(mdb, s->s_flags & MS_RDONLY);
486 bail2:
487         set_blocksize(dev, BLOCK_SIZE);
488 bail3:
489         return NULL;    
490 }
491
492 int hfs_remount(struct super_block *s, int *flags, char *data)
493 {
494         int part; /* ignored */
495
496         if (!parse_options(data, HFS_SB(s), &part)) {
497                 hfs_warn("hfs_fs: unable to parse mount options.\n");
498                 return -EINVAL;
499         }
500
501         if ((*flags & MS_RDONLY) == (s->s_flags & MS_RDONLY))
502                 return 0;
503         if (!(*flags & MS_RDONLY)) {
504                 if (HFS_SB(s)->s_mdb->attrib & (HFS_SB_ATTRIB_HLOCK | HFS_SB_ATTRIB_SLOCK)) {
505                         hfs_warn("hfs_fs: Filesystem is marked locked, leaving it read-only.\n");
506                         s->s_flags |= MS_RDONLY;
507                         *flags |= MS_RDONLY;
508                 }
509         }
510         return 0;
511 }
512
513 static int __init init_hfs_fs(void)
514 {
515         hfs_cat_init();
516         return register_filesystem(&hfs_fs);
517 }
518
519 static void __exit exit_hfs_fs(void) {
520         hfs_cat_free();
521         unregister_filesystem(&hfs_fs);
522 }
523
524 module_init(init_hfs_fs)
525 module_exit(exit_hfs_fs)
526
527 #if defined(DEBUG_ALL) || defined(DEBUG_MEM)
528 long int hfs_alloc = 0;
529 #endif