4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU Public License.
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.
11 * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
13 * "XXX" in a comment is a note to myself to consider changing something.
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.
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.
26 #include <linux/hfs_fs_sb.h>
27 #include <linux/hfs_fs_i.h>
28 #include <linux/hfs_fs.h>
30 #include <linux/config.h> /* for CONFIG_MAC_PARTITION */
31 #include <linux/blkdev.h>
32 #include <linux/module.h>
33 #include <linux/init.h>
35 /*================ Forward declarations ================*/
37 static void hfs_read_inode(struct inode
*);
38 static void hfs_put_super(struct super_block
*);
39 static int hfs_statfs(struct super_block
*, struct statfs
*);
40 static void hfs_write_super(struct super_block
*);
42 /*================ Global variables ================*/
44 static struct super_operations hfs_super_operations
= {
45 read_inode
: hfs_read_inode
,
46 put_inode
: hfs_put_inode
,
47 put_super
: hfs_put_super
,
48 write_super
: hfs_write_super
,
52 /*================ File-local variables ================*/
54 static DECLARE_FSTYPE_DEV(hfs_fs
, "hfs", hfs_read_super
);
56 /*================ File-local functions ================*/
61 * this doesn't actually do much. hfs_iget actually fills in the
62 * necessary inode information.
64 static void hfs_read_inode(struct inode
*inode
)
73 * This function is called by the VFS only. When the filesystem
74 * is mounted r/w it updates the MDB on disk.
76 * struct super_block *sb: Pointer to the hfs superblock
82 * 'sb' points to a "valid" (struct super_block).
84 * The MDB is marked 'unsuccessfully unmounted' by clearing bit 8 of drAtrb
85 * (hfs_put_super() must set this flag!). Some MDB fields are updated
86 * and the MDB buffer is written to disk by calling hfs_mdb_commit().
88 static void hfs_write_super(struct super_block
*sb
)
90 struct hfs_mdb
*mdb
= HFS_SB(sb
)->s_mdb
;
92 /* is this a valid hfs superblock? */
93 if (!sb
|| sb
->s_magic
!= HFS_SUPER_MAGIC
) {
97 if (!(sb
->s_flags
& MS_RDONLY
)) {
98 /* sync everything to the buffers */
99 hfs_mdb_commit(mdb
, 0);
107 * This is the put_super() entry in the super_operations structure for
108 * HFS filesystems. The purpose is to release the resources
109 * associated with the superblock sb.
111 static void hfs_put_super(struct super_block
*sb
)
113 struct hfs_mdb
*mdb
= HFS_SB(sb
)->s_mdb
;
115 if (!(sb
->s_flags
& MS_RDONLY
)) {
116 hfs_mdb_commit(mdb
, 0);
120 /* release the MDB's resources */
121 hfs_mdb_put(mdb
, sb
->s_flags
& MS_RDONLY
);
123 /* restore default blocksize for the device */
124 set_blocksize(sb
->s_dev
, BLOCK_SIZE
);
130 * This is the statfs() entry in the super_operations structure for
131 * HFS filesystems. The purpose is to return various data about the
134 * changed f_files/f_ffree to reflect the fs_ablock/free_ablocks.
136 static int hfs_statfs(struct super_block
*sb
, struct statfs
*buf
)
138 struct hfs_mdb
*mdb
= HFS_SB(sb
)->s_mdb
;
140 buf
->f_type
= HFS_SUPER_MAGIC
;
141 buf
->f_bsize
= HFS_SECTOR_SIZE
;
142 buf
->f_blocks
= mdb
->alloc_blksz
* mdb
->fs_ablocks
;
143 buf
->f_bfree
= mdb
->alloc_blksz
* mdb
->free_ablocks
;
144 buf
->f_bavail
= buf
->f_bfree
;
145 buf
->f_files
= mdb
->fs_ablocks
;
146 buf
->f_ffree
= mdb
->free_ablocks
;
147 buf
->f_namelen
= HFS_NAMELEN
;
155 * adapted from linux/fs/msdos/inode.c written 1992,93 by Werner Almesberger
156 * This function is called by hfs_read_super() to parse the mount options.
158 static int parse_options(char *options
, struct hfs_sb_info
*hsb
, int *part
)
160 char *this_char
, *value
;
163 /* initialize the sb with defaults */
164 memset(hsb
, 0, sizeof(*hsb
));
165 hsb
->magic
= HFS_SB_MAGIC
;
166 hsb
->s_uid
= current
->uid
;
167 hsb
->s_gid
= current
->gid
;
168 hsb
->s_umask
= current
->fs
->umask
;
169 hsb
->s_type
= 0x3f3f3f3f; /* == '????' */
170 hsb
->s_creator
= 0x3f3f3f3f; /* == '????' */
171 hsb
->s_lowercase
= 0;
174 /* default version. 0 just selects the defaults */
184 for (this_char
= strtok(options
,","); this_char
;
185 this_char
= strtok(NULL
,",")) {
186 if ((value
= strchr(this_char
,'=')) != NULL
) {
189 /* Numeric-valued options */
190 if (!strcmp(this_char
, "version")) {
191 if (!value
|| !*value
) {
194 hsb
->s_version
= simple_strtoul(value
,&value
,0);
198 } else if (!strcmp(this_char
,"uid")) {
199 if (!value
|| !*value
) {
202 hsb
->s_uid
= simple_strtoul(value
,&value
,0);
206 } else if (!strcmp(this_char
,"gid")) {
207 if (!value
|| !*value
) {
210 hsb
->s_gid
= simple_strtoul(value
,&value
,0);
214 } else if (!strcmp(this_char
,"umask")) {
215 if (!value
|| !*value
) {
218 hsb
->s_umask
= simple_strtoul(value
,&value
,8);
222 } else if (!strcmp(this_char
,"part")) {
223 if (!value
|| !*value
) {
226 *part
= simple_strtoul(value
,&value
,0);
230 /* String-valued options */
231 } else if (!strcmp(this_char
,"type") && value
) {
232 if (strlen(value
) != 4) {
235 hsb
->s_type
= hfs_get_nl(value
);
236 } else if (!strcmp(this_char
,"creator") && value
) {
237 if (strlen(value
) != 4) {
240 hsb
->s_creator
= hfs_get_nl(value
);
241 /* Boolean-valued options */
242 } else if (!strcmp(this_char
,"quiet")) {
247 } else if (!strcmp(this_char
,"afpd")) {
252 /* Multiple choice options */
253 } else if (!strcmp(this_char
,"names") && value
) {
254 if ((*value
&& !value
[1] && strchr("ntal78c",*value
)) ||
255 !strcmp(value
,"netatalk") ||
256 !strcmp(value
,"trivial") ||
257 !strcmp(value
,"alpha") ||
258 !strcmp(value
,"latin") ||
259 !strcmp(value
,"7bit") ||
260 !strcmp(value
,"8bit") ||
261 !strcmp(value
,"cap")) {
266 } else if (!strcmp(this_char
,"fork") && value
) {
267 if ((*value
&& !value
[1] && strchr("nsdc",*value
)) ||
268 !strcmp(value
,"netatalk") ||
269 !strcmp(value
,"single") ||
270 !strcmp(value
,"double") ||
271 !strcmp(value
,"cap")) {
276 } else if (!strcmp(this_char
,"case") && value
) {
277 if ((*value
&& !value
[1] && strchr("la",*value
)) ||
278 !strcmp(value
,"lower") ||
279 !strcmp(value
,"asis")) {
280 hsb
->s_lowercase
= (*value
== 'l');
284 } else if (!strcmp(this_char
,"conv") && value
) {
285 if ((*value
&& !value
[1] && strchr("bta",*value
)) ||
286 !strcmp(value
,"binary") ||
287 !strcmp(value
,"text") ||
288 !strcmp(value
,"auto")) {
289 hsb
->s_conv
= *value
;
299 /* Parse the "fork" and "names" options */
301 fork
= hsb
->s_afpd
? 'n' : 'c';
306 hsb
->s_ifill
= hfs_cap_ifill
;
307 hsb
->s_reserved1
= hfs_cap_reserved1
;
308 hsb
->s_reserved2
= hfs_cap_reserved2
;
312 hfs_warn("hfs_fs: AppleSingle not yet implemented.\n");
317 hsb
->s_ifill
= hfs_dbl_ifill
;
318 hsb
->s_reserved1
= hfs_dbl_reserved1
;
319 hsb
->s_reserved2
= hfs_dbl_reserved2
;
323 hsb
->s_ifill
= hfs_nat_ifill
;
324 hsb
->s_reserved1
= hfs_nat_reserved1
;
325 hsb
->s_reserved2
= hfs_nat_reserved2
;
335 hsb
->s_nameout
= hfs_colon2mac
;
336 hsb
->s_namein
= hfs_mac2nat
;
340 hsb
->s_nameout
= hfs_colon2mac
;
341 hsb
->s_namein
= hfs_mac2cap
;
345 hsb
->s_nameout
= hfs_triv2mac
;
346 hsb
->s_namein
= hfs_mac2triv
;
350 hsb
->s_nameout
= hfs_prcnt2mac
;
351 hsb
->s_namein
= hfs_mac2seven
;
355 hsb
->s_nameout
= hfs_prcnt2mac
;
356 hsb
->s_namein
= hfs_mac2eight
;
360 hsb
->s_nameout
= hfs_latin2mac
;
361 hsb
->s_namein
= hfs_mac2latin
;
364 case 'a': /* 's' and 'd' are unadvertised aliases for 'alpha', */
365 case 's': /* since 'alpha' is the default if fork=s or fork=d. */
366 case 'd': /* (It is also helpful for poor typists!) */
367 hsb
->s_nameout
= hfs_prcnt2mac
;
368 hsb
->s_namein
= hfs_mac2alpha
;
375 /*================ Global functions ================*/
380 * This is the function that is responsible for mounting an HFS
381 * filesystem. It performs all the tasks necessary to get enough data
382 * from the disk to read the root inode. This includes parsing the
383 * mount options, dealing with Macintosh partitions, reading the
384 * superblock and the allocation bitmap blocks, calling
385 * hfs_btree_init() to get the necessary data about the extents and
386 * catalog B-trees and, finally, reading the root inode into memory.
388 struct super_block
*hfs_read_super(struct super_block
*s
, void *data
,
392 struct hfs_cat_key key
;
393 kdev_t dev
= s
->s_dev
;
394 hfs_s32 part_size
, part_start
;
395 struct inode
*root_inode
;
398 if (!parse_options((char *)data
, HFS_SB(s
), &part
)) {
399 hfs_warn("hfs_fs: unable to parse mount options.\n");
403 /* set the device driver to 512-byte blocks */
404 set_blocksize(dev
, HFS_SECTOR_SIZE
);
406 #ifdef CONFIG_MAC_PARTITION
407 /* check to see if we're in a partition */
408 mdb
= hfs_mdb_get(s
, s
->s_flags
& MS_RDONLY
, 0);
410 /* erk. try parsing the partition table ourselves */
412 if (hfs_part_find(s
, part
, silent
, &part_size
, &part_start
)) {
415 mdb
= hfs_mdb_get(s
, s
->s_flags
& MS_RDONLY
, part_start
);
418 if (hfs_part_find(s
, part
, silent
, &part_size
, &part_start
)) {
422 mdb
= hfs_mdb_get(s
, s
->s_flags
& MS_RDONLY
, part_start
);
427 hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n",
433 HFS_SB(s
)->s_mdb
= mdb
;
434 if (HFS_ITYPE(mdb
->next_id
) != 0) {
435 hfs_warn("hfs_fs: too many files.\n");
439 s
->s_magic
= HFS_SUPER_MAGIC
;
440 s
->s_blocksize_bits
= HFS_SECTOR_SIZE_BITS
;
441 s
->s_blocksize
= HFS_SECTOR_SIZE
;
442 s
->s_op
= &hfs_super_operations
;
444 /* try to get the root inode */
445 hfs_cat_build_key(htonl(HFS_POR_CNID
),
446 (struct hfs_name
*)(mdb
->vname
), &key
);
448 root_inode
= hfs_iget(hfs_cat_get(mdb
, &key
), HFS_ITYPE_NORM
, NULL
);
452 s
->s_root
= d_alloc_root(root_inode
);
456 /* fix up pointers. */
457 HFS_I(root_inode
)->entry
->sys_entry
[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM
)] =
459 s
->s_root
->d_op
= &hfs_dentry_operations
;
461 /* everything's okay */
465 hfs_warn("hfs_fs: get root inode failed.\n");
468 hfs_mdb_put(mdb
, s
->s_flags
& MS_RDONLY
);
470 set_blocksize(dev
, BLOCK_SIZE
);
475 static int __init
init_hfs_fs(void)
478 return register_filesystem(&hfs_fs
);
481 static void __exit
exit_hfs_fs(void) {
483 unregister_filesystem(&hfs_fs
);
486 module_init(init_hfs_fs
)
487 module_exit(exit_hfs_fs
)
489 #if defined(DEBUG_ALL) || defined(DEBUG_MEM)
490 long int hfs_alloc
= 0;