]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] HFS rewrite
authorAndrew Morton <akpm@osdl.org>
Thu, 26 Feb 2004 00:17:36 +0000 (16:17 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 26 Feb 2004 00:17:36 +0000 (16:17 -0800)
From: Roman Zippel <zippel@linux-m68k.org>

This is a complete rewrite of the HFS driver, it gets rid of a all the
special conversion options, which belong in user space.  The driver uses now
a btree support very similiar to HFS+, so that both could be merged at some
point.

Thanks to Ethan Benson <erbenson@alaska.net> for a number of patches to make
the driver more compliant with the spec and Christoph Hellwig <hch@lst.de>
for fixing up the documentation.

43 files changed:
Documentation/filesystems/hfs.txt [new file with mode: 0644]
MAINTAINERS
fs/hfs/ChangeLog [deleted file]
fs/hfs/FAQ.txt [deleted file]
fs/hfs/HFS.txt [deleted file]
fs/hfs/INSTALL.txt [deleted file]
fs/hfs/Makefile
fs/hfs/TODO [deleted file]
fs/hfs/balloc.c [deleted file]
fs/hfs/bdelete.c [deleted file]
fs/hfs/bfind.c
fs/hfs/bins_del.c [deleted file]
fs/hfs/binsert.c [deleted file]
fs/hfs/bitmap.c
fs/hfs/bitops.c [deleted file]
fs/hfs/bnode.c
fs/hfs/brec.c
fs/hfs/btree.c
fs/hfs/btree.h [new file with mode: 0644]
fs/hfs/catalog.c
fs/hfs/dir.c
fs/hfs/dir_cap.c [deleted file]
fs/hfs/dir_dbl.c [deleted file]
fs/hfs/dir_nat.c [deleted file]
fs/hfs/extent.c
fs/hfs/file.c [deleted file]
fs/hfs/file_cap.c [deleted file]
fs/hfs/file_hdr.c [deleted file]
fs/hfs/hfs.h
fs/hfs/hfs_btree.h [deleted file]
fs/hfs/hfs_fs.h [new file with mode: 0644]
fs/hfs/inode.c
fs/hfs/mdb.c
fs/hfs/part_tbl.c
fs/hfs/string.c
fs/hfs/super.c
fs/hfs/sysdep.c
fs/hfs/trans.c
fs/hfs/version.c [deleted file]
include/linux/hfs_fs.h [deleted file]
include/linux/hfs_fs_i.h [deleted file]
include/linux/hfs_fs_sb.h [deleted file]
include/linux/hfs_sysdep.h [deleted file]

diff --git a/Documentation/filesystems/hfs.txt b/Documentation/filesystems/hfs.txt
new file mode 100644 (file)
index 0000000..bd0fa77
--- /dev/null
@@ -0,0 +1,83 @@
+
+Macintosh HFS Filesystem for Linux
+==================================
+
+HFS stands for ``Hierarchical File System'' and is the filesystem used
+by the Mac Plus and all later Macintosh models.  Earlier Macintosh
+models used MFS (``Macintosh File System''), which is not supported,
+MacOS 8.1 and newer support a filesystem called HFS+ that's similar to
+HFS but is extended in various areas.  Use the hfsplus filesystem driver
+to access such filesystems from Linux.
+
+
+Mount options
+=============
+
+When mounting an HFS filesystem, the following options are accepted:
+
+  creator=cccc, type=cccc
+       Specifies the creator/type values as shown by the MacOS finder
+       used for creating new files.  Default values: '????'.
+
+  uid=n, gid=n
+       Specifies the user/group that owns all files on the filesystems.
+       Default:  user/group id of the mounting process.
+
+  dir_umask=n, file_umask=n, umask=n
+       Specifies the umask used for all files , all directories or all
+       files and directories.  Defaults to the umask of the mounting process.
+
+  session=n
+       Select the CDROM session to mount as HFS filesystem.  Defaults to
+       leaving that decision to the CDROM driver.  This option will fail
+       with anything but a CDROM as underlying devices.
+
+  part=n
+       Select partition number n from the devices.  Does only makes
+       sense for CDROMS because they can't be partitioned under Linux.
+       For disk devices the generic partition parsing code does this
+       for us.  Defaults to not parsing the partition table at all.
+
+  quiet
+       Ignore invalid mount options instead of complaining.
+
+
+Writing to HFS Filesystems
+==========================
+
+HFS is not a UNIX filesystem, thus it does not have the usual features you'd
+expect:
+
+ o You can't modify the set-uid, set-gid, sticky or executable bits or the uid
+   and gid of files.
+ o You can't create hard- or symlinks, device files, sockets or FIFOs.
+
+HFS does on the other have the concepts of multiple forks per file.  These
+non-standard forks are represented as hidden additional files in the normal
+filesystems namespace which is kind of a cludge and makes the semantics for
+the a little strange:
+
+ o You can't create, delete or rename resource forks of files or the
+   Finder's metadata.
+ o They are however created (with default values), deleted and renamed
+   along with the corresponding data fork or directory.
+ o Copying files to a different filesystem will loose those attributes
+   that are essential for MacOS to work.
+
+
+Creating HFS filesystems
+===================================
+
+The hfsutils package from Robert Leslie contains a program called
+hformat that can be used to create HFS filesystem. See
+<http://www.mars.org/home/rob/proj/hfs/> for details.
+
+
+Credits
+=======
+
+The HFS drivers was written by Paul H. Hargrovea (hargrove@sccm.Stanford.EDU)
+and is now maintained by Roman Zippel (roman@ardistech.com) at Ardis
+Technologies.
+Roman rewrote large parts of the code and brought in btree routines derived
+from Brad Boyer's hfsplus driver (also maintained by Roman now).
index 1ccb1e946719ce7bb5d9115705636b76581b38be..05bd91451706c20b0735e72a138dff03a879e361 100644 (file)
@@ -862,8 +862,8 @@ W:  http://www.nyx.net/~arobinso
 S:     Maintained
 
 HFS FILESYSTEM
-P:     Oliver Neukum
-M:     oliver@neukum.org
+P:     Roman Zippel
+M:     zippel@linux-m68k.org
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
diff --git a/fs/hfs/ChangeLog b/fs/hfs/ChangeLog
deleted file mode 100644 (file)
index 723f223..0000000
+++ /dev/null
@@ -1,2506 +0,0 @@
-2000-01-02  a sun  <asun@asun.cobalt.com>
-
-       * file.c (hfs_get_block): added hfs_get_block for regular files. 
-
-1999-04-12  a sun  <asun@hecate.darksunrising.blah>
-
-       * file_hdr.c (hdr_read): added rootinfo behaviour for DID header.
-
-1999-04-11  a sun  <asun@hecate.darksunrising.blah>
-
-       * super.c (parse_options): added s_version so that we can select
-       between different versions of the same layout.
-
-1999-04-05  a sun  <asun@hecate.darksunrising.blah>
-
-       * linux/hfs_fs.h: unified netatalk and appledouble header format. 
-       added in all of the AFP attribute bits.
-
-       * file_hdr.c: added netatalk appledouble v2 compatible headers. 
-
-1999-01-30  a sun  <asun@hecate.darksunrising.blah>
-
-       * catalog.c (hfs_cat_move): fixed corruption problem with
-       renames.
-
-1999-01-27  a sun  <asun@hecate.darksunrising.blah>
-
-       * file_hdr.c (get/set_dates): got rid of broken afpd times. NOTE:
-       you must use netatalk-1.4b2+asun2.1.2 or newer for this.
-
-1998-12-20  a sun  <asun@hecate.darksunrising.blah>
-
-       * bdelete.c (del_root): assign bthLNode and bthFNode only if the
-       root node becomes a leaf node. Disk First Aid no longer
-       complains. Norton Utilities, of course, has decided that it
-       doesn't like the root node number. bleah. i think that it might be
-       due to Norton Utilities not expecting the root node to have moved.
-
-1998-12-16  a sun  <asun@hecate.darksunrising.blah>
-
-       * sysdep.c (hfs_revalidate_dentry): fix inode dates when there's a
-       timezone change.
-
-1998-12-15  root  <root@hecate.darksunrising.blah>
-
-       * extent.c (new_extent): expand block size variables to handle
-       u32. 
-
-       * mdb.c (hfs_mdb_get): AlBlkSiz shouldn't be capped at 65535. we
-       should be able to handle much larger volumes now.
-
-1998-11-21  a sun  <asun@hecate.darksunrising.blah>
-
-       * hfs_sysdep.h, hfs_fs.h: added hfs_from_utc/to_utc to deal with
-       date differences on hfs formatted media. 
-
-       NOTE: hfs extended keeps everything in utc, so we'll need to deal
-       with that when appropriate.
-
-1998-11-12  a sun  <asun@hecate.darksunrising.blah>
-
-       * extent.c (shrink_fork): added some lock_bitmap/unlock_bitmap's
-       to protect hfs_clear_vbm_bits. we should no longer have problems
-       with free_ablocks wrapping around.
-
-1998-11-02  a sun  <asun@hecate.darksunrising.blah>
-
-       * mdb.c (hfs_mdb_get): plugged up an mdb failed initialization
-       leak.
-
-1998-10-31  a sun  <asun@hecate.darksunrising.blah>
-
-       * version.c (hfs_version): bumped to version 0.96.
-
-       * mdb.c (hfs_mdb_commit): you only write out the alternate MDB
-       when the catalog or extents overflow files grow. that just leaves
-       the btree corruption problems. bleah (whilst deleting a bunch of
-       files, more of the btree can get pruned away than desired).
-
-1998-10-30  a sun  <asun@hecate.darksunrising.blah>
-
-       * dir.c: fixed a bunch of silliness with deletions. make sure to
-       zero out stuff and set mark_inode_dirty().
-       
-1998-10-29  a sun  <asun@hecate.darksunrising.blah>
-
-       * string.c (hfs_strcmp, hfs_streq, hfs_strhash): converted them to
-       take name/len arguments instead of hfs_name to reduce copying.
-
-       * dir.c, dir_nat.c, dir_cap.c, dir_dbl.c, sysdep.c: modified
-       relevant areas to reflect string.c changes.
-       
-1998-10-28  a sun  <asun@hecate.darksunrising.blah>
-
-       * hfs.h (hfs_lookup_dentry): oh my. more silliness. make sure to
-       have the d_lookup use the same hash value as the one generated by
-       hfs_hash_dentry. i also changed the argument order.
-       (hfs_drop_special): change the argument order to be more in line
-       with what the dcache stuff looks like.
-
-       * sysdep.c (hfs_compare_dentry): the compare was returning the
-       wrong value for correct matches and causing all sorts of
-       mischief. this fixes both directory counts and mounting on top of
-       hfs volumes.
-
-       * file.c, file_cap.c, file_hdr.c: added mark_inode_dirty()'s in
-       the relevant places.
-
-1998-10-11  root  <asun@hecate.darksunrising.blah>
-
-       * mdb.c (hfs_mdb_get): moved initialization of mdb->entry_dirty
-       list to here to deal with trying to read a bad hfs volume.
-
-1998-10-10  a sun  <asun@zoology.washington.edu>
-
-       * inode.c, catalog.c, dir_*.c, sysdep.c: parts of the dcache
-       conversion didn't get done properly. specifically, i forgot to
-       move the hfs_cat_puts into the right place. that's fixed now.
-
-1998-09-11  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * mdb.c: altered mdb struct to reflect hfs plus usage.
-
-1998-08-27  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * file.c, file_hdr.c, file_cap.c: dealt with the remaining
-       copy_to/from_user() error cases.
-
-1998-08-26  a sun  <asun@purgatorius.zoology.washington.edu>
-
-       * super.c (hfs_read_super): fixed to deal with cdroms. why doesn't
-       the cdrom layer call the partition table code?
-
-Wed Jan 21 14:04:26 1998  a sun  <asun@zoology.washington.edu>
-
-       * inode.c, sysdep.c
-       use d_iput to uncache dentry from catalog entry instead of relying
-       on put_inode. no more NULL pointer dereferences!
-
-       * catalog.c
-       cleaned up hfs_cat_put a little.
-       
-       ISSUES (non-fatal): mv dir dir2 while creating files in dir screws
-                           up directory counts.
-               
-                           deletion using netatalk screws up directory
-                           counts.
-
-Thu Jan 15 19:14:28 1998  a sun  <asun@zoology.washington.edu>
-
-       * catalog.c
-       make deletion happen when requested instead of waiting until
-       an hfs_cat_put as the dcache can hold onto entries for quite
-       some time.
-
-Wed Jan 14 14:43:16 1998  a sun  <asun@zoology.washington.edu>
-       
-       * catalog.c
-       the current catalog allocation scheme allocates
-       PAGE_SIZE/sizeof(struct hfs_cat_entry) entries at a time and keeps
-       a pool of free entries up to this allocation unit * 8.
-
-       * inode.c
-       make sure to always hfs_cat_put if hfs_iget is going to return
-       NULL.
-
-       * string.c, catalog.c
-       use linux' hashing method to generate hashes. the old hashing was
-       getting collisions. catalog.c also has a larger hash table to
-       prevent collisions.
-       
-Tue Jan 13 13:06:01 1998  a sun  <asun@zoology.washington.edu>
-
-       * version.c
-       bumped to 0.95+asun3
-
-       * catalog.c
-       re-wrote to dynamically allocate/delete catalog entries. on a 486,
-       entries fit into the size-256 slab.
-
-Wed Jan  7 19:33:33 1998  a sun  <asun@zoology.washington.edu>
-
-       * inode.c 
-       don't hfs_cat_put gratuitously in hfs_iget. that's a bad
-       idea and results in screwed up entry counts.
-
-Tue Jan  6 14:38:24 1998  a sun  <asun@zoology.washington.edu>
-
-       * version.c
-       changed it to 0.95+asun2
-
-       * sysdep.c
-       altered catalog entry pruning to make sure that an iput
-       gets done. for some reason, shrink_dcache_parent wasn't
-       doing it.
-
-       * catalog.c
-       added a global dirty list to check for pruning.
-       
-Tue Jan  6 12:29:52 1998  a sun  <asun@zoology.washington.edu>
-
-       * catalog.c
-       re-wrote it to be similar to 2.1.x inode.c. this should
-       at least make catalog.c SMP safe. 
-
-       * hfs.h, linux/hfs_fs.h
-       moved dentry operations into hfs.h. these probably should
-       be moved somewhere else.
-
-       * super.c, dir_cap.c, dir_nat.c, dir_dbl.c, sysdep.c
-       added dentry ops to hash everything to lowercase.
-
-Sun Dec 28 22:48:53 1997  a sun  <asun@zoology.washington.edu>
-
-       * sysdep.c, catalog.c, hfs.h
-       as a temporary workaround until catalog.c gets re-written, 
-       i flush the dcache if we need more entries. 
-       
-Fri Dec 19 15:11:21 1997  a sun  <asun@zoology.washington.edu>
-
-       * dir_dbl.c
-       statically allocate tmp_name instead of doing it dynamically.
-
-       NOTE: well, those pesky hfs_cat_put messages still aren't gone. in
-       addition, catalog.c needs to be modified to free up some entries
-       when the cache gets filled up. 
-
-Sun Dec 14 11:51:11 1997  a sun  <asun@zoology.washington.edu>
-
-       * linux/hfs_fs.h
-       moved the dentry stuff into within the #ifdef __KERNEL__ 
-       part of hfs_fs.h and cleaned up a little.
-
-Sun Dec 14 11:24:54 1997  a sun  <asun@zoology.washington.edu>
-
-       * dir.c
-       changed hfs_rename to delete all old dentries. hfs_cat_put
-       messages on umount should be a thing of the past now.
-
-Sun Dec 14 01:12:58 1997  a sun  <asun@zoology.washington.edu>
-
-       * dir.c
-       changed mark_inodes_deleted to dget/d_delete/dput the dentry
-       instead of just dropping it. the bytes available should now
-       be updated properly upon deletion.
-
-Wed Dec 10 00:01:25 1997  a sun  <asun@zoology.washington.edu>
-
-       * dir.c
-       changed mark_inodes_deleted to drop the dentry instead of 
-       just deleting it. 
-
-       TODO: bytes available aren't being properly updated when a
-       resource fork gets deleted.
-
-Mon Dec  8 23:22:40 1997  a sun  <asun@zoology.washington.edu>
-
-       * dir_cap.c, dir_nat.c, dir_dbl.c, dir.c
-       * hfs.h, linux/hfs_sysdep.h, linux/hfs_fs_i.h
-       Added code to drop ({dbl,cap,nat}_drop_dentry) invalid
-       dentries when creating or moving a file.
-
-       * inode.c
-       Added code to delete cached dentries when a file gets deleted.
-
-       * current yuckiness: there's an extra hfs_cat_put somewhere. it's
-       harmless but bothersome.
-       
-Thu Dec  4 00:14:03 1997  a sun  <asun@zoology.washington.edu>
-
-       * dir.c, dir_cap.c, dir_nat.c, file.c, file_hdr.c, inode.c,
-       * linux/{hfs_sysdep.h, hfs_fs.h}, version.c:
-       Completed first code dentrification sweep. It mounts! It copies!
-       It dcaches! 
-
-Mon Apr 28 06:58:44 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, INSTALL.sgml, HFS.sgml:
-       Bump version to 0.95 (Woohoo! We're beta!)
-
-       * linux/hfs_fs.h:
-       Modify HFS_SB() and HFS_I() when compiled into the kernel.
-
-       * FAQ.sgml:
-       Add a new question (and its answer):
-       Why does my Macintosh show generic application and document icons?
-
-       * HFS.sgml:
-       Add some URLs and remove the (now empty) FAQ section.
-
-Sun Apr 27 22:17:01 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * HFS.sgml:
-       Don't call the version 1 headers "slightly modified".
-
-       * file_hdr.c, dir_nat.c:
-       Comment some AFPD compatibility stuff.
-
-       * FAQ.sgml:
-       Update for version 0.95.
-
-       * BUG_INFO:
-       Remove the BIG_INFO script since we no longer mention it.
-
-       * README.sgml, INSTALL.sgml, HFS.sgml, Makefile:
-       Split README.sgml into HFS.sgml and INSTALL.sgml.
-       Stop including the document sources in snapshots.
-
-       * file_hdr.c:
-       Fix hdr_truncate() not to truncate the data fork.
-
-Wed Apr 16 23:56:25 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * FAQ.sgml:
-       Bump version to 0.8.4 and add two answers:
-               How to fsck an HFS filesystem.
-               How to generate linux/version.h.
-
-       * version.c, README.sgml:
-       Bump version to 0.8.4.
-
-       * README.sgml, FAQ.sgml, Makefile:
-       Separate the FAQ from the README.
-
-       * linux/hfs_fs.h:
-       Add (struct hfs_fork) to the forward declarations.
-
-Thu Apr 10 05:47:16 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * linux/hfs_sysdep.h:
-       Work around the non-const declaration of test_bit()'s second argument.
-
-       * Makefile:
-       Use .config from the kernel source to check for MODVERSIONS.
-
-Wed Apr  9 07:57:17 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * bnode.c:
-       Check the record table in each bnode as we read it from disk.
-
-       * super.c, mdb.c, hfs.h:
-       Deal with the ATTRIB_CLEAN bit of the MDB properly (in mdb.c).
-
-       * super.c, hfs.h, mdb.c:
-       Search for the alt-MDB rather than using the device size to find it.
-
-Wed Apr  9 03:39:05 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Bump version to 0.8.3.
-
-Mon Apr  7 20:09:56 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * part_tbl.c:
-       Fix to allow bootable CDROMs (which have blocksize != 512) to mount.
-
-       * super.c:
-       Check that blk_size[MAJOR(dev)] is non-NULL before dereferencing.
-
-Sat Apr  5 10:44:42 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_btree.h, binsert.c, brec.c, bfind.c, bins_del.c, bdelete.c:
-       Make btree operations less likely to do
-       nasty things if the tree is corrupted.
-
-       * part_tbl.c, README.sgml:
-       Count partitions from 0 rather than from 1.
-
-Wed Apr  2 23:26:51 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * bdelete.c:
-       Don't bother checking for oversized keys in hfs_bdelete().
-
-       * bdelete.c, bfind.c, binsert.c:
-       Verify key lengths against the maximum given for the tree.
-
-       * Makefile:
-       Check that /usr/include/linux/modversions.h exists before including it.
-       This allows compilation without CONFIG_MODVERSIONS enabled.
-
-Sat Mar 29 13:17:53 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * linux/hfs_fs.h, super.c, file_hdr.c, hfs.h, extent.c, file_cap.c,
-         dir_dbl.c, dir_nat.c, dir.c, dir_cap.c, binsert.c, catalog.c,
-         bfind.c:
-       Make (struct hfs_bkey) and (struct hfs_brec) more "abstract".
-
-       * binsert.c:
-       Remove redundant test in hfs_binsert().
-
-Sat Mar 29 05:24:23 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Fix formatting problems in README.sgml and bump version to 0.8.2.
-
-       * extent.c:
-       Fix bug that caused serious headaches with fragmented files.
-
-Fri Mar 28 00:23:18 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Bump version to 0.8.1.
-
-       * btree.c, balloc.c:
-       Commit map nodes to buffers when new map nodes are added.
-
-Thu Mar 27 22:41:07 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * Makefile:
-       Include linux/modversions.h from the gcc command line.
-
-       * mdb.c:
-       Was updating modified date twice in hfs_mdb_commit().
-
-       * linux/hfs_sysdep.h, linux/hfs_fs.h, linux/hfs_fs_i.h,
-         linux/hfs_fs_sb.h, sysdep.c, trans.c, super.c, hfs_sysdep.h, inode.c,
-         hfs_fs_i.h, hfs_fs_sb.h, hfs_fs.h, hfs.h, file_cap.c, file_hdr.c,
-         file.c, dir_nat.c, dir_cap.c, dir_dbl.c, Makefile, dir.c:
-       Rearrange headers in preparation for inclusion in the kernel.
-
-       * hfs_fs_sb.h, hfs_fs.h:
-       Add forward declarations so other code can include these headers.
-
-       * hfs_sysdep.h:
-       Include __constant_hton[ls]() for little-endian machines.
-
-       * hfs_fs.h, hfs_sysdep.h, hfs.h:
-       Move typedefs of hfs_{byte,word,lword}_t from hfs.h to hfs_sysdep.h.
-       Include hfs_sysdep.h from hfs_fs.h.
-
-       * trans.c, super.c, part_tbl.c, string.c, inode.c, mdb.c, hfs_fs_sb.h,
-         hfs_sysdep.h, hfs_fs.h, hfs.h, hfs_btree.h, file_cap.c, file_hdr.c,
-         file.c, dir_nat.c, extent.c, dir_dbl.c, dir.c, dir_cap.c, catalog.c,
-         btree.c, bnode.c, brec.c, bitmap.c, bitops.c, bins_del.c, binsert.c,
-         bdelete.c, bfind.c, balloc.c:
-       Big type system changes in preparation for kernel inclusion:
-       '[US](8|16|32)' -> 'hfs_[us](8|16|32)' (avoids name space pollution)
-       'hfs_name_t' -> 'struct hfs_name' (allows forward declaration)
-
-       * super.c, hfs_fs.h:
-       Add init_hfs_fs() to super.c for non-module compilation.
-
-Wed Mar 26 07:53:59 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Bump version to 0.8.
-
-       * README.sgml:
-       Special compilation note for DEC Alpha.
-
-       * README.sgml:
-       Note status on non-Intel processors.
-
-       * hfs_fs.h:
-       Use long's for read() and write() on the Alpha.
-
-       * README.sgml:
-       Document the afpd mount option.
-
-       * inode.c:
-       Make files always writable for owner in afpd mode.
-
-Tue Mar 25 23:21:39 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * part_tbl.c:
-       Clean up the error checking code a bit.
-
-Sat Mar 22 19:43:40 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * part_tbl.c:
-       Fixed uninitialized variable in old-style partition code.
-
-       * bins_del.c, bdelete.c:
-       Fix extraneous "bad argument to shift_{left,right}" messages.
-
-       * bitops.c:
-       Note that these routines are now tested on Intel, PPC and Alpha.
-
-       * Makefile:
-       Add -fno-builtin to the CFLAGS.
-
-Fri Feb 14 10:50:14 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_sysdep.h:
-       Don't include <asm/*.h> until after <linux/types.h>.
-
-       * catalog.c:
-       Use volume create date in hashfn() rather than casting pointer to int.
-
-       * hfs.h, mdb.c:
-       Maintaing volume create, modify and backup dates in struct hfs_mdb.
-
-       * hfs_fs.h:
-       Include the header for put_user BEFORE using it!
-
-       * string.c, hfs.h:
-       Make hfs_strhash() return an unsigned int.
-
-       * trans.c, version.c, super.c, mdb.c, part_tbl.c, string.c, inode.c,
-         hfs_sysdep.h, hfs_fs.h, hfs_fs_sb.h, hfs_btree.h, hfs.h, file_cap.c,
-         file_hdr.c, extent.c, dir_dbl.c, dir_nat.c, dir_cap.c, dir.c,
-         catalog.c, btree.c, bnode.c, brec.c, bitmap.c, binsert.c,
-         bins_del.c, bdelete.c, balloc.c, README.sgml, Makefile:
-       Updated copyright notices.
-
-       * trans.c, part_tbl.c, string.c, super.c, inode.c, mdb.c, hfs_fs.h,
-         hfs_fs_sb.h, hfs_sysdep.h, hfs_btree.h, hfs.h, file_cap.c,
-         file_hdr.c, dir_nat.c, extent.c, dir_cap.c, dir_dbl.c, catalog.c,
-         dir.c, brec.c, btree.c, bitmap.c, bnode.c, bdelete.c, bins_del.c,
-         binsert.c, Makefile, TODO, balloc.c:
-       First shot at portability to the DEC Alpha and non-gcc compilers.
-       This involved a significant overhaul of the type system.
-
-Tue Feb  4 04:26:54 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Bump version to "pre-0.8-4".
-
-       * dir_nat.c:
-       Allow creat() in Netatalk .AppleDouble directories.
-
-       * dir_dbl.c:
-       Make local functions static.
-
-       * dir_dbl.c:
-       Removed unnecessary 'extern' qualifiers from forward declarations.
-
-       * file_hdr.c, TODO:
-       Fixed the 30-year time warp with afpd.
-
-       * TODO, trans.c:
-       Don't mangle the name .AppleDesktop under fork=netatalk.
-
-Mon Feb  3 23:18:45 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * inode.c:
-       Make header files always writable when the afpd mount option is given.
-       Otherwise it is impossible to unlock a locked file.
-
-       * TODO, inode.c:
-       Let afpd think chmod() always succeeds, so "New Folder" works right.
-
-       * super.c:
-       The 'afpd' mount option now makes 'fork=n,names=n' the default.
-
-       * TODO:
-       List the current known afpd-compatibility problems as bugs.
-
-       * file_hdr.c:
-       Make certain date changes through header files get written to disk.
-
-Sat Feb  1 02:24:12 1997  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * mdb.c:
-       Work around for Linux rounding device sizes to 1k increments.
-
-       * README.sgml:
-       Fixed a typo: "the a".
-
-Sat Dec 28 20:41:01 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * TODO:
-       Add ioctl() interface as a "missing feature."
-
-       * dir_nat.c:
-       Finish implementing the afpd-compatibility
-       mode using the new 'afpd' mount option.
-
-       * hfs_fs_sb.h, super.c:
-       Add new 'afpd' mount option.
-
-       * file_cap.c:
-       Spelling fix.
-
-Wed Dec 11 23:16:08 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * TODO, README.sgml:
-       Optimistically document the hybrid CD problem as fixed.
-
-       * part_tbl.c:
-       Fix the partition code so at least some of the hybrid
-       CDROMs that were previously rejected are now accepted.
-
-       * hfs.h:
-       Make fs_start a 32-bit integer rather than 16-bits.
-       The 16-bit value would overflow if a partition started
-       beyond the 32M mark (e.g. the Executor 2 Beta 1 CDROM).
-
-       * extent.c:
-       Fixed a typo in an error message.
-
-Tue Dec 10 14:43:46 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * dir_nat.c:
-       Merge in the (still dormant) afpd-compatibility changes.
-
-       * inode.c:
-       Make the .AppleDouble directory writable (again).
-
-       * version.c, README.sgml:
-       Bump version up to "pre-0.8-3".
-
-       * hfs_fs.h, file_cap.c, file_hdr.c:
-       Move AFP constants to hfs_fs.h and prefix them with "HFS_".
-
-       * dir_nat.c, inode.c:
-       Back-out changes that allowed writing to the .AppleDouble directory.
-
-       * Makefile:
-       Update rules for linuxdoc-sgml v1.5.
-
-       * extent.c:
-       Fixed serious bug in decode_extent() with handling of empty extents.
-
-       * file.c:
-       Rewrote hfs_getblk().
-       It will no longer hang if hfs_extent_map() is buggy.
-       Also halves the worst-case number of calls to hfs_extent_map().
-
-       * extent.c:
-       Fixed serious bug in decode_extent() with handling of empty extents.
-
-       * hfs_fs.h:
-       Small change so the PPC (and maybe other architectures?)
-       pick up the prototypes for the user-space access functions.
-
-       * super.c, file_cap.c, file_hdr.c, hfs_fs.h, file.c:
-       Updated for new user-space memory interface.
-
-Sun Dec  8 11:49:36 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * dir_nat.c:
-       Add special code for unlink(), and rename() in the .AppleDouble
-       directory and rmdir() of the .AppleDouble directory.
-
-       * inode.c:
-       Make the .AppleDouble directory writable.
-
-       * file_hdr.c:
-       Use AFP flags in version 1 headers (for Netatalk compatibility).
-
-       * trans.c:
-       Fixed bug with long names causing kernel Oops.
-
-Mon Oct  7 06:05:01 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_fs.h, file_cap.c, file_hdr.c, hfs.h, extent.c, file.c, dir.c:
-       Fix types for various read/write/truncate computations.
-       Also allows compilation with 2.1.x kernels.
-
-Thu Sep 19 10:28:43 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * README.sgml, version.c:
-       Bump version up to "pre-0.8-2".
-
-       * TODO:
-       Reformat the To Do list introducing prioritized categories.
-
-       * file_hdr.c, file.c:
-       Move comments about mmap() for headers from file.c to file_hdr.c.
-       Also revise the reasoning for not yet having it implemented.
-
-       * dir_nat.c, dir_cap.c, dir_dbl.c:
-       Remove 'hfs_' prefix from names of some purely local functions.
-
-       * dir_dbl.c, TODO:
-       Under AppleDouble make create(), mkdir(), mknod(), unlink(), rename()
-       and rename() check against header files when arguments start with '%'.
-
-       * super.c, hfs_fs_sb.h, hfs_fs.h, dir_dbl.c, dir_nat.c, dir_cap.c,
-         dir.c, README.sgml:
-       Fix problem that prevented creating %RootInfo or .rootinfo in all
-       directories in addition to preventing deletion from the root directory.
-
-       * TODO:
-       Remove writable header files from the To Do list.
-
-       * README.sgml:
-       Add extensive discussion of writing to HFS filesystems and
-       the format of the special files.
-
-       * file_hdr.c:
-       Generate the 'homefs' field for version 1 header files.
-
-Wed Sep 18 23:07:45 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_fs.h, file_cap.c:
-       Comment the definition of (struct hfs_cap_info).
-
-       * version.c, README.sgml:
-       Bump version up to "pre-0.8-1" and update the "How can I write?" FAQ.
-
-       * file_hdr.c:
-       Implement hdr_write() and hdr_truncate()!!
-
-       * hfs_fs_i.h, inode.c:
-       Make hdr_layout per-inode (not per-file) so hdr_truncate() will work.
-
-       * file.c, hfs.h, catalog.c, extent.c, balloc.c:
-       hfs_extent_adj() now uses fork->lsize to determine the target file size.
-
-Sun Sep 15 07:55:24 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * README.sgml, trans.c:
-       Prevent creation of files & directories with '\0' or ':' in their names.
-
-       * string.c, hfs_fs.h, hfs.h, dir_dbl.c, dir_nat.c, dir_cap.c:
-       With case=lower could have run off end of string.
-
-Tue Sep 10 12:05:47 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * inode.c:
-       Small clean up of HFS_FIL_LOCK handling.
-
-       * inode.c:
-       Fix notify_change() not to accidentally make metadata executable.
-
-       * hfs_fs.h:
-       AppleSingle files should have HFS_ITYPE_NORM.
-
-       * inode.c:
-       Return to old behavior where MdDat = i_mtime.
-
-       * dir_dbl.c:
-       Fix serious bug in hfs_dbl_readdir() that would lock-up access to a
-       directory if one tried to write to a directory they had previously read.
-
-       * file.c:
-       Fix hfs_do_write() to adjust the fork's 'lsize' if it changed.
-
-       * inode.c, file_cap.c:
-       Allow truncate() to be called even on metadata.
-       Any size changes will last only until the next iput() of the inode.
-       Truncating a header file doesn't yet truncate the resource fork.
-
-       * inode.c:
-       Allow chmod() on a directory if it doesn't actually change i_mode.
-
-       * hfs_fs.h, trans.c, super.c:
-       Rename hfs_cap2mac() to hfs_colon2mac().
-       Rename hfs_apl2mac() to hfs_prcnt2mac().
-
-       * file_hdr.c:
-       Move header construction out of hdr_read() to create hdr_build_meta().
-
-       * hfs.h:
-       Add byte-order independent conversions: U32->U16, U32->U8 and U16->U8.
-
-       * file.c, file_cap.c, hfs_fs.h:
-       Rename fix_perms() to hfs_file_fix_mode() and
-       move it from file_cap.c to file.c.
-
-       * README.sgml, super.c:
-       Make the default for the names mount option vary with the fork option.
-
-       * file_cap.c:
-       The umask was applied incorrectly in fix_perms().
-
-Mon Sep  9 13:11:28 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * README.sgml:
-       Note that it compiles on m68k machines, but needs more testing.
-
-       * hfs_sysdep.h, Makefile:
-       Changes to compile unmodified on m68k (and possibly other machines).
-
-       * dir_cap.c:
-       hfs_cap_readdir() was mistakenly producing .rootinfo entries for
-       the .finderinfo and .resource subdirectories of the root directory.
-
-       * inode.c:
-       A directory's i_size was too small by 1 under CAP, so hfs_cap_readdir()
-       would omit the last directory entry.  i_nlink was also too large by 1.
-
-Sun Sep  8 12:56:06 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * file_hdr.c:
-       Rewrite hdr_read() to be more efficient and to deal correctly with
-       descriptors having lengths that differ from the actual size of the data.
-
-       * file_cap.c:
-       Add write support for CAP finderinfo files!!
-
-       * super.c, inode.c, hfs_fs.h, hfs_fs_i.h, hfs_fs_sb.h, file_dbl.c,
-         file_nat.c, file_hdr.c, file.c, file_cap.c, Makefile, dir.c:
-       Generate metadata (header files and CAP finderinfo files) on-the-fly.
-       The files file_{dbl,nat}.c are merged into file_hdr.c as a result.
-
-Sat Sep  7 08:09:24 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * README.sgml:
-       Fix silly grammatical error.
-
-Fri Sep  6 09:17:12 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_fs_sb.h, super.c:
-       No need to cast type of s_reserved.
-
-       * file_dbl.c, file_nat.c, dir_dbl.c, dir_nat.c, file_cap.c, dir_cap.c:
-       Add the missing NULL readpage and writepage entries to the inode_ops.
-
-       * file_dbl.c, file_nat.c, file.c, file_cap.c:
-       Cleanup error checking for read() and write().
-
-Thu Sep  5 05:29:53 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Bump version up to "0.7.2".
-       User-visible changes from 0.7.0:
-       + Corrected CAP finderinfo file format.
-       + Support for more features of CAP finderinfo files.
-       + No longer requires gcc 2.7.0 or newer.
-       + Now implements mknod() system call.
-
-       * hfs_fs.h, dir_nat.c, file_cap.c, file_nat.c, README.sgml, dir_cap.c:
-       Include the CAP and Netatalk copyright notices.
-
-       * hfs_fs.h, file_cap.c:
-       Repair and improve CAP support.
-
-       * catalog.c:
-       Oops! The BkDat for new files and directories was in 1972 when
-       it should have been in 1904 (not that it matters that much).
-
-       * inode.c:
-       The HFS MdDat should be the larger of the i_mtime and i_ctime.
-
-       * README.sgml:
-       Change 'm_time' to 'i_mtime'.
-
-Wed Sep  4 13:27:35 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Bump version up to "0.7.1".
-       User-visible changes from 0.7.0:
-       + Minor bug in CAP finderinfo file format fixed.
-       + No longer requires gcc 2.7.0 or newer.
-       + Now implements mknod() system call.
-
-       * README.sgml:
-       Removed note about needing gcc 2.7.0 or newer.
-
-       * file.c:
-       Optimize hfs_do_read() based on the fact that HFS has no holes in files.
-       Minor code formatting changes.
-
-       * hfs.h, hfs_sysdep.h, mdb.c, extent.c, file.c, btree.c, catalog.c,
-         balloc.c, bnode.c:
-       Reorganize memory management routines.
-       hfs_malloc() and hfs_free() are the main routines.
-       The macros FREE() and MALLOC() are gone.
-       HFS_NEW() and HFS_DELETE() are new 'shorthand' macros.
-
-       * btree.c:
-       Fix broken debugging code.
-
-       * super.c, hfs.h, mdb.c, part_tbl.c, Makefile:
-       Separate partition table handling into its own file.
-
-       * dir.c:
-       Spelling fixes.
-
-       * sysdep.c:
-       Oops!  Error check got sense reversed while editing.
-
-       * mdb.c, sysdep.c, hfs.h, hfs_btree.h, hfs_sysdep.h, btree.c, extent.c,
-         bfind.c, bnode.c, balloc.c:
-       Make hfs_buffer a pointer to a buffer_head, rather than a buffer_head.
-
-       * hfs_fs.h, dir_cap.c, dir_dbl.c, dir_nat.c, dir.c:
-       Add a mknod() entry to the inode_operations for normal directories.
-       All it is good for is letting root create regular files.
-
-       * file_dbl.c, file_nat.c, file.c, file_cap.c, dir_cap.c, dir_dbl.c,
-         dir_nat.c:
-       Add the missing NULL entries to the end of the file_operations.
-
-       * super.c, hfs_btree.h, hfs_fs.h, mdb.c, extent.c, hfs.h, catalog.c:
-       Make the remainder of the (untested) changes
-       to allow compilation with gcc 2.6.3.
-
-       * hfs_fs.h:
-       Fix hfs_fs.h to work with gcc 2.6.3.
-
-       * hfs_fs.h:
-       (struct hfs_cap_info) should never have been 'packed'.
-
-       * BUG_INFO:
-       Use -V for getting version of module utilities.
-
-       * super.c, sysdep.c, trans.c, hfs_fs_sb.h, inode.c, hfs_fs.h,
-         hfs_fs_i.h, file_cap.c, file_dbl.c, file_nat.c, dir_dbl.c,
-         dir_nat.c, file.c, dir.c, dir_cap.c:
-       Fix up hfs_fs{,_i,_sb}.h in preparation for inclusion in kernel.
-
-Tue Sep  3 23:58:03 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs.h:
-       Change eventual destination to linux/fs/hfs rather than include/linux.
-
-       * super.c, inode.c, mdb.c, hfs_btree.h, hfs_fs.h, hfs_sysdep.h,
-         file_dbl.c, file_nat.c, hfs.h, dir_nat.c, extent.c, dir_dbl.c,
-         catalog.c, dir_cap.c, brec.c, btree.c, binsert.c, bnode.c, bdelete.c,
-         bfind.c, bins_del.c, balloc.c:
-       Replace all the swap{16,32}() stuff w/ ntohl() and friends.
-
-Fri Aug 30 09:51:23 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Rewrite installation instructions and bump version up to "0.7.0".
-
-       * Makefile:
-       Remove the INCDIR variable; we now rely on the
-       user to have the correct links in /usr/include.
-
-Mon Aug 26 12:25:41 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Reformat the documentation and bump version up to "pre-0.7-9".
-       Hopefully this will become version 0.7 in a few days.
-
-Thu Aug 22 08:00:44 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * README.sgml, version.c:
-       Bump version up to "pre-0.7-8".
-
-       * file_nat.c, file_dbl.c:
-       AppleDouble headers had resource fork size in wrong byte order.
-
-Wed Aug 21 05:22:28 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Bump version up to "pre-0.7-7".
-
-       * bnode.c:
-       Fixed a long-standing bug in hfs_bnode_lock().
-       This bug occasionally caused lock-up under heavy load.
-
-Tue Aug 20 09:15:10 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * README.sgml, version.c:
-       Bump version up to "pre-0.7-6".
-
-       * catalog.c:
-       Fix a deadlock problem in catalog readers/writers locking.
-
-       * bins_del.c:
-       hfs_bnode_update_key() was still corrupting the header node sometimes.
-
-       * catalog.c, dir.c:
-       Fix problem with extending the catalog B-tree hanging hfs_cat_commit().
-       Fix a race that could delete a non-empty directory.
-
-Sun Aug 18 23:16:43 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Bump version to "pre-0.7-5" for test release.
-
-       * dir_cap.c, README.sgml:
-       Change ".:rootinfo:" to ".rootinfo".
-
-       * hfs_fs.h, dir_cap.c, dir_dbl.c, dir_nat.c:
-       Mangle the names as first step in hfs_{cap,dbl,nat}_lookup().
-       Use the new hfs_streq() to catch mixed case matches to the special
-       files and directories in hfs_{cap,dbl,nat}_lookup().
-       Store reserved names only once.
-
-       * dir.c, hfs.h, string.c:
-       Implement hfs_streq() which tests for string equality more
-       rapidly than hfs_strcmp() by checking for equal length first,
-       and use it when checking for reserved names.
-
-       * inode.c, TODO, dir_cap.c, dir_dbl.c, README.sgml:
-       Provide the metadata for the root directory for the CAP and AppleDouble
-       schemes in the files ".:rootinfo:" and "%RootInfo", respectively.
-
-       * TODO, super.c:
-       Add (untested) support for the old Mac Plus style of partition map.
-
-       * bdelete.c, TODO:
-       Note the possibility of bdelete() to hanging on a corrupted B-tree.
-
-       * TODO:
-       Add items corresponding to some of the 'XXX' comments in the sources.
-
-       * dir_dbl.c, dir_cap.c:
-       Update comments, removing ref. to a comment that once existed in inode.c
-
-       * catalog.c:
-       Remove some redundant locking and error checks
-       that had been previously marked as questionable.
-
-Sat Aug 17 08:06:56 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * binsert.c, bfind.c, bins_del.c, balloc.c, bdelete.c:
-       Edited some comments for correctness.
-
-       * README.sgml, version.c:
-       Bump version up to "pre-0.7-4" in preparation for snapshot release.
-
-       * Makefile:
-       Have 'make dep' delete the *.o and *.s files.
-
-       * catalog.c, hfs.h, TODO, bfind.c:
-       Move looping from hfs_cat_next() into hfs_bsucc(),
-       where it can be done an entire node at a time.
-
-Fri Aug 16 05:02:59 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * TODO:
-       Add AppleShare support to the list of goals.
-
-       * trans.c, super.c, hfs_fs.h, README.sgml:
-       Add a "names=netatalk" mount option, since
-       Netatalk quotes initial periods and CAP doesn't.
-
-       * Makefile:
-       Oops! Had removed the 'include .depend' from Makefile.
-
-       * inode.c, hfs_fs.h, file_nat.c, file_dbl.c, file.c, dir_nat.c,
-         dir_dbl.c, dir_cap.c, dir.c, README.sgml:
-       Update for 2.0.1 and newer kernels.
-
-       * Makefile:
-       Get rid of ifeq stuff and use a .tmpdepend file to make sure
-       a failed 'make depend' doesn't allow a 'make hfs.o'.
-
-Wed Aug 14 01:03:01 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Bump version up to "pre-0.7-3" in preparation for snapshot release.
-
-       * btree.c, extent.c, bnode.c:
-       Fix up some debugging code.
-
-Tue Aug 13 12:42:12 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * version.c, README.sgml:
-       Bump revision to "pre-0.7-2".
-
-       * super.c, sysdep.c, mdb.c, file_nat.c, inode.c, file_cap.c,
-         file_dbl.c, file.c, extent.c, dir.c, catalog.c, btree.c, bnode.c,
-         balloc.c:
-       Added the remaining missing function comments.
-
-       * Makefile, README.sgml:
-       Simplify the default make rule to build the dependency file AND hfs.o.
-       Change the installation instructions to reflect the change.
-
-       * hfs.h:
-       Added missing structure comments.
-
-       * bdelete.c:
-       Merge bdelete_brec() back into hfs_bdelete().
-       Add missing function comments.
-
-
-       * extent.c:
-       Insignificant code change removing an unneeded indirection.
-
-       * btree.c, hfs_btree.h, balloc.c, bnode.c:
-       Add a 'sys_mdb' field to (struct hfs_btree).
-
-       * extent.c, hfs_sysdep.h, sysdep.c, bnode.c, balloc.c, bfind.c,
-         Makefile:
-       Move hfs_buffer_read() from hfs_sysdep.h to sysdep.c so it can use
-       the symbol HFS_SECTOR_SIZE rather than the manifest constant 512.
-       Have hfs_buffer_read() print an error message,
-       and remove redundant errors from the callers.
-
-       * hfs_sysdep.h, mdb.c, super.c, file.c, hfs.h, hfs_btree.h, catalog.c,
-         extent.c, btree.c, balloc.c, bfind.c, bnode.c:
-       Get rid of the type hfs_device and the fields of that type,
-       using the type hfs_sysmdb and the 'sys_mdb' field in its place.
-
-       * Makefile:
-       Fix definition of HDRS variable.
-
-       * README.sgml, version.c:
-       Bump version up to "pre-0.7-1".
-
-       * Makefile:
-       Separate sources and headers into three groups:
-       B-tree code, HFS code and Linux code.
-
-       * bitmap.c, bitops.c, hfs.h, hfs_sysdep.h, balloc.c:
-       Implemented portable set of bit operations in hfs_sysdep.h
-
-       * mdb.c, hfs_sysdep.h, hfs_btree.h, extent.c, btree.c, bitmap.c,
-         bnode.c, balloc.c:
-       Implement a portable set of buffer operations in hfs_sysdep.h
-
-       * TODO:
-       Remove note about separating header files into two parts.
-
-       * catalog.c:
-       Remove call to hfs_mdb_dirty(), since the hfs_brec_relse() does it.
-
-       * hfs.h, extent.c, file.c:
-       Move hfs_getblk() from extent.c to file.c, since that is now the
-       only file that actually uses it.
-
-       * balloc.c:
-       Replace use of hfs_getblk() in balloc.c with a local function
-       (get_new_node()) that doesn't retry, since B-trees can't shrink.
-
-       * hfs.h, hfs_btree.h, hfs_sysdep.h, mdb.c, extent.c:
-       Make hfs_buffer a typedef.
-
-       * inode.c, hfs.h, hfs_sysdep.h, dir.c:
-       Change hfs_sysentry to a typedef.
-       Rename 'sysentry' field of (struct hfs_cat_entry) to 'sys_entry'.
-
-       * super.c, mdb.c, catalog.c:
-       Rename hfs_cat_sync() to hfs_cat_commit() and call it
-       from hfs_mdb_commit() rather than from hfs_write_super().
-
-       * catalog.c, file.c:
-       Minimize the calls to hfs_mdb_dirty().   Now called when:
-       1) A buffer holding a volume bitmap block is dirtied.
-       2) A dirty B-tree node is written back to the buffers.
-       3) A dirty catalog entry is written back to the buffers.
-
-       * hfs_sysdep.h, hfs.h:
-       Make hfs_sysmdb a typedef.
-
-Sun Aug 11 08:46:10 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_sysdep.h, extent.c, hfs.h:
-       Replace hfs_mdb_{lock,unlock} with more portable
-       scheme using a wait queue in the MDB.
-
-       * hfs.h, hfs_btree.h, hfs_sysdep.h, bnode.c, catalog.c, binsert.c:
-       Make hfs_wait_queue a typedef'd pointer to a (struct wait_queue).
-       Rename hfs_wait_on() to hfs_sleep_on().
-
-       * catalog.c, hfs_sysdep.h, super.c, bfind.c, bnode.c, balloc.c:
-       Implemented hfs_dev_name() in hfs_sysdep.h
-       as a portable call to produce a device name.
-
-       * super.c, hfs.h, mdb.c:
-       Rename hfs_mdb_read() to hfs_mdb_get(), and don't take a
-       'sys_mdb' argument.  That's the callers responsibility.
-
-       * sysdep.c, Makefile:
-       Remove the pointless file sysdep.c
-
-       * README.sgml:
-       Clean up the "System Requirements" section.
-
-Sat Aug 10 22:41:24 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * sysdep.h, sysdep.c, super.c, hfs_sysdep.h, mdb.c, string.c,
-         hfs_fs.h, hfs_fs_i.h, hfs_fs_sb.h, hfs_btree_private.h, hfs_btree.h,
-         file_cap.c, file_dbl.c, file_nat.c, hfs.h, file.c, dir_nat.c,
-         extent.c, dir.c, dir_cap.c, dir_dbl.c, catalog.c, bnode.c, brec.c,
-         btree.c, binsert.c, bitmap.c, bitops.c, bfind.c, bins_del.c,
-         Makefile, balloc.c, bdelete.c:
-       Includes the hfs.h that was missing from the previous check in.
-       MAJOR include-file cleanup:
-               hfs_btree.h merged into hfs.h
-               hfs_btree_private.h renamed hfs_btree.h
-               sysdep.h renamed hfs_sysdep.h
-       Fixed some minor portability fixes shown up by the header split.
-
-       * README.sgml:
-       Add instructions for a dealing with a missing linux/version.h
-
-       * hfs_fs.h, mdb.c, string.c, catalog.c, extent.c, btree.c, bitmap.c,
-         bitops.c, bnode.c, brec.c, bins_del.c, binsert.c, bdelete.c, bfind.c,
-         balloc.c:
-       Major split of hfs_fs.h into Linux-specific
-       part (hfs_fs.h) and HFS-specific part (hfs.h).
-
-       * file.c, extent.c:
-       Move hfs_getblk() from file.c to extent.c
-
-       * sysdep.h, super.c, mdb.c, hfs_fs_sb.h, hfs_fs.h, file.c, extent.c,
-         catalog.c, bnode.c, bitmap.c:
-       Make the field 's_mdb' in (struct hfs_sb_info) a pointer to
-       the MDB, rather than the actual MDB.  This allowed the definition
-       of (struct hfs_mdb) to be moved from hfs_fs_sb.h to hfs_fs.h.
-
-       * ccache.c, hfs_fs.h, Makefile, catalog.c:
-       Merged ccache.c and catalog.c into the latter.
-       Moved definition of (struct hfs_cat_rec) into catalog.c
-
-       * extent.c:
-       Oops!  Last set of changes didn't compile but they're OK now.
-
-       * hfs_btree.h, hfs_fs.h, mdb.c, ccache.c, extent.c, btree.c:
-       Move the definition of (struct hfs_raw_extent) inside
-       extent.c and treat it as simple array of U16's elsewhere.
-
-       * hfs_fs.h, dir_dbl.c, dir_nat.c, ccache.c, catalog.c, dir_cap.c:
-       Make hfs_cat_next() return the CNID and cdrType of the entry.
-       Now catalog.c and ccache.c are the only files which
-       depend on the structure of a catalog record on disk.
-
-       * dir.c, hfs_fs.h, catalog.c:
-       Replace hfs_cat_new_{file,dir}() with hfs_cat_{create,mkdir}()
-       which are wrappers for what used to be hfs_cat_create().
-
-       * hfs_fs.h, mdb.c, super.c, Makefile:
-       Split super.c into super.c (Linux stuff) and mdb.c (MDB stuff).
-
-       * super.c, hfs_fs_sb.h:
-       Add the MDB field 'drAtrb' to (struct hfs_mdb) as the field 'attrib'.
-
-       * hfs_fs_sb.h, super.c:
-       Split hfs_read_super() into hfs_read_super() and hfs_mdb_read().
-
-       * super.c, hfs_fs_sb.h:
-       Remove the unneeded 'hs' field from (struct hfs_mdb).
-
-       * TODO:
-       Remove item about hfs_notify_change() needing to update metadata.
-
-       * inode.c, hfs_fs.h, hfs_fs_sb.h, file_cap.c, file_dbl.c, file_nat.c,
-         file.c, dir.c:
-       Add a flags argument to hfs_{cap,dbl,nat}_buildmeta() so that
-       it only builds the parts that are currently out-of-date.
-       Call hfs_{cap,dbl,nat}_buildmeta() through hfs_update_meta()
-       in hfs_notify_change() and hfs_rename() to update the metadata.
-
-       * dir.c:
-       Make test for normal dir in update_dirs_{plus,minus}() more explicit.
-
-       * inode.c, file_cap.c, file_dbl.c, file_nat.c, dir_dbl.c, dir_nat.c,
-         file.c, README.sgml, dir_cap.c:
-       Resolve the "meta-data" vs. "metadata" rivalry in favor of the latter.
-
-       * btree.c:
-       Simplify some debugging code.
-
-       * hfs_btree_private.h, bnode.c, btree.c, balloc.c:
-       Put the in-core copy of the header node IN the
-       B-tree structure rather than just a pointer to it.
-
-       * hfs_btree_private.h, btree.c, bnode.c:
-       Have hfs_btree_commit() call hfs_bnode_commit()
-       to commit the header and root nodes.
-
-       * hfs_fs.h, super.c, hfs_btree_private.h, btree.c, hfs_btree.h,
-         balloc.c:
-       Change hfs_commit_mdb() to hfs_mdb_commit().
-       Make hfs_mdb_commit() call hfs_btree_commit().
-       Move code to update B-tree size and extent
-       from hfs_btree_extend() to hfs_btree_commit().
-       Make hfs_btree_extend() call hfs_mdb_commit().
-
-       * super.c:
-       Change hfs_commit_super() to hfs_commit_mdb().
-
-       * btree.c, bnode.c, bfind.c:
-       Fixed up broken debugging code and error messages.
-
-       * super.c, hfs_btree_private.h, btree.c, hfs_btree.h, bdelete.c,
-         binsert.c, balloc.c:
-       Now use write-back caching of B-tree header fields.
-
-       * hfs_fs.h:
-       Get rid of the add{16,32}() inlines as they are no longer used.
-
-       * hfs_btree_private.h, binsert.c, btree.c, bdelete.c, bfind.c, balloc.c:
-       All the needed fields of the B-tree header are
-       now cached for reading, but not yet writing.
-
-       * TODO:
-       Remove "Implement write count" from TODO list.
-
-       * file.c, super.c, bnode.c:
-       Implement write count.
-
-       * catalog.c:
-       Fix directory entry counting in hfs_cat_move().
-
-       * balloc.c:
-       Simplify hfs_btree_extend(), since the allocation
-       request will get rounded up to the clumpsize.
-
-       * extent.c:
-       Honor clumpsize when allocating blocks to files.
-
-       * file_cap.c, file_dbl.c, file_nat.c, super.c, dir.c, file.c,
-         ccache.c, catalog.c, balloc.c:
-       Mark 44 functions in need of commenting.
-
-       * hfs_fs_sb.h, super.c, extent.c, hfs_fs.h, ccache.c, btree.c, balloc.c:
-       Record clumpsize in allocation blocks rather than 512-byte blocks.
-
-       * sysdep.h, super.c, TODO, balloc.c, hfs_fs_sb.h:
-       Now updates the backup MDB when a B-tree grows.
-
-       * extent.c:
-       hfs_extent_free() had test against NULL backward.
-       The result is that access to a file with extents in the extents
-       B-tree would result in an infinite loop in hfs_cat_put().
-
-       * hfs_fs_sb.h, super.c, hfs_fs.h:
-       Reorganize partition map code to get size of partition
-       in preparation for dealing with the alternate MDB.
-
-Fri Aug  9 03:25:13 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * Makefile:
-       Add make rules for README.{ps,info}
-
-       * README, README.sgml, DOC, FAQ, Makefile, .cvsignore, 
-       Merge CHANGES into ChangeLog.
-       Merge DOC, FAQ and README into README.sgml.
-       Add make rules for building README.{txt,dvi}
-
-       * BUG_INFO, Makefile:
-       Added a BUG_INFO script which attempts to collect some useful
-       information which I'd like to see in every bug report I receive.
-
-       * Makefile, version.c:
-       Added version.c which contains a version string.
-
-Thu Aug  8 21:48:24 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * trans.c:
-       Fix Latin-1 -> Macintosh filename mapping to change colons to pipes.
-
-       * trans.c:
-       Fixed Mac->Latin-1 translation to behave as documented for the
-       extended 8-bit characters without corresponding Latin-1 characters.
-
-       * inode.c, super.c, file.c, hfs_fs_i.h, hfs_fs_sb.h, DOC:
-       Added a conv={binary,text,auto} mount option similar to that of the
-       msdos, hpfs and iso9660 filesystems, but applying only to data forks.
-       As compared to those filesystems, HFS has the advantage that only a
-       single CR need be converted to a NL, rather than a CR/NL sequence, so
-       it is quite safe to seek in the file.
-       Additionally the 'Type' field is far more reliable indicator of text
-       files than a file extension.
-
-       * super.c:
-       Simplified parsing of mount options.
-
-       * super.c:
-       Oops!  The part=<n> mount option was being parsed in octal!
-
-       * TODO:
-       Remove "case=lower" from the list of goals.
-
-       * super.c, hfs_fs.h, hfs_fs_sb.h, string.c, dir_dbl.c, dir_nat.c,
-         dir_cap.c, DOC:
-       Resurrect the case={asis,lower} mount option.
-
-       * dir.c:
-       Simpler test for "normal" directory in update_dirs_{plus,minus}().
-
-       * hfs_fs_sb.h, super.c, dir.c, hfs_fs.h, catalog.c, DOC:
-       Add mount options to specify what Type and Creator will be used for
-       new files and change the default from NULLs to "????".
-
-Wed Aug  7 11:32:22 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * catalog.c:
-       In hfs_cat_next() use entry->cnid rather than the key of the initial
-       brec to identify the end of the directory.
-
-       * README:
-       Update for pre-0.7 version.
-
-       * hfs_fs.h:
-       Create versioned module if CONFIG_MODVERSIONS is set in linux/config.h
-
-       * TODO:
-       Note need for special steps for unaligned accesses on some machines.
-
-       * FAQ:
-       Added Q0: What is HFS?
-       Added Q7: Does hfs_fs work w/ 400k and 800k diskettes?
-       Brought Q6 (about writability) up to date.
-       Made a few other answers more verbose.
-
-Tue Aug  6 00:58:46 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * Makefile:
-       Changed 'snapshot' rule to include cvs tag command.
-
-       * hfs_fs.h, dir_cap.c, dir_dbl.c, dir_nat.c, catalog.c, ccache.c:
-       Implemented readers half of dir locking scheme so readdir() should
-       produce consistent results and count_dir_entries() is not race prone.
-
-       * catalog.c:
-       hfs_cat_move() was calling hfs_cat_decache() after changing
-       the key rather than before, corrupting the hash lists.
-
-Mon Aug  5 14:03:46 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_fs.h, catalog.c:
-       Implemented the writers half of a locking scheme for directories.
-
-       * inode.c:
-       Fixed a serious bug in hfs_notify_change() that would allow a chmod()
-       on directory meta-data and would cause the directory inode (if it was
-       in memory at the time) to change into a file inode.
-
-       * inode.c:
-       Fixed a problem with write permissions on directory meta-data.
-
-       * dir_dbl.c, dir_nat.c, dir_cap.c:
-       hfs_{cap,dbl,nat}_readdir() now return the correct value in the 'd_ino'
-       field of the dirent for all cases, something I think has always been
-       done incorrectly until now.
-
-       * dir_nat.c, inode.c, dir_cap.c:
-       In hfs_{cap,nat}_lookup() take advantage of the
-       'file_type' field of (struct hfs_inode_info).
-
-       * TODO:
-       Removed two accomplished goals (rename() and improved readdir()).
-
-       * inode.c, dir_dbl.c, dir_nat.c, hfs_fs_i.h, dir.c, dir_cap.c:
-       Rewrite hfs_{cap,dbl,nat}_readdir() to take advantage of hfs_cat_next().
-       They now use a uniform 'i_size' for all inodes for a given directory.
-       This simplifies update_dirs_{plus,minus}() and eliminates the need for
-       the 'file_size' and 'dir_link' fields of (struct hfs_inode_info).
-       For the CAP and Netatalk schemes the meta-data directories are now the
-       last entries rather than coming just after '.' and '..'.  This is in
-       preparation for the day when we can write to the files in those
-       directories, and ensures that when using 'tar' to copy HFS filesystems
-       the file or directory will be created before the meta-data is written.
-       Otherwise we could be stuck writing meta-data and not knowing if it is
-       for a file or a directory!
-
-       * ccache.c:
-       Updated count_dir_entries() for new hfs_cat_next().
-
-       * hfs_fs.h, catalog.c:
-       hfs_cat{nth,next}() no longer take a 'types' argument,
-       so they now return all entries.
-       hfs_cat_next() now uses the ParID of the key to detect
-       the end of the directory.
-       hfs_cat_nth() now accepts n=0 as a valid input, requesting the thread.
-
-       * trans.c, string.c, super.c, dir_nat.c, hfs_fs.h, dir.c, dir_cap.c,
-         dir_dbl.c, catalog.c:
-       Rename (struct hfs_cname) to the more appropriate (struct hfs_pstr).
-
-       * hfs_fs.h, hfs_btree.h:
-       Move some constants from hfs_fs.h to hfs_btree.h
-
-       * bdelete.c, hfs_btree.h:
-       Remove hfs_bdelete_brec() from public B-tree interface.
-
-       * hfs_btree_private.h, hfs_fs.h, btree.c, hfs_btree.h, bnode.c, brec.c,
-         bfind.c, bins_del.c, binsert.c, balloc.c, bdelete.c, Makefile:
-       Split B-tree stuff into public and private parts:
-               brec.c split into bfind.c and brec.c
-               hfs_btree.h split into hfs_btree.h and hfs_btree_private.c
-
-       * inode.c:
-       The tests and sets of the HFS_FIL_LOCK bit where all reversed!
-
-       * hfs_fs.h, ccache.c:
-       Redo some ccache stuff, removing the 'error' field from
-       (struct hfs_cat_entry) and ensuring that hfs_cat_put()
-       will not sleep on an uninitialized entry.
-
-Sun Aug  4 23:43:28 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * sysdep.h:
-       Change swap{16,32}() back to macros since hton[ls]() are functions.
-
-       * hfs_fs.h, ccache.c:
-       Use only lowest order byte of parent CNID in hashing a catalog key.
-
-       * bdelete.c:
-       The "improved" bdelete() was TOO paranoid looking for missing parents.
-
-       * ccache.c:
-       Get rid of pointless swap16const(0).
-
-       * hfs_fs.h, inode.c, extent.c, ccache.c, dir_cap.c, dir_nat.c,
-         binsert.c, catalog.c:
-       Store cnid and associated constants in big-endian byte order.
-       This reduces the number of byte-order swaps required.
-
-       * sysdep.h:
-       Make swap32() and swap16() inline functions.
-
-       * dir_nat.c, dir_cap.c, dir_dbl.c:
-       Added hfs_rename() to the inode_operations for normal directories.
-
-       * dir.c, hfs_fs.h:
-       Added hfs_rename() and cleaned up hfs_{create,mkdir,unlink,rmdir}().
-
-       * catalog.c:
-       Added the missing check for moving a directory into itself.
-
-       * catalog.c, ccache.c, hfs_fs.h:
-       Implement a nearly ideal hfs_cat_move().
-       It still needs to prevent moving a directory into itself.
-       The functions hfs_cat_{create,delete,move}() still need work with
-       respect to their atomicity (especially vs. readdir).
-
-       * bdelete.c:
-       Fixed a serious bug in hfs_bdelete_brec() that would yield a corrupted
-       b-tree when the first record in a bnode was deleted.
-       Made bdelete() more aggressive when checking for missing parents.
-
-Sat Aug  3 06:11:50 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * btree.c, super.c:
-       Fixed a problem that caused a kernel oops when no HFS filesystem
-       is found.
-
-Wed Jul 24 13:06:12 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * catalog.c:
-       Remove race in hfs_cat_create() that could overflow directory valence.
-
-       * catalog.c:
-       Fix hfs_cat_create() so the parent directory doesn't get deleted
-       out from under it.  Otherwise we could have created files and
-       directories in deleted directories.
-
-       * hfs_fs.h, dir_cap.c, dir_dbl.c, dir_nat.c, catalog.c, ccache.c:
-       Redo hfs_cat_{next,nth}() in terms of which entry types to
-       allow, rather than which to skip.
-
-       * catalog.c:
-       The function hfs_cat_create() would fail to hfs_cat_put(entry) if
-       the 'record' argument was invalid or if the 'result' argument was NULL.
-
-       * dir.c:
-       The functions hfs_{create,mkdir,unlink,rmdir} all failed to
-       call iput() when their arguments conflicted with a reserved name.
-
-       * catalog.c, hfs_fs_sb.h:
-       Start over on rename().  Still unfinished.
-       Fix silly bug in hfs_cat_create() that made it always fail.
-
-       * ccache.c:
-       Fix byte-order bug in write_entry().
-
-Tue Jul 23 12:12:58 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * dir_dbl.c, dir_nat.c, hfs_fs.h, dir.c, dir_cap.c:
-       Remove the macros KEY() and PARENT() since the key is now easy
-       to access through the catalog entry.
-       Replace the macros NAME{IN,OUT}() with inline functions
-       hfs_name{in,out}() to gain type checking of arguments.
-
-       * catalog.c:
-       Remove the macro TYPE().
-
-       * inode.c, file_dbl.c, file_nat.c, file.c, file_cap.c:
-       Remove the #define's of the unused macro KEY().
-
-       * hfs_fs.h, dir_cap.c, dir_dbl.c, dir_nat.c, catalog.c, dir.c:
-       Replace hfs_lookup_parent() in dir.c with hfs_cat_parent() in catalog.c.
-       This new function performs locking to protect against rename() changing
-               the parent during I/O.
-       It is also intended for use with files as well as directories.
-       Change hfs_{cap,dbl,nat}_lookup() to use the new function.
-
-       * dir.c, hfs_fs.h, catalog.c:
-       Remerge hfs_cat_{create,mkdir}() into hfs_cat_create() and resurrect
-               hfs_cat_new_{file,dir}().
-       Fix hfs_cat_{create,delete} to use the improved catalog cache for
-               locking in place of directory-level create/delete locks.
-       Fix hfs_{create,mkdir}() to use the new hfs_cat_create().
-
-       * hfs_fs.h, ccache.c:
-       Rewrite parts to remove need for specialized create/delete locking.
-       Use new case-independent hash function.
-       Fix bug in hfs_cat_get() that would read an entry w/o locking it.
-       Call hfs_relinquish() before retrying a deleted entry in hfs_cat_get.
-       If there is a read error, then don't retry in hfs_cat_get().
-       Remove unused 'version' field from (struct hfs_cat_entry).
-
-       * sysdep.h:
-       Add hfs_relinquish(), a system-independent alias for schedule().
-
-       * hfs_fs.h, string.c:
-       Add hfs_strhash(), a simplistic case-independent hash function.
-
-       * hfs_fs.h, inode.c:
-       Make hfs_iget() an inline function.
-
-       * TODO:
-       Add a few goals and removed those that have been achieved.
-
-       * Makefile:
-       Add ccache.c to list of source files.
-       Add rule for *.s files and include them in the 'clean' rule.
-
-Wed Jul 17 17:22:45 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * sysdep.h, trans.c, string.c, super.c, hfs_fs_i.h, hfs_fs_sb.h,
-         inode.c, hfs_btree.h, hfs_fs.h, file_dbl.c, file_nat.c, extent.c,
-         file.c, file_cap.c, dir_dbl.c, dir_nat.c, ccache.c, dir.c,
-         dir_cap.c, btree.c, catalog.c, bnode.c, brec.c, balloc.c:
-       Total rewrite of the inode-handling stuff to be centered around
-       a catalog entry cache (ccache.c).  This results not only in a far
-       more sensible way of doing things, but also removed many race
-       conditions. (The source and object code both got smaller too!)
-       Many small "undocumented features" were also fixed.
-       Replace HFS_CNAME with (struct hfs_cname).
-       rename() has been temporarily abandoned.
-
-Thu Jul 11 01:14:38 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * dir.c:
-       As written hfs_lookup_parent() had two overlapping read requests
-       in the catalog tree.  This could have led to deadlock.
-
-Wed Jul 10 09:27:00 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * catalog.c, hfs_fs.h, bdelete.c:
-       More work on getting rename() fleshed out.  Still not done.
-       Before I can finish it looks like I'll need to build a
-       mechanism for exclusive access to the catalog tree.  There
-       just doesn't seem to be any other way to get proper POSIX
-       semantics without a bunch of race conditions elsewhere.
-
-       * hfs_fs.h, inode.c, dir_cap.c, dir_dbl.c, dir_nat.c, catalog.c:
-       More work on the still incomplete rename() code.
-       Merge hfs_cat_add_{dir,file}() into hfs_cat_create().
-       Add file-thread support to hfs_cat_{create,delete,rename}.
-
-Tue Jul  9 09:43:15 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * inode.c, dir_dbl.c, dir_nat.c, extent.c, dir_cap.c:
-       The indirect (struct hfs_file) was causing blocks not to be freed
-       when files where deleted, and an omission in hfs_put_inode() was
-       preventing the inode from getting freed.  Both are now fixed.
-
-       * hfs_fs.h, dir_dbl.c, dir_nat.c, hfs_btree.h, catalog.c, dir_cap.c,
-         bdelete.c:
-       Made unlink() and rmdir() more race resistant and did some more
-       work on the still incomplete code for rename().
-
-       * btree.c, bnode.c:
-       There was a serious race condition in the bnode cache, so
-       hfs_bnode_find() is now modeled after Linus's inode cache.
-
-Mon Jul  8 10:33:38 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_fs_i.h, inode.c, file_cap.c, file_dbl.c, file_nat.c, dir_dbl.c,
-         dir_nat.c, file.c, dir.c, dir_cap.c:
-       More changes to layout of (struct hfs_inode_info).
-
-       * super.c, inode_cap.c, inode_dbl.c, inode_nat.c, inode.c, hfs_fs_i.h,
-         hfs_fs_sb.h, file_nat.c, hfs_fs.h, file.c, file_cap.c, file_dbl.c,
-         Makefile, catalog.c:
-       Implemented new layout for (struct hfs_inode_info) resulting in the
-       elimination of lots of duplicated code for hfs_*_write_inode(),
-       hfs_*_put_inode() and *_open() functions.
-       Merged inode_*.c files back into inode.c.
-       Not fully tested.
-
-       * TODO:
-       Add a few more of my goals to the list.
-
-       * README:
-       Documentation updates.
-
-       * inode_nat.c, inode_cap.c, inode_dbl.c, inode.c, hfs_fs.h, hfs_fs_i.h,
-         file.c, file_cap.c, file_dbl.c, file_nat.c, catalog.c:
-       (struct hfs_file) and metadata are read when file is opened or
-       truncated and are released by iput().
-
-Sun Jul  7 23:55:43 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * inode_nat.c, inode_cap.c, inode_dbl.c, inode.c, dir_nat.c, hfs_fs.h,
-         hfs_fs_i.h, dir_cap.c, dir_dbl.c, catalog.c, dir.c:
-       (struct hfs_dir) is now inside (struct hfs_inode_info) once again.
-
-       * inode_nat.c, super.c, inode_cap.c, inode_dbl.c, inode.c, file_nat.c,
-         hfs_btree.h, hfs_fs.h, extent.c, file_cap.c, file_dbl.c, dir_nat.c,
-         dir_cap.c, dir_dbl.c, btree.c, catalog.c, dir.c, bpath.c, brec.c,
-         bins_del.c, binsert.c, bnode.c, bfind.c, balloc.c, bdelete.c,
-         Makefile:
-       Remerged (struct hfs_bpath) and (struct hfs_brec), merging the
-       files bfind.c and bpath.c as a resurrected brec.c.
-
-Sat Jul  6 21:47:05 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * inode_cap.c, inode_dbl.c, inode_nat.c, inode.c, hfs_fs.h, hfs_fs_i.h,
-         file_cap.c, file_dbl.c, file_nat.c, hfs_btree.h, dir_nat.c, extent.c,
-         dir.c, dir_cap.c, dir_dbl.c, btree.c, catalog.c, bfind.c, bpath.c,
-         binsert.c, bdelete.c:
-       Renamed (struct hfs_brec_key) to (struct hfs_bkey).
-
-Tue May 28 07:53:24 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * inode_cap.c, catalog.c:
-       Spelling fixes.
-
-       * inode_nat.c, super.c, inode_cap.c, inode_dbl.c, inode.c, hfs_fs.h,
-         hfs_fs_i.h, hfs_fs_sb.h, file.c, file_dbl.c, file_nat.c, dir_dbl.c,
-         dir_nat.c, extent.c, dir.c, dir_cap.c, catalog.c:
-       Structures got too big, so I had to add a layer of indirection
-       to (struct hfs_inode_info).
-       This means we must clear_inode() in inode_put().
-
-Mon May 27 01:32:42 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * catalog.c, file_cap.c:
-       Some sizeof() stuff now uses variable not type.
-
-       * hfs_fs.h:
-       Make HFS_I() and HFS_SB() inline to gain type checking.
-
-Sun May 26 13:34:17 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * dir_nat.c:
-       Oops.  Had left some debugging printk()s in place.
-
-       * file_dbl.c, file_nat.c, file_cap.c:
-       Cleaned up variable names for consistency.
-
-       * hfs_fs_sb.h:
-       Add a couple 'const's to function typedefs.
-
-       * hfs_fs.h:
-       Add and update function prototypes.
-       Cleaned up type names.
-       Fix debugging malloc code.
-       Add hfs_iget_by_name() as an inline function.
-
-       * sysdep.h:
-       Remove extra semicolon from macro definitions.
-
-       * super.c:
-       Use new hfs_iget_by_name() to get root inode.
-
-       * extent.c:
-       Cleaned up some variable naming for consistency.
-
-       * catalog.c:
-       Added (untested) code for hfs_cat_move_file().
-
-       * catalog.c:
-       Fix one missed call to hfs_cat_build_key().
-       Make hfs_cat_add_{file,dir}() take a cat_entry as an argument.
-       Add hfs_cat_new_{file,dir}() to generate new cat_entry's.
-
-       * dir_dbl.c, dir_nat.c, dir.c, dir_cap.c:
-       Cleaned up type and variable names.
-       Updated calls to hfs_cat_build_key() and NAMEOUT()
-       Use new hfs_iget_by_*() calls.
-
-       * inode_cap.c, inode_dbl.c, inode_nat.c:
-       Cleaned up type and variable names.
-
-       * inode.c:
-       Update calls to hfs_cat_build_key().
-       Cleaned up type and variable names.
-       Implemented a hierarchy of hfs_iget_by*() calls.
-
-       * catalog.c:
-       Change hfs_cat_build_key() to take a HFS_CNAME as input.
-
-       * btree.c:
-       Initialize lsize and psize fields of file.
-
-       * trans.c:
-       Now passes type HFS_CNAME and has name/len in "normal" order.
-
-Tue May 21 07:02:34 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * bnode.c:
-       Attempt to read invalid bnode would have led to an infinite loop under
-       certain circumstances.  One way to cause this was with an invalid
-       partition table which points beyond the end of the device.
-
-Sat May 11 12:38:42 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * sysdep.h, sysdep.c, inode_dbl.c, inode_nat.c, super.c, inode_cap.c,
-         inode.c, hfs_fs.h, hfs_fs_i.h, hfs_fs_sb.h, file_dbl.c, file_nat.c,
-         hfs_btree.h, extent.c, file.c, file_cap.c, dir_nat.c, dir.c,
-         dir_cap.c, dir_dbl.c, btree.c, catalog.c, bitmap.c, bitops.c,
-         bnode.c, bfind.c, bins_del.c, binsert.c, balloc.c, bdelete.c:
-       Another big wave of portability-oriented changes.
-
-Tue May  7 11:28:35 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * super.c, sysdep.c, sysdep.h, inode_cap.c, inode_dbl.c, inode_nat.c,
-         hfs_fs_i.h, inode.c, file_nat.c, hfs_btree.h, hfs_fs.h, file.c,
-         file_cap.c, file_dbl.c, dir_nat.c, extent.c, dir_cap.c, dir_dbl.c,
-         btree.c, catalog.c, dir.c, bnode.c, bpath.c, binsert.c, bitmap.c,
-         bitops.c, bdelete.c, bfind.c, bins_del.c, Makefile, balloc.c:
-       Start a big move to abstract all the Linux-specific stuff
-       out of the lower levels.  Created sysdep.[ch] to hold it.
-
-       * FAQ, TODO:
-       Bring some documentation up-to-date.
-
-Fri May  3 20:15:29 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * super.c, inode_dbl.c, inode_nat.c, inode.c, inode_cap.c, extent.c,
-         hfs_fs.h, hfs_fs_i.h, dir_dbl.c, dir_nat.c, catalog.c, dir.c,
-         dir_cap.c, bpath.c, btree.c, binsert.c, bnode.c:
-       "FID reform": 'fid' became 'cnid' (Catalog Node ID), and is now
-       a field in (struct hfs_file).  The new name is more consistent
-       with Apple's documentation.  The presence of 'cnid' in (struct
-       hfs_file) help move more of the code toward OS-independence.
-
-       * inode_nat.c, super.c, trans.c, inode.c, inode_cap.c, inode_dbl.c,
-         hfs_fs.h, file_cap.c, file_dbl.c, file_nat.c, dir_nat.c, extent.c,
-         file.c, dir.c, dir_cap.c, dir_dbl.c, btree.c, catalog.c, bnode.c,
-         bpath.c, bins_del.c, binsert.c, bitmap.c, bitops.c, bdelete.c,
-         bfind.c, balloc.c:
-       A lot of changes in what headers are included and in what order.
-
-Sat Apr 27 12:28:54 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * FAQ:
-       Updated for current writability status.
-
-       * .cvsignore:
-       Added ChangeLog.
-
-       * file_dbl.c, file_nat.c, file_cap.c, file.c, dir_dbl.c, dir_nat.c,
-         dir_cap.c:
-       Added the default fsync() to all file_operations structures.
-
-       * dir_nat.c, hfs_fs.h, dir.c, dir_cap.c, dir_dbl.c:
-       Add rmdir() for normal directories.
-
-       * binsert.c:
-       I had messed up insertion so that is would sometime fail to
-       split the root, but its OK now.
-
-       * dir.c:
-       hfs_do_unlink() decremented directory counts rather than file counts.
-
-Wed Apr 24 13:20:08 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_fs.h, bnode.c, hfs_btree.h:
-       Fixed a couple more type size assumptions.
-
-       * hfs_fs.h, balloc.c, bitmap.c, bitops.c:
-       "Portable" bitmap handling was wrong for just about everything but
-       the i386 and the "inverse big-endian" bit ordering that I thought
-       the m68k port was using.  It seems the m68k port is now using standard
-       big-endian bit-numbering conventions.
-       This code is now correct for the standard big- and little-endian bit
-       orderings. (which should cover all Linux systems?)
-       Also no longer assumes sizeof(long) == 4, though that might still be
-       a problem in other parts of the code.
-
-Tue Apr 23 19:19:27 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * FAQ:
-       Bring uptodate for this snapshot.
-
-       * Makefile:
-       Add FAQ to $(MISC)
-
-       * README, TODO:
-       Documentation updates.
-
-       * bdelete.c:
-       Spelling fixes.
-
-       * dir_cap.c:
-       In unlink() don't force metadata into memory if not present.
-
-       * bdelete.c:
-       Some function comments and some clean up.
-
-       * bins_del.c:
-       Added missing function comment for hfs_bnode_update_key().
-
-       * binsert.c, bitmap.c:
-       Spelling and grammar corrections to comments.
-
-       * hfs_btree.h, hfs_fs.h, bins_del.c, binsert.c, Makefile, bdelete.c:
-       Clean up of hfs_bdelete(), splitting bins_del.c into three files:
-               bins_del.c, binsert.c and bdelete.c
-
-       * bpath.c, bins_del.c:
-       hfs_bdelete() is now working "correctly", but needs some cleaning up.
-
-Mon Apr 22 05:35:41 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_fs.h, bpath.c, hfs_btree.h, bins_del.c, bnode.c, balloc.c,
-         bfind.c:
-       Rewrite bnode handling, heading toward a more write-behind approach.
-       Have done away with HFS_LOCK_BLIND.
-
-       * inode_dbl.c, inode_nat.c, extent.c, hfs_fs_i.h, inode_cap.c:
-       Was trying to truncate resource fork of directories!
-
-Sun Apr 21 08:15:43 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * balloc.c:
-       Updated to use truncate() to grow full trees.
-
-       * extent.c, hfs_fs.h, file.c, inode.c:
-       Added truncate() for normal files.
-
-       * bins_del.c:
-       hfs_bdelete() fixes for handling removal of root.
-
-       * inode_cap.c, inode_dbl.c, inode_nat.c:
-       Release storage for deleted files in hfs_*_put_inode().
-
-       * bitmap.c:
-       Make len=0 valid for hfs_{set,clear}_vbm_bits().
-
-       * super.c, inode.c, hfs_fs_i.h, hfs_fs_sb.h, btree.c, balloc.c:
-       Changed from clumpsize to clumpblks.
-
-       * inode_nat.c, hfs_fs.h, inode_cap.c, inode_dbl.c, btree.c, extent.c,
-         balloc.c:
-       Some extent-related changes in preparation for truncate() support.
-
-Sat Apr 20 10:59:13 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * inode_nat.c, hfs_fs_i.h, inode.c, inode_cap.c, inode_dbl.c,
-         dir_nat.c, hfs_fs.h, dir.c, dir_cap.c, dir_dbl.c:
-       Removed dir.valence from hfs inode.
-       Added unlink(), but still need truncate() and some more support
-       in hfs_*_put_inode() to free the disk space used by deleted files.
-
-       * bnode.c:
-       Check for NULL bnode in hfs_bnode_relse().
-
-       * bins_del.c:
-       Fixed a byte-order problem in bdelete_nonempty().
-
-       * hfs_fs.h, bnode.c, bpath.c, hfs_btree.h, balloc.c, bins_del.c:
-       First attempt at hfs_bdelete().
-
-       * dir.c:
-       The Finder would display strange things if it couldn't set frView.
-       Therefore initialize frView field for new directories.
-
-       * file_cap.c, file_dbl.c, file_nat.c, hfs_fs.h:
-       Define User/Finder info fields of catalog entry in more detail.
-
-       * hfs_fs.h:
-       HFS_BFIND_DELETE should require exact match.
-
-       * dir.c:
-       Set "record in use" bit of filFlags for new files.
-
-       * inode.c:
-       Was doing the wrong thing with i_ctime.
-
-       * dir_nat.c, dir_cap.c, dir_dbl.c:
-       Added some missing updates to the inode in hfs_*_{create,mkdir}().
-
-Sun Apr 14 00:10:52 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_fs.h, file_dbl.c, file_nat.c, file.c:
-       Work around the ever-changing type of f_reada.
-
-Sat Apr 13 00:43:41 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * bpath.c, bfind.c:
-       Spelling corrections in comments.
-
-       * bins_del.c:
-       ifdef out shift_left() until it is actually used.
-
-       * hfs_btree.h, hfs_fs.h, bins_del.c, bpath.c, bfind.c:
-       Cleaned up code related to 'flags' argument to hfs_bpath_find().
-
-Fri Apr 12 23:30:01 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * bpath.c:
-       Updated comments.
-       Rewrote hfs_bpath_init() and hfs_bpath_next().
-
-       * hfs_btree.h:
-       Updated prototype for hfs_bpath_init().
-
-       * bins_del.c:
-       Updated call to hfs_bpath_init().
-
-       * inode.c, inode_cap.c, inode_dbl.c, inode_nat.c, extent.c, file_cap.c,
-         file_dbl.c, file_nat.c, dir_cap.c, dir_dbl.c, dir_nat.c, catalog.c,
-         dir.c:
-       Renamed hfs_brec_relse() to hfs_brelse().
-
-       * hfs_fs.h, hfs_btree.h:
-       Updated prototypes to reflect new names in bpath.c
-
-       * bins_del.c:
-       Updated calls to functions in bpath.c
-       Updated comments.
-
-       * Makefile:
-       Renamed brec.c to bpath.c
-
-       * bfind.c:
-       Updated calls to functions in bpath.c
-       Added hfs_brelse() which was previously hfs_brec_relse() in brec.c
-
-       * bpath.c:
-       brec.c renamed to bpath.c
-       Functions renamed to reflect their current actions.
-       Comments are still out of date.
-       hfs_brec_relse() renamed to hfs_brelse() and moved to bfind.c
-
-       * brec.c:
-       brec.c renamed to bpath.c
-
-Wed Apr 10 07:20:28 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_fs.h, extent.c, hfs_btree.h, brec.c, dir.c, bfind.c,
-         bins_del.c:
-       Backed-out changes to hfs_binsert() that added the ability to
-       return the new record, since it will probably not ever be needed.
-
-       * extent.c:
-       Since 1.3.45 truncate() has locked the file, so there is no need
-       for all the things I've been doing to hfs_file_extend() & new_extent().
-       Those two functions have been cleaned up a bit (similar to older forms).
-
-       * extent.c:
-       hfs_file_extend() now more "robust", but new_extent() is still
-       not fully "concurrency safe."
-
-Tue Apr  9 09:01:18 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * bins_del.c:
-       Made split() inline.
-
-       * inode.c, dir_nat.c, hfs_fs.h, dir_cap.c:
-       Added hfs_itry() to get in-core inodes.
-
-       * inode_dbl.c, inode_nat.c, hfs_fs.h, inode.c, inode_cap.c, file_dbl.c,
-         file_nat.c, hfs_btree.h, extent.c, file_cap.c, dir_cap.c, dir_dbl.c,
-         dir_nat.c, brec.c, catalog.c, dir.c, bins_del.c, bnode.c,
-         bfind.c:
-       Rewrite of all the (struct hfs_brec) stuff.
-
-Mon Apr  8 21:50:01 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * btree.c, extent.c, bnode.c:
-       Fixed format strings in a few debugging printk()'s.
-
-       * brec.c, hfs_fs.h:
-       Removed hfs_brec_relse_one().
-
-       * hfs_fs.h, bnode.c, brec.c, hfs_btree.h, bfind.c, bins_del.c, balloc.c:
-       (struct hfs_bnode_ref)s are now returned by value rather than reference
-       and they are in (struct hfs_brec) rather than pointed to.  Cuts down on
-       a lot of kmalloc() and kfree() traffic.
-
-       * hfs_fs.h, dir.c, extent.c, bins_del.c:
-       Modified hfs_binsert() to be able to return the new record.
-
-       * bins_del.c, hfs_btree.h:
-       Added shift_left(), still untested.
-
-       * bins_del.c:
-       new_root() was missing its comment.
-
-       * super.c, trans.c, hfs_fs_i.h, inode.c, inode_dbl.c, inode_nat.c,
-         file_nat.c, hfs_btree.h, hfs_fs.h, file.c, file_dbl.c, dir_dbl.c,
-         dir_nat.c, extent.c, dir.c, dir_cap.c, bitops.c, bnode.c, brec.c,
-         bfind.c, bins_del.c, bitmap.c, balloc.c:
-       Fixed lines over 80 characters and tabified files.
-
-       * bins_del.c:
-       Fixed line(s) over 80 columns.
-
-       * trans.c, inode_nat.c, string.c, super.c, inode.c, inode_cap.c,
-         inode_dbl.c, hfs_fs_i.h, hfs_fs_sb.h, hfs_btree.h, hfs_fs.h, file.c,
-         file_cap.c, file_dbl.c, file_nat.c, dir_dbl.c, extent.c, btree.c,
-         dir_cap.c, bitops.c, bnode.c, brec.c, bfind.c, bins_del.c, bitmap.c,
-         DOC, README, TODO, balloc.c, CHANGES:
-       About 150 spelling corrections.
-
-Sun Apr  7 23:14:28 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * dir_cap.c, dir_dbl.c, dir_nat.c, dir.c:
-       Cleaned-up check for special names in mkdir().
-
-       * extent.c:
-       More verbose error message.
-
-       * inode_dbl.c, inode_nat.c, hfs_fs_i.h, inode.c, inode_cap.c, dir.c,
-         hfs_fs.h:
-       Limit directories to 32767 entries, since Mac uses 16-bit integer.
-
-Fri Apr  5 07:27:57 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * FAQ:
-       Initial version.
-
-       * dir_dbl.c, dir_nat.c, bins_del.c, dir.c, dir_cap.c:
-       Added missing function comments.
-
-Wed Apr  3 06:38:36 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * brec.c:
-       Cleaned-up code for brec->flags.
-
-       * extent.c:
-       Added function comments.
-
-       * bins_del.c:
-       Added function comments.
-       hfs_binsert() was incrementing record count even on failure.
-
-Mon Apr  1 08:35:51 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * extent.c:
-       Rewrote find_ext() and new_extent() for new hfs_btree_extend().
-       Moved hfs_btree_extend() to balloc.c
-       Fixed potential kernel OOPS in new_extent().
-
-       * brec.c:
-       Fixed potential kernel OOPS in hfs_brec_get_root().
-       Removed hfs_brec_find_first().
-       Fixed return value of hfs_brec_find().
-
-       * bins_del.c:
-       Updated call to hfs_btree_extend().
-
-       * balloc.c:
-       Merged hfs_bnode_add() and hfs_btree_extend() into the later.
-       Commented init_mapnode().
-
-       * bfind.c:
-       Removed hfs_bfind_first().
-
-       * hfs_fs.h, hfs_btree.h:
-       Updated prototypes.
-
-Sat Mar 30 22:56:47 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * CHANGES, README, TODO:
-       Updated documentation in preparation for 0.6 release.
-
-       * inode.c, hfs_fs.h:
-       Got rid of HFS_FAKE_EXEC in favor of noexec mount option.
-
-       * inode.c, super.c, DOC, hfs_fs_sb.h:
-       Added "quiet" mount option, like the fat filesystem.
-
-       * inode.c, dir_cap.c, dir_nat.c:
-       Pseudo-directories are read-only (at least for now).
-
-       * hfs_fs.h, dir_dbl.c, dir_nat.c, dir.c, dir_cap.c:
-       mkdir() updated to check against reserved names, but the
-       AppleDouble scheme still has problems with names starting with '%'.
-
-       * dir_dbl.c, dir_nat.c, hfs_fs.h, dir.c, dir_cap.c:
-       Added mkdir(). (It only took 2 tries to get it right!!)
-       Only works in "normal" directories and doesn't yet stop
-       one from creating dirs with the reserved names.
-
-       * brec.c, extent.c, bins_del.c:
-       Now have a way to get an EEXIST back from hfs_binsert().
-
-       * btree.c, inode.c, hfs_fs_i.h, file.c, bfind.c, bnode.c, balloc.c:
-       Added 'dev' field to struct hfs_file.
-
-       * hfs_fs_i.h, inode.c, btree.c, extent.c, file.c, bnode.c, brec.c,
-         balloc.c:
-       Removed duplicated fields from struct hfs_file since
-       even B*-trees now have that information in the inode.
-
-       * extent.c:
-       zero_blocks() neglected allocation block size in computing start.
-
-Fri Mar 29 16:04:37 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * super.c:
-       hfs_statfs(): f_files and f_ffree fields are now -1, which is
-       documented as the value for "undefined" fields in struct statfs.
-
-       * trans.c, inode_nat.c, string.c, super.c, inode_dbl.c, inode_cap.c,
-         inode.c, file_nat.c, file_dbl.c, file_cap.c, file.c, dir_dbl.c,
-         extent.c, dir_cap.c, catalog.c, btree.c, brec.c, bnode.c, bitops.c,
-         bitmap.c, bins_del.c, balloc.c:
-       Stylistic editing: {} for all 'for', 'while' and 'if' blocks.
-       I hope I didn't screw-up anything.
-
-       * hfs_fs.h, dir.c, dir_cap.c, dir_dbl.c, dir_nat.c:
-       Added creation of normal files to all three fork schemes!
-       Strange things may happen when trying to create "non-normal" files.
-
-       * brec.c:
-       Cleaned up some debugging code.
-
-       * hfs_fs_i.h:
-       File and directory counts could have overflown 16-bit integer.
-
-       * hfs_btree.h:
-       Added HFS_BREC_RIGHT to help fix insertion problem.
-
-       * extent.c:
-       Various fixes to hfs_{file,btree}_extend().
-
-       * catalog.c:
-       Made hfs_build_cat_key() more "correct".
-
-       * btree.c:
-       Added and fixed debugging code.
-
-       * brec.c:
-       Fixed overflow detection.
-       Added some debugging code.
-
-       * bnode.c:
-       Dirtied some buffers in places that might have been missed.
-       Fixed some debugging code that had broken.
-
-       * bitops.c:
-       hfs_count_free_bits() was running off end of bitmap.
-
-       * bins_del.c:
-       Fixed various bugs, mostly related to variable-length keys.
-
-       * balloc.c:
-       Had forgotten to set a bit in new mapnodes.
-       Node counts were overflowing 16-bit integers.
-
-       * bitmap.c:
-       Oops! clear/set did opposite operation on full words.
-
-Wed Mar 27 10:59:07 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * hfs_fs_i.h:
-       Updated struct hfs_extent for concurrent access.
-       Also caused a slight modification to struct hfs_file.
-
-       * hfs_fs.h, hfs_btree.h:
-       Added/updated prototypes.
-
-       * balloc.c:
-       hfs_bnode_alloc() finished but still untested.
-
-       * bins_del.c:
-       Fixed up deadlock avoidance in hfs_binsert() again.
-       Perhaps I even got it right this time.
-
-       * extent.c:
-       hfs_file_extend() now safe under concurrent operations?
-
-       * file.c:
-       hfs_getblk() now safe under concurrent operations?
-
-Tue Mar 26 23:26:35 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * btree.c:
-       Added call to hfs_extent_trim() to fix memory leak.
-
-       * extent.c:
-       Oops, had left a "#define static" in from debugging.
-
-       * bins_del.c:
-       hfs_binsert() rewritten to avoid deadlock when extending
-       the extents B*-tree.
-
-       * btree.c:
-       Moved hfs_btree_extend() to extent.c
-
-       * inode_nat.c, inode_cap.c, inode_dbl.c:
-       hfs_*_put_inode() rewritten to call hfs_extent_trim().
-
-       * extent.c:
-       Big rewrite for new struct hfs_extent:
-               Now keep linked list of extents.
-               Cache is now a pointer to a list element.
-               Now have 'end' field to aid decode_extent().
-       New functions:
-               hfs_extent_trim(): frees linked list.
-               hfs_btree_extend(): for extending B*-trees.
-       Improved debugging output.
-
-       * balloc.c:
-       Added hfs_bnode_add() (incomplete and uncommented).
-
-       * btree.c:
-       Moved some work from hfs_btree_extend() to hfs_bnode_add().
-
-       * bfind.c:
-       Added hfs_bfind_first() as wrapper for hfs_brec_find_first().
-
-       * brec.c:
-       Added hfs_brec_find_first() to search first leaf node.
-
-       * bins_del.c:
-       Added error returns to hfs_binsert() and binsert().
-
-       * bins_del.c:
-       Check to see that we really need ancestors before starting.
-       Check that hfs_btree_alloc() gave us enough nodes.
-       binsert() uses info precomputed by hfs_binsert().
-
-Mon Mar 25 11:33:53 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * bnode.c:
-       Collected together the error returns in hfs_bnode_lock().
-
-       * Makefile:
-       Added ChangeLog to $(MISC).
-
-Wed Mar 20 19:41:45 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * super.c, hfs_fs.h, file.c, dir_dbl.c, dir_nat.c, dir.c, dir_cap.c:
-       Removed support for kernels older than about 1.3.70
-       Most of that support had been broken recently anyway.
-
-       * super.c:
-       Fixed so DEBUG_MEM works w/o DEBUG_ALL.
-       Updated call to hfs_btree_init().
-
-       * hfs_fs.h:
-       Updated/added prototypes.
-
-       * hfs_btree.h:
-       HFS_BFIND_CHAIN removed.
-       struct hfs_brec gets new 'flags' field with bits:
-               HFS_BREC_{FIRST,OVERFLOW,UNDERFLOW,UNINITIALIZED}
-       Removed bitmap size constants.
-       Changes to struct hfs_btree:
-               'file' and 'cache' now structs rather than pointers.
-               Added 'reserved' field (used during insertion).
-               Added pointers to size and extent in MDB.
-
-       * file.c:
-       Made hfs_getblk() public.
-       Removed (fil->inode == NULL) special cases.
-
-       * extent.c:
-       {find,update}_ext() are no longer inline.
-       new_extent() fails when called for the extents tree;
-               previously it would hanging calling hfs_binsert().
-       extend_file():
-               renamed to hfs_file_extend() and made public.
-               fixed to work for B*-trees.
-               zeros-out blocks as they are allocated.
-               fixed bugs for (allocation block) != (physical block).
-
-       * btree.c:
-       hfs_btree_{init,free}() modified for changes to struct:
-               'file' and 'cache' moved back into structure
-               file.inode initialized to reduce special cases
-       hfs_btree_init() gets pointer to size in MDB instead of size.
-       Added hfs_btree_extend() (incomplete and uncommented).
-
-       * bnode.c:
-       hfs_bnode_{alloc,free}() moved to separate file.
-       Removed 'const' from some function arguments
-               due to change in struct hfs_btree.
-       hfs_bnode_lock(): added WRITE/RESRV->READ transition.
-
-       * brec.c:
-       hfs_brec_get_{root,child}() now take a 'keep_mask' argument
-               indicating when to keep ancestor nodes, and store
-               information about why ancestors were kept.
-       HFS_BFIND_CHAIN eliminated in favor of HFS_BFIND_{INSERT,DELETE}
-               which are now implemented using 'keep_mask'.
-       Added hfs_brec_relse_one() that doesn't release ancestors.
-
-       * bins_del.c:
-       Lots of rewrites to cleanup insertion.
-       Now tries to extend tree before insertion starts.
-       binsert() iterative rather than recursive.
-       No point in keeping track as it is still not "stable".
-
-       * balloc.c:
-       New file: started with hfs_bnode_{free,alloc}()
-       Added hfs_bnode_init() to initialize a newly allocated bnode.
-       hfs_bnode_free():
-               Renamed hfs_bnode_bitop().
-               Can set or clear a specified bit.
-               Gets bitmap sizes from nodes directly.
-       hfs_bnode_alloc():
-               Returns actual node, calling hfs_bnode_init().
-               Gets bitmap sizes from nodes directly.
-
-       * bfind.c:
-       Removed obsolete comment from hfs_bsucc()
-       Removed 'const' from tree arg of hfs_bfind()
-               due to changes in struct hfs_btree.
-
-       * Makefile:
-       Added new file: balloc.c
-
-Sat Mar  9 22:03:53 1996  Paul H. Hargrove  <hargrove@sccm.stanford.edu>
-
-       * Start of detailed CVS logging.
-
-Mar 09, 1996: snapshot-09Mar96 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       NOT AN OFFICIAL RELEASE
-       Fixed up debugging code that was broken by split of btree.c
-       Added debugging kmalloc/kfree
-       Fixed memory leak in hfs_bnode_relse()
-
-Mar 08, 1996: snapshot-08Mar96 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       NOT AN OFFICIAL RELEASE
-       now reset blocksize on device when done.
-       hfs_binsert done (except for the full tree case).
-       btree.c split up into manageable pieces (need to sort out hfs_btree.h)
-
-Feb 26, 1996: snapshot-26Feb96 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       NOT AN OFFICIAL RELEASE
-       Some writability.
-       Bug with multiple opens of meta data fixed.
-       Netatalk support no longer considered experimental.
-
-Virtually everything has changed, so I've lost track here.
-
-Nov 16, 1995: snapshot-16Nov95 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       NOT AN OFFICIAL RELEASE
-       Still more comments.
-       btree.c back to 80 columns.  will do same to other files soon.
-       Starting with btree.c have begun to put file contents into some
-               sort of standard order.
-       Moved metadata reading to VFS open() routine and now free it in
-               the VFS release() routine.  Much cleaner than the old way.
-       Unified hfs_iget by shifting scheme-dependent code into a function
-               pointer in the superblock.  This could/should be shifted to
-               a VFS read_inode() routine if that can be done cleanly.
-       Probably lots of other changes; I've lost track.
-
-Nov 05, 1995: version 0.5.3 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       NOT AN OFFICIAL RELEASE
-       1.2.x compatibility removed
-       Added lots of comments to btree.c and cleanup some code.  The result
-               is that the source file doubled in size while the object
-               file dropped in size by 20%.
-       Added some comments to super.c and dir.c as well.
-       Cleaned up some stuff in dir.c adding some additional error checking
-               and moving closer to using a unified hfs_iget by migrating
-               common code into lookup_parent().
-       Changed btree.c to use a separate bnode cache per filesystem.
-       Renamed a bunch of the bnode functions in btree.c
-
-Jun 29, 1995: version 0.5.2 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       BUG FIX and 1.3.x-compatibility release.
-       Will compile under 1.2.x or 1.3.x by changing one line in Makefile.
-       Started adding magic numbers to structures for "safety".
-       Don't strip internal symbols when linking or loading, as this made
-               good bug reports rather difficult.
-       Fixed a bug that could cause the fs to lock-up after trying to open
-               a non-existent file.
-       Fixed a bug that allowed files to appear truncated, when in fact it
-               is still not possible to truncate a file.
-       Added more/better comments to header files.
-       Deal with volume and b-tree bitmaps in preparation for writing.
-       Fixed readdir() to deal properly with the case where the directory
-               changes while writing to user-space. (which can't yet
-               actually happen, until directories are writable).
-
-Jun 23, 1995: version 0.5.1 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       BUG FIX RELEASE
-       Removed two debugging messages that didn't belong.
-       Fixed a typo that prevented modified inodes from being written to disk.
-       Added a missing line which prevented rmmod'ing sometimes.
-       Added a missing line which caused errors when modifying .finderinfo or
-               .resource under the CAP system.
-       Added a notify_change() to keep mode bits sensible, and to cause
-               changes to an inode to affect the data fork and resource fork
-               of a file together.
-
-Jun 22, 1995: version 0.5 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       Fixed a bug that was giving wrong values for i_blocks
-       Partly writable (can only 'touch' existing files, so far)
-       Removed case= mount option.  It will be back eventually.
-       Can now deal with CDROMs (and hard disks?), many thanks to
-               Holger Schemel for this work.
-       Latin-1 filename conversion also due to Holger Schemel.
-       Rewritten btree operations.
-
-Feb 28, 1995: version 0.4 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       Requires Linux >= 1.1.94: depends on changes made to asm/byteorder.h
-       Now using string comparison code donated by ARDI (see string.c)
-       Code reorganized to use data structures more like ARDI's.
-       More code reorganization to abstract the btree operations.
-       Added the fork= mount option.
-       Added AppleDouble support.  Executor, from ARDI, can now run programs
-               from HFS filesystems mounted with the HFS module.
-
-Jan 28, 1995: version 0.3 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       Major code reorganization.
-       Known for certain to work ONLY on floppies.
-       Started caching extents, so got faster on long file reads.
-       Now compiles separate from kernel tree.
-       Supports 5 filename conversion methods.
-       Supports forks, using the method from CAP.
-       All external symbols now start with HFS_ or hfs_
-
-Jan 12, 1995: version 0.2 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       Should now work on all HFS volumes, but still only tested on floppies.
-       Got smaller and faster with some code reorganization.
-       Since Linus moved htons() and friends to an asm file, should now be
-        truly endian-independent, but still only tested on Intel machines.
-       Requires Linux >= 1.1.77, since Linus moved htons().
-
-Jan 05, 1995: version 0.1 hargrove@sccm.stanford.edu (Paul H. Hargrove)
-       First release.
-       1.44Mb floppies only
-       no resource forks
-       trivial name mangling only
-       read only
-       for Linux >= 1.1.75
diff --git a/fs/hfs/FAQ.txt b/fs/hfs/FAQ.txt
deleted file mode 100644 (file)
index de76e8d..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-  Frequently Asked Questions about the HFS filesystem for
-  Linux
-  Paul H. Hargrove, hargrove@sccm.Stanford.EDU
-  version 1.0.3, 27 Apr 1997
-
-  This document provides answers to some of the most frequently asked
-  questions about the HFS filesystem for Linux.  It is currently pretty
-  rough and totally unorganized.  Corrections, additions and clarifica-
-  tions are appreciated.  The most current version of this document is
-  kept on The HFS for Linux Page <http://www-sccm.Stanford.EDU/~har-
-  grove/HFS/>.
-  ______________________________________________________________________
-
-  Table of Contents:
-
-  1.      What is this FAQ about?
-
-  2.      What is HFS?
-
-  3.      How I mount AppleShare volumes?
-
-  4.      What is the current version of the HFS filesystem.
-
-  5.      How stable is the current version?
-
-  6.      Is there a mailing list for discussion of the HFS filesystem?
-
-  7.      What version of Linux do I need to be running?
-
-  8.      Will it run on my (your processor type here)?
-
-  9.      Will it run under (your non-Linux operating system here)?
-
-  10.     Why can I mount some HFS CDROMs but not others?
-
-  11.     What does ``only 1024-char blocks implemented (512)'' mean?
-
-  12.     Why do I get a message about a bad or unknown partition table?
-
-  13.     Can I mount multiple HFS partitions from the same Macintosh
-  disk?
-
-  14.     In what ways can I write to HFS filesystems?
-
-  15.     Does the HFS filesystem work with 400 kB or 800 kB Macintosh
-  diskettes?
-
-  16.     How can I format an HFS filesystem?
-
-  17.     How can I fsck an HFS filesystem?
-
-  18.     Why do I get ``error -50'' messages from my Mac when using
-  netatalk?
-
-  19.     Why does my Macintosh show generic application and document
-  icons?
-
-  20.     How owns all the copyrights and trademarks? ;-)
-
-  20.1.   This Document
-
-  20.2.   The Software
-
-  20.3.   Trademarks
-  ______________________________________________________________________
-
-  1\b1.\b.  W\bWh\bha\bat\bt i\bis\bs t\bth\bhi\bis\bs F\bFA\bAQ\bQ a\bab\bbo\bou\but\bt?\b?
-
-  This FAQ is about the HFS filesystem for Linux, which is available in
-  two forms.  The stand-alone version (called hfs_fs) is a Linux kernel
-  loadable module implementing the Macintosh HFS filesystem.  The HFS
-  filesystem is also included in some distributions of the Linux kernel
-  source (in the directory linux/fs/hfs).  This version can be compiled
-  as a loadable module or compiled into the kernel.
-
-  Either version allows a machine running Linux to read and write disks
-  from a Macintosh (almost) as though they were native Linux disks.
-
-  2\b2.\b.  W\bWh\bha\bat\bt i\bis\bs H\bHF\bFS\bS?\b?
-
-  HFS stands for ``Hierarchical File System'' and is the filesystem used
-  by the Mac Plus and all later Macintosh models.  Earlier Macintosh
-  models used MFS (``Macintosh File System''), which is not supported.
-
-  3\b3.\b.  H\bHo\bow\bw I\bI m\bmo\bou\bun\bnt\bt A\bAp\bpp\bpl\ble\beS\bSh\bha\bar\bre\be v\bvo\bol\blu\bum\bme\bes\bs?\b?
-
-  The HFS filesystem is for mounting local filesystems only.  There is
-  an experimental afpfs by Ben Hekster heksterb@acm.org available from
-  http://www.odyssey.co.il/~heksterb/Software/afpfs/.
-
-  4\b4.\b.  W\bWh\bha\bat\bt i\bis\bs t\bth\bhe\be c\bcu\bur\brr\bre\ben\bnt\bt v\bve\ber\brs\bsi\bio\bon\bn o\bof\bf t\bth\bhe\be H\bHF\bFS\bS f\bfi\bil\ble\bes\bsy\bys\bst\bte\bem\bm.\b.
-
-  As of version 1.0.3 of this FAQ, version 0.95 is the most recent.  You
-  can always find the most recent version on The HFS for Linux Page
-  <http://www-sccm.Stanford.EDU/~hargrove/HFS/>.  Announcements of new
-  versions are made to the comp.os.linux.announce newsgroup.
-
-  5\b5.\b.  H\bHo\bow\bw s\bst\bta\bab\bbl\ble\be i\bis\bs t\bth\bhe\be c\bcu\bur\brr\bre\ben\bnt\bt v\bve\ber\brs\bsi\bio\bon\bn?\b?
-
-  Version 0.95 is considered to be ``beta'' software, so I recommend
-  making backups of anything important before you start playing.  It is
-  relatively free of bugs due to lots of testing of the previous
-  releases.
-
-  After a suitable period without new bugs the I will consider the
-  software to be ``stable'' and the version number will jump to 1.0.
-
-  6\b6.\b.  I\bIs\bs t\bth\bhe\ber\bre\be a\ba m\bma\bai\bil\bli\bin\bng\bg l\bli\bis\bst\bt f\bfo\bor\br d\bdi\bis\bsc\bcu\bus\bss\bsi\bio\bon\bn o\bof\bf t\bth\bhe\be H\bHF\bFS\bS f\bfi\bil\ble\bes\bsy\bys\bst\bte\bem\bm?\b?
-
-  There is no mailing list devoted exclusively to the HFS filesystem.
-  However, announcements of new versions are posted to the ``linux-
-  atalk'' and ``hfs-interest'' lists.  I will see bug reports sent to
-  those lists but e-mail is more reliable (hargrove@sccm.Stanford.EDU).
-
-  To subscribe to hfs-interest send e-mail with a body of ``subscribe
-  hfs-interest (your e-mail address)'' to majordomo@ccs.neu.edu.
-
-  To subscribe to linux-atalk send e-mail with a body of ``SUBSCRIBE
-  LINUX-ATALK (Your full name)'' to listserv@netspace.org.
-
-  7\b7.\b.  W\bWh\bha\bat\bt v\bve\ber\brs\bsi\bio\bon\bn o\bof\bf L\bLi\bin\bnu\bux\bx d\bdo\bo I\bI n\bne\bee\bed\bd t\bto\bo b\bbe\be r\bru\bun\bnn\bni\bin\bng\bg?\b?
-
-  To compile and use the stand-alone distribution of the HFS filesystem
-  you will need Linux kernel version 2.0.1 or newer compiled with
-  modules enabled (CONFIG_MODULES).  To compile you will need the kernel
-  headers which match the kernel you are running.  This is covered in
-  more detail in the installation instructions in INSTALL.txt.
-
-  If your kernel came with HFS in the kernel source tree then HFS should
-  work with your Linux version.  There may be small problems with a few
-  of the development kernel releases.  For these releases check the HFS
-  for Linux Page <http://www-sccm.Stanford.EDU/~hargrove/HFS/> for
-  patches.
-
-  8\b8.\b.  W\bWi\bil\bll\bl i\bit\bt r\bru\bun\bn o\bon\bn m\bmy\by (\b(y\byo\bou\bur\br p\bpr\bro\boc\bce\bes\bss\bso\bor\br t\bty\byp\bpe\be h\bhe\ber\bre\be)\b)?\b?
-
-  The code is carefully written to be independent of your processor's
-  word size and byte-order, so if your machine runs Linux it can run the
-  HFS filesystem.  However some younger ports don't yet have support for
-  loadable modules.
-
-  Note that HFS is tested most extensively on Intel platforms.  So there
-  could be subtle compilation problems on other platforms.  If you
-  encounter any that are not addressed by the documentation then please
-  let me know.
-
-  9\b9.\b.  W\bWi\bil\bll\bl i\bit\bt r\bru\bun\bn u\bun\bnd\bde\ber\br (\b(y\byo\bou\bur\br n\bno\bon\bn-\b-L\bLi\bin\bnu\bux\bx o\bop\bpe\ber\bra\bat\bti\bin\bng\bg s\bsy\bys\bst\bte\bem\bm h\bhe\ber\bre\be)\b)?\b?
-
-  No.  There is a port in progress to NetBSD.  I know of no other active
-  porting attempts.  If you are interested in porting the HFS filesystem
-  to another Unix-like operating system, I am interested in providing
-  what guidance I can.
-
-  1\b10\b0.\b.  W\bWh\bhy\by c\bca\ban\bn I\bI m\bmo\bou\bun\bnt\bt s\bso\bom\bme\be H\bHF\bFS\bS C\bCD\bDR\bRO\bOM\bMs\bs b\bbu\but\bt n\bno\bot\bt o\bot\bth\bhe\ber\brs\bs?\b?
-
-  In the past there was a known incompatibility with some ``hybrid''
-  CDROMs that appear as HFS disks on Macs and as ISO9660 disks on other
-  systems.  I think I have fixed the problem.  So, if you encounter this
-  particular problem or have problems with specific non-hybrid CDROMs
-  please e-mail me with the title and manufacturer of the CD.
-
-  1\b11\b1.\b.  W\bWh\bha\bat\bt d\bdo\boe\bes\bs `\b``\b`o\bon\bnl\bly\by 1\b10\b02\b24\b4-\b-c\bch\bha\bar\br b\bbl\blo\boc\bck\bks\bs i\bim\bmp\bpl\ble\bem\bme\ben\bnt\bte\bed\bd (\b(5\b51\b12\b2)\b)'\b''\b' m\bme\bea\ban\bn?\b?
-
-  This message comes from the kernel and indicates that an attempt was
-  made to read a 512-byte block from a device that doesn't support
-  512-byte blocks.  The HFS filesystem only works with 512-byte blocks,
-  and therefore doesn't function with these devices.  Eventually it may
-  be able to use 1024-byte (or even 2048-byte) blocks when necessary.
-  Ideally the device driver should be enhanced to support 512-byte
-  blocks so that the various filesystems which need 512-byte blocks
-  don't each need to work around it.
-
-  1\b12\b2.\b.  W\bWh\bhy\by d\bdo\bo I\bI g\bge\bet\bt a\ba m\bme\bes\bss\bsa\bag\bge\be a\bab\bbo\bou\but\bt a\ba b\bba\bad\bd o\bor\br u\bun\bnk\bkn\bno\bow\bwn\bn p\bpa\bar\brt\bti\bit\bti\bio\bon\bn t\bta\bab\bbl\ble\be?\b?
-
-  If your Linux kernel doesn't understand Macintosh partition tables it
-  gives this warning when it can't find a partition table it recognizes.
-  To support partitioned media with such kernels, decoding of Mac
-  partition tables is done by the HFS filesystem so you should still be
-  able to mount the disk.  However, to do so you will need to mount the
-  raw device (such as /dev/sdb instead of /dev/sdb4) and use the part
-  mount option to indicate which partition you want.
-
-  1\b13\b3.\b.  C\bCa\ban\bn I\bI m\bmo\bou\bun\bnt\bt m\bmu\bul\blt\bti\bip\bpl\ble\be H\bHF\bFS\bS p\bpa\bar\brt\bti\bit\bti\bio\bon\bns\bs f\bfr\bro\bom\bm t\bth\bhe\be s\bsa\bam\bme\be M\bMa\bac\bci\bin\bnt\bto\bos\bsh\bh d\bdi\bis\bsk\bk?\b?
-
-  Only if your kernel understands Macintosh partition tables.  It the
-  kernel doesn't understand the Macintosh partition table, the HFS
-  filesystem must access the raw device.  Therefore, the kernel thinks
-  the entire drive is in use and prevents additional mounts on it.
-
-  1\b14\b4.\b.  I\bIn\bn w\bwh\bha\bat\bt w\bwa\bay\bys\bs c\bca\ban\bn I\bI w\bwr\bri\bit\bte\be t\bto\bo H\bHF\bFS\bS f\bfi\bil\ble\bes\bsy\bys\bst\bte\bem\bms\bs?\b?
-
-  The HFS filesystem is as capable as the MS-DOS or VFAT filesystems,
-  except that certain things can only be done with a file's data fork.
-
-  You c\bca\ban\bn:
-
-  +\bo  Create, delete and rename directories and data forks of files with
-     the caveat that names are case insensitive (so foo and Foo are the
-     same file or directory).
-
-  +\bo  Run Linux executables or shared libraries on an HFS disk if they
-     are stored in the data fork of a file.
-
-  +\bo  Read, write and truncate both forks of files and the Finder's
-     metadata of files and directories.
-
-  +\bo  Mmap data forks of files (and the resource fork if the filesystem
-     is mounted with the fork=cap option).
-
-  +\bo  Toggle the 'w' permission bits (as a group) of data forks.
-
-  +\bo  Change the i_mtime of files and directories.
-
-  You c\bca\ban\bnn\bno\bot\bt:
-
-  +\bo  Create, delete or rename resource forks of files or the Finder's
-     metadata.  Note, however, that they are created (with defaults
-     values), deleted and renamed along with the corresponding data fork
-     or directory.
-
-  +\bo  Run Linux executables or shared libraries on an HFS disk if they
-     are stored in the resource fork of a file.
-
-  +\bo  Mmap the Finder's metadata (when fork=cap) or AppleDouble header
-     files (when fork=double or fork=netatalk).
-
-  +\bo  Change permissions on directories.
-
-  +\bo  Change the uid or gid of files or directories.
-
-  +\bo  Set the set-uid, set-gid or sticky permission bits.
-
-  +\bo  Create multiple links to files.
-
-  +\bo  Create symlinks, device files, sockets or FIFOs.
-
-  1\b15\b5.\b.  D\bDo\boe\bes\bs t\bth\bhe\be H\bHF\bFS\bS f\bfi\bil\ble\bes\bsy\bys\bst\bte\bem\bm w\bwo\bor\brk\bk w\bwi\bit\bth\bh 4\b40\b00\b0k\bk o\bor\br 8\b80\b00\b0k\bk M\bMa\bac\bci\bin\bnt\bto\bos\bsh\bh
-  d\bdi\bis\bsk\bke\bet\btt\bte\bes\bs?\b?
-
-  Yes and no.  The software is fully capable of dealing with HFS disks
-  of any size.  However, the 400k and 800k diskettes are written in a
-  physical format that is incompatible with most non-Macintosh floppy
-  drives.  Note also that almost all 400k Macintosh diskettes are MFS,
-  not HFS.
-
-  1\b16\b6.\b.  H\bHo\bow\bw c\bca\ban\bn I\bI f\bfo\bor\brm\bma\bat\bt a\ban\bn H\bHF\bFS\bS f\bfi\bil\ble\bes\bsy\bys\bst\bte\bem\bm?\b?
-
-  Robert Leslie (rob@mars.org) has written a package for working with
-  HFS filesystems (like mtools plus a graphical interface).  One program
-  in the package is hformat which can format HFS filesystems.  The
-  latest version can be found on the HFS Utilities home page
-  <http://www.mars.org/home/rob/proj/hfs/>.
-
-  1\b17\b7.\b.  H\bHo\bow\bw c\bca\ban\bn I\bI f\bfs\bsc\bck\bk a\ban\bn H\bHF\bFS\bS f\bfi\bil\ble\bes\bsy\bys\bst\bte\bem\bm?\b?
-
-  Right now you'll have to use a Macintosh to do this.  However, Rob
-  Leslie is working on an fsck for HFS filesystems.
-
-  1\b18\b8.\b.  W\bWh\bhy\by d\bdo\bo I\bI g\bge\bet\bt `\b``\b`e\ber\brr\bro\bor\br -\b-5\b50\b0'\b''\b' m\bme\bes\bss\bsa\bag\bge\bes\bs f\bfr\bro\bom\bm m\bmy\by M\bMa\bac\bc w\bwh\bhe\ben\bn u\bus\bsi\bin\bng\bg
-  n\bne\bet\bta\bat\bta\bal\blk\bk?\b?
-
-  To be compatible with netatalk's afpd you will need to use netatalk
-  version 1.4b1 or newer and mount the HFS filesystem with the ``afpd''
-  mount option.  More information is provided in the ``afpd'' subsection
-  of the ``Mount Options'' section of the HFS documentation (HFS.txt if
-  you have the stand-alone HFS distribution or
-  linux/Documentation/filesystems/hfs.txt if HFS is in your kernel
-  source tree.)
-
-  1\b19\b9.\b.  W\bWh\bhy\by d\bdo\boe\bes\bs m\bmy\by M\bMa\bac\bci\bin\bnt\bto\bos\bsh\bh s\bsh\bho\bow\bw g\bge\ben\bne\ber\bri\bic\bc a\bap\bpp\bpl\bli\bic\bca\bat\bti\bio\bon\bn a\ban\bnd\bd d\bdo\boc\bcu\bum\bme\ben\bnt\bt
-  i\bic\bco\bon\bns\bs?\b?
-
-  When using the ``afpd'' mount option the Desktop database on the disk
-  is not made available to Netatalk's afpd.  Because of this mounting an
-  HFS filesystem across the network to a Macintosh may result in the
-  Finder showing generic application and document icons.  Additionally
-  double clicking on a document will fail to start the correct
-  application.
-
-  If the disk is writable you can make Netatalk build a new Desktop
-  database in its own format by holding down the Option key while
-  selecting the volume in the Chooser.  If the disk is not writable then
-  these problems can be worked around by copying the application to a
-  local disk on the Macintosh.
-
-  2\b20\b0.\b.  H\bHo\bow\bw o\bow\bwn\bns\bs a\bal\bll\bl t\bth\bhe\be c\bco\bop\bpy\byr\bri\big\bgh\bht\bts\bs a\ban\bnd\bd t\btr\bra\bad\bde\bem\bma\bar\brk\bks\bs?\b? ;\b;-\b-)\b)
-
-  2\b20\b0.\b.1\b1.\b.  T\bTh\bhi\bis\bs D\bDo\boc\bcu\bum\bme\ben\bnt\bt
-
-  This document is Copyright (c) 1996, 1997 by Paul H. Hargrove.
-
-  Permission is granted to make and distribute verbatim copies of this
-  document provided the copyright notice and this permission notice are
-  preserved on all copies.
-
-  Permission is granted to copy and distribute modified versions of this
-  document under the conditions for verbatim copies above, provided a
-  notice clearly stating that the document is a modified version is also
-  included in the modified document.
-
-  Permission is granted to copy and distribute translations of this
-  document into another language, under the conditions specified above
-  for modified versions.
-
-  Permission is granted to convert this document into another media
-  under the conditions specified above for modified versions provided
-  the requirement to acknowledge the source document is fulfilled by
-  inclusion of an obvious reference to the source document in the new
-  media. Where there is any doubt as to what defines ``obvious'' the
-  copyright owner reserves the right to decide.
-
-  2\b20\b0.\b.2\b2.\b.  T\bTh\bhe\be S\bSo\bof\bft\btw\bwa\bar\bre\be
-
-  The HFS filesystem software is Copyright (c) 1994-1997 by Paul H.
-  Hargrove.
-
-  The software is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2, or (at your option)
-  any later version.
-
-  The software is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with the software in the file ``COPYING''; if not, write to the
-  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
-  USA.
-
-  2\b20\b0.\b.3\b3.\b.  T\bTr\bra\bad\bde\bem\bma\bar\brk\bks\bs
-
-  +\bo  ``Finder'' is a trademark of Apple Computer, Inc.
-
-  +\bo  ``Apple'', ``AppleShare'', and ``Macintosh'' are registered
-     trademarks of Apple Computer, Inc.
-
-  +\bo  ``MS-DOS'' is a registered trademarks of Microsoft Corporation.
-
-  +\bo  All other trademarks are the property of their respective owners.
-
diff --git a/fs/hfs/HFS.txt b/fs/hfs/HFS.txt
deleted file mode 100644 (file)
index 5c1ae5f..0000000
+++ /dev/null
@@ -1,1042 +0,0 @@
-  Macintosh HFS Filesystem for Linux
-  Paul H. Hargrove, hargrove@sccm.Stanford.EDU
-  version 0.95, 28 Apr 1997
-
-  This document describes version 0.95 of the Macintosh HFS filesystem
-  for Linux.  The most current versions of this document and the
-  software are kept at The HFS for Linux Page
-  <http://www-sccm.Stanford.EDU/~hargrove/HFS/>.
-  ______________________________________________________________________
-
-  Table of Contents:
-
-  1.      Introduction
-
-  2.      Mounting HFS Filesystems
-
-  2.1.    afpd
-
-  2.2.    case={asis, lower}
-
-  2.3.    conv={auto, binary, text}
-
-  2.4.    creator=cccc
-
-  2.5.    fork={cap, double, netatalk}
-
-  2.6.    gid=n
-
-  2.7.    names={7bit, 8bit, alpha, cap, latin, netatalk, trivial}
-
-  2.8.    part=n
-
-  2.9.    quiet
-
-  2.10.   type=cccc
-
-  2.11.   uid=n
-
-  2.12.   umask=n
-
-  3.      Writing to HFS Filesystems
-
-  3.1.    Writing with fork=cap
-
-  3.2.    Writing with fork=double
-
-  3.3.    Writing with fork=netatalk
-
-  4.      A Guide to Special File Formats
-
-  4.1.    CAP .finderinfo Files
-
-  4.2.    AppleDouble Header Files
-
-  5.      Reporting Bugs
-
-  5.1.    What Goes in a Bug Report
-
-  5.2.    How to Report a Kernel Oops or GPF
-
-  6.      Legal Notices
-
-  6.1.    This Document
-
-  6.2.    The Software
-
-  6.2.1.  The Columbia AppleTalk Package for UNIX
-
-  6.2.2.  Netatalk
-
-  6.3.    Trademarks
-  ______________________________________________________________________
-
-  1\b1.\b.  I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn
-
-  This software implements the Macintosh HFS filesystem under Linux.  It
-  allows you to read and write HFS filesystems on floppy disks, CDROMs,
-  hard drives, ZIP drives, etc.  It is _\bn_\bo_\bt an AppleShare client.
-
-  If you use this software, please send me a note telling of your
-  success or failure with it.  Your feedback lets me know that this
-  project is not a waste of my time.
-
-  This code is still experimental, so backup anything important before
-  you start playing.  I'd like you to know that I've never lost any
-  files while using this software, or I would not release it.  However,
-  a ``better safe than sorry'' attitude is probably best.
-
-  If, for instance, the buffer cache were to become corrupted you could
-  start losing things on other disks.  Because of this, if you get a
-  General Protection Fault, or a kernel Oops, I _\bs_\bt_\br_\bo_\bn_\bg_\bl_\by recommend that
-  you reboot before writing any files.
-
-  2\b2.\b.  M\bMo\bou\bun\bnt\bti\bin\bng\bg H\bHF\bFS\bS F\bFi\bil\ble\bes\bsy\bys\bst\bte\bem\bms\bs
-
-  Once you have the HFS filesystem compiled into the kernel or installed
-  as a loadable module, you will be able to use hfs as a filesystem type
-  option to mount.  For instance, to mount a Macintosh floppy disk on
-  the directory /mnt using the default mount options you would execute
-  ``mount -t hfs /dev/fd0 /mnt''.
-
-  The remainder of this section describes the several mount options
-  available to control how the HFS filesystem is mapped onto a Linux
-  filesystem structure.  The values for the multiple-choice options
-  (case, conv, fork and names) can be abbreviated by their first
-  character.
-
-  2\b2.\b.1\b1.\b.  a\baf\bfp\bpd\bd
-
-  If included in the options, then the behavior of the filesystem is
-  changed to make it fully read-write compatible with Netatalk's afpd.
-  In this mode you should not use normal user-level tools to modify the
-  filesystem, though reading from it is acceptable.  This is because the
-  return codes from some system calls are changed to fool afpd.  These
-  changes will confuse many user-level tools.  In particular ``rm -r''
-  will loop forever.
-
-  This option implies fork=netatalk, which in turn implies
-  names=netatalk.  If either of these options are explicitly set to
-  something else they will take precedence and will confuse afpd.  The
-  quiet option has no effect.  The case= option functions normally, but
-  afpd usually does the same thing for you.  The conv= and part= options
-  also function normally.
-
-  You will probably want to use the uid=, gid= and umask= mount options.
-  Note that because all the files on an HFS filesystem belong to a
-  single user and group and have a single umask, the full AppleShare
-  permission scheme will not work through Netatalk.
-
-  One additional limitation is that the Desktop database on the disk is
-  stored in afpd's format and is separate from any existing database
-  maintained by the Finder when the volume is used on a Macintosh.
-  Because of this mounting an HFS CDROM across the network to a
-  Macintosh may result in applications and documents showing up with
-  default application and document icons.  Additionally double clicking
-  on a document will fail to start the correct application.  Both of
-  these problems can be worked around by copying the application to a
-  local disk on the Macintosh.
-
-  This mode is known to be compatible with afpd from Netatalk versions
-  1.4b1 and 1.4b2, and known to be incompatible with the afpd from
-  version 1.3.3.  As of this writing Netatalk version 1.4 has not yet
-  been released.  However, it is expected that this mode will be
-  compatible with afpd from Netatalk version 1.4 when it is released.
-
-  2\b2.\b.2\b2.\b.  c\bca\bas\bse\be=\b={\b{a\bas\bsi\bis\bs,\b, l\blo\bow\bwe\ber\br}\b}
-
-  default value: asis
-
-  This option determines if Macintosh filenames are presented in their
-  original case or in all lowercase.  Filename lookup is always case
-  insensitive, so either way foo and Foo refer to the same file but ls
-  will list Foo with case=asis, and foo with case=lower.  (Same as for
-  the HPFS filesystem.)
-
-     a\bas\bsi\bis\bs
-        Filenames are reported in the case they were created with.
-
-     l\blo\bow\bwe\ber\br
-        Filenames are reported in lowercase.
-
-  2\b2.\b.3\b3.\b.  c\bco\bon\bnv\bv=\b={\b{a\bau\but\bto\bo,\b, b\bbi\bin\bna\bar\bry\by,\b, t\bte\bex\bxt\bt}\b}
-
-  default value: binary
-
-  This option controls CR<->NL conversion of Macintosh _\bd_\ba_\bt_\ba _\bf_\bo_\br_\bk_\bs.  Any
-  translation takes place only for files accessed with the read() and
-  write() system calls (either directly or through the stdio functions).
-  Access through mmap() is unaffected.  (Similar to the conv= option for
-  the MS-DOS filesystem.)
-
-     a\bau\but\bto\bo
-        If the Finder's type for a file is TEXT or ttro, then CR
-        characters are converted to NL characters when read, and NL
-        characters are converted to CR characters when written.
-
-        Be warned that some Macintosh applications create files with
-        type TEXT even though the contents is clearly binary.
-
-     b\bbi\bin\bna\bar\bry\by
-        No CR<->NL conversion is done.
-
-     t\bte\bex\bxt\bt
-        In all data forks, regardless of the Finder's type for the file,
-        CR characters are converted to NL characters when read, and NL
-        characters are converted to CR characters when written.
-
-  2\b2.\b.4\b4.\b.  c\bcr\bre\bea\bat\bto\bor\br=\b=c\bcc\bcc\bcc\bc
-
-  default value: ``????''
-
-  Specifies the 4-character string specifying the Finder's Creator for
-  new files.
-
-  2\b2.\b.5\b5.\b.  f\bfo\bor\brk\bk=\b={\b{c\bca\bap\bp,\b, d\bdo\bou\bub\bbl\ble\be,\b, n\bne\bet\bta\bat\bta\bal\blk\bk}\b}
-
-  default value: cap
-
-  This option determines how resource forks and the Finder's metadata
-  are represented within the structure of the Linux filesystem.
-
-     c\bca\bap\bp
-        The scheme used by the Columbia AppleTalk Package's AUFS.
-
-        Associated with each directory are two special directories and a
-        metadata file.  The directory ./bar is represented by:
-
-        .\b./\b/b\bba\bar\br
-           The directory itself, containing subdirectories, the data
-           forks of files, and the following two special directories.
-
-        .\b./\b/b\bba\bar\br/\b/.\b.r\bre\bes\bso\bou\bur\brc\bce\be
-           A special directory holding resource forks of the files in
-           ./bar.
-
-        .\b./\b/b\bba\bar\br/\b/.\b.f\bfi\bin\bnd\bde\ber\bri\bin\bnf\bfo\bo
-           A special directory holding metadata files for the files and
-           subdirectories in ./bar.
-
-        .\b./\b/.\b.f\bfi\bin\bnd\bde\ber\bri\bin\bnf\bfo\bo/\b/b\bba\bar\br
-           The metadata file for the directory ./bar.
-
-        The files in a directory are represented as three files:
-
-        .\b./\b/f\bfo\boo\bo
-           The data fork of the file ./foo.
-
-        .\b./\b/.\b.r\bre\bes\bso\bou\bur\brc\bce\be/\b/f\bfo\boo\bo
-           The resource fork of the file ./foo.
-
-        .\b./\b/.\b.f\bfi\bin\bnd\bde\ber\bri\bin\bnf\bfo\bo/\b/f\bfo\boo\bo
-           The metadata file for the file ./foo.
-
-        Additionally, the file .rootinfo in the root directory of the
-        HFS filesystem is a metadata file for the root directory.
-
-        Brief documentation on the format of file containing the
-        Finder's metadata is included in the section ``A Guide to
-        Special File Formats'' in this document.  More detailed
-        information is available in the Columbia AppleTalk Package.
-
-     d\bdo\bou\bub\bbl\ble\be
-        The ``AppleDouble'' format recommended by Apple.  (Apple's other
-        recommended format, ``AppleSingle'', is not yet implemented.)
-
-        Associated with each directory is an AppleDouble ``header
-        file''.  The directory ./bar is represented by:
-
-        .\b./\b/b\bba\bar\br
-           The directory itself, containing subdirectories, the data
-           forks for files, and the header files for files and
-           subdirectories.
-
-        .\b./\b/%\b%b\bba\bar\br
-           The header file for the directory ./bar, containing the
-           Finder's metadata for the directory.
-
-        The files in a directory are represented as two files:
-
-        .\b./\b/f\bfo\boo\bo
-           The data fork of the file ./foo.
-
-        .\b./\b/%\b%f\bfo\boo\bo
-           The header file for the file ./foo, containing the resource
-           fork and the Finder's metadata for the file.
-
-        Additionally, the file %RootInfo in the root directory of the
-        HFS filesystem is a header file for the root directory.  This is
-        not quite the %RootInfo file referred to in the AppleDouble
-        specification.
-
-        The header files used in this scheme are version 2 AppleDouble
-        header files.  Their format is described briefly in the section
-        ``A Guide to Special File Formats'' in this document.  They are
-        documented in detail in ``AppleSingle/AppleDouble Formats:
-        Developer's Note (9/94)'', available from Apple's Developer
-        Services Page <http://devworld.apple.com>.
-
-        Note that the naming convention for the header file can cause
-        name conflicts.  For instance, using Apple's 7-bit ASCII name
-        conversion (see the names mount option) the name %Desktop could
-        be interpreted either as the header file for the file Desktop or
-        as the file with 0xDE as the hexadecimal representation of its
-        first character, and "sktop" as the remaining 5 characters.  The
-        problem arises when both files exist, since only one will be
-        accessible.  The behavior of the HFS filesystem in the case of
-        such a conflict is undefined, and may change in future releases.
-        (If this causes problems for you, please don't report it as a
-        bug; I didn't design this ``standard'', Apple did.)
-
-     n\bne\bet\bta\bat\bta\bal\blk\bk
-        The scheme used by the Netatalk afpd.
-
-        Associated with each directory is a special directory and a
-        metadata file.  The directory ./bar is represented by:
-
-        .\b./\b/b\bba\bar\br
-           The directory itself, containing subdirectories, the data
-           forks of files, and the following special directory.
-
-        .\b./\b/b\bba\bar\br/\b/.\b.A\bAp\bpp\bpl\ble\beD\bDo\bou\bub\bbl\ble\be
-           A special directory holding AppleDouble header files for
-           ./bar and the files it contains, but not for the
-           subdirectories it contains.
-
-        .\b./\b/b\bba\bar\br/\b/.\b.A\bAp\bpp\bpl\ble\beD\bDo\bou\bub\bbl\ble\be/\b/.\b.P\bPa\bar\bre\ben\bnt\bt
-           The header file for the directory ./bar, containing the
-           Finder's metadata for the directory.
-
-        The files in a directory are represented as two files:
-
-        .\b./\b/f\bfo\boo\bo
-           The data fork of the file ./foo.
-
-        .\b./\b/.\b.A\bAp\bpp\bpl\ble\beD\bDo\bou\bub\bbl\ble\be/\b/f\bfo\boo\bo
-           The header file for file ./foo, containing the resource fork
-           and the Finder's metadata.
-
-        The header files used in this scheme are version 1 AppleDouble
-        header files.  They are described briefly in the section ``A
-        Guide to Special File Formats'' in this document.  The format is
-        documented in detail in the ``Apple II File Type Notes'' under
-        the type ``$E0.0002/$E0.0003-AppleDouble'', and in Appendix B of
-        the ``A/UX Toolbox: Macintosh ROM Interface'' manual.
-
-  2\b2.\b.6\b6.\b.  g\bgi\bid\bd=\b=n\bn
-
-  default value: gid of the mounting process
-
-  Specifies the group that owns all files and directories on the
-  filesystem.  (Same as for the MS-DOS and HPFS filesystems.)
-
-  2\b2.\b.7\b7.\b.  n\bna\bam\bme\bes\bs=\b={\b{7\b7b\bbi\bit\bt,\b, 8\b8b\bbi\bit\bt,\b, a\bal\blp\bph\bha\ba,\b, c\bca\bap\bp,\b, l\bla\bat\bti\bin\bn,\b, n\bne\bet\bta\bat\bta\bal\blk\bk,\b, t\btr\bri\biv\bvi\bia\bal\bl}\b}
-
-  default value: varies as follows
-
-  +\bo  If the fork option is set to double, then names defaults to alpha.
-
-  +\bo  If the fork option is set to netatalk, then names defaults to
-     netatalk.
-
-  +\bo  If the fork option is set to cap (or has taken that value by
-     default), then names defaults to cap.
-
-  This option determines how to convert between valid Macintosh
-  filenames and valid Linux filenames.  The 7bit, 8bit and alpha options
-  correspond to Apple's recommended conventions named ``7-bit ASCII'',
-  ``8-bit'' and ``7-bit alphanumeric''.
-
-     7\b7b\bbi\bit\bt
-        When converting from Macintosh filenames to Linux filenames the
-        NULL (0x00), slash (/) and percent (%) characters and the
-        extended 8-bit characters (hexadecimal codes 0x80-0xff) are
-        replaced by a percent character (%) followed by the two-digit
-        hexadecimal code for the character.
-
-        When converting from Linux filenames to Macintosh filenames the
-        string "%YZ" is replaced by the character with hexadecimal code
-        0xYZ.  If 0xYZ is not a valid hexadecimal number or is the code
-        for NULL or colon (:) then the string "%YZ" is unchanged.  A
-        colon (:) is replaced by a pipe character (|).
-
-     8\b8b\bbi\bit\bt
-        When converting from Macintosh filenames to Linux filenames the
-        NULL (0x00), slash (/) and percent (%) characters are replaced
-        by a percent character (%) followed by the two-digit hexadecimal
-        code for the character.
-
-        When converting from Linux filenames to Macintosh filenames the
-        string "%YZ" is replaced by the character with hexadecimal code
-        0xYZ.  If 0xYZ is not a valid hexadecimal number or is the code
-        for NULL or colon (:) then the string "%YZ" is unchanged.  A
-        colon (:) is replaced by a pipe character (|).
-
-     a\bal\blp\bph\bha\ba
-        When converting from Macintosh filenames to Linux filenames only
-        the alphanumeric characters (a-z, A-Z and 0-9), the underscore
-        (_) and the last period (.) in the filename are unchanged.  The
-        remaining characters are replaced by a percent character (%)
-        followed by the two-digit hexadecimal code for the character.
-
-        When converting from Linux filenames to Macintosh filenames the
-        string "%YZ" is replaced by the character with hexadecimal code
-        0xYZ.  If 0xYZ is not a valid hexadecimal number or is the code
-        for NULL or colon (:) then the string "%YZ" is unchanged.  A
-        colon (:) is replaced by a pipe character (|).
-
-     c\bca\bap\bp
-        The convention used by the Columbia AppleTalk Package's AUFS.
-
-        When converting from Macintosh filenames to Linux filenames the
-        characters from space ( ) through tilde (~) (ASCII 32-126) are
-        unchanged, with the exception of slash (/).  The slash (/) and
-        all characters outside the range 32-126 are replaced by a colon
-        (:) followed by the two-digit hexadecimal code for the
-        character.
-
-        When converting from Linux filenames to Macintosh filenames the
-        string ":YZ" is replaced by the character with hexadecimal code
-        0xYZ.  If 0xYZ is not a valid hexadecimal number or is the code
-        for NULL or colon (:) then the colon is replaced by a pipe
-        character (|).
-
-     l\bla\bat\bti\bin\bn
-        When converting from Macintosh filenames to Linux filenames the
-        characters from space ( ) through tilde (~) (ASCII 32-126) are
-        unchanged, with the exception of slash (/) and percent (%).  The
-        extended 8-bit Macintosh characters with equivalents in the
-        Latin-1 character set are replaced by those equivalents.  The
-        remaining characters are replaced by a percent character (%)
-        followed by the two-digit hexadecimal code for the character.
-
-        When converting from Linux filenames to Macintosh filenames the
-        string "%YZ" is replaced by the character with hexadecimal code
-        0xYZ.  If 0xYZ is not a valid hexadecimal number or is the code
-        for NULL or colon (:) then the string "%YZ" is unchanged. The
-        Latin-1 characters with equivalents in the extended 8-bit
-        Macintosh character set are replaced by those equivalents.  A
-        colon (:) is replaced by a pipe character (|).
-
-        Thanks to Holger Schemel (aeglos@valinor.owl.de) for
-        contributing this conversion mode.
-
-     n\bne\bet\bta\bat\bta\bal\blk\bk
-        The convention used by the Netatalk afpd.
-
-        When converting from Macintosh filenames to Linux filenames the
-        characters from space ( ) through tilde (~) (ASCII 32-126) are
-        unchanged, with the exception of slash (/) and any initial
-        period (.).  The slash (/) and any initial period (.)  and all
-        characters outside the range 32-126 are replaced by a colon (:)
-        followed by the two-digit hexadecimal code for the character.
-
-        When converting from Linux filenames to Macintosh filenames the
-        string ":YZ" is replaced by the character with hexadecimal code
-        0xYZ.  If 0xYZ is not a valid hexadecimal number or is the code
-        for NULL or colon (:) then the colon is replaced by a pipe
-        character (|).
-
-     t\btr\bri\biv\bvi\bia\bal\bl
-        When converting from Macintosh filenames to Linux filenames a
-        slash character (/) is replaced by a colon (:).
-
-        When converting from Linux filenames to Macintosh filenames a
-        colon (:) is replaced by a slash character (/).
-
-  2\b2.\b.8\b8.\b.  p\bpa\bar\brt\bt=\b=n\bn
-
-  default value: 0
-
-  Specifies which HFS partition to mount from a Macintosh CDROM or hard
-  drive.  Partitions are numbered from 0 and count only those identified
-  in the partition table as containing HFS filesystems.  This option is
-  only useful when the Linux platform doesn't fully support Macintosh
-  partition tables.  In particular on MkLinux and Linux-Pmac this option
-  is useless.
-
-  Note that in versions before 0.8.3 partitions were numbered from 1.
-
-  2\b2.\b.9\b9.\b.  q\bqu\bui\bie\bet\bt
-
-  If included in the options, then chown and chmod operations will not
-  return errors, but will instead fail silently.  (Same as for the MS-
-  DOS and HPFS filesystems.)
-
-  2\b2.\b.1\b10\b0.\b.  t\bty\byp\bpe\be=\b=c\bcc\bcc\bcc\bc
-
-  default value: ``????''
-
-  Specifies the 4-character string specifying the Finder's Type for new
-  files.
-
-  2\b2.\b.1\b11\b1.\b.  u\bui\bid\bd=\b=n\bn
-
-  default value: uid of the mounting process
-
-  Specifies the user that owns all files and directories on the
-  filesystem.  (Same as for the MS-DOS and HPFS filesystems.)
-
-  2\b2.\b.1\b12\b2.\b.  u\bum\bma\bas\bsk\bk=\b=n\bn
-
-  default value: umask of the mounting process
-
-  Specifies (in octal) the umask used for all files and directories.
-  (Same as for the MS-DOS and HPFS filesystems.)
-
-  3\b3.\b.  W\bWr\bri\bit\bti\bin\bng\bg t\bto\bo H\bHF\bFS\bS F\bFi\bil\ble\bes\bsy\bys\bst\bte\bem\bms\bs
-
-  Each of the values of the fork mount option yields a different
-  representation of the Macintosh-specific parts of a file within the
-  structure of the Linux filesystem.  There are, therefore, slightly
-  different steps involved in copying files if you want to preserve the
-  resource forks and the Finder's metadata.
-
-  It is important to remember not to use normal user-level tools to
-  modify a filesystem mounted with the afpd mount option.
-
-  Regardless of the value of the fork mount option you can do virtually
-  everything to the data fork of a file that you can to a file on any
-  other filesystem.  The limitations are essentially the same as those
-  imposed by the MS-DOS filesystem:
-
-  +\bo  You can't change the uid or gid of files.
-
-  +\bo  You can't set the set-uid, set-gid or sticky permission bits.
-
-  +\bo  You can't clear the execute permission bits.
-
-  Likewise you can do virtually everything to a directory that you can
-  to a directory on another file system with the following exceptions:
-
-  +\bo  You can't create, delete or rename resource forks of files or the
-     Finder's metadata.  Note, however, that they are created (with
-     defaults values), deleted and renamed along with the corresponding
-     data fork or directory.
-
-  +\bo  You can't change permissions on directories.
-
-  +\bo  You can't change the uid or gid of directories.
-
-  +\bo  You can't create multiple links to files.
-
-  +\bo  You can't create symlinks, device files, sockets or FIFOs.
-
-  3\b3.\b.1\b1.\b.  W\bWr\bri\bit\bti\bin\bng\bg w\bwi\bit\bth\bh f\bfo\bor\brk\bk=\b=c\bca\bap\bp
-
-  Unlike the other schemes for representing forked files, the CAP scheme
-  presents the resource fork as an independent file; the resource fork
-  of ./foo is ./.resource/foo.  Therefore, you can treat it as a normal
-  file.  You can do anything to a resource fork that you can do to a
-  data fork, except that you cannot enable execute permissions on a
-  resource fork.  Therefore, resource forks are not suitable for holding
-  Linux executables or shared libraries.
-
-  If you plan to use the resource fork on a Macintosh then you must obey
-  the format of a valid resource fork.  This format is documented in
-  Chapter 1 of Apple's _\bI_\bn_\bs_\bi_\bd_\be _\bM_\ba_\bc_\bi_\bn_\bt_\bo_\bs_\bh_\b: _\bM_\bo_\br_\be _\bM_\ba_\bc_\bi_\bn_\bt_\bo_\bs_\bh _\bT_\bo_\bo_\bl_\bb_\bo_\bx.  The
-  filesystem knows nothing about this format and so does nothing to
-  enforce it.
-
-  The current support for reading and writing is sufficient to allow
-  copying of entire directories with tar, as long as both the source and
-  destination are mounted with fork=cap.  tar may complain about being
-  unable to change the uid, gid or mode of files.  This is normal and is
-  an unavoidable side effect of the having a single uid, gid and umask
-  for the entire filesystem.
-
-  It is impossible to create a resource fork or a Finder metadata file.
-  However, they are created automatically when the data fork is created.
-  Therefore, if you wish to copy a single file including both forks and
-  the Finder's metadata then you must create the data fork first.  Then
-  you can copy the resource fork and the Finder's metadata.  For
-  instance to copy the file foo to dir/bar you should do the following:
-
-  1. cp foo dir/bar
-
-  2. cp .resource/foo dir/.resource/bar
-
-  3. cp .finderinfo/foo dir/.finderinfo/bar
-
-  You may get ``Operation not permitted'' errors from cp when it tries
-  to change the permissions on files.  These errors can safely be
-  ignored.  This method will work even if the file dir/bar exists.
-
-  If you wish to move foo to dir/bar and foo and dir are on the same
-  filesystem then you only need to execute ``mv foo dir/bar'' and the
-  resource fork and the Finder's metadata will move too.  However, if
-  foo and dir are on different filesystem then this will lose the
-  resource fork and metadata.  Therefore, it is safest to always move
-  files as follows:
-
-  1. cp foo dir/bar
-
-  2. cp .resource/foo dir/.resource/bar
-
-  3. cp .finderinfo/foo dir/.finderinfo/bar
-
-  4. rm foo
-
-  You may get ``Operation not permitted'' errors from cp when it tries
-  to change the permissions on files.  These errors can safely be
-  ignored.  This method will work even if the file dir/bar exists.
-
-  Directories have no resource fork but you may wish to create a
-  directory which has the same location and view on the Finder's screen
-  as an existing one.  This can be done by copying the Finder metadata
-  file.  To give the directory bar the same location, layout, creation
-  date and modify date as foo you simply execute ``cp .finderinfo/foo
-  .finderinfo/bar''.
-
-  When copying an entire directory with ``cp -R'' you may also wish to
-  copy the metadata for the directory:
-
-  1. cp -R foo bar
-
-  2. cp .finderinfo/foo .finderinfo/bar
-
-  You may get ``Operation not permitted'' errors from cp when it tries
-  to change the permissions on files.  These errors can safely be
-  ignored.
-
-  3\b3.\b.2\b2.\b.  W\bWr\bri\bit\bti\bin\bng\bg w\bwi\bit\bth\bh f\bfo\bor\brk\bk=\b=d\bdo\bou\bub\bbl\ble\be
-
-  The current support for reading and writing header files is sufficient
-  to allow copying of entire directories with tar, as long as both the
-  source and destination are mounted with fork=double.  tar may complain
-  about being unable to change the uid, gid or mode of files.  This is
-  normal and is an unavoidable side effect of the having a single uid,
-  gid and umask for the entire filesystem.
-
-  It is impossible to create a header file.  However, they are created
-  automatically when the data fork is created.  Therefore, if you wish
-  to copy a single file including both forks and the Finder's metadata
-  then you must create the data fork first.  Then you can copy the
-  header file.  instance to copy the file foo to dir/bar you should do
-  the following:
-
-  1. cp foo dir/bar
-
-  2. cp %foo dir/%bar
-
-  You may get ``Operation not permitted'' errors from cp when it tries
-  to change the permissions on files.  These errors can safely be
-  ignored.  This method will work even if the file dir/bar exists.
-
-  If you wish to move foo to dir/bar and foo and dir are on the same
-  filesystem then you only need to execute ``mv foo dir/bar'' and the
-  header file will move too.  However, if foo and dir are on different
-  filesystem then this will lose the header file.  Therefore, it is
-  safest to always move files as follows:
-
-  1. cp foo dir/bar
-
-  2. cp %foo dir/%bar
-
-  3. rm foo
-
-  You may get ``Operation not permitted'' errors from cp when it tries
-  to change the permissions on files.  These errors can safely be
-  ignored.  This method will work even if the file dir/bar exists.
-
-  Directories have no resource fork but you may wish to create a
-  directory which has the same location and view on the Finder's screen
-  as an existing one.  This can be done by copying the corresponding
-  header file.  To give the directory bar the same location, layout,
-  creation date and modify date as foo simply execute ``cp %foo %bar''.
-
-  When copying an entire directory with ``cp -R'' you may also wish to
-  copy the header file for the directory as well:
-
-  1. cp -R foo bar
-
-  2. cp %foo %bar
-
-  You may get ``Operation not permitted'' errors from cp when it tries
-  to change the permissions on files.  These errors can safely be
-  ignored.
-
-  3\b3.\b.3\b3.\b.  W\bWr\bri\bit\bti\bin\bng\bg w\bwi\bit\bth\bh f\bfo\bor\brk\bk=\b=n\bne\bet\bta\bat\bta\bal\blk\bk
-
-  The current support for reading and writing header files is sufficient
-  to allow copying of entire directories with tar, as long as both the
-  source and destination are mounted fork=netatalk.  tar may complain
-  about being unable to change the uid, gid or mode of files.  This is
-  normal and is an unavoidable side effect of the having a single uid,
-  gid and umask for the entire filesystem.
-
-  It is impossible to create a header file.  However, they are created
-  automatically when the data fork is created.  Therefore, if you wish
-  to copy a single file including both forks and the Finder's metadata
-  then you must create the data fork first.  Then you can copy the
-  header file.  instance to copy the file foo to dir/bar you should do
-  the following:
-
-  1. cp foo dir/bar
-
-  2. cp .AppleDouble/foo dir/.AppleDouble/bar
-
-  You may get ``Operation not permitted'' errors from cp when it tries
-  to change the permissions on files.  These errors can safely be
-  ignored.  This method will work even if the file dir/bar exists.
-
-  If you wish to move foo to dir/bar and foo and dir are on the same
-  filesystem then you only need to execute ``mv foo dir/bar'' and the
-  header file will move too.  However, if foo and dir are on different
-  filesystem then this will lose the header file.  Therefore, it is
-  safest to always move files as follows:
-
-  1. cp foo dir/bar
-
-  2. cp .AppleDouble/foo dir/.AppleDouble/bar
-
-  3. rm foo
-
-  You may get ``Operation not permitted'' errors from cp when it tries
-  to change the permissions on files.  These errors can safely be
-  ignored.  This method will work even if the file dir/bar exists.
-
-  Directories have no resource fork but you may wish to create a
-  directory which has the same location and view on the Finder's screen
-  as an existing one.  This can be done by copying the corresponding
-  header file.  To give the directory bar the same location, layout,
-  creation date and modify date as foo you simply execute ``cp
-  foo/.AppleDouble/.Parent bar/.AppleDouble/.Parent''.
-
-  Because the fork=netatalk scheme holds the header file for a directory
-  within that directory, directories can safely be copied with ``cp -R
-  foo bar'' with no loss of information.  However, you may get
-  ``Operation not permitted'' errors from cp when it tries to change the
-  permissions on files.  These errors can safely be ignored.
-
-  4\b4.\b.  A\bA G\bGu\bui\bid\bde\be t\bto\bo S\bSp\bpe\bec\bci\bia\bal\bl F\bFi\bil\ble\be F\bFo\bor\brm\bma\bat\bts\bs
-
-  Each of the values of the fork mount option yields different special
-  files to represent the Macintosh-specific parts of a file within the
-  structure of the Linux filesystem.  You can write to these special
-  files to change things such as the Creator and Type of a file.
-  However, to do so safely you must follow certain rules to avoid
-  corrupting the data.  Additionally, there are certain fields in the
-  special files that you can't change (writes to them will fail
-  silently).
-
-  4\b4.\b.1\b1.\b.  C\bCA\bAP\bP .\b.f\bfi\bin\bnd\bde\ber\bri\bin\bnf\bfo\bo F\bFi\bil\ble\bes\bs
-
-  The Finder's metadata for the file ./foo in held in the file
-  ./.finderinfo/foo.  The file has a fixed format defined in hfs_fs.h as
-  follows:
-
-       ______________________________________________________________________
-       struct hfs_cap_info {
-               __u8    fi_fndr[32];            /* Finder's info */
-               __u16   fi_attr;                /* AFP attributes */
-               __u8    fi_magic1;              /* Magic number: */
-       #define HFS_CAP_MAGIC1          0xFF
-               __u8    fi_version;             /* Version of this structure: */
-       #define HFS_CAP_VERSION         0x10
-               __u8    fi_magic;               /* Another magic number: */
-       #define HFS_CAP_MAGIC           0xDA
-               __u8    fi_bitmap;              /* Bitmap of which names are valid: */
-       #define HFS_CAP_SHORTNAME       0x01
-       #define HFS_CAP_LONGNAME        0x02
-               __u8    fi_shortfilename[12+1]; /* "short name" (unused) */
-               __u8    fi_macfilename[32+1];   /* Original (Macintosh) name */
-               __u8    fi_comln;               /* Length of comment (always 0) */
-               __u8    fi_comnt[200];          /* Finder comment (unused) */
-               /* optional:    used by aufs only if compiled with USE_MAC_DATES */
-               __u8    fi_datemagic;           /* Magic number for dates extension: */
-       #define HFS_CAP_DMAGIC          0xDA
-               __u8    fi_datevalid;           /* Bitmap of which dates are valid: */
-       #define HFS_CAP_MDATE           0x01
-       #define HFS_CAP_CDATE           0x02
-               __u8    fi_ctime[4];            /* Creation date (in AFP format) */
-               __u8    fi_mtime[4];            /* Modify date (in AFP format) */
-               __u8    fi_utime[4];            /* Un*x time of last mtime change */
-       };
-       ______________________________________________________________________
-
-  The type __u8 is an unsigned character, and __u16 is an unsigned
-  16-bit integer.
-
-  Currently only the fields fi_fndr, fi_attr, fi_ctime and fi_mtime can
-  be changed.  Writes to the other fields are silently ignored.
-  However, you shouldn't write random bytes to the other fields, since
-  they may be writable in the future.
-
-  The fi_fndr field is the ``Finder info'' and ``Extended Finder info''
-  for a file or directory.  These structures are described in various
-  books on Macintosh programming.  The portion of the most interest is
-  probably the first 8 bytes which, for a file, give the 4-byte Type
-  followed by the 4-byte Creator.
-
-  The fi_attr field is the AFP attributes of the file or directory.
-  While you can write any value to this field, only the ``write-
-  inhibit'' bit is significant.  Setting or clearing this bit will clear
-  or set the write bits in the file's permissions.  When you read from
-  this field anything you may have written is lost.  If the file has
-  write permissions enabled then you will read zero from this field.
-  With write permission disabled you will read back 0x01 0xA0, which
-  corresponds to setting the ``write-inhibit'', ``rename-inhibit'' and
-  ``delete-inhibit'' bits.
-
-  The fi_ctime and fi_mtime are the Macintosh created and modified time
-  for the file or directory, and are 32-bit signed integers in network
-  byteorder giving seconds from 00:00 GMT Jan. 1, 2000.
-
-  4\b4.\b.2\b2.\b.  A\bAp\bpp\bpl\ble\beD\bDo\bou\bub\bbl\ble\be H\bHe\bea\bad\bde\ber\br F\bFi\bil\ble\bes\bs
-
-  Both the fork=double and fork=netatalk schemes for representing forked
-  files use AppleDouble header files to contain the resource fork and
-  the Finder's metadata together in a single file.
-
-  The AppleDouble format specifies a fixed-format header which describes
-  which fields are contained in the remainder of the file, where they
-  are located in the file and how long they are.  A full description of
-  the version 1 format used when fork=netatalk is available from ??????.
-  The version 2 format used when fork=double is documented in ??????.
-  The discussion that follows assumes you have read and understood these
-  documents, which may be difficult until I've replaced the ``??????''s
-  above with something more informative :-).
-
-  Due to the variable structure of an AppleDouble header file you must
-  not use buffered I/O when reading or writing them; you should only use
-  the read() and write() system calls.  It is also important that you
-  make some effort to coordinate processes that are reading and writing
-  the same header file, since a reader will receive the wrong data if
-  the location of a given entry has changed since it read the descriptor
-  for the entry.  If a process tries to read the descriptor table while
-  it is changing then it is possible to read totally meaningless data.
-
-  When a header file is opened it is initially presented with a default
-  header layout.  You may write to the header to change the layout, but
-  when all file descriptors for the file or directory have been closed
-  the change in format is lost and subsequent opens will yield the
-  default layout.  Changes to supported entries are made directly to the
-  filesystem and are thus preserved when the file is closed and
-  reopened.
-
-  The HFS filesystem currently uses a fixed-size table to hold the
-  descriptors.  Therefore you are limited to HFS_HDR_MAX (currently 10)
-  descriptors.  In the unlikely event that you try to write a header
-  with more descriptors, a warning will be issued by the kernel, and
-  extra descriptors will be ignored.  This should be considered a bug
-  and will hopefully change sooner rather than later.
-
-  The results of specifying overlapping entries is undefined and should
-  not be relied upon to remain unchanged from one version of the HFS
-  filesystem to the next.  There is no valid reason to define
-  overlapping entries, so just don't do it!
-
-  Changes to the magic number and version fields are preserved until all
-  file descriptors are closed, however the only significance given to
-  them internally is that the 16 bytes following the version changes
-  meaning according to the version.  For version 1 header files these 16
-  bytes contain the string ``Macintosh'' followed by 7 spaces.  For any
-  other value of the version field these 16 bytes are all zeros.  In
-  either case writes to these 16 bytes are silently ignored.
-
-  Since the magic number and version are given no other significance
-  internally, you are free to do many things that violate the official
-  formats.  For instance you can create an entry for the data fork in a
-  header file with an AppleDouble magic number or create ``File Info''
-  (id=7) entries in version 2 header files and ``File Dates Info''
-  (id=8) entries in version 1 header files.  However, future versions of
-  the filesystem may enforce the format more strictly.
-
-  Entry id 1 (``Data Fork'') is read-only.  You should use the data file
-  to modify the data fork.  The data fork is, of course, not supported
-  for directories.
-
-  Entry ids 2, 7, 8, 9 and 10 (``Resource Fork'', ``File Info'', ``File
-  Dates Info'', ``Finder Info'' and ``Macintosh File Info'') are fully
-  supported, meaning that their contents may be read and written and
-  that data written is preserved when the file is closed and reopened.
-  The resource fork is, of course, not supported for directories.
-
-  Entry id 7 specifies some of the same data given by ids 8 and 10.  If
-  you create a header file with an entry for id 7 and for ids 8 or 10,
-  then the behavior with respect to their interaction is undefined.  A
-  header that contains an entry for id 7 and for ids 8 or 10 is not
-  valid as either a version 1 or a version 2 header file, so there is no
-  reason to do this and future versions may prevent it.
-
-  Entry id 3 (``Real Name'') is read-only, since it will change
-  automatically when a file is renamed.  Writes to the corresponding
-  entry are silently ignored.
-
-  All other entry ids are ignored.  You may create descriptors for them;
-  in fact the default header layout when fork=netatalk includes a
-  descriptor for id 4 (``Comment'').  However writes to the entries
-  corresponding to the ignored ids fail silently and reads from the
-  entries always return zeros.  However, you shouldn't write random
-  bytes to unsupported entries, since they may be supported in the
-  future.
-
-  All of the supported entry types except the data and resource forks
-  have a fixed length.  If you give them a smaller length in the
-  descriptor then you are unable to access part of the corresponding
-  entry.  If you give them a larger length in the descriptor, then the
-  corresponding entry is padded with zeros and writes to the extra space
-  are silently ignored.
-
-  Writes to the length field of descriptors for the data and resource
-  forks will cause the corresponding fork to grow (with zero padding) or
-  shrink to the indicated length.
-
-  If you have an entry for the data fork then the descriptor's length
-  field does not change automatically to reflect any modification of the
-  data fork directly (the data does change however).  If the data fork
-  is longer than the descriptor indicates, then a portion of it is
-  inaccessible.  If the data fork is shorter than the descriptor
-  indicates then reads will be padded with zeros.
-
-  Writes beyond the end of the resource fork that extend into empty
-  space between entries or beyond the end of the file will extend the
-  fork, automatically changing the length field of the corresponding
-  descriptor.  Writes to any other space between entries are silently
-  ignored and read of such spaces always return zeros.
-
-  Calling truncate() on a header file can change the length of the
-  resource fork and such a change will automatically be reflected in the
-  length field of the corresponding descriptor.  If truncate() shortens
-  the file so that the entry for the resource fork would extend beyond
-  the new end of the file then the fork is shortened to fit in the space
-  that remains, or to zero bytes if the entry is now entirely beyond the
-  end of the file.  If the last entry in a header file is the resource
-  fork then a call to truncate() that extends the header file will
-  extend the fork with zeros.  Note that this happens even if there was
-  previously space between the end of the fork and the end of the file.
-
-  5\b5.\b.  R\bRe\bep\bpo\bor\brt\bti\bin\bng\bg B\bBu\bug\bgs\bs
-
-  If you'd like any problems you encounter fixed, you'll need to provide
-  a detailed bug report.  However, you should check the FAQ (available
-  from the HFS for Linux Page <http://www-sccm.Stanford.EDU/~hargrove/HFS/>)
-  first to be certain that your problem is not a known limitation of the
-  filesystem.  If your bug doesn't appear in the FAQ then you should e-mail
-  me at hargrove@sccm.Stanford.EDU.
-
-  5\b5.\b.1\b1.\b.  W\bWh\bha\bat\bt G\bGo\boe\bes\bs i\bin\bn a\ba B\bBu\bug\bg R\bRe\bep\bpo\bor\brt\bt
-
-  When writing your bug report, include any facts you think might be
-  relevant; I'd much rather have a bunch of extra facts than need to
-  e-mail you to get the information.  At a minimum the following
-  information should be included:
-
-  +\bo  The version of the HFS filesystem you are using (see
-     linux/fs/hfs/version.h).
-
-  +\bo  The kernel version you are using.
-
-  +\bo  Any unofficial kernel patches or loadable modules you are using.
-
-  +\bo  If you are loading the HFS filesystem as a module, then version of
-     the module utilities used to load hfs.o.
-
-  +\bo  The type of media you are working with (floppy, CDROM, ZIP Drive,
-     etc.).
-
-  +\bo  The steps required to reproduce the bug, including mount options
-     used.  (If you can't reproduce the bug tell me everything you did
-     the one time it did occur, but be warned that non-reproducible bugs
-     can only rarely be fixed.)
-
-  5\b5.\b.2\b2.\b.  H\bHo\bow\bw t\bto\bo R\bRe\bep\bpo\bor\brt\bt a\ba K\bKe\ber\brn\bne\bel\bl O\bOo\bop\bps\bs o\bor\br G\bGP\bPF\bF
-
-  If you encounter a bug that causes a kernel Oops or a General
-  Protection Fault then you'll need to collect some additional
-  information for the bug report.  If you are loading the HFS filesystem
-  as a module, then is important that you do this before rebooting,
-  since the module is unlikely to be loaded at the same address after
-  the reboot.
-
-  You should include all the information that the kernel prints to the
-  console or to the system logs.  However, the EIP and Stack Trace are
-  addresses in _\by_\bo_\bu_\br kernel and mean nothing to me without more
-  information.  Using your System.map file (or either ksymoops or klogd)
-  determine which functions the EIP and Stack Trace are in.  If you do
-  this by hand using your System.map file then the correct symbol is the
-  one of type t or T with the largest address less than or equal to the
-  one you are resolving.
-
-  If you are loading the HFS filesystem as a module and the Oops or GPF
-  was in the HFS code then the EIP and the top levels of the Stack Trace
-  will be in a loadable module, rather than in the kernel proper.  So,
-  their symbols will not be in the file System.map.  Therefore, you will
-  need to use /proc/ksyms, or a loadmap produced by passing the -m
-  option to insmod, to locate those symbols.
-
-  6\b6.\b.  L\bLe\beg\bga\bal\bl N\bNo\bot\bti\bic\bce\bes\bs
-
-  6\b6.\b.1\b1.\b.  T\bTh\bhi\bis\bs D\bDo\boc\bcu\bum\bme\ben\bnt\bt
-
-  This document is Copyright (c) 1996, 1997 by Paul H. Hargrove.
-
-  Permission is granted to make and distribute verbatim copies of this
-  document provided the copyright notice and this permission notice are
-  preserved on all copies.
-
-  Permission is granted to copy and distribute modified versions of this
-  document under the conditions for verbatim copies above, provided a
-  notice clearly stating that the document is a modified version is also
-  included in the modified document.
-
-  Permission is granted to copy and distribute translations of this
-  document into another language, under the conditions specified above
-  for modified versions.
-
-  Permission is granted to convert this document into another media
-  under the conditions specified above for modified versions provided
-  the requirement to acknowledge the source document is fulfilled by
-  inclusion of an obvious reference to the source document in the new
-  media. Where there is any doubt as to what defines ``obvious'' the
-  copyright owner reserves the right to decide.
-
-  6\b6.\b.2\b2.\b.  T\bTh\bhe\be S\bSo\bof\bft\btw\bwa\bar\bre\be
-
-  The HFS filesystem for Linux is Copyright (c) 1994-1997 by Paul H.
-  Hargrove.
-
-  This software is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2, or (at your option)
-  any later version.
-
-  This software is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this software in the file ``COPYING''; if not, write to the
-  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
-  USA.
-
-  6\b6.\b.2\b2.\b.1\b1.\b.  T\bTh\bhe\be C\bCo\bol\blu\bum\bmb\bbi\bia\ba A\bAp\bpp\bpl\ble\beT\bTa\bal\blk\bk P\bPa\bac\bck\bka\bag\bge\be f\bfo\bor\br U\bUN\bNI\bIX\bX
-
-  The source code distribution of the Columbia AppleTalk Package for
-  UNIX, version 6.0, (CAP) was used as a _\bs_\bp_\be_\bc_\bi_\bf_\bi_\bc_\ba_\bt_\bi_\bo_\bn of the location
-  and format of files used by CAP's Aufs.  No code from CAP appears in
-  the HFS filesystem. The HFS filesystem is not a work ``derived'' from
-  CAP in the sense of intellectual property law.
-
-  6\b6.\b.2\b2.\b.2\b2.\b.  N\bNe\bet\bta\bat\bta\bal\blk\bk
-
-  The source code distributions of Netatalk, versions 1.3.3b2 and 1.4b2,
-  were used as a _\bs_\bp_\be_\bc_\bi_\bf_\bi_\bc_\ba_\bt_\bi_\bo_\bn of the location and format of files used
-  by Netatalk's afpd.  No code from Netatalk appears in the HFS
-  filesystem.  The HFS filesystem is not a work ``derived'' from
-  Netatalk in the sense of intellectual property law.
-
-  6\b6.\b.3\b3.\b.  T\bTr\bra\bad\bde\bem\bma\bar\brk\bks\bs
-
-  +\bo  ``Finder'' is a trademarks of Apple Computer, Inc.
-
-  +\bo  ``Apple'', ``AppleShare'', ``AppleTalk'' and ``Macintosh'' are
-     registered trademarks of Apple Computer, Inc.
-
-  +\bo  ``Microsoft'' and ``MS-DOS'' are registered trademarks of Microsoft
-     Corporation.
-
-  +\bo  All other trademarks are the property of their respective owners.
-
diff --git a/fs/hfs/INSTALL.txt b/fs/hfs/INSTALL.txt
deleted file mode 100644 (file)
index b9c8efe..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-  Installation instructions for the HFS Filesystem for Linux
-  Paul H. Hargrove, hargrove@sccm.Stanford.EDU
-  version 0.95 28 Apr 1997
-
-  This document explains how to compile and install version 0.95 of
-  hfs_fs, the HFS filesystem for Linux.
-
-  1\b1.\b.  S\bSy\bys\bst\bte\bem\bm R\bRe\beq\bqu\bui\bir\bre\bem\bme\ben\bnt\bts\bs
-
-  You will need the following to compile and use this release of hfs_fs:
-
-  +\bo  Kernel version 2.0.1 or newer compiled with modules enabled
-     (CONFIG_MODULES).
-
-  +\bo  The kernel sources (or at least the header files) available online.
-
-  +\bo  The module utilities package current for your kernel version and an
-     understanding of how to use it.
-
-  2\b2.\b.  I\bIn\bns\bst\bta\bal\bll\bla\bat\bti\bio\bon\bn
-
-  This release of the HFS filesystem is not part of the official kernel
-  distribution.  Therefore, it is compiled as a module and then loaded
-  into the kernel using the module utilities.  Therefore, your kernel
-  must be compiled with CONFIG_MODULES enabled.
-
-  2\b2.\b.1\b1.\b.  C\bCo\bom\bmp\bpi\bil\bli\bin\bng\bg t\bth\bhe\be l\blo\boa\bad\bda\bab\bbl\ble\be m\bmo\bod\bdu\bul\ble\be
-
-  To compile hfs.o you should only need to execute ``make'' in the
-  hfs_fs source directory.
-
-  If gcc complains about not finding a large number of header files with
-  names beginning with ``linux/'' then you probably don't have the
-  kernel header files installed correctly.  Either /usr/include/linux,
-  /usr/include/asm and /usr/include/scsi should be symbolic links to
-  include/linux, include/asm and include/scsi in the kernel source tree
-  for the kernel you wish to use hfs_fs with, or else they should be
-  directories containing the header files for the kernel you wish to use
-  hfs_fs with.
-
-  If gcc complains about not finding linux/version.h, then you will need
-  to run ``make dep'' in the kernel source directory to build it.  Under
-  MkLinux, run ``make include/linux/version.h'' instead.
-
-  If gcc complains about not finding the files linux/config.h or
-  linux/autoconf.h, then you will need to run ``make config'' and ``make
-  dep'' in the kernel source directory to build these two files.
-
-  If you are compiling on a DEC Alpha and receive messages saying
-  assignment from incompatible pointer type when compiling files dir_*.c
-  and file_*.c, then you need to change a single line in the file
-  linux/hfs_fs.h.  Remove the text ``&& !defined(__alpha__)'' from the
-  end of line 217.
-
-  2\b2.\b.2\b2.\b.  I\bIn\bns\bst\bta\bal\bll\bli\bin\bng\bg t\bth\bhe\be m\bmo\bod\bdu\bul\ble\be i\bin\bn t\bth\bhe\be m\bmo\bod\bdu\bul\ble\bes\bs d\bdi\bir\bre\bec\bct\bto\bor\bry\by (\b(o\bop\bpt\bti\bio\bon\bna\bal\bl)\b)
-
-  If you plan to use kerneld to automatically load the module or if you
-  wish to use modprobe or insmod without supplying a complete path to
-  hfs.o, then you will need to copy hfs.o into a directory where the
-  module utilities expect to find it.
-
-  The proper directory may depend slightly on your configuration.
-  However, /lib/modules/default/fs/ is a common one for filesystem
-  modules.  Once hfs.o is in the proper directory you should run depmod
-  -a to update the dependency list used by kerneld and modprobe.
-
-  2\b2.\b.3\b3.\b.  L\bLo\boa\bad\bdi\bin\bng\bg t\bth\bhe\be m\bmo\bod\bdu\bul\ble\be i\bin\bnt\bto\bo t\bth\bhe\be r\bru\bun\bnn\bni\bin\bng\bg k\bke\ber\brn\bne\bel\bl
-
-  There are three ways to accomplish this:
-
-  1. If you are running kerneld and have installed hfs.o in the modules
-     directory then you don't need to issue any commands; the module
-     will be loaded when you attempt to mount an HFS filesystem.
-
-  2. If you are _\bn_\bo_\bt running kerneld then you can load hfs.o manually by
-     running modprobe hfs.o.  If you have not installed hfs.o in one of
-     the standard module directories, then you will need provide a full
-     path to the file hfs.o.
-
-  3. If you have been experiencing kernel crashes with hfs_fs, then you
-     should file a bug report including the names of the functions which
-     the EIP and Stack Trace point into.  To help with this you can ask
-     for relocation map for the module when you load it.  To do this
-     load the module with ``insmod -m hfs.o >loadmap''.  Again, you may
-     need a full path to the file hfs.o if you have not placed it in one
-     of the standard module directories.
-
-  2\b2.\b.4\b4.\b.  U\bUs\bsi\bin\bng\bg t\bth\bhe\be m\bmo\bod\bdu\bul\ble\be w\bwi\bit\bth\bh v\bve\ber\brs\bsi\bio\bon\bne\bed\bd s\bsy\bym\bmb\bbo\bol\bls\bs
-
-  All the interface between the module and the kernel take place through
-  very stable (since the mid-1.3.x kernels) parts of the kernel.  If you
-  enabled versioned symbols (CONFIG_MODVERSIONS) when you compiled your
-  kernel you should often be able to compile this module once and then
-  use it with many kernels newer than the one you compiled it for.
-
-  In any case, it is unlikely that this module will need changes with
-  each new kernel patch; simple recompilation should usually suffice.
-
-  3\b3.\b.  L\bLe\beg\bga\bal\bl N\bNo\bot\bti\bic\bce\bes\bs
-
-  3\b3.\b.1\b1.\b.  T\bTh\bhi\bis\bs D\bDo\boc\bcu\bum\bme\ben\bnt\bt
-
-  This document is Copyright (c) 1996, 1997 by Paul H. Hargrove.
-
-  Permission is granted to make and distribute verbatim copies of this
-  document provided the copyright notice and this permission notice are
-  preserved on all copies.
-
-  Permission is granted to copy and distribute modified versions of this
-  document under the conditions for verbatim copies above, provided a
-  notice clearly stating that the document is a modified version is also
-  included in the modified document.
-
-  Permission is granted to copy and distribute translations of this
-  document into another language, under the conditions specified above
-  for modified versions.
-
-  Permission is granted to convert this document into another media
-  under the conditions specified above for modified versions provided
-  the requirement to acknowledge the source document is fulfilled by
-  inclusion of an obvious reference to the source document in the new
-  media. Where there is any doubt as to what defines ``obvious'' the
-  copyright owner reserves the right to decide.
-
index c7fbf07d61663984bfdc873e8e30ed38184358be..fa13214b1848d767c27ddbaab23f78524be621ab 100644 (file)
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_HFS_FS) += hfs.o
 
-hfs-objs := balloc.o bdelete.o bfind.o bins_del.o binsert.o bitmap.o bitops.o \
-           bnode.o brec.o btree.o catalog.o dir.o dir_cap.o dir_dbl.o \
-           dir_nat.o extent.o file.o file_cap.o file_hdr.o inode.o mdb.o \
-            part_tbl.o string.o super.o sysdep.o trans.o version.o
+hfs-objs := bitmap.o bfind.o bnode.o brec.o btree.o \
+           catalog.o dir.o extent.o inode.o mdb.o \
+            part_tbl.o string.o super.o sysdep.o trans.o
+
diff --git a/fs/hfs/TODO b/fs/hfs/TODO
deleted file mode 100644 (file)
index fbbc6e1..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-The hfs_fs "to do" list.
-------------------------
-Items are broken down into groups and the groups are listed in order
-from most important to least important.  The items within each group
-are not placed in any particular order.  The order in which items are
-listed probably doesn't correlate well with the order they will be
-addressed.
-
-Genuine bugs:
-1.     Header files have compiled-in limit (currently 10) on descriptors.
-
-Missing features:
-1.     1k block support is needed for some devices.
-2.     An ioctl()-based interface is needed to provide a consistent way
-       to do things under all of the representations of forked files.
-
-Possible additional "fork" mount options:
-1.     AppleSingle.
-2.     The scheme MacOS uses on FAT disks (PC Exchange).
-3.     "Flat" (no resource forks or metadata).
-
-Performance issues:
-1.     Use drAllocPtr to speed block allocations.
-2.     Keep a real cache of bnodes, rather than just a hash table of
-       the ones that are currently in use.
-3.     Keep a real cache of extent records, rather than just a linked
-       list of the ones that are currently in use and the one most
-       recently used.  This is particularly needed to get acceptable
-       performance with multiple readers on a file.  Perhaps simply
-       keep them in memory once they've been read until the file is
-       closed.
-
-Implementation details:
-1.     Allocation scheme could/should be closer to that used by Apple.
-2.     B*-tree insertion could/should be closer to that used by Apple.
-3.     Magic-number checks on data structures are rarely done.
-4.     Error recovery is needed for failed binsert(), bdelete() and rename().
-5.     Deadlock detection is needed to make insert_empty_bnode() and
-       bdelete() less likely to hang on a corrupted B-tree.
-6.     Metadata for covered directories shouldn't appear in the filesystem.
-       Under CAP and AppleDouble it currently does.  However, the obvious
-       solution is a real performance killer and is not worth implementing.
-
-Fantasy features:
-1.     Access Desktop file/database for comment and icon.
-2.     Implement mmap() for AppleDouble header files and CAP info files.
-3.     Implement AppleShare client support.
-
-Suggestions/comments/questions are welcome.
-Code addressing any of the issues listed above is especially welcome.
-Paul H. Hargrove
-hargrove@sccm.Stanford.EDU
diff --git a/fs/hfs/balloc.c b/fs/hfs/balloc.c
deleted file mode 100644 (file)
index 58d2817..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * linux/fs/hfs/balloc.c
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * hfs_bnode_alloc() and hfs_bnode_bitop() are based on GPLed code
- * Copyright (C) 1995  Michael Dreher
- *
- * This file contains the code to create and destroy nodes
- * in the B-tree structure.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- *
- * The code in this file initializes some structures which contain
- * pointers by calling memset(&foo, 0, sizeof(foo)).
- * This produces the desired behavior only due to the non-ANSI
- * assumption that the machine representation of NULL is all zeros.
- */
-
-#include "hfs_btree.h"
-
-/*================ File-local functions ================*/
-
-/*
- * get_new_node()
- *
- * Get a buffer for a new node with out reading it from disk.
- */
-static hfs_buffer get_new_node(struct hfs_btree *tree, hfs_u32 node)
-{
-       int tmp;
-       hfs_buffer retval = HFS_BAD_BUFFER;
-
-       tmp = hfs_extent_map(&tree->entry.u.file.data_fork, node, 0);
-       if (tmp) {
-               retval = hfs_buffer_get(tree->sys_mdb, tmp, 0);
-       }
-       return retval;
-}
-
-/*
- * hfs_bnode_init()
- *
- * Description:
- *   Initialize a newly allocated bnode.
- * Input Variable(s):
- *   struct hfs_btree *tree: Pointer to a B-tree
- *   hfs_u32 node: the node number to allocate
- * Output Variable(s):
- *   NONE
- * Returns:
- *   struct hfs_bnode_ref for the new node
- * Preconditions:
- *   'tree' points to a "valid" (struct hfs_btree)
- *   'node' exists and has been allocated in the bitmap of bnodes.
- * Postconditions:
- *   On success:
- *    The node is not read from disk, nor added to the bnode cache.
- *    The 'sticky' and locking-related fields are all zero/NULL.
- *    The bnode's nd{[FB]Link, Type, NHeight} fields are uninitialized.
- *    The bnode's ndNRecs field and offsets table indicate an empty bnode.
- *   On failure:
- *    The node is deallocated.
- */
-static struct hfs_bnode_ref hfs_bnode_init(struct hfs_btree * tree,
-                                          hfs_u32 node)
-{
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-       extern int bnode_count;
-#endif
-       struct hfs_bnode_ref retval;
-
-       retval.lock_type = HFS_LOCK_NONE;
-       if (!HFS_NEW(retval.bn)) {
-               hfs_warn("hfs_bnode_init: out of memory.\n");
-               goto bail2;
-       }
-
-       /* Partially initialize the in-core structure */
-       memset(retval.bn, 0, sizeof(*retval.bn));
-       retval.bn->magic = HFS_BNODE_MAGIC;
-       retval.bn->tree = tree;
-       retval.bn->node = node;
-       hfs_init_waitqueue(&retval.bn->wqueue);
-       hfs_init_waitqueue(&retval.bn->rqueue);
-       hfs_bnode_lock(&retval, HFS_LOCK_WRITE);
-
-       retval.bn->buf = get_new_node(tree, node);
-       if (!hfs_buffer_ok(retval.bn->buf)) {
-               goto bail1;
-       }
-
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-       ++bnode_count;
-#endif
-
-       /* Partially initialize the on-disk structure */
-       memset(hfs_buffer_data(retval.bn->buf), 0, HFS_SECTOR_SIZE);
-       hfs_put_hs(sizeof(struct NodeDescriptor), RECTBL(retval.bn, 1));
-
-       return retval;
-
-bail1:
-       HFS_DELETE(retval.bn);
-bail2:
-       /* clear the bit in the bitmap */
-       hfs_bnode_bitop(tree, node, 0);
-       return retval;
-}
-
-/*
- * init_mapnode()
- *
- * Description:
- *   Initializes a given node as a mapnode in the given tree.
- * Input Variable(s):
- *   struct hfs_bnode *bn: the node to add the mapnode after.
- *   hfs_u32: the node to use as a mapnode.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   struct hfs_bnode *: the new mapnode or NULL
- * Preconditions:
- *   'tree' is a valid (struct hfs_btree).
- *   'node' is the number of the first node in 'tree' that is not
- *    represented by a bit in the existing mapnodes.
- * Postconditions:
- *   On failure 'tree' is unchanged and NULL is returned.
- *   On success the node given by 'node' has been added to the linked
- *    list of mapnodes attached to 'tree', and has been initialized as
- *    a valid mapnode with its first bit set to indicate itself as
- *    allocated.
- */
-static struct hfs_bnode *init_mapnode(struct hfs_bnode *bn, hfs_u32 node)
-{
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-       extern int bnode_count;
-#endif
-       struct hfs_bnode *retval;
-
-       if (!HFS_NEW(retval)) {
-               hfs_warn("hfs_bnode_add: out of memory.\n");
-               return NULL;
-       }
-
-       memset(retval, 0, sizeof(*retval));
-       retval->magic = HFS_BNODE_MAGIC;
-       retval->tree = bn->tree;
-       retval->node = node;
-       retval->sticky = HFS_STICKY;
-       retval->buf = get_new_node(bn->tree, node);
-       if (!hfs_buffer_ok(retval->buf)) {
-               HFS_DELETE(retval);
-               return NULL;
-       }
-
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-       ++bnode_count;
-#endif
-
-       /* Initialize the bnode data structure */
-       memset(hfs_buffer_data(retval->buf), 0, HFS_SECTOR_SIZE);
-       retval->ndFLink = 0;
-       retval->ndBLink = bn->node;
-       retval->ndType = ndMapNode;
-       retval->ndNHeight = 0;
-       retval->ndNRecs = 1;
-       hfs_put_hs(sizeof(struct NodeDescriptor), RECTBL(retval, 1));
-       hfs_put_hs(0x1fa,                         RECTBL(retval, 2));
-       *((hfs_u8 *)bnode_key(retval, 1)) = 0x80; /* set first bit of bitmap */
-       retval->prev = bn;
-       hfs_bnode_commit(retval);
-
-       bn->ndFLink = node;
-       bn->next = retval;
-       hfs_bnode_commit(bn);
-
-       return retval;
-}
-
-/*================ Global functions ================*/
-
-/*
- * hfs_bnode_bitop()
- *
- * Description:
- *   Allocate/free the requested node of a B-tree of the hfs filesystem
- *   by setting/clearing the corresponding bit in the B-tree bitmap.
- *   The size of the B-tree will not be changed.
- * Input Variable(s):
- *   struct hfs_btree *tree: Pointer to a B-tree
- *   hfs_u32 bitnr: The node number to free
- *   int set: 0 to clear the bit, non-zero to set it.
- * Output Variable(s):
- *   None
- * Returns:
- *    0: no error
- *   -1: The node was already allocated/free, nothing has been done.
- *   -2: The node is out of range of the B-tree.
- *   -4: not enough map nodes to hold all the bits
- * Preconditions:
- *   'tree' points to a "valid" (struct hfs_btree)
- *   'bitnr' is a node number within the range of the btree, which is
- *   currently free/allocated.
- * Postconditions:
- *   The bit number 'bitnr' of the node bitmap is set/cleared and the
- *   number of free nodes in the btree is decremented/incremented by one.
- */
-int hfs_bnode_bitop(struct hfs_btree *tree, hfs_u32 bitnr, int set)
-{
-       struct hfs_bnode *bn;   /* the current bnode */
-       hfs_u16 start;          /* the start (in bits) of the bitmap in node */
-       hfs_u16 len;            /* the len (in bits) of the bitmap in node */
-       hfs_u32 *u32;           /* address of the u32 containing the bit */
-
-       if (bitnr >= tree->bthNNodes) {
-               hfs_warn("hfs_bnode_bitop: node number out of range.\n");
-               return -2;
-       }
-
-       bn = &tree->head;
-       for (;;) {
-               start = bnode_offset(bn, bn->ndNRecs) << 3;
-               len = (bnode_offset(bn, bn->ndNRecs + 1) << 3) - start;
-
-               if (bitnr < len) {
-                       break;
-               }
-
-               /* continue on to next map node if available */
-               if (!(bn = bn->next)) {
-                       hfs_warn("hfs_bnode_bitop: too few map nodes.\n");
-                       return -4;
-               }
-               bitnr -= len;
-       }
-
-       /* Change the correct bit */
-       bitnr += start;
-       u32 = (hfs_u32 *)hfs_buffer_data(bn->buf) + (bitnr >> 5);
-       bitnr %= 32;
-       if ((set && hfs_set_bit(bitnr, u32)) ||
-           (!set && !hfs_clear_bit(bitnr, u32))) {
-               hfs_warn("hfs_bnode_bitop: bitmap corruption.\n");
-               return -1;
-       }
-       hfs_buffer_dirty(bn->buf);
-
-       /* adjust the free count */
-       tree->bthFree += (set ? -1 : 1);
-       tree->dirt = 1;
-
-       return 0;
-}
-
-/*
- * hfs_bnode_alloc()
- *
- * Description:
- *   Find a cleared bit in the B-tree node bitmap of the hfs filesystem,
- *   set it and return the corresponding bnode, with its contents zeroed.
- *   When there is no free bnode in the tree, an error is returned, no
- *   new nodes will be added by this function!
- * Input Variable(s):
- *   struct hfs_btree *tree: Pointer to a B-tree
- * Output Variable(s):
- *   NONE
- * Returns:
- *   struct hfs_bnode_ref for the new bnode
- * Preconditions:
- *   'tree' points to a "valid" (struct hfs_btree)
- *   There is at least one free bnode.
- * Postconditions:
- *   On success:
- *     The corresponding bit in the btree bitmap is set.
- *     The number of free nodes in the btree is decremented by one.
- *   The node is not read from disk, nor added to the bnode cache.
- *   The 'sticky' field is uninitialized.
- */
-struct hfs_bnode_ref hfs_bnode_alloc(struct hfs_btree *tree)
-{
-       struct hfs_bnode *bn;   /* the current bnode */
-       hfs_u32 bitnr = 0;      /* which bit are we examining */
-       hfs_u16 first;          /* the first clear bit in this bnode */
-       hfs_u16 start;          /* the start (in bits) of the bitmap in node */
-       hfs_u16 end;            /* the end (in bits) of the bitmap in node */
-       hfs_u32 *data;          /* address of the data in this bnode */
-       
-       bn = &tree->head;
-       for (;;) {
-               start = bnode_offset(bn, bn->ndNRecs) << 3;
-               end = bnode_offset(bn, bn->ndNRecs + 1) << 3;
-               data =  (hfs_u32 *)hfs_buffer_data(bn->buf);
-               
-               /* search the current node */
-               first = hfs_find_zero_bit(data, end, start);
-               if (first < end) {
-                       break;
-               }
-
-               /* continue search in next map node */
-               bn = bn->next;
-
-               if (!bn) {
-                       hfs_warn("hfs_bnode_alloc: too few map nodes.\n");
-                       goto bail;
-               }
-               bitnr += (end - start);
-       }
-
-       if ((bitnr += (first - start)) >= tree->bthNNodes) {
-               hfs_warn("hfs_bnode_alloc: no free nodes found, "
-                        "count wrong?\n");
-               goto bail;
-       }
-
-       if (hfs_set_bit(first % 32, data + (first>>5))) {
-               hfs_warn("hfs_bnode_alloc: bitmap corruption.\n");
-               goto bail;
-       }
-       hfs_buffer_dirty(bn->buf);
-
-       /* decrement the free count */
-       --tree->bthFree;
-       tree->dirt = 1;
-
-       return hfs_bnode_init(tree, bitnr);
-
-bail:
-       return (struct hfs_bnode_ref){NULL, HFS_LOCK_NONE};
-}
-
-/*
- * hfs_btree_extend()
- *
- * Description:
- *   Adds nodes to a B*-tree if possible.
- * Input Variable(s):
- *   struct hfs_btree *tree: the btree to add nodes to.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'tree' is a valid (struct hfs_btree *).
- * Postconditions:
- *   If possible the number of nodes indicated by the tree's clumpsize
- *    have been added to the tree, updating all in-core and on-disk
- *    allocation information.
- *   If insufficient disk-space was available then fewer nodes may have
- *    been added than would be expected based on the clumpsize.
- *   In the case of the extents B*-tree this function will add fewer
- *    nodes than expected if adding more would result in an extent
- *    record for the extents tree being added to the extents tree.
- *    The situation could be dealt with, but doing so confuses Macs.
- */
-void hfs_btree_extend(struct hfs_btree *tree)
-{
-       struct hfs_bnode_ref head;
-       struct hfs_bnode *bn, *tmp;
-       struct hfs_cat_entry *entry = &tree->entry;
-       struct hfs_mdb *mdb = entry->mdb;
-       hfs_u32 old_nodes, new_nodes, total_nodes, new_mapnodes, seen;
-
-       old_nodes = entry->u.file.data_fork.psize;
-
-       entry->u.file.data_fork.lsize += 1; /* rounded up to clumpsize */
-       hfs_extent_adj(&entry->u.file.data_fork);
-
-       total_nodes = entry->u.file.data_fork.psize;
-       entry->u.file.data_fork.lsize = total_nodes << HFS_SECTOR_SIZE_BITS;
-       new_nodes = total_nodes - old_nodes;
-       if (!new_nodes) {
-               return;
-       }
-
-       head = hfs_bnode_find(tree, 0, HFS_LOCK_WRITE);
-       if (!(bn = head.bn)) {
-               hfs_warn("hfs_btree_extend: header node not found.\n");
-               return;
-       }
-
-       seen = 0;
-       new_mapnodes = 0;
-       for (;;) {
-               seen += bnode_rsize(bn, bn->ndNRecs) << 3;
-
-               if (seen >= total_nodes) {
-                       break;
-               }
-
-               if (!bn->next) {
-                       tmp = init_mapnode(bn, seen);
-                       if (!tmp) {
-                               hfs_warn("hfs_btree_extend: "
-                                        "can't build mapnode.\n");
-                               hfs_bnode_relse(&head);
-                               return;
-                       }
-                       ++new_mapnodes;
-               }
-               bn = bn->next;
-       }
-       hfs_bnode_relse(&head);
-
-       tree->bthNNodes = total_nodes;
-       tree->bthFree += (new_nodes - new_mapnodes);
-       tree->dirt = 1;
-
-       /* write the backup MDB, not returning until it is written */
-       hfs_mdb_commit(mdb, 1);
-
-       return;
-}
-
-/*
- * hfs_bnode_free()
- *
- * Remove a node from the cache and mark it free in the bitmap.
- */
-int hfs_bnode_free(struct hfs_bnode_ref *bnr)
-{
-       hfs_u32 node = bnr->bn->node;
-       struct hfs_btree *tree = bnr->bn->tree;
-
-       if (bnr->bn->count != 1) {
-               hfs_warn("hfs_bnode_free: count != 1.\n");
-               return -EIO;
-       }
-
-       hfs_bnode_relse(bnr);
-       hfs_bnode_bitop(tree, node, 0);
-       return 0;
-}
diff --git a/fs/hfs/bdelete.c b/fs/hfs/bdelete.c
deleted file mode 100644 (file)
index aec1394..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * linux/fs/hfs/bdelete.c
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the code to delete records in a B-tree.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- */
-
-#include "hfs_btree.h"
-
-/*================ Variable-like macros ================*/
-
-#define FULL (HFS_SECTOR_SIZE - sizeof(struct NodeDescriptor))
-#define NO_SPACE (HFS_SECTOR_SIZE+1)
-
-/*================ File-local functions ================*/
-
-/*
- * bdelete_nonempty()
- *
- * Description:
- *   Deletes a record from a given bnode without regard to it becoming empty.
- * Input Variable(s):
- *   struct hfs_brec* brec: pointer to the brec for the deletion
- *   struct hfs_belem* belem: which node in 'brec' to delete from
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'brec' points to a valid (struct hfs_brec).
- *   'belem' points to a valid (struct hfs_belem) in 'brec'.
- * Postconditions:
- *   The record has been inserted in the position indicated by 'brec'.
- */
-static void bdelete_nonempty(struct hfs_brec *brec, struct hfs_belem *belem)
-{
-       int i, rec, nrecs, tomove;
-       hfs_u16 size;
-       hfs_u8 *start;
-       struct hfs_bnode *bnode = belem->bnr.bn;
-
-       rec = belem->record;
-       nrecs = bnode->ndNRecs;
-       size = bnode_rsize(bnode, rec);
-       tomove = bnode_offset(bnode, nrecs+1) - bnode_offset(bnode, rec+1);
-       
-       /* adjust the record table */
-       for (i = rec+1; i <= nrecs; ++i) {
-               hfs_put_hs(bnode_offset(bnode,i+1) - size, RECTBL(bnode,i));
-       }
-
-       /* move it down */
-       start = bnode_key(bnode, rec);
-       memmove(start, start + size, tomove);
-
-       /* update record count */
-       --bnode->ndNRecs;
-}
-
-/*
- * del_root()
- *
- * Description:
- *   Delete the current root bnode.
- * Input Variable(s):
- *   struct hfs_bnode_ref *root: reference to the root bnode
- * Output Variable(s):
- *   NONE
- * Returns:
- *   int: 0 on success, error code on failure
- * Preconditions:
- *   'root' refers to the root bnode with HFS_LOCK_WRITE access.
- *   None of 'root's children are held with HFS_LOCK_WRITE access.
- * Postconditions:
- *   The current 'root' node is removed from the tree and the depth
- *    of the tree is reduced by one.
- *   If 'root' is an index node with exactly one child, then that
- *    child becomes the new root of the tree.
- *   If 'root' is an empty leaf node the tree becomes empty.
- *   Upon return access to 'root' is relinquished.
- */
-static int del_root(struct hfs_bnode_ref *root)
-{
-       struct hfs_btree *tree = root->bn->tree;
-       struct hfs_bnode_ref child;
-       hfs_u32 node;
-
-       if (root->bn->ndNRecs > 1) {
-               return 0;
-       } else if (root->bn->ndNRecs == 0) {
-               /* tree is empty */
-               tree->bthRoot = 0;
-               tree->root = NULL;
-               tree->bthRoot = 0;
-               tree->bthFNode = 0;
-               tree->bthLNode = 0;
-               --tree->bthDepth;
-               tree->dirt = 1;
-               if (tree->bthDepth) {
-                       hfs_warn("hfs_bdelete: empty tree with bthDepth=%d\n",
-                                tree->bthDepth);
-                       goto bail;
-               }
-               return hfs_bnode_free(root);
-       } else if (root->bn->ndType == ndIndxNode) {
-               /* tree is non-empty */
-               node = hfs_get_hl(bkey_record(bnode_datastart(root->bn)));
-
-               child = hfs_bnode_find(tree, node, HFS_LOCK_READ);
-               if (!child.bn) {
-                       hfs_warn("hfs_bdelete: can't read child node.\n");
-                       goto bail;
-               }
-                       
-               child.bn->sticky = HFS_STICKY;
-               if (child.bn->next) {
-                       child.bn->next->prev = child.bn->prev;
-               }
-               if (child.bn->prev) {
-                       child.bn->prev->next = child.bn->next;
-               }
-               if (bhash(tree, child.bn->node) == child.bn) {
-                       bhash(tree, child.bn->node) = child.bn->next;
-               }
-               child.bn->next = NULL;
-               child.bn->prev = NULL;
-
-               tree->bthRoot = child.bn->node;
-               tree->root = child.bn;
-
-               /* re-assign bthFNode and bthLNode if the new root is
-                   a leaf node. */
-               if (child.bn->ndType == ndLeafNode) {
-                       tree->bthFNode = node;
-                       tree->bthLNode = node;
-               }
-               hfs_bnode_relse(&child);
-
-               tree->bthRoot = node;
-               --tree->bthDepth;
-               tree->dirt = 1;
-               if (!tree->bthDepth) {
-                       hfs_warn("hfs_bdelete: non-empty tree with "
-                                "bthDepth == 0\n");
-                       goto bail;
-               }
-               return hfs_bnode_free(root);    /* marks tree dirty */
-       }
-       hfs_bnode_relse(root);
-       return 0;
-
-bail:
-       hfs_bnode_relse(root);
-       return -EIO;
-}
-
-
-/*
- * delete_empty_bnode()
- *
- * Description:
- *   Removes an empty non-root bnode from between 'left' and 'right'
- * Input Variable(s):
- *   hfs_u32 left_node: node number of 'left' or zero if 'left' is invalid
- *   struct hfs_bnode_ref *left: reference to the left neighbor of the
- *    bnode to remove, or invalid if no such neighbor exists.
- *   struct hfs_bnode_ref *center: reference to the bnode to remove
- *   hfs_u32 right_node: node number of 'right' or zero if 'right' is invalid
- *   struct hfs_bnode_ref *right: reference to the right neighbor of the
- *    bnode to remove, or invalid if no such neighbor exists.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'left_node' is as described above.
- *   'left' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE
- *    access and referring to the left neighbor of 'center' if such a
- *    neighbor exists, or invalid if no such neighbor exists.
- *   'center' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE
- *    access and referring to the bnode to delete.
- *   'right_node' is as described above.
- *   'right' points to a valid (struct hfs_bnode_ref) having HFS_LOCK_WRITE
- *    access and referring to the right neighbor of 'center' if such a
- *    neighbor exists, or invalid if no such neighbor exists.
- * Postconditions:
- *   If 'left' is valid its 'ndFLink' field becomes 'right_node'.
- *   If 'right' is valid its 'ndBLink' field becomes 'left_node'.
- *   If 'center' was the first leaf node then the tree's 'bthFNode'
- *    field becomes 'right_node' 
- *   If 'center' was the last leaf node then the tree's 'bthLNode'
- *    field becomes 'left_node' 
- *   'center' is NOT freed and access to the nodes is NOT relinquished.
- */
-static void delete_empty_bnode(hfs_u32 left_node, struct hfs_bnode_ref *left,
-                              struct hfs_bnode_ref *center,
-                              hfs_u32 right_node, struct hfs_bnode_ref *right)
-{
-       struct hfs_bnode *bnode = center->bn;
-
-       if (left_node) {
-               left->bn->ndFLink = right_node;
-       } else if (bnode->ndType == ndLeafNode) {
-               bnode->tree->bthFNode = right_node;
-               bnode->tree->dirt = 1;
-       }
-
-       if (right_node) {
-               right->bn->ndBLink = left_node;
-       } else if (bnode->ndType == ndLeafNode) {
-               bnode->tree->bthLNode = left_node;
-               bnode->tree->dirt = 1;
-       }
-}
-
-/*
- * balance()
- *
- * Description:
- *   Attempt to equalize space usage in neighboring bnodes.
- * Input Variable(s):
- *   struct hfs_bnode *left: the left bnode.
- *   struct hfs_bnode *right: the right bnode.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'left' and 'right' point to valid (struct hfs_bnode)s obtained
- *    with HFS_LOCK_WRITE access, and are neighbors.
- * Postconditions:
- *   Records are shifted either left or right to make the space usage
- *   nearly equal.  When exact equality is not possible the break
- *   point is chosen to reduce data movement.
- *   The key corresponding to 'right' in its parent is NOT updated.
- */
-static void balance(struct hfs_bnode *left, struct hfs_bnode *right)
-{
-       int index, left_free, right_free, half;
-
-       left_free = bnode_freespace(left);
-       right_free = bnode_freespace(right);
-       half = (left_free + right_free)/2;
-
-       if (left_free < right_free) {
-               /* shift right to balance */
-               index = left->ndNRecs + 1;
-               while (right_free >= half) {
-                       --index;
-                       right_free -= bnode_rsize(left,index)+sizeof(hfs_u16);
-               }
-               if (index < left->ndNRecs) {
-#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)
-                       hfs_warn("shifting %d of %d recs right to balance: ",
-                              left->ndNRecs - index, left->ndNRecs);
-#endif
-                       hfs_bnode_shift_right(left, right, index+1);
-#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)
-                       hfs_warn("%d,%d\n", left->ndNRecs, right->ndNRecs);
-#endif
-               }
-       } else {
-               /* shift left to balance */
-               index = 0;
-               while (left_free >= half) {
-                       ++index;
-                       left_free -= bnode_rsize(right,index)+sizeof(hfs_u16);
-               }
-               if (index > 1) {
-#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)
-                       hfs_warn("shifting %d of %d recs left to balance: ",
-                              index-1, right->ndNRecs);
-#endif
-                       hfs_bnode_shift_left(left, right, index-1);
-#if defined(DEBUG_ALL) || defined(DEBUG_BALANCE)
-                       hfs_warn("%d,%d\n", left->ndNRecs, right->ndNRecs);
-#endif
-               }
-       }
-}
-
-/*
- * bdelete()
- *
- * Delete the given record from a B-tree.
- */
-static int bdelete(struct hfs_brec *brec)
-{
-       struct hfs_btree *tree = brec->tree;
-       struct hfs_belem *belem = brec->bottom;
-       struct hfs_belem *parent = (belem-1);
-       struct hfs_bnode *bnode;
-       hfs_u32 left_node, right_node;
-       struct hfs_bnode_ref left, right;
-       int left_space, right_space, min_space;
-       int fix_right_key;
-       int fix_key;
-       
-       while ((belem > brec->top) &&
-              (belem->flags & (HFS_BPATH_UNDERFLOW | HFS_BPATH_FIRST))) {
-               bnode = belem->bnr.bn;
-               fix_key = belem->flags & HFS_BPATH_FIRST;
-               fix_right_key = 0;
-
-               bdelete_nonempty(brec, belem);
-
-               if (bnode->node == tree->root->node) {
-                       del_root(&belem->bnr);
-                       --brec->bottom;
-                       goto done;
-               }
-
-               /* check for btree corruption which could lead to deadlock */
-               left_node = bnode->ndBLink;
-               right_node = bnode->ndFLink;
-               if ((left_node && hfs_bnode_in_brec(left_node, brec)) ||
-                   (right_node && hfs_bnode_in_brec(right_node, brec)) ||
-                   (left_node == right_node)) {
-                       hfs_warn("hfs_bdelete: corrupt btree\n");
-                       hfs_brec_relse(brec, NULL);
-                       return -EIO;
-               }
-
-               /* grab the left neighbor if it exists */
-               if (left_node) {
-                       hfs_bnode_lock(&belem->bnr, HFS_LOCK_RESRV);
-                       left = hfs_bnode_find(tree,left_node,HFS_LOCK_WRITE);
-                       if (!left.bn) {
-                               hfs_warn("hfs_bdelete: unable to read left "
-                                        "neighbor.\n");
-                               hfs_brec_relse(brec, NULL);
-                               return -EIO;
-                       }
-                       hfs_bnode_lock(&belem->bnr, HFS_LOCK_WRITE);
-                       if (parent->record != 1) {
-                               left_space = bnode_freespace(left.bn);
-                       } else {
-                               left_space = NO_SPACE;
-                       }
-               } else {
-                       left.bn = NULL;
-                       left_space = NO_SPACE;
-               }
-
-               /* grab the right neighbor if it exists */
-               if (right_node) {
-                       right = hfs_bnode_find(tree,right_node,HFS_LOCK_WRITE);
-                       if (!right.bn) {
-                               hfs_warn("hfs_bdelete: unable to read right "
-                                        "neighbor.\n");
-                               hfs_bnode_relse(&left);
-                               hfs_brec_relse(brec, NULL);
-                               return -EIO;
-                       }
-                       if (parent->record < parent->bnr.bn->ndNRecs) {
-                               right_space = bnode_freespace(right.bn);
-                       } else {
-                               right_space = NO_SPACE;
-                       }
-               } else {
-                       right.bn = NULL;
-                       right_space = NO_SPACE;
-               }
-
-               if (left_space < right_space) {
-                       min_space = left_space;
-               } else {
-                       min_space = right_space;
-               }
-
-               if (min_space == NO_SPACE) {
-                       hfs_warn("hfs_bdelete: no siblings?\n");
-                       hfs_brec_relse(brec, NULL);
-                       return -EIO;
-               }
-
-               if (bnode->ndNRecs == 0) {
-                       delete_empty_bnode(left_node, &left, &belem->bnr,
-                                          right_node, &right);
-               } else if (min_space + bnode_freespace(bnode) >= FULL) {
-                       if ((right_space == NO_SPACE) ||
-                           ((right_space == min_space) &&
-                            (left_space != NO_SPACE))) {
-                               hfs_bnode_shift_left(left.bn, bnode,
-                                                    bnode->ndNRecs);
-                       } else {
-                               hfs_bnode_shift_right(bnode, right.bn, 1);
-                               fix_right_key = 1;
-                       }
-                       delete_empty_bnode(left_node, &left, &belem->bnr,
-                                          right_node, &right);
-               } else if (min_space == right_space) {
-                       balance(bnode, right.bn);
-                       fix_right_key = 1;
-               } else {
-                       balance(left.bn, bnode);
-                       fix_key = 1;
-               }
-
-               if (fix_right_key) {
-                       hfs_bnode_update_key(brec, belem, right.bn, 1);
-               }
-
-               hfs_bnode_relse(&left);
-               hfs_bnode_relse(&right);
-
-               if (bnode->ndNRecs) {
-                       if (fix_key) {
-                               hfs_bnode_update_key(brec, belem, bnode, 0);
-                       }
-                       goto done;
-               }
-
-               hfs_bnode_free(&belem->bnr);
-               --brec->bottom;
-               belem = parent;
-               --parent;
-       }
-
-       if (belem < brec->top) {
-               hfs_warn("hfs_bdelete: Missing parent.\n");
-               hfs_brec_relse(brec, NULL);
-               return -EIO;
-       }
-
-       bdelete_nonempty(brec, belem);
-
-done:
-       hfs_brec_relse(brec, NULL);
-       return 0;
-}
-
-/*================ Global functions ================*/
-
-/*
- * hfs_bdelete()
- *
- * Delete the requested record from a B-tree.
- */
-int hfs_bdelete(struct hfs_btree *tree, const struct hfs_bkey *key)
-{ 
-       struct hfs_belem *belem;
-       struct hfs_bnode *bnode;
-       struct hfs_brec brec;
-       int retval;
-
-       if (!tree || (tree->magic != HFS_BTREE_MAGIC) || !key) {
-               hfs_warn("hfs_bdelete: invalid arguments.\n");
-               return -EINVAL;
-       }
-
-       retval = hfs_bfind(&brec, tree, key, HFS_BFIND_DELETE);
-       if (!retval) {
-               belem = brec.bottom;
-               bnode = belem->bnr.bn;
-
-               belem->flags = 0;
-               if ((bnode->ndNRecs * sizeof(hfs_u16) + bnode_end(bnode) -
-                    bnode_rsize(bnode, belem->record)) < FULL/2) {
-                       belem->flags |= HFS_BPATH_UNDERFLOW;
-               }
-               if (belem->record == 1) {
-                       belem->flags |= HFS_BPATH_FIRST;
-               }
-
-               if (!belem->flags) {
-                       hfs_brec_lock(&brec, brec.bottom);
-               } else {
-                       hfs_brec_lock(&brec, NULL);
-               }
-
-               retval = bdelete(&brec);
-               if (!retval) {
-                       --brec.tree->bthNRecs;
-                       brec.tree->dirt = 1;
-               }
-               hfs_brec_relse(&brec, NULL);
-       }
-       return retval;
-}
index 8e84133d20bd9a10282e14b3127f46896625f1dc..af78ad64fa3a43af864bdc248e1ab001bb905eac 100644 (file)
 /*
- * linux/fs/hfs/bfind.c
+ *  linux/fs/hfs/bfind.c
  *
- * Copyright (C) 1995, 1996  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
+ * Copyright (C) 2001
+ * Brad Boyer (flar@allandria.com)
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  *
- * This file contains the code to access records in a btree.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
+ * Search routines for btrees
  */
 
-#include "hfs_btree.h"
+#include <linux/slab.h>
+#include "btree.h"
 
-/*================ Global functions ================*/
-
-/*
- * hfs_brec_relse()
- *
- * Description:
- *   This function releases some of the nodes associated with a brec.
- * Input Variable(s):
- *   struct hfs_brec *brec: pointer to the brec to release some nodes from.
- *   struct hfs_belem *elem: the last node to release or NULL for all
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'brec' points to a "valid" (struct hfs_brec)
- * Postconditions: 
- *   All nodes between the indicated node and the beginning of the path
- *    are released.
- */
-void hfs_brec_relse(struct hfs_brec *brec, struct hfs_belem *elem)
+int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
 {
-       if (!elem) {
-               elem = brec->bottom;
-       }
-
-       while (brec->top <= elem) {
-               hfs_bnode_relse(&brec->top->bnr);
-               ++brec->top;
-       }
+       void *ptr;
+
+       fd->tree = tree;
+       fd->bnode = NULL;
+       ptr = kmalloc(tree->max_key_len * 2 + 4, GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+       fd->search_key = ptr;
+       fd->key = ptr + tree->max_key_len + 2;
+       dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0));
+       down(&tree->tree_lock);
+       return 0;
 }
 
-/*
- * hfs_bfind()
- *
- * Description:
- *   This function has sole responsibility for locating existing
- *   records in a B-tree.  Given a B-tree and a key it locates the
- *   "greatest" record "less than or equal to" the given key.  The
- *   exact behavior is determined by the bits of the flags variable as
- *   follows:
- *     ('flags' & HFS_LOCK_MASK):
- *      The lock_type argument to be used when calling hfs_bnode_find().
- *     HFS_BFIND_EXACT: only accept an exact match, otherwise take the
- *     "largest" record less than 'target' as a "match"
- *     HFS_BFIND_LOCK: request HFS_LOCK_WRITE access to the node containing
- *     the "matching" record when it is located
- *     HFS_BPATH_FIRST: keep access to internal nodes when accessing their
- *      first child.
- *     HFS_BPATH_OVERFLOW: keep access to internal nodes when the accessed
- *      child is too full to insert another pointer record.
- *     HFS_BPATH_UNDERFLOW: keep access to internal nodes when the accessed
- *      child is would be less than half full upon removing a pointer record.
- * Input Variable(s):
- *   struct hfs_brec *brec: pointer to the (struct hfs_brec) to hold
- *    the search results.
- *   struct hfs_bkey *target: pointer to the (struct hfs_bkey)
- *    to search for
- *   int flags: bitwise OR of flags which determine the function's behavior
- * Output Variable(s):
- *   'brec' contains the results of the search on success or is invalid
- *    on failure.
- * Returns:
- *   int: 0 or 1 on success or an error code on failure:
- *     -EINVAL: one of the input variables was NULL.
- *     -ENOENT: tree is valid but empty or no "matching" record was located.
- *      If the HFS_BFIND_EXACT bit of 'flags' is not set then the case of no
- *      matching record will give a 'brec' with a 'record' field of zero
- *      rather than returning this error.
- *     -EIO: an I/O operation or an assertion about the structure of a
- *       valid B-tree failed indicating corruption of either the B-tree
- *       structure on the disk or one of the in-core structures representing
- *       the B-tree.
- *      (This could also be returned if a kmalloc() call failed in a
- *      subordinate routine that is intended to get the data from the
- *      disk or the buffer cache.)
- * Preconditions:
- *   'brec' is NULL or points to a (struct hfs_brec) with a 'tree' field
- *    which points to a valid (struct hfs_btree).
- *   'target' is NULL or points to a "valid" (struct hfs_bkey)
- * Postconditions:
- *   If 'brec', 'brec->tree' or 'target' is NULL then -EINVAL is returned.
- *   If 'brec', 'brec->tree' and 'target' are non-NULL but the tree
- *   is empty then -ENOENT is returned.
- *   If 'brec', 'brec->tree' and 'target' are non-NULL but the call to
- *   hfs_brec_init() fails then '*brec' is NULL and -EIO is returned.
- *   If 'brec', 'brec->tree' and 'target' are non-NULL and the tree is
- *   non-empty then the tree is searched as follows:
- *    If any call to hfs_brec_next() fails or returns a node that is
- *     neither an index node nor a leaf node then -EIO is returned to
- *     indicate that the B-tree or buffer-cache are corrupted.
- *    If every record in the tree is "greater than" the given key
- *     and the HFS_BFIND_EXACT bit of 'flags' is set then -ENOENT is returned.
- *    If every record in the tree is "greater than" the given key
- *     and the HFS_BFIND_EXACT bit of 'flags' is clear then 'brec' refers
- *     to the first leaf node in the tree and has a 'record' field of
- *     zero, and 1 is returned.
- *    If a "matching" record is located with key "equal to" 'target'
- *     then the return value is 0 and 'brec' indicates the record.
- *    If a "matching" record is located with key "greater than" 'target'
- *     then the behavior is determined as follows:
- *     If the HFS_BFIND_EXACT bit of 'flags' is not set then 1 is returned
- *       and 'brec' refers to the "matching" record.
- *     If the HFS_BFIND_EXACT bit of 'flags' is set then -ENOENT is returned.
- *    If the return value is non-negative and the HFS_BFIND_LOCK bit of
- *     'flags' is set then hfs_brec_lock() is called on the bottom element
- *     of 'brec' before returning.
- */
-int hfs_bfind(struct hfs_brec *brec, struct hfs_btree *tree,
-             const struct hfs_bkey *target, int flags)
+void hfs_find_exit(struct hfs_find_data *fd)
 {
-       struct hfs_belem *curr;
-       struct hfs_bkey *key;
-       struct hfs_bnode *bn;
-       int result, ntype;
-
-       /* check for invalid arguments */
-       if (!brec || (tree->magic != HFS_BTREE_MAGIC) || !target) {
-               return -EINVAL;
-       }
-
-       /* check for empty tree */
-       if (!tree->root || !tree->bthNRecs) {
-               return -ENOENT;
-       }
-
-       /* start search at root of tree */
-       if (!(curr = hfs_brec_init(brec, tree, flags))) {
-               return -EIO;
-       }
+       hfs_bnode_put(fd->bnode);
+       kfree(fd->search_key);
+       dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0));
+       up(&fd->tree->tree_lock);
+       fd->tree = NULL;
+}
 
-       /* traverse the tree */
+/* Find the record in bnode that best matches key (not greater than...)*/
+int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
+{
+       int cmpval;
+       u16 off, len, keylen;
+       int rec;
+       int b, e;
+       int res;
+
+       b = 0;
+       e = bnode->num_recs - 1;
+       res = -ENOENT;
        do {
-               bn = curr->bnr.bn;
-
-               if (!curr->record) {
-                       hfs_warn("hfs_bfind: empty bnode\n");
-                       hfs_brec_relse(brec, NULL);
-                       return -EIO;
-               }
-
-               /* reverse linear search yielding largest key "less
-                  than or equal to" 'target'.
-                  It is questionable whether a binary search would be
-                  significantly faster */
-               do {
-                       key = belem_key(curr);
-                       if (!key->KeyLen) {
-                               hfs_warn("hfs_bfind: empty key\n");
-                               hfs_brec_relse(brec, NULL);
-                               return -EIO;
-                       }
-                       result = (tree->compare)(target, key);
-               } while ((result<0) && (--curr->record));
-
-               ntype = bn->ndType;
-
-               /* see if all keys > target */
-               if (!curr->record) {
-                       if (bn->ndBLink) {
-                               /* at a node other than the left-most at a
-                                  given level it means the parent had an
-                                  incorrect key for this child */
-                               hfs_brec_relse(brec, NULL);
-                               hfs_warn("hfs_bfind: corrupted b-tree %d.\n",
-                                        (int)ntohl(tree->entry.cnid));
-                               return -EIO;
-                       }
-                       if (flags & HFS_BFIND_EXACT) {
-                               /* we're not going to find it */
-                               hfs_brec_relse(brec, NULL);
-                               return -ENOENT;
-                       }
-                       if (ntype == ndIndxNode) {
-                               /* since we are at the left-most node at
-                                  the current level and looking for the
-                                  predecessor of 'target' keep going down */
-                               curr->record = 1;
-                       } else {
-                               /* we're at first leaf so fall through */
-                       }
-               }
-
-               /* get next node if necessary */
-               if ((ntype == ndIndxNode) && !(curr = hfs_brec_next(brec))) {
-                       return -EIO;
+               rec = (e + b) / 2;
+               len = hfs_brec_lenoff(bnode, rec, &off);
+               keylen = hfs_brec_keylen(bnode, rec);
+               hfs_bnode_read(bnode, fd->key, off, keylen);
+               cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
+               if (!cmpval) {
+                       e = rec;
+                       res = 0;
+                       goto done;
                }
-       } while (ntype == ndIndxNode);
-
-       if (key->KeyLen > tree->bthKeyLen) {
-               hfs_warn("hfs_bfind: oversized key\n");
-               hfs_brec_relse(brec, NULL);
-               return -EIO;
-       }
-
-       if (ntype != ndLeafNode) {
-               hfs_warn("hfs_bfind: invalid node type %02x in node %d of "
-                        "btree %d\n", bn->ndType, bn->node,
-                        (int)ntohl(tree->entry.cnid));
-               hfs_brec_relse(brec, NULL);
-               return -EIO;
+               if (cmpval < 0)
+                       b = rec + 1;
+               else
+                       e = rec - 1;
+       } while (b <= e);
+       //printk("%d: %d,%d,%d\n", bnode->this, b, e, rec);
+       if (rec != e && e >= 0) {
+               len = hfs_brec_lenoff(bnode, e, &off);
+               keylen = hfs_brec_keylen(bnode, e);
+               hfs_bnode_read(bnode, fd->key, off, keylen);
        }
+done:
+       fd->record = e;
+       fd->keyoffset = off;
+       fd->keylength = keylen;
+       fd->entryoffset = off + keylen;
+       fd->entrylength = len - keylen;
+       return res;
+}
 
-       if ((flags & HFS_BFIND_EXACT) && result) {
-               hfs_brec_relse(brec, NULL);
+/* Traverse a B*Tree from the root to a leaf finding best fit to key */
+/* Return allocated copy of node found, set recnum to best record */
+int hfs_brec_find(struct hfs_find_data *fd)
+{
+       struct hfs_btree *tree;
+       struct hfs_bnode *bnode;
+       u32 data, nidx, parent;
+       int height, res;
+
+       tree = fd->tree;
+       if (fd->bnode)
+               hfs_bnode_put(fd->bnode);
+       fd->bnode = NULL;
+       nidx = tree->root;
+       if (!nidx)
                return -ENOENT;
-       }
-
-       if (!(flags & HFS_BPATH_MASK)) {
-               hfs_brec_relse(brec, brec->bottom-1);
-       }
+       height = tree->depth;
+       res = 0;
+       parent = 0;
+       for (;;) {
+               bnode = hfs_bnode_find(tree, nidx);
+               if (IS_ERR(bnode)) {
+                       res = PTR_ERR(bnode);
+                       bnode = NULL;
+                       break;
+               }
+               if (bnode->height != height)
+                       goto invalid;
+               if (bnode->type != (--height ? HFS_NODE_INDEX : HFS_NODE_LEAF))
+                       goto invalid;
+               bnode->parent = parent;
+
+               res = __hfs_brec_find(bnode, fd);
+               if (!height)
+                       break;
+               if (fd->record < 0)
+                       goto release;
 
-       if (flags & HFS_BFIND_LOCK) {
-               hfs_brec_lock(brec, brec->bottom);
+               parent = nidx;
+               hfs_bnode_read(bnode, &data, fd->entryoffset, 4);
+               nidx = be32_to_cpu(data);
+               hfs_bnode_put(bnode);
        }
-
-       brec->key  = brec_key(brec);
-       brec->data = bkey_record(brec->key);
-
-       return result ? 1 : 0;
+       fd->bnode = bnode;
+       return res;
+
+invalid:
+       printk("HFS: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n",
+               height, bnode->height, bnode->type, nidx, parent);
+       res = -EIO;
+release:
+       hfs_bnode_put(bnode);
+       return res;
 }
 
-/*
- * hfs_bsucc()
- *
- * Description:
- *   This function overwrites '*brec' with its successor in the B-tree,
- *   obtaining the same type of access.
- * Input Variable(s):
- *   struct hfs_brec *brec: address of the (struct hfs_brec) to overwrite
- *    with its successor
- * Output Variable(s):
- *   struct hfs_brec *brec: address of the successor of the original
- *    '*brec' or to invalid data
- * Returns:
- *   int: 0 on success, or one of -EINVAL, -EIO, or -EINVAL on failure
- * Preconditions:
- *   'brec' pointers to a "valid" (struct hfs_brec)
- * Postconditions:
- *   If the given '*brec' is not "valid" -EINVAL is returned and
- *    '*brec' is unchanged.
- *   If the given 'brec' is "valid" but has no successor then -ENOENT
- *    is returned and '*brec' is invalid.
- *   If a call to hfs_bnode_find() is necessary to find the successor,
- *    but fails then -EIO is returned and '*brec' is invalid.
- *   If none of the three previous conditions prevents finding the
- *    successor of '*brec', then 0 is returned, and '*brec' is overwritten
- *    with the (struct hfs_brec) for its successor.
- *   In the cases when '*brec' is invalid, the old records is freed.
- */
-int hfs_bsucc(struct hfs_brec *brec, int count)
+int hfs_brec_read(struct hfs_find_data *fd, void *rec, int rec_len)
 {
-       struct hfs_belem *belem;
-       struct hfs_bnode *bn;
+       int res;
 
-       if (!brec || !(belem = brec->bottom) || (belem != brec->top) ||
-           !(bn = belem->bnr.bn) || (bn->magic != HFS_BNODE_MAGIC) ||
-           !bn->tree || (bn->tree->magic != HFS_BTREE_MAGIC) ||
-           !hfs_buffer_ok(bn->buf)) {
-               hfs_warn("hfs_bsucc: invalid/corrupt arguments.\n");
+       res = hfs_brec_find(fd);
+       if (res)
+               return res;
+       if (fd->entrylength > rec_len)
                return -EINVAL;
-       }
-
-       while (count) {
-               int left = bn->ndNRecs - belem->record;
-
-               if (left < count) {
-                       struct hfs_bnode_ref old;
-                       hfs_u32 node;
+       hfs_bnode_read(fd->bnode, rec, fd->entryoffset, fd->entrylength);
+       return 0;
+}
 
-                       /* Advance to next node */
-                       if (!(node = bn->ndFLink)) {
-                               hfs_brec_relse(brec, belem);
-                               return -ENOENT;
+int hfs_brec_goto(struct hfs_find_data *fd, int cnt)
+{
+       struct hfs_btree *tree;
+       struct hfs_bnode *bnode;
+       int idx, res = 0;
+       u16 off, len, keylen;
+
+       bnode = fd->bnode;
+       tree = bnode->tree;
+
+       if (cnt < 0) {
+               cnt = -cnt;
+               while (cnt > fd->record) {
+                       cnt -= fd->record + 1;
+                       fd->record = bnode->num_recs - 1;
+                       idx = bnode->prev;
+                       if (!idx) {
+                               res = -ENOENT;
+                               goto out;
+                       }
+                       hfs_bnode_put(bnode);
+                       bnode = hfs_bnode_find(tree, idx);
+                       if (IS_ERR(bnode)) {
+                               res = PTR_ERR(bnode);
+                               bnode = NULL;
+                               goto out;
                        }
-                       if (node == bn->node) {
-                               hfs_warn("hfs_bsucc: corrupt btree\n");
-                               hfs_brec_relse(brec, belem);
-                               return -EIO;
+               }
+               fd->record -= cnt;
+       } else {
+               while (cnt >= bnode->num_recs - fd->record) {
+                       cnt -= bnode->num_recs - fd->record;
+                       fd->record = 0;
+                       idx = bnode->next;
+                       if (!idx) {
+                               res = -ENOENT;
+                               goto out;
                        }
-                       old = belem->bnr;
-                       belem->bnr = hfs_bnode_find(brec->tree, node,
-                                                   belem->bnr.lock_type);
-                       hfs_bnode_relse(&old);
-                       if (!(bn = belem->bnr.bn)) {
-                               return -EIO;
+                       hfs_bnode_put(bnode);
+                       bnode = hfs_bnode_find(tree, idx);
+                       if (IS_ERR(bnode)) {
+                               res = PTR_ERR(bnode);
+                               bnode = NULL;
+                               goto out;
                        }
-                       belem->record = 1;
-                       count -= (left + 1);
-               } else {
-                       belem->record += count;
-                       break;
                }
+               fd->record += cnt;
        }
-       brec->key  = belem_key(belem);
-       brec->data = bkey_record(brec->key);
 
-       if (brec->key->KeyLen > brec->tree->bthKeyLen) {
-               hfs_warn("hfs_bsucc: oversized key\n");
-               hfs_brec_relse(brec, NULL);
-               return -EIO;
-       }
-
-       return 0;
+       len = hfs_brec_lenoff(bnode, fd->record, &off);
+       keylen = hfs_brec_keylen(bnode, fd->record);
+       fd->keyoffset = off;
+       fd->keylength = keylen;
+       fd->entryoffset = off + keylen;
+       fd->entrylength = len - keylen;
+       hfs_bnode_read(bnode, fd->key, off, keylen);
+out:
+       fd->bnode = bnode;
+       return res;
 }
diff --git a/fs/hfs/bins_del.c b/fs/hfs/bins_del.c
deleted file mode 100644 (file)
index a03b959..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * linux/fs/hfs/bins_del.c
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the code common to inserting and deleting records
- * in a B-tree.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- */
-
-#include "hfs_btree.h"
-
-/*================ File-local functions ================*/
-
-/*
- * hfs_bnode_update_key()
- *
- * Description:
- *   Updates the key for a bnode in its parent.
- *   The key change is propagated up the tree as necessary.
- * Input Variable(s):
- *   struct hfs_brec *brec: the search path to update keys in
- *   struct hfs_belem *belem: the search path element with the changed key
- *   struct hfs_bnode *bnode: the bnode with the changed key
- *   int offset: the "distance" from 'belem->bn' to 'bnode':
- *    0 if the change is in 'belem->bn',
- *    1 if the change is in its right sibling, etc.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'brec' points to a valid (struct hfs_brec)
- *   'belem' points to a valid (struct hfs_belem) in 'brec'.
- *   'bnode' points to a valid (struct hfs_bnode) which is non-empty
- *    and is 'belem->bn' or one of its siblings.
- *   'offset' is as described above.
- * Postconditions:
- *   The key change is propagated up the tree as necessary.
- */
-void hfs_bnode_update_key(struct hfs_brec *brec, struct hfs_belem *belem,
-                         struct hfs_bnode *bnode, int offset)
-{
-       int record = (--belem)->record + offset;
-       void *key = bnode_datastart(bnode) + 1;
-       int keysize = brec->tree->bthKeyLen;
-       struct hfs_belem *limit;
-
-       memcpy(1+bnode_key(belem->bnr.bn, record), key, keysize);
-
-       /* don't trash the header */
-       if (brec->top > &brec->elem[1]) {
-               limit = brec->top;
-       } else {
-               limit = &brec->elem[1];
-       }
-
-       while ((belem > limit) && (record == 1)) {
-               record = (--belem)->record;
-               memcpy(1+belem_key(belem), key, keysize);
-       }
-}
-
-/*
- * hfs_bnode_shift_right()
- *
- * Description:
- *   Shifts some records from a node to its right neighbor.
- * Input Variable(s):
- *   struct hfs_bnode* left: the node to shift records from
- *   struct hfs_bnode* right: the node to shift records to
- *   hfs_u16 first: the number of the first record in 'left' to move to 'right'
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'left' and 'right' point to valid (struct hfs_bnode)s.
- *   'left' contains at least 'first' records.
- *   'right' has enough free space to hold the records to be moved from 'left'
- * Postconditions:
- *   The record numbered 'first' and all records after it in 'left' are
- *   placed at the beginning of 'right'.
- *   The key corresponding to 'right' in its parent is NOT updated.
- */
-void hfs_bnode_shift_right(struct hfs_bnode *left, struct hfs_bnode *right,
-                          int first)
-{
-       int i, adjust, nrecs;
-       unsigned size;
-       hfs_u16 *to, *from;
-
-       if ((first <= 0) || (first > left->ndNRecs)) {
-               hfs_warn("bad argument to shift_right: first=%d, nrecs=%d\n",
-                      first, left->ndNRecs);
-               return;
-       }
-
-       /* initialize variables */
-       nrecs = left->ndNRecs + 1 - first;
-       size = bnode_end(left) - bnode_offset(left, first);
-
-       /* move (possibly empty) contents of right node forward */
-       memmove(bnode_datastart(right) + size,
-               bnode_datastart(right), 
-               bnode_end(right) - sizeof(struct NodeDescriptor));
-
-       /* copy in new records */
-       memcpy(bnode_datastart(right), bnode_key(left,first), size);
-
-       /* fix up offsets in right node */
-       i = right->ndNRecs + 1;
-       from = RECTBL(right, i);
-       to = from - nrecs;
-       while (i--) {
-               hfs_put_hs(hfs_get_hs(from++) + size, to++);
-       }
-       adjust = sizeof(struct NodeDescriptor) - bnode_offset(left, first);
-       i = nrecs-1;
-       from = RECTBL(left, first+i);
-       while (i--) {
-               hfs_put_hs(hfs_get_hs(from++) + adjust, to++);
-       }
-
-       /* fix record counts */
-       left->ndNRecs -= nrecs;
-       right->ndNRecs += nrecs;
-}
-
-/*
- * hfs_bnode_shift_left()
- *
- * Description:
- *   Shifts some records from a node to its left neighbor.
- * Input Variable(s):
- *   struct hfs_bnode* left: the node to shift records to
- *   struct hfs_bnode* right: the node to shift records from
- *   hfs_u16 last: the number of the last record in 'right' to move to 'left'
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'left' and 'right' point to valid (struct hfs_bnode)s.
- *   'right' contains at least 'last' records.
- *   'left' has enough free space to hold the records to be moved from 'right'
- * Postconditions:
- *   The record numbered 'last' and all records before it in 'right' are
- *   placed at the end of 'left'.
- *   The key corresponding to 'right' in its parent is NOT updated.
- */
-void hfs_bnode_shift_left(struct hfs_bnode *left, struct hfs_bnode *right,
-                         int last)
-{
-       int i, adjust, nrecs;
-       unsigned size;
-       hfs_u16 *to, *from;
-
-       if ((last <= 0) || (last > right->ndNRecs)) {
-               hfs_warn("bad argument to shift_left: last=%d, nrecs=%d\n",
-                      last, right->ndNRecs);
-               return;
-       }
-
-       /* initialize variables */
-       size = bnode_offset(right, last + 1) - sizeof(struct NodeDescriptor);
-
-       /* copy records to left node */
-       memcpy(bnode_dataend(left), bnode_datastart(right), size);
-
-       /* move (possibly empty) remainder of right node backward */
-       memmove(bnode_datastart(right), bnode_datastart(right) + size, 
-                       bnode_end(right) - bnode_offset(right, last + 1));
-
-       /* fix up offsets */
-       nrecs = left->ndNRecs;
-       i = last;
-       from = RECTBL(right, 2);
-       to = RECTBL(left, nrecs + 2);
-       adjust = bnode_offset(left, nrecs + 1) - sizeof(struct NodeDescriptor);
-       while (i--) {
-               hfs_put_hs(hfs_get_hs(from--) + adjust, to--);
-       }
-       i = right->ndNRecs + 1 - last;
-       ++from;
-       to = RECTBL(right, 1);
-       while (i--) {
-               hfs_put_hs(hfs_get_hs(from--) - size, to--);
-       }
-
-       /* fix record counts */
-       left->ndNRecs += last;
-       right->ndNRecs -= last;
-}
-
-/*
- * hfs_bnode_in_brec()
- *
- * Description:
- *   Determines whethet a given bnode is part of a given brec.
- *   This is used to avoid deadlock in the case of a corrupted b-tree.
- * Input Variable(s):
- *   hfs_u32 node: the number of the node to check for.
- *   struct hfs_brec* brec: the brec to check in.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   int: 1 it found, 0 if not
- * Preconditions:
- *   'brec' points to a valid struct hfs_brec.
- * Postconditions:
- *   'brec' is unchanged.
- */
-int hfs_bnode_in_brec(hfs_u32 node, const struct hfs_brec *brec)
-{
-       const struct hfs_belem *belem = brec->bottom;
-
-       while (belem && (belem >= brec->top)) {
-               if (belem->bnr.bn && (belem->bnr.bn->node == node)) {
-                       return 1;
-               }
-               --belem;
-       }
-       return 0;
-}
diff --git a/fs/hfs/binsert.c b/fs/hfs/binsert.c
deleted file mode 100644 (file)
index 7fe11c3..0000000
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * linux/fs/hfs/binsert.c
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the code to insert records in a B-tree.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- */
-
-#include "hfs_btree.h"
-
-/*================ File-local functions ================*/
-/*
- * binsert_nonfull()
- *
- * Description:
- *   Inserts a record in a given bnode known to have sufficient space.
- * Input Variable(s):
- *   struct hfs_brec* brec: pointer to the brec for the insertion
- *   struct hfs_belem* belem: the element in the search path to insert in
- *   struct hfs_bkey* key: pointer to the key for the record to insert
- *   void* data: pointer to the record to insert
- *   hfs_u16 keysize: size of the key to insert
- *   hfs_u16 datasize: size of the record to insert
- * Output Variable(s):
- *   NONE
- * Returns:
- *   NONE
- * Preconditions:
- *   'brec' points to a valid (struct hfs_brec).
- *   'belem' points to a valid (struct hfs_belem) in 'brec', the node
- *    of which has enough free space to insert 'key' and 'data'.
- *   'key' is a pointer to a valid (struct hfs_bkey) of length 'keysize'
- *    which, in sorted order, belongs at the location indicated by 'brec'.
- *   'data' is non-NULL an points to appropriate data of length 'datasize'
- * Postconditions:
- *   The record has been inserted in the position indicated by 'brec'.
- */
-static void binsert_nonfull(struct hfs_brec *brec, struct hfs_belem *belem,
-                           const struct hfs_bkey *key, const void *data,
-                           hfs_u8 keysize, hfs_u16 datasize)
-{
-       int i, rec, nrecs, size, tomove;
-       hfs_u8 *start;
-       struct hfs_bnode *bnode = belem->bnr.bn;
-
-       rec = ++(belem->record);
-       size = ROUND(keysize+1) + datasize;
-       nrecs = bnode->ndNRecs + 1;
-       tomove = bnode_offset(bnode, nrecs) - bnode_offset(bnode, rec);
-       
-       /* adjust the record table */
-       for (i = nrecs; i >= rec; --i) {
-               hfs_put_hs(bnode_offset(bnode,i) + size, RECTBL(bnode,i+1));
-       }
-
-       /* make room */
-       start = bnode_key(bnode, rec);
-       memmove(start + size, start, tomove);
-
-       /* copy in the key and the data*/
-       *start = keysize;
-       keysize = ROUND(keysize+1);
-       memcpy(start + 1, (hfs_u8 *)key + 1, keysize-1);
-       memcpy(start + keysize, data, datasize);
-
-       /* update record count */
-       ++bnode->ndNRecs;
-}
-
-/*
- * add_root()
- *
- * Description:
- *   Adds a new root to a B*-tree, increasing its height.
- * Input Variable(s):
- *   struct hfs_btree *tree: the tree to add a new root to
- *   struct hfs_bnode *left: the new root's first child or NULL
- *   struct hfs_bnode *right: the new root's second child or NULL
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'tree' points to a valid (struct hfs_btree).
- *   'left' and 'right' point to valid (struct hfs_bnode)s, which
- *    resulted from splitting the old root node, or are both NULL
- *    if there was no root node before.
- * Postconditions:
- *   Upon success a new root node is added to 'tree' with either
- *    two children ('left' and 'right') or none.
- */
-static void add_root(struct hfs_btree *tree,
-                    struct hfs_bnode *left,
-                    struct hfs_bnode *right)
-{
-       struct hfs_bnode_ref bnr;
-       struct hfs_bnode *root;
-       struct hfs_bkey *key;
-       int keylen = tree->bthKeyLen;
-
-       if (left && !right) {
-               hfs_warn("add_root: LEFT but no RIGHT\n");
-               return;
-       }
-
-       bnr = hfs_bnode_alloc(tree);
-       if (!(root = bnr.bn)) {
-               return;
-       }
-
-       root->sticky = HFS_STICKY;
-       tree->root = root;
-       tree->bthRoot = root->node;
-       ++tree->bthDepth;
-
-       root->ndNHeight = tree->bthDepth;
-       root->ndFLink = 0;
-       root->ndBLink = 0;
-
-       if (!left) {
-               /* tree was empty */
-               root->ndType  = ndLeafNode;
-               root->ndNRecs = 0;
-
-               tree->bthFNode = root->node;
-               tree->bthLNode = root->node;
-       } else {
-               root->ndType  = ndIndxNode;
-               root->ndNRecs = 2;
-
-               hfs_put_hs(sizeof(struct NodeDescriptor) + ROUND(1+keylen) +
-                          sizeof(hfs_u32), RECTBL(root, 2));
-               key = bnode_key(root, 1);
-               key->KeyLen = keylen;
-               memcpy(key->value,
-                      ((struct hfs_bkey *)bnode_key(left, 1))->value, keylen);
-               hfs_put_hl(left->node, bkey_record(key));
-               
-               hfs_put_hs(sizeof(struct NodeDescriptor) + 2*ROUND(1+keylen) +
-                          2*sizeof(hfs_u32), RECTBL(root, 3));
-               key = bnode_key(root, 2);
-               key->KeyLen = keylen;
-               memcpy(key->value,
-                      ((struct hfs_bkey *)bnode_key(right, 1))->value, keylen);
-               hfs_put_hl(right->node, bkey_record(key));
-
-               /* the former root (left) is now just a normal node */
-               left->sticky = HFS_NOT_STICKY;
-               if ((left->next = bhash(tree, left->node))) {
-                       left->next->prev = left;
-               }
-               bhash(tree, left->node) = left;
-       }
-       hfs_bnode_relse(&bnr);
-       tree->dirt = 1;
-}
-
-/*
- * insert_empty_bnode()
- *
- * Description:
- *   Adds an empty node to the right of 'left'.
- * Input Variable(s):
- *   struct hfs_btree *tree: the tree to add a node to
- *   struct hfs_bnode *left: the node to add a node after
- * Output Variable(s):
- *   NONE
- * Returns:
- *   struct hfs_bnode_ref *: reference to the new bnode.
- * Preconditions:
- *   'tree' points to a valid (struct hfs_btree) with at least 1 free node.
- *   'left' points to a valid (struct hfs_bnode) belonging to 'tree'.
- * Postconditions:
- *   If NULL is returned then 'tree' and 'left' are unchanged.
- *   Otherwise a node with 0 records is inserted in the tree to the right
- *   of the node 'left'.  The 'ndFLink' of 'left' and the 'ndBLink' of
- *   the former right-neighbor of 'left' (if one existed) point to the
- *   new node. If 'left' had no right neighbor and is a leaf node the
- *   the 'bthLNode' of 'tree' points to the new node.  The free-count and
- *   bitmap for 'tree' are kept current by hfs_bnode_alloc() which supplies
- *   the required node.
- */
-static struct hfs_bnode_ref insert_empty_bnode(struct hfs_btree *tree,
-                                              struct hfs_bnode *left)
-{
-       struct hfs_bnode_ref retval;
-       struct hfs_bnode_ref right;
-
-       retval = hfs_bnode_alloc(tree);
-       if (!retval.bn) {
-               hfs_warn("hfs_binsert: out of bnodes?.\n");
-               goto done;
-       }
-       retval.bn->sticky = HFS_NOT_STICKY;
-       if ((retval.bn->next = bhash(tree, retval.bn->node))) {
-               retval.bn->next->prev = retval.bn;
-       }
-       bhash(tree, retval.bn->node) = retval.bn;
-
-       if (left->ndFLink) {
-               right = hfs_bnode_find(tree, left->ndFLink, HFS_LOCK_WRITE);
-               if (!right.bn) {
-                       hfs_warn("hfs_binsert: corrupt btree.\n");
-                       hfs_bnode_bitop(tree, retval.bn->node, 0);
-                       hfs_bnode_relse(&retval);
-                       goto done;
-               }
-               right.bn->ndBLink = retval.bn->node;
-               hfs_bnode_relse(&right);
-       } else if (left->ndType == ndLeafNode) {
-               tree->bthLNode = retval.bn->node;
-               tree->dirt = 1;
-       }
-
-       retval.bn->ndFLink   = left->ndFLink;
-       retval.bn->ndBLink   = left->node;
-       retval.bn->ndType    = left->ndType;
-       retval.bn->ndNHeight = left->ndNHeight;
-       retval.bn->ndNRecs   = 0;
-
-       left->ndFLink = retval.bn->node;
-
- done:
-       return retval;
-}
-
-/*
- * split()
- *
- * Description:
- *   Splits an over full node during insertion.
- *   Picks the split point that results in the most-nearly equal
- *   space usage in the new and old nodes.
- * Input Variable(s):
- *   struct hfs_belem *elem: the over full node.
- *   int size: the number of bytes to be used by the new record and its key.
- * Output Variable(s):
- *   struct hfs_belem *elem: changed to indicate where the new record
- *    should be inserted.
- * Returns:
- *   struct hfs_bnode_ref: reference to the new bnode.
- * Preconditions:
- *   'elem' points to a valid path element corresponding to the over full node.
- *   'size' is positive.
- * Postconditions:
- *   The records in the node corresponding to 'elem' are redistributed across
- *   the old and new nodes so that after inserting the new record, the space
- *   usage in these two nodes is as equal as possible.
- *   'elem' is updated so that a call to binsert_nonfull() will insert the
- *   new record in the correct location.
- */
-static inline struct hfs_bnode_ref split(struct hfs_belem *elem, int size)
-{
-       struct hfs_bnode *bnode = elem->bnr.bn;
-       int nrecs, cutoff, index, tmp, used, in_right;
-       struct hfs_bnode_ref right;
-
-       right = insert_empty_bnode(bnode->tree, bnode);
-       if (right.bn) {
-               nrecs = bnode->ndNRecs;
-               cutoff = (size + bnode_end(bnode) -
-                             sizeof(struct NodeDescriptor) +
-                             (nrecs+1)*sizeof(hfs_u16))/2;
-               used = 0;
-               in_right = 1;
-               /* note that this only works because records sizes are even */
-               for (index=1; index <= elem->record; ++index) {
-                       tmp = (sizeof(hfs_u16) + bnode_rsize(bnode, index))/2;
-                       used += tmp;
-                       if (used > cutoff) {
-                               goto found;
-                       }
-                       used += tmp;
-               }
-               tmp = (size + sizeof(hfs_u16))/2;
-               used += tmp;
-               if (used > cutoff) {
-                       goto found;
-               }
-               in_right = 0;
-               used += tmp;
-               for (; index <= nrecs; ++index) {
-                       tmp = (sizeof(hfs_u16) + bnode_rsize(bnode, index))/2;
-                       used += tmp;
-                       if (used > cutoff) {
-                               goto found;
-                       }
-                       used += tmp;
-               }
-               /* couldn't find the split point! */
-               hfs_bnode_relse(&right);
-       }
-       return right;
-
-found:
-       if (in_right) {
-               elem->bnr = right;
-               elem->record -= index-1;
-       }
-       hfs_bnode_shift_right(bnode, right.bn, index);
-
-       return right;
-}
-
-/*
- * binsert()
- *
- * Description:
- *   Inserts a record in a tree known to have enough room, even if the
- *   insertion requires the splitting of nodes.
- * Input Variable(s):
- *    struct hfs_brec *brec: partial path to the node to insert in
- *    const struct hfs_bkey *key: key for the new record
- *    const void *data: data for the new record
- *    hfs_u8 keysize: size of the key
- *    hfs_u16 datasize: size of the data
- *    int reserve: number of nodes reserved in case of splits
- * Output Variable(s):
- *    *brec = NULL
- * Returns:
- *    int: 0 on success, error code on failure
- * Preconditions:
- *    'brec' points to a valid (struct hfs_brec) corresponding to a
- *     record in a leaf node, after which a record is to be inserted,
- *     or to "record 0" of the leaf node if the record is to be inserted
- *     before all existing records in the node.         The (struct hfs_brec)
- *     includes all ancestors of the leaf node that are needed to
- *     complete the insertion including the parents of any nodes that
- *     will be split.
- *    'key' points to a valid (struct hfs_bkey) which is appropriate
- *     to this tree, and which belongs at the insertion point.
- *    'data' points data appropriate for the indicated node.
- *    'keysize' gives the size in bytes of the key.
- *    'datasize' gives the size in bytes of the data.
- *    'reserve' gives the number of nodes that have been reserved in the
- *     tree to allow for splitting of nodes.
- * Postconditions:
- *    All 'reserve'd nodes have been either used or released.
- *    *brec = NULL
- *    On success the key and data have been inserted at the indicated
- *    location in the tree, all appropriate fields of the in-core data
- *    structures have been changed and updated versions of the on-disk
- *    data structures have been scheduled for write-back to disk.
- *    On failure the B*-tree is probably invalid both on disk and in-core.
- *
- *    XXX: Some attempt at repair might be made in the event of failure,
- *    or the fs should be remounted read-only so things don't get worse.
- */
-static int binsert(struct hfs_brec *brec, const struct hfs_bkey *key,
-                  const void *data, hfs_u8 keysize, hfs_u16 datasize,
-                  int reserve)
-{
-       struct hfs_bnode_ref left, right, other;
-       struct hfs_btree *tree = brec->tree;
-       struct hfs_belem *belem = brec->bottom;
-       int tmpsize = 1 + tree->bthKeyLen;
-       struct hfs_bkey *tmpkey = hfs_malloc(tmpsize);
-       hfs_u32 node;
-       
-       while ((belem >= brec->top) && (belem->flags & HFS_BPATH_OVERFLOW)) {
-               left = belem->bnr;
-               if (left.bn->ndFLink &&
-                    hfs_bnode_in_brec(left.bn->ndFLink, brec)) {
-                       hfs_warn("hfs_binsert: corrupt btree\n");
-                       tree->reserved -= reserve;
-                       hfs_free(tmpkey, tmpsize);
-                       return -EIO;
-               }
-                       
-               right = split(belem, ROUND(keysize+1) + ROUND(datasize));
-               --reserve;
-               --tree->reserved;
-               if (!right.bn) {
-                       hfs_warn("hfs_binsert: unable to split node!\n");
-                       tree->reserved -= reserve;
-                       hfs_free(tmpkey, tmpsize);
-                       return -ENOSPC;
-               }
-               binsert_nonfull(brec, belem, key, data, keysize, datasize);
-       
-               if (belem->bnr.bn == left.bn) {
-                       other = right;
-                       if (belem->record == 1) {
-                               hfs_bnode_update_key(brec, belem, left.bn, 0);
-                       }
-               } else {
-                       other = left;
-               }
-
-               if (left.bn->node == tree->root->node) {
-                       add_root(tree, left.bn, right.bn);
-                       hfs_bnode_relse(&other);
-                       goto done;
-               }
-
-               data = &node;
-               datasize = sizeof(node);
-               node = htonl(right.bn->node);
-               key = tmpkey;
-               keysize = tree->bthKeyLen;
-               memcpy(tmpkey, bnode_key(right.bn, 1), keysize+1);
-               hfs_bnode_relse(&other);
-               
-               --belem;
-       }
-
-       if (belem < brec->top) {
-               hfs_warn("hfs_binsert: Missing parent.\n");
-               tree->reserved -= reserve;
-               hfs_free(tmpkey, tmpsize);
-               return -EIO;
-       }
-
-       binsert_nonfull(brec, belem, key, data, keysize, datasize);
-
-done:
-       tree->reserved -= reserve;
-       hfs_free(tmpkey, tmpsize);
-       return 0;
-}
-
-/*================ Global functions ================*/
-
-/*
- * hfs_binsert()
- *
- * Description:
- *   This function inserts a new record into a b-tree.
- * Input Variable(s):
- *   struct hfs_btree *tree: pointer to the (struct hfs_btree) to insert in
- *   struct hfs_bkey *key: pointer to the (struct hfs_bkey) to insert
- *   void *data: pointer to the data to associate with 'key' in the b-tree
- *   unsigned int datasize: the size of the data
- * Output Variable(s):
- *   NONE
- * Returns:
- *   int: 0 on success, error code on failure
- * Preconditions:
- *   'tree' points to a valid (struct hfs_btree)
- *   'key' points to a valid (struct hfs_bkey)
- *   'data' points to valid memory of length 'datasize'
- * Postconditions:
- *   If zero is returned then the record has been inserted in the
- *    indicated location updating all in-core data structures and
- *    scheduling all on-disk data structures for write-back.
- */
-int hfs_binsert(struct hfs_btree *tree, const struct hfs_bkey *key,
-               const void *data, hfs_u16 datasize)
-{ 
-       struct hfs_brec brec;
-       struct hfs_belem *belem;
-       int err, reserve, retval;
-       hfs_u8 keysize;
-
-       if (!tree || (tree->magic != HFS_BTREE_MAGIC) || !key || !data) {
-               hfs_warn("hfs_binsert: invalid arguments.\n");
-               return -EINVAL;
-       }
-
-       if (key->KeyLen > tree->bthKeyLen) {
-               hfs_warn("hfs_binsert: oversized key\n");
-               return -EINVAL;
-       }
-
-restart:
-       if (!tree->bthNRecs) {
-               /* create the root bnode */
-               add_root(tree, NULL, NULL);
-               if (!hfs_brec_init(&brec, tree, HFS_BFIND_INSERT)) {
-                       hfs_warn("hfs_binsert: failed to create root.\n");
-                       return -ENOSPC;
-               }
-       } else {
-               err = hfs_bfind(&brec, tree, key, HFS_BFIND_INSERT);
-               if (err < 0) {
-                       hfs_warn("hfs_binsert: hfs_brec_find failed.\n");
-                       return err;
-               } else if (err == 0) {
-                       hfs_brec_relse(&brec, NULL);
-                       return -EEXIST;
-               }
-       }
-
-       keysize = key->KeyLen;
-       datasize = ROUND(datasize);
-       belem = brec.bottom;
-       belem->flags = 0;
-       if (bnode_freespace(belem->bnr.bn) <
-                           (sizeof(hfs_u16) + ROUND(keysize+1) + datasize)) {
-               belem->flags |= HFS_BPATH_OVERFLOW;
-       }
-       if (belem->record == 0) {
-               belem->flags |= HFS_BPATH_FIRST;
-       }
-
-       if (!belem->flags) {
-               hfs_brec_lock(&brec, brec.bottom);
-               reserve = 0;
-       } else {
-               reserve = brec.bottom - brec.top;
-               if (brec.top == 0) {
-                       ++reserve;
-               }
-               /* make certain we have enough nodes to proceed */
-               if ((tree->bthFree - tree->reserved) < reserve) {
-                       hfs_brec_relse(&brec, NULL);
-                       down(&tree->sem);
-                       if ((tree->bthFree - tree->reserved) < reserve) {
-                               hfs_btree_extend(tree);
-                       }
-                       up(&tree->sem);
-                       if ((tree->bthFree - tree->reserved) < reserve) {
-                               return -ENOSPC;
-                       } else {
-                               goto restart;
-                       }
-               }
-               tree->reserved += reserve;
-               hfs_brec_lock(&brec, NULL);
-       }
-
-       retval = binsert(&brec, key, data, keysize, datasize, reserve);
-       hfs_brec_relse(&brec, NULL);
-       if (!retval) {
-               ++tree->bthNRecs;
-               tree->dirt = 1;
-       }
-       return retval;
-}
index c9bb850d3d9ac9c2f9199b9daadabd875b0d074d..117fe1e1983a4736efb670756f57ffe6c2a12e0a 100644 (file)
 /*
- * linux/fs/hfs/bitmap.c
+ *  linux/fs/hfs/bitmap.c
  *
  * Copyright (C) 1996-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * Based on GPLed code Copyright (C) 1995  Michael Dreher
  *
  * This file contains the code to modify the volume bitmap:
  * search/set/clear bits.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
  */
 
-#include "hfs.h"
-
-/*================ Global functions ================*/
+#include "hfs_fs.h"
 
 /*
- * hfs_vbm_count_free()
+ * hfs_find_zero_bit()
  *
  * Description:
- *   Count the number of consecutive cleared bits in the bitmap blocks of
- *   the hfs MDB starting at bit number 'start'.  'mdb' had better
- *   be locked or the indicated number of blocks may be no longer free,
- *   when this functions returns!
- * Input Variable(s):
- *   struct hfs_mdb *mdb: Pointer to the hfs MDB
- *   hfs_u16 start: bit number to start at
- * Output Variable(s):
- *   NONE
- * Returns:
- *   The number of consecutive cleared bits starting at bit 'start'
- * Preconditions:
- *   'mdb' points to a "valid" (struct hfs_mdb).
- * Postconditions:
- *   NONE
+ *  Given a block of memory, its length in bits, and a starting bit number,
+ *  determine the number of the first zero bits (in left-to-right ordering)
+ *  in that range.
+ *
+ *  Returns >= 'size' if no zero bits are found in the range.
+ *
+ *  Accesses memory in 32-bit aligned chunks of 32-bits and thus
+ *  may read beyond the 'size'th bit.
  */
-hfs_u16 hfs_vbm_count_free(const struct hfs_mdb *mdb, hfs_u16 start)
+static u32 hfs_find_set_zero_bits(u32 *bitmap, u32 size, u32 offset, u32 *max)
 {
-       hfs_u16 block_nr;       /* index of the current bitmap block */
-       hfs_u16 bit_nr;         /* index of the current bit in block */
-       hfs_u16 count;          /* number of bits found so far */
-       hfs_u16 len;            /* number of bits found in this block */
-       hfs_u16 max_block;      /* index of last bitmap block */
-       hfs_u16 max_bits;       /* index of last bit in block */
-
-       /* is this a valid HFS MDB? */
-       if (!mdb) {
-               return 0;
+       u32 *curr, *end;
+       u32 val, mask, start, len;
+       int i;
+
+       len = *max;
+       if (!len)
+               return size;
+
+       curr = bitmap + (offset / 32);
+       end = bitmap + ((size + 31) / 32);
+
+       /* scan the first partial u32 for zero bits */
+       val = *curr;
+       if (~val) {
+               val = be32_to_cpu(val);
+               i = offset % 32;
+               mask = (1U << 31) >> i;
+               for (; i < 32; mask >>= 1, i++) {
+                       if (!(val & mask))
+                               goto found;
+               }
        }
 
-       block_nr = start / HFS_BM_BPB;
-       bit_nr   = start % HFS_BM_BPB;
-       max_block = (mdb->fs_ablocks + HFS_BM_BPB - 1) / HFS_BM_BPB - 1;
-
-       count = 0;
-       while (block_nr <= max_block) {
-               if (block_nr != max_block) {
-                       max_bits = HFS_BM_BPB;
-               } else {
-                       max_bits = mdb->fs_ablocks % HFS_BM_BPB;
+       /* scan complete u32s for the first zero bit */
+       while (++curr < end) {
+               val = *curr;
+               if (~val) {
+                       val = be32_to_cpu(val);
+                       mask = 1 << 31;
+                       for (i = 0; i < 32; mask >>= 1, i++) {
+                               if (!(val & mask))
+                                       goto found;
+                       }
                }
-
-               len=hfs_count_zero_bits(hfs_buffer_data(mdb->bitmap[block_nr]),
-                                       max_bits, bit_nr);
-               count += len;
-
-               /* see if we fell short of the end of this block */
-               if ((len + bit_nr) < max_bits) {
+       }
+       return size;
+
+found:
+       start = (curr - bitmap) * 32 + i;
+       if (start >= size)
+               return start;
+       /* do any partial u32 at the start */
+       len = min(size - start, len);
+       while (1) {
+               val |= mask;
+               if (++i >= 32)
+                       break;
+               mask >>= 1;
+               if (!--len || val & mask)
+                       goto done;
+       }
+       if (!--len)
+               goto done;
+       *curr++ = cpu_to_be32(val);
+       /* do full u32s */
+       while (1) {
+               val = be32_to_cpu(*curr);
+               if (len < 32)
+                       break;
+               if (val) {
+                       len = 32;
                        break;
                }
-
-               ++block_nr;
-               bit_nr = 0;
+               *curr++ = 0xffffffffU;
+               len -= 32;
+       }
+       /* do any partial u32 at end */
+       mask = 1U << 31;
+       for (i = 0; i < len; i++) {
+               if (val & mask)
+                       break;
+               val |= mask;
+               mask >>= 1;
        }
-       return count;
+done:
+       *curr = cpu_to_be32(val);
+       *max = (curr - bitmap) * 32 + i - start;
+       return start;
 }
 
 /*
@@ -92,10 +119,10 @@ hfs_u16 hfs_vbm_count_free(const struct hfs_mdb *mdb, hfs_u16 start)
  *   the bit number stored in 's_alloc_ptr' of the MDB.
  * Input Variable(s):
  *   struct hfs_mdb *mdb: Pointer to the hfs MDB
- *   hfs_u16 *num_bits: Pointer to the number of cleared bits
+ *   u16 *num_bits: Pointer to the number of cleared bits
  *     to search for
  * Output Variable(s):
- *   hfs_u16 *num_bits: The number of consecutive clear bits of the
+ *   u16 *num_bits: The number of consecutive clear bits of the
  *     returned range. If the bitmap is fragmented, this will be less than
  *     requested and it will be zero, when the disk is full.
  * Returns:
@@ -103,198 +130,42 @@ hfs_u16 hfs_vbm_count_free(const struct hfs_mdb *mdb, hfs_u16 start)
  *   found. When 'num_bits' is zero, this is invalid!
  * Preconditions:
  *   'mdb' points to a "valid" (struct hfs_mdb).
- *   'num_bits' points to a variable of type (hfs_u16), which contains
+ *   'num_bits' points to a variable of type (u16), which contains
  *     the number of cleared bits to find.
  * Postconditions:
  *   'num_bits' is set to the length of the found sequence.
  */
-hfs_u16 hfs_vbm_search_free(const struct hfs_mdb *mdb, hfs_u16 *num_bits)
+u32 hfs_vbm_search_free(struct super_block *sb, u32 goal, u32 *num_bits)
 {
-       hfs_u16 block_nr; /* index of the current bitmap block */
+       void *bitmap;
+       u32 pos;
 
-       /* position and length of current portion of a run */
-       hfs_u16 cur_pos, cur_len;
-
-       /* position and length of current complete run */
-       hfs_u16 pos=0, len=0;
-       
-       /* position and length of longest complete run */
-       hfs_u16 longest_pos=0, longest_len=0;
-
-       void *bitmap; /* contents of the current bitmap block */
-       hfs_u16 max_block; /* upper limit of outer loop */
-       hfs_u16 max_bits; /* upper limit of inner loop */
-
-       /* is this a valid HFS MDB? */
-       if (!mdb) {
-               *num_bits = 0;
-               hfs_warn("hfs_vbm_search_free: not a valid MDB\n");
-               return 0;
-       }
-       
        /* make sure we have actual work to perform */
-       if (!(*num_bits)) {
+       if (!*num_bits)
                return 0;
-       }
 
-       max_block = (mdb->fs_ablocks+HFS_BM_BPB-1) / HFS_BM_BPB - 1;
-       
-       /* search all bitmap blocks */
-       for (block_nr = 0; block_nr <= max_block; block_nr++) {
-               bitmap = hfs_buffer_data(mdb->bitmap[block_nr]);
+       down(&HFS_SB(sb)->bitmap_lock);
+       bitmap = HFS_SB(sb)->bitmap;
 
-               if (block_nr != max_block) {
-                       max_bits = HFS_BM_BPB;
-               } else {
-                       max_bits = mdb->fs_ablocks % HFS_BM_BPB;
+       pos = hfs_find_set_zero_bits(bitmap, HFS_SB(sb)->fs_ablocks, goal, num_bits);
+       if (pos >= HFS_SB(sb)->fs_ablocks) {
+               if (goal)
+                       pos = hfs_find_set_zero_bits(bitmap, goal, 0, num_bits);
+               if (pos >= HFS_SB(sb)->fs_ablocks) {
+                       *num_bits = pos = 0;
+                       goto out;
                }
-
-               cur_pos = 0;
-               do {
-                       cur_len = hfs_count_zero_bits(bitmap, max_bits,
-                                                     cur_pos);
-                       len += cur_len;
-                       if (len > longest_len) {
-                               longest_pos = pos;
-                               longest_len = len;
-                               if (len >= *num_bits) {
-                                       goto search_end;
-                               }
-                       }
-                       if ((cur_pos + cur_len) == max_bits) {
-                               break; /* zeros may continue into next block */
-                       }
-
-                       /* find start of next run of zeros */
-                       cur_pos = hfs_find_zero_bit(bitmap, max_bits,
-                                                   cur_pos + cur_len);
-                       pos = cur_pos + HFS_BM_BPB*block_nr;
-                       len = 0;
-               } while (cur_pos < max_bits);
        }
 
-search_end:
-       *num_bits = longest_len;
-       return longest_pos;
+       dprint(DBG_BITMAP, "alloc_bits: %u,%u\n", pos, *num_bits);
+       HFS_SB(sb)->free_ablocks -= *num_bits;
+       hfs_bitmap_dirty(sb);
+out:
+       up(&HFS_SB(sb)->bitmap_lock);
+       return pos;
 }
 
 
-/*
- * hfs_set_vbm_bits()
- *
- * Description:
- *   Set the requested bits in the volume bitmap of the hfs filesystem
- * Input Variable(s):
- *   struct hfs_mdb *mdb: Pointer to the hfs MDB
- *   hfs_u16 start: The offset of the first bit
- *   hfs_u16 count: The number of bits
- * Output Variable(s):
- *   None
- * Returns:
- *    0: no error
- *   -1: One of the bits was already set.  This is a strange
- *      error and when it happens, the filesystem must be repaired!
- *   -2: One or more of the bits are out of range of the bitmap.
- *   -3: The 's_magic' field of the MDB does not match
- * Preconditions:
- *   'mdb' points to a "valid" (struct hfs_mdb).
- * Postconditions:
- *   Starting with bit number 'start', 'count' bits in the volume bitmap
- *   are set. The affected bitmap blocks are marked "dirty", the free
- *   block count of the MDB is updated and the MDB is marked dirty.
- */
-int hfs_set_vbm_bits(struct hfs_mdb *mdb, hfs_u16 start, hfs_u16 count)
-{
-       hfs_u16 block_nr;       /* index of the current bitmap block */
-       hfs_u16 u32_nr;         /* index of the current hfs_u32 in block */
-       hfs_u16 bit_nr;         /* index of the current bit in hfs_u32 */
-       hfs_u16 left = count;   /* number of bits left to be set */
-       hfs_u32 *bitmap;        /* the current bitmap block's contents */
-
-       /* is this a valid HFS MDB? */
-       if (!mdb) {
-               return -3;
-       }
-
-       /* is there any actual work to be done? */
-       if (!count) {
-               return 0;
-       }
-
-       /* are all of the bits in range? */
-       if ((start + count) > mdb->fs_ablocks) {
-               return -2;
-       }
-
-       block_nr = start / HFS_BM_BPB;
-       u32_nr = (start % HFS_BM_BPB) / 32;
-       bit_nr = start % 32;
-
-       /* bitmap is always on a 32-bit boundary */
-       bitmap = (hfs_u32 *)hfs_buffer_data(mdb->bitmap[block_nr]);
-
-       /* do any partial hfs_u32 at the start */
-       if (bit_nr != 0) {
-               while ((bit_nr < 32) && left) {
-                       if (hfs_set_bit(bit_nr, bitmap + u32_nr)) {
-                               hfs_buffer_dirty(mdb->bitmap[block_nr]);
-                               return -1;
-                       }
-                       ++bit_nr;
-                       --left;
-               }
-               bit_nr=0;
-
-               /* advance u32_nr and check for end of this block */
-               if (++u32_nr > 127) {
-                       u32_nr = 0;
-                       hfs_buffer_dirty(mdb->bitmap[block_nr]);
-                       ++block_nr;
-                       /* bitmap is always on a 32-bit boundary */
-                       bitmap = (hfs_u32 *)
-                                       hfs_buffer_data(mdb->bitmap[block_nr]);
-               }
-       }
-
-       /* do full hfs_u32s */
-       while (left > 31) {
-               if (bitmap[u32_nr] != ((hfs_u32)0)) {
-                       hfs_buffer_dirty(mdb->bitmap[block_nr]);
-                       return -1;
-               }
-               bitmap[u32_nr] = ~((hfs_u32)0);
-               left -= 32;
-
-               /* advance u32_nr and check for end of this block */
-               if (++u32_nr > 127) {
-                       u32_nr = 0;
-                       hfs_buffer_dirty(mdb->bitmap[block_nr]);
-                       ++block_nr;
-                       /* bitmap is always on a 32-bit boundary */
-                       bitmap = (hfs_u32 *)
-                                       hfs_buffer_data(mdb->bitmap[block_nr]);
-               }
-       }
-
-                       
-       /* do any partial hfs_u32 at end */
-       while (left) {
-               if (hfs_set_bit(bit_nr, bitmap + u32_nr)) {
-                       hfs_buffer_dirty(mdb->bitmap[block_nr]);
-                       return -1;
-               }
-               ++bit_nr;
-               --left;
-       }
-
-       hfs_buffer_dirty(mdb->bitmap[block_nr]);
-       mdb->free_ablocks -= count;
-
-       /* successful completion */
-       hfs_mdb_dirty(mdb->sys_mdb);
-       return 0;
-}
-
 /*
  * hfs_clear_vbm_bits()
  *
@@ -302,8 +173,8 @@ int hfs_set_vbm_bits(struct hfs_mdb *mdb, hfs_u16 start, hfs_u16 count)
  *   Clear the requested bits in the volume bitmap of the hfs filesystem
  * Input Variable(s):
  *   struct hfs_mdb *mdb: Pointer to the hfs MDB
- *   hfs_u16 start: The offset of the first bit
- *   hfs_u16 count: The number of bits
+ *   u16 start: The offset of the first bit
+ *   u16 count: The number of bits
  * Output Variable(s):
  *   None
  * Returns:
@@ -311,7 +182,6 @@ int hfs_set_vbm_bits(struct hfs_mdb *mdb, hfs_u16 start, hfs_u16 count)
  *   -1: One of the bits was already clear.  This is a strange
  *      error and when it happens, the filesystem must be repaired!
  *   -2: One or more of the bits are out of range of the bitmap.
- *   -3: The 's_magic' field of the MDB does not match
  * Preconditions:
  *   'mdb' points to a "valid" (struct hfs_mdb).
  * Postconditions:
@@ -319,94 +189,54 @@ int hfs_set_vbm_bits(struct hfs_mdb *mdb, hfs_u16 start, hfs_u16 count)
  *   are cleared. The affected bitmap blocks are marked "dirty", the free
  *   block count of the MDB is updated and the MDB is marked dirty.
  */
-int hfs_clear_vbm_bits(struct hfs_mdb *mdb, hfs_u16 start, hfs_u16 count)
+int hfs_clear_vbm_bits(struct super_block *sb, u16 start, u16 count)
 {
-       hfs_u16 block_nr;       /* index of the current bitmap block */
-       hfs_u16 u32_nr;         /* index of the current hfs_u32 in block */
-       hfs_u16 bit_nr;         /* index of the current bit in hfs_u32 */
-       hfs_u16 left = count;   /* number of bits left to be set */
-       hfs_u32 *bitmap;        /* the current bitmap block's contents */
-
-       /* is this a valid HFS MDB? */
-       if (!mdb) {
-               return -3;
-       }
+       u32 *curr;
+       u32 mask;
+       int i, len;
 
        /* is there any actual work to be done? */
-       if (!count) {
+       if (!count)
                return 0;
-       }
 
+       dprint(DBG_BITMAP, "clear_bits: %u,%u\n", start, count);
        /* are all of the bits in range? */
-       if ((start + count) > mdb->fs_ablocks) {
+       if ((start + count) > HFS_SB(sb)->fs_ablocks)
                return -2;
-       }
-
-       block_nr = start / HFS_BM_BPB;
-       u32_nr = (start % HFS_BM_BPB) / 32;
-       bit_nr = start % 32;
 
+       down(&HFS_SB(sb)->bitmap_lock);
        /* bitmap is always on a 32-bit boundary */
-       bitmap = (hfs_u32 *)hfs_buffer_data(mdb->bitmap[block_nr]);
-
-       /* do any partial hfs_u32 at the start */
-       if (bit_nr != 0) {
-               while ((bit_nr < 32) && left) {
-                       if (!hfs_clear_bit(bit_nr, bitmap + u32_nr)) {
-                               hfs_buffer_dirty(mdb->bitmap[block_nr]);
-                               return -1;
-                       }
-                       ++bit_nr;
-                       --left;
-               }
-               bit_nr=0;
-
-               /* advance u32_nr and check for end of this block */
-               if (++u32_nr > 127) {
-                       u32_nr = 0;
-                       hfs_buffer_dirty(mdb->bitmap[block_nr]);
-                       ++block_nr;
-                       /* bitmap is always on a 32-bit boundary */
-                       bitmap = (hfs_u32 *)
-                                       hfs_buffer_data(mdb->bitmap[block_nr]);
+       curr = HFS_SB(sb)->bitmap + (start / 32);
+       len = count;
+
+       /* do any partial u32 at the start */
+       i = start % 32;
+       if (i) {
+               int j = 32 - i;
+               mask = 0xffffffffU << j;
+               if (j > count) {
+                       mask |= 0xffffffffU >> (i + count);
+                       *curr &= cpu_to_be32(mask);
+                       goto out;
                }
+               *curr++ &= cpu_to_be32(mask);
+               count -= j;
        }
 
-       /* do full hfs_u32s */
-       while (left > 31) {
-               if (bitmap[u32_nr] != ~((hfs_u32)0)) {
-                       hfs_buffer_dirty(mdb->bitmap[block_nr]);
-                       return -1;
-               }
-               bitmap[u32_nr] = ((hfs_u32)0);
-               left -= 32;
-
-               /* advance u32_nr and check for end of this block */
-               if (++u32_nr > 127) {
-                       u32_nr = 0;
-                       hfs_buffer_dirty(mdb->bitmap[block_nr]);
-                       ++block_nr;
-                       /* bitmap is always on a 32-bit boundary */
-                       bitmap = (hfs_u32 *)
-                                       hfs_buffer_data(mdb->bitmap[block_nr]);
-               }
+       /* do full u32s */
+       while (count >= 32) {
+               *curr++ = 0;
+               count -= 32;
        }
-
-                       
-       /* do any partial hfs_u32 at end */
-       while (left) {
-               if (!hfs_clear_bit(bit_nr, bitmap + u32_nr)) {
-                       hfs_buffer_dirty(mdb->bitmap[block_nr]);
-                       return -1;
-               }
-               ++bit_nr;
-               --left;
+       /* do any partial u32 at end */
+       if (count) {
+               mask = 0xffffffffU >> count;
+               *curr &= cpu_to_be32(mask);
        }
+out:
+       HFS_SB(sb)->free_ablocks += len;
+       up(&HFS_SB(sb)->bitmap_lock);
+       hfs_bitmap_dirty(sb);
 
-       hfs_buffer_dirty(mdb->bitmap[block_nr]);
-       mdb->free_ablocks += count;
-
-       /* successful completion */
-       hfs_mdb_dirty(mdb->sys_mdb);
        return 0;
 }
diff --git a/fs/hfs/bitops.c b/fs/hfs/bitops.c
deleted file mode 100644 (file)
index e2cb388..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * linux/fs/hfs/bitops.c
- *
- * Copyright (C) 1996  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains functions to handle bitmaps in "left-to-right"
- * bit-order such that the MSB of a 32-bit big-endian word is bit 0.
- * (This corresponds to bit 7 of a 32-bit little-endian word.)
- *
- * I have tested and confirmed that the results are identical on the
- * Intel x86, PowerPC and DEC Alpha processors.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- */
-
-#include "hfs.h"
-
-/*================ Global functions ================*/
-
-/*
- * hfs_find_zero_bit()
- *
- * Description:
- *  Given a block of memory, its length in bits, and a starting bit number,
- *  determine the number of the first zero bits (in left-to-right ordering)
- *  in that range.
- *
- *  Returns >= 'size' if no zero bits are found in the range.
- *
- *  Accesses memory in 32-bit aligned chunks of 32-bits and thus
- *  may read beyond the 'size'th bit.
- */
-hfs_u32 hfs_find_zero_bit(const hfs_u32 *start, hfs_u32 size, hfs_u32 offset)
-{
-       const hfs_u32 *end   = start + ((size + 31) >> 5);
-       const hfs_u32 *curr  = start + (offset >> 5);
-       int bit = offset % 32;
-       
-       if (offset < size) {
-               /* scan the first partial hfs_u32 for zero bits */
-               if (bit != 0) {
-                       do {
-                               if (!hfs_test_bit(bit, curr)) {
-                                       goto done;
-                               }
-                               ++bit;
-                       } while (bit < 32);
-                       bit = 0;
-                       ++curr;
-               }
-       
-               /* scan complete hfs_u32s for the first zero bit */
-               while (curr < end) {
-                       if (*curr == ~((hfs_u32)0)) {
-                               ++curr;
-                       } else {
-                               while (hfs_test_bit(bit, curr)) {
-                                       ++bit;
-                               }
-                               break;
-                       }
-               }
-
-done:
-               bit |= (curr - start) << 5;
-               return bit;
-       } else {
-               return size;
-       }
-}
-
-/*
- * hfs_count_zero_bits()
- *
- * Description:
- *  Given a block of memory, its length in bits, and a starting bit number,
- *  determine the number of consecutive zero bits (in left-to-right ordering)
- *  in that range.
- *
- *  Accesses memory in 32-bit aligned chunks of 32-bits and thus
- *  may read beyond the 'size'th bit.
- */
-hfs_u32 hfs_count_zero_bits(const hfs_u32 *start, hfs_u32 size, hfs_u32 offset)
-{
-       const hfs_u32 *end   = start + ((size + 31) >> 5);
-       const hfs_u32 *curr  = start + (offset >> 5);
-       int bit = offset % 32;
-
-       if (offset < size) {
-               /* scan the first partial hfs_u32 for one bits */
-               if (bit != 0) {
-                       do {
-                               if (hfs_test_bit(bit, curr)) {
-                                       goto done;
-                               }
-                               ++bit;
-                       } while (bit < 32);
-                       bit = 0;
-                       ++curr;
-               }
-       
-               /* scan complete hfs_u32s for the first one bit */
-               while (curr < end) {
-                       if (*curr == ((hfs_u32)0)) {
-                               ++curr;
-                       } else {
-                               while (!hfs_test_bit(bit, curr)) {
-                                       ++bit;
-                               }
-                               break;
-                       }
-               }
-
-done:
-               bit |= (curr - start) << 5;
-               if (bit > size) {
-                       bit = size;
-               }
-               return bit - offset;
-       } else {
-               return 0;
-       }
-}
index d7f0566e3cc06ea8bec2b4d4260299b8a61d316f..d0cf0a6f431c1314b1949d229832a70aff1b92e3 100644 (file)
 /*
- * linux/fs/hfs/bnode.c
+ *  linux/fs/hfs/bnode.c
  *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
+ * Copyright (C) 2001
+ * Brad Boyer (flar@allandria.com)
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  *
- * This file contains the code to access nodes in the B-tree structure.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- *
- * The code in this file initializes some structures which contain
- * pointers by calling memset(&foo, 0, sizeof(foo)).
- * This produces the desired behavior only due to the non-ANSI
- * assumption that the machine representation of NULL is all zeros.
+ * Handle basic btree node operations
  */
 
-#include "hfs_btree.h"
+#include <linux/pagemap.h>
+#include <linux/swap.h>
 
-/*================ File-local variables ================*/
-/* debugging statistics */
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-int bnode_count = 0;
-#endif
+#include "btree.h"
 
-/*================ Global functions ================*/
+#define REF_PAGES      0
 
-/*
- * hfs_bnode_delete()
- *
- * Description:
- *   This function is called to remove a bnode from the cache and
- *   release its resources.
- * Input Variable(s):
- *   struct hfs_bnode *bn: Pointer to the (struct hfs_bnode) to be
- *   removed from the cache.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'bn' points to a "valid" (struct hfs_bnode).
- * Postconditions:
- *   The node 'bn' is removed from the cache, its memory freed and its
- *   buffer (if any) released.
- */
-void hfs_bnode_delete(struct hfs_bnode *bn)
+void hfs_bnode_read(struct hfs_bnode *node, void *buf,
+               int off, int len)
 {
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-       --bnode_count;
-#endif
-       /* join neighbors */
-       if (bn->next) {
-               bn->next->prev = bn->prev;
-       }
-       if (bn->prev) {
-               bn->prev->next = bn->next;
-       }
-       /* fix cache slot if necessary */
-       if (bhash(bn->tree, bn->node) == bn) {
-               bhash(bn->tree, bn->node) = bn->next;
-       }
-       /* release resources */
-       hfs_buffer_put(bn->buf); /* safe: checks for NULL argument */
-       HFS_DELETE(bn);
+       struct page *page;
+
+       off += node->page_offset;
+       page = node->page[0];
+
+       memcpy(buf, kmap(page) + off, len);
+       kunmap(page);
+}
+
+u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
+{
+       u16 data;
+       // optimize later...
+       hfs_bnode_read(node, &data, off, 2);
+       return be16_to_cpu(data);
 }
 
+u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
+{
+       u8 data;
+       // optimize later...
+       hfs_bnode_read(node, &data, off, 1);
+       return data;
+}
 
-/*
- * hfs_bnode_read()
- *
- * Description: 
- *   This function creates a (struct hfs_bnode) and, if appropriate,
- *   inserts it in the cache.
- * Input Variable(s):
- *   struct hfs_bnode *bnode: pointer to the new bnode.
- *   struct hfs_btree *tree: pointer to the (struct hfs_btree)
- *    containing the desired node
- *   hfs_u32 node: the number of the desired node.
- *   int sticky: the value to assign to the 'sticky' field.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   (struct hfs_bnode *) pointing to the newly created bnode or NULL.
- * Preconditions:
- *   'bnode' points to a "valid" (struct hfs_bnode).
- *   'tree' points to a "valid" (struct hfs_btree).
- *   'node' is an existing node number in the B-tree.
- * Postconditions:
- *   The following are true of 'bnode' upon return:
- *    The 'magic' field is set to indicate a valid (struct hfs_bnode). 
- *    The 'sticky', 'tree' and 'node' fields are initialized to the
- *    values of the of the corresponding arguments.
- *    If the 'sticky' argument is zero then the fields 'prev' and
- *    'next' are initialized by inserting the (struct hfs_bnode) in the
- *    linked list of the appropriate cache slot; otherwise they are
- *    initialized to NULL.
- *    The data is read from disk (or buffer cache) and the 'buf' field
- *    points to the buffer for that data.
- *    If no other processes tried to access this node while this
- *    process was waiting on disk I/O (if necessary) then the
- *    remaining fields are zero ('count', 'resrv', 'lock') or NULL
- *    ('wqueue', 'rqueue') corresponding to no accesses.
- *    If there were access attempts during I/O then they were blocked
- *    until the I/O was complete, and the fields 'count', 'resrv',
- *    'lock', 'wqueue' and 'rqueue' reflect the results of unblocking
- *    those processes when the I/O was completed.
- */
-void hfs_bnode_read(struct hfs_bnode *bnode, struct hfs_btree *tree,
-                   hfs_u32 node, int sticky)
+void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
 {
-       struct NodeDescriptor *nd;
-       int block, lcv;
-       hfs_u16 curr, prev, limit;
-
-       /* Initialize the structure */
-       memset(bnode, 0, sizeof(*bnode));
-       bnode->magic = HFS_BNODE_MAGIC;
-       bnode->tree = tree;
-       bnode->node = node;
-       bnode->sticky = sticky;
-       hfs_init_waitqueue(&bnode->rqueue);
-       hfs_init_waitqueue(&bnode->wqueue);
-
-       if (sticky == HFS_NOT_STICKY) {
-               /* Insert it in the cache if appropriate */
-               if ((bnode->next = bhash(tree, node))) {
-                       bnode->next->prev = bnode;
-               }
-               bhash(tree, node) = bnode;
-       }
+       struct hfs_btree *tree;
+       int key_len;
 
-       /* Make the bnode look like it is being
-          modified so other processes will wait for
-          the I/O to complete */
-       bnode->count = bnode->resrv = bnode->lock = 1;
-
-       /* Read in the node, possibly causing a schedule()
-          call.  If the I/O fails then emit a warning.  Each
-          process that was waiting on the bnode (including
-          the current one) will notice the failure and
-          hfs_bnode_relse() the node.  The last hfs_bnode_relse()
-          will call hfs_bnode_delete() and discard the bnode.  */
-
-       block = hfs_extent_map(&tree->entry.u.file.data_fork, node, 0);
-       if (!block) {
-               hfs_warn("hfs_bnode_read: bad node number 0x%08x\n", node);
-       } else if (hfs_buffer_ok(bnode->buf =
-                                hfs_buffer_get(tree->sys_mdb, block, 1))) {
-               /* read in the NodeDescriptor */
-               nd = (struct NodeDescriptor *)hfs_buffer_data(bnode->buf);
-               bnode->ndFLink    = hfs_get_hl(nd->ndFLink);
-               bnode->ndBLink    = hfs_get_hl(nd->ndBLink);
-               bnode->ndType     = nd->ndType;
-               bnode->ndNHeight  = nd->ndNHeight;
-               bnode->ndNRecs    = hfs_get_hs(nd->ndNRecs);
-
-               /* verify the integrity of the node */
-               prev = sizeof(struct NodeDescriptor);
-               limit = HFS_SECTOR_SIZE - sizeof(hfs_u16)*(bnode->ndNRecs + 1);
-               for (lcv=1; lcv <= (bnode->ndNRecs + 1); ++lcv) {
-                       curr = hfs_get_hs(RECTBL(bnode, lcv));
-                       if ((curr < prev) || (curr > limit)) {
-                               hfs_warn("hfs_bnode_read: corrupt node "
-                                        "number 0x%08x\n", node);
-                               hfs_buffer_put(bnode->buf);
-                               bnode->buf = NULL;
-                               break;
-                       }
-                       prev = curr;
-               }
-       }
+       tree = node->tree;
+       if (node->type == HFS_NODE_LEAF ||
+           tree->attributes & HFS_TREE_VARIDXKEYS)
+               key_len = hfs_bnode_read_u8(node, off) + 1;
+       else
+               key_len = tree->max_key_len + 1;
 
-       /* Undo our fakery with the lock state and
-          hfs_wake_up() anyone who we managed to trick */
-       --bnode->count;
-       bnode->resrv = bnode->lock = 0;
-       hfs_wake_up(&bnode->rqueue);
+       hfs_bnode_read(node, key, off, key_len);
 }
 
-/*
- * hfs_bnode_lock()
- *
- * Description:
- *   This function does the locking of a bnode.
- * Input Variable(s):
- *   struct hfs_bnode *bn: pointer to the (struct hfs_bnode) to lock
- *   int lock_type: the type of lock desired
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'bn' points to a "valid" (struct hfs_bnode).
- *   'lock_type' is a valid hfs_lock_t
- * Postconditions:
- *   The 'count' field of 'bn' is incremented by one.  If 'lock_type'
- *   is HFS_LOCK_RESRV the 'resrv' field is also incremented.
- */
-void hfs_bnode_lock(struct hfs_bnode_ref *bnr, int lock_type)
+void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
 {
-       struct hfs_bnode *bn = bnr->bn;
+       struct page *page;
+
+       off += node->page_offset;
+       page = node->page[0];
 
-       if ((lock_type == bnr->lock_type) || !bn) {
+       memcpy(kmap(page) + off, buf, len);
+       kunmap(page);
+       set_page_dirty(page);
+}
+
+void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data)
+{
+       data = cpu_to_be16(data);
+       // optimize later...
+       hfs_bnode_write(node, &data, off, 2);
+}
+
+void hfs_bnode_write_u8(struct hfs_bnode *node, int off, u8 data)
+{
+       // optimize later...
+       hfs_bnode_write(node, &data, off, 1);
+}
+
+void hfs_bnode_clear(struct hfs_bnode *node, int off, int len)
+{
+       struct page *page;
+
+       off += node->page_offset;
+       page = node->page[0];
+
+       memset(kmap(page) + off, 0, len);
+       kunmap(page);
+       set_page_dirty(page);
+}
+
+void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
+               struct hfs_bnode *src_node, int src, int len)
+{
+       struct hfs_btree *tree;
+       struct page *src_page, *dst_page;
+
+       dprint(DBG_BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
+       if (!len)
                return;
-       }
+       tree = src_node->tree;
+       src += src_node->page_offset;
+       dst += dst_node->page_offset;
+       src_page = src_node->page[0];
+       dst_page = dst_node->page[0];
+
+       memcpy(kmap(dst_page) + dst, kmap(src_page) + src, len);
+       kunmap(src_page);
+       kunmap(dst_page);
+       set_page_dirty(dst_page);
+}
 
-       if (bnr->lock_type == HFS_LOCK_WRITE) {
-               hfs_bnode_commit(bnr->bn);
-       }
+void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
+{
+       struct page *page;
+       void *ptr;
 
-       switch (lock_type) {
-       default:
-               goto bail;
-               break;
+       dprint(DBG_BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
+       if (!len)
+               return;
+       src += node->page_offset;
+       dst += node->page_offset;
+       page = node->page[0];
+       ptr = kmap(page);
+       memmove(ptr + dst, ptr + src, len);
+       kunmap(page);
+       set_page_dirty(page);
+}
 
-       case HFS_LOCK_READ:
-               /* We may not obtain read access if any process is
-                  currently modifying or waiting to modify this node.
-                  If we can't obtain access we wait on the rqueue
-                  wait queue to be woken up by the modifying process
-                  when it relinquishes its lock. */
-               switch (bnr->lock_type) {
-               default:
-                       goto bail;
-                       break;
-
-               case HFS_LOCK_NONE:
-                       while (bn->lock || waitqueue_active(&bn->wqueue)) {
-                               hfs_sleep_on(&bn->rqueue);
-                       }
-                       ++bn->count;
-                       break;
-               }
-               break;
-                       
-       case HFS_LOCK_RESRV:
-               /* We may not obtain a reservation (read access with
-                  an option to write later), if any process currently
-                  holds a reservation on this node.  That includes
-                  any process which is currently modifying this node.
-                  If we can't obtain access, then we wait on the
-                  rqueue wait queue to e woken up by the
-                  reservation-holder when it calls hfs_bnode_relse. */
-               switch (bnr->lock_type) {
-               default:
-                       goto bail;
-                       break;
-
-               case HFS_LOCK_NONE:
-                       while (bn->resrv) {
-                               hfs_sleep_on(&bn->rqueue);
-                       }
-                       bn->resrv = 1;
-                       ++bn->count;
-                       break;
-
-               case HFS_LOCK_WRITE:
-                       bn->lock = 0;
-                       hfs_wake_up(&bn->rqueue);
-                       break;
-               }
-               break;
-               
-       case HFS_LOCK_WRITE:
-               switch (bnr->lock_type) {
-               default:
-                       goto bail;
-                       break;
-
-               case HFS_LOCK_NONE:
-                       while (bn->resrv) {
-                               hfs_sleep_on(&bn->rqueue);
-                       }
-                       bn->resrv = 1;
-                       ++bn->count;
-               case HFS_LOCK_RESRV:
-                       while (bn->count > 1) {
-                               hfs_sleep_on(&bn->wqueue);
-                       }
-                       bn->lock = 1;
-                       break;
+void hfs_bnode_dump(struct hfs_bnode *node)
+{
+       struct hfs_bnode_desc desc;
+       u32 cnid;
+       int i, off, key_off;
+
+       dprint(DBG_BNODE_MOD, "bnode: %d\n", node->this);
+       hfs_bnode_read(node, &desc, 0, sizeof(desc));
+       dprint(DBG_BNODE_MOD, "%d, %d, %d, %d, %d\n",
+               be32_to_cpu(desc.next), be32_to_cpu(desc.prev),
+               desc.type, desc.height, be16_to_cpu(desc.num_recs));
+
+       off = node->tree->node_size - 2;
+       for (i = be16_to_cpu(desc.num_recs); i >= 0; off -= 2, i--) {
+               key_off = hfs_bnode_read_u16(node, off);
+               dprint(DBG_BNODE_MOD, " %d", key_off);
+               if (i && node->type == HFS_NODE_INDEX) {
+                       int tmp;
+
+                       if (node->tree->attributes & HFS_TREE_VARIDXKEYS)
+                               tmp = (hfs_bnode_read_u8(node, key_off) | 1) + 1;
+                       else
+                               tmp = node->tree->max_key_len + 1;
+                       dprint(DBG_BNODE_MOD, " (%d,%d", tmp, hfs_bnode_read_u8(node, key_off));
+                       hfs_bnode_read(node, &cnid, key_off + tmp, 4);
+                       dprint(DBG_BNODE_MOD, ",%d)", be32_to_cpu(cnid));
+               } else if (i && node->type == HFS_NODE_LEAF) {
+                       int tmp;
+
+                       tmp = hfs_bnode_read_u8(node, key_off);
+                       dprint(DBG_BNODE_MOD, " (%d)", tmp);
                }
-               break;
+       }
+       dprint(DBG_BNODE_MOD, "\n");
+}
 
-       case HFS_LOCK_NONE:
-               switch (bnr->lock_type) {
-               default:
-                       goto bail;
-                       break;
-
-               case HFS_LOCK_READ:
-                       /* This process was reading this node.  If
-                          there is now exactly one other process using
-                          the node then hfs_wake_up() a (potentially
-                          nonexistent) waiting process.  Note that I
-                          refer to "a" process since the reservation
-                          system ensures that only one process can
-                          get itself on the wait queue.  */
-                       if (bn->count == 2) {
-                               hfs_wake_up(&bn->wqueue);
-                       }
-                       break;
-
-               case HFS_LOCK_WRITE:
-                       /* This process was modifying this node.
-                          Unlock the node and fall-through to the
-                          HFS_LOCK_RESRV case, since a 'reservation'
-                          is a prerequisite for HFS_LOCK_WRITE.  */
-                       bn->lock = 0;
-               case HFS_LOCK_RESRV:
-                       /* This process had placed a 'reservation' on
-                          this node, indicating an intention to
-                          possibly modify the node.  We can get to
-                          this spot directly (if the 'reservation'
-                          not converted to a HFS_LOCK_WRITE), or by
-                          falling through from the above case if the
-                          reservation was converted.
-                          Since HFS_LOCK_RESRV and HFS_LOCK_WRITE
-                          both block processes that want access
-                          (HFS_LOCK_RESRV blocks other processes that
-                          want reservations but allow HFS_LOCK_READ
-                          accesses, while HFS_LOCK_WRITE must have
-                          exclusive access and thus blocks both
-                          types) we hfs_wake_up() any processes that
-                          might be waiting for access.  If multiple
-                          processes are waiting for a reservation
-                          then the magic of process scheduling will
-                          settle the dispute. */
-                       bn->resrv = 0;
-                       hfs_wake_up(&bn->rqueue);
-                       break;
-               }
-               --bn->count;
-               break;
+void hfs_bnode_unlink(struct hfs_bnode *node)
+{
+       struct hfs_btree *tree;
+       struct hfs_bnode *tmp;
+       u32 cnid;
+
+       tree = node->tree;
+       if (node->prev) {
+               tmp = hfs_bnode_find(tree, node->prev);
+               if (IS_ERR(tmp))
+                       return;
+               tmp->next = node->next;
+               cnid = cpu_to_be32(tmp->next);
+               hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
+               hfs_bnode_put(tmp);
+       } else if (node->type == HFS_NODE_LEAF)
+               tree->leaf_head = node->next;
+
+       if (node->next) {
+               tmp = hfs_bnode_find(tree, node->next);
+               if (IS_ERR(tmp))
+                       return;
+               tmp->prev = node->prev;
+               cnid = cpu_to_be32(tmp->prev);
+               hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, prev), 4);
+               hfs_bnode_put(tmp);
+       } else if (node->type == HFS_NODE_LEAF)
+               tree->leaf_tail = node->prev;
+
+       // move down?
+       if (!node->prev && !node->next) {
+               printk("hfs_btree_del_level\n");
        }
-       bnr->lock_type = lock_type;
-       return;
+       if (!node->parent) {
+               tree->root = 0;
+               tree->depth = 0;
+       }
+       set_bit(HFS_BNODE_DELETED, &node->flags);
+}
 
-bail:
-       hfs_warn("hfs_bnode_lock: invalid lock change: %d->%d.\n",
-               bnr->lock_type, lock_type);
-       return;
+static inline int hfs_bnode_hash(u32 num)
+{
+       num = (num >> 16) + num;
+       num += num >> 8;
+       return num & (NODE_HASH_SIZE - 1);
 }
 
-/*
- * hfs_bnode_relse()
- *
- * Description:
- *   This function is called when a process is done using a bnode.  If
- *   the proper conditions are met then we call hfs_bnode_delete() to remove
- *   it from the cache.         If it is not deleted then we update its state
- *   to reflect one less process using it.
- * Input Variable(s):
- *   struct hfs_bnode *bn: pointer to the (struct hfs_bnode) to release.
- *   int lock_type: The type of lock held by the process releasing this node.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'bn' is NULL or points to a "valid" (struct hfs_bnode).
- * Postconditions:
- *   If 'bn' meets the appropriate conditions (see below) then it is
- *   kept in the cache and all fields are set to consistent values
- *   which reflect one less process using the node than upon entry.
- *   If 'bn' does not meet the conditions then it is deleted (see
- *   hfs_bnode_delete() for postconditions).
- *   In either case, if 'lock_type' is HFS_LOCK_WRITE
- *   then the corresponding buffer is dirtied.
- */
-void hfs_bnode_relse(struct hfs_bnode_ref *bnr)
+struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid)
 {
-       struct hfs_bnode *bn;
+       struct hfs_bnode *node;
 
-       if (!bnr || !(bn = bnr->bn)) {
-               return;
+       if (cnid >= tree->node_count) {
+               printk("HFS: request for non-existent node %d in B*Tree\n", cnid);
+               return NULL;
        }
 
-       /* We update the lock state of the node if it is still in use
-          or if it is "sticky" (such as the B-tree head and root).
-          Otherwise we just delete it.  */
-       if ((bn->count > 1) || (waitqueue_active(&bn->rqueue)) || (bn->sticky != HFS_NOT_STICKY)) {
-               hfs_bnode_lock(bnr, HFS_LOCK_NONE);
-       } else {
-               /* dirty buffer if we (might) have modified it */
-               if (bnr->lock_type == HFS_LOCK_WRITE) {
-                       hfs_bnode_commit(bn);
+       for (node = tree->node_hash[hfs_bnode_hash(cnid)];
+            node; node = node->next_hash) {
+               if (node->this == cnid) {
+                       return node;
                }
-               hfs_bnode_delete(bn);
-               bnr->lock_type = HFS_LOCK_NONE;
        }
-       bnr->bn = NULL;
+       return NULL;
 }
 
-/*
- * hfs_bnode_find()
- *
- * Description:
- *   This function is called to obtain a bnode.  The cache is
- *   searched for the node.  If it not found there it is added to
- *   the cache by hfs_bnode_read().  There are two special cases node=0
- *   (the header node) and node='tree'->bthRoot (the root node), in
- *   which the nodes are obtained from fields of 'tree' without
- *   consulting or modifying the cache.
- * Input Variable(s):
- *   struct hfs_tree *tree: pointer to the (struct hfs_btree) from
- *    which to get a node.
- *   int node: the node number to get from 'tree'.
- *   int lock_type: The kind of access (HFS_LOCK_READ, or
- *    HFS_LOCK_RESRV) to obtain to the node
- * Output Variable(s):
- *   NONE
- * Returns:
- *   (struct hfs_bnode_ref) Reference to the requested node.
- * Preconditions:
- *   'tree' points to a "valid" (struct hfs_btree).
- * Postconditions:
- *   If 'node' refers to a valid node in 'tree' and 'lock_type' has
- *   one of the values listed above and no I/O errors occur then the
- *   value returned refers to a valid (struct hfs_bnode) corresponding
- *   to the requested node with the requested access type.  The node
- *   is also added to the cache if not previously present and not the
- *   root or header.
- *   If the conditions given above are not met, the bnode in the
- *   returned reference is NULL.
- */
-struct hfs_bnode_ref hfs_bnode_find(struct hfs_btree *tree,
-                                   hfs_u32 node, int lock_type)
+static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
 {
-       struct hfs_bnode *bn;
-       struct hfs_bnode *empty = NULL;
-       struct hfs_bnode_ref bnr;
-
-       bnr.lock_type = HFS_LOCK_NONE;
-       bnr.bn = NULL;
-
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-       hfs_warn("hfs_bnode_find: %c %d:%d\n",
-                lock_type==HFS_LOCK_READ?'R':
-                       (lock_type==HFS_LOCK_RESRV?'V':'W'),
-                (int)ntohl(tree->entry.cnid), node);
-#endif
-
-       /* check special cases */
-       if (!node) {
-               bn = &tree->head;
-               goto return_it;
-       } else if (node == tree->bthRoot) {
-               bn = tree->root;
-               goto return_it;
-       } 
-
-restart:
-       /* look for the node in the cache. */
-       bn = bhash(tree, node);
-       while (bn && (bn->magic == HFS_BNODE_MAGIC)) {
-               if (bn->node == node) {
-                       goto found_it;
-               }
-               bn = bn->next;
+       struct super_block *sb;
+       struct hfs_bnode *node, *node2;
+       struct address_space *mapping;
+       struct page *page;
+       int size, block, i, hash;
+       loff_t off;
+
+       if (cnid >= tree->node_count) {
+               printk("HFS: request for non-existent node %d in B*Tree\n", cnid);
+               return NULL;
        }
 
-       if (!empty) {
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-               ++bnode_count;
-#endif
-               if (HFS_NEW(empty)) {
-                       goto restart;
-               }
-               return bnr;
+       sb = tree->inode->i_sb;
+       size = sizeof(struct hfs_bnode) + tree->pages_per_bnode *
+               sizeof(struct page *);
+       node = kmalloc(size, GFP_KERNEL);
+       if (!node)
+               return NULL;
+       memset(node, 0, size);
+       node->tree = tree;
+       node->this = cnid;
+       set_bit(HFS_BNODE_NEW, &node->flags);
+       atomic_set(&node->refcnt, 1);
+       dprint(DBG_BNODE_REFS, "new_node(%d:%d): 1\n",
+              node->tree->cnid, node->this);
+       init_waitqueue_head(&node->lock_wq);
+       spin_lock(&tree->hash_lock);
+       node2 = hfs_bnode_findhash(tree, cnid);
+       if (!node2) {
+               hash = hfs_bnode_hash(cnid);
+               node->next_hash = tree->node_hash[hash];
+               tree->node_hash[hash] = node;
+               tree->node_hash_cnt++;
+       } else {
+               spin_unlock(&tree->hash_lock);
+               kfree(node);
+               wait_event(node2->lock_wq, !test_bit(HFS_BNODE_NEW, &node2->flags));
+               return node2;
        }
-       bn = empty;
-       hfs_bnode_read(bn, tree, node, HFS_NOT_STICKY);
-       goto return_it;
-
-found_it:
-       /* check validity */
-       if (bn->magic != HFS_BNODE_MAGIC) {
-               /* If we find a corrupt bnode then we return
-                  NULL.  However, we don't try to remove it
-                  from the cache or release its resources
-                  since we have no idea what kind of trouble
-                  we could get into that way. */
-               hfs_warn("hfs_bnode_find: bnode cache is corrupt.\n");
-               return bnr;
-       } 
-       if (empty) {
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-               --bnode_count;
+       spin_unlock(&tree->hash_lock);
+
+       mapping = tree->inode->i_mapping;
+       off = (loff_t)cnid * tree->node_size;
+       block = off >> PAGE_CACHE_SHIFT;
+       node->page_offset = off & ~PAGE_CACHE_MASK;
+       for (i = 0; i < tree->pages_per_bnode; i++) {
+               page = read_cache_page(mapping, block++, (filler_t *)mapping->a_ops->readpage, NULL);
+               if (IS_ERR(page))
+                       goto fail;
+#if !REF_PAGES
+               page_cache_release(page);
 #endif
-               HFS_DELETE(empty);
+               node->page[i] = page;
+       }
+
+       return node;
+fail:
+       set_bit(HFS_BNODE_ERROR, &node->flags);
+       return node;
+}
+
+void hfs_bnode_unhash(struct hfs_bnode *node)
+{
+       struct hfs_bnode **p;
+
+       dprint(DBG_BNODE_REFS, "remove_node(%d:%d): %d\n",
+               node->tree->cnid, node->this, atomic_read(&node->refcnt));
+       for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
+            *p && *p != node; p = &(*p)->next_hash)
+               ;
+       if (!*p)
+               BUG();
+       *p = node->next_hash;
+       node->tree->node_hash_cnt--;
+}
+
+/* Load a particular node out of a tree */
+struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
+{
+       struct hfs_bnode *node;
+       struct hfs_bnode_desc *desc;
+       int i, rec_off, off, next_off;
+       int entry_size, key_size;
+
+       spin_lock(&tree->hash_lock);
+       node = hfs_bnode_findhash(tree, num);
+       if (node) {
+               hfs_bnode_get(node);
+               spin_unlock(&tree->hash_lock);
+               wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags));
+               return node;
        }
-       
-return_it:
-       /* Wait our turn */
-       bnr.bn = bn;
-       hfs_bnode_lock(&bnr, lock_type);
-
-       /* Check for failure to read the node from disk */
-       if (!hfs_buffer_ok(bn->buf)) {
-               hfs_bnode_relse(&bnr);
+       spin_unlock(&tree->hash_lock);
+       node = __hfs_bnode_create(tree, num);
+       if (!node)
+               return ERR_PTR(-ENOMEM);
+       if (!test_bit(HFS_BNODE_NEW, &node->flags))
+               return node;
+
+       desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) + node->page_offset);
+       node->prev = be32_to_cpu(desc->prev);
+       node->next = be32_to_cpu(desc->next);
+       node->num_recs = be16_to_cpu(desc->num_recs);
+       node->type = desc->type;
+       node->height = desc->height;
+       kunmap(node->page[0]);
+
+       switch (node->type) {
+       case HFS_NODE_HEADER:
+       case HFS_NODE_MAP:
+               if (node->height != 0)
+                       goto node_error;
+               break;
+       case HFS_NODE_LEAF:
+               if (node->height != 1)
+                       goto node_error;
+               break;
+       case HFS_NODE_INDEX:
+               if (node->height <= 1 || node->height > tree->depth)
+                       goto node_error;
+               break;
+       default:
+               goto node_error;
        }
 
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-       if (!bnr.bn) {
-               hfs_warn("hfs_bnode_find: failed\n");
-       } else {
-               hfs_warn("hfs_bnode_find: use %d(%d) lvl %d [%d]\n", bn->count,
-                        bn->buf->b_count, bn->ndNHeight, bnode_count);
-               hfs_warn("hfs_bnode_find: blnk %u flnk %u recs %u\n", 
-                        bn->ndBLink, bn->ndFLink, bn->ndNRecs);
+       rec_off = tree->node_size - 2;
+       off = hfs_bnode_read_u16(node, rec_off);
+       if (off != sizeof(struct hfs_bnode_desc))
+               goto node_error;
+       for (i = 1; i <= node->num_recs; off = next_off, i++) {
+               rec_off -= 2;
+               next_off = hfs_bnode_read_u16(node, rec_off);
+               if (next_off <= off ||
+                   next_off > tree->node_size ||
+                   next_off & 1)
+                       goto node_error;
+               entry_size = next_off - off;
+               if (node->type != HFS_NODE_INDEX &&
+                   node->type != HFS_NODE_LEAF)
+                       continue;
+               key_size = hfs_bnode_read_u8(node, off) + 1;
+               if (key_size >= entry_size /*|| key_size & 1*/)
+                       goto node_error;
        }
-#endif
+       clear_bit(HFS_BNODE_NEW, &node->flags);
+       wake_up(&node->lock_wq);
+       return node;
+
+node_error:
+       set_bit(HFS_BNODE_ERROR, &node->flags);
+       clear_bit(HFS_BNODE_NEW, &node->flags);
+       wake_up(&node->lock_wq);
+       hfs_bnode_put(node);
+       return ERR_PTR(-EIO);
+}
 
-       return bnr;
+void hfs_bnode_free(struct hfs_bnode *node)
+{
+       //int i;
+
+       //for (i = 0; i < node->tree->pages_per_bnode; i++)
+       //      if (node->page[i])
+       //              page_cache_release(node->page[i]);
+       kfree(node);
 }
 
-/*
- * hfs_bnode_commit()
- *
- * Called to write a possibly dirty bnode back to disk.
- */
-void hfs_bnode_commit(struct hfs_bnode *bn)
+struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num)
 {
-       if (hfs_buffer_ok(bn->buf)) {
-               struct NodeDescriptor *nd;
-               nd = (struct NodeDescriptor *)hfs_buffer_data(bn->buf);
-
-               hfs_put_hl(bn->ndFLink, nd->ndFLink);
-               hfs_put_hl(bn->ndBLink, nd->ndBLink);
-               nd->ndType    = bn->ndType;
-               nd->ndNHeight = bn->ndNHeight;
-               hfs_put_hs(bn->ndNRecs, nd->ndNRecs);
-               hfs_buffer_dirty(bn->buf);
-
-               /* increment write count */
-               hfs_mdb_dirty(bn->tree->sys_mdb);
+       struct hfs_bnode *node;
+       struct page **pagep;
+       int i;
+
+       spin_lock(&tree->hash_lock);
+       node = hfs_bnode_findhash(tree, num);
+       spin_unlock(&tree->hash_lock);
+       if (node)
+               BUG();
+       node = __hfs_bnode_create(tree, num);
+       if (!node)
+               return ERR_PTR(-ENOMEM);
+
+       pagep = node->page;
+       memset(kmap(*pagep) + node->page_offset, 0,
+              min((int)PAGE_CACHE_SIZE, (int)tree->node_size));
+       set_page_dirty(*pagep);
+       kunmap(*pagep);
+       for (i = 1; i < tree->pages_per_bnode; i++) {
+               memset(kmap(*++pagep), 0, PAGE_CACHE_SIZE);
+               set_page_dirty(*pagep);
+               kunmap(*pagep);
+       }
+       clear_bit(HFS_BNODE_NEW, &node->flags);
+       wake_up(&node->lock_wq);
+
+       return node;
+}
+
+void hfs_bnode_get(struct hfs_bnode *node)
+{
+       if (node) {
+               atomic_inc(&node->refcnt);
+#if REF_PAGES
+               {
+               int i;
+               for (i = 0; i < node->tree->pages_per_bnode; i++)
+                       get_page(node->page[i]);
+               }
+#endif
+               dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
+                      node->tree->cnid, node->this, atomic_read(&node->refcnt));
+       }
+}
+
+/* Dispose of resources used by a node */
+void hfs_bnode_put(struct hfs_bnode *node)
+{
+       if (node) {
+               struct hfs_btree *tree = node->tree;
+               int i;
+
+               dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
+                      node->tree->cnid, node->this, atomic_read(&node->refcnt));
+               if (!atomic_read(&node->refcnt))
+                       BUG();
+               if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock)) {
+#if REF_PAGES
+                       for (i = 0; i < tree->pages_per_bnode; i++)
+                               put_page(node->page[i]);
+#endif
+                       return;
+               }
+               for (i = 0; i < tree->pages_per_bnode; i++) {
+                       mark_page_accessed(node->page[i]);
+#if REF_PAGES
+                       put_page(node->page[i]);
+#endif
+               }
+
+               if (test_bit(HFS_BNODE_DELETED, &node->flags)) {
+                       hfs_bnode_unhash(node);
+                       spin_unlock(&tree->hash_lock);
+                       hfs_bmap_free(node);
+                       hfs_bnode_free(node);
+                       return;
+               }
+               spin_unlock(&tree->hash_lock);
        }
 }
index 4db76fc4f62cb7fed928793efdeb5d1220307447..5e54671dcff9c6a195163a4f6f36052531c89967 100644 (file)
 /*
- * linux/fs/hfs/brec.c
+ *  linux/fs/hfs/brec.c
  *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
+ * Copyright (C) 2001
+ * Brad Boyer (flar@allandria.com)
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  *
- * This file contains the code to access records in a btree.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
+ * Handle individual btree records
  */
 
-#include "hfs_btree.h"
-
-/*================ File-local functions ================*/
+#include "btree.h"
 
-/*
- * first()
- *
- * returns HFS_BPATH_FIRST if elem->record == 1, 0 otherwise
- */
-static inline int first(const struct hfs_belem *elem)
+/* Get the length and offset of the given record in the given node */
+u16 hfs_brec_lenoff(struct hfs_bnode *node, u16 rec, u16 *off)
 {
-       return (elem->record == 1) ? HFS_BPATH_FIRST : 0;
+       u16 retval[2];
+       u16 dataoff;
+
+       dataoff = node->tree->node_size - (rec + 2) * 2;
+       hfs_bnode_read(node, retval, dataoff, 4);
+       *off = be16_to_cpu(retval[1]);
+       return be16_to_cpu(retval[0]) - *off;
 }
 
-/*
- * overflow()
- *
- * return HFS_BPATH_OVERFLOW if the node has no room for an 
- * additional pointer record, 0 otherwise.
- */
-static inline int overflow(const struct hfs_btree *tree,
-                          const struct hfs_bnode *bnode)
+/* Get the length of the key from a keyed record */
+u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
 {
-       /* there is some algebra involved in getting this form */
-       return ((HFS_SECTOR_SIZE - sizeof(hfs_u32)) <
-                (bnode_end(bnode) + (2+bnode->ndNRecs)*sizeof(hfs_u16) +
-                 ROUND(tree->bthKeyLen+1))) ?  HFS_BPATH_OVERFLOW : 0;
+       u16 retval, recoff;
+
+       if (node->type != HFS_NODE_INDEX && node->type != HFS_NODE_LEAF)
+               return 0;
+
+       if ((node->type == HFS_NODE_INDEX) &&
+          !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
+               if (node->tree->attributes & HFS_TREE_BIGKEYS)
+                       retval = node->tree->max_key_len + 2;
+               else
+                       retval = node->tree->max_key_len + 1;
+       } else {
+               recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
+               if (!recoff)
+                       return 0;
+               if (node->tree->attributes & HFS_TREE_BIGKEYS)
+                       retval = hfs_bnode_read_u16(node, recoff) + 2;
+               else
+                       retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
+       }
+       return retval;
 }
 
-/*
- * underflow()
- *
- * return HFS_BPATH_UNDERFLOW if the node will be less that 1/2 full
- * upon removal of a pointer record, 0 otherwise.
- */
-static inline int underflow(const struct hfs_btree *tree,
-                           const struct hfs_bnode *bnode)
+int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
 {
-       return ((bnode->ndNRecs * sizeof(hfs_u16) +
-                bnode_offset(bnode, bnode->ndNRecs)) <
-               (HFS_SECTOR_SIZE - sizeof(struct NodeDescriptor))/2) ?
-               HFS_BPATH_UNDERFLOW : 0;
+       struct hfs_btree *tree;
+       struct hfs_bnode *node, *new_node;
+       int size, key_len, rec;
+       int data_off, end_off;
+       int idx_rec_off, data_rec_off, end_rec_off;
+       u32 cnid;
+
+       tree = fd->tree;
+       if (!fd->bnode) {
+               if (!tree->root)
+                       hfs_btree_inc_height(tree);
+               fd->bnode = hfs_bnode_find(tree, tree->leaf_head);
+               if (IS_ERR(fd->bnode))
+                       return PTR_ERR(fd->bnode);
+               fd->record = -1;
+       }
+       new_node = NULL;
+       key_len = (fd->search_key->key_len | 1) + 1;
+again:
+       /* new record idx and complete record size */
+       rec = fd->record + 1;
+       size = key_len + entry_len;
+
+       node = fd->bnode;
+       hfs_bnode_dump(node);
+       /* get last offset */
+       end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
+       end_off = hfs_bnode_read_u16(node, end_rec_off);
+       end_rec_off -= 2;
+       dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", rec, size, end_off, end_rec_off);
+       if (size > end_rec_off - end_off) {
+               if (new_node)
+                       panic("not enough room!\n");
+               new_node = hfs_bnode_split(fd);
+               if (IS_ERR(new_node))
+                       return PTR_ERR(new_node);
+               goto again;
+       }
+       if (node->type == HFS_NODE_LEAF) {
+               tree->leaf_count++;
+               mark_inode_dirty(tree->inode);
+       }
+       node->num_recs++;
+       /* write new last offset */
+       hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
+       hfs_bnode_write_u16(node, end_rec_off, end_off + size);
+       data_off = end_off;
+       data_rec_off = end_rec_off + 2;
+       idx_rec_off = tree->node_size - (rec + 1) * 2;
+       if (idx_rec_off == data_rec_off)
+               goto skip;
+       /* move all following entries */
+       do {
+               data_off = hfs_bnode_read_u16(node, data_rec_off + 2);
+               hfs_bnode_write_u16(node, data_rec_off, data_off + size);
+               data_rec_off += 2;
+       } while (data_rec_off < idx_rec_off);
+
+       /* move data away */
+       hfs_bnode_move(node, data_off + size, data_off,
+                      end_off - data_off);
+
+skip:
+       hfs_bnode_write(node, fd->search_key, data_off, key_len);
+       hfs_bnode_write(node, entry, data_off + key_len, entry_len);
+       hfs_bnode_dump(node);
+
+       if (new_node) {
+               /* update parent key if we inserted a key
+                * at the start of the first node
+                */
+               if (!rec && new_node != node)
+                       hfs_brec_update_parent(fd);
+
+               hfs_bnode_put(fd->bnode);
+               if (!new_node->parent) {
+                       hfs_btree_inc_height(tree);
+                       new_node->parent = tree->root;
+               }
+               fd->bnode = hfs_bnode_find(tree, new_node->parent);
+
+               /* create index data entry */
+               cnid = cpu_to_be32(new_node->this);
+               entry = &cnid;
+               entry_len = sizeof(cnid);
+
+               /* get index key */
+               hfs_bnode_read_key(new_node, fd->search_key, 14);
+               __hfs_brec_find(fd->bnode, fd);
+
+               hfs_bnode_put(new_node);
+               new_node = NULL;
+
+               if (tree->attributes & HFS_TREE_VARIDXKEYS)
+                       key_len = fd->search_key->key_len + 1;
+               else {
+                       fd->search_key->key_len = tree->max_key_len;
+                       key_len = tree->max_key_len + 1;
+               }
+               goto again;
+       }
+
+       if (!rec)
+               hfs_brec_update_parent(fd);
+
+       return 0;
 }
 
-/*================ Global functions ================*/
+int hfs_brec_remove(struct hfs_find_data *fd)
+{
+       struct hfs_btree *tree;
+       struct hfs_bnode *node, *parent;
+       int end_off, rec_off, data_off, size;
 
-/*
- * hfs_brec_next()
- *
- * Description:
- *   Obtain access to a child of an internal node in a B-tree.
- * Input Variable(s):
- *   struct hfs_brec *brec: pointer to the (struct hfs_brec) to
- *    add an element to.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   struct hfs_belem *: pointer to the new path element or NULL
- * Preconditions:
- *   'brec' points to a "valid" (struct hfs_brec), the last element of
- *   which corresponds to a record in a bnode of type ndIndxNode and the
- *   'record' field indicates the index record for the desired child.
- * Postconditions:
- *   If the call to hfs_bnode_find() fails then 'brec' is released
- *   and a NULL is returned.
- *   Otherwise:
- *    Any ancestors in 'brec' that are not needed (as determined by the
- *     'keep_flags' field of 'brec) are released from 'brec'.
- *    A new element is added to 'brec' corresponding to the desired
- *     child.
- *    The child is obtained with the same 'lock_type' field as its
- *     parent.
- *    The 'record' field is initialized to the last record.
- *    A pointer to the new path element is returned.
- */
-struct hfs_belem *hfs_brec_next(struct hfs_brec *brec)
+       tree = fd->tree;
+       node = fd->bnode;
+again:
+       rec_off = tree->node_size - (fd->record + 2) * 2;
+       end_off = tree->node_size - (node->num_recs + 1) * 2;
+
+       if (node->type == HFS_NODE_LEAF) {
+               tree->leaf_count--;
+               mark_inode_dirty(tree->inode);
+       }
+       hfs_bnode_dump(node);
+       dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n", fd->record, fd->keylength + fd->entrylength);
+       if (!--node->num_recs) {
+               hfs_bnode_unlink(node);
+               if (!node->parent)
+                       return 0;
+               parent = hfs_bnode_find(tree, node->parent);
+               if (IS_ERR(parent))
+                       return PTR_ERR(parent);
+               hfs_bnode_put(node);
+               node = fd->bnode = parent;
+
+               __hfs_brec_find(node, fd);
+               goto again;
+       }
+       hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
+
+       if (rec_off == end_off)
+               goto skip;
+       size = fd->keylength + fd->entrylength;
+
+       do {
+               data_off = hfs_bnode_read_u16(node, rec_off);
+               hfs_bnode_write_u16(node, rec_off + 2, data_off - size);
+               rec_off -= 2;
+       } while (rec_off >= end_off);
+
+       /* fill hole */
+       hfs_bnode_move(node, fd->keyoffset, fd->keyoffset + size,
+                      data_off - fd->keyoffset - size);
+skip:
+       hfs_bnode_dump(node);
+       if (!fd->record)
+               hfs_brec_update_parent(fd);
+       return 0;
+}
+
+struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
 {
-       struct hfs_belem *elem = brec->bottom;
-       hfs_u32 node;
-       int lock_type;
+       struct hfs_btree *tree;
+       struct hfs_bnode *node, *new_node;
+       struct hfs_bnode_desc node_desc;
+       int num_recs, new_rec_off, new_off, old_rec_off;
+       int data_start, data_end, size;
 
-       /* release unneeded ancestors */
-       elem->flags = first(elem) |
-                     overflow(brec->tree, elem->bnr.bn) |
-                     underflow(brec->tree, elem->bnr.bn);
-       if (!(brec->keep_flags & elem->flags)) {
-               hfs_brec_relse(brec, brec->bottom-1);
-       } else if ((brec->bottom-2 >= brec->top) &&
-                  !(elem->flags & (elem-1)->flags)) {
-               hfs_brec_relse(brec, brec->bottom-2);
+       tree = fd->tree;
+       node = fd->bnode;
+       new_node = hfs_bmap_alloc(tree);
+       if (IS_ERR(new_node))
+               return new_node;
+       hfs_bnode_get(node);
+       dprint(DBG_BNODE_MOD, "split_nodes: %d - %d - %d\n",
+               node->this, new_node->this, node->next);
+       new_node->next = node->next;
+       new_node->prev = node->this;
+       new_node->parent = node->parent;
+       new_node->type = node->type;
+       new_node->height = node->height;
+
+       size = tree->node_size / 2 - node->num_recs * 2 - 14;
+       old_rec_off = tree->node_size - 4;
+       num_recs = 1;
+       for (;;) {
+               data_start = hfs_bnode_read_u16(node, old_rec_off);
+               if (data_start > size)
+                       break;
+               old_rec_off -= 2;
+               if (++num_recs < node->num_recs)
+                       continue;
+               /* panic? */
+               hfs_bnode_put(node);
+               hfs_bnode_put(new_node);
+               return ERR_PTR(-ENOSPC);
        }
 
-       node = hfs_get_hl(belem_record(elem));
-       lock_type = elem->bnr.lock_type;
+       if (fd->record + 1 < num_recs) {
+               /* new record is in the lower half,
+                * so leave some more space there
+                */
+               old_rec_off += 2;
+               num_recs--;
+               data_start = hfs_bnode_read_u16(node, old_rec_off);
+       } else {
+               hfs_bnode_put(node);
+               hfs_bnode_get(new_node);
+               fd->bnode = new_node;
+               fd->record -= num_recs;
+               fd->keyoffset -= data_start - 14;
+               fd->entryoffset -= data_start - 14;
+       }
+       new_node->num_recs = node->num_recs - num_recs;
+       node->num_recs = num_recs;
 
-       if (!node || hfs_bnode_in_brec(node, brec)) {
-               hfs_warn("hfs_bfind: corrupt btree\n");
-               hfs_brec_relse(brec, NULL);
-               return NULL;
+       new_rec_off = tree->node_size - 2;
+       new_off = 14;
+       size = data_start - new_off;
+       num_recs = new_node->num_recs;
+       data_end = data_start;
+       while (num_recs) {
+               hfs_bnode_write_u16(new_node, new_rec_off, new_off);
+               old_rec_off -= 2;
+               new_rec_off -= 2;
+               data_end = hfs_bnode_read_u16(node, old_rec_off);
+               new_off = data_end - size;
+               num_recs--;
        }
+       hfs_bnode_write_u16(new_node, new_rec_off, new_off);
+       hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start);
 
-       ++elem;
-       ++brec->bottom;
+       /* update new bnode header */
+       node_desc.next = cpu_to_be32(new_node->next);
+       node_desc.prev = cpu_to_be32(new_node->prev);
+       node_desc.type = new_node->type;
+       node_desc.height = new_node->height;
+       node_desc.num_recs = cpu_to_be16(new_node->num_recs);
+       node_desc.reserved = 0;
+       hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));
 
-       elem->bnr = hfs_bnode_find(brec->tree, node, lock_type);
-       if (!elem->bnr.bn) {
-               hfs_brec_relse(brec, NULL);
-               return NULL;
+       /* update previous bnode header */
+       node->next = new_node->this;
+       hfs_bnode_read(node, &node_desc, 0, sizeof(node_desc));
+       node_desc.next = cpu_to_be32(node->next);
+       node_desc.num_recs = cpu_to_be16(node->num_recs);
+       hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));
+
+       /* update next bnode header */
+       if (new_node->next) {
+               struct hfs_bnode *next_node = hfs_bnode_find(tree, new_node->next);
+               next_node->prev = new_node->this;
+               hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
+               node_desc.prev = cpu_to_be32(next_node->prev);
+               hfs_bnode_write(next_node, &node_desc, 0, sizeof(node_desc));
+               hfs_bnode_put(next_node);
+       } else if (node->this == tree->leaf_tail) {
+               /* if there is no next node, this might be the new tail */
+               tree->leaf_tail = new_node->this;
+               mark_inode_dirty(tree->inode);
        }
-       elem->record = elem->bnr.bn->ndNRecs;
 
-       return elem;
+       hfs_bnode_dump(node);
+       hfs_bnode_dump(new_node);
+       hfs_bnode_put(node);
+
+       return new_node;
 }
 
-/*
- * hfs_brec_lock()
- *
- * Description:
- *   This function obtains HFS_LOCK_WRITE access to the bnode
- *   containing this hfs_brec. All descendents in the path from this
- *   record to the leaf are given HFS_LOCK_WRITE access and all
- *   ancestors in the path from the root to here are released.
- * Input Variable(s):
- *   struct hfs_brec *brec: pointer to the brec to obtain
- *    HFS_LOCK_WRITE access to some of the nodes of.
- *   struct hfs_belem *elem: the first node to lock or NULL for all
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'brec' points to a "valid" (struct hfs_brec)
- * Postconditions: 
- *   All nodes between the indicated node and the beginning of the path
- *    are released.  hfs_bnode_lock() is called in turn on each node
- *    from the indicated node to the leaf node of the path, with a
- *    lock_type argument of HFS_LOCK_WRITE.  If one of those calls
- *    results in deadlock, then this function will never return.
- */
-void hfs_brec_lock(struct hfs_brec *brec, struct hfs_belem *elem) 
+int hfs_brec_update_parent(struct hfs_find_data *fd)
 {
-       if (!elem) {
-               elem = brec->top;
-       } else if (elem > brec->top) {
-               hfs_brec_relse(brec, elem-1);
+       struct hfs_btree *tree;
+       struct hfs_bnode *node, *new_node, *parent;
+       int newkeylen, diff;
+       int rec, rec_off, end_rec_off;
+       int start_off, end_off;
+
+       tree = fd->tree;
+       node = fd->bnode;
+       new_node = NULL;
+       if (!node->parent)
+               return 0;
+
+again:
+       parent = hfs_bnode_find(tree, node->parent);
+       if (IS_ERR(parent))
+               return PTR_ERR(parent);
+       __hfs_brec_find(parent, fd);
+       hfs_bnode_dump(parent);
+       rec = fd->record;
+
+       /* size difference between old and new key */
+       if (tree->attributes & HFS_TREE_VARIDXKEYS)
+               newkeylen = (hfs_bnode_read_u8(node, 14) | 1) + 1;
+       else
+               fd->keylength = newkeylen = tree->max_key_len + 1;
+       dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n", rec, fd->keylength, newkeylen);
+
+       rec_off = tree->node_size - (rec + 2) * 2;
+       end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
+       diff = newkeylen - fd->keylength;
+       if (!diff)
+               goto skip;
+       if (diff > 0) {
+               end_off = hfs_bnode_read_u16(parent, end_rec_off);
+               if (end_rec_off - end_off < diff) {
+
+                       printk("splitting index node...\n");
+                       fd->bnode = parent;
+                       new_node = hfs_bnode_split(fd);
+                       if (IS_ERR(new_node))
+                               return PTR_ERR(new_node);
+                       parent = fd->bnode;
+                       rec = fd->record;
+                       rec_off = tree->node_size - (rec + 2) * 2;
+                       end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
+               }
        }
 
-       while (elem <= brec->bottom) {
-               hfs_bnode_lock(&elem->bnr, HFS_LOCK_WRITE);
-               ++elem;
+       end_off = start_off = hfs_bnode_read_u16(parent, rec_off);
+       hfs_bnode_write_u16(parent, rec_off, start_off + diff);
+       start_off -= 4; /* move previous cnid too */
+
+       while (rec_off > end_rec_off) {
+               rec_off -= 2;
+               end_off = hfs_bnode_read_u16(parent, rec_off);
+               hfs_bnode_write_u16(parent, rec_off, end_off + diff);
        }
+       hfs_bnode_move(parent, start_off + diff, start_off,
+                      end_off - start_off);
+skip:
+       hfs_bnode_copy(parent, fd->keyoffset, node, 14, newkeylen);
+       if (!(tree->attributes & HFS_TREE_VARIDXKEYS))
+               hfs_bnode_write_u8(parent, fd->keyoffset, newkeylen - 1);
+       hfs_bnode_dump(parent);
+
+       hfs_bnode_put(node);
+       node = parent;
+
+       if (new_node) {
+               u32 cnid;
+
+               fd->bnode = hfs_bnode_find(tree, new_node->parent);
+               /* create index key and entry */
+               hfs_bnode_read_key(new_node, fd->search_key, 14);
+               cnid = cpu_to_be32(new_node->this);
+
+               __hfs_brec_find(fd->bnode, fd);
+               hfs_brec_insert(fd, &cnid, sizeof(cnid));
+               hfs_bnode_put(fd->bnode);
+               hfs_bnode_put(new_node);
+
+               if (!rec) {
+                       if (new_node == node)
+                               goto out;
+                       /* restore search_key */
+                       hfs_bnode_read_key(node, fd->search_key, 14);
+               }
+       }
+
+       if (!rec && node->parent)
+               goto again;
+out:
+       fd->bnode = node;
+       return 0;
 }
 
-/*
- * hfs_brec_init()
- *
- * Description:
- *   Obtain access to the root node of a B-tree.
- *   Note that this first must obtain access to the header node.
- * Input Variable(s):
- *   struct hfs_brec *brec: pointer to the (struct hfs_brec) to
- *    initialize
- *   struct hfs_btree *btree: pointer to the (struct hfs_btree)
- *   int lock_type: the type of access to get to the nodes.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   struct hfs_belem *: pointer to the root path element or NULL
- * Preconditions:
- *   'brec' points to a (struct hfs_brec).
- *   'tree' points to a valid (struct hfs_btree).
- * Postconditions:
- *   If the two calls to brec_bnode_find() succeed then the return value
- *   points to a (struct hfs_belem) which corresponds to the root node
- *   of 'brec->tree'.
- *   Both the root and header nodes are obtained with the type of lock
- *   given by (flags & HFS_LOCK_MASK).
- *   The fields 'record' field of the root is set to its last record.
- *   If the header node is not needed to complete the appropriate
- *   operation (as determined by the 'keep_flags' field of 'brec') then
- *   it is released before this function returns.
- *   If either call to brec_bnode_find() fails, NULL is returned and the
- *   (struct hfs_brec) pointed to by 'brec' is invalid.
- */
-struct hfs_belem *hfs_brec_init(struct hfs_brec *brec, struct hfs_btree *tree,
-                               int flags)
+int hfs_btree_inc_height(struct hfs_btree *tree)
 {
-       struct hfs_belem *head = &brec->elem[0];
-       struct hfs_belem *root = &brec->elem[1];
-       int lock_type = flags & HFS_LOCK_MASK;
+       struct hfs_bnode *node, *new_node;
+       struct hfs_bnode_desc node_desc;
+       int key_size, rec;
+       u32 cnid;
 
-       brec->tree = tree;
-
-       head->bnr = hfs_bnode_find(tree, 0, lock_type);
-       if (!head->bnr.bn) {
-               return NULL;
+       node = NULL;
+       if (tree->root) {
+               node = hfs_bnode_find(tree, tree->root);
+               if (IS_ERR(node))
+                       return PTR_ERR(node);
+       }
+       new_node = hfs_bmap_alloc(tree);
+       if (IS_ERR(new_node)) {
+               hfs_bnode_put(node);
+               return PTR_ERR(new_node);
        }
 
-       root->bnr = hfs_bnode_find(tree, tree->bthRoot, lock_type);
-       if (!root->bnr.bn) {
-               hfs_bnode_relse(&head->bnr);
-               return NULL;
+       tree->root = new_node->this;
+       if (!tree->depth) {
+               tree->leaf_head = tree->leaf_tail = new_node->this;
+               new_node->type = HFS_NODE_LEAF;
+               new_node->num_recs = 0;
+       } else {
+               new_node->type = HFS_NODE_INDEX;
+               new_node->num_recs = 1;
        }
+       new_node->parent = 0;
+       new_node->next = 0;
+       new_node->prev = 0;
+       new_node->height = ++tree->depth;
 
-       root->record = root->bnr.bn->ndNRecs;
-       
-       brec->top = head;
-       brec->bottom = root;
-       
-       brec->keep_flags = flags & HFS_BPATH_MASK;
+       node_desc.next = cpu_to_be32(new_node->next);
+       node_desc.prev = cpu_to_be32(new_node->prev);
+       node_desc.type = new_node->type;
+       node_desc.height = new_node->height;
+       node_desc.num_recs = cpu_to_be16(new_node->num_recs);
+       node_desc.reserved = 0;
+       hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));
 
-       /* HFS_BPATH_FIRST not applicable for root */
-       /* and HFS_BPATH_UNDERFLOW is different */
-       root->flags = overflow(tree, root->bnr.bn);
-       if (root->record < 3) {
-               root->flags |= HFS_BPATH_UNDERFLOW;
-       }
+       rec = tree->node_size - 2;
+       hfs_bnode_write_u16(new_node, rec, 14);
+
+       if (node) {
+               /* insert old root idx into new root */
+               node->parent = tree->root;
+               if (node->type == HFS_NODE_LEAF ||
+                   tree->attributes & HFS_TREE_VARIDXKEYS)
+                       key_size = hfs_bnode_read_u8(node, 14) + 1;
+               else
+                       key_size = tree->max_key_len + 1;
+               hfs_bnode_copy(new_node, 14, node, 14, key_size);
+
+               if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
+                       key_size = tree->max_key_len + 1;
+                       hfs_bnode_write_u8(new_node, 14, tree->max_key_len);
+               }
+               key_size = (key_size + 1) & -2;
+               cnid = cpu_to_be32(node->this);
+               hfs_bnode_write(new_node, &cnid, 14 + key_size, 4);
+
+               rec -= 2;
+               hfs_bnode_write_u16(new_node, rec, 14 + key_size + 4);
 
-       if (!(root->flags & brec->keep_flags)) {
-               hfs_brec_relse(brec, head);
+               hfs_bnode_put(node);
        }
+       hfs_bnode_put(new_node);
+       mark_inode_dirty(tree->inode);
 
-       return root;
+       return 0;
 }
index f14bb508e134eab427bc26f5e7a0f1ff895b3b40..3e620efdd476ee63f437c6bf0b38ece367af6f28 100644 (file)
 /*
- * linux/fs/hfs/btree.c
+ *  linux/fs/hfs/btree.c
  *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
+ * Copyright (C) 2001
+ * Brad Boyer (flar@allandria.com)
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  *
- * This file contains the code to manipulate the B-tree structure.
- * The catalog and extents files are both B-trees.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- *
- * The code in this file initializes some structures which contain
- * pointers by calling memset(&foo, 0, sizeof(foo)).
- * This produces the desired behavior only due to the non-ANSI
- * assumption that the machine representation of NULL is all zeros.
+ * Handle opening/closing btree
  */
 
-#include "hfs_btree.h"
+#include <linux/pagemap.h>
 
-/*================ File-local functions ================*/
+#include "btree.h"
 
-/*
- * hfs_bnode_ditch() 
- *
- * Description:
- *   This function deletes an entire linked list of bnodes, so it
- *   does not need to keep the linked list consistent as
- *   hfs_bnode_delete() does.
- *   Called by hfs_btree_init() for error cleanup and by hfs_btree_free().
- * Input Variable(s):
- *   struct hfs_bnode *bn: pointer to the first (struct hfs_bnode) in
- *    the linked list to be deleted.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'bn' is NULL or points to a "valid" (struct hfs_bnode) with a 'prev'
- *    field of NULL.
- * Postconditions:
- *   'bn' and all (struct hfs_bnode)s in the chain of 'next' pointers
- *   are deleted, freeing the associated memory and hfs_buffer_put()ing
- *   the associated buffer.
- */
-static void hfs_bnode_ditch(struct hfs_bnode *bn) {
-       struct hfs_bnode *tmp;
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-       extern int bnode_count;
-#endif
-
-       while (bn != NULL) {
-               tmp = bn->next;
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-               hfs_warn("deleting node %d from tree %d with count %d\n",
-                        bn->node, (int)ntohl(bn->tree->entry.cnid), bn->count);
-               --bnode_count;
-#endif
-               hfs_buffer_put(bn->buf); /* safe: checks for NULL argument */
-
-               /* free all but the header */
-               if (bn->node) {
-                       HFS_DELETE(bn);
-               }
-               bn = tmp;
+/* Get a reference to a B*Tree and do some initial checks */
+struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp keycmp)
+{
+       struct hfs_btree *tree;
+       struct hfs_btree_header_rec *head;
+       struct address_space *mapping;
+       struct page *page;
+       unsigned int shift, size;
+
+       tree = kmalloc(sizeof(*tree), GFP_KERNEL);
+       if (!tree)
+               return NULL;
+       memset(tree, 0, sizeof(*tree));
+
+       init_MUTEX(&tree->tree_lock);
+       spin_lock_init(&tree->hash_lock);
+       /* Set the correct compare function */
+       tree->sb = sb;
+       tree->cnid = id;
+       tree->keycmp = keycmp;
+
+       tree->inode = iget_locked(sb, id);
+       if (!tree->inode)
+               goto free_tree;
+       if (!(tree->inode->i_state & I_NEW))
+               BUG();
+       {
+       struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
+       HFS_I(tree->inode)->flags = 0;
+       init_MUTEX(&HFS_I(tree->inode)->extents_lock);
+       switch (id) {
+       case HFS_EXT_CNID:
+               hfs_inode_read_fork(tree->inode, mdb->drXTExtRec, mdb->drXTFlSize,
+                                   mdb->drXTFlSize, be32_to_cpu(mdb->drXTClpSiz));
+               tree->inode->i_mapping->a_ops = &hfs_btree_aops;
+               break;
+       case HFS_CAT_CNID:
+               hfs_inode_read_fork(tree->inode, mdb->drCTExtRec, mdb->drCTFlSize,
+                                   mdb->drCTFlSize, be32_to_cpu(mdb->drCTClpSiz));
+               tree->inode->i_mapping->a_ops = &hfs_btree_aops;
+               break;
+       default:
+               BUG();
        }
-}
+       }
+       unlock_new_inode(tree->inode);
 
-/*================ Global functions ================*/
+       mapping = tree->inode->i_mapping;
+       page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage, NULL);
+       if (IS_ERR(page))
+               goto free_tree;
 
-/*
- * hfs_btree_free()
- *
- * Description:
- *   This function frees a (struct hfs_btree) obtained from hfs_btree_init().
- *   Called by hfs_put_super().
- * Input Variable(s):
- *   struct hfs_btree *bt: pointer to the (struct hfs_btree) to free
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'bt' is NULL or points to a "valid" (struct hfs_btree)
- * Postconditions:
- *   If 'bt' points to a "valid" (struct hfs_btree) then all (struct
- *    hfs_bnode)s associated with 'bt' are freed by calling
- *    hfs_bnode_ditch() and the memory associated with the (struct
- *    hfs_btree) is freed.
- *   If 'bt' is NULL or not "valid" an error is printed and nothing
- *    is changed.
- */
-void hfs_btree_free(struct hfs_btree *bt)
+       /* Load the header */
+       head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
+       tree->root = be32_to_cpu(head->root);
+       tree->leaf_count = be32_to_cpu(head->leaf_count);
+       tree->leaf_head = be32_to_cpu(head->leaf_head);
+       tree->leaf_tail = be32_to_cpu(head->leaf_tail);
+       tree->node_count = be32_to_cpu(head->node_count);
+       tree->free_nodes = be32_to_cpu(head->free_nodes);
+       tree->attributes = be32_to_cpu(head->attributes);
+       tree->node_size = be16_to_cpu(head->node_size);
+       tree->max_key_len = be16_to_cpu(head->max_key_len);
+       tree->depth = be16_to_cpu(head->depth);
+
+       size = tree->node_size;
+       if (!size || size & (size - 1))
+               goto fail_page;
+       if (!tree->node_count)
+               goto fail_page;
+       for (shift = 0; size >>= 1; shift += 1)
+               ;
+       tree->node_size_shift = shift;
+
+       tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+       kunmap(page);
+       page_cache_release(page);
+       return tree;
+
+ fail_page:
+       tree->inode->i_mapping->a_ops = &hfs_aops;
+       page_cache_release(page);
+ free_tree:
+       iput(tree->inode);
+       kfree(tree);
+       return NULL;
+}
+
+/* Release resources used by a btree */
+void hfs_btree_close(struct hfs_btree *tree)
 {
-       int lcv;
+       struct hfs_bnode *node;
+       int i;
 
-       if (bt && (bt->magic == HFS_BTREE_MAGIC)) {
-               hfs_extent_free(&bt->entry.u.file.data_fork);
+       if (!tree)
+               return;
 
-               for (lcv=0; lcv<HFS_CACHELEN; ++lcv) {
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-                       hfs_warn("deleting nodes from bucket %d:\n", lcv);
-#endif
-                       hfs_bnode_ditch(bt->cache[lcv]);
+       for (i = 0; i < NODE_HASH_SIZE; i++) {
+               while ((node = tree->node_hash[i])) {
+                       tree->node_hash[i] = node->next_hash;
+                       if (atomic_read(&node->refcnt))
+                               printk("HFS: node %d:%d still has %d user(s)!\n",
+                                       node->tree->cnid, node->this, atomic_read(&node->refcnt));
+                       hfs_bnode_free(node);
+                       tree->node_hash_cnt--;
                }
+       }
+       iput(tree->inode);
+       kfree(tree);
+}
 
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-               hfs_warn("deleting header and bitmap nodes\n");
-#endif
-               hfs_bnode_ditch(&bt->head);
+void hfs_btree_write(struct hfs_btree *tree)
+{
+       struct hfs_btree_header_rec *head;
+       struct hfs_bnode *node;
+       struct page *page;
 
-#if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
-               hfs_warn("deleting root node\n");
-#endif
-               hfs_bnode_ditch(bt->root);
+       node = hfs_bnode_find(tree, 0);
+       if (IS_ERR(node))
+               /* panic? */
+               return;
+       /* Load the header */
+       page = node->page[0];
+       head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
 
-               HFS_DELETE(bt);
-       } else if (bt) {
-               hfs_warn("hfs_btree_free: corrupted hfs_btree.\n");
-       }
+       head->root = cpu_to_be32(tree->root);
+       head->leaf_count = cpu_to_be32(tree->leaf_count);
+       head->leaf_head = cpu_to_be32(tree->leaf_head);
+       head->leaf_tail = cpu_to_be32(tree->leaf_tail);
+       head->node_count = cpu_to_be32(tree->node_count);
+       head->free_nodes = cpu_to_be32(tree->free_nodes);
+       head->attributes = cpu_to_be32(tree->attributes);
+       head->depth = cpu_to_be16(tree->depth);
+
+       kunmap(page);
+       set_page_dirty(page);
+       hfs_bnode_put(node);
 }
 
-/*
- * hfs_btree_init()
- *
- * Description:
- *   Given some vital information from the MDB (HFS superblock),
- *   initializes the fields of a (struct hfs_btree).
- * Input Variable(s):
- *   struct hfs_mdb *mdb: pointer to the MDB
- *   ino_t cnid: the CNID (HFS_CAT_CNID or HFS_EXT_CNID) of the B-tree
- *   hfs_u32 tsize: the size, in bytes, of the B-tree
- *   hfs_u32 csize: the size, in bytes, of the clump size for the B-tree
- * Output Variable(s):
- *   NONE
- * Returns:
- *   (struct hfs_btree *): pointer to the initialized hfs_btree on success,
- *    or NULL on failure
- * Preconditions:
- *   'mdb' points to a "valid" (struct hfs_mdb)
- * Postconditions:
- *   Assuming the inputs are what they claim to be, no errors occur
- *   reading from disk, and no inconsistencies are noticed in the data
- *   read from disk, the return value is a pointer to a "valid"
- *   (struct hfs_btree).  If there are errors reading from disk or
- *   inconsistencies are noticed in the data read from disk, then and
- *   all resources that were allocated are released and NULL is
- *   returned. If the inputs are not what they claim to be or if they
- *   are unnoticed inconsistencies in the data read from disk then the
- *   returned hfs_btree is probably going to lead to errors when it is
- *   used in a non-trivial way.
- */
-struct hfs_btree * hfs_btree_init(struct hfs_mdb *mdb, ino_t cnid,
-                                 hfs_byte_t ext[12],
-                                 hfs_u32 tsize, hfs_u32 csize)
+static struct hfs_bnode *hfs_bmap_new_bmap(struct hfs_bnode *prev, u32 idx)
 {
-       struct hfs_btree * bt;
-       struct BTHdrRec * th;
-       struct hfs_bnode * tmp;
-       unsigned int next;
-#if defined(DEBUG_HEADER) || defined(DEBUG_ALL)
-       unsigned char *p, *q;
-#endif
-
-       if (!mdb || !ext || !HFS_NEW(bt)) {
-               goto bail3;
-       }
+       struct hfs_btree *tree = prev->tree;
+       struct hfs_bnode *node;
+       struct hfs_bnode_desc desc;
+       u32 cnid;
 
-       bt->magic = HFS_BTREE_MAGIC;
-       bt->sys_mdb = mdb->sys_mdb;
-       bt->reserved = 0;
-       sema_init(&bt->sem, 1);
-       bt->dirt = 0;
-       memset(bt->cache, 0, sizeof(bt->cache));
-
-#if 0   /* this is a fake entry. so we don't need to initialize it. */
-       memset(&bt->entry, 0, sizeof(bt->entry));
-       hfs_init_waitqueue(&bt->entry.wait);
-       INIT_LIST_HEAD(&bt->entry.hash);
-       INIT_LIST_HEAD(&bt->entry.list);
-#endif
-
-       bt->entry.mdb = mdb;
-       bt->entry.cnid = cnid;
-       bt->entry.type = HFS_CDR_FIL;
-       bt->entry.u.file.magic = HFS_FILE_MAGIC;
-       bt->entry.u.file.clumpablks = (csize / mdb->alloc_blksz)
-                                               >> HFS_SECTOR_SIZE_BITS;
-       bt->entry.u.file.data_fork.entry = &bt->entry;
-       bt->entry.u.file.data_fork.lsize = tsize;
-       bt->entry.u.file.data_fork.psize = tsize >> HFS_SECTOR_SIZE_BITS;
-       bt->entry.u.file.data_fork.fork = HFS_FK_DATA;
-       hfs_extent_in(&bt->entry.u.file.data_fork, ext);
-
-       hfs_bnode_read(&bt->head, bt, 0, HFS_STICKY);
-       if (!hfs_buffer_ok(bt->head.buf)) {
-               goto bail2;
-       }
-       th = (struct BTHdrRec *)((char *)hfs_buffer_data(bt->head.buf) +
-                                               sizeof(struct NodeDescriptor));
-
-       /* read in the bitmap nodes (if any) */
-       tmp = &bt->head;
-       while ((next = tmp->ndFLink)) {
-               if (!HFS_NEW(tmp->next)) {
-                       goto bail2;
-               }
-               hfs_bnode_read(tmp->next, bt, next, HFS_STICKY);
-               if (!hfs_buffer_ok(tmp->next->buf)) {
-                       goto bail2;
-               }
-               tmp->next->prev = tmp;
-               tmp = tmp->next;
-       }
+       node = hfs_bnode_create(tree, idx);
+       if (IS_ERR(node))
+               return node;
 
-       if (hfs_get_ns(th->bthNodeSize) != htons(HFS_SECTOR_SIZE)) {
-               hfs_warn("hfs_btree_init: bthNodeSize!=512 not supported\n");
-               goto bail2;
-       }
+       if (!tree->free_nodes)
+               panic("FIXME!!!");
+       tree->free_nodes--;
+       prev->next = idx;
+       cnid = cpu_to_be32(idx);
+       hfs_bnode_write(prev, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
 
-       if (cnid == htonl(HFS_CAT_CNID)) {
-               bt->compare = (hfs_cmpfn)hfs_cat_compare;
-       } else if (cnid == htonl(HFS_EXT_CNID)) {
-               bt->compare = (hfs_cmpfn)hfs_ext_compare;
-       } else {
-               goto bail2;
-       }
-       bt->bthDepth  = hfs_get_hs(th->bthDepth);
-       bt->bthRoot   = hfs_get_hl(th->bthRoot);
-       bt->bthNRecs  = hfs_get_hl(th->bthNRecs);
-       bt->bthFNode  = hfs_get_hl(th->bthFNode);
-       bt->bthLNode  = hfs_get_hl(th->bthLNode);
-       bt->bthNNodes = hfs_get_hl(th->bthNNodes);
-       bt->bthFree   = hfs_get_hl(th->bthFree);
-       bt->bthKeyLen = hfs_get_hs(th->bthKeyLen);
-
-#if defined(DEBUG_HEADER) || defined(DEBUG_ALL)
-       hfs_warn("bthDepth %d\n", bt->bthDepth);
-       hfs_warn("bthRoot %d\n", bt->bthRoot);
-       hfs_warn("bthNRecs %d\n", bt->bthNRecs);
-       hfs_warn("bthFNode %d\n", bt->bthFNode);
-       hfs_warn("bthLNode %d\n", bt->bthLNode);
-       hfs_warn("bthKeyLen %d\n", bt->bthKeyLen);
-       hfs_warn("bthNNodes %d\n", bt->bthNNodes);
-       hfs_warn("bthFree %d\n", bt->bthFree);
-       p = (unsigned char *)hfs_buffer_data(bt->head.buf);
-       q = p + HFS_SECTOR_SIZE;
-       while (p < q) {
-               hfs_warn("%02x %02x %02x %02x %02x %02x %02x %02x "
-                        "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-                        *p++, *p++, *p++, *p++, *p++, *p++, *p++, *p++,
-                        *p++, *p++, *p++, *p++, *p++, *p++, *p++, *p++);
-       }
-#endif
-
-       /* Read in the root if it exists.
-          The header always exists, but the root exists only if the
-          tree is non-empty */
-       if (bt->bthDepth && bt->bthRoot) {
-               if (!HFS_NEW(bt->root)) {
-                       goto bail2;
-               }
-               hfs_bnode_read(bt->root, bt, bt->bthRoot, HFS_STICKY);
-               if (!hfs_buffer_ok(bt->root->buf)) {
-                       goto bail1;
-               }
-       } else {
-               bt->root = NULL;
+       node->type = HFS_NODE_MAP;
+       node->num_recs = 1;
+       hfs_bnode_clear(node, 0, tree->node_size);
+       desc.next = 0;
+       desc.prev = 0;
+       desc.type = HFS_NODE_MAP;
+       desc.height = 0;
+       desc.num_recs = cpu_to_be16(1);
+       desc.reserved = 0;
+       hfs_bnode_write(node, &desc, 0, sizeof(desc));
+       hfs_bnode_write_u16(node, 14, 0x8000);
+       hfs_bnode_write_u16(node, tree->node_size - 2, 14);
+       hfs_bnode_write_u16(node, tree->node_size - 4, tree->node_size - 6);
+
+       return node;
+}
+
+struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
+{
+       struct hfs_bnode *node, *next_node;
+       struct page **pagep;
+       u32 nidx, idx;
+       u16 off, len;
+       u8 *data, byte, m;
+       int i;
+
+       while (!tree->free_nodes) {
+               struct inode *inode = tree->inode;
+               u32 count;
+               int res;
+
+               res = hfs_extend_file(inode);
+               if (res)
+                       return ERR_PTR(res);
+               inode->i_blocks = HFS_I(inode)->alloc_blocks *
+                                 HFS_SB(tree->sb)->fs_div;
+               HFS_I(inode)->phys_size = inode->i_size =
+                       (loff_t)inode->i_blocks << tree->sb->s_blocksize_bits;
+               count = inode->i_size >> tree->node_size_shift;
+               tree->free_nodes = count - tree->node_count;
+               tree->node_count = count;
        }
 
-       return bt;
+       nidx = 0;
+       node = hfs_bnode_find(tree, nidx);
+       if (IS_ERR(node))
+               return node;
+       len = hfs_brec_lenoff(node, 2, &off);
 
- bail1:
-       hfs_bnode_ditch(bt->root);
- bail2:
-       hfs_bnode_ditch(&bt->head);
-       HFS_DELETE(bt);
- bail3:
-       return NULL;
+       off += node->page_offset;
+       pagep = node->page + (off >> PAGE_CACHE_SHIFT);
+       data = kmap(*pagep);
+       off &= ~PAGE_CACHE_MASK;
+       idx = 0;
+
+       for (;;) {
+               while (len) {
+                       byte = data[off];
+                       if (byte != 0xff) {
+                               for (m = 0x80, i = 0; i < 8; m >>= 1, i++) {
+                                       if (!(byte & m)) {
+                                               idx += i;
+                                               data[off] |= m;
+                                               set_page_dirty(*pagep);
+                                               kunmap(*pagep);
+                                               tree->free_nodes--;
+                                               mark_inode_dirty(tree->inode);
+                                               hfs_bnode_put(node);
+                                               return hfs_bnode_create(tree, idx);
+                                       }
+                               }
+                       }
+                       if (++off >= PAGE_CACHE_SIZE) {
+                               kunmap(*pagep);
+                               data = kmap(*++pagep);
+                               off = 0;
+                       }
+                       idx += 8;
+                       len--;
+               }
+               kunmap(*pagep);
+               nidx = node->next;
+               if (!nidx) {
+                       printk("create new bmap node...\n");
+                       next_node = hfs_bmap_new_bmap(node, idx);
+               } else
+                       next_node = hfs_bnode_find(tree, nidx);
+               hfs_bnode_put(node);
+               if (IS_ERR(next_node))
+                       return next_node;
+               node = next_node;
+
+               len = hfs_brec_lenoff(node, 0, &off);
+               off += node->page_offset;
+               pagep = node->page + (off >> PAGE_CACHE_SHIFT);
+               data = kmap(*pagep);
+               off &= ~PAGE_CACHE_MASK;
+       }
 }
 
-/*
- * hfs_btree_commit()
- *
- * Called to write a possibly dirty btree back to disk.
- */
-void hfs_btree_commit(struct hfs_btree *bt, hfs_byte_t ext[12], hfs_lword_t size)
+void hfs_bmap_free(struct hfs_bnode *node)
 {
-       if (bt->dirt) {
-               struct BTHdrRec *th;
-               th = (struct BTHdrRec *)((char *)hfs_buffer_data(bt->head.buf) +
-                                                sizeof(struct NodeDescriptor));
-
-               hfs_put_hs(bt->bthDepth,  th->bthDepth);
-               hfs_put_hl(bt->bthRoot,   th->bthRoot);
-               hfs_put_hl(bt->bthNRecs,  th->bthNRecs);
-               hfs_put_hl(bt->bthFNode,  th->bthFNode);
-               hfs_put_hl(bt->bthLNode,  th->bthLNode);
-               hfs_put_hl(bt->bthNNodes, th->bthNNodes);
-               hfs_put_hl(bt->bthFree,   th->bthFree);
-               hfs_buffer_dirty(bt->head.buf);
-
-               /*
-                * Commit the bnodes which are not cached.
-                * The map nodes don't need to be committed here because
-                * they are committed every time they are changed.
-                */
-               hfs_bnode_commit(&bt->head);
-               if (bt->root) {
-                       hfs_bnode_commit(bt->root);
-               }
+       struct hfs_btree *tree;
+       struct page *page;
+       u16 off, len;
+       u32 nidx;
+       u8 *data, byte, m;
 
-       
-               hfs_put_hl(bt->bthNNodes << HFS_SECTOR_SIZE_BITS, size);
-               hfs_extent_out(&bt->entry.u.file.data_fork, ext);
-               /* hfs_buffer_dirty(mdb->buf); (Done by caller) */
+       dprint(DBG_BNODE_MOD, "btree_free_node: %u\n", node->this);
+       tree = node->tree;
+       nidx = node->this;
+       node = hfs_bnode_find(tree, 0);
+       if (IS_ERR(node))
+               return;
+       len = hfs_brec_lenoff(node, 2, &off);
+       while (nidx >= len * 8) {
+               u32 i;
 
-               bt->dirt = 0;
+               nidx -= len * 8;
+               i = node->next;
+               hfs_bnode_put(node);
+               if (!i) {
+                       /* panic */;
+                       printk("HFS: unable to free bnode %u. bmap not found!\n", node->this);
+                       return;
+               }
+               node = hfs_bnode_find(tree, i);
+               if (IS_ERR(node))
+                       return;
+               if (node->type != HFS_NODE_MAP) {
+                       /* panic */;
+                       printk("HFS: invalid bmap found! (%u,%d)\n", node->this, node->type);
+                       hfs_bnode_put(node);
+                       return;
+               }
+               len = hfs_brec_lenoff(node, 0, &off);
+       }
+       off += node->page_offset + nidx / 8;
+       page = node->page[off >> PAGE_CACHE_SHIFT];
+       data = kmap(page);
+       off &= ~PAGE_CACHE_MASK;
+       m = 1 << (~nidx & 7);
+       byte = data[off];
+       if (!(byte & m)) {
+               printk("HFS: trying to free free bnode %u(%d)\n", node->this, node->type);
+               kunmap(page);
+               hfs_bnode_put(node);
+               return;
        }
+       data[off] = byte & ~m;
+       set_page_dirty(page);
+       kunmap(page);
+       hfs_bnode_put(node);
+       tree->free_nodes++;
+       mark_inode_dirty(tree->inode);
 }
diff --git a/fs/hfs/btree.h b/fs/hfs/btree.h
new file mode 100644 (file)
index 0000000..266af5e
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ *  linux/fs/hfs/btree.h
+ *
+ * Copyright (C) 2001
+ * Brad Boyer (flar@allandria.com)
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
+ */
+
+#include "hfs_fs.h"
+
+typedef int (*btree_keycmp)(const btree_key *, const btree_key *);
+
+#define NODE_HASH_SIZE  256
+
+/* A HFS BTree held in memory */
+struct hfs_btree {
+       struct super_block *sb;
+       struct inode *inode;
+       btree_keycmp keycmp;
+
+       u32 cnid;
+       u32 root;
+       u32 leaf_count;
+       u32 leaf_head;
+       u32 leaf_tail;
+       u32 node_count;
+       u32 free_nodes;
+       u32 attributes;
+
+       unsigned int node_size;
+       unsigned int node_size_shift;
+       unsigned int max_key_len;
+       unsigned int depth;
+
+       //unsigned int map1_size, map_size;
+       struct semaphore tree_lock;
+
+       unsigned int pages_per_bnode;
+       spinlock_t hash_lock;
+       struct hfs_bnode *node_hash[NODE_HASH_SIZE];
+       int node_hash_cnt;
+};
+
+/* A HFS BTree node in memory */
+struct hfs_bnode {
+       struct hfs_btree *tree;
+
+       u32 prev;
+       u32 this;
+       u32 next;
+       u32 parent;
+
+       u16 num_recs;
+       u8 type;
+       u8 height;
+
+       struct hfs_bnode *next_hash;
+       unsigned long flags;
+       wait_queue_head_t lock_wq;
+       atomic_t refcnt;
+       unsigned int page_offset;
+       struct page *page[0];
+};
+
+#define HFS_BNODE_ERROR                0
+#define HFS_BNODE_NEW          1
+#define HFS_BNODE_DELETED      2
+
+struct hfs_find_data {
+       btree_key *key;
+       btree_key *search_key;
+       struct hfs_btree *tree;
+       struct hfs_bnode *bnode;
+       int record;
+       int keyoffset, keylength;
+       int entryoffset, entrylength;
+};
+
+
+/* btree.c */
+extern struct hfs_btree *hfs_btree_open(struct super_block *, u32, btree_keycmp);
+extern void hfs_btree_close(struct hfs_btree *);
+extern void hfs_btree_write(struct hfs_btree *);
+extern struct hfs_bnode * hfs_bmap_alloc(struct hfs_btree *);
+extern void hfs_bmap_free(struct hfs_bnode *node);
+
+/* bnode.c */
+extern void hfs_bnode_read(struct hfs_bnode *, void *, int, int);
+extern u16 hfs_bnode_read_u16(struct hfs_bnode *, int);
+extern u8 hfs_bnode_read_u8(struct hfs_bnode *, int);
+extern void hfs_bnode_read_key(struct hfs_bnode *, void *, int);
+extern void hfs_bnode_write(struct hfs_bnode *, void *, int, int);
+extern void hfs_bnode_write_u16(struct hfs_bnode *, int, u16);
+extern void hfs_bnode_write_u8(struct hfs_bnode *, int, u8);
+extern void hfs_bnode_clear(struct hfs_bnode *, int, int);
+extern void hfs_bnode_copy(struct hfs_bnode *, int,
+                          struct hfs_bnode *, int, int);
+extern void hfs_bnode_move(struct hfs_bnode *, int, int, int);
+extern void hfs_bnode_dump(struct hfs_bnode *);
+extern void hfs_bnode_unlink(struct hfs_bnode *);
+extern struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *, u32);
+extern struct hfs_bnode *hfs_bnode_find(struct hfs_btree *, u32);
+extern void hfs_bnode_unhash(struct hfs_bnode *);
+extern void hfs_bnode_free(struct hfs_bnode *);
+extern struct hfs_bnode *hfs_bnode_create(struct hfs_btree *, u32);
+extern void hfs_bnode_get(struct hfs_bnode *);
+extern void hfs_bnode_put(struct hfs_bnode *);
+
+/* brec.c */
+extern u16 hfs_brec_lenoff(struct hfs_bnode *, u16, u16 *);
+extern u16 hfs_brec_keylen(struct hfs_bnode *, u16);
+extern int hfs_brec_insert(struct hfs_find_data *, void *, int);
+extern int hfs_brec_remove(struct hfs_find_data *);
+extern struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *);
+extern int hfs_brec_update_parent(struct hfs_find_data *);
+extern int hfs_btree_inc_height(struct hfs_btree *);
+
+/* bfind.c */
+extern int hfs_find_init(struct hfs_btree *, struct hfs_find_data *);
+extern void hfs_find_exit(struct hfs_find_data *);
+extern int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *);
+extern int hfs_brec_find(struct hfs_find_data *);
+extern int hfs_brec_read(struct hfs_find_data *, void *, int);
+extern int hfs_brec_goto(struct hfs_find_data *, int);
+
+
+struct hfs_bnode_desc {
+       u32 next;               /* (V) Number of the next node at this level */
+       u32 prev;               /* (V) Number of the prev node at this level */
+       u8 type;                /* (F) The type of node */
+       u8 height;              /* (F) The level of this node (leaves=1) */
+       u16 num_recs;           /* (V) The number of records in this node */
+       u16 reserved;
+} __packed;
+
+#define HFS_NODE_INDEX 0x00    /* An internal (index) node */
+#define HFS_NODE_HEADER        0x01    /* The tree header node (node 0) */
+#define HFS_NODE_MAP   0x02    /* Holds part of the bitmap of used nodes */
+#define HFS_NODE_LEAF  0xFF    /* A leaf (ndNHeight==1) node */
+
+struct hfs_btree_header_rec {
+       u16 depth;              /* (V) The number of levels in this B-tree */
+       u32 root;               /* (V) The node number of the root node */
+       u32 leaf_count;         /* (V) The number of leaf records */
+       u32 leaf_head;          /* (V) The number of the first leaf node */
+       u32 leaf_tail;          /* (V) The number of the last leaf node */
+       u16 node_size;          /* (F) The number of bytes in a node (=512) */
+       u16 max_key_len;        /* (F) The length of a key in an index node */
+       u32 node_count;         /* (V) The total number of nodes */
+       u32 free_nodes;         /* (V) The number of unused nodes */
+       u16 reserved1;
+       u32 clump_size;         /* (F) clump size. not usually used. */
+       u8 btree_type;          /* (F) BTree type */
+       u8 reserved2;
+       u32 attributes;         /* (F) attributes */
+       u32 reserved3[16];
+} __packed;
+
+#define HFS_NODE_INDEX 0x00    /* An internal (index) node */
+#define HFS_NODE_HEADER        0x01    /* The tree header node (node 0) */
+#define HFS_NODE_MAP           0x02    /* Holds part of the bitmap of used nodes */
+#define HFS_NODE_LEAF          0xFF    /* A leaf (ndNHeight==1) node */
+
+#define BTREE_ATTR_BADCLOSE    0x00000001      /* b-tree not closed properly. not
+                                                  used by hfsplus. */
+#define HFS_TREE_BIGKEYS       0x00000002      /* key length is u16 instead of u8.
+                                                  used by hfsplus. */
+#define HFS_TREE_VARIDXKEYS    0x00000004      /* variable key length instead of
+                                                  max key length. use din catalog
+                                                  b-tree but not in extents
+                                                  b-tree (hfsplus). */
index 1d6f65ef72e22fdc617045abacc3b63038b4f06f..701f896f10f8fb2b1b3983028349d2465d1f0f05 100644 (file)
 /*
- * linux/fs/hfs/catalog.c
+ *  linux/fs/hfs/catalog.c
  *
  * Copyright (C) 1995-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * This file contains the functions related to the catalog B-tree.
  *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * Cache code shamelessly stolen from 
+ * Cache code shamelessly stolen from
  *     linux/fs/inode.c Copyright (C) 1991, 1992  Linus Torvalds
  *     re-shamelessly stolen Copyright (C) 1997 Linus Torvalds
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- *
- * The code in this file initializes some structures by calling
- * memset(&foo, 0, sizeof(foo)).  This produces the desired behavior
- * only due to the non-ANSI assumption that the machine representation
- */
-
-#include "hfs.h"
-
-/*================ Variable-like macros ================*/
-
-/* Number of hash table slots */
-#define C_HASHBITS  10
-#define C_HASHSIZE  (1UL << C_HASHBITS)
-#define C_HASHMASK  (C_HASHSIZE - 1)
-
-/* Number of entries to fit in a single page on an i386.
- * Actually, now it's used to increment the free entry pool. */
-#define CCACHE_INC (PAGE_SIZE/sizeof(struct hfs_cat_entry))
-#define CCACHE_MAX (CCACHE_INC * 8)
-
-/*================ File-local data types ================*/
-
-/* The catalog record for a file */
-typedef struct {
-       hfs_byte_t      Flags;          /* Flags such as read-only */
-       hfs_byte_t      Typ;            /* file version number = 0 */
-       hfs_finfo_t     UsrWds;         /* data used by the Finder */
-       hfs_lword_t     FlNum;          /* The CNID */
-       hfs_word_t      StBlk;          /* obsolete */
-       hfs_lword_t     LgLen;          /* The logical EOF of the data fork*/
-       hfs_lword_t     PyLen;          /* The physical EOF of the data fork */
-       hfs_word_t      RStBlk;         /* obsolete */
-       hfs_lword_t     RLgLen;         /* The logical EOF of the rsrc fork */
-       hfs_lword_t     RPyLen;         /* The physical EOF of the rsrc fork */
-       hfs_lword_t     CrDat;          /* The creation date */
-       hfs_lword_t     MdDat;          /* The modified date */
-       hfs_lword_t     BkDat;          /* The last backup date */
-       hfs_fxinfo_t    FndrInfo;       /* more data for the Finder */
-       hfs_word_t      ClpSize;        /* number of bytes to allocate
-                                          when extending files */
-       hfs_byte_t      ExtRec[12];     /* first extent record
-                                          for the data fork */
-       hfs_byte_t      RExtRec[12];    /* first extent record
-                                          for the resource fork */
-       hfs_lword_t     Resrv;          /* reserved by Apple */
-} __attribute__((packed)) FIL_REC;
-
-/* the catalog record for a directory */
-typedef struct {
-       hfs_word_t      Flags;          /* flags */
-       hfs_word_t      Val;            /* Valence: number of files and
-                                          dirs in the directory */
-       hfs_lword_t     DirID;          /* The CNID */
-       hfs_lword_t     CrDat;          /* The creation date */
-       hfs_lword_t     MdDat;          /* The modification date */
-       hfs_lword_t     BkDat;          /* The last backup date */
-       hfs_dinfo_t     UsrInfo;        /* data used by the Finder */
-       hfs_dxinfo_t    FndrInfo;       /* more data used by Finder */
-       hfs_byte_t      Resrv[16];      /* reserved by Apple */
-} __attribute__((packed)) DIR_REC;
-
-/* the catalog record for a thread */
-typedef struct {
-       hfs_byte_t              Reserv[8];      /* reserved by Apple */
-       hfs_lword_t             ParID;          /* CNID of parent directory */
-       struct hfs_name         CName;          /* The name of this entry */
-}  __attribute__((packed)) THD_REC;
-
-/* A catalog tree record */
-struct hfs_cat_rec {
-       hfs_byte_t              cdrType;        /* The type of entry */
-       hfs_byte_t              cdrResrv2;      /* padding */
-       union {
-               FIL_REC fil;
-               DIR_REC dir;
-               THD_REC thd;
-       } u;
-} __attribute__((packed));
-
-/*================ File-local variables ================*/
-static LIST_HEAD(entry_in_use);
-static LIST_HEAD(entry_unused);
-static struct list_head hash_table[C_HASHSIZE];
-
-static spinlock_t entry_lock = SPIN_LOCK_UNLOCKED;
-
-static struct {
-        int nr_entries;
-        int nr_free_entries;
-} entries_stat;
-
-/*================ File-local functions ================*/
-
-/*
- * brec_to_id
- *
- * Get the CNID from a brec
- */
-static inline hfs_u32 brec_to_id(struct hfs_brec *brec)
-{
-       struct hfs_cat_rec *rec = brec->data;
-
-       return hfs_get_nl((rec->cdrType==HFS_CDR_FIL) ?
-                               rec->u.fil.FlNum : rec->u.dir.DirID);
-}
-
-/*
- * hashfn()
- *
- * hash an (struct mdb *) and a (struct hfs_cat_key *) to an integer.
- */
-static inline unsigned int hashfn(const struct hfs_mdb *mdb,
-                                 const struct hfs_cat_key *key)
-{
-       unsigned int hash;
-       
-       hash = (unsigned long) mdb | (unsigned long) key->ParID[3] | 
-               hfs_strhash(key->CName.Name, key->CName.Len);
-       hash = hash ^ (hash >> C_HASHBITS) ^ (hash >> C_HASHBITS*2);
-       return hash & C_HASHMASK;
-}
-
-/*
- * hash()
- *
- * hash an (struct mdb *) and a (struct hfs_cat_key *)
- * to a pointer to a slot in the hash table.
- */
-static inline struct list_head *hash(struct hfs_mdb *mdb,
-                                    const struct hfs_cat_key *key)
-{
-       return hash_table + hashfn(mdb, key);
-}
-
-static inline void insert_hash(struct hfs_cat_entry *entry)
-{
-       struct list_head *head = hash(entry->mdb, &entry->key);
-       list_add(&entry->hash, head);
-}
-
-static inline void remove_hash(struct hfs_cat_entry *entry)
-{
-       list_del_init(&entry->hash);
-}
-
-/*
- * wait_on_entry()
- *
- * Sleep until a locked entry is unlocked.
- */
-static inline void wait_on_entry(struct hfs_cat_entry * entry)
-{
-       while ((entry->state & HFS_LOCK)) {
-               hfs_sleep_on(&entry->wait);
-       }
-}
-
-/*
- * lock_entry()
- *
- * Obtain an exclusive lock on an entry.
  */
-static void lock_entry(struct hfs_cat_entry * entry)
-{
-       wait_on_entry(entry);
-       spin_lock(&entry_lock);
-       entry->state |= HFS_LOCK;
-       spin_unlock(&entry_lock);
-}
-
-/*
- * lock_entry()
- *
- * Relinquish an exclusive lock on an entry.
- */
-static void unlock_entry(struct hfs_cat_entry * entry)
-{
-       spin_lock(&entry_lock);
-       entry->state &= ~HFS_LOCK;
-       spin_unlock(&entry_lock);
-       hfs_wake_up(&entry->wait);
-}
-
-/* put entry on mdb dirty list. */
-void hfs_cat_mark_dirty(struct hfs_cat_entry *entry)
-{
-        struct hfs_mdb *mdb = entry->mdb;
 
-       spin_lock(&entry_lock);
-       if (!(entry->state & HFS_DIRTY)) {
-               entry->state |= HFS_DIRTY;
-
-               /* Only add valid (ie hashed) entries to the dirty list. */
-               if (!list_empty(&entry->hash)) {
-                       list_del(&entry->list);
-                       list_add(&entry->list, &mdb->entry_dirty);
-               }
-       }
-       spin_unlock(&entry_lock);
-}
-
-/* delete an entry and remove it from the hash table. */
-static void delete_entry(struct hfs_cat_entry *entry)
-{
-        if (!(entry->state & HFS_DELETED)) {
-               entry->state |= HFS_DELETED;
-               list_del_init(&entry->hash);
-
-               if (entry->type == HFS_CDR_FIL) {
-                 /* free all extents */
-                 entry->u.file.data_fork.lsize = 0;
-                 hfs_extent_adj(&entry->u.file.data_fork);
-                 entry->u.file.rsrc_fork.lsize = 0;
-                 hfs_extent_adj(&entry->u.file.rsrc_fork);
-               }
-       }
-}
-
-
-static inline void init_entry(struct hfs_cat_entry *entry)
-{
-       memset(entry, 0, sizeof(*entry));
-       hfs_init_waitqueue(&entry->wait);
-       INIT_LIST_HEAD(&entry->hash);
-       INIT_LIST_HEAD(&entry->list);
-}
-
-/*
- * hfs_cat_alloc()
- *
- * Try to allocate another entry. 
- */
-static inline struct hfs_cat_entry *hfs_cat_alloc(void)
-{
-        struct hfs_cat_entry *entry;
-
-       if (!HFS_NEW(entry))
-               return NULL;
-
-       init_entry(entry);
-       return entry;
-}
-
-/* this gets called with the spinlock held. */
-static int grow_entries(void)
-{
-        struct hfs_cat_entry *entry;
-       int i;
-       
-       for (i = 0; i < CCACHE_INC; i++) {
-               if (!(entry = hfs_cat_alloc()))
-                       break;
-               list_add(&entry->list, &entry_unused);
-       }
-
-       entries_stat.nr_entries += i;
-       entries_stat.nr_free_entries += i;
-               
-       return i;
-}
+#include "hfs_fs.h"
+#include "btree.h"
 
 /*
- * __read_entry()
+ * hfs_cat_build_key()
  *
- * Convert a (struct hfs_cat_rec) to a (struct hfs_cat_entry).
+ * Given the ID of the parent and the name build a search key.
  */
-static void __read_entry(struct hfs_cat_entry *entry,
-                        const struct hfs_cat_rec *cat)
+void hfs_cat_build_key(btree_key *key, u32 parent, struct qstr *name)
 {
-       entry->type = cat->cdrType;
-
-       if (cat->cdrType == HFS_CDR_DIR) {
-               struct hfs_dir *dir = &entry->u.dir;
-
-               entry->cnid = hfs_get_nl(cat->u.dir.DirID);
-
-               dir->magic = HFS_DIR_MAGIC;
-               dir->flags = hfs_get_ns(cat->u.dir.Flags);
-               memcpy(&entry->info.dir.dinfo, &cat->u.dir.UsrInfo, 16);
-               memcpy(&entry->info.dir.dxinfo, &cat->u.dir.FndrInfo, 16);
-               entry->create_date = hfs_get_nl(cat->u.dir.CrDat);
-               entry->modify_date = hfs_get_nl(cat->u.dir.MdDat);
-               entry->backup_date = hfs_get_nl(cat->u.dir.BkDat);
-               dir->dirs = dir->files = 0;
-               init_rwsem(&dir->sem);
-       } else if (cat->cdrType == HFS_CDR_FIL) {
-               struct hfs_file *fil = &entry->u.file;
-
-               entry->cnid = hfs_get_nl(cat->u.fil.FlNum);
-
-               fil->magic = HFS_FILE_MAGIC;
-
-               fil->data_fork.fork = HFS_FK_DATA;
-               fil->data_fork.entry = entry;
-               fil->data_fork.lsize = hfs_get_hl(cat->u.fil.LgLen);
-               fil->data_fork.psize = hfs_get_hl(cat->u.fil.PyLen) >>
-                                                    HFS_SECTOR_SIZE_BITS;
-               hfs_extent_in(&fil->data_fork, cat->u.fil.ExtRec);
-
-               fil->rsrc_fork.fork = HFS_FK_RSRC;
-               fil->rsrc_fork.entry = entry;
-               fil->rsrc_fork.lsize = hfs_get_hl(cat->u.fil.RLgLen);
-               fil->rsrc_fork.psize = hfs_get_hl(cat->u.fil.RPyLen) >>
-                                                    HFS_SECTOR_SIZE_BITS;
-               hfs_extent_in(&fil->rsrc_fork, cat->u.fil.RExtRec);
-
-               memcpy(&entry->info.file.finfo, &cat->u.fil.UsrWds, 16);
-               memcpy(&entry->info.file.fxinfo, &cat->u.fil.FndrInfo, 16);
-
-               entry->create_date = hfs_get_nl(cat->u.fil.CrDat);
-               entry->modify_date = hfs_get_nl(cat->u.fil.MdDat);
-               entry->backup_date = hfs_get_nl(cat->u.fil.BkDat);
-               fil->clumpablks = (hfs_get_hs(cat->u.fil.ClpSize)
-                                       / entry->mdb->alloc_blksz)
-                                               >> HFS_SECTOR_SIZE_BITS;
-               fil->flags = cat->u.fil.Flags;
+       key->cat.reserved = 0;
+       key->cat.ParID = cpu_to_be32(parent);
+       if (name) {
+               hfs_triv2mac(&key->cat.CName, name);
+               key->key_len = 6 + key->cat.CName.len;
        } else {
-               hfs_warn("hfs_fs: entry is neither file nor directory!\n");
+               memset(&key->cat.CName, 0, sizeof(struct hfs_name));
+               key->key_len = 6;
        }
 }
 
-/*
- * count_dir_entries()
- *
- * Count the number of files and directories in a given directory.
- */
-static inline void count_dir_entries(struct hfs_cat_entry *entry,
-                                    struct hfs_brec *brec)
-{
-       int error = 0;
-       hfs_u32 cnid;
-       hfs_u8 type;
-
-       if (!hfs_cat_open(entry, brec)) {
-               while (!(error = hfs_cat_next(entry, brec, 1, &cnid, &type))) {
-                       if (type == HFS_CDR_FIL) {
-                               ++entry->u.dir.files;
-                       } else if (type == HFS_CDR_DIR) {
-                               ++entry->u.dir.dirs;
-                       }
-               } /* -ENOENT is normal termination */
-       }
-       if (error != -ENOENT) {
-               entry->cnid = 0;
-       }
-}
-
-/*
- * read_entry()
- *
- * Convert a (struct hfs_brec) to a (struct hfs_cat_entry).
- */
-static inline void read_entry(struct hfs_cat_entry *entry,
-                             struct hfs_brec *brec)
-{
-       int need_count;
-       struct hfs_cat_rec *rec = brec->data;
-
-       __read_entry(entry, rec);
-
-       need_count = (rec->cdrType == HFS_CDR_DIR) && rec->u.dir.Val;
-
-       hfs_brec_relse(brec, NULL);
-
-       if (need_count) {
-               count_dir_entries(entry, brec);
-       }
-}
-
-/*
- * __write_entry()
- *
- * Convert a (struct hfs_cat_entry) to a (struct hfs_cat_rec).
- */
-static void __write_entry(const struct hfs_cat_entry *entry,
-                         struct hfs_cat_rec *cat)
+int hfs_cat_build_record(hfs_cat_rec *rec, u32 cnid, struct inode *inode)
 {
-       if (entry->type == HFS_CDR_DIR) {
-               const struct hfs_dir *dir = &entry->u.dir;
+       u32 mtime = hfs_mtime();
 
-               hfs_put_ns(dir->flags,             cat->u.dir.Flags);
-               hfs_put_hs(dir->dirs + dir->files, cat->u.dir.Val);
-               hfs_put_nl(entry->cnid,            cat->u.dir.DirID);
-               hfs_put_nl(entry->create_date,     cat->u.dir.CrDat);
-               hfs_put_nl(entry->modify_date,     cat->u.dir.MdDat);
-               hfs_put_nl(entry->backup_date,     cat->u.dir.BkDat);
-               memcpy(&cat->u.dir.UsrInfo, &entry->info.dir.dinfo, 16);
-               memcpy(&cat->u.dir.FndrInfo, &entry->info.dir.dxinfo, 16);
-       } else if (entry->type == HFS_CDR_FIL) {
-               const struct hfs_file *fil = &entry->u.file;
-
-               cat->u.fil.Flags = fil->flags;
-               hfs_put_nl(entry->cnid,            cat->u.fil.FlNum);
-               memcpy(&cat->u.fil.UsrWds, &entry->info.file.finfo, 16);
-               hfs_put_hl(fil->data_fork.lsize, cat->u.fil.LgLen);
-               hfs_put_hl(fil->data_fork.psize << HFS_SECTOR_SIZE_BITS,
-                                                       cat->u.fil.PyLen);
-               hfs_put_hl(fil->rsrc_fork.lsize, cat->u.fil.RLgLen);
-               hfs_put_hl(fil->rsrc_fork.psize << HFS_SECTOR_SIZE_BITS,
-                                                       cat->u.fil.RPyLen);
-               hfs_put_nl(entry->create_date,     cat->u.fil.CrDat);
-               hfs_put_nl(entry->modify_date,     cat->u.fil.MdDat);
-               hfs_put_nl(entry->backup_date,     cat->u.fil.BkDat);
-               memcpy(&cat->u.fil.FndrInfo, &entry->info.file.fxinfo, 16);
-               hfs_put_hs((fil->clumpablks * entry->mdb->alloc_blksz)
-                               << HFS_SECTOR_SIZE_BITS, cat->u.fil.ClpSize);
-               hfs_extent_out(&fil->data_fork, cat->u.fil.ExtRec);
-               hfs_extent_out(&fil->rsrc_fork, cat->u.fil.RExtRec);
+       memset(rec, 0, sizeof(*rec));
+       if (S_ISDIR(inode->i_mode)) {
+               rec->type = HFS_CDR_DIR;
+               rec->dir.DirID = cpu_to_be32(cnid);
+               rec->dir.CrDat = mtime;
+               rec->dir.MdDat = mtime;
+               rec->dir.BkDat = 0;
+               rec->dir.UsrInfo.frView = cpu_to_be16(0xff);
+               return sizeof(struct hfs_cat_dir);
        } else {
-               hfs_warn("__write_entry: invalid entry\n");
-       }
-}
-
-/*
- * write_entry()
- *
- * Write a modified entry back to the catalog B-tree. this gets called
- * with the entry locked.
- */
-static void write_entry(struct hfs_cat_entry * entry)
-{
-       struct hfs_brec brec;
-       int error;
-
-       if (!(entry->state & HFS_DELETED)) {
-               error = hfs_bfind(&brec, entry->mdb->cat_tree,
-                                 HFS_BKEY(&entry->key), HFS_BFIND_WRITE);
-               if (!error) {
-                       if ((entry->state & HFS_KEYDIRTY)) {
-                               /* key may have changed case due to a rename */
-                               entry->state &= ~HFS_KEYDIRTY;
-                               if (brec.key->KeyLen != entry->key.KeyLen) {
-                                       hfs_warn("hfs_write_entry: key length "
-                                                "changed!\n");
-                                       error = 1;
-                               } else {
-                                       memcpy(brec.key, &entry->key,
-                                              entry->key.KeyLen);
-                               }
-                       } else if (entry->cnid != brec_to_id(&brec)) {
-                               hfs_warn("hfs_write_entry: CNID "
-                                        "changed unexpectedly!\n");
-                               error = 1;
-                       }
-                       if (!error) {
-                               __write_entry(entry, brec.data);
-                       }
-                       hfs_brec_relse(&brec, NULL);
-               }
-               if (error) {
-                       hfs_warn("hfs_write_entry: unable to write "
-                                "entry %08x\n", entry->cnid);
-               }
-       }
-}
-
-
-/* this gets called with the spinlock held. */
-static struct hfs_cat_entry *find_entry(struct hfs_mdb *mdb,
-                                       const struct hfs_cat_key *key)
-{
-       struct list_head *tmp, *head = hash(mdb, key);
-       struct hfs_cat_entry * entry;
-
-       tmp = head;
-       for (;;) {
-               tmp = tmp->next;
-               entry = NULL;
-               if (tmp == head)
-                       break;
-               entry = list_entry(tmp, struct hfs_cat_entry, hash);
-               if (entry->mdb != mdb)
-                       continue;
-               if (hfs_cat_compare(&entry->key, key)) {
-                       continue;
-               }
-               entry->count++;
-               break;
-       }
-
-       return entry;
-}
-
-
-/* be careful. this gets called with the spinlock held. */
-static struct hfs_cat_entry *get_new_entry(struct hfs_mdb *mdb,
-                                          const struct hfs_cat_key *key,
-                                          const int read)
-{
-       struct hfs_cat_entry *entry;
-       struct list_head *head = hash(mdb, key);
-       struct list_head *tmp;
-
-add_new_entry:
-       tmp = entry_unused.next;
-       if ((tmp != &entry_unused) ) {
-               list_del(tmp);
-               entries_stat.nr_free_entries--;
-               entry = list_entry(tmp, struct hfs_cat_entry, list);
-               list_add(&entry->list, &entry_in_use);
-               list_add(&entry->hash, head);
-               entry->mdb = mdb;
-               entry->count = 1;
-               memcpy(&entry->key, key, sizeof(*key));
-               entry->state = HFS_LOCK;
-               spin_unlock(&entry_lock);
-
-               if (read) {
-                  struct hfs_brec brec;
-
-                  if (hfs_bfind(&brec, mdb->cat_tree,
-                                HFS_BKEY(key), HFS_BFIND_READ_EQ)) {
-                       /* uh oh. we failed to read the record.
-                        * the entry doesn't actually exist. */
-                       goto read_fail;
-                  }
-
-                  read_entry(entry, &brec);
-                  
-                  /* error */
-                  if (!entry->cnid) {
-                       goto read_fail;
-                  }
-
-                  /* we don't have to acquire a spinlock here or
-                   * below for the unlocking bits as we're the first
-                   * user of this entry. */
-                  entry->state &= ~HFS_LOCK;
-                  hfs_wake_up(&entry->wait);
-               }
-
-               return entry;
+               /* init some fields for the file record */
+               rec->type = HFS_CDR_FIL;
+               rec->file.Flags = HFS_FIL_USED | HFS_FIL_THD;
+               if (!(inode->i_mode & S_IWUSR))
+                       rec->file.Flags |= HFS_FIL_LOCK;
+               rec->file.FlNum = cpu_to_be32(cnid);
+               rec->file.CrDat = mtime;
+               rec->file.MdDat = mtime;
+               rec->file.BkDat = 0;
+               rec->file.UsrWds.fdType = HFS_SB(inode->i_sb)->s_type;
+               rec->file.UsrWds.fdCreator = HFS_SB(inode->i_sb)->s_creator;
+               return sizeof(struct hfs_cat_file);
        }
-
-
-       /* try to allocate more entries. grow_entries() doesn't release
-        * the spinlock. */
-       if (grow_entries())
-               goto add_new_entry;
-
-       spin_unlock(&entry_lock);
-       return NULL;
-
-read_fail: 
-       /* short-cut hfs_cat_put by doing everything here. */
-       spin_lock(&entry_lock);
-       list_del(&entry->hash);
-       list_del(&entry->list);
-       init_entry(entry);
-       list_add(&entry->list, &entry_unused);
-       entries_stat.nr_free_entries++;
-       spin_unlock(&entry_lock);
-       return NULL;
 }
 
-/*
- * get_entry()
- *
- * Try to return an entry for the indicated file or directory.
- * If ('read' == 0) then no attempt will be made to read it from disk
- * and a locked, but uninitialized, entry is returned.
- */
-static struct hfs_cat_entry *get_entry(struct hfs_mdb *mdb,
-                                      const struct hfs_cat_key *key,
-                                      const int read)
-{
-       struct hfs_cat_entry * entry;
-
-#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
-       hfs_warn("hfs_get_entry: mdb=%p key=%s read=%d\n",
-                mdb, key->CName.Name, read);
-#endif
-
-       spin_lock(&entry_lock);
-       entry = find_entry(mdb, key);
-       if (!entry) {
-               return get_new_entry(mdb, key, read);
-       }
-       spin_unlock(&entry_lock);
-       wait_on_entry(entry);
-       return entry;
-}
-
-/* 
- * new_cnid()
- *
- * Allocate a CNID to use for a new file or directory.
- */
-static inline hfs_u32 new_cnid(struct hfs_mdb *mdb)
+static int hfs_cat_build_thread(hfs_cat_rec *rec, int type,
+                               u32 parentid, struct qstr *name)
 {
-       /* If the create succeeds then the mdb will get dirtied */
-       return htonl(mdb->next_id++);
-}
-
-/*
- * update_dir()
- *
- * Update counts, times and dirt on a changed directory
- */
-static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir,
-                      int is_dir, int count)
-{
-       /* update counts */
-       if (is_dir) {
-               mdb->dir_count += count;
-               dir->u.dir.dirs += count;
-               if (dir->cnid == htonl(HFS_ROOT_CNID)) {
-                       mdb->root_dirs += count;
-               }
-       } else {
-               mdb->file_count += count;
-               dir->u.dir.files += count;
-               if (dir->cnid == htonl(HFS_ROOT_CNID)) {
-                       mdb->root_files += count;
-               }
-       }
-       
-       /* update times and dirt */
-       dir->modify_date = hfs_time();
-       hfs_cat_mark_dirty(dir);
+       rec->type = type;
+       memset(rec->thread.reserved, 0, sizeof(rec->thread.reserved));
+       rec->thread.ParID = cpu_to_be32(parentid);
+       hfs_triv2mac(&rec->thread.CName, name);
+       return sizeof(struct hfs_cat_thread);
 }
 
 /*
@@ -644,301 +78,53 @@ static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir,
  * Add a new file or directory to the catalog B-tree and
  * return a (struct hfs_cat_entry) for it in '*result'.
  */
-static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
-                       const struct hfs_cat_rec *record, int is_dir,
-                       hfs_u32 cnid, struct hfs_cat_entry **result)
+int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode)
 {
-       struct hfs_mdb *mdb = parent->mdb;
-       struct hfs_cat_entry *entry;
-       struct hfs_cat_key thd_key;
-       struct hfs_cat_rec thd_rec;
-       int error, has_thread;
-
-       if (result) {
-               *result = NULL;
-       }
-
-       /* keep readers from getting confused by changing dir size */
-       down_write(&parent->u.dir.sem);
-
-       /* create a locked entry in the cache */
-       entry = get_entry(mdb, key, 0);
-       if (!entry) {
-               /* The entry exists but can't be read */
-               error = -EIO;
-               goto done;
-       }
-
-       if (entry->cnid) {
-               /* The (unlocked) entry exists in the cache */
-               error = -EEXIST;
-               goto bail2;
-       }
+       struct hfs_find_data fd;
+       struct super_block *sb;
+       union hfs_cat_rec entry;
+       int entry_size;
+       int err;
 
-       /* limit directory valence to signed 16-bit integer */
-        if ((parent->u.dir.dirs + parent->u.dir.files) >= HFS_MAX_VALENCE) {
-               error = -ENOSPC;
-               goto bail1;
-       }
-
-       has_thread = is_dir || (record->u.fil.Flags & HFS_FIL_THD);
+       dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink);
+       if (dir->i_size >= HFS_MAX_VALENCE)
+               return -ENOSPC;
 
-       if (has_thread) {
-               /* init some fields for the thread record */
-               memset(&thd_rec, 0, sizeof(thd_rec));
-               thd_rec.cdrType = is_dir ? HFS_CDR_THD : HFS_CDR_FTH;
-               memcpy(&thd_rec.u.thd.ParID, &key->ParID,
-                      sizeof(hfs_u32) + sizeof(struct hfs_name));
+       sb = dir->i_sb;
+       hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
 
-               /* insert the thread record */
-               hfs_cat_build_key(cnid, NULL, &thd_key);
-               error = hfs_binsert(mdb->cat_tree, HFS_BKEY(&thd_key),
-                                   &thd_rec, 2 + sizeof(THD_REC));
-               if (error) {
-                       goto bail1;
-               }
+       hfs_cat_build_key(fd.search_key, cnid, NULL);
+       entry_size = hfs_cat_build_thread(&entry, S_ISDIR(inode->i_mode) ?
+                       HFS_CDR_THD : HFS_CDR_FTH,
+                       dir->i_ino, str);
+       err = hfs_brec_find(&fd);
+       if (err != -ENOENT) {
+               if (!err)
+                       err = -EEXIST;
+               goto out;
        }
+       err = hfs_brec_insert(&fd, &entry, entry_size);
+       if (err)
+               goto out;
 
-       /* insert the record */
-       error = hfs_binsert(mdb->cat_tree, HFS_BKEY(key), record,
-                               is_dir ?  2 + sizeof(DIR_REC) :
-                                         2 + sizeof(FIL_REC));
-       if (error) {
-               if (has_thread && (error != -EIO)) {
-                       /* at least TRY to remove the thread record */
-                       (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&thd_key));
-               }
-               goto bail1;
+       hfs_cat_build_key(fd.search_key, dir->i_ino, str);
+       entry_size = hfs_cat_build_record(&entry, cnid, inode);
+       err = hfs_brec_find(&fd);
+       if (err != -ENOENT) {
+               /* panic? */
+               if (!err)
+                       err = -EEXIST;
+               goto out;
        }
-
-       /* update the parent directory */
-       update_dir(mdb, parent, is_dir, 1);
-
-       /* complete the cache entry and return success */
-       __read_entry(entry, record);
-       unlock_entry(entry);
-
-       if (result) {
-               *result = entry;
-       } else {
-               hfs_cat_put(entry);
+       err = hfs_brec_insert(&fd, &entry, entry_size);
+       if (!err) {
+               dir->i_size++;
+               mark_inode_dirty(dir);
        }
-       goto done;
+out:
+       hfs_find_exit(&fd);
 
-bail1:
-       /* entry really didn't exist, so we don't need to really delete it.
-        * we do need to remove it from the hash, though. */
-       entry->state |= HFS_DELETED;
-       remove_hash(entry);
-       unlock_entry(entry);
-bail2:
-       hfs_cat_put(entry);
-done:
-       up_write(&parent->u.dir.sem);
-       return error;
-}
-
-/*================ Global functions ================*/
-
-/* 
- * hfs_cat_put()
- *
- * Release an entry we aren't using anymore.
- *
- * nothing in hfs_cat_put goes to sleep now except on the initial entry.  
- */
-void hfs_cat_put(struct hfs_cat_entry * entry)
-{
-       if (entry) {
-               wait_on_entry(entry);
-
-               /* just in case. this should never happen. */
-               if (!entry->count) { 
-                 hfs_warn("hfs_cat_put: trying to free free entry: %p\n",
-                          entry);
-                 return;
-               }
-
-#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
-               hfs_warn("hfs_cat_put: %p(%u) type=%d state=%lu\n", 
-                        entry, entry->count, entry->type, entry->state);
-#endif
-               spin_lock(&entry_lock);
-               if (!--entry->count) {
-                       if ((entry->state & HFS_DELETED))
-                               goto entry_deleted;
-
-                       if ((entry->type == HFS_CDR_FIL)) {
-                               /* clear out any cached extents */
-                               if (entry->u.file.data_fork.first.next) {
-                                 hfs_extent_free(&entry->u.file.data_fork);
-                               }
-                               if (entry->u.file.rsrc_fork.first.next) {
-                                 hfs_extent_free(&entry->u.file.rsrc_fork);
-                               }
-                       }
-
-                       /* if we put a dirty entry, write it out. */
-                       if ((entry->state & HFS_DIRTY)) {
-                               entry->state ^= HFS_DIRTY | HFS_LOCK;
-                               write_entry(entry);
-                               entry->state &= ~HFS_LOCK;
-                       }
-
-                       list_del(&entry->hash);
-entry_deleted:                 /* deleted entries have already been removed
-                        * from the hash list. */
-                       list_del(&entry->list);
-                       if (entries_stat.nr_free_entries > CCACHE_MAX) {
-                               HFS_DELETE(entry);
-                               entries_stat.nr_entries--;
-                       } else {
-                               init_entry(entry);
-                               list_add(&entry->list, &entry_unused);
-                               entries_stat.nr_free_entries++;
-                       }
-               }
-               spin_unlock(&entry_lock);
-       }
-}
-
-/* 
- * hfs_cat_get()
- *
- * Wrapper for get_entry() which always calls with ('read'==1).
- * Used for access to get_entry() from outside this file.
- */
-struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *mdb,
-                                 const struct hfs_cat_key *key)
-{
-       return get_entry(mdb, key, 1);
-}
-
-/* invalidate all entries for a device */
-static void invalidate_list(struct list_head *head, struct hfs_mdb *mdb,
-                           struct list_head *dispose)
-{
-        struct list_head *next;
-
-       next = head->next;
-       for (;;) {
-               struct list_head *tmp = next;
-               struct hfs_cat_entry * entry;
-               
-               next = next->next;
-               if (tmp == head)
-                       break;
-               entry = list_entry(tmp, struct hfs_cat_entry, list);
-               if (entry->mdb != mdb) {
-                       continue;
-               }
-
-               if (!entry->count) {
-                       list_del_init(&entry->hash);
-                       list_del(&entry->list);
-                       list_add(&entry->list, dispose);
-                       continue;
-               }
-               
-               hfs_warn("hfs_fs: entry %p(%u) busy on removed device %s.\n",
-                        entry, entry->count, 
-                        hfs_mdb_name(entry->mdb->sys_mdb));
-       }
-}
-
-/* delete entries from a list */
-static void delete_list(struct list_head *head) 
-{
-       struct list_head *next = head->next;
-       struct hfs_cat_entry *entry;
-       
-       for (;;) {
-               struct list_head * tmp = next;
-
-               next = next->next;
-               if (tmp == head) {
-                       break;
-               }
-               entry = list_entry(tmp, struct hfs_cat_entry, list);
-               HFS_DELETE(entry);
-       }
-}
-
-/* 
- * hfs_cat_invalidate()
- *
- * Called by hfs_mdb_put() to remove all the entries
- * in the cache that are associated with a given MDB.
- */
-void hfs_cat_invalidate(struct hfs_mdb *mdb)
-{
-       LIST_HEAD(throw_away);
-
-       spin_lock(&entry_lock);
-       invalidate_list(&entry_in_use, mdb, &throw_away);
-       invalidate_list(&mdb->entry_dirty, mdb, &throw_away);
-       spin_unlock(&entry_lock);
-
-       delete_list(&throw_away);
-#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
-       hfs_warn("hfs_cat_invalidate: free=%d total=%d\n",
-                entries_stat.nr_free_entries,
-                entries_stat.nr_entries);
-#endif
-}
-
-/*
- * hfs_cat_commit()
- *
- * Called by hfs_mdb_commit() to write dirty entries to the disk buffers.
- */
-void hfs_cat_commit(struct hfs_mdb *mdb)
-{
-        struct list_head *tmp, *head = &mdb->entry_dirty;
-       struct hfs_cat_entry *entry;
-
-       spin_lock(&entry_lock);
-       while ((tmp = head->prev) != head) {
-               entry = list_entry(tmp, struct hfs_cat_entry, list);
-                 
-               if ((entry->state & HFS_LOCK)) {
-                       spin_unlock(&entry_lock);
-                       wait_on_entry(entry);
-                       spin_lock(&entry_lock);
-               } else {
-                      struct list_head *insert = &entry_in_use;
-
-                      if (!entry->count)
-                               insert = entry_in_use.prev;
-
-                      /* add to in_use list */
-                      list_del(&entry->list);
-                      list_add(&entry->list, insert);
-
-                      /* reset DIRTY, set LOCK */
-                      entry->state ^= HFS_DIRTY | HFS_LOCK;
-                      spin_unlock(&entry_lock);
-                      write_entry(entry);
-                      spin_lock(&entry_lock);
-                      entry->state &= ~HFS_LOCK;
-                      hfs_wake_up(&entry->wait);
-               }
-       }
-       spin_unlock(&entry_lock);
-}
-
-/*
- * hfs_cat_free()
- *
- * Releases all the memory allocated in grow_entries().
- * Must call hfs_cat_invalidate() on all MDBs before calling this.
- * This only gets rid of the unused pool of entries. all the other
- * entry references should have either been freed by cat_invalidate
- * or moved onto the unused list.
- */
-void hfs_cat_free(void)
-{
-       delete_list(&entry_unused);
+       return err;
 }
 
 /*
@@ -962,223 +148,43 @@ void hfs_cat_free(void)
  * Postconditions:
  *   This function has no side-effects
  */
-int hfs_cat_compare(const struct hfs_cat_key *key1,
-                   const struct hfs_cat_key *key2)
+int hfs_cat_keycmp(const btree_key *key1, const btree_key *key2)
 {
-       unsigned int parents;
        int retval;
 
-       parents = hfs_get_hl(key1->ParID) - hfs_get_hl(key2->ParID);
-       if (parents != 0) {
-               retval = (int)parents;
-       } else {
-               retval = hfs_strcmp(key1->CName.Name, key1->CName.Len,
-                                   key2->CName.Name, key2->CName.Len);
-       }
-       return retval;
-}
-
-/*
- * hfs_cat_build_key()
- *
- * Given the ID of the parent and the name build a search key.
- */
-void hfs_cat_build_key(hfs_u32 parent, const struct hfs_name *cname,
-                      struct hfs_cat_key *key)
-{
-       hfs_put_nl(parent, key->ParID);
-
-       if (cname) {
-               key->KeyLen = 6 + cname->Len;
-               memcpy(&key->CName, cname, sizeof(*cname));
-       } else {
-               key->KeyLen = 6;
-               memset(&key->CName, 0, sizeof(*cname));
-       }
-}
-
-/*
- * hfs_cat_open()
- *
- * Given a directory on an HFS filesystem get its thread and
- * lock the directory against insertions and deletions.
- * Return 0 on success or an error code on failure.
- */
-int hfs_cat_open(struct hfs_cat_entry *dir, struct hfs_brec *brec)
-{
-       struct hfs_cat_key key;
-       int error;
-
-       if (dir->type != HFS_CDR_DIR)
-               return -EINVAL;
-       
-       /* Block writers */
-       down_read(&dir->u.dir.sem);
-
-       /* Find the directory */
-       hfs_cat_build_key(dir->cnid, NULL, &key);
-       error = hfs_bfind(brec, dir->mdb->cat_tree,
-                         HFS_BKEY(&key), HFS_BFIND_READ_EQ);
-
-       if (error)
-               up_read(&dir->u.dir.sem);
-
-       return error;
-}
-
-/*
- * hfs_cat_next()
- *
- * Given a catalog brec structure, replace it with the count'th next brec
- * in the same directory.
- * Return an error code if there is a problem, 0 if OK.
- * Note that an error code of -ENOENT means there are no more entries
- * in this directory.
- * The directory is "closed" on an error.
- */
-int hfs_cat_next(struct hfs_cat_entry *dir, struct hfs_brec *brec,
-                hfs_u16 count, hfs_u32 *cnid, hfs_u8 *type)
-{
-       int error;
-
-       if (!dir || !brec) {
-               return -EINVAL;
-       }
-
-       /* Get the count'th next catalog tree entry */
-       error = hfs_bsucc(brec, count);
-       if (!error) {
-               struct hfs_cat_key *key = (struct hfs_cat_key *)brec->key;
-               if (hfs_get_nl(key->ParID) != dir->cnid) {
-                       hfs_brec_relse(brec, NULL);
-                       error = -ENOENT;
-               }
-       }
-       if (!error) {
-               *type = ((struct hfs_cat_rec *)brec->data)->cdrType;
-               *cnid = brec_to_id(brec);
-       } else {
-               up_read(&dir->u.dir.sem);
-       }
-       return error;
-}
+       retval = be32_to_cpu(key1->cat.ParID) - be32_to_cpu(key2->cat.ParID);
+       if (!retval)
+               retval = hfs_strcmp(key1->cat.CName.name, key1->cat.CName.len,
+                                   key2->cat.CName.name, key2->cat.CName.len);
 
-/*
- * hfs_cat_close()
- *
- * Given a catalog brec structure, replace it with the count'th next brec
- * in the same directory.
- * Return an error code if there is a problem, 0 if OK.
- * Note that an error code of -ENOENT means there are no more entries
- * in this directory.
- */
-void hfs_cat_close(struct hfs_cat_entry *dir, struct hfs_brec *brec)
-{
-       if (dir && brec) {
-               hfs_brec_relse(brec, NULL);
-               up_read(&dir->u.dir.sem);
-       }
+       return retval;
 }
 
-/*
- * hfs_cat_parent()
- *
- * Given a catalog entry, return the entry for its parent.
- * Uses catalog key for the entry to get its parent's ID
- * and then uses the parent's thread record to locate the
- * parent's actual catalog entry.
- */
-struct hfs_cat_entry *hfs_cat_parent(struct hfs_cat_entry *entry)
+/* Try to get a catalog entry for given catalog id */
+// move to read_super???
+int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
+                     struct hfs_find_data *fd)
 {
-       struct hfs_cat_entry *retval = NULL;
-       struct hfs_mdb *mdb = entry->mdb;
-       struct hfs_brec brec;
-       struct hfs_cat_key key;
-       int error;
-
-       lock_entry(entry);
-       if (!(entry->state & HFS_DELETED)) {
-               hfs_cat_build_key(hfs_get_nl(entry->key.ParID), NULL, &key);
-               error = hfs_bfind(&brec, mdb->cat_tree,
-                                 HFS_BKEY(&key), HFS_BFIND_READ_EQ);
-               if (!error) {
-                       /* convert thread record to key */
-                       struct hfs_cat_rec *rec = brec.data;
-                       key.KeyLen = 6 + rec->u.thd.CName.Len;
-                       memcpy(&key.ParID, &rec->u.thd.ParID,
-                                      sizeof(hfs_u32) + sizeof(struct hfs_name));
+       hfs_cat_rec rec;
+       int res, len, type;
 
-                       hfs_brec_relse(&brec, NULL);
+       hfs_cat_build_key(fd->search_key, cnid, NULL);
+       res = hfs_brec_read(fd, &rec, sizeof(rec));
+       if (res)
+               return res;
 
-                       retval = hfs_cat_get(mdb, &key);
-               }
+       type = rec.type;
+       if (type != HFS_CDR_THD && type != HFS_CDR_FTH) {
+               printk("HFS-fs: Found bad thread record in catalog\n");
+               return -EIO;
        }
-       unlock_entry(entry);
-       return retval;
-}
-       
-/*
- * hfs_cat_create()
- *
- * Create a new file with the indicated name in the indicated directory.
- * The file will have the indicated flags, type and creator.
- * If successful an (struct hfs_cat_entry) is returned in '*result'.
- */
-int hfs_cat_create(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
-                  hfs_u8 flags, hfs_u32 type, hfs_u32 creator,
-                  struct hfs_cat_entry **result)
-{
-       struct hfs_cat_rec record;
-       hfs_u32 id = new_cnid(parent->mdb);
-       hfs_u32 mtime = hfs_time();
-
-#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
-       hfs_warn("hfs_cat_create: %p/%s flags=%d res=%p\n",
-                parent, key->CName.Name, flags, result);
-#endif
-       /* init some fields for the file record */
-       memset(&record, 0, sizeof(record));
-       record.cdrType = HFS_CDR_FIL;
-       record.u.fil.Flags = flags | HFS_FIL_USED;
-       hfs_put_nl(id,      record.u.fil.FlNum);
-       hfs_put_nl(mtime,   record.u.fil.CrDat);
-       hfs_put_nl(mtime,   record.u.fil.MdDat);
-       hfs_put_nl(0,       record.u.fil.BkDat);
-       hfs_put_nl(type,    record.u.fil.UsrWds.fdType);
-       hfs_put_nl(creator, record.u.fil.UsrWds.fdCreator);
 
-       return create_entry(parent, key, &record, 0, id, result);
+       fd->search_key->cat.ParID = rec.thread.ParID;
+       len = fd->search_key->cat.CName.len = rec.thread.CName.len;
+       memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
+       return hfs_brec_find(fd);
 }
 
-/*
- * hfs_cat_mkdir()
- *
- * Create a new directory with the indicated name in the indicated directory.
- * If successful an (struct hfs_cat_entry) is returned in '*result'.
- */
-int hfs_cat_mkdir(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
-                 struct hfs_cat_entry **result)
-{
-       struct hfs_cat_rec record;
-       hfs_u32 id = new_cnid(parent->mdb);
-       hfs_u32 mtime = hfs_time();
-
-#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
-       hfs_warn("hfs_cat_mkdir: %p/%s res=%p\n", parent, key->CName.Name,
-                result);
-#endif
-
-       /* init some fields for the directory record */
-       memset(&record, 0, sizeof(record));
-       record.cdrType = HFS_CDR_DIR;
-       hfs_put_nl(id,     record.u.dir.DirID);
-       hfs_put_nl(mtime, record.u.dir.CrDat);
-       hfs_put_nl(mtime, record.u.dir.MdDat);
-       hfs_put_nl(0,     record.u.dir.BkDat);
-       hfs_put_hs(0xff,  record.u.dir.UsrInfo.frView);
-
-       return create_entry(parent, key, &record, 1, id, result);
-}
 
 /*
  * hfs_cat_delete()
@@ -1186,72 +192,60 @@ int hfs_cat_mkdir(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
  * Delete the indicated file or directory.
  * The associated thread is also removed unless ('with_thread'==0).
  */
-int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,
-                  int with_thread)
-{
-       struct hfs_cat_key key;
-       struct hfs_mdb *mdb = parent->mdb;
-       int is_dir, error = 0;
-
-#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
-       hfs_warn("hfs_cat_delete: %p/%p type=%d state=%lu, thread=%d\n",
-                parent, entry, entry->type, entry->state, with_thread);
+int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
+{
+       struct super_block *sb;
+       struct hfs_find_data fd;
+       struct list_head *pos;
+       int res, type;
+
+       dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
+       sb = dir->i_sb;
+       hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+
+       hfs_cat_build_key(fd.search_key, dir->i_ino, str);
+       res = hfs_brec_find(&fd);
+       if (res)
+               goto out;
+
+       type = hfs_bnode_read_u8(fd.bnode, fd.entryoffset);
+       if (type == HFS_CDR_FIL) {
+               struct hfs_cat_file file;
+               hfs_bnode_read(fd.bnode, &file, fd.entryoffset, sizeof(file));
+               if (be32_to_cpu(file.FlNum) == cnid) {
+#if 0
+                       hfs_free_fork(sb, &file, HFS_FK_DATA);
 #endif
-       if (parent->mdb != entry->mdb) {
-               return -EINVAL;
-       }
-
-       if (entry->type == HFS_CDR_FIL) {
-               with_thread = (entry->u.file.flags&HFS_FIL_THD) && with_thread;
-               is_dir = 0;
-       } else {
-               is_dir = 1;
-       }
-
-       /* keep readers from getting confused by changing dir size */
-       down_write(&parent->u.dir.sem);
-
-       /* don't delete a busy directory */
-       if (entry->type == HFS_CDR_DIR) {
-               down_read(&entry->u.dir.sem);
-
-               error = -ENOTEMPTY;
-               if (entry->u.dir.files || entry->u.dir.dirs) 
-                       goto hfs_delete_end;
+                       hfs_free_fork(sb, &file, HFS_FK_RSRC);
+               }
        }
 
-       /* try to delete the file or directory */
-       lock_entry(entry);
-       error = -ENOENT;
-       if ((entry->state & HFS_DELETED)) {
-               /* somebody beat us to it. */
-               goto hfs_delete_unlock;
-       }
-               
-       /* delete the catalog record */
-       if ((error = hfs_bdelete(mdb->cat_tree, HFS_BKEY(&entry->key)))) {
-               goto hfs_delete_unlock;
+       list_for_each(pos, &HFS_I(dir)->open_dir_list) {
+               struct hfs_readdir_data *rd =
+                       list_entry(pos, struct hfs_readdir_data, list);
+               if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
+                       rd->file->f_pos--;
        }
 
-       /* Mark the entry deleted and remove it from the cache */
-       delete_entry(entry);
+       res = hfs_brec_remove(&fd);
+       if (res)
+               goto out;
 
-       /* try to delete the thread entry if it exists */
-       if (with_thread) {
-               hfs_cat_build_key(entry->cnid, NULL, &key);
-               (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key));
+       hfs_cat_build_key(fd.search_key, cnid, NULL);
+       res = hfs_brec_find(&fd);
+       if (!res) {
+               res = hfs_brec_remove(&fd);
+               if (res)
+                       goto out;
        }
-       
-       update_dir(mdb, parent, is_dir, -1);
 
-hfs_delete_unlock:
-       unlock_entry(entry);
+       dir->i_size--;
+       mark_inode_dirty(dir);
+       res = 0;
+out:
+       hfs_find_exit(&fd);
 
-hfs_delete_end:
-       if (entry->type == HFS_CDR_DIR)
-               up_read(&entry->u.dir.sem);
-       up_write(&parent->u.dir.sem);
-       return error;
+       return res;
 }
 
 /*
@@ -1261,267 +255,82 @@ hfs_delete_end:
  * If the destination exists it is removed and a
  * (struct hfs_cat_entry) for it is returned in '*result'.
  */
-int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir,
-                struct hfs_cat_entry *entry, struct hfs_cat_key *new_key,
-                struct hfs_cat_entry **removed)
-{
-       struct hfs_cat_entry *dest;
-       struct hfs_mdb *mdb;
-       int error = 0;
-       int is_dir, has_thread;
-
-       if (removed) {
-               *removed = NULL;
-       }
-
-       /* sanity checks */
-       if (!old_dir || !new_dir) {
-               return -EINVAL;
-       }
-       mdb = old_dir->mdb;
-       if (mdb != new_dir->mdb) {
-               return -EXDEV;
-       }
-
-       /* precompute a few things */
-       if (entry->type == HFS_CDR_DIR) {
-               is_dir = 1;
-               has_thread = 1;
-       } else if (entry->type == HFS_CDR_FIL) {
-               is_dir = 0;
-               has_thread = entry->u.file.flags & HFS_FIL_THD;
-       } else {
-               return -EINVAL;
-       }
-
-       /* keep readers from getting confused by changing dir size */
-       down_write(&new_dir->u.dir.sem);
-       /* AV: smells like a deadlock */
-       if (old_dir != new_dir)
-               down_write(&old_dir->u.dir.sem);
-
-       /* Don't move a directory inside itself */
-       if (is_dir) {
-               struct hfs_cat_key thd_key;
-               struct hfs_brec brec;
-
-               hfs_u32 id = new_dir->cnid;
-               while (id != htonl(HFS_ROOT_CNID)) {
-                       if (id == entry->cnid) {
-                               error = -EINVAL;
-                       } else {
-                               hfs_cat_build_key(id, NULL, &thd_key);
-                               error = hfs_bfind(&brec, mdb->cat_tree,
-                                                 HFS_BKEY(&thd_key),
-                                                 HFS_BFIND_READ_EQ);
-                       }
-                       if (error) {
-                               goto done;
-                       } else {
-                               struct hfs_cat_rec *rec = brec.data;
-                               id = hfs_get_nl(rec->u.thd.ParID);
-                               hfs_brec_relse(&brec, NULL);
-                       }
-               }
-       }
-
-restart:
-       /* see if the destination exists, getting it if it does */
-       dest = hfs_cat_get(mdb, new_key);
-       if (!dest) {
-               /* destination doesn't exist, so create it */
-               struct hfs_cat_rec new_record;
-
-               /* create a locked entry in the cache */
-               dest = get_entry(mdb, new_key, 0);
-               if (!dest) {
-                       error = -EIO;
-                       goto done;
-               }
-               if (dest->cnid) {
-                       /* The (unlocked) entry exists in the cache */
-                       goto have_distinct;
-               }
-
-               /* limit directory valence to signed 16-bit integer */
-               if ((new_dir->u.dir.dirs + new_dir->u.dir.files) >=
-                                                       HFS_MAX_VALENCE) {
-                       error = -ENOSPC;
-                       goto bail3;
-               }
-
-               /* build the new record. make sure to zero out the
-                   record. */
-               memset(&new_record, 0, sizeof(new_record));
-               new_record.cdrType = entry->type;
-               __write_entry(entry, &new_record);
-
-               /* insert the new record */
-               error = hfs_binsert(mdb->cat_tree, HFS_BKEY(new_key),
-                                   &new_record, is_dir ? 2 + sizeof(DIR_REC) :
-                                   2 + sizeof(FIL_REC));
-               if (error == -EEXIST) {
-                       delete_entry(dest);
-                       unlock_entry(dest);
-                       hfs_cat_put(dest);
-                       goto restart;
-               } else if (error) {
-                       goto bail3;
-               }
-
-               /* update the destination directory */
-               update_dir(mdb, new_dir, is_dir, 1);
-       } else if (entry != dest) {
-have_distinct:
-               /* The destination exists and is not same as source */
-               lock_entry(dest);
-               if ((dest->state & HFS_DELETED)) {
-                       unlock_entry(dest);
-                       hfs_cat_put(dest);
-                       goto restart;
-               }
-               if (dest->type != entry->type) {
-                       /* can't move a file on top
-                          of a dir nor vice versa. */
-                       error = is_dir ? -ENOTDIR : -EISDIR;
-               } else if (is_dir && (dest->u.dir.dirs || dest->u.dir.files)) {
-                       /* directory to replace is not empty */
-                       error = -ENOTEMPTY;
-               }
-
-               if (error) {
-                       goto bail2;
-               }
-       } else {
-               /* The destination exists but is same as source */
-               --entry->count;
-               dest = NULL;
-       }
-
-       /* lock the entry */
-       lock_entry(entry);
-       if ((entry->state & HFS_DELETED)) {
-               error = -ENOENT;
-               goto bail1;
-       }
-
-       if (dest) {
-               /* remove the old entry */
-               error = hfs_bdelete(mdb->cat_tree, HFS_BKEY(&entry->key));
-
-               if (error) {
-                       /* We couldn't remove the entry for the
-                          original file, so nothing has changed. */
-                       goto bail1;
-               }
-               update_dir(mdb, old_dir, is_dir, -1);
-       }
-
-       /* update the thread of the dir/file we're moving */
-       if (has_thread) {
-               struct hfs_cat_key thd_key;
-               struct hfs_brec brec;
-
-               hfs_cat_build_key(entry->cnid, NULL, &thd_key);
-               error = hfs_bfind(&brec, mdb->cat_tree,
-                                 HFS_BKEY(&thd_key), HFS_BFIND_WRITE);
-               if (error == -ENOENT) {
-                       if (is_dir) {
-                               /* directory w/o a thread! */
-                               error = -EIO;
-                       } else {
-                               /* We were lied to! */
-                               entry->u.file.flags &= ~HFS_FIL_THD;
-                               hfs_cat_mark_dirty(entry);
-                       }
-               }
-               if (!error) {
-                       struct hfs_cat_rec *rec = brec.data;
-                       memcpy(&rec->u.thd.ParID, &new_key->ParID,
-                              sizeof(hfs_u32) + sizeof(struct hfs_name));
-                       hfs_brec_relse(&brec, NULL);
-               } else if (error == -ENOENT) {
-                       error = 0;
-               } else if (!dest) {
-                       /* Nothing was changed */
-                       unlock_entry(entry);
-                       goto done;
-               } else {
-                       /* Something went seriously wrong.
-                          The dir/file has been deleted. */
-                       /* XXX try some recovery? */
-                       delete_entry(entry);
-                       goto bail1;
-               }
-       }
-
-       /* TRY to remove the thread for the pre-existing entry */
-       if (dest && dest->cnid &&
-           (is_dir || (dest->u.file.flags & HFS_FIL_THD))) {
-               struct hfs_cat_key thd_key;
-
-               hfs_cat_build_key(dest->cnid, NULL, &thd_key);
-               (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&thd_key));
-       }
-
-       /* update directories */
-       new_dir->modify_date = hfs_time();
-       hfs_cat_mark_dirty(new_dir);
-
-       /* update key */
-       remove_hash(entry);
-       memcpy(&entry->key, new_key, sizeof(*new_key));
-       /* KEYDIRTY as case might differ */
-       entry->state |= HFS_KEYDIRTY;
-       insert_hash(entry);
-       hfs_cat_mark_dirty(entry);
-       unlock_entry(entry);
-
-       /* delete any pre-existing or place-holder entry */
-       if (dest) {
-               delete_entry(dest);
-               unlock_entry(dest);
-               if (removed && dest->cnid) {
-                       *removed = dest;
-               } else {
-                       hfs_cat_put(dest);
-               }
-       }
-       goto done;
-
-bail1:
-       unlock_entry(entry);
-bail2:
-       if (dest) {
-               if (!dest->cnid) {
-                       /* TRY to remove the new entry */
-                       (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(new_key));
-                       update_dir(mdb, new_dir, is_dir, -1);
-bail3:
-                       delete_entry(dest);
-               }
-               unlock_entry(dest);
-               hfs_cat_put(dest);
-       }
-done:
-       if (new_dir != old_dir)
-               up_write(&old_dir->u.dir.sem);
-       up_write(&new_dir->u.dir.sem);
-       return error;
-}
-
-/*
- * Initialize the hash tables
- */
-void hfs_cat_init(void)
-{
-       int i;
-       struct list_head *head = hash_table;
-
-        i = C_HASHSIZE;
-        do {
-                INIT_LIST_HEAD(head);
-                head++;
-                i--;
-        } while (i);
+int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
+                struct inode *dst_dir, struct qstr *dst_name)
+{
+       struct super_block *sb;
+       struct hfs_find_data src_fd, dst_fd;
+       union hfs_cat_rec entry;
+       int entry_size, type;
+       int err;
+
+       dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name,
+               dst_dir->i_ino, dst_name->name);
+       sb = src_dir->i_sb;
+       hfs_find_init(HFS_SB(sb)->cat_tree, &src_fd);
+       dst_fd = src_fd;
+
+       /* find the old dir entry and read the data */
+       hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
+       err = hfs_brec_find(&src_fd);
+       if (err)
+               goto out;
+
+       hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset,
+                           src_fd.entrylength);
+
+       /* create new dir entry with the data from the old entry */
+       hfs_cat_build_key(dst_fd.search_key, dst_dir->i_ino, dst_name);
+       err = hfs_brec_find(&dst_fd);
+       if (err != -ENOENT) {
+               if (!err)
+                       err = -EEXIST;
+               goto out;
+       }
+
+       err = hfs_brec_insert(&dst_fd, &entry, src_fd.entrylength);
+       if (err)
+               goto out;
+       dst_dir->i_size++;
+       mark_inode_dirty(dst_dir);
+
+       /* finally remove the old entry */
+       hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
+       err = hfs_brec_find(&src_fd);
+       if (err)
+               goto out;
+       err = hfs_brec_remove(&src_fd);
+       if (err)
+               goto out;
+       src_dir->i_size--;
+       mark_inode_dirty(src_dir);
+
+       type = entry.type;
+       if (type == HFS_CDR_FIL && !(entry.file.Flags & HFS_FIL_THD))
+               goto out;
+
+       /* remove old thread entry */
+       hfs_cat_build_key(src_fd.search_key, cnid, NULL);
+       err = hfs_brec_find(&src_fd);
+       if (err)
+               goto out;
+       err = hfs_brec_remove(&src_fd);
+       if (err)
+               goto out;
+
+       /* create new thread entry */
+       hfs_cat_build_key(dst_fd.search_key, cnid, NULL);
+       entry_size = hfs_cat_build_thread(&entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD,
+                                       dst_dir->i_ino, dst_name);
+       err = hfs_brec_find(&dst_fd);
+       if (err != -ENOENT) {
+               if (!err)
+                       err = -EEXIST;
+               goto out;
+       }
+       err = hfs_brec_insert(&dst_fd, &entry, entry_size);
+out:
+       hfs_bnode_put(dst_fd.bnode);
+       hfs_find_exit(&src_fd);
+       return err;
 }
index 40df8a2b116c7b1655dd3fddfda132699d65d920..6106ab6e34cd89a2e6f333750e075b7ef18991ac 100644 (file)
 /*
- * linux/fs/hfs/dir.c
+ *  linux/fs/hfs/dir.c
  *
  * Copyright (C) 1995-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * This file contains directory-related functions independent of which
  * scheme is being used to represent forks.
  *
  * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
  */
 
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
-#include <linux/smp_lock.h>
-
-/*================ File-local functions ================*/
+#include "hfs_fs.h"
+#include "btree.h"
 
 /*
- * build_key()
- *
- * Build a key for a file by the given name in the given directory.
- * If the name matches one of the reserved names returns 1 otherwise 0.
+ * hfs_lookup()
  */
-static int build_key(struct hfs_cat_key *key, struct inode *dir,
-                    const char *name, int len)
+struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
+                         struct nameidata *nd)
 {
-       struct hfs_name cname;
-       const struct hfs_name *reserved;
-
-       /* mangle the name */
-       hfs_nameout(dir, &cname, name, len);
-
-       /* check against reserved names */
-       reserved = HFS_SB(dir->i_sb)->s_reserved1;
-       while (reserved->Len) {
-               if (hfs_streq(reserved->Name, reserved->Len, 
-                             cname.Name, cname.Len)) {
-                       return 1;
-               }
-               ++reserved;
-       }
-
-       /* check against the names reserved only in the root directory */
-       if (HFS_I(dir)->entry->cnid == htonl(HFS_ROOT_CNID)) {
-               reserved = HFS_SB(dir->i_sb)->s_reserved2;
-               while (reserved->Len) {
-                       if (hfs_streq(reserved->Name, reserved->Len,
-                                     cname.Name, cname.Len)) {
-                               return 1;
-                       }
-                       ++reserved;
+       hfs_cat_rec rec;
+       struct hfs_find_data fd;
+       struct inode *inode = NULL;
+       int res;
+
+       dentry->d_op = &hfs_dentry_operations;
+
+       hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
+       hfs_cat_build_key(fd.search_key, dir->i_ino, &dentry->d_name);
+       res = hfs_brec_read(&fd, &rec, sizeof(rec));
+       if (res) {
+               hfs_find_exit(&fd);
+               if (res == -ENOENT) {
+                       /* No such entry */
+                       inode = NULL;
+                       goto done;
                }
+               return ERR_PTR(res);
        }
-
-       /* build the key */
-       hfs_cat_build_key(HFS_I(dir)->entry->cnid, &cname, key);
-
-       return 0;
+       inode = hfs_iget(dir->i_sb, &fd.search_key->cat, &rec);
+       hfs_find_exit(&fd);
+       if (!inode)
+               return ERR_PTR(-EACCES);
+done:
+       d_add(dentry, inode);
+       return NULL;
 }
 
 /*
- * update_dirs_plus()
- *
- * Update the fields 'i_size', 'i_nlink', 'i_ctime' and 'i_mtime'
- * of the inodes associated with a directory that has
- * had a file ('is_dir'==0) or directory ('is_dir'!=0) added to it.
+ * hfs_readdir
  */
-static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir)
+int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
-       int i;
-
-       for (i = 0; i < 4; ++i) {
-               struct dentry *de = dir->sys_entry[i];
-               if (de) {
-                       struct inode *tmp = de->d_inode;
-                       if (S_ISDIR(tmp->i_mode)) {
-                               if (is_dir &&
-                                   (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {
-                                       /* In "normal" directory only */
-                                       ++(tmp->i_nlink);
-                               }
-                               tmp->i_size += HFS_I(tmp)->dir_size;
-                       }
-                       tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
-                       mark_inode_dirty(tmp);
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
+       int len, err;
+       char strbuf[HFS_NAMELEN + 1];
+       union hfs_cat_rec entry;
+       struct hfs_find_data fd;
+       struct hfs_readdir_data *rd;
+       u16 type;
+
+       if (filp->f_pos >= inode->i_size)
+               return 0;
+
+       hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+       hfs_cat_build_key(fd.search_key, inode->i_ino, NULL);
+       err = hfs_brec_find(&fd);
+       if (err)
+               goto out;
+
+       switch ((u32)filp->f_pos) {
+       case 0:
+               /* This is completely artificial... */
+               if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR))
+                       goto out;
+               filp->f_pos++;
+               /* fall through */
+       case 1:
+               hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
+               if (entry.type != HFS_CDR_THD) {
+                       printk("HFS: bad catalog folder thread\n");
+                       err = -EIO;
+                       goto out;
                }
+               //if (fd.entrylength < HFS_MIN_THREAD_SZ) {
+               //      printk("HFS: truncated catalog thread\n");
+               //      err = -EIO;
+               //      goto out;
+               //}
+               if (filldir(dirent, "..", 2, 1,
+                           be32_to_cpu(entry.thread.ParID), DT_DIR))
+                       goto out;
+               filp->f_pos++;
+               /* fall through */
+       default:
+               if (filp->f_pos >= inode->i_size)
+                       goto out;
+               err = hfs_brec_goto(&fd, filp->f_pos - 1);
+               if (err)
+                       goto out;
        }
-}
-
-/*
- * update_dirs_minus()
- *
- * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
- * of the inodes associated with a directory that has
- * had a file ('is_dir'==0) or directory ('is_dir'!=0) removed.
- */
-static inline void update_dirs_minus(struct hfs_cat_entry *dir, int is_dir)
-{
-       int i;
 
-       for (i = 0; i < 4; ++i) {
-               struct dentry *de = dir->sys_entry[i];
-               if (de) {
-                       struct inode *tmp = de->d_inode;
-                       if (S_ISDIR(tmp->i_mode)) {
-                               if (is_dir &&
-                                   (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {
-                                       /* In "normal" directory only */
-                                       --(tmp->i_nlink);
-                               }
-                               tmp->i_size -= HFS_I(tmp)->dir_size;
+       for (;;) {
+               if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) {
+                       printk("HFS: walked past end of dir\n");
+                       err = -EIO;
+                       goto out;
+               }
+               hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
+               type = entry.type;
+               len = hfs_mac2triv(strbuf, &fd.key->cat.CName);
+               if (type == HFS_CDR_DIR) {
+                       if (fd.entrylength < sizeof(struct hfs_cat_dir)) {
+                               printk("HFS: small dir entry\n");
+                               err = -EIO;
+                               goto out;
                        }
-                       tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
-                       mark_inode_dirty(tmp);
+                       if (filldir(dirent, strbuf, len, filp->f_pos,
+                                   be32_to_cpu(entry.dir.DirID), DT_DIR))
+                               break;
+               } else if (type == HFS_CDR_FIL) {
+                       if (fd.entrylength < sizeof(struct hfs_cat_file)) {
+                               printk("HFS: small file entry\n");
+                               err = -EIO;
+                               goto out;
+                       }
+                       if (filldir(dirent, strbuf, len, filp->f_pos,
+                                   be32_to_cpu(entry.file.FlNum), DT_REG))
+                               break;
+               } else {
+                       printk("HFS: bad catalog entry type %d\n", type);
+                       err = -EIO;
+                       goto out;
                }
+               filp->f_pos++;
+               if (filp->f_pos >= inode->i_size)
+                       goto out;
+               err = hfs_brec_goto(&fd, 1);
+               if (err)
+                       goto out;
        }
+       rd = filp->private_data;
+       if (!rd) {
+               rd = kmalloc(sizeof(struct hfs_readdir_data), GFP_KERNEL);
+               if (!rd) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+               filp->private_data = rd;
+               rd->file = filp;
+               list_add(&rd->list, &HFS_I(inode)->open_dir_list);
+       }
+       memcpy(&rd->key, &fd.key, sizeof(struct hfs_cat_key));
+out:
+       hfs_find_exit(&fd);
+       return err;
 }
 
-/*
- * mark_inodes_deleted()
- *
- * Update inodes associated with a deleted entry to reflect its deletion.
- * Well, we really just drop the dentry.
- *
- * XXX: we should be using delete_inode for some of this stuff.
- */
-static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, 
-                                      struct dentry *dentry)
+static int hfs_dir_release(struct inode *inode, struct file *file)
 {
-       struct dentry *de;
-       struct inode *tmp;
-       int i;
-
-       for (i = 0; i < 4; ++i) {
-               if ((de = entry->sys_entry[i]) && (dentry != de)) {
-                     dget(de);
-                     tmp = de->d_inode;
-                     tmp->i_nlink = 0;
-                     tmp->i_ctime = CURRENT_TIME;
-                     mark_inode_dirty(tmp);
-                     d_delete(de);
-                     dput(de);
-               }
+       struct hfs_readdir_data *rd = file->private_data;
+       if (rd) {
+               list_del(&rd->list);
+               kfree(rd);
        }
+       return 0;
 }
 
-/*================ Global functions ================*/
-
 /*
  * hfs_create()
  *
@@ -163,47 +177,25 @@ static inline void mark_inodes_deleted(struct hfs_cat_entry *entry,
  * a directory and return a corresponding inode, given the inode for
  * the directory and the name (and its length) of the new file.
  */
-int hfs_create(struct inode * dir, struct dentry *dentry, int mode, struct nameidata *nd)
+int hfs_create(struct inode *dir, struct dentry *dentry, int mode,
+              struct nameidata *nd)
 {
-       struct hfs_cat_entry *entry = HFS_I(dir)->entry;
-       struct hfs_cat_entry *new;
-       struct hfs_cat_key key;
        struct inode *inode;
-       int error;
-
-       lock_kernel();
-       /* build the key, checking against reserved names */
-       if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) {
-               unlock_kernel();
-               return -EEXIST;
-       }
-
-       if ((error = hfs_cat_create(entry, &key, 
-                              (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK,
-                              HFS_SB(dir->i_sb)->s_type,
-                              HFS_SB(dir->i_sb)->s_creator, &new))) {
-               unlock_kernel();
-               return error;
-       }
-
-       /* create an inode for the new file. back out if we run
-        * into trouble. */
-       new->count++; /* hfs_iget() eats one */
-       if (!(inode = hfs_iget(new, HFS_I(dir)->file_type, dentry))) {
-               hfs_cat_delete(entry, new, 1);
-               hfs_cat_put(new);
-               unlock_kernel();
-               return -EIO;
+       int res;
+
+       inode = hfs_new_inode(dir, &dentry->d_name, mode);
+       if (!inode)
+               return -ENOSPC;
+
+       res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
+       if (res) {
+               inode->i_nlink = 0;
+               hfs_delete_inode(inode);
+               iput(inode);
+               return res;
        }
-
-       hfs_cat_put(new);
-       update_dirs_plus(entry, 0);
-       /* toss any relevant negative dentries */
-       if (HFS_I(dir)->d_drop_op)
-               HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type);
-       mark_inode_dirty(inode);
-       unlock_kernel();
        d_instantiate(dentry, inode);
+       mark_inode_dirty(inode);
        return 0;
 }
 
@@ -215,43 +207,24 @@ int hfs_create(struct inode * dir, struct dentry *dentry, int mode, struct namei
  * in a directory, given the inode for the parent directory and the
  * name (and its length) of the new directory.
  */
-int hfs_mkdir(struct inode * parent, struct dentry *dentry, int mode)
+int hfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
-       struct hfs_cat_entry *entry;
-       struct hfs_cat_entry *new;
-       struct hfs_cat_key key;
        struct inode *inode;
-       int error;
-
-       lock_kernel();
-       entry = HFS_I(parent)->entry;
-       /* build the key, checking against reserved names */
-       if (build_key(&key, parent, dentry->d_name.name, 
-                     dentry->d_name.len)) {
-               unlock_kernel();
-               return -EEXIST;
-       }
-
-       /* try to create the directory */
-       if ((error = hfs_cat_mkdir(entry, &key, &new))) {
-               unlock_kernel();
-               return error;
-       }
-
-       /* back out if we run into trouble */
-       new->count++; /* hfs_iget eats one */
-       if (!(inode = hfs_iget(new, HFS_I(parent)->file_type, dentry))) {
-               hfs_cat_delete(entry, new, 1);
-               hfs_cat_put(new);
-               unlock_kernel();
-               return -EIO;
+       int res;
+
+       inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode);
+       if (!inode)
+               return -ENOSPC;
+
+       res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
+       if (res) {
+               inode->i_nlink = 0;
+               hfs_delete_inode(inode);
+               iput(inode);
+               return res;
        }
-
-       hfs_cat_put(new);
-       update_dirs_plus(entry, 1);
-       mark_inode_dirty(inode);
        d_instantiate(dentry, inode);
-       unlock_kernel();
+       mark_inode_dirty(inode);
        return 0;
 }
 
@@ -263,44 +236,22 @@ int hfs_mkdir(struct inode * parent, struct dentry *dentry, int mode)
  * file, given the inode for the parent directory and the name
  * (and its length) of the existing file.
  */
-int hfs_unlink(struct inode * dir, struct dentry *dentry)
+int hfs_unlink(struct inode *dir, struct dentry *dentry)
 {
-       struct hfs_cat_entry *entry = HFS_I(dir)->entry;
-       struct hfs_cat_entry *victim = NULL;
-       struct hfs_cat_key key;
-       int error;
-
-       lock_kernel();
-       entry = HFS_I(dir)->entry;
-       if (build_key(&key, dir, dentry->d_name.name,
-                     dentry->d_name.len)) {
-               unlock_kernel();
-               return -EPERM;
-       }
-
-       if (!(victim = hfs_cat_get(entry->mdb, &key))) {
-               unlock_kernel();
-               return -ENOENT;
-       }
-
-       error = -EPERM;
-       if (victim->type != HFS_CDR_FIL)
-               goto hfs_unlink_put;
+       struct inode *inode;
+       int res;
 
-       if (!(error = hfs_cat_delete(entry, victim, 1))) {
-               struct inode *inode = dentry->d_inode;
+       inode = dentry->d_inode;
+       res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
+       if (res)
+               return res;
 
-               mark_inodes_deleted(victim, dentry);
-               inode->i_nlink--; 
-               inode->i_ctime = CURRENT_TIME;
-               mark_inode_dirty(inode);
-               update_dirs_minus(entry, 0);
-       }
+       inode->i_nlink--;
+       hfs_delete_inode(inode);
+       inode->i_ctime = CURRENT_TIME;
+       mark_inode_dirty(inode);
 
-hfs_unlink_put:
-       hfs_cat_put(victim);    /* Note that hfs_cat_put(NULL) is safe. */
-       unlock_kernel();
-       return error;
+       return res;
 }
 
 /*
@@ -311,55 +262,22 @@ hfs_unlink_put:
  * directory, given the inode for the parent directory and the name
  * (and its length) of the existing directory.
  */
-int hfs_rmdir(struct inode * parent, struct dentry *dentry)
+int hfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       struct hfs_cat_entry *entry;
-       struct hfs_cat_entry *victim = NULL;
-       struct inode *inode = dentry->d_inode;
-       struct hfs_cat_key key;
-       int error;
-
-       lock_kernel();
-       entry = HFS_I(parent)->entry;
-       if (build_key(&key, parent, dentry->d_name.name,
-                     dentry->d_name.len)) {
-               unlock_kernel();
-               return -EPERM;
-       }
-
-       if (!(victim = hfs_cat_get(entry->mdb, &key))) {
-               unlock_kernel();
-               return -ENOENT;
-       }
-
-       error = -ENOTDIR;
-       if (victim->type != HFS_CDR_DIR) 
-               goto hfs_rmdir_put;
-
-       error = -EBUSY;
-       if (!d_unhashed(dentry))
-               goto hfs_rmdir_put;
-
-       /* we only have to worry about 2 and 3 for mount points */
-       if (victim->sys_entry[2] && d_mountpoint(victim->sys_entry[2]))
-               goto hfs_rmdir_put;
-       if (victim->sys_entry[3] && d_mountpoint(victim->sys_entry[3])) 
-               goto hfs_rmdir_put;
-
-       
-       if ((error = hfs_cat_delete(entry, victim, 1)))
-               goto hfs_rmdir_put;
-
-       mark_inodes_deleted(victim, dentry);
+       struct inode *inode;
+       int res;
+
+       inode = dentry->d_inode;
+       if (inode->i_size != 2)
+               return -ENOTEMPTY;
+       res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
+       if (res)
+               return res;
        inode->i_nlink = 0;
        inode->i_ctime = CURRENT_TIME;
+       hfs_delete_inode(inode);
        mark_inode_dirty(inode);
-       update_dirs_minus(entry, 1);
-        
-hfs_rmdir_put:
-       hfs_cat_put(victim);    /* Note that hfs_cat_put(NULL) is safe. */
-       unlock_kernel();
-       return error;
+       return 0;
 }
 
 /*
@@ -376,55 +294,34 @@ hfs_rmdir_put:
 int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
               struct inode *new_dir, struct dentry *new_dentry)
 {
-       struct hfs_cat_entry *old_parent;
-       struct hfs_cat_entry *new_parent;
-       struct hfs_cat_entry *victim = NULL;
-       struct hfs_cat_entry *deleted;
-       struct hfs_cat_key key;
-       int error;
-
-       lock_kernel();
-       old_parent = HFS_I(old_dir)->entry;
-       new_parent = HFS_I(new_dir)->entry;
-       if (build_key(&key, old_dir, old_dentry->d_name.name,
-                     old_dentry->d_name.len) ||
-           (HFS_ITYPE(old_dir->i_ino) != HFS_ITYPE(new_dir->i_ino))) {
-               unlock_kernel();
-               return -EPERM;
-       }
+       int res;
 
-       if (!(victim = hfs_cat_get(old_parent->mdb, &key))) {
-               unlock_kernel();
-               return -ENOENT;
+       /* Unlink destination if it already exists */
+       if (new_dentry->d_inode) {
+               res = hfs_unlink(new_dir, new_dentry);
+               if (res)
+                       return res;
        }
 
-       error = -EPERM;
-       if (build_key(&key, new_dir, new_dentry->d_name.name,
-                            new_dentry->d_name.len)) 
-               goto hfs_rename_put;
-
-       if (!(error = hfs_cat_move(old_parent, new_parent,
-                                  victim, &key, &deleted))) {
-               int is_dir = (victim->type == HFS_CDR_DIR);
-               
-               /* drop the old dentries */
-               mark_inodes_deleted(victim, old_dentry);
-               update_dirs_minus(old_parent, is_dir);
-               if (deleted) {
-                       mark_inodes_deleted(deleted, new_dentry);
-                       hfs_cat_put(deleted);
-               } else {
-                       /* no existing inodes. just drop negative dentries */
-                       if (HFS_I(new_dir)->d_drop_op) 
-                               HFS_I(new_dir)->d_drop_op(new_dentry, 
-                                         HFS_I(new_dir)->file_type);
-                       update_dirs_plus(new_parent, is_dir);
-               }
-       
-       }
-
-hfs_rename_put:
-       hfs_cat_put(victim);    /* Note that hfs_cat_put(NULL) is safe. */
-       unlock_kernel();
-       return error;
+       res = hfs_cat_move(old_dentry->d_inode->i_ino,
+                          old_dir, &old_dentry->d_name,
+                          new_dir, &new_dentry->d_name);
+       return res;
 }
+
+struct file_operations hfs_dir_operations = {
+       .read           = generic_read_dir,
+       .readdir        = hfs_readdir,
+       .llseek         = generic_file_llseek,
+       .release        = hfs_dir_release,
+};
+
+struct inode_operations hfs_dir_inode_operations = {
+       .create         = hfs_create,
+       .lookup         = hfs_lookup,
+       .unlink         = hfs_unlink,
+       .mkdir          = hfs_mkdir,
+       .rmdir          = hfs_rmdir,
+       .rename         = hfs_rename,
+       .setattr        = hfs_inode_setattr,
+};
diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c
deleted file mode 100644 (file)
index 62bbda0..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the inode_operations and file_operations
- * structures for HFS directories under the CAP scheme.
- *
- * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
- *
- * The source code distribution of the Columbia AppleTalk Package for
- * UNIX, version 6.0, (CAP) was used as a specification of the
- * location and format of files used by CAP's Aufs.  No code from CAP
- * appears in hfs_fs.  hfs_fs is not a work ``derived'' from CAP in
- * the sense of intellectual property law.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- */
-
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
-#include <linux/smp_lock.h>
-
-/*================ Forward declarations ================*/
-
-static struct dentry *cap_lookup(struct inode *, struct dentry *, struct nameidata *);
-static int cap_readdir(struct file *, void *, filldir_t);
-
-/*================ Global variables ================*/
-
-#define DOT_LEN                        1
-#define DOT_DOT_LEN            2
-#define DOT_RESOURCE_LEN       9
-#define DOT_FINDERINFO_LEN     11
-#define DOT_ROOTINFO_LEN       9
-
-const struct hfs_name hfs_cap_reserved1[] = {
-       {DOT_LEN,               "."},
-       {DOT_DOT_LEN,           ".."},
-       {DOT_RESOURCE_LEN,      ".resource"},
-       {DOT_FINDERINFO_LEN,    ".finderinfo"},
-       {0,                     ""},
-};
-
-const struct hfs_name hfs_cap_reserved2[] = {
-       {DOT_ROOTINFO_LEN,      ".rootinfo"},
-       {0,                     ""},
-};
-
-#define DOT            (&hfs_cap_reserved1[0])
-#define DOT_DOT                (&hfs_cap_reserved1[1])
-#define DOT_RESOURCE   (&hfs_cap_reserved1[2])
-#define DOT_FINDERINFO (&hfs_cap_reserved1[3])
-#define DOT_ROOTINFO   (&hfs_cap_reserved2[0])
-
-struct file_operations hfs_cap_dir_operations = {
-       .read           = generic_read_dir,
-       .readdir        = cap_readdir,
-       .fsync          = file_fsync,
-};
-
-struct inode_operations hfs_cap_ndir_inode_operations = {
-       .create         = hfs_create,
-       .lookup         = cap_lookup,
-       .unlink         = hfs_unlink,
-       .mkdir          = hfs_mkdir,
-       .rmdir          = hfs_rmdir,
-       .rename         = hfs_rename,
-       .setattr        = hfs_notify_change,
-};
-
-struct inode_operations hfs_cap_fdir_inode_operations = {
-       .lookup         = cap_lookup,
-       .setattr        = hfs_notify_change,
-};
-
-struct inode_operations hfs_cap_rdir_inode_operations = {
-       .create         = hfs_create,
-       .lookup         = cap_lookup,
-       .setattr        = hfs_notify_change,
-};
-
-/*================ File-local functions ================*/
-
-/*
- * cap_lookup()
- *
- * This is the lookup() entry in the inode_operations structure for
- * HFS directories in the CAP scheme.  The purpose is to generate the
- * inode corresponding to an entry in a directory, given the inode for
- * the directory and the name (and its length) of the entry.
- */
-static struct dentry *cap_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
-{
-       ino_t dtype;
-       struct hfs_name cname;
-       struct hfs_cat_entry *entry;
-       struct hfs_cat_key key;
-       struct inode *inode = NULL;
-
-       lock_kernel();
-
-       dentry->d_op = &hfs_dentry_operations;
-       entry = HFS_I(dir)->entry;
-       dtype = HFS_ITYPE(dir->i_ino);
-
-       /* Perform name-mangling */
-       hfs_nameout(dir, &cname, dentry->d_name.name, 
-                   dentry->d_name.len);
-
-       /* no need to check for "."  or ".." */
-
-       /* Check for epecial directories if in a normal directory.
-          Note that cap_dupdir() does an iput(dir). */
-       if (dtype==HFS_CAP_NDIR) {
-               /* Check for ".resource", ".finderinfo" and ".rootinfo" */
-               if (hfs_streq(cname.Name, cname.Len, 
-                             DOT_RESOURCE->Name, DOT_RESOURCE_LEN)) {
-                       ++entry->count; /* __hfs_iget() eats one */
-                       inode = hfs_iget(entry, HFS_CAP_RDIR, dentry);
-                       goto done;
-               } else if (hfs_streq(cname.Name, cname.Len, 
-                                    DOT_FINDERINFO->Name, 
-                                    DOT_FINDERINFO_LEN)) {
-                       ++entry->count; /* __hfs_iget() eats one */
-                       inode = hfs_iget(entry, HFS_CAP_FDIR, dentry);
-                       goto done;
-               } else if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
-                          hfs_streq(cname.Name, cname.Len, 
-                                    DOT_ROOTINFO->Name, DOT_ROOTINFO_LEN)) {
-                       ++entry->count; /* __hfs_iget() eats one */
-                       inode = hfs_iget(entry, HFS_CAP_FNDR, dentry);
-                       goto done;
-               }
-       }
-
-       /* Do an hfs_iget() on the mangled name. */
-       hfs_cat_build_key(entry->cnid, &cname, &key);
-       inode = hfs_iget(hfs_cat_get(entry->mdb, &key),
-                        HFS_I(dir)->file_type, dentry);
-
-       /* Don't return a resource fork for a directory */
-       if (inode && (dtype == HFS_CAP_RDIR) && 
-           (HFS_I(inode)->entry->type == HFS_CDR_DIR)) {
-               iput(inode); /* this does an hfs_cat_put */
-               inode = NULL;
-       }
-
-done:
-       unlock_kernel();
-       d_add(dentry, inode);
-       return NULL;
-}
-
-/*
- * cap_readdir()
- *
- * This is the readdir() entry in the file_operations structure for
- * HFS directories in the CAP scheme.  The purpose is to enumerate the
- * entries in a directory, given the inode of the directory and a
- * (struct file *), the 'f_pos' field of which indicates the location
- * in the directory.  The (struct file *) is updated so that the next
- * call with the same 'dir' and 'filp' arguments will produce the next
- * directory entry.  The entries are returned in 'dirent', which is
- * "filled-in" by calling filldir().  This allows the same readdir()
- * function be used for different dirent formats.  We try to read in
- * as many entries as we can before filldir() refuses to take any more.
- *
- * XXX: In the future it may be a good idea to consider not generating
- * metadata files for covered directories since the data doesn't
- * correspond to the mounted directory.         However this requires an
- * iget() for every directory which could be considered an excessive
- * amount of overhead. Since the inode for a mount point is always
- * in-core this is another argument for a call to get an inode if it
- * is in-core or NULL if it is not.
- */
-static int cap_readdir(struct file * filp,
-                      void * dirent, filldir_t filldir)
-{
-       ino_t type;
-       int skip_dirs;
-       struct hfs_brec brec;
-        struct hfs_cat_entry *entry;
-       struct inode *dir = filp->f_dentry->d_inode;
-
-       lock_kernel();
-
-       entry = HFS_I(dir)->entry;
-       type = HFS_ITYPE(dir->i_ino);
-       skip_dirs = (type == HFS_CAP_RDIR);
-
-       if (filp->f_pos == 0) {
-               /* Entry 0 is for "." */
-               if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino, DT_DIR)) {
-                       goto out;
-               }
-               filp->f_pos = 1;
-       }
-
-       if (filp->f_pos == 1) {
-               /* Entry 1 is for ".." */
-               hfs_u32 cnid;
-
-               if (type == HFS_CAP_NDIR) {
-                       cnid = hfs_get_nl(entry->key.ParID);
-               } else {
-                       cnid = entry->cnid;
-               }
-
-               if (filldir(dirent, DOT_DOT->Name,
-                           DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) {
-                       goto out;
-               }
-               filp->f_pos = 2;
-       }
-
-       if (filp->f_pos < (dir->i_size - 3)) {
-               hfs_u32 cnid;
-               hfs_u8 type;
-
-               if (hfs_cat_open(entry, &brec) ||
-                   hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) {
-                       goto out;
-               }
-               while (filp->f_pos < (dir->i_size - 3)) {
-                       if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) {
-                               goto out;
-                       }
-                       if (!skip_dirs || (type != HFS_CDR_DIR)) {
-                               ino_t ino;
-                               unsigned int len;
-                               unsigned char tmp_name[HFS_NAMEMAX];
-
-                               ino = ntohl(cnid) | HFS_I(dir)->file_type;
-                               len = hfs_namein(dir, tmp_name,
-                                   &((struct hfs_cat_key *)brec.key)->CName);
-                               if (filldir(dirent, tmp_name, len,
-                                           filp->f_pos, ino, DT_UNKNOWN)) {
-                                       hfs_cat_close(entry, &brec);
-                                       goto out;
-                               }
-                       }
-                       ++filp->f_pos;
-               }
-               hfs_cat_close(entry, &brec);
-       }
-
-       if (filp->f_pos == (dir->i_size - 3)) {
-               if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
-                   (type == HFS_CAP_NDIR)) {
-                       /* In root dir last-2 entry is for ".rootinfo" */
-                       if (filldir(dirent, DOT_ROOTINFO->Name,
-                                   DOT_ROOTINFO_LEN, filp->f_pos,
-                                   ntohl(entry->cnid) | HFS_CAP_FNDR,
-                                   DT_UNKNOWN)) {
-                               goto out;
-                       }
-               }
-               ++filp->f_pos;
-       }
-
-       if (filp->f_pos == (dir->i_size - 2)) {
-               if (type == HFS_CAP_NDIR) {
-                       /* In normal dirs last-1 entry is for ".finderinfo" */
-                       if (filldir(dirent, DOT_FINDERINFO->Name,
-                                   DOT_FINDERINFO_LEN, filp->f_pos,
-                                   ntohl(entry->cnid) | HFS_CAP_FDIR,
-                                   DT_UNKNOWN)) {
-                               goto out;
-                       }
-               }
-               ++filp->f_pos;
-       }
-
-       if (filp->f_pos == (dir->i_size - 1)) {
-               if (type == HFS_CAP_NDIR) {
-                       /* In normal dirs last entry is for ".resource" */
-                       if (filldir(dirent, DOT_RESOURCE->Name,
-                                   DOT_RESOURCE_LEN, filp->f_pos,
-                                   ntohl(entry->cnid) | HFS_CAP_RDIR,
-                                   DT_UNKNOWN)) {
-                               goto out;
-                       }
-               }
-               ++filp->f_pos;
-       }
-
-out:
-       unlock_kernel();
-       return 0;
-}
-
-
-/* due to the dcache caching negative dentries for non-existent files,
- * we need to drop those entries when a file silently gets created.
- * as far as i can tell, the calls that need to do this are the file
- * related calls (create, rename, and mknod). the directory calls
- * should be immune. the relevant calls in dir.c call drop_dentry 
- * upon successful completion. */
-void hfs_cap_drop_dentry(struct dentry *dentry, const ino_t type)
-{
-  if (type == HFS_CAP_DATA) { /* given name */
-    hfs_drop_special(dentry->d_parent, DOT_FINDERINFO, dentry);
-    hfs_drop_special(dentry->d_parent, DOT_RESOURCE, dentry);
-  } else {
-    struct dentry *de;
-
-    /* given {.resource,.finderinfo}/name, look for name */
-    if ((de = hfs_lookup_dentry(dentry->d_parent->d_parent,
-                               dentry->d_name.name, dentry->d_name.len))) {
-      if (!de->d_inode)
-       d_drop(de);
-      dput(de);
-    }
-    
-    switch (type) {
-    case HFS_CAP_RSRC: /* given .resource/name */
-       /* look for .finderinfo/name */
-      hfs_drop_special(dentry->d_parent->d_parent, DOT_FINDERINFO, 
-                      dentry);
-      break;
-    case HFS_CAP_FNDR: /* given .finderinfo/name. i don't this 
-                       * happens. */
-      /* look for .resource/name */
-      hfs_drop_special(dentry->d_parent->d_parent, DOT_RESOURCE, 
-                      dentry);
-      break;
-    }
-  }
-}
diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c
deleted file mode 100644 (file)
index ee2ccef..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * linux/fs/hfs/dir_dbl.c
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the inode_operations and file_operations
- * structures for HFS directories.
- *
- * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- */
-
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
-#include <linux/smp_lock.h>
-
-/*================ Forward declarations ================*/
-
-static struct dentry *dbl_lookup(struct inode *, struct dentry *, struct nameidata *);
-static int dbl_readdir(struct file *, void *, filldir_t);
-static int dbl_create(struct inode *, struct dentry *, int, struct nameidata *);
-static int dbl_mkdir(struct inode *, struct dentry *, int);
-static int dbl_unlink(struct inode *, struct dentry *);
-static int dbl_rmdir(struct inode *, struct dentry *);
-static int dbl_rename(struct inode *, struct dentry *,
-                     struct inode *, struct dentry *);
-
-/*================ Global variables ================*/
-
-#define DOT_LEN                        1
-#define DOT_DOT_LEN            2
-#define ROOTINFO_LEN           8
-#define PCNT_ROOTINFO_LEN      9
-
-const struct hfs_name hfs_dbl_reserved1[] = {
-       {DOT_LEN,               "."},
-       {DOT_DOT_LEN,           ".."},
-       {0,                     ""},
-};
-
-const struct hfs_name hfs_dbl_reserved2[] = {
-       {ROOTINFO_LEN,          "RootInfo"},
-       {PCNT_ROOTINFO_LEN,     "%RootInfo"},
-       {0,                     ""},
-};
-
-#define DOT            (&hfs_dbl_reserved1[0])
-#define DOT_DOT                (&hfs_dbl_reserved1[1])
-#define ROOTINFO       (&hfs_dbl_reserved2[0])
-#define PCNT_ROOTINFO  (&hfs_dbl_reserved2[1])
-
-struct file_operations hfs_dbl_dir_operations = {
-       .read           = generic_read_dir,
-       .readdir        = dbl_readdir,
-       .fsync          = file_fsync,
-};
-
-struct inode_operations hfs_dbl_dir_inode_operations = {
-       .create         = dbl_create,
-       .lookup         = dbl_lookup,
-       .unlink         = dbl_unlink,
-       .mkdir          = dbl_mkdir,
-       .rmdir          = dbl_rmdir,
-       .rename         = dbl_rename,
-       .setattr        = hfs_notify_change,
-};
-
-
-/*================ File-local functions ================*/
-
-/*
- * is_hdr()
- */
-static int is_hdr(struct inode *dir, const char *name, int len)
-{
-       int retval = 0;
-
-       if (name[0] == '%') {
-               struct hfs_cat_entry *entry = HFS_I(dir)->entry;
-               struct hfs_cat_entry *victim;
-               struct hfs_name cname;
-               struct hfs_cat_key key;
-
-               hfs_nameout(dir, &cname, name+1, len-1);
-               hfs_cat_build_key(entry->cnid, &cname, &key);
-               if ((victim = hfs_cat_get(entry->mdb, &key))) {
-                       hfs_cat_put(victim);
-                       retval = 1;
-               }
-       }
-       return retval;
-}
-
-/*
- * dbl_lookup()
- *
- * This is the lookup() entry in the inode_operations structure for
- * HFS directories in the AppleDouble scheme.  The purpose is to
- * generate the inode corresponding to an entry in a directory, given
- * the inode for the directory and the name (and its length) of the
- * entry.
- */
-static struct dentry *dbl_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
-{
-       struct hfs_name cname;
-       struct hfs_cat_entry *entry;
-       struct hfs_cat_key key;
-       struct inode *inode = NULL;
-
-       lock_kernel();
-       dentry->d_op = &hfs_dentry_operations;
-       entry = HFS_I(dir)->entry;
-       
-       /* Perform name-mangling */
-       hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len);
-       /* no need to check for "."  or ".." */
-
-       /* Check for "%RootInfo" if in the root directory. */
-       if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
-           hfs_streq(cname.Name, cname.Len, 
-                     PCNT_ROOTINFO->Name, PCNT_ROOTINFO_LEN)) {
-               ++entry->count; /* __hfs_iget() eats one */
-               inode = hfs_iget(entry, HFS_DBL_HDR, dentry);
-               goto done;
-       }
-
-       /* Do an hfs_iget() on the mangled name. */
-       hfs_cat_build_key(entry->cnid, &cname, &key);
-       inode = hfs_iget(hfs_cat_get(entry->mdb, &key), HFS_DBL_NORM, dentry);
-
-       /* Try as a header if not found and first character is '%' */
-       if (!inode && (dentry->d_name.name[0] == '%')) {
-               hfs_nameout(dir, &cname, dentry->d_name.name+1,
-                           dentry->d_name.len-1);
-               hfs_cat_build_key(entry->cnid, &cname, &key);
-               inode = hfs_iget(hfs_cat_get(entry->mdb, &key),
-                                HFS_DBL_HDR, dentry);
-       }
-       
-done:
-       unlock_kernel();
-       d_add(dentry, inode);
-       return NULL;
-}
-
-/*
- * dbl_readdir()
- *
- * This is the readdir() entry in the file_operations structure for
- * HFS directories in the AppleDouble scheme.  The purpose is to
- * enumerate the entries in a directory, given the inode of the
- * directory and a (struct file *), the 'f_pos' field of which
- * indicates the location in the directory.  The (struct file *) is
- * updated so that the next call with the same 'dir' and 'filp'
- * arguments will produce the next directory entry.  The entries are
- * returned in 'dirent', which is "filled-in" by calling filldir().
- * This allows the same readdir() function be used for different
- * formats.  We try to read in as many entries as we can before
- * filldir() refuses to take any more.
- *
- * XXX: In the future it may be a good idea to consider not generating
- * metadata files for covered directories since the data doesn't
- * correspond to the mounted directory.         However this requires an
- * iget() for every directory which could be considered an excessive
- * amount of overhead. Since the inode for a mount point is always
- * in-core this is another argument for a call to get an inode if it
- * is in-core or NULL if it is not.
- */
-static int dbl_readdir(struct file * filp,
-                      void * dirent, filldir_t filldir)
-{
-       struct hfs_brec brec;
-        struct hfs_cat_entry *entry;
-       struct inode *dir = filp->f_dentry->d_inode;
-
-       lock_kernel();
-
-       entry = HFS_I(dir)->entry;
-
-       if (filp->f_pos == 0) {
-               /* Entry 0 is for "." */
-               if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino,
-                           DT_DIR)) {
-                       goto out;
-               }
-               filp->f_pos = 1;
-       }
-
-       if (filp->f_pos == 1) {
-               /* Entry 1 is for ".." */
-               if (filldir(dirent, DOT_DOT->Name, DOT_DOT_LEN, 1,
-                           hfs_get_hl(entry->key.ParID), DT_DIR)) {
-                       goto out;       
-               }
-               filp->f_pos = 2;
-       }
-
-       if (filp->f_pos < (dir->i_size - 1)) {
-                hfs_u32 cnid;
-                hfs_u8 type;
-
-               if (hfs_cat_open(entry, &brec) ||
-                   hfs_cat_next(entry, &brec, (filp->f_pos - 1) >> 1,
-                                &cnid, &type)) {
-                       goto out;
-               }
-
-               while (filp->f_pos < (dir->i_size - 1)) {
-                       unsigned char tmp_name[HFS_NAMEMAX + 1];
-                       ino_t ino;
-                       int is_hdr = (filp->f_pos & 1);
-                       unsigned int len;
-
-                       if (is_hdr) {
-                               ino = ntohl(cnid) | HFS_DBL_HDR;
-                               tmp_name[0] = '%';
-                               len = 1 + hfs_namein(dir, tmp_name + 1,
-                                   &((struct hfs_cat_key *)brec.key)->CName);
-                       } else {
-                               if (hfs_cat_next(entry, &brec, 1,
-                                                       &cnid, &type)) {
-                                       goto out;
-                               }
-                               ino = ntohl(cnid);
-                               len = hfs_namein(dir, tmp_name,
-                                   &((struct hfs_cat_key *)brec.key)->CName);
-                       }
-
-                       if (filldir(dirent, tmp_name, len, filp->f_pos, ino,
-                                   DT_UNKNOWN)) {
-                               hfs_cat_close(entry, &brec);
-                               goto out;
-                       }
-                       ++filp->f_pos;
-               }
-               hfs_cat_close(entry, &brec);
-       }
-
-       if (filp->f_pos == (dir->i_size - 1)) {
-               if (entry->cnid == htonl(HFS_ROOT_CNID)) {
-                       /* In root dir last entry is for "%RootInfo" */
-                       if (filldir(dirent, PCNT_ROOTINFO->Name,
-                                   PCNT_ROOTINFO_LEN, filp->f_pos,
-                                   ntohl(entry->cnid) | HFS_DBL_HDR,
-                                   DT_UNKNOWN)) {
-                               goto out;
-                       }
-               }
-               ++filp->f_pos;
-       }
-
-out:
-       unlock_kernel();
-       return 0;
-}
-
-/*
- * dbl_create()
- *
- * This is the create() entry in the inode_operations structure for
- * AppleDouble directories.  The purpose is to create a new file in
- * a directory and return a corresponding inode, given the inode for
- * the directory and the name (and its length) of the new file.
- */
-static int dbl_create(struct inode * dir, struct dentry *dentry,
-                     int mode, struct nameidata *nd)
-{
-       int error;
-
-       lock_kernel();
-       if (is_hdr(dir, dentry->d_name.name, dentry->d_name.len)) {
-               error = -EEXIST;
-       } else {
-               error = hfs_create(dir, dentry, mode, nd);
-       }
-       unlock_kernel();
-       return error;
-}
-
-/*
- * dbl_mkdir()
- *
- * This is the mkdir() entry in the inode_operations structure for
- * AppleDouble directories.  The purpose is to create a new directory
- * in a directory, given the inode for the parent directory and the
- * name (and its length) of the new directory.
- */
-static int dbl_mkdir(struct inode * parent, struct dentry *dentry,
-                    int mode)
-{
-       int error;
-
-       lock_kernel();
-       if (is_hdr(parent, dentry->d_name.name, dentry->d_name.len)) {
-               error = -EEXIST;
-       } else {
-               error = hfs_mkdir(parent, dentry, mode);
-       }
-       unlock_kernel();
-       return error;
-}
-
-/*
- * dbl_unlink()
- *
- * This is the unlink() entry in the inode_operations structure for
- * AppleDouble directories.  The purpose is to delete an existing
- * file, given the inode for the parent directory and the name
- * (and its length) of the existing file.
- */
-static int dbl_unlink(struct inode * dir, struct dentry *dentry)
-{
-       int error;
-
-       lock_kernel();
-       error = hfs_unlink(dir, dentry);
-       if ((error == -ENOENT) && is_hdr(dir, dentry->d_name.name,
-                                        dentry->d_name.len)) {
-               error = -EPERM;
-       }
-       unlock_kernel();
-       return error;
-}
-
-/*
- * dbl_rmdir()
- *
- * This is the rmdir() entry in the inode_operations structure for
- * AppleDouble directories.  The purpose is to delete an existing
- * directory, given the inode for the parent directory and the name
- * (and its length) of the existing directory.
- */
-static int dbl_rmdir(struct inode * parent, struct dentry *dentry)
-{
-       int error;
-
-       lock_kernel();
-       error = hfs_rmdir(parent, dentry);
-       if ((error == -ENOENT) && is_hdr(parent, dentry->d_name.name,
-                                        dentry->d_name.len)) {
-               error = -ENOTDIR;
-       }
-       unlock_kernel();
-       return error;
-}
-
-/*
- * dbl_rename()
- *
- * This is the rename() entry in the inode_operations structure for
- * AppleDouble directories.  The purpose is to rename an existing
- * file or directory, given the inode for the current directory and
- * the name (and its length) of the existing file/directory and the
- * inode for the new directory and the name (and its length) of the
- * new file/directory.
- * 
- * XXX: how do we handle must_be_dir?
- */
-static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry,
-                     struct inode *new_dir, struct dentry *new_dentry)
-{
-       int error;
-
-       lock_kernel();
-       if (is_hdr(new_dir, new_dentry->d_name.name,
-                  new_dentry->d_name.len)) {
-               error = -EPERM;
-       } else {
-               error = hfs_rename(old_dir, old_dentry,
-                                  new_dir, new_dentry);
-               if ((error == -ENOENT) /*&& !must_be_dir*/ &&
-                   is_hdr(old_dir, old_dentry->d_name.name,
-                          old_dentry->d_name.len)) {
-                       error = -EPERM;
-               }
-       }
-       unlock_kernel();
-       return error;
-}
-
-
-/* due to the dcache caching negative dentries for non-existent files,
- * we need to drop those entries when a file silently gets created.
- * as far as i can tell, the calls that need to do this are the file
- * related calls (create, rename, and mknod). the directory calls
- * should be immune. the relevant calls in dir.c call drop_dentry 
- * upon successful completion. */
-void hfs_dbl_drop_dentry(struct dentry *dentry, const ino_t type)
-{
-  unsigned char tmp_name[HFS_NAMEMAX + 1];
-  struct dentry *de = NULL;
-
-  switch (type) {
-  case HFS_DBL_HDR:
-   /* given %name, look for name. i don't think this happens. */
-   de = hfs_lookup_dentry(dentry->d_parent,
-                         dentry->d_name.name + 1, dentry->d_name.len - 1);
-    break;
-  case HFS_DBL_DATA:
-    /* given name, look for %name */
-    tmp_name[0] = '%';
-    strncpy(tmp_name + 1, dentry->d_name.name, HFS_NAMELEN - 1);
-    de = hfs_lookup_dentry(dentry->d_parent, 
-                          tmp_name, dentry->d_name.len + 1);
-  }
-
-  if (de) {
-    if (!de->d_inode)
-      d_drop(de);
-    dput(de);
-  }
-}
diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c
deleted file mode 100644 (file)
index 9688bcf..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * linux/fs/hfs/dir_nat.c
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the inode_operations and file_operations
- * structures for HFS directories.
- *
- * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
- *
- * The source code distributions of Netatalk, versions 1.3.3b2 and
- * 1.4b2, were used as a specification of the location and format of
- * files used by Netatalk's afpd.  No code from Netatalk appears in
- * hfs_fs.  hfs_fs is not a work ``derived'' from Netatalk in the
- * sense of intellectual property law.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- */
-
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
-#include <linux/smp_lock.h>
-
-/*================ Forward declarations ================*/
-
-static struct dentry *nat_lookup(struct inode *, struct dentry *, struct nameidata *);
-static int nat_readdir(struct file *, void *, filldir_t);
-static int nat_rmdir(struct inode *, struct dentry *);
-static int nat_hdr_unlink(struct inode *, struct dentry *);
-static int nat_hdr_rename(struct inode *, struct dentry *,
-                         struct inode *, struct dentry *);
-
-/*================ Global variables ================*/
-
-#define DOT_LEN                        1
-#define DOT_DOT_LEN            2
-#define DOT_APPLEDOUBLE_LEN    12
-#define DOT_PARENT_LEN         7
-#define ROOTINFO_LEN            8
-
-const struct hfs_name hfs_nat_reserved1[] = {
-       {DOT_LEN,               "."},
-       {DOT_DOT_LEN,           ".."},
-       {DOT_APPLEDOUBLE_LEN,   ".AppleDouble"},
-       {DOT_PARENT_LEN,        ".Parent"},
-       {0,                     ""},
-};
-
-const struct hfs_name hfs_nat_reserved2[] = {
-       {ROOTINFO_LEN,                  "RootInfo"},
-};
-
-#define DOT            (&hfs_nat_reserved1[0])
-#define DOT_DOT                (&hfs_nat_reserved1[1])
-#define DOT_APPLEDOUBLE        (&hfs_nat_reserved1[2])
-#define DOT_PARENT     (&hfs_nat_reserved1[3])
-#define ROOTINFO        (&hfs_nat_reserved2[0])
-
-struct file_operations hfs_nat_dir_operations = {
-       .read           = generic_read_dir,
-       .readdir        = nat_readdir,
-       .fsync          = file_fsync,
-};
-
-struct inode_operations hfs_nat_ndir_inode_operations = {
-       .create         = hfs_create,
-       .lookup         = nat_lookup,
-       .unlink         = hfs_unlink,
-       .mkdir          = hfs_mkdir,
-       .rmdir          = nat_rmdir,
-       .rename         = hfs_rename,
-       .setattr        = hfs_notify_change,
-};
-
-struct inode_operations hfs_nat_hdir_inode_operations = {
-       .create         = hfs_create,
-       .lookup         = nat_lookup,
-       .unlink         = nat_hdr_unlink,
-       .rename         = nat_hdr_rename,
-       .setattr        = hfs_notify_change,
-};
-
-/*================ File-local functions ================*/
-
-/*
- * nat_lookup()
- *
- * This is the lookup() entry in the inode_operations structure for
- * HFS directories in the Netatalk scheme.  The purpose is to generate
- * the inode corresponding to an entry in a directory, given the inode
- * for the directory and the name (and its length) of the entry.
- */
-static struct dentry *nat_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
-{
-       ino_t dtype;
-       struct hfs_name cname;
-       struct hfs_cat_entry *entry;
-       struct hfs_cat_key key;
-       struct inode *inode = NULL;
-
-       lock_kernel();
-       dentry->d_op = &hfs_dentry_operations;
-       entry = HFS_I(dir)->entry;
-       dtype = HFS_ITYPE(dir->i_ino);
-
-       /* Perform name-mangling */
-       hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len);
-
-       /* no need to check for "."  or ".." */
-
-       /* Check for ".AppleDouble" if in a normal directory,
-          and for ".Parent" in ".AppleDouble". */
-       if (dtype==HFS_NAT_NDIR) {
-               /* Check for ".AppleDouble" */
-               if (hfs_streq(cname.Name, cname.Len, 
-                             DOT_APPLEDOUBLE->Name, DOT_APPLEDOUBLE_LEN)) {
-                       ++entry->count; /* __hfs_iget() eats one */
-                       inode = hfs_iget(entry, HFS_NAT_HDIR, dentry);
-                       goto done;
-               }
-       } else if (dtype==HFS_NAT_HDIR) {
-               if (hfs_streq(cname.Name, cname.Len, 
-                             DOT_PARENT->Name, DOT_PARENT_LEN)) {
-                       ++entry->count; /* __hfs_iget() eats one */
-                       inode = hfs_iget(entry, HFS_NAT_HDR, dentry);
-                       goto done;
-               }
-
-               if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
-                   hfs_streq(cname.Name, cname.Len, 
-                             ROOTINFO->Name, ROOTINFO_LEN)) {
-                       ++entry->count; /* __hfs_iget() eats one */
-                       inode = hfs_iget(entry, HFS_NAT_HDR, dentry);
-                        goto done;
-               }
-       }
-
-       /* Do an hfs_iget() on the mangled name. */
-       hfs_cat_build_key(entry->cnid, &cname, &key);
-       inode = hfs_iget(hfs_cat_get(entry->mdb, &key), 
-                        HFS_I(dir)->file_type, dentry);
-
-       /* Don't return a header file for a directory other than .Parent */
-       if (inode && (dtype == HFS_NAT_HDIR) &&
-           (HFS_I(inode)->entry != entry) &&
-           (HFS_I(inode)->entry->type == HFS_CDR_DIR)) {
-               iput(inode); /* this does an hfs_cat_put */
-               inode = NULL;
-       }
-
-done:
-       unlock_kernel();
-       d_add(dentry, inode);
-       return NULL;
-}
-
-/*
- * nat_readdir()
- *
- * This is the readdir() entry in the file_operations structure for
- * HFS directories in the netatalk scheme.  The purpose is to
- * enumerate the entries in a directory, given the inode of the
- * directory and a struct file which indicates the location in the
- * directory.  The struct file is updated so that the next call with
- * the same dir and filp will produce the next directory entry.         The
- * entries are returned in dirent, which is "filled-in" by calling
- * filldir().  This allows the same readdir() function be used for
- * different dirent formats.  We try to read in as many entries as we
- * can before filldir() refuses to take any more.
- *
- * Note that the Netatalk format doesn't have the problem with
- * metadata for covered directories that exists in the other formats,
- * since the metadata is contained within the directory.
- */
-static int nat_readdir(struct file * filp,
-                      void * dirent, filldir_t filldir)
-{
-       ino_t type;
-       int skip_dirs;
-       struct hfs_brec brec;
-        struct hfs_cat_entry *entry;
-       struct inode *dir = filp->f_dentry->d_inode;
-
-       lock_kernel();
-       
-       entry = HFS_I(dir)->entry;
-       type = HFS_ITYPE(dir->i_ino);
-       skip_dirs = (type == HFS_NAT_HDIR);
-
-       if (filp->f_pos == 0) {
-               /* Entry 0 is for "." */
-               if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino,
-                           DT_DIR)) {
-                       goto out;
-               }
-               filp->f_pos = 1;
-       }
-
-       if (filp->f_pos == 1) {
-               /* Entry 1 is for ".." */
-               hfs_u32 cnid;
-
-               if (type == HFS_NAT_NDIR) {
-                       cnid = hfs_get_nl(entry->key.ParID);
-               } else {
-                       cnid = entry->cnid;
-               }
-
-               if (filldir(dirent, DOT_DOT->Name,
-                           DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) {
-                       goto out;
-               }
-               filp->f_pos = 2;
-       }
-
-       if (filp->f_pos < (dir->i_size - 2)) {
-               hfs_u32 cnid;
-               hfs_u8 type;
-
-               if (hfs_cat_open(entry, &brec) ||
-                   hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) {
-                       goto out;
-               }
-               while (filp->f_pos < (dir->i_size - 2)) {
-                       if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) {
-                               goto out;
-                       }
-                       if (!skip_dirs || (type != HFS_CDR_DIR)) {
-                               ino_t ino;
-                               unsigned int len;
-                               unsigned char tmp_name[HFS_NAMEMAX];
-
-                               ino = ntohl(cnid) | HFS_I(dir)->file_type;
-                               len = hfs_namein(dir, tmp_name,
-                                   &((struct hfs_cat_key *)brec.key)->CName);
-                               if (filldir(dirent, tmp_name, len,
-                                           filp->f_pos, ino, DT_UNKNOWN)) {
-                                       hfs_cat_close(entry, &brec);
-                                       goto out;
-                               }
-                       }
-                       ++filp->f_pos;
-               }
-               hfs_cat_close(entry, &brec);
-       }
-
-       if (filp->f_pos == (dir->i_size - 2)) {
-               if (type == HFS_NAT_NDIR) {
-                       /* In normal dirs entry 2 is for ".AppleDouble" */
-                       if (filldir(dirent, DOT_APPLEDOUBLE->Name,
-                                   DOT_APPLEDOUBLE_LEN, filp->f_pos,
-                                   ntohl(entry->cnid) | HFS_NAT_HDIR,
-                                   DT_UNKNOWN)) {
-                               goto out;
-                       }
-               } else if (type == HFS_NAT_HDIR) {
-                       /* In .AppleDouble entry 2 is for ".Parent" */
-                       if (filldir(dirent, DOT_PARENT->Name,
-                                   DOT_PARENT_LEN, filp->f_pos,
-                                   ntohl(entry->cnid) | HFS_NAT_HDR,
-                                   DT_UNKNOWN)) {
-                               goto out;
-                       }
-               }
-               ++filp->f_pos;
-       }
-
-       if (filp->f_pos == (dir->i_size - 1)) {
-               /* handle ROOT/.AppleDouble/RootInfo as the last entry. */
-               if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
-                   (type == HFS_NAT_HDIR)) {
-                       if (filldir(dirent, ROOTINFO->Name,
-                                   ROOTINFO_LEN, filp->f_pos,
-                                   ntohl(entry->cnid) | HFS_NAT_HDR,
-                                   DT_UNKNOWN)) {
-                               goto out;
-                       }
-               }
-               ++filp->f_pos;
-       }
-
-out:
-       unlock_kernel();
-       return 0;
-}
-
-/* due to the dcache caching negative dentries for non-existent files,
- * we need to drop those entries when a file silently gets created.
- * as far as i can tell, the calls that need to do this are the file
- * related calls (create, rename, and mknod). the directory calls
- * should be immune. the relevant calls in dir.c call drop_dentry 
- * upon successful completion. */
-void hfs_nat_drop_dentry(struct dentry *dentry, const ino_t type)
-{
-  struct dentry *de;
-  
-  switch (type) {
-  case HFS_NAT_HDR: /* given .AppleDouble/name */
-    /* look for name */
-    de = hfs_lookup_dentry(dentry->d_parent->d_parent,
-                          dentry->d_name.name, dentry->d_name.len);
-
-    if (de) {
-      if (!de->d_inode)
-       d_drop(de);
-      dput(de);
-    }
-    break;
-  case HFS_NAT_DATA: /* given name */
-    /* look for .AppleDouble/name */
-    hfs_drop_special(dentry->d_parent, DOT_APPLEDOUBLE, dentry);
-    break;
-  }
-
-}
-
-/*
- * nat_rmdir()
- *
- * This is the rmdir() entry in the inode_operations structure for
- * Netatalk directories.  The purpose is to delete an existing
- * directory, given the inode for the parent directory and the name
- * (and its length) of the existing directory.
- *
- * We handle .AppleDouble and call hfs_rmdir() for all other cases.
- */
-static int nat_rmdir(struct inode *parent, struct dentry *dentry)
-{
-       struct hfs_cat_entry *entry = HFS_I(parent)->entry;
-       struct hfs_name cname;
-       int error;
-
-       lock_kernel();
-       hfs_nameout(parent, &cname, dentry->d_name.name, dentry->d_name.len);
-       if (hfs_streq(cname.Name, cname.Len,
-                     DOT_APPLEDOUBLE->Name, DOT_APPLEDOUBLE_LEN)) {
-               if (!HFS_SB(parent->i_sb)->s_afpd) {
-                       /* Not in AFPD compatibility mode */
-                       error = -EPERM;
-               } else if (entry->u.dir.files || entry->u.dir.dirs) {
-                       /* AFPD compatible, but the directory is not empty */
-                       error = -ENOTEMPTY;
-               } else {
-                       /* AFPD compatible, so pretend to succeed */
-                       error = 0;
-               }
-       } else {
-               error = hfs_rmdir(parent, dentry);
-       }
-       unlock_kernel();
-       return error;
-}
-
-/*
- * nat_hdr_unlink()
- *
- * This is the unlink() entry in the inode_operations structure for
- * Netatalk .AppleDouble directories.  The purpose is to delete an
- * existing file, given the inode for the parent directory and the name
- * (and its length) of the existing file.
- *
- * WE DON'T ACTUALLY DELETE HEADER THE FILE.
- * In non-afpd-compatible mode:
- *   We return -EPERM.
- * In afpd-compatible mode:
- *   We return success if the file exists or is .Parent.
- *   Otherwise we return -ENOENT.
- */
-static int nat_hdr_unlink(struct inode *dir, struct dentry *dentry)
-{
-       struct hfs_cat_entry *entry;
-       int error = 0;
-
-       lock_kernel();
-       entry = HFS_I(dir)->entry;
-       if (!HFS_SB(dir->i_sb)->s_afpd) {
-               /* Not in AFPD compatibility mode */
-               error = -EPERM;
-       } else {
-               struct hfs_name cname;
-
-               hfs_nameout(dir, &cname, dentry->d_name.name, 
-                           dentry->d_name.len);
-               if (!hfs_streq(cname.Name, cname.Len,
-                              DOT_PARENT->Name, DOT_PARENT_LEN)) {
-                       struct hfs_cat_entry *victim;
-                       struct hfs_cat_key key;
-
-                       hfs_cat_build_key(entry->cnid, &cname, &key);
-                       victim = hfs_cat_get(entry->mdb, &key);
-
-                       if (victim) {
-                               /* pretend to succeed */
-                               hfs_cat_put(victim);
-                       } else {
-                               error = -ENOENT;
-                       }
-               }
-       }
-       unlock_kernel();
-       return error;
-}
-
-/*
- * nat_hdr_rename()
- *
- * This is the rename() entry in the inode_operations structure for
- * Netatalk header directories.  The purpose is to rename an existing
- * file given the inode for the current directory and the name 
- * (and its length) of the existing file and the inode for the new
- * directory and the name (and its length) of the new file/directory.
- *
- * WE NEVER MOVE ANYTHING.
- * In non-afpd-compatible mode:
- *   We return -EPERM.
- * In afpd-compatible mode:
- *   If the source header doesn't exist, we return -ENOENT.
- *   If the destination is not a header directory we return -EPERM.
- *   We return success if the destination is also a header directory
- *    and the header exists or is ".Parent".
- */
-static int nat_hdr_rename(struct inode *old_dir, struct dentry *old_dentry,
-                         struct inode *new_dir, struct dentry *new_dentry)
-{
-       struct hfs_cat_entry *entry;
-       int error = 0;
-
-       lock_kernel();
-       entry = HFS_I(old_dir)->entry;
-       if (!HFS_SB(old_dir->i_sb)->s_afpd) {
-               /* Not in AFPD compatibility mode */
-               error = -EPERM;
-       } else {
-               struct hfs_name cname;
-
-               hfs_nameout(old_dir, &cname, old_dentry->d_name.name,
-                           old_dentry->d_name.len);
-               if (!hfs_streq(cname.Name, cname.Len, 
-                              DOT_PARENT->Name, DOT_PARENT_LEN)) {
-                       struct hfs_cat_entry *victim;
-                       struct hfs_cat_key key;
-
-                       hfs_cat_build_key(entry->cnid, &cname, &key);
-                       victim = hfs_cat_get(entry->mdb, &key);
-
-                       if (victim) {
-                               /* pretend to succeed */
-                               hfs_cat_put(victim);
-                       } else {
-                               error = -ENOENT;
-                       }
-               }
-
-               if (!error && (HFS_ITYPE(new_dir->i_ino) != HFS_NAT_HDIR)) {
-                       error = -EPERM;
-               }
-       }
-       unlock_kernel();
-       return error;
-}
index 4b7d36f5f2fb3730ca88a26bdbb261a1030826f4..a9f4e23f715a2bd79af190e87f8c8eb8ae848c25 100644 (file)
 /*
- * linux/fs/hfs/extent.c
+ *  linux/fs/hfs/extent.c
  *
  * Copyright (C) 1995-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * This file contains the functions related to the extents B-tree.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
  */
 
-#include "hfs.h"
+#include <linux/pagemap.h>
 
-/*================ File-local data type ================*/
-
-/* An extent record on disk*/
-struct hfs_raw_extent {
-       hfs_word_t      block1;
-       hfs_word_t      length1;
-       hfs_word_t      block2;
-       hfs_word_t      length2;
-       hfs_word_t      block3;
-       hfs_word_t      length3;
-};
+#include "hfs_fs.h"
+#include "btree.h"
 
 /*================ File-local functions ================*/
 
 /*
  * build_key
  */
-static inline void build_key(struct hfs_ext_key *key,
-                            const struct hfs_fork *fork, hfs_u16 block)
+static void hfs_ext_build_key(hfs_btree_key *key, u32 cnid, u16 block, u8 type)
 {
-       key->KeyLen = 7;
-       key->FkType = fork->fork;
-       hfs_put_nl(fork->entry->cnid, key->FNum);
-       hfs_put_hs(block,             key->FABN);
-}
-
-
-/*
- * lock_bitmap()
- *
- * Get an exclusive lock on the B-tree bitmap.
- */
-static inline void lock_bitmap(struct hfs_mdb *mdb) {
-       down(&mdb->bitmap_sem);
+       key->key_len = 7;
+       key->ext.FkType = type;
+       key->ext.FNum = cpu_to_be32(cnid);
+       key->ext.FABN = cpu_to_be16(block);
 }
 
 /*
- * unlock_bitmap()
+ * hfs_ext_compare()
  *
- * Relinquish an exclusive lock on the B-tree bitmap.
- */
-static inline void unlock_bitmap(struct hfs_mdb *mdb) {
-       up(&mdb->bitmap_sem);
-}
+ * Description:
+ *   This is the comparison function used for the extents B-tree.  In
+ *   comparing extent B-tree entries, the file id is the most
+ *   significant field (compared as unsigned ints); the fork type is
+ *   the second most significant field (compared as unsigned chars);
+ *   and the allocation block number field is the least significant
+ *   (compared as unsigned ints).
+ * Input Variable(s):
+ *   struct hfs_ext_key *key1: pointer to the first key to compare
+ *   struct hfs_ext_key *key2: pointer to the second key to compare
+ * Output Variable(s):
+ *   NONE
+ * Returns:
+ *   int: negative if key1<key2, positive if key1>key2, and 0 if key1==key2
+ * Preconditions:
+ *   key1 and key2 point to "valid" (struct hfs_ext_key)s.
+ * Postconditions:
+ *   This function has no side-effects */
+int hfs_ext_keycmp(const btree_key *key1, const btree_key *key2)
+{
+       unsigned int tmp;
+       int retval;
 
-/*
- * dump_ext()
- *
- * prints the content of a extent for debugging purposes.
- */
-#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL)
-static void dump_ext(const char *msg, const struct hfs_extent *e) {
-       if (e) {
-               hfs_warn("%s (%d-%d) (%d-%d) (%d-%d)\n", msg,
-                        e->start,
-                        e->start + e->length[0] - 1,
-                        e->start + e->length[0],
-                        e->start + e->length[0] + e->length[1] - 1,
-                        e->start + e->length[0] + e->length[1],
-                        e->end);
+       tmp = be32_to_cpu(key1->ext.FNum) - be32_to_cpu(key2->ext.FNum);
+       if (tmp != 0) {
+               retval = (int)tmp;
        } else {
-               hfs_warn("%s NULL\n", msg);
+               tmp = (unsigned char)key1->ext.FkType - (unsigned char)key2->ext.FkType;
+               if (tmp != 0) {
+                       retval = (int)tmp;
+               } else {
+                       retval = (int)(be16_to_cpu(key1->ext.FABN)
+                                      - be16_to_cpu(key2->ext.FABN));
+               }
        }
-}
-#else
-#define dump_ext(A,B) {}
-#endif
-
-/*
- * read_extent()
- * 
- * Initializes a (struct hfs_extent) from a (struct hfs_raw_extent) and
- * the number of the starting block for the extent.
- *
- * Note that the callers must check that to,from != NULL
- */
-static void read_extent(struct hfs_extent *to,
-                       const struct hfs_raw_extent *from,
-                       hfs_u16 start)
-{
-       to->start = start;
-       to->block[0]  = hfs_get_hs(from->block1);
-       to->length[0] = hfs_get_hs(from->length1);
-       to->block[1]  = hfs_get_hs(from->block2);
-       to->length[1] = hfs_get_hs(from->length2);
-       to->block[2]  = hfs_get_hs(from->block3);
-       to->length[2] = hfs_get_hs(from->length3);
-       to->end = start + to->length[0] + to->length[1] + to->length[2] - 1;
-       to->next = to->prev = NULL;
-       to->count = 0;
+       return retval;
 }
 
 /*
- * write_extent()
- * 
- * Initializes a (struct hfs_raw_extent) from a (struct hfs_extent).
+ * hfs_ext_find_block
  *
- * Note that the callers must check that to,from != NULL
+ * Find a block within an extent record
  */
-static void write_extent(struct hfs_raw_extent *to,
-                        const struct hfs_extent *from)
+static u16 hfs_ext_find_block(struct hfs_extent *ext, u16 off)
 {
-       hfs_put_hs(from->block[0], to->block1);
-       hfs_put_hs(from->length[0], to->length1);
-       hfs_put_hs(from->block[1], to->block2);
-       hfs_put_hs(from->length[1], to->length2);
-       hfs_put_hs(from->block[2], to->block3);
-       hfs_put_hs(from->length[2], to->length3);
-}
+       int i;
+       u16 count;
 
-/*
- * decode_extent()
- *
- * Given an extent record and allocation block offset into the file,
- * return the number of the corresponding allocation block on disk,
- * or -1 if the desired block is not mapped by the given extent.
- *
- * Note that callers must check that extent != NULL
- */
-static int decode_extent(const struct hfs_extent * extent, int block)
-{
-       if (!extent || (block < extent->start) || (block > extent->end) ||
-           (extent->end == (hfs_u16)(extent->start - 1))) {
-               return -1;
-       }
-       block -= extent->start;
-       if (block < extent->length[0]) {
-               return block + extent->block[0];
+       for (i = 0; i < 3; ext++, i++) {
+               count = be16_to_cpu(ext->count);
+               if (off < count)
+                       return be16_to_cpu(ext->block) + off;
+               off -= count;
        }
-       block -= extent->length[0];
-       if (block < extent->length[1]) {
-               return block + extent->block[1];
-       }
-       return block + extent->block[2] - extent->length[1];
+       /* panic? */
+       return 0;
 }
 
-/*
- * relse_ext()
- *
- * Reduce the reference count of an in-core extent record by one,
- * removing it from memory if the count falls to zero.
- */
-static void relse_ext(struct hfs_extent *ext)
+static int hfs_ext_block_count(struct hfs_extent *ext)
 {
-       if (--ext->count || !ext->start) {
-               return;
-       }
-       ext->prev->next = ext->next;
-       if (ext->next) {
-               ext->next->prev = ext->prev;
-       }
-       HFS_DELETE(ext);
+       int i;
+       u16 count = 0;
+
+       for (i = 0; i < 3; ext++, i++)
+               count += be16_to_cpu(ext->count);
+       return count;
 }
 
-/*
- * set_cache()
- * 
- * Changes the 'cache' field of the fork.
- */
-static inline void set_cache(struct hfs_fork *fork, struct hfs_extent *ext)
+static u16 hfs_ext_lastblock(struct hfs_extent *ext)
 {
-       struct hfs_extent *tmp = fork->cache;
+       int i;
 
-       ++ext->count;
-       fork->cache = ext;
-       relse_ext(tmp);
+       ext += 2;
+       for (i = 0; i < 2; ext--, i++)
+               if (ext->count)
+                       break;
+       return be16_to_cpu(ext->block) + be16_to_cpu(ext->count);
 }
 
-/*
- * find_ext()
- *
- * Given a pointer to a (struct hfs_file) and an allocation block
- * number in the file, find the extent record containing that block.
- * Returns a pointer to the extent record on success or NULL on failure.
- * The 'cache' field of 'fil' also points to the extent so it has a
- * reference count of at least 2.
- *
- * Callers must check that fil != NULL
- */
-static struct hfs_extent * find_ext(struct hfs_fork *fork, int alloc_block)
+static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd)
 {
-        struct hfs_cat_entry *entry = fork->entry;
-       struct hfs_btree *tr= entry->mdb->ext_tree;
-       struct hfs_ext_key target, *key;
-       struct hfs_brec brec;
-       struct hfs_extent *ext, *ptr;
-       int tmp;
-
-       if (alloc_block < 0) {
-               ext = &fork->first;
-               goto found;
-       }
-
-       ext = fork->cache;
-       if (!ext || (alloc_block < ext->start)) {
-               ext = &fork->first;
-       }
-       while (ext->next && (alloc_block > ext->end)) {
-               ext = ext->next;
-       }
-       if ((alloc_block <= ext->end) && (alloc_block >= ext->start)) {
-               goto found;
-       }
-
-       /* time to read more extents */
-       if (!HFS_NEW(ext)) {
-               goto bail3;
-       }
-
-       build_key(&target, fork, alloc_block);
-
-       tmp = hfs_bfind(&brec, tr, HFS_BKEY(&target), HFS_BFIND_READ_LE);
-       if (tmp < 0) {
-               goto bail2;
-       }
-
-       key = (struct hfs_ext_key *)brec.key;
-       if ((hfs_get_nl(key->FNum) != hfs_get_nl(target.FNum)) ||
-           (key->FkType != fork->fork)) {
-               goto bail1;
-       }
-               
-       read_extent(ext, brec.data, hfs_get_hs(key->FABN));
-       hfs_brec_relse(&brec, NULL);
-
-       if ((alloc_block > ext->end) && (alloc_block < ext->start)) {
-               /* something strange happened */
-               goto bail2;
-       }
-
-       ptr = fork->cache;
-       if (!ptr || (alloc_block < ptr->start)) {
-               ptr = &fork->first;
-       }
-       while (ptr->next && (alloc_block > ptr->end)) {
-               ptr = ptr->next;
-       }
-       if (ext->start == ptr->start) {
-               /* somebody beat us to it. */
-               HFS_DELETE(ext);
-               ext = ptr;
-       } else if (ext->start < ptr->start) {
-               /* insert just before ptr */
-               ptr->prev->next = ext;
-               ext->prev = ptr->prev;
-               ext->next = ptr;
-               ptr->prev = ext;
+       int res;
+
+       hfs_ext_build_key(fd->search_key, inode->i_ino, HFS_I(inode)->cached_start,
+                         HFS_IS_RSRC(inode) ?  HFS_FK_RSRC : HFS_FK_DATA);
+       res = hfs_brec_find(fd);
+       if (HFS_I(inode)->flags & HFS_FLG_EXT_NEW) {
+               if (res != -ENOENT)
+                       return;
+               hfs_brec_insert(fd, HFS_I(inode)->cached_extents, sizeof(hfs_extent_rec));
+               HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW);
        } else {
-               /* insert at end */
-               ptr->next = ext;
-               ext->prev = ptr;
+               if (res)
+                       return;
+               hfs_bnode_write(fd->bnode, HFS_I(inode)->cached_extents, fd->entryoffset, fd->entrylength);
+               HFS_I(inode)->flags &= ~HFS_FLG_EXT_DIRTY;
        }
- found:
-       ++ext->count; /* for return value */
-       set_cache(fork, ext);
-       return ext;
-
- bail1:
-       hfs_brec_relse(&brec, NULL);
- bail2:
-       HFS_DELETE(ext);
- bail3:
-       return NULL;
 }
 
-/*
- * delete_extent()
- *
- * Description:
- *   Deletes an extent record from a fork, reducing its physical length.
- * Input Variable(s):
- *   struct hfs_fork *fork: the fork
- *   struct hfs_extent *ext: the current last extent for 'fork'
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'fork' points to a valid (struct hfs_fork)
- *   'ext' point to a valid (struct hfs_extent) which is the last in 'fork'
- *    and which is not also the first extent in 'fork'.
- * Postconditions:
- *   The extent record has been removed if possible, and a warning has been
- *   printed otherwise.
- */
-static void delete_extent(struct hfs_fork *fork, struct hfs_extent *ext)
+void hfs_ext_write_extent(struct inode *inode)
 {
-       struct hfs_mdb *mdb = fork->entry->mdb;
-       struct hfs_ext_key key;
-       int error;
-
-       if (fork->cache == ext) {
-               set_cache(fork, ext->prev);
-       }
-       ext->prev->next = NULL;
-       if (ext->count != 1) {
-               hfs_warn("hfs_truncate: extent has count %d.\n", ext->count);
-       }
-
-       lock_bitmap(mdb);
-       error = hfs_clear_vbm_bits(mdb, ext->block[2], ext->length[2]);
-       if (error) {
-               hfs_warn("hfs_truncate: error %d freeing blocks.\n", error);
-       }
-       error = hfs_clear_vbm_bits(mdb, ext->block[1], ext->length[1]);
-       if (error) {
-               hfs_warn("hfs_truncate: error %d freeing blocks.\n", error);
-       }
-       error = hfs_clear_vbm_bits(mdb, ext->block[0], ext->length[0]);
-       if (error) {
-               hfs_warn("hfs_truncate: error %d freeing blocks.\n", error);
-       }
-       unlock_bitmap(mdb);
-
-       build_key(&key, fork, ext->start);
+       struct hfs_find_data fd;
 
-       error = hfs_bdelete(mdb->ext_tree, HFS_BKEY(&key));
-       if (error) {
-               hfs_warn("hfs_truncate: error %d deleting an extent.\n", error);
+       if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY) {
+               hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd);
+               __hfs_ext_write_extent(inode, &fd);
+               hfs_find_exit(&fd);
        }
-
-       HFS_DELETE(ext);
 }
 
-/*
- * new_extent()
- *
- * Description:
- *   Adds a new extent record to a fork, extending its physical length.
- * Input Variable(s):
- *   struct hfs_fork *fork: the fork to extend
- *   struct hfs_extent *ext: the current last extent for 'fork'
- *   hfs_u16 ablock: the number of allocation blocks in 'fork'.
- *   hfs_u16 start: first allocation block to add to 'fork'.
- *   hfs_u16 len: the number of allocation blocks to add to 'fork'.
- *   hfs_u32 ablksz: number of sectors in an allocation block.
- * Output Variable(s):
- *   NONE
- * Returns:
- *   (struct hfs_extent *) the new extent or NULL
- * Preconditions:
- *   'fork' points to a valid (struct hfs_fork)
- *   'ext' point to a valid (struct hfs_extent) which is the last in 'fork'
- *   'ablock', 'start', 'len' and 'ablksz' are what they claim to be.
- * Postconditions:
- *   If NULL is returned then no changes have been made to 'fork'.
- *   If the return value is non-NULL that it is the extent that has been
- *   added to 'fork' both in memory and on disk.  The 'psize' field of
- *   'fork' has been updated to reflect the new physical size.
- */
-static struct hfs_extent *new_extent(struct hfs_fork *fork,
-                                    struct hfs_extent *ext,
-                                    hfs_u16 ablock, hfs_u16 start,
-                                    hfs_u16 len, hfs_u16 ablksz)
+static inline int __hfs_ext_read_extent(struct hfs_find_data *fd, struct hfs_extent *extent,
+                                       u32 cnid, u32 block, u8 type)
 {
-       struct hfs_raw_extent raw;
-       struct hfs_ext_key key;
-       int error;
-
-       if (fork->entry->cnid == htonl(HFS_EXT_CNID)) {
-               /* Limit extents tree to the record in the MDB */
-               return NULL;
-       }
-
-       if (!HFS_NEW(ext->next)) {
-               return NULL;
-       }
-       ext->next->prev = ext;
-       ext->next->next = NULL;
-       ext = ext->next;
-       relse_ext(ext->prev);
-
-       ext->start = ablock;
-       ext->block[0] = start;
-       ext->length[0] = len;
-       ext->block[1] = 0;
-       ext->length[1] = 0;
-       ext->block[2] = 0;
-       ext->length[2] = 0;
-       ext->end = ablock + len - 1;
-       ext->count = 1;
-
-       write_extent(&raw, ext);
-       
-       build_key(&key, fork, ablock);
-
-       error = hfs_binsert(fork->entry->mdb->ext_tree, 
-                           HFS_BKEY(&key), &raw, sizeof(raw));
-       if (error) {
-               ext->prev->next = NULL;
-               HFS_DELETE(ext);
-               return NULL;
-       }
-       set_cache(fork, ext);
-       return ext;
+       int res;
+
+       hfs_ext_build_key(fd->search_key, cnid, block, type);
+       fd->key->ext.FNum = 0;
+       res = hfs_brec_find(fd);
+       if (res && res != -ENOENT)
+               return res;
+       if (fd->key->ext.FNum != fd->search_key->ext.FNum ||
+           fd->key->ext.FkType != fd->search_key->ext.FkType)
+               return -ENOENT;
+       if (fd->entrylength != sizeof(hfs_extent_rec))
+               return -EIO;
+       hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfs_extent_rec));
+       return 0;
 }
 
-/*
- * update_ext()
- *
- * Given a (struct hfs_fork) write an extent record back to disk.
- */
-static void update_ext(struct hfs_fork *fork, struct hfs_extent *ext)
+static inline int __hfs_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block)
 {
-       struct hfs_ext_key target;
-       struct hfs_brec brec;
+       int res;
 
-       if (ext->start) {
-               build_key(&target, fork, ext->start);
+       if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY)
+               __hfs_ext_write_extent(inode, fd);
 
-               if (!hfs_bfind(&brec, fork->entry->mdb->ext_tree,
-                              HFS_BKEY(&target), HFS_BFIND_WRITE)) {
-                       write_extent(brec.data, ext);
-                       hfs_brec_relse(&brec, NULL);
-               }
-       }
-}
-
-/*
- * zero_blocks()
- * 
- * Zeros-out 'num' allocation blocks beginning with 'start'.
- */
-static int zero_blocks(struct hfs_mdb *mdb, int start, int num) {
-       hfs_buffer buf;
-       int end;
-       int j;
-
-       start = mdb->fs_start + start * mdb->alloc_blksz;
-       end = start + num * mdb->alloc_blksz;
-
-       for (j=start; j<end; ++j) {
-               if (hfs_buffer_ok(buf = hfs_buffer_get(mdb->sys_mdb, j, 0))) {
-                       memset(hfs_buffer_data(buf), 0, HFS_SECTOR_SIZE);
-                       hfs_buffer_dirty(buf);
-                       hfs_buffer_put(buf);
-               }
+       res = __hfs_ext_read_extent(fd, HFS_I(inode)->cached_extents, inode->i_ino,
+                                   block, HFS_IS_RSRC(inode) ? HFS_FK_RSRC : HFS_FK_DATA);
+       if (!res) {
+               HFS_I(inode)->cached_start = be16_to_cpu(fd->key->ext.FABN);
+               HFS_I(inode)->cached_blocks = hfs_ext_block_count(HFS_I(inode)->cached_extents);
+       } else {
+               HFS_I(inode)->cached_start = HFS_I(inode)->cached_blocks = 0;
+               HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW);
        }
-       return 0;
+       return res;
 }
 
-/*
- * shrink_fork()
- *
- * Try to remove enough allocation blocks from 'fork'
- * so that it is 'ablocks' allocation blocks long. 
- */
-static void shrink_fork(struct hfs_fork *fork, int ablocks)
+static int hfs_ext_read_extent(struct inode *inode, u16 block)
 {
-       struct hfs_mdb *mdb = fork->entry->mdb;
-       struct hfs_extent *ext;
-       int i, error, next, count;
-       hfs_u32 ablksz = mdb->alloc_blksz;
-
-       next =  (fork->psize / ablksz) - 1;
-       ext = find_ext(fork, next);
-       while (ext && ext->start && (ext->start >= ablocks)) {
-               next = ext->start - 1;
-               delete_extent(fork, ext);
-               ext = find_ext(fork, next);
-       }
-       if (!ext) {
-               fork->psize = (next + 1) * ablksz;
-               return;
-       }
+       struct hfs_find_data fd;
+       int res;
 
-       if ((count = next + 1 - ablocks) > 0) {
-               for (i=2; (i>=0) && !ext->length[i]; --i) {};
-               lock_bitmap(mdb);
-               while (count && (ext->length[i] <= count)) {
-                       ext->end -= ext->length[i];
-                       count -= ext->length[i];
-                       error = hfs_clear_vbm_bits(mdb, ext->block[i],
-                                                  ext->length[i]);
-                       if (error) {
-                               hfs_warn("hfs_truncate: error %d freeing "
-                                      "blocks.\n", error);
-                       }
-                       ext->block[i] = ext->length[i] = 0;
-                       --i;
-               }
-               if (count) {
-                       ext->end -= count;
-                       ext->length[i] -= count;
-                       error = hfs_clear_vbm_bits(mdb, ext->block[i] +
-                                                      ext->length[i], count);
-                       if (error) {
-                               hfs_warn("hfs_truncate: error %d freeing "
-                                      "blocks.\n", error);
-                       }
-               }
-               unlock_bitmap(mdb);
-               update_ext(fork, ext);
-       }
+       if (block >= HFS_I(inode)->cached_start &&
+           block < HFS_I(inode)->cached_start + HFS_I(inode)->cached_blocks)
+               return 0;
 
-       fork->psize = ablocks * ablksz;
+       hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd);
+       res = __hfs_ext_cache_extent(&fd, inode, block);
+       hfs_find_exit(&fd);
+       return res;
 }
 
-/*
- * grow_fork()
- *
- * Try to add enough allocation blocks to 'fork'
- * so that it is 'ablock' allocation blocks long. 
- */
-static int grow_fork(struct hfs_fork *fork, int ablocks)
+static void hfs_dump_extent(struct hfs_extent *extent)
 {
-       struct hfs_cat_entry *entry = fork->entry;
-       struct hfs_mdb *mdb = entry->mdb;
-       struct hfs_extent *ext;
-       int i, start, err;
-       hfs_u16 need, len=0;
-       hfs_u32 ablksz = mdb->alloc_blksz;
-       hfs_u32 blocks, clumpablks;
-
-       blocks = fork->psize;
-       need = ablocks - blocks/ablksz;
-       if (need < 1) { /* no need to grow the fork */
-               return 0;
-       }
-
-       /* round up to clumpsize */
-       if (entry->u.file.clumpablks) {
-               clumpablks = entry->u.file.clumpablks;
-       } else {
-               clumpablks = mdb->clumpablks;
-       }
-       need = ((need + clumpablks - 1) / clumpablks) * clumpablks;
+       int i;
 
-       /* find last extent record and try to extend it */
-       if (!(ext = find_ext(fork, blocks/ablksz - 1))) {
-               /* somehow we couldn't find the end of the file! */
-               return -1;
-       }
+       dprint(DBG_EXTENT, "   ");
+       for (i = 0; i < 3; i++)
+               dprint(DBG_EXTENT, " %u:%u", be16_to_cpu(extent[i].block),
+                                be16_to_cpu(extent[i].count));
+       dprint(DBG_EXTENT, "\n");
+}
 
-       /* determine which is the last used extent in the record */
-       /* then try to allocate the blocks immediately following it */
-       for (i=2; (i>=0) && !ext->length[i]; --i) {};
-       if (i>=0) {
-               /* try to extend the last extent */
-               start = ext->block[i] + ext->length[i];
-
-               err = 0;
-               lock_bitmap(mdb);
-               len = hfs_vbm_count_free(mdb, start);
-               if (!len) {
-                       unlock_bitmap(mdb);
-                       goto more_extents;
-               }
-               if (need < len) {
-                       len = need;
-               }
-               err = hfs_set_vbm_bits(mdb, start, len);
-               unlock_bitmap(mdb);
-               if (err) {
-                       relse_ext(ext);
-                       return -1;
-               }
-       
-               zero_blocks(mdb, start, len);
-       
-               ext->length[i] += len;
-               ext->end += len;
-               blocks = (fork->psize += len * ablksz);
-               need -= len;
-               update_ext(fork, ext);
+static int hfs_add_extent(struct hfs_extent *extent, u16 offset,
+                         u16 alloc_block, u16 block_count)
+{
+       u16 count, start;
+       int i;
+
+       hfs_dump_extent(extent);
+       for (i = 0; i < 3; extent++, i++) {
+               count = be16_to_cpu(extent->count);
+               if (offset == count) {
+                       start = be16_to_cpu(extent->block);
+                       if (alloc_block != start + count) {
+                               if (++i >= 3)
+                                       return -ENOSPC;
+                               extent++;
+                               extent->block = cpu_to_be16(alloc_block);
+                       } else
+                               block_count += count;
+                       extent->count = cpu_to_be16(block_count);
+                       return 0;
+               } else if (offset < count)
+                       break;
+               offset -= count;
        }
+       /* panic? */
+       return -EIO;
+}
 
-more_extents:
-       /* add some more extents */
-       while (need) {
-               len = need;
-               err = 0;
-               lock_bitmap(mdb);
-               start = hfs_vbm_search_free(mdb, &len);
-               if (need < len) {
-                       len = need;
-               }
-               err = hfs_set_vbm_bits(mdb, start, len);
-               unlock_bitmap(mdb);
-               if (!len || err) {
-                       relse_ext(ext);
-                       return -1;
-               }
-               zero_blocks(mdb, start, len);
-
-               /* determine which is the first free extent in the record */
-               for (i=0; (i<3) && ext->length[i]; ++i) {};
-               if (i < 3) {
-                       ext->block[i] = start;
-                       ext->length[i] = len;
-                       ext->end += len;
-                       update_ext(fork, ext);
+int hfs_free_extents(struct super_block *sb, struct hfs_extent *extent,
+                    u16 offset, u16 block_nr)
+{
+       u16 count, start;
+       int i;
+
+       hfs_dump_extent(extent);
+       for (i = 0; i < 3; extent++, i++) {
+               count = be16_to_cpu(extent->count);
+               if (offset == count)
+                       goto found;
+               else if (offset < count)
+                       break;
+               offset -= count;
+       }
+       /* panic? */
+       return -EIO;
+found:
+       for (;;) {
+               start = be16_to_cpu(extent->block);
+               if (count <= block_nr) {
+                       hfs_clear_vbm_bits(sb, start, count);
+                       extent->block = 0;
+                       extent->count = 0;
+                       block_nr -= count;
                } else {
-                       if (!(ext = new_extent(fork, ext, blocks/ablksz,
-                                              start, len, ablksz))) {
-                               lock_bitmap(mdb);
-                               hfs_clear_vbm_bits(mdb, start, len);
-                               unlock_bitmap(mdb);
-                               return -1;
-                       }
+                       count -= block_nr;
+                       hfs_clear_vbm_bits(sb, start + count, block_nr);
+                       extent->count = cpu_to_be16(count);
+                       block_nr = 0;
                }
-               blocks = (fork->psize += len * ablksz);
-               need -= len;
+               if (!block_nr || !i)
+                       return 0;
+               i--;
+               extent--;
+               count = be16_to_cpu(extent->count);
        }
-       set_cache(fork, ext);
-       relse_ext(ext);
-       return 0;
 }
 
-/*================ Global functions ================*/
-
-/*
- * hfs_ext_compare()
- *
- * Description:
- *   This is the comparison function used for the extents B-tree.  In
- *   comparing extent B-tree entries, the file id is the most
- *   significant field (compared as unsigned ints); the fork type is
- *   the second most significant field (compared as unsigned chars);
- *   and the allocation block number field is the least significant
- *   (compared as unsigned ints).
- * Input Variable(s):
- *   struct hfs_ext_key *key1: pointer to the first key to compare
- *   struct hfs_ext_key *key2: pointer to the second key to compare
- * Output Variable(s):
- *   NONE
- * Returns:
- *   int: negative if key1<key2, positive if key1>key2, and 0 if key1==key2
- * Preconditions:
- *   key1 and key2 point to "valid" (struct hfs_ext_key)s.
- * Postconditions:
- *   This function has no side-effects */
-int hfs_ext_compare(const struct hfs_ext_key *key1,
-                   const struct hfs_ext_key *key2)
+int hfs_free_fork(struct super_block *sb, struct hfs_cat_file *file, int type)
 {
-       unsigned int tmp;
-       int retval;
-
-       tmp = hfs_get_hl(key1->FNum) - hfs_get_hl(key2->FNum);
-       if (tmp != 0) {
-               retval = (int)tmp;
+       struct hfs_find_data fd;
+       u32 total_blocks, blocks, start;
+       u32 cnid = be32_to_cpu(file->FlNum);
+       struct hfs_extent *extent;
+       int res, i;
+
+       if (type == HFS_FK_DATA) {
+               total_blocks = file->PyLen;
+               extent = file->ExtRec;
        } else {
-               tmp = (unsigned char)key1->FkType - (unsigned char)key2->FkType;
-               if (tmp != 0) {
-                       retval = (int)tmp;
-               } else {
-                       retval = (int)(hfs_get_hs(key1->FABN)
-                                      - hfs_get_hs(key2->FABN));
-               }
+               total_blocks = file->RPyLen;
+               extent = file->RExtRec;
        }
-       return retval;
-}
+       total_blocks = be32_to_cpu(total_blocks) / HFS_SB(sb)->alloc_blksz;
+       if (!total_blocks)
+               return 0;
 
-/*
- * hfs_extent_adj()
- *
- * Given an hfs_fork shrink or grow the fork to hold the
- * forks logical size.
- */
-void hfs_extent_adj(struct hfs_fork *fork)
-{
-       if (fork) {
-               hfs_u32 blks, ablocks, ablksz;
+       blocks = 0;
+       for (i = 0; i < 3; extent++, i++)
+               blocks += be16_to_cpu(extent[i].count);
 
-               if (fork->lsize > HFS_FORK_MAX) {
-                       fork->lsize = HFS_FORK_MAX;
-               }
+       res = hfs_free_extents(sb, extent, blocks, blocks);
+       if (res)
+               return res;
+       if (total_blocks == blocks)
+               return 0;
 
-               blks = (fork->lsize+HFS_SECTOR_SIZE-1) >> HFS_SECTOR_SIZE_BITS;
-               ablksz = fork->entry->mdb->alloc_blksz;
-               ablocks = (blks + ablksz - 1) / ablksz;
-
-               if (blks > fork->psize) {
-                       grow_fork(fork, ablocks);
-                       if (blks > fork->psize) {
-                               fork->lsize =
-                                       fork->psize >> HFS_SECTOR_SIZE_BITS;
-                       }
-               } else if (blks < fork->psize) {
-                       shrink_fork(fork, ablocks);
-               }
-       }
+       hfs_find_init(HFS_SB(sb)->ext_tree, &fd);
+       do {
+               res = __hfs_ext_read_extent(&fd, extent, cnid, total_blocks, type);
+               if (res)
+                       break;
+               start = be16_to_cpu(fd.key->ext.FABN);
+               hfs_free_extents(sb, extent, total_blocks - start, total_blocks);
+               hfs_brec_remove(&fd);
+               total_blocks = start;
+       } while (total_blocks > blocks);
+       hfs_find_exit(&fd);
+
+       return res;
 }
 
 /*
- * hfs_extent_map()
- *
- * Given an hfs_fork and a block number within the fork, return the
- * number of the corresponding physical block on disk, or zero on
- * error.
+ * hfs_get_block
  */
-int hfs_extent_map(struct hfs_fork *fork, int block, int create) 
+int hfs_get_block(struct inode *inode, sector_t block,
+                 struct buffer_head *bh_result, int create)
 {
-       int ablksz, ablock, offset, tmp;
-       struct hfs_extent *ext;
+       struct super_block *sb;
+       u16 dblock, ablock;
+       int res;
+
+       sb = inode->i_sb;
+       /* Convert inode block to disk allocation block */
+       ablock = (u32)block / HFS_SB(sb)->fs_div;
+
+       if (block >= inode->i_blocks) {
+               if (block > inode->i_blocks || !create)
+                       return -EIO;
+               if (ablock >= HFS_I(inode)->alloc_blocks) {
+                       res = hfs_extend_file(inode);
+                       if (res)
+                               return res;
+               }
+       } else
+               create = 0;
 
-       if (!fork || !fork->entry || !fork->entry->mdb) {
-               return 0;
+       if (ablock < HFS_I(inode)->first_blocks) {
+               dblock = hfs_ext_find_block(HFS_I(inode)->first_extents, ablock);
+               goto done;
        }
 
-#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL)
-       hfs_warn("hfs_extent_map: ablock %d of file %d, fork %d\n",
-                block, fork->entry->cnid, fork->fork);
-#endif
-
-       if (block < 0) {
-               hfs_warn("hfs_extent_map: block < 0\n");
-               return 0;
-       }
-       if (block > (HFS_FORK_MAX >> HFS_SECTOR_SIZE_BITS)) {
-               hfs_warn("hfs_extent_map: block(0x%08x) > big; cnid=%d "
-                        "fork=%d\n", block, fork->entry->cnid, fork->fork);
-               return 0;
-       }
-       ablksz = fork->entry->mdb->alloc_blksz;
-       offset = fork->entry->mdb->fs_start + (block % ablksz);
-       ablock = block / ablksz;
-       
-       if (block >= fork->psize) {
-               if (!create || (grow_fork(fork, ablock + 1) < 0))
-                       return 0;
+       down(&HFS_I(inode)->extents_lock);
+       res = hfs_ext_read_extent(inode, ablock);
+       if (!res)
+               dblock = hfs_ext_find_block(HFS_I(inode)->cached_extents,
+                                           ablock - HFS_I(inode)->cached_start);
+       else {
+               up(&HFS_I(inode)->extents_lock);
+               return -EIO;
        }
+       up(&HFS_I(inode)->extents_lock);
 
-#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL)
-       hfs_warn("(lblock %d offset %d)\n", ablock, offset);
-#endif
-
-       if ((ext = find_ext(fork, ablock))) {
-               dump_ext("trying new: ", ext);
-               tmp = decode_extent(ext, ablock);
-               relse_ext(ext);
-               if (tmp >= 0) {
-                       return tmp*ablksz + offset;
-               }
-       } 
+done:
+       map_bh(bh_result, sb, HFS_SB(sb)->fs_start +
+              dblock * HFS_SB(sb)->fs_div +
+              (u32)block % HFS_SB(sb)->fs_div);
 
+       if (create) {
+               set_buffer_new(bh_result);
+               HFS_I(inode)->phys_size += sb->s_blocksize;
+               inode->i_blocks++;
+               mark_inode_dirty(inode);
+       }
        return 0;
 }
 
-/*
- * hfs_extent_out()
- *
- * Copy the first extent record from a (struct hfs_fork) to a (struct
- * raw_extent), record (normally the one in the catalog entry).
- */
-void hfs_extent_out(const struct hfs_fork *fork, hfs_byte_t dummy[12])
+int hfs_extend_file(struct inode *inode)
 {
-       struct hfs_raw_extent *ext = (struct hfs_raw_extent *)dummy;
-
-       if (fork && ext) {
-               write_extent(ext, &fork->first);
-               dump_ext("extent out: ", &fork->first);
-       }
+       struct super_block *sb = inode->i_sb;
+       u32 start, len, goal;
+       int res;
+
+       down(&HFS_I(inode)->extents_lock);
+       if (HFS_I(inode)->alloc_blocks == HFS_I(inode)->first_blocks)
+               goal = hfs_ext_lastblock(HFS_I(inode)->first_extents);
+       else {
+               res = hfs_ext_read_extent(inode, HFS_I(inode)->alloc_blocks);
+               if (res)
+                       goto out;
+               goal = hfs_ext_lastblock(HFS_I(inode)->cached_extents);
+       }
+
+       len = HFS_I(inode)->clump_blocks;
+       start = hfs_vbm_search_free(sb, goal, &len);
+       if (!len) {
+               res = -ENOSPC;
+               goto out;
+       }
+
+       dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
+       if (HFS_I(inode)->alloc_blocks == HFS_I(inode)->first_blocks) {
+               if (!HFS_I(inode)->first_blocks) {
+                       dprint(DBG_EXTENT, "first extents\n");
+                       /* no extents yet */
+                       HFS_I(inode)->first_extents[0].block = cpu_to_be16(start);
+                       HFS_I(inode)->first_extents[0].count = cpu_to_be16(len);
+                       res = 0;
+               } else {
+                       /* try to append to extents in inode */
+                       res = hfs_add_extent(HFS_I(inode)->first_extents,
+                                            HFS_I(inode)->alloc_blocks,
+                                            start, len);
+                       if (res == -ENOSPC)
+                               goto insert_extent;
+               }
+               if (!res) {
+                       hfs_dump_extent(HFS_I(inode)->first_extents);
+                       HFS_I(inode)->first_blocks += len;
+               }
+       } else {
+               res = hfs_add_extent(HFS_I(inode)->cached_extents,
+                                    HFS_I(inode)->alloc_blocks -
+                                    HFS_I(inode)->cached_start,
+                                    start, len);
+               if (!res) {
+                       hfs_dump_extent(HFS_I(inode)->cached_extents);
+                       HFS_I(inode)->flags |= HFS_FLG_EXT_DIRTY;
+                       HFS_I(inode)->cached_blocks += len;
+               } else if (res == -ENOSPC)
+                       goto insert_extent;
+       }
+out:
+       up(&HFS_I(inode)->extents_lock);
+       if (!res) {
+               HFS_I(inode)->alloc_blocks += len;
+               mark_inode_dirty(inode);
+               if (inode->i_ino < HFS_FIRSTUSER_CNID)
+                       set_bit(HFS_FLG_ALT_MDB_DIRTY, &HFS_SB(sb)->flags);
+               set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
+               sb->s_dirt = 1;
+       }
+       return res;
+
+insert_extent:
+       dprint(DBG_EXTENT, "insert new extent\n");
+       hfs_ext_write_extent(inode);
+
+       memset(HFS_I(inode)->cached_extents, 0, sizeof(hfs_extent_rec));
+       HFS_I(inode)->cached_extents[0].block = cpu_to_be16(start);
+       HFS_I(inode)->cached_extents[0].count = cpu_to_be16(len);
+       hfs_dump_extent(HFS_I(inode)->cached_extents);
+       HFS_I(inode)->flags |= HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW;
+       HFS_I(inode)->cached_start = HFS_I(inode)->alloc_blocks;
+       HFS_I(inode)->cached_blocks = len;
+
+       res = 0;
+       goto out;
 }
 
-/*
- * hfs_extent_in()
- *
- * Copy an raw_extent to the 'first' and 'cache' fields of an hfs_fork.
- */
-void hfs_extent_in(struct hfs_fork *fork, const hfs_byte_t dummy[12])
+void hfs_file_truncate(struct inode *inode)
 {
-       const struct hfs_raw_extent *ext =
-               (const struct hfs_raw_extent *)dummy;
-
-       if (fork && ext) {
-               read_extent(&fork->first, ext, 0);
-               fork->cache = &fork->first;
-               fork->first.count = 2;
-               dump_ext("extent in: ", &fork->first);
+       struct super_block *sb = inode->i_sb;
+       struct hfs_find_data fd;
+       u16 blk_cnt, alloc_cnt, start;
+       u32 size;
+       int res;
+
+       dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n", inode->i_ino,
+              (long long)HFS_I(inode)->phys_size, inode->i_size);
+       if (inode->i_size > HFS_I(inode)->phys_size) {
+               struct address_space *mapping = inode->i_mapping;
+               struct page *page;
+               int res;
+
+               size = inode->i_size - 1;
+               page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT);
+               if (!page)
+                       return;
+               size &= PAGE_CACHE_SIZE - 1;
+               size++;
+               res = mapping->a_ops->prepare_write(NULL, page, size, size);
+               if (!res)
+                       res = mapping->a_ops->commit_write(NULL, page, size, size);
+               if (res)
+                       inode->i_size = HFS_I(inode)->phys_size;
+               unlock_page(page);
+               page_cache_release(page);
+               mark_inode_dirty(inode);
+               return;
        }
-}
-
-/* 
- * hfs_extent_free()
- *
- * Removes from memory all extents associated with 'fil'.
- */
-void hfs_extent_free(struct hfs_fork *fork)
-{
-       if (fork) {
-               set_cache(fork, &fork->first);
-
-               if (fork->first.next) {
-                       hfs_warn("hfs_extent_free: extents in use!\n");
+       size = inode->i_size + HFS_SB(sb)->alloc_blksz - 1;
+       blk_cnt = size / HFS_SB(sb)->alloc_blksz;
+       alloc_cnt = HFS_I(inode)->alloc_blocks;
+       if (blk_cnt == alloc_cnt)
+               goto out;
+
+       down(&HFS_I(inode)->extents_lock);
+       hfs_find_init(HFS_SB(sb)->ext_tree, &fd);
+       while (1) {
+               if (alloc_cnt == HFS_I(inode)->first_blocks) {
+                       hfs_free_extents(sb, HFS_I(inode)->first_extents,
+                                        alloc_cnt, alloc_cnt - blk_cnt);
+                       hfs_dump_extent(HFS_I(inode)->first_extents);
+                       HFS_I(inode)->first_blocks = blk_cnt;
+                       break;
                }
-       }
+               res = __hfs_ext_cache_extent(&fd, inode, alloc_cnt);
+               if (res)
+                       break;
+               start = HFS_I(inode)->cached_start;
+               hfs_free_extents(sb, HFS_I(inode)->cached_extents,
+                                alloc_cnt - start, alloc_cnt - blk_cnt);
+               hfs_dump_extent(HFS_I(inode)->cached_extents);
+               if (blk_cnt > start) {
+                       HFS_I(inode)->flags |= HFS_FLG_EXT_DIRTY;
+                       break;
+               }
+               alloc_cnt = start;
+               HFS_I(inode)->cached_start = HFS_I(inode)->cached_blocks = 0;
+               HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW);
+               hfs_brec_remove(&fd);
+       }
+       hfs_find_exit(&fd);
+       up(&HFS_I(inode)->extents_lock);
+
+       HFS_I(inode)->alloc_blocks = blk_cnt;
+out:
+       HFS_I(inode)->phys_size = inode->i_size;
+       mark_inode_dirty(inode);
+       inode->i_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
 }
diff --git a/fs/hfs/file.c b/fs/hfs/file.c
deleted file mode 100644 (file)
index 3d649c0..0000000
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * linux/fs/hfs/file.c
- *
- * Copyright (C) 1995, 1996  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the file-related functions which are independent of
- * which scheme is being used to represent forks.
- *
- * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- */
-
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
-#include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
-
-/*================ Forward declarations ================*/
-
-static hfs_rwret_t hfs_file_read(struct file *, char __user *, hfs_rwarg_t,
-                                loff_t *);
-static hfs_rwret_t hfs_file_write(struct file *, const char __user *,
-                                 hfs_rwarg_t, loff_t *);
-static void hfs_file_truncate(struct inode *);
-
-/*================ Global variables ================*/
-
-struct file_operations hfs_file_operations = {
-       .llseek         = generic_file_llseek,
-       .read           = hfs_file_read,
-       .write          = hfs_file_write,
-       .mmap           = generic_file_mmap,
-       .fsync          = file_fsync,
-};
-
-struct inode_operations hfs_file_inode_operations = {
-       .truncate       = hfs_file_truncate,
-       .setattr        = hfs_notify_change,
-};
-
-/*================ Variable-like macros ================*/
-
-/* maximum number of blocks to try to read in at once */
-#define NBUF 32
-
-/*================ File-local functions ================*/
-
-/*
- * hfs_getblk()
- *
- * Given an hfs_fork and a block number return the buffer_head for
- * that block from the fork.  If 'create' is non-zero then allocate
- * the necessary block(s) to the fork.
- */
-struct buffer_head *hfs_getblk(struct hfs_fork *fork, int block, int create)
-{
-       int tmp;
-       struct super_block *sb = fork->entry->mdb->sys_mdb;
-
-       tmp = hfs_extent_map(fork, block, create);
-
-       if (create) {
-               /* If writing the block, then we have exclusive access
-                  to the file until we return, so it can't have moved.
-               */
-               if (tmp) {
-                       hfs_cat_mark_dirty(fork->entry);
-                       return sb_getblk(sb, tmp);
-               }
-               return NULL;
-       } else {
-               /* If reading the block, then retry since the
-                  location on disk could have changed while
-                  we waited on the I/O in getblk to complete.
-               */
-               do {
-                       struct buffer_head *bh = sb_getblk(sb, tmp);
-                       int tmp2 = hfs_extent_map(fork, block, 0);
-
-                       if (tmp2 == tmp) {
-                               return bh;
-                       } else {
-                               /* The block moved or no longer exists. */
-                               brelse(bh);
-                               tmp = tmp2;
-                       }
-               } while (tmp != 0);
-
-               /* The block no longer exists. */
-               return NULL;
-       }
-}
-
-/*
- * hfs_get_block
- *
- * This is the hfs_get_block() field in the inode_operations structure for
- * "regular" (non-header) files.  The purpose is to translate an inode
- * and a block number within the corresponding file into a physical
- * block number.  This function just calls hfs_extent_map() to do the
- * real work and then stuffs the appropriate info into the buffer_head.
- */
-int hfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
-{
-       unsigned long phys;
-
-       phys = hfs_extent_map(HFS_I(inode)->fork, iblock, create);
-       if (phys) {
-               if (create)
-                       set_buffer_new(bh_result);
-               map_bh(bh_result, inode->i_sb, phys);
-               return 0;
-       }
-
-       if (!create)
-               return 0;
-
-       /* we tried to add stuff, but we couldn't. send back an out-of-space
-        * error. */
-       return -ENOSPC;
-}
-
-
-/*
- * hfs_file_read()
- *
- * This is the read field in the inode_operations structure for
- * "regular" (non-header) files.  The purpose is to transfer up to
- * 'count' bytes from the file corresponding to 'inode', beginning at
- * 'filp->offset' bytes into the file. The data is transferred to
- * user-space at the address 'buf'.  Returns the number of bytes
- * successfully transferred.  This function checks the arguments, does
- * some setup and then calls hfs_do_read() to do the actual transfer.  */
-static hfs_rwret_t hfs_file_read(struct file *filp, char __user *buf, 
-                                hfs_rwarg_t count, loff_t *ppos)
-{
-        struct inode *inode = filp->f_dentry->d_inode;
-       hfs_s32 read, left, pos, size;
-
-       if (!S_ISREG(inode->i_mode)) {
-               hfs_warn("hfs_file_read: mode = %07o\n",inode->i_mode);
-               return -EINVAL;
-       }
-       pos = *ppos;
-       if (pos >= HFS_FORK_MAX) {
-               return 0;
-       }
-       size = inode->i_size;
-       if (pos > size) {
-               left = 0;
-       } else {
-               left = size - pos;
-       }
-       if (left > count) {
-               left = count;
-       }
-       if (left <= 0) {
-               return 0;
-       }
-       if ((read = hfs_do_read(inode, HFS_I(inode)->fork, pos, buf, left)) > 0) {
-               *ppos += read;
-       }
-
-       return read;
-}
-
-/*
- * hfs_file_write()
- *
- * This is the write() entry in the file_operations structure for
- * "regular" files.  The purpose is to transfer up to 'count' bytes
- * to the file corresponding to 'inode' beginning at offset
- * 'file->f_pos' from user-space at the address 'buf'.  The return
- * value is the number of bytes actually transferred.
- */
-static hfs_rwret_t hfs_file_write(struct file *filp, const char __user *buf,
-                                 hfs_rwarg_t count, loff_t *ppos)
-{
-        struct inode    *inode = filp->f_dentry->d_inode;
-       struct hfs_fork *fork = HFS_I(inode)->fork;
-       hfs_s32 written, pos;
-
-       if (!S_ISREG(inode->i_mode)) {
-               hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode);
-               return -EINVAL;
-       }
-
-       pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
-
-       if (pos >= HFS_FORK_MAX) {
-               return 0;
-       }
-       if (count > HFS_FORK_MAX) {
-               count = HFS_FORK_MAX;
-       }
-       if ((written = hfs_do_write(inode, fork, pos, buf, count)) > 0)
-               pos += written;
-
-       *ppos = pos;
-       if (*ppos > inode->i_size) {
-               inode->i_size = *ppos;
-               mark_inode_dirty(inode);
-       }
-
-       return written;
-}
-
-/*
- * hfs_file_truncate()
- *
- * This is the truncate() entry in the file_operations structure for
- * "regular" files.  The purpose is to change the length of the file
- * corresponding to the given inode.  Changes can either lengthen or
- * shorten the file.
- */
-static void hfs_file_truncate(struct inode * inode)
-{
-       struct hfs_fork *fork;
-
-       lock_kernel();
-       fork = HFS_I(inode)->fork;
-       fork->lsize = inode->i_size;
-       hfs_extent_adj(fork);
-       hfs_cat_mark_dirty(HFS_I(inode)->entry);
-
-       inode->i_size = fork->lsize;
-       inode->i_blocks = fork->psize;
-       mark_inode_dirty(inode);
-       unlock_kernel();
-}
-
-/*
- * xlate_to_user()
- *
- * Like copy_to_user() while translating CR->NL.
- */
-static inline void xlate_to_user(char __user *buf, const char *data, int count)
-{
-       char ch;
-
-       while (count--) {
-               ch = *(data++);
-               put_user((ch == '\r') ? '\n' : ch, buf++);
-       }
-}
-
-/*
- * xlate_from_user()
- *
- * Like copy_from_user() while translating NL->CR;
- */
-static inline
-int xlate_from_user(char *data, const char __user *buf, int count)
-{
-       int i;
-
-       i = copy_from_user(data, buf, count);
-       count -= i;
-       while (count--) {
-               if (*data == '\n') {
-                       *data = '\r';
-               }
-               ++data;
-       }
-       return i;
-}
-
-/*================ Global functions ================*/
-
-/*
- * hfs_do_read()
- *
- * This function transfers actual data from disk to user-space memory,
- * returning the number of bytes successfully transferred.  'fork' tells
- * which file on the disk to read from.  'pos' gives the offset into
- * the Linux file at which to begin the transfer.  Note that this will
- * differ from 'filp->offset' in the case of an AppleDouble header file
- * due to the block of metadata at the beginning of the file, which has
- * no corresponding place in the HFS file.  'count' tells how many
- * bytes to transfer.  'buf' gives an address in user-space to transfer
- * the data to.
- * 
- * This is based on Linus's minix_file_read().
- * It has been changed to take into account that HFS files have no holes.
- */
-hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork *fork, hfs_u32 pos,
-                   char __user *buf, hfs_u32 count)
-{
-       hfs_s32 size, chars, offset, block, blocks, read = 0;
-       int bhrequest, uptodate;
-       int convert = HFS_I(inode)->convert;
-       struct buffer_head ** bhb, ** bhe;
-       struct buffer_head * bhreq[NBUF];
-       struct buffer_head * buflist[NBUF];
-
-       /* split 'pos' in to block and (byte) offset components */
-       block = pos >> HFS_SECTOR_SIZE_BITS;
-       offset = pos & (HFS_SECTOR_SIZE-1);
-
-       /* compute the logical size of the fork in blocks */
-       size = (fork->lsize + (HFS_SECTOR_SIZE-1)) >> HFS_SECTOR_SIZE_BITS;
-
-       /* compute the number of physical blocks to be transferred */
-       blocks = (count+offset+HFS_SECTOR_SIZE-1) >> HFS_SECTOR_SIZE_BITS;
-
-       bhb = bhe = buflist;
-
-       /* We do this in a two stage process.  We first try and
-          request as many blocks as we can, then we wait for the
-          first one to complete, and then we try and wrap up as many
-          as are actually done.
-          
-          This routine is optimized to make maximum use of the
-          various buffers and caches. */
-
-       do {
-               bhrequest = 0;
-               uptodate = 1;
-               while (blocks) {
-                       --blocks;
-                       *bhb = hfs_getblk(fork, block++, 0);
-
-                       if (!(*bhb)) {
-                               /* Since there are no holes in HFS files
-                                  we must have encountered an error.
-                                  So, stop adding blocks to the queue. */
-                               blocks = 0;
-                               break;
-                       }
-
-                       if (!buffer_uptodate(*bhb)) {
-                               uptodate = 0;
-                               bhreq[bhrequest++] = *bhb;
-                       }
-
-                       if (++bhb == &buflist[NBUF]) {
-                               bhb = buflist;
-                       }
-
-                       /* If the block we have on hand is uptodate,
-                          go ahead and complete processing. */
-                       if (uptodate) {
-                               break;
-                       }
-                       if (bhb == bhe) {
-                               break;
-                       }
-               }
-
-               /* If the only block in the queue is bad then quit */
-               if (!(*bhe)) {
-                       break;
-               }
-
-               /* Now request them all */
-               if (bhrequest) {
-                       ll_rw_block(READ, bhrequest, bhreq);
-               }
-
-               do {  /* Finish off all I/O that has actually completed */
-                       char *p;
-
-                       wait_on_buffer(*bhe);
-
-                       if (!buffer_uptodate(*bhe)) {
-                               /* read error? */
-                               brelse(*bhe);
-                               if (++bhe == &buflist[NBUF]) {
-                                       bhe = buflist;
-                               }
-                               count = 0;
-                               break;
-                       }
-
-                       if (count < HFS_SECTOR_SIZE - offset) {
-                               chars = count;
-                       } else {
-                               chars = HFS_SECTOR_SIZE - offset;
-                       }
-                       p = (*bhe)->b_data + offset;
-                       if (convert) {
-                               xlate_to_user(buf, p, chars);
-                       } else {
-                               chars -= copy_to_user(buf, p, chars);
-                               if (!chars) {
-                                       brelse(*bhe);
-                                       count = 0;
-                                       if (!read)
-                                               read = -EFAULT;
-                                       break;
-                               }
-                       }
-                       brelse(*bhe);
-                       count -= chars;
-                       buf += chars;
-                       read += chars;
-                       offset = 0;
-                       if (++bhe == &buflist[NBUF]) {
-                               bhe = buflist;
-                       }
-               } while (count && (bhe != bhb) && !buffer_locked(*bhe));
-       } while (count);
-
-       /* Release the read-ahead blocks */
-       while (bhe != bhb) {
-               brelse(*bhe);
-               if (++bhe == &buflist[NBUF]) {
-                       bhe = buflist;
-               }
-       }
-       if (!read) {
-               return -EIO;
-       }
-       return read;
-}
-/*
- * hfs_do_write()
- *
- * This function transfers actual data from user-space memory to disk,
- * returning the number of bytes successfully transferred.  'fork' tells
- * which file on the disk to write to.  'pos' gives the offset into
- * the Linux file at which to begin the transfer.  Note that this will
- * differ from 'filp->offset' in the case of an AppleDouble header file
- * due to the block of metadata at the beginning of the file, which has
- * no corresponding place in the HFS file.  'count' tells how many
- * bytes to transfer.  'buf' gives an address in user-space to transfer
- * the data from.
- * 
- * This is just a minor edit of Linus's minix_file_write().
- */
-hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork *fork, hfs_u32 pos,
-                    const char __user *buf, hfs_u32 count)
-{
-       hfs_s32 written, c;
-       struct buffer_head * bh;
-       char * p;
-       int convert = HFS_I(inode)->convert;
-
-       written = 0;
-       while (written < count) {
-               bh = hfs_getblk(fork, pos/HFS_SECTOR_SIZE, 1);
-               if (!bh) {
-                       if (!written) {
-                               written = -ENOSPC;
-                       }
-                       break;
-               }
-               c = HFS_SECTOR_SIZE - (pos % HFS_SECTOR_SIZE);
-               if (c > count - written) {
-                       c = count - written;
-               }
-               if (c != HFS_SECTOR_SIZE && !buffer_uptodate(bh)) {
-                       ll_rw_block(READ, 1, &bh);
-                       wait_on_buffer(bh);
-                       if (!buffer_uptodate(bh)) {
-                               brelse(bh);
-                               if (!written) {
-                                       written = -EIO;
-                               }
-                               break;
-                       }
-               }
-               p = (pos % HFS_SECTOR_SIZE) + bh->b_data;
-               c -= convert ? xlate_from_user(p, buf, c) :
-                       copy_from_user(p, buf, c);
-               if (!c) {
-                       brelse(bh);
-                       if (!written)
-                               written = -EFAULT;
-                       break;
-               }
-               pos += c;
-               written += c;
-               buf += c;
-               set_buffer_uptodate(bh);
-               mark_buffer_dirty(bh);
-               brelse(bh);
-       }
-       if (written > 0) {
-               struct hfs_cat_entry *entry = fork->entry;
-
-               inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-               if (pos > fork->lsize) {
-                       fork->lsize = pos;
-               }
-               entry->modify_date = hfs_u_to_mtime(get_seconds());
-               hfs_cat_mark_dirty(entry);
-       }
-       return written;
-}
-
-/*
- * hfs_file_fix_mode()
- *
- * Fixes up the permissions on a file after changing the write-inhibit bit.
- */
-void hfs_file_fix_mode(struct hfs_cat_entry *entry)
-{
-       struct dentry **de = entry->sys_entry;
-       int i;
-
-       if (entry->u.file.flags & HFS_FIL_LOCK) {
-               for (i = 0; i < 4; ++i) {
-                       if (de[i]) {
-                               de[i]->d_inode->i_mode &= ~S_IWUGO;
-                       }
-               }
-       } else {
-               for (i = 0; i < 4; ++i) {
-                       if (de[i]) {
-                               struct inode *inode = de[i]->d_inode;
-                               inode->i_mode |= S_IWUGO;
-                               inode->i_mode &= 
-                                 ~HFS_SB(inode->i_sb)->s_umask;
-                       }
-               }
-       }
-}
diff --git a/fs/hfs/file_cap.c b/fs/hfs/file_cap.c
deleted file mode 100644 (file)
index 500a016..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * linux/fs/hfs/file_cap.c
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the file_ops and inode_ops for the metadata
- * files under the CAP representation.
- *
- * The source code distribution of the Columbia AppleTalk Package for
- * UNIX, version 6.0, (CAP) was used as a specification of the
- * location and format of files used by CAP's Aufs.  No code from CAP
- * appears in hfs_fs.  hfs_fs is not a work ``derived'' from CAP in
- * the sense of intellectual property law.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- */
-
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
-#include <linux/smp_lock.h>
-
-/*================ Forward declarations ================*/
-static loff_t      cap_info_llseek(struct file *, loff_t,
-                                   int);
-static hfs_rwret_t cap_info_read(struct file *, char __user *,
-                                hfs_rwarg_t, loff_t *);
-static hfs_rwret_t cap_info_write(struct file *, const char __user *,
-                                 hfs_rwarg_t, loff_t *);
-/*================ Function-like macros ================*/
-
-/*
- * OVERLAPS()
- *
- * Determines if a given range overlaps the specified structure member
- */
-#define OVERLAPS(START, END, TYPE, MEMB) \
-       ((END > offsetof(TYPE, MEMB)) && \
-        (START < offsetof(TYPE, MEMB) + sizeof(((TYPE *)0)->MEMB)))
-
-/*================ Global variables ================*/
-
-struct file_operations hfs_cap_info_operations = {
-       .llseek         = cap_info_llseek,
-       .read           = cap_info_read,
-       .write          = cap_info_write,
-       .fsync          = file_fsync,
-};
-
-struct inode_operations hfs_cap_info_inode_operations = {
-       .setattr        = hfs_notify_change_cap,
-};
-
-/*================ File-local functions ================*/
-
-/*
- * cap_build_meta()
- *
- * Build the metadata structure.
- */
-static void cap_build_meta(struct hfs_cap_info *meta,
-                          struct hfs_cat_entry *entry)
-{
-       memset(meta, 0, sizeof(*meta));
-       memcpy(meta->fi_fndr, &entry->info, 32);
-       if ((entry->type == HFS_CDR_FIL) &&
-           (entry->u.file.flags & HFS_FIL_LOCK)) {
-               /* Couple the locked bit of the file to the
-                  AFP {write,rename,delete} inhibit bits. */
-               hfs_put_hs(HFS_AFP_RDONLY, meta->fi_attr);
-       }
-       meta->fi_magic1 = HFS_CAP_MAGIC1;
-       meta->fi_version = HFS_CAP_VERSION;
-       meta->fi_magic = HFS_CAP_MAGIC;
-       meta->fi_bitmap = HFS_CAP_LONGNAME;
-       memcpy(meta->fi_macfilename, entry->key.CName.Name,
-              entry->key.CName.Len);
-       meta->fi_datemagic = HFS_CAP_DMAGIC;
-       meta->fi_datevalid = HFS_CAP_MDATE | HFS_CAP_CDATE;
-       hfs_put_nl(hfs_m_to_htime(entry->create_date), meta->fi_ctime);
-       hfs_put_nl(hfs_m_to_htime(entry->modify_date), meta->fi_mtime);
-       hfs_put_nl(get_seconds(),                       meta->fi_utime);
-}
-
-static loff_t cap_info_llseek(struct file *file, loff_t offset, int origin)
-{
-       long long retval;
-
-       lock_kernel();
-
-       switch (origin) {
-               case 2:
-                       offset += file->f_dentry->d_inode->i_size;
-                       break;
-               case 1:
-                       offset += file->f_pos;
-       }
-       retval = -EINVAL;
-       if (offset>=0 && offset<=HFS_FORK_MAX) {
-               if (offset != file->f_pos) {
-                       file->f_pos = offset;
-               }
-               retval = offset;
-       }
-       unlock_kernel();
-       return retval;
-}
-
-/*
- * cap_info_read()
- *
- * This is the read() entry in the file_operations structure for CAP
- * metadata files.  The purpose is to transfer up to 'count' bytes
- * from the file corresponding to 'inode' beginning at offset
- * 'file->f_pos' to user-space at the address 'buf'.  The return value
- * is the number of bytes actually transferred.
- */
-static hfs_rwret_t cap_info_read(struct file *filp, char __user *buf,
-                                hfs_rwarg_t count, loff_t *ppos)
-{
-       struct inode *inode = filp->f_dentry->d_inode;
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
-       hfs_s32 left, size, read = 0;
-       hfs_u32 pos;
-
-       if (!S_ISREG(inode->i_mode)) {
-               hfs_warn("hfs_cap_info_read: mode = %07o\n", inode->i_mode);
-               return -EINVAL;
-       }
-
-       pos = *ppos;
-       if (pos > HFS_FORK_MAX) {
-               return 0;
-       }
-       size = inode->i_size;
-       if (pos > size) {
-               left = 0;
-       } else {
-               left = size - pos;
-       }
-       if (left > count) {
-               left = count;
-       }
-       if (left <= 0) {
-               return 0;
-       }
-
-       if (pos < sizeof(struct hfs_cap_info)) {
-               int memcount = sizeof(struct hfs_cap_info) - pos;
-               struct hfs_cap_info meta;
-
-               if (memcount > left) {
-                       memcount = left;
-               }
-               cap_build_meta(&meta, entry);
-               memcount -= copy_to_user(buf, ((char *)&meta) + pos, memcount);
-               left -= memcount;
-               read += memcount;
-               pos += memcount;
-               buf += memcount;
-       }
-
-       if (left > 0) {
-               clear_user(buf, left);
-               pos += left;
-       }
-
-       if (read) {
-               inode->i_atime = CURRENT_TIME;
-               *ppos = pos;
-               mark_inode_dirty(inode);
-       }
-
-       return read;
-}
-
-/*
- * cap_info_write()
- *
- * This is the write() entry in the file_operations structure for CAP
- * metadata files.  The purpose is to transfer up to 'count' bytes
- * to the file corresponding to 'inode' beginning at offset
- * '*ppos' from user-space at the address 'buf'.
- * The return value is the number of bytes actually transferred.
- */
-static hfs_rwret_t cap_info_write(struct file *filp, const char __user *buf, 
-                                 hfs_rwarg_t count, loff_t *ppos)
-{
-        struct inode *inode = filp->f_dentry->d_inode;
-       hfs_u32 pos;
-
-       if (!S_ISREG(inode->i_mode)) {
-               hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode);
-               return -EINVAL;
-       }
-       if (count <= 0) {
-               return 0;
-       }
-       
-       pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
-
-       if (pos > HFS_FORK_MAX) {
-               return 0;
-       }
-
-       *ppos += count;
-       if (*ppos > HFS_FORK_MAX) {
-               *ppos = HFS_FORK_MAX;
-               count = HFS_FORK_MAX - pos;
-       }
-
-       if (*ppos > inode->i_size)
-               inode->i_size = *ppos;
-
-       /* Only deal with the part we store in memory */
-       if (pos < sizeof(struct hfs_cap_info)) {
-               int end, mem_count;
-               struct hfs_cat_entry *entry = HFS_I(inode)->entry;
-               struct hfs_cap_info meta;
-
-               mem_count = sizeof(struct hfs_cap_info) - pos;
-               if (mem_count > count) {
-                       mem_count = count;
-               }
-               end = pos + mem_count;
-
-               cap_build_meta(&meta, entry);
-               mem_count -= copy_from_user(((char *)&meta) + pos, buf, mem_count);
-
-               /* Update finder attributes if changed */
-               if (OVERLAPS(pos, end, struct hfs_cap_info, fi_fndr)) {
-                       memcpy(&entry->info, meta.fi_fndr, 32);
-                       hfs_cat_mark_dirty(entry);
-               }
-
-               /* Update file flags if changed */
-               if (OVERLAPS(pos, end, struct hfs_cap_info, fi_attr) &&
-                   (entry->type == HFS_CDR_FIL)) {
-                       int locked = hfs_get_ns(&meta.fi_attr) &
-                                                       htons(HFS_AFP_WRI);
-                       hfs_u8 new_flags;
-
-                       if (locked) {
-                               new_flags = entry->u.file.flags | HFS_FIL_LOCK;
-                       } else {
-                               new_flags = entry->u.file.flags & ~HFS_FIL_LOCK;
-                       }
-
-                       if (new_flags != entry->u.file.flags) {
-                               entry->u.file.flags = new_flags;
-                               hfs_cat_mark_dirty(entry);
-                               hfs_file_fix_mode(entry);
-                       }
-               }
-
-               /* Update CrDat if changed */
-               if (OVERLAPS(pos, end, struct hfs_cap_info, fi_ctime)) {
-                       entry->create_date =
-                               hfs_h_to_mtime(hfs_get_nl(meta.fi_ctime));
-                       hfs_cat_mark_dirty(entry);
-               }
-
-               /* Update MdDat if changed */
-               if (OVERLAPS(pos, end, struct hfs_cap_info, fi_mtime)) {
-                       entry->modify_date =
-                               hfs_h_to_mtime(hfs_get_nl(meta.fi_mtime));
-                       hfs_cat_mark_dirty(entry);
-               }
-       }
-
-       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       mark_inode_dirty(inode);
-       return count;
-}
diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c
deleted file mode 100644 (file)
index b394849..0000000
+++ /dev/null
@@ -1,1033 +0,0 @@
-/*
- * linux/fs/hfs/file_hdr.c
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the file_ops and inode_ops for the metadata
- * files under the AppleDouble and Netatalk representations.
- *
- * The source code distributions of Netatalk, versions 1.3.3b2 and
- * 1.4b2, were used as a specification of the location and format of
- * files used by Netatalk's afpd.  No code from Netatalk appears in
- * hfs_fs.  hfs_fs is not a work ``derived'' from Netatalk in the
- * sense of intellectual property law.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- *
- * XXX: Note the reason that there is not bmap() for AppleDouble
- * header files is that dynamic nature of their structure make it
- * very difficult to safely mmap them.  Maybe in the distant future
- * I'll get bored enough to implement it.
- */
-
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
-#include <linux/smp_lock.h>
-
-/* prodos types */
-#define PRODOSI_FTYPE_DIR   0x0F
-#define PRODOSI_FTYPE_TEXT  0x04
-#define PRODOSI_FTYPE_8BIT  0xFF
-#define PRODOSI_FTYPE_16BIT 0xB3
-
-#define PRODOSI_AUXTYPE_DIR 0x0200
-
-/*================ Forward declarations ================*/
-static loff_t      hdr_llseek(struct file *, loff_t, int);
-static hfs_rwret_t hdr_read(struct file *, char __user *,
-                           hfs_rwarg_t, loff_t *);
-static hfs_rwret_t hdr_write(struct file *, const char __user *,
-                            hfs_rwarg_t, loff_t *);
-/*================ Global variables ================*/
-
-struct file_operations hfs_hdr_operations = {
-       .llseek         = hdr_llseek,
-       .read           = hdr_read,
-       .write          = hdr_write,
-       .fsync          = file_fsync,
-};
-
-struct inode_operations hfs_hdr_inode_operations = {
-       .setattr        = hfs_notify_change_hdr,
-};
-
-const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout = {
-       .magic          = __constant_htonl(HFS_DBL_MAGIC),      /* magic   */
-       .version        = __constant_htonl(HFS_HDR_VERSION_2),  /* version */
-       .entries        = 6,                                    /* entries */
-       {                                       /* descr[] */
-               {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
-               {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
-               {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
-               {HFS_HDR_MACI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
-               {HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4},
-               {HFS_HDR_RSRC,  HFS_DBL_HDR_LEN,                           ~0}
-       },
-       {                                       /* order[] */
-               (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[0],
-               (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[1],
-               (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[2],
-               (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[3],
-               (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[4],
-               (struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[5]
-       }
-};
-
-const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout = {
-       .magic          = __constant_htonl(HFS_DBL_MAGIC),      /* magic   */
-       .version        = __constant_htonl(HFS_HDR_VERSION_2),  /* version */
-       .entries        = 5,                                    /* entries */
-       {                                       /* descr[] */
-               {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
-               {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
-               {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
-               {HFS_HDR_MACI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
-               {HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4}
-       },
-       {                                       /* order[] */
-               (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[0],
-               (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[1],
-               (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[2],
-               (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[3],
-               (struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[4]
-       }
-};
-
-const struct hfs_hdr_layout hfs_nat2_hdr_layout = {
-       .magic          = __constant_htonl(HFS_DBL_MAGIC),      /* magic   */
-       .version        = __constant_htonl(HFS_HDR_VERSION_2),  /* version */
-       .entries        = 9,                                    /* entries */
-       {                                       /* descr[] */
-               {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
-               {HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
-               {HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
-               {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
-               {HFS_HDR_AFPI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
-               {HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4},
-               {HFS_HDR_SNAME,  offsetof(struct hfs_dbl_hdr, short_name), ~0},
-               {HFS_HDR_PRODOSI,  offsetof(struct hfs_dbl_hdr, prodosi),   8},
-               {HFS_HDR_RSRC,  HFS_NAT_HDR_LEN,                           ~0}
-       },
-       {                                       /* order[] */
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[5],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[6],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[7],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[8]
-       }
-};
-
-const struct hfs_hdr_layout hfs_nat_hdr_layout = {
-       .magic          = __constant_htonl(HFS_DBL_MAGIC),      /* magic   */
-       .version        = __constant_htonl(HFS_HDR_VERSION_1),  /* version */
-       .entries        = 5,                                    /* entries */
-       {                                       /* descr[] */
-               {HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
-               {HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
-               {HFS_HDR_OLDI,  offsetof(struct hfs_dbl_hdr, create_time), 16},
-               {HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
-               {HFS_HDR_RSRC,  HFS_NAT_HDR_LEN,                           ~0},
-       },
-       {                                       /* order[] */
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3],
-               (struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4]
-       }
-};
-
-/*================ File-local variables ================*/
-
-static const char fstype[16] =
-       {'M','a','c','i','n','t','o','s','h',' ',' ',' ',' ',' ',' ',' '};
-
-/*================ File-local data types ================*/
-
-struct hdr_hdr {
-        hfs_lword_t    magic;
-        hfs_lword_t    version;
-        hfs_byte_t     filler[16];
-        hfs_word_t     entries;
-        hfs_byte_t     descrs[12*HFS_HDR_MAX];
-}  __attribute__((packed));
-
-/*================ File-local functions ================*/
-
-/*
- * dlength()
- */
-static int dlength(const struct hfs_hdr_descr *descr,
-                  const struct hfs_cat_entry *entry)
-{
-       hfs_u32 length = descr->length;
-
-       /* handle auto-sized entries */
-       if (length == ~0) {
-               switch (descr->id) {
-               case HFS_HDR_DATA:
-                       if (entry->type == HFS_CDR_FIL) {
-                               length = entry->u.file.data_fork.lsize;
-                       } else {
-                               length = 0;
-                       }
-                       break;
-
-               case HFS_HDR_RSRC:
-                       if (entry->type == HFS_CDR_FIL) {
-                               length = entry->u.file.rsrc_fork.lsize;
-                       } else {
-                               length = 0;
-                       }
-                       break;
-
-               case HFS_HDR_FNAME:
-                       length = entry->key.CName.Len;
-                       break;
-
-               case HFS_HDR_SNAME:
-               default:
-                       length = 0;
-               }
-       }
-       return length;
-}
-
-/*
- * hdr_build_meta()
- */
-static void hdr_build_meta(struct hdr_hdr *meta,
-                          const struct hfs_hdr_layout *layout,
-                          const struct hfs_cat_entry *entry)
-{
-       const struct hfs_hdr_descr *descr;
-       hfs_byte_t *ptr;
-       int lcv;
-
-       hfs_put_nl(layout->magic,   meta->magic);
-       hfs_put_nl(layout->version, meta->version);
-       if (layout->version == htonl(HFS_HDR_VERSION_1)) {
-               memcpy(meta->filler, fstype, 16);
-       } else {
-               memset(meta->filler, 0, 16);
-       }
-       hfs_put_hs(layout->entries, meta->entries);
-       memset(meta->descrs, 0, sizeof(meta->descrs));
-       for (lcv = 0, descr = layout->descr, ptr = meta->descrs;
-            lcv < layout->entries; ++lcv, ++descr, ptr += 12) {
-               hfs_put_hl(descr->id,             ptr);
-               hfs_put_hl(descr->offset,         ptr + 4);
-               hfs_put_hl(dlength(descr, entry), ptr + 8);
-       }
-}
-
-/*
- * dup_layout ()
- */
-static struct hfs_hdr_layout *dup_layout(const struct hfs_hdr_layout *old)
-{
-       struct hfs_hdr_layout *new;
-       int lcv;
-
-       if (HFS_NEW(new)) {
-               memcpy(new, old, sizeof(*new));
-               for (lcv = 0; lcv < new->entries; ++lcv) {
-                       new->order[lcv] = (struct hfs_hdr_descr *)
-                       ((char *)new->order[lcv] + ((char *)new - (char *)old));
-               }
-       }
-       return new;
-}
-
-/*
- * init_layout()
- */
-static inline void init_layout(struct hfs_hdr_layout *layout,
-                              const hfs_byte_t *descrs)
-{
-       struct hfs_hdr_descr **base, **p, **q, *tmp;
-       int lcv, entries = layout->entries;
-
-       for (lcv = 0; lcv < entries; ++lcv, descrs += 12) {
-               layout->order[lcv] = &layout->descr[lcv];
-               layout->descr[lcv].id     = hfs_get_hl(descrs);
-               layout->descr[lcv].offset = hfs_get_hl(descrs + 4);
-               layout->descr[lcv].length = hfs_get_hl(descrs + 8);
-       }
-       for (lcv = layout->entries; lcv < HFS_HDR_MAX; ++lcv) {
-               layout->order[lcv] = NULL;
-               layout->descr[lcv].id     = 0;
-               layout->descr[lcv].offset = 0;
-               layout->descr[lcv].length = 0;
-       }
-
-       /* Sort the 'order' array using an insertion sort */
-       base = &layout->order[0];
-       for (p = (base+1); p < (base+entries); ++p) {
-               q=p;
-               while ((*q)->offset < (*(q-1))->offset) {
-                       tmp = *q;
-                       *q = *(q-1);
-                       *(--q) = tmp;
-                       if (q == base) break;
-               }
-       }
-}
-
-/*
- * adjust_forks()
- */
-static inline void adjust_forks(struct hfs_cat_entry *entry,
-                               const struct hfs_hdr_layout *layout)
-{
-       int lcv;
-
-       for (lcv = 0; lcv < layout->entries; ++lcv) {
-               const struct hfs_hdr_descr *descr = &layout->descr[lcv];
-
-               if ((descr->id == HFS_HDR_DATA) &&
-                   (descr->length != entry->u.file.data_fork.lsize)) {
-                       entry->u.file.data_fork.lsize = descr->length;
-                       hfs_extent_adj(&entry->u.file.data_fork);
-               } else if ((descr->id == HFS_HDR_RSRC) &&
-                          (descr->length != entry->u.file.rsrc_fork.lsize)) {
-                       entry->u.file.rsrc_fork.lsize = descr->length;
-                       hfs_extent_adj(&entry->u.file.rsrc_fork);
-               }
-       }
-}
-
-/*
- * get_dates()
- */
-static void get_dates(const struct hfs_cat_entry *entry,
-                     const struct inode *inode,  hfs_u32 dates[3])
-{
-       dates[0] = hfs_m_to_htime(entry->create_date);
-       dates[1] = hfs_m_to_htime(entry->modify_date);
-       dates[2] = hfs_m_to_htime(entry->backup_date);
-}
-
-/*
- * set_dates()
- */
-static void set_dates(struct hfs_cat_entry *entry, struct inode *inode,
-                     const hfs_u32 *dates)
-{
-       hfs_u32 tmp;
-
-       tmp = hfs_h_to_mtime(dates[0]);
-       if (entry->create_date != tmp) {
-               entry->create_date = tmp;
-               hfs_cat_mark_dirty(entry);
-       }
-       tmp = hfs_h_to_mtime(dates[1]);
-       if (entry->modify_date != tmp) {
-               entry->modify_date = tmp;
-               inode->i_ctime.tv_sec = inode->i_atime.tv_sec = inode->i_mtime.tv_sec = 
-                       hfs_h_to_utime(dates[1]);
-               inode->i_ctime.tv_nsec = 0;
-               inode->i_mtime.tv_nsec = 0;
-               inode->i_atime.tv_nsec = 0;
-               hfs_cat_mark_dirty(entry);
-       }
-       tmp = hfs_h_to_mtime(dates[2]);
-       if (entry->backup_date != tmp) {
-               entry->backup_date = tmp;
-               hfs_cat_mark_dirty(entry);
-       }
-}
-
-loff_t hdr_llseek(struct file *file, loff_t offset, int origin)
-{
-       long long retval;
-
-       lock_kernel();
-
-       switch (origin) {
-               case 2:
-                       offset += file->f_dentry->d_inode->i_size;
-                       break;
-               case 1:
-                       offset += file->f_pos;
-       }
-       retval = -EINVAL;
-       if (offset>=0 && offset<file->f_dentry->d_inode->i_size) {
-               if (offset != file->f_pos) {
-                       file->f_pos = offset;
-               }
-               retval = offset;
-       }
-       unlock_kernel();
-       return retval;
-}
-
-/*
- * hdr_read()
- *
- * This is the read field in the inode_operations structure for
- * header files.  The purpose is to transfer up to 'count' bytes
- * from the file corresponding to 'inode', beginning at
- * 'filp->offset' bytes into the file. The data is transferred to
- * user-space at the address 'buf'.  Returns the number of bytes
- * successfully transferred.
- */
-/* XXX: what about the entry count changing on us? */
-static hfs_rwret_t hdr_read(struct file *filp, char __user *buf, 
-                           hfs_rwarg_t count, loff_t *ppos)
-{
-       struct inode *inode = filp->f_dentry->d_inode;
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
-       const struct hfs_hdr_layout *layout;
-       off_t start, length, offset;
-       off_t pos = *ppos;
-       int left, lcv, read = 0;
-
-       if (!S_ISREG(inode->i_mode)) {
-               hfs_warn("hfs_hdr_read: mode = %07o\n",inode->i_mode);
-               return -EINVAL;
-       }
-
-       if (HFS_I(inode)->layout) {
-               layout = HFS_I(inode)->layout;
-       } else {
-               layout = HFS_I(inode)->default_layout;
-       }
-
-       /* Adjust count to fit within the bounds of the file */
-       if ((pos >= inode->i_size) || (count <= 0)) {
-               return 0;
-       } else if (count > inode->i_size - pos) {
-               count = inode->i_size - pos;
-       }
-
-       /* Handle the fixed-location portion */
-       length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 +
-                sizeof(hfs_u16) + layout->entries * (3 * sizeof(hfs_u32));
-       if (pos < length) {
-               struct hdr_hdr meta;
-
-               left = length - pos;
-               if (left > count) {
-                       left = count;
-               }
-
-               hdr_build_meta(&meta, layout, entry);
-               left -= copy_to_user(buf, ((char *)&meta) + pos, left);
-               count -= left;
-               read += left;
-               pos += left;
-               buf += left;
-       }
-       if (!count) {
-               goto done;
-       }
-
-       /* Handle the actual data */
-       for (lcv = 0; count && (lcv < layout->entries); ++lcv) {
-               const struct hfs_hdr_descr *descr = layout->order[lcv];
-               struct hfs_fork *fork;
-               char tmp[16], *p;
-               off_t limit;
-
-               /* stop reading if we run out of descriptors early */
-               if (!descr) {
-                       break;
-               }
-
-               /* find start and length of this entry */
-               start = descr->offset;
-               length = dlength(descr, entry);
-
-               /* Skip to next entry if this one is empty or isn't needed */
-               if (!length || (pos >= start + length)) {
-                       continue;
-               }
-
-               /* Pad with zeros to the start of this entry if needed */
-               if (pos < start) {
-                       left = start - pos;
-                       if (left > count) {
-                               left = count;
-                       }
-                       clear_user(buf, left);
-                       count -= left;
-                       read += left;
-                       pos += left;
-                       buf += left;
-               }
-               if (!count) {
-                       goto done;
-               }
-
-               /* locate and/or construct the data for this entry */
-               fork = NULL;
-               p = NULL;
-               switch (descr->id) {
-               case HFS_HDR_DATA:
-                       fork = &entry->u.file.data_fork;
-                       limit = fork->lsize;
-                       break;
-
-               case HFS_HDR_RSRC:
-                       fork = &entry->u.file.rsrc_fork;
-                       limit = fork->lsize;
-                       break;
-
-               case HFS_HDR_FNAME:
-                       p = entry->key.CName.Name;
-                       limit = entry->key.CName.Len;
-                       break;
-
-               case HFS_HDR_OLDI:
-               case HFS_HDR_DATES:
-                       get_dates(entry, inode, (hfs_u32 *)tmp);
-                       if (descr->id == HFS_HDR_DATES) {
-                               /* XXX: access date. hfsplus actually
-                                   has this. */
-                               memcpy(tmp + 12, tmp + 4, 4);
-                       } else if ((entry->type == HFS_CDR_FIL) &&
-                                  (entry->u.file.flags & HFS_FIL_LOCK)) {
-                               hfs_put_hl(HFS_AFP_RDONLY, tmp + 12);
-                       } else {
-                               hfs_put_nl(0, tmp + 12);
-                       }
-                       p = tmp;
-                       limit = 16;
-                       break;
-
-               case HFS_HDR_FINFO:
-                       p = (char *)&entry->info;
-                       limit = 32;
-                       break;
-
-               case HFS_HDR_AFPI:
-                       /* XXX: this needs to do more mac->afp mappings */
-                       hfs_put_ns(0, tmp);
-                       if ((entry->type == HFS_CDR_FIL) &&
-                           (entry->u.file.flags & HFS_FIL_LOCK)) {
-                               hfs_put_hs(HFS_AFP_RDONLY, tmp + 2);
-                       } else {
-                               hfs_put_ns(0, tmp + 2);
-                       }
-                       p = tmp;
-                       limit = 4;
-                       break;
-
-               case HFS_HDR_PRODOSI:
-                       /* XXX: this needs to do mac->prodos translations */
-                       memset(tmp, 0, 8);
-#if 0
-                       hfs_put_ns(0, tmp); /* access */
-                       hfs_put_ns(0, tmp); /* type */
-                       hfs_put_nl(0, tmp); /* aux type */
-#endif
-                       p = tmp;
-                       limit = 8;
-                       break;
-
-               case HFS_HDR_MACI:
-                       hfs_put_ns(0, tmp);
-                       if (entry->type == HFS_CDR_FIL) {
-                               hfs_put_hs(entry->u.file.flags, tmp + 2);
-                       } else {
-                               hfs_put_ns(entry->u.dir.flags, tmp + 2);
-                       }
-                       p = tmp;
-                       limit = 4;
-                       break;
-
-               case HFS_HDR_DID:
-                       /* if it's rootinfo, stick the next available did in
-                        * the did slot. */
-                       limit = 4;
-                       if (entry->cnid == htonl(HFS_ROOT_CNID)) {
-                               struct hfs_mdb *mdb = entry->mdb;
-                               const struct hfs_name *reserved = 
-                               HFS_SB(mdb->sys_mdb)->s_reserved2;
-                               
-                               while (reserved->Len) {
-                                       if (hfs_streq(reserved->Name,
-                                                     reserved->Len,
-                                                     entry->key.CName.Name,
-                                                     entry->key.CName.Len)) {
-                                               hfs_put_hl(mdb->next_id, tmp);
-                                               p = tmp;
-                                               goto hfs_did_done;
-                                       }
-                                       reserved++;
-                               }
-                       }
-                       p = (char *) &entry->cnid;
-hfs_did_done:
-                       break;
-
-               case HFS_HDR_SNAME:
-               default:
-                       limit = 0;
-               }
-               
-               /* limit the transfer to the available data
-                  of to the stated length of the entry. */
-               if (length > limit) {
-                       length = limit;
-               }
-               offset = pos - start;
-               left = length - offset;
-               if (left > count) {
-                       left = count;
-               }
-               if (left <= 0) {
-                       continue;
-               }
-
-               /* transfer the data */
-               if (p) {
-                       left -= copy_to_user(buf, p + offset, left);
-               } else if (fork) {
-                       left = hfs_do_read(inode, fork, offset, buf, left);
-                       if (left > 0) {
-                       } else if (!read) {
-                               return left;
-                       } else {
-                               goto done;
-                       }
-               }
-               count -= left;
-               read += left;
-               pos += left;
-               buf += left;
-       }
-
-       /* Pad the file out with zeros */
-       if (count) {
-               clear_user(buf, count);
-               read += count;
-               pos += count;
-       }
-               
-done:
-       if (read) {
-               inode->i_atime = CURRENT_TIME;
-               *ppos = pos;
-               mark_inode_dirty(inode);
-       }
-       return read;
-}
-
-/*
- * hdr_write()
- *
- * This is the write() entry in the file_operations structure for
- * header files.  The purpose is to transfer up to 'count' bytes
- * to the file corresponding to 'inode' beginning at offset
- * '*ppos' from user-space at the address 'buf'.
- * The return value is the number of bytes actually transferred.
- */
-static hfs_rwret_t hdr_write(struct file *filp, const char __user *buf,
-                            hfs_rwarg_t count, loff_t *ppos)
-{
-       struct inode *inode = filp->f_dentry->d_inode;
-        struct hfs_cat_entry *entry = HFS_I(inode)->entry;
-        struct hfs_hdr_layout *layout;
-        off_t start, length, offset;
-        int left, lcv, written = 0;
-       struct hdr_hdr meta;
-       int built_meta = 0;
-        off_t pos;
-
-       if (!S_ISREG(inode->i_mode)) {
-               hfs_warn("hfs_hdr_write: mode = %07o\n", inode->i_mode);
-               return -EINVAL;
-       }
-       if (count <= 0) {
-               return 0;
-       }
-
-       pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
-
-       if (!HFS_I(inode)->layout) {
-               HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
-       }
-       layout = HFS_I(inode)->layout;
-
-       /* Handle the 'magic', 'version', 'filler' and 'entries' fields */
-       length = sizeof(hfs_u32) + sizeof(hfs_u32) + 16 + sizeof(hfs_u16);
-       if (pos < length) {
-               hdr_build_meta(&meta, layout, entry);
-               built_meta = 1;
-
-               left = length - pos;
-               if (left > count) {
-                       left = count;
-               }
-
-               left -= copy_from_user(((char *)&meta) + pos, buf, left);
-               layout->magic   = hfs_get_nl(meta.magic);
-               layout->version = hfs_get_nl(meta.version);
-               layout->entries = hfs_get_hs(meta.entries);
-               if (layout->entries > HFS_HDR_MAX) {
-                       /* XXX: should allocate slots dynamically */
-                       hfs_warn("hfs_hdr_write: TRUNCATING TO %d "
-                                "DESCRIPTORS\n", HFS_HDR_MAX);
-                       layout->entries = HFS_HDR_MAX;
-               }
-
-               count -= left;
-               written += left;
-               pos += left;
-               buf += left;
-       }
-       if (!count) {
-               goto done;
-       }
-
-       /* We know for certain how many entries we have, so process them */
-       length += layout->entries * 3 * sizeof(hfs_u32);
-       if (pos < length) {
-               if (!built_meta) {
-                       hdr_build_meta(&meta, layout, entry);
-               }
-
-               left = length - pos;
-               if (left > count) {
-                       left = count;
-               }
-
-               left -= copy_from_user(((char *)&meta) + pos, buf, left);
-               init_layout(layout, meta.descrs);
-
-               count -= left;
-               written += left;
-               pos += left;
-               buf += left;
-
-               /* Handle possible size changes for the forks */
-               if (entry->type == HFS_CDR_FIL) {
-                       adjust_forks(entry, layout);
-                       hfs_cat_mark_dirty(entry);
-               }
-       }
-
-       /* Handle the actual data */
-       for (lcv = 0; count && (lcv < layout->entries); ++lcv) {
-               struct hfs_hdr_descr *descr = layout->order[lcv];
-               struct hfs_fork *fork;
-               char tmp[16], *p;
-               off_t limit;
-
-               /* stop writing if we run out of descriptors early */
-               if (!descr) {
-                       break;
-               }
-
-               /* find start and length of this entry */
-               start = descr->offset;
-               if ((descr->id == HFS_HDR_DATA) ||
-                   (descr->id == HFS_HDR_RSRC)) {
-                       if (entry->type == HFS_CDR_FIL) {
-                               length = 0x7fffffff - start;
-                       } else {
-                               continue;
-                       }
-               } else {
-                       length = dlength(descr, entry);
-               }
-
-               /* Trim length to avoid overlap with the next entry */
-               if (layout->order[lcv+1] &&
-                   ((start + length) > layout->order[lcv+1]->offset)) {
-                       length = layout->order[lcv+1]->offset - start;
-               }
-
-               /* Skip to next entry if this one is empty or isn't needed */
-               if (!length || (pos >= start + length)) {
-                       continue;
-               }
-
-               /* Skip any padding that may exist between entries */
-               if (pos < start) {
-                       left = start - pos;
-                       if (left > count) {
-                               left = count;
-                       }
-                       count -= left;
-                       written += left;
-                       pos += left;
-                       buf += left;
-               }
-               if (!count) {
-                       goto done;
-               }
-
-               /* locate and/or construct the data for this entry */
-               fork = NULL;
-               p = NULL;
-               switch (descr->id) {
-               case HFS_HDR_DATA:
-#if 0
-/* Can't yet write to the data fork via a header file, since there is the
- * possibility to write via the data file, and the only locking is at the
- * inode level.
- */
-                       fork = &entry->u.file.data_fork;
-                       limit = length;
-#else
-                       limit = 0;
-#endif
-                       break;
-
-               case HFS_HDR_RSRC:
-                       fork = &entry->u.file.rsrc_fork;
-                       limit = length;
-                       break;
-
-               case HFS_HDR_OLDI:
-               case HFS_HDR_DATES:
-                       get_dates(entry, inode, (hfs_u32 *)tmp);
-                       if (descr->id == HFS_HDR_DATES) {
-                               memcpy(tmp + 12, tmp + 4, 4);
-                       } else if ((entry->type == HFS_CDR_FIL) &&
-                                  (entry->u.file.flags & HFS_FIL_LOCK)) {
-                               hfs_put_hl(HFS_AFP_RDONLY, tmp + 12);
-                       } else {
-                               hfs_put_nl(0, tmp + 12);
-                       }
-                       p = tmp;
-                       limit = 16;
-                       break;
-
-               case HFS_HDR_FINFO:
-                       p = (char *)&entry->info;
-                       limit = 32;
-                       break;
-
-               case HFS_HDR_AFPI:
-                       hfs_put_ns(0, tmp);
-                       if ((entry->type == HFS_CDR_FIL) &&
-                           (entry->u.file.flags & HFS_FIL_LOCK)) {
-                               hfs_put_hs(HFS_AFP_RDONLY, tmp + 2);
-                       } else {
-                               hfs_put_ns(0, tmp + 2);
-                       }                       
-                       p = tmp;
-                       limit = 4;
-                       break;
-
-               case HFS_HDR_PRODOSI:
-                       /* XXX: this needs to do mac->prodos translations */
-                       memset(tmp, 0, 8); 
-#if 0
-                       hfs_put_ns(0, tmp); /* access */
-                       hfs_put_ns(0, tmp); /* type */
-                       hfs_put_nl(0, tmp); /* aux type */
-#endif
-                       p = tmp;
-                       limit = 8;
-                       break;
-
-               case HFS_HDR_MACI:
-                       hfs_put_ns(0, tmp);
-                       if (entry->type == HFS_CDR_FIL) {
-                               hfs_put_hs(entry->u.file.flags, tmp + 2);
-                       } else {
-                               hfs_put_ns(entry->u.dir.flags, tmp + 2);
-                       }
-                       p = tmp;
-                       limit = 4;
-                       break;
-
-               case HFS_HDR_FNAME:     /* Can't rename a file this way */
-               case HFS_HDR_DID:       /* can't specify a did this way */
-               default:
-                       limit = 0;
-               }
-               
-               /* limit the transfer to the available data
-                  of to the stated length of the entry. */
-               if (length > limit) {
-                       length = limit;
-               }
-               offset = pos - start;
-               left = length - offset;
-               if (left > count) {
-                       left = count;
-               }
-               if (left <= 0) {
-                       continue;
-               }
-
-               /* transfer the data from user space */
-               if (p) {
-                       left -= copy_from_user(p + offset, buf, left);
-               } else if (fork) {
-                       left = hfs_do_write(inode, fork, offset, buf, left);
-               }
-
-               /* process the data */
-               switch (descr->id) {
-               case HFS_HDR_OLDI:
-                       set_dates(entry, inode, (hfs_u32 *)tmp);
-                       if (entry->type == HFS_CDR_FIL) {
-                               hfs_u8 new_flags = entry->u.file.flags;
-
-                               if (hfs_get_nl(tmp+12) & htonl(HFS_AFP_WRI)) {
-                                       new_flags |= HFS_FIL_LOCK;
-                               } else {
-                                       new_flags &= ~HFS_FIL_LOCK;
-                               }
-
-                               if (new_flags != entry->u.file.flags) {
-                                       entry->u.file.flags = new_flags;
-                                       hfs_cat_mark_dirty(entry);
-                                       hfs_file_fix_mode(entry);
-                               }
-                       }
-                       break;
-
-               case HFS_HDR_DATES:
-                       set_dates(entry, inode, (hfs_u32 *)tmp);
-                       break;
-
-               case HFS_HDR_FINFO:
-                       hfs_cat_mark_dirty(entry);
-                       break;
-
-               case HFS_HDR_MACI:
-                       if (entry->type == HFS_CDR_DIR) {
-                               hfs_u16 new_flags = hfs_get_ns(tmp + 2);
-
-                               if (entry->u.dir.flags != new_flags) {
-                                       entry->u.dir.flags = new_flags;
-                                       hfs_cat_mark_dirty(entry);
-                               }
-                       } else {
-                               hfs_u8 new_flags = tmp[3];
-                               hfs_u8 changed = entry->u.file.flags^new_flags;
-                               
-                               if (changed) {
-                                       entry->u.file.flags = new_flags;
-                                       hfs_cat_mark_dirty(entry);
-                                       if (changed & HFS_FIL_LOCK) {
-                                               hfs_file_fix_mode(entry);
-                                       }
-                               }
-                       }
-                       break;
-
-               case HFS_HDR_DATA:
-               case HFS_HDR_RSRC:
-                       if (left <= 0) {
-                               if (!written) {
-                                       return left;
-                               } else {
-                                       goto done;
-                               }
-                       } else if (fork->lsize > descr->length) {
-                               descr->length = fork->lsize;
-                       }
-                       break;
-
-               case HFS_HDR_FNAME:     /* Can't rename a file this way */
-               case HFS_HDR_DID:       /* Can't specify a did this way */
-               case HFS_HDR_PRODOSI:   /* not implemented yet */
-               case HFS_HDR_AFPI:      /* ditto */
-               default:
-                       break;
-               }
-
-               count -= left;
-               written += left;
-               pos += left;
-               buf += left;
-       }
-
-       /* Skip any padding at the end */
-       if (count) {
-               written += count;
-               pos += count;
-       }
-               
-done:
-       *ppos = pos;
-       if (written > 0) {
-               if (pos > inode->i_size)
-                       inode->i_size = pos;
-               inode->i_mtime = inode->i_atime = CURRENT_TIME;
-               mark_inode_dirty(inode);
-       }
-       return written;
-}
-
-/*
- * hdr_truncate()
- *
- * This is the truncate field in the inode_operations structure for
- * header files.  The purpose is to allocate or release blocks as needed
- * to satisfy a change in file length.
- */
-void hdr_truncate(struct inode *inode, size_t size)
-{
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
-       struct hfs_hdr_layout *layout;
-       int lcv, last;
-
-       inode->i_size = size;
-       if (!HFS_I(inode)->layout) {
-               HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
-       }
-       layout = HFS_I(inode)->layout;
-
-       last = layout->entries - 1;
-       for (lcv = 0; lcv <= last; ++lcv) {
-               struct hfs_hdr_descr *descr = layout->order[lcv];
-               struct hfs_fork *fork;
-               hfs_u32 offset;
-
-               if (!descr) {
-                       break;
-               }
-
-               if (descr->id == HFS_HDR_RSRC) {
-                       fork = &entry->u.file.rsrc_fork;
-#if 0
-/* Can't yet truncate the data fork via a header file, since there is the
- * possibility to truncate via the data file, and the only locking is at
- * the inode level.
- */
-               } else if (descr->id == HFS_HDR_DATA) {
-                       fork = &entry->u.file.data_fork;
-#endif
-               } else {
-                       continue;
-               }
-
-               offset = descr->offset;
-
-               if ((lcv != last) && ((offset + descr->length) <= size)) {
-                       continue;
-               }
-
-               if (offset < size) {
-                       descr->length = size - offset;
-               } else {
-                       descr->length = 0;
-               }
-               if (fork->lsize != descr->length) {
-                       fork->lsize = descr->length;
-                       hfs_extent_adj(fork);
-                       hfs_cat_mark_dirty(entry);
-               }
-       }
-}
index adf912cbec0ccc90c952d7ba5c223e6a1fe28862..73ac40810d159e9ff4df56cf9b772ae2571d7360 100644 (file)
@@ -1,21 +1,14 @@
-/* 
- * linux/fs/hfs/hfs.h
+/*
+ *  linux/fs/hfs/hfs.h
  *
  * Copyright (C) 1995-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
  */
 
 #ifndef _HFS_H
 #define _HFS_H
 
-#include <linux/hfs_sysdep.h>
-
-#define HFS_NEW(X)     ((X) = hfs_malloc(sizeof(*(X))))
-#define HFS_DELETE(X)  do { hfs_free((X), sizeof(*(X))); (X) = NULL; } \
-                        while (0)
 /* offsets to various blocks */
 #define HFS_DD_BLK             0 /* Driver Descriptor block */
 #define HFS_PMAP_BLK           1 /* First block of partition map */
 #define HFS_SUPER_MAGIC                0x4244 /* "BD": HFS MDB (super block) */
 #define HFS_MFS_SUPER_MAGIC    0xD2D7 /* MFS MDB (super block) */
 
-/* magic numbers for various internal structures */
-#define HFS_FILE_MAGIC         0x4801
-#define HFS_DIR_MAGIC          0x4802
-#define HFS_MDB_MAGIC          0x4803
-#define HFS_EXT_MAGIC          0x4804 /* XXX currently unused */
-#define HFS_BREC_MAGIC         0x4811 /* XXX currently unused */
-#define HFS_BTREE_MAGIC                0x4812
-#define HFS_BNODE_MAGIC                0x4813
-
 /* various FIXED size parameters */
 #define HFS_SECTOR_SIZE                512    /* size of an HFS sector */
 #define HFS_SECTOR_SIZE_BITS   9      /* log_2(HFS_SECTOR_SIZE) */
 #define HFS_NAMELEN            31     /* maximum length of an HFS filename */
-#define HFS_NAMEMAX            (3*31) /* max size of ENCODED filename */
-#define HFS_BM_MAXBLOCKS       (16)   /* max number of bitmap blocks */
-#define HFS_BM_BPB (8*HFS_SECTOR_SIZE) /* number of bits per bitmap block */
 #define HFS_MAX_VALENCE                32767U
-#define HFS_FORK_MAX           (0x7FFFFFFF)
 
 /* Meanings of the drAtrb field of the MDB,
  * Reference: _Inside Macintosh: Files_ p. 2-61
  */
-#define HFS_SB_ATTRIB_HLOCK 0x0080
-#define HFS_SB_ATTRIB_CLEAN 0x0100
-#define HFS_SB_ATTRIB_SPARED 0x0200
-#define HFS_SB_ATTRIB_SLOCK 0x8000
-
-/* 2**16 - 1 */
-#define HFS_USHRT_MAX  65535
+#define HFS_SB_ATTRIB_HLOCK    (1 << 7)
+#define HFS_SB_ATTRIB_UNMNT    (1 << 8)
+#define HFS_SB_ATTRIB_SPARED   (1 << 9)
+#define HFS_SB_ATTRIB_INCNSTNT (1 << 11)
+#define HFS_SB_ATTRIB_SLOCK    (1 << 15)
 
 /* Some special File ID numbers */
-#define HFS_POR_CNID   1       /* Parent Of the Root */
-#define HFS_ROOT_CNID  2       /* ROOT directory */
-#define HFS_EXT_CNID   3       /* EXTents B-tree */
-#define HFS_CAT_CNID   4       /* CATalog B-tree */
-#define HFS_BAD_CNID   5       /* BAD blocks file */
-#define HFS_ALLOC_CNID  6       /* ALLOCation file (HFS+) */
-#define HFS_START_CNID  7       /* STARTup file (HFS+) */
-#define HFS_ATTR_CNID   8       /* ATTRibutes file (HFS+) */
-#define HFS_EXCH_CNID  15       /* ExchangeFiles temp id */
+#define HFS_POR_CNID           1       /* Parent Of the Root */
+#define HFS_ROOT_CNID          2       /* ROOT directory */
+#define HFS_EXT_CNID           3       /* EXTents B-tree */
+#define HFS_CAT_CNID           4       /* CATalog B-tree */
+#define HFS_BAD_CNID           5       /* BAD blocks file */
+#define HFS_ALLOC_CNID         6       /* ALLOCation file (HFS+) */
+#define HFS_START_CNID         7       /* STARTup file (HFS+) */
+#define HFS_ATTR_CNID          8       /* ATTRibutes file (HFS+) */
+#define HFS_EXCH_CNID          15      /* ExchangeFiles temp id */
+#define HFS_FIRSTUSER_CNID     16
 
 /* values for hfs_cat_rec.cdrType */
 #define HFS_CDR_DIR    0x01    /* folder (directory) */
@@ -85,7 +64,6 @@
 #define HFS_FIL_DOPEN   0x04  /* data fork open */
 #define HFS_FIL_ROPEN   0x08  /* resource fork open */
 #define HFS_FIL_DIR     0x10  /* directory (always clear) */
-#define HFS_FIL_RSRV1   0x20  /* reserved */
 #define HFS_FIL_NOCOPY  0x40  /* copy-protected file */
 #define HFS_FIL_USED   0x80  /* open */
 
 #define HFS_DIR_MOUNTED     0x08  /* mounted */
 #define HFS_DIR_DIR         0x10  /* directory (always set) */
 #define HFS_DIR_EXPFOLDER   0x20  /* share point */
-#define HFS_DIR_RSRV1       0x40  /* reserved */
-#define HFS_DIR_RSRV2       0x80  /* reserved */
-
-/* Access types used when requesting access to a B-node */
-#define HFS_LOCK_NONE  0x0000  /* Illegal */
-#define HFS_LOCK_READ  0x0001  /* read-only access */
-#define HFS_LOCK_RESRV 0x0002  /* might potentially modify */
-#define HFS_LOCK_WRITE 0x0003  /* will modify now (exclusive access) */
-#define HFS_LOCK_MASK  0x000f
-
-/* Flags field of the hfs_path_elem */
-#define HFS_BPATH_FIRST                0x0100
-#define HFS_BPATH_OVERFLOW     0x0200
-#define HFS_BPATH_UNDERFLOW    0x0400
-#define HFS_BPATH_MASK         0x0f00
-
-/* Flags for hfs_bfind() */
-#define HFS_BFIND_EXACT                0x0010
-#define HFS_BFIND_LOCK         0x0020
-
-/* Modes for hfs_bfind() */
-#define HFS_BFIND_WRITE   (HFS_LOCK_RESRV|HFS_BFIND_EXACT|HFS_BFIND_LOCK)
-#define HFS_BFIND_READ_EQ (HFS_LOCK_READ|HFS_BFIND_EXACT)
-#define HFS_BFIND_READ_LE (HFS_LOCK_READ)
-#define HFS_BFIND_INSERT  (HFS_LOCK_RESRV|HFS_BPATH_FIRST|HFS_BPATH_OVERFLOW)
-#define HFS_BFIND_DELETE \
-        (HFS_LOCK_RESRV|HFS_BFIND_EXACT|HFS_BPATH_FIRST|HFS_BPATH_UNDERFLOW)
+
+/* bits hfs_finfo.fdFlags */
+#define HFS_FLG_INITED         0x0100
+#define HFS_FLG_LOCKED         0x1000
+#define HFS_FLG_INVISIBLE      0x4000
 
 /*======== HFS structures as they appear on the disk ========*/
 
+#define __packed __attribute__ ((packed))
+
 /* Pascal-style string of up to 31 characters */
 struct hfs_name {
-       hfs_byte_t      Len;
-       hfs_byte_t      Name[31];
-} __attribute__((packed));
-
-typedef struct {
-       hfs_word_t      v;
-       hfs_word_t      h;
-} hfs_point_t;
-
-typedef struct {
-       hfs_word_t      top;
-       hfs_word_t      left;
-       hfs_word_t      bottom;
-       hfs_word_t      right;
-} hfs_rect_t;
-
-typedef struct {
-       hfs_lword_t      fdType;
-       hfs_lword_t      fdCreator;
-       hfs_word_t       fdFlags;
-       hfs_point_t      fdLocation;
-       hfs_word_t       fdFldr;
-} __attribute__((packed)) hfs_finfo_t;
-
-typedef struct {
-       hfs_word_t      fdIconID;
-       hfs_byte_t      fdUnused[8];
-       hfs_word_t      fdComment;
-       hfs_lword_t     fdPutAway;
-} __attribute__((packed)) hfs_fxinfo_t;
-
-typedef struct {
-       hfs_rect_t      frRect;
-       hfs_word_t      frFlags;
-       hfs_point_t     frLocation;
-       hfs_word_t      frView;
-} __attribute__((packed)) hfs_dinfo_t;
-
-typedef struct {
-       hfs_point_t     frScroll;
-       hfs_lword_t     frOpenChain;
-       hfs_word_t      frUnused;
-       hfs_word_t      frComment;
-       hfs_lword_t     frPutAway;
-} __attribute__((packed)) hfs_dxinfo_t;
+       u8 len;
+       u8 name[HFS_NAMELEN];
+} __packed;
+
+struct hfs_point {
+       u16 v;
+       u16 h;
+} __packed;
+
+struct hfs_rect {
+       u16 top;
+       u16 left;
+       u16 bottom;
+       u16 right;
+} __packed;
+
+struct hfs_finfo {
+       u32 fdType;
+       u32 fdCreator;
+       u16 fdFlags;
+       struct hfs_point fdLocation;
+       u16 fdFldr;
+} __packed;
+
+struct hfs_fxinfo {
+       u16 fdIconID;
+       u8 fdUnused[8];
+       u16 fdComment;
+       u32 fdPutAway;
+} __packed;
+
+struct hfs_dinfo {
+       struct hfs_rect frRect;
+       u16 frFlags;
+       struct hfs_point frLocation;
+       u16 frView;
+} __packed;
+
+struct hfs_dxinfo {
+       struct hfs_point frScroll;
+       u32 frOpenChain;
+       u16 frUnused;
+       u16 frComment;
+       u32 frPutAway;
+} __packed;
 
 union hfs_finder_info {
        struct {
-               hfs_finfo_t     finfo;
-               hfs_fxinfo_t    fxinfo;
+               struct hfs_finfo finfo;
+               struct hfs_fxinfo fxinfo;
        } file;
        struct {
-               hfs_dinfo_t     dinfo;
-               hfs_dxinfo_t    dxinfo;
+               struct hfs_dinfo dinfo;
+               struct hfs_dxinfo dxinfo;
        } dir;
-};
-
-/* A btree record key on disk */
-struct hfs_bkey {
-       hfs_byte_t      KeyLen;         /* number of bytes in the key */
-       hfs_byte_t      value[1];       /* (KeyLen) bytes of key */
-} __attribute__((packed));
+} __packed;
 
 /* Cast to a pointer to a generic bkey */
 #define        HFS_BKEY(X)     (((void)((X)->KeyLen)), ((struct hfs_bkey *)(X)))
 
 /* The key used in the catalog b-tree: */
 struct hfs_cat_key {
-       hfs_byte_t      KeyLen; /* number of bytes in the key */
-       hfs_byte_t      Resrv1; /* padding */
-       hfs_lword_t     ParID;  /* CNID of the parent dir */
+       u8 key_len;             /* number of bytes in the key */
+       u8 reserved;            /* padding */
+       u32 ParID;              /* CNID of the parent dir */
        struct hfs_name CName;  /* The filename of the entry */
-} __attribute__((packed));
+} __packed;
 
 /* The key used in the extents b-tree: */
 struct hfs_ext_key {
-       hfs_byte_t      KeyLen; /* number of bytes in the key */
-       hfs_byte_t      FkType; /* HFS_FK_{DATA,RSRC} */
-       hfs_lword_t     FNum;   /* The File ID of the file */
-       hfs_word_t      FABN;   /* allocation blocks number*/
-} __attribute__((packed));
+       u8 key_len;             /* number of bytes in the key */
+       u8 FkType;              /* HFS_FK_{DATA,RSRC} */
+       u32 FNum;               /* The File ID of the file */
+       u16 FABN;               /* allocation blocks number*/
+} __packed;
 
-/*======== Data structures kept in memory ========*/
+typedef union hfs_btree_key {
+       u8 key_len;                     /* number of bytes in the key */
+       struct hfs_cat_key cat;
+       struct hfs_ext_key ext;
+} hfs_btree_key;
 
-/*
- * struct hfs_mdb
- *
- * The fields from the MDB of an HFS filesystem
- */
-struct hfs_mdb {
-       int                     magic;          /* A magic number */
-       unsigned char           vname[28];      /* The volume name */
-       hfs_sysmdb              sys_mdb;        /* superblock */
-       hfs_buffer              buf;            /* The hfs_buffer
-                                                  holding the real
-                                                  superblock (aka VIB
-                                                  or MDB) */
-       hfs_buffer              alt_buf;        /* The hfs_buffer holding
-                                                  the alternate superblock */
-       hfs_buffer              bitmap[16];     /* The hfs_buffer holding the
-                                                  allocation bitmap */
-       struct hfs_btree *      ext_tree;       /* Information about
-                                                  the extents b-tree */
-       struct hfs_btree *      cat_tree;       /* Information about
-                                                  the catalog b-tree */
-       hfs_u32                 file_count;     /* The number of
-                                                  regular files in
-                                                  the filesystem */
-       hfs_u32                 dir_count;      /* The number of
-                                                  directories in the
-                                                  filesystem */
-       hfs_u32                 next_id;        /* The next available
-                                                  file id number */
-       hfs_u32                 clumpablks;     /* The number of allocation
-                                                  blocks to try to add when
-                                                  extending a file */
-       hfs_u32                 write_count;    /* The number of MDB
-                                                  writes (a sort of
-                                                  version number) */
-       hfs_u32                 fs_start;       /* The first 512-byte
-                                                  block represented
-                                                  in the bitmap */
-       hfs_u32                 create_date;    /* In network byte-order */
-       hfs_u32                 modify_date;    /* In network byte-order */
-       hfs_u32                 backup_date;    /* In network byte-order */
-       hfs_u16                 root_files;     /* The number of
-                                                  regular
-                                                  (non-directory)
-                                                  files in the root
-                                                  directory */
-       hfs_u16                 root_dirs;      /* The number of
-                                                  directories in the
-                                                  root directory */
-       hfs_u16                 fs_ablocks;     /* The number of
-                                                  allocation blocks
-                                                  in the filesystem */
-       hfs_u16                 free_ablocks;   /* The number of unused
-                                                  allocation blocks
-                                                  in the filesystem */
-       hfs_u32                 alloc_blksz;    /* The number of
-                                                  512-byte blocks per
-                                                  "allocation block" */
-       hfs_u16                 attrib;         /* Attribute word */
-       struct semaphore        bitmap_sem;
-        struct list_head        entry_dirty;
-};
+typedef union hfs_btree_key btree_key;
 
-/*
- * struct hfs_extent
- *
- * The offset to allocation block mapping for a given file is
- * contained in a series of these structures.  Each (struct
- * hfs_extent) records up to three runs of contiguous allocation
- * blocks.  An allocation block is a contiguous group of physical
- * blocks.
- */
 struct hfs_extent {
-       int                magic;     /* A magic number */
-       unsigned short     start;     /* Where in the file this record
-                                        begins (in allocation blocks) */
-       unsigned short     end;       /* Where in the file this record
-                                        ends (in allocation blocks) */
-       unsigned short     block[3];  /* The allocation block on disk which
-                                        begins this extent */
-       unsigned short     length[3]; /* The number of allocation blocks
-                                        in this extent */
-       struct hfs_extent  *next;     /* Next extent record for this file */
-       struct hfs_extent  *prev;     /* Previous extent record for this file */
-       int                count;     /* Number of times it is used */
-};
-
-/*
- * struct hfs_dir 
- *
- * This structure holds information specific
- * to a directory in an HFS filesystem.
- */
-struct hfs_dir {               
-       int             magic;          /* A magic number */
-       hfs_u16         flags;
-       hfs_u16         dirs;           /* Number of directories in this one */
-       hfs_u16         files;          /* Number of files in this directory */
-       struct rw_semaphore     sem;
-};
-
-/*
- * struct hfs_fork
- *
- * This structure holds the information
- * specific to a single fork of a file.
- */
-struct hfs_fork {
-       struct hfs_cat_entry    *entry;    /* The file this fork is part of */
-       struct hfs_extent       first;     /* The first extent record for
-                                                this fork */
-       struct hfs_extent       *cache;    /* The most-recently accessed
-                                                extent record for this fork */
-       hfs_u32                 lsize;     /* The logical size in bytes */
-       hfs_u32                 psize;     /* The phys size (512-byte blocks) */
-        hfs_u8                 fork;      /* Which fork is this? */
-};
-
-/*
- * struct hfs_file 
- *
- * This structure holds information specific
- * to a file in an HFS filesystem.
- */
-struct hfs_file {
-       int                magic;
-       struct hfs_fork    data_fork;
-       struct hfs_fork    rsrc_fork;
-       hfs_u16            clumpablks;
-       hfs_u8             flags;
-};
-
-/*
- * struct hfs_file 
- *
- * This structure holds information about a
- * file or directory in an HFS filesystem.
- *
- * 'wait' must remain 1st and 'hash' 2nd since we do some pointer arithmetic.
- */
-struct hfs_cat_entry {
-       hfs_wait_queue          wait;
-        struct list_head        hash;
-        struct list_head        list;
-       struct hfs_mdb          *mdb;
-       hfs_sysentry            sys_entry;
-       struct hfs_cat_key      key;
-       union hfs_finder_info   info;
-       hfs_u32                 cnid;           /* In network byte-order */
-       hfs_u32                 create_date;    /* In network byte-order */
-       hfs_u32                 modify_date;    /* In network byte-order */
-       hfs_u32                 backup_date;    /* In network byte-order */
-       unsigned short          count;
-        unsigned long           state;
-       hfs_u8                  type;
-       union {
-               struct hfs_dir  dir;
-               struct hfs_file file;
-       } u;
+       u16 block;
+       u16 count;
 };
+typedef struct hfs_extent hfs_extent_rec[3];
+
+/* The catalog record for a file */
+struct hfs_cat_file {
+       s8 type;                        /* The type of entry */
+       u8 reserved;
+       u8 Flags;                       /* Flags such as read-only */
+       s8 Typ;                         /* file version number = 0 */
+       struct hfs_finfo UsrWds;        /* data used by the Finder */
+       u32 FlNum;                      /* The CNID */
+       u16 StBlk;                      /* obsolete */
+       u32 LgLen;                      /* The logical EOF of the data fork*/
+       u32 PyLen;                      /* The physical EOF of the data fork */
+       u16 RStBlk;                     /* obsolete */
+       u32 RLgLen;                     /* The logical EOF of the rsrc fork */
+       u32 RPyLen;                     /* The physical EOF of the rsrc fork */
+       u32 CrDat;                      /* The creation date */
+       u32 MdDat;                      /* The modified date */
+       u32 BkDat;                      /* The last backup date */
+       struct hfs_fxinfo FndrInfo;     /* more data for the Finder */
+       u16 ClpSize;                    /* number of bytes to allocate
+                                          when extending files */
+       hfs_extent_rec ExtRec;          /* first extent record
+                                          for the data fork */
+       hfs_extent_rec RExtRec;         /* first extent record
+                                          for the resource fork */
+       u32 Resrv;                      /* reserved by Apple */
+} __packed;
+
+/* the catalog record for a directory */
+struct hfs_cat_dir {
+       s8 type;                        /* The type of entry */
+       u8 reserved;
+       u16 Flags;                      /* flags */
+       u16 Val;                        /* Valence: number of files and
+                                          dirs in the directory */
+       u32 DirID;                      /* The CNID */
+       u32 CrDat;                      /* The creation date */
+       u32 MdDat;                      /* The modification date */
+       u32 BkDat;                      /* The last backup date */
+       struct hfs_dinfo UsrInfo;       /* data used by the Finder */
+       struct hfs_dxinfo FndrInfo;     /* more data used by Finder */
+       u8 Resrv[16];                   /* reserved by Apple */
+} __packed;
+
+/* the catalog record for a thread */
+struct hfs_cat_thread {
+       s8 type;                        /* The type of entry */
+       u8 reserved[9];                 /* reserved by Apple */
+       u32 ParID;                      /* CNID of parent directory */
+       struct hfs_name CName;          /* The name of this entry */
+}  __packed;
+
+/* A catalog tree record */
+typedef union hfs_cat_rec {
+       s8 type;                        /* The type of entry */
+       struct hfs_cat_file file;
+       struct hfs_cat_dir dir;
+       struct hfs_cat_thread thread;
+} hfs_cat_rec;
 
-/* hfs entry state bits */
-#define HFS_DIRTY        1
-#define HFS_KEYDIRTY     2
-#define HFS_LOCK         4
-#define HFS_DELETED      8
-
-/* 
- * struct hfs_bnode_ref
- *
- * A pointer to a (struct hfs_bnode) and the type of lock held on it.
- */
-struct hfs_bnode_ref {
-        struct hfs_bnode *bn;
-        int lock_type;
-};
+struct hfs_mdb {
+       u16 drSigWord;                  /* Signature word indicating fs type */
+       u32 drCrDate;                   /* fs creation date/time */
+       u32 drLsMod;                    /* fs modification date/time */
+       u16 drAtrb;                     /* fs attributes */
+       u16 drNmFls;                    /* number of files in root directory */
+       u16 drVBMSt;                    /* location (in 512-byte blocks)
+                                          of the volume bitmap */
+       u16 drAllocPtr;                 /* location (in allocation blocks)
+                                          to begin next allocation search */
+       u16 drNmAlBlks;                 /* number of allocation blocks */
+       u32 drAlBlkSiz;                 /* bytes in an allocation block */
+       u32 drClpSiz;                   /* clumpsize, the number of bytes to
+                                          allocate when extending a file */
+       u16 drAlBlSt;                   /* location (in 512-byte blocks)
+                                          of the first allocation block */
+       u32 drNxtCNID;                  /* CNID to assign to the next
+                                          file or directory created */
+       u16 drFreeBks;                  /* number of free allocation blocks */
+       u8 drVN[28];                    /* the volume label */
+       u32 drVolBkUp;                  /* fs backup date/time */
+       u16 drVSeqNum;                  /* backup sequence number */
+       u32 drWrCnt;                    /* fs write count */
+       u32 drXTClpSiz;                 /* clumpsize for the extents B-tree */
+       u32 drCTClpSiz;                 /* clumpsize for the catalog B-tree */
+       u16 drNmRtDirs;                 /* number of directories in
+                                          the root directory */
+       u32 drFilCnt;                   /* number of files in the fs */
+       u32 drDirCnt;                   /* number of directories in the fs */
+       u8 drFndrInfo[32];              /* data used by the Finder */
+       u16 drEmbedSigWord;             /* embedded volume signature */
+       u32 drEmbedExtent;              /* starting block number (xdrStABN)
+                                          and number of allocation blocks
+                                          (xdrNumABlks) occupied by embedded
+                                          volume */
+       u32 drXTFlSize;                 /* bytes in the extents B-tree */
+       hfs_extent_rec drXTExtRec;      /* extents B-tree's first 3 extents */
+       u32 drCTFlSize;                 /* bytes in the catalog B-tree */
+       hfs_extent_rec drCTExtRec;      /* catalog B-tree's first 3 extents */
+} __packed;
 
-/*
- * struct hfs_belem
- *
- * An element of the path from the root of a B-tree to a leaf.
- * Includes the reference to a (struct hfs_bnode), the index of
- * the appropriate record in that node, and some flags.
- */
-struct hfs_belem {
-       struct hfs_bnode_ref    bnr;
-       int                     record;
-       int                     flags;
-};
+/*======== Data structures kept in memory ========*/
 
-/*
- * struct hfs_brec
- *
- * The structure returned by hfs_bfind() to describe the requested record.
- */
-struct hfs_brec {
-       int                     keep_flags;
-       struct hfs_btree        *tree;
-       struct hfs_belem        *top;
-       struct hfs_belem        *bottom;
-       struct hfs_belem        elem[9];
-       struct hfs_bkey         *key;
-       void                    *data;  /* The actual data */
+struct hfs_readdir_data {
+       struct list_head list;
+       struct file *file;
+       struct hfs_cat_key key;
 };
 
-/*================ Function prototypes ================*/
-
-/* bdelete.c */
-extern int hfs_bdelete(struct hfs_btree *, const struct hfs_bkey *);
-
-/* bfind.c */
-extern void hfs_brec_relse(struct hfs_brec *, struct hfs_belem *);
-extern int hfs_bsucc(struct hfs_brec *, int);
-extern int hfs_bfind(struct hfs_brec *, struct hfs_btree *,
-                    const struct hfs_bkey *, int);
-/* binsert.c */
-extern int hfs_binsert(struct hfs_btree *, const struct hfs_bkey *,
-                      const void *, hfs_u16);
-
-/* bitmap.c */
-extern hfs_u16 hfs_vbm_count_free(const struct hfs_mdb *, hfs_u16);
-extern hfs_u16 hfs_vbm_search_free(const struct hfs_mdb *, hfs_u16 *);
-extern int hfs_set_vbm_bits(struct hfs_mdb *, hfs_u16, hfs_u16);
-extern int hfs_clear_vbm_bits(struct hfs_mdb *, hfs_u16, hfs_u16);
-
-/* bitops.c */
-extern hfs_u32 hfs_find_zero_bit(const hfs_u32 *, hfs_u32, hfs_u32);
-extern hfs_u32 hfs_count_zero_bits(const hfs_u32 *, hfs_u32, hfs_u32);
-
-/* btree.c */
-extern struct hfs_btree *hfs_btree_init(struct hfs_mdb *, ino_t,
-                                       hfs_byte_t *, hfs_u32, hfs_u32);
-extern void hfs_btree_free(struct hfs_btree *);
-extern void hfs_btree_commit(struct hfs_btree *, hfs_byte_t *, hfs_lword_t);
-
-/* catalog.c */
-extern void hfs_cat_init(void);
-extern void hfs_cat_put(struct hfs_cat_entry *);
-extern void hfs_cat_mark_dirty(struct hfs_cat_entry *);
-extern struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *,
-                                        const struct hfs_cat_key *);
-
-extern void hfs_cat_invalidate(struct hfs_mdb *);
-extern void hfs_cat_commit(struct hfs_mdb *);
-extern void hfs_cat_free(void);
-
-extern int hfs_cat_compare(const struct hfs_cat_key *,
-                          const struct hfs_cat_key *);
-extern void hfs_cat_build_key(hfs_u32, const struct hfs_name *,
-                             struct hfs_cat_key *);
-extern struct hfs_cat_entry *hfs_cat_parent(struct hfs_cat_entry *);
-
-extern int hfs_cat_open(struct hfs_cat_entry *, struct hfs_brec *);
-extern int hfs_cat_next(struct hfs_cat_entry *, struct hfs_brec *,
-                       hfs_u16, hfs_u32 *, hfs_u8 *);
-extern void hfs_cat_close(struct hfs_cat_entry *, struct hfs_brec *);
-
-extern int hfs_cat_create(struct hfs_cat_entry *, struct hfs_cat_key *,
-                         hfs_u8, hfs_u32, hfs_u32, struct hfs_cat_entry **);
-extern int hfs_cat_mkdir(struct hfs_cat_entry *, struct hfs_cat_key *,
-                        struct hfs_cat_entry **);
-extern int hfs_cat_delete(struct hfs_cat_entry *, struct hfs_cat_entry *, int);
-extern int hfs_cat_move(struct hfs_cat_entry *, struct hfs_cat_entry *,
-                       struct hfs_cat_entry *, struct hfs_cat_key *,
-                       struct hfs_cat_entry **);
-
-/* extent.c */
-extern int hfs_ext_compare(const struct hfs_ext_key *,
-                          const struct hfs_ext_key *);
-extern void hfs_extent_in(struct hfs_fork *, const hfs_byte_t *);
-extern void hfs_extent_out(const struct hfs_fork *, hfs_byte_t *);
-extern int hfs_extent_map(struct hfs_fork *, int, int);
-extern void hfs_extent_adj(struct hfs_fork *);
-extern void hfs_extent_free(struct hfs_fork *);
-
-/* file.c */
-extern int hfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
-
-/* mdb.c */
-extern struct hfs_mdb *hfs_mdb_get(hfs_sysmdb, int, hfs_s32);
-extern void hfs_mdb_commit(struct hfs_mdb *, int);
-extern void hfs_mdb_put(struct hfs_mdb *, int);
-
-/* part_tbl.c */
-extern int hfs_part_find(hfs_sysmdb, int, int, hfs_s32 *, hfs_s32 *);
-
-/* string.c */
-extern unsigned int hfs_strhash(const unsigned char *, unsigned int);
-extern int hfs_strcmp(const unsigned char *, unsigned int, 
-                     const unsigned char *, unsigned int);
-extern int hfs_streq(const unsigned char *, unsigned int, 
-                    const unsigned char *, unsigned int);
-extern void hfs_tolower(unsigned char *, int);
-
-static __inline__ struct dentry 
-*hfs_lookup_dentry(struct dentry *base, const char *name, const int len)
-{
-  struct qstr this;
-
-  this.name = name;
-  this.len = len;
-  this.hash = hfs_strhash(name, len);
-
-  return d_lookup(base, &this);
-}
-
-/* drop a dentry for one of the special directories.
- * it's in the form of base/name/dentry. */
-static __inline__ void hfs_drop_special(struct dentry *base,
-                                       const struct hfs_name *name,
-                                       struct dentry *dentry)
-{
-  struct dentry *dparent, *de;
-  
-  dparent = hfs_lookup_dentry(base, name->Name, name->Len);
-  if (dparent) {
-         de = hfs_lookup_dentry(dparent, dentry->d_name.name, 
-                                dentry->d_name.len);
-         if (de) {
-                 if (!de->d_inode)
-                         d_drop(de);
-                 dput(de);
-         }
-         dput(dparent);
-  }
-}
-
-extern struct dentry_operations hfs_dentry_operations;
 #endif
diff --git a/fs/hfs/hfs_btree.h b/fs/hfs/hfs_btree.h
deleted file mode 100644 (file)
index b4bc106..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * linux/fs/hfs/hfs_btree.h
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the declarations of the private B-tree
- * structures and functions.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- */
-
-#ifndef _HFS_BTREE_H
-#define _HFS_BTREE_H
-
-#include "hfs.h"
-
-/*================ Variable-like macros ================*/
-
-/* The stickiness of a (struct hfs_bnode) */
-#define HFS_NOT_STICKY 0
-#define HFS_STICKY     1
-
-/* The number of hash buckets in a B-tree's bnode cache */
-#define HFS_CACHELEN   17      /* primes are best? */
-
-/*
- * Legal values for the 'ndType' field of a (struct NodeDescriptor)
- *
- * Reference: _Inside Macintosh: Files_ p. 2-65
- */
-#define ndIndxNode     0x00    /* An internal (index) node */
-#define ndHdrNode      0x01    /* The tree header node (node 0) */
-#define ndMapNode      0x02    /* Holds part of the bitmap of used nodes */
-#define ndLeafNode     0xFF    /* A leaf (ndNHeight==1) node */
-
-/*
- * Legal values for the bthAtrb field of a (struct BTHdrRec)
- *
- * Reference: TN 1150
- */
-#define bthBadClose     0x00000001  /* b-tree not closed properly. not
-                                       used by hfsplus. */
-#define bthBigKeys      0x00000002  /* key length is u16 instead of u8.
-                                      used by hfsplus. */
-#define bthVarIndxKeys  0x00000004  /* variable key length instead of
-                                       max key length. use din catalog
-                                       b-tree but not in extents
-                                       b-tree (hfsplus). */
-
-/*================ Function-like macros ================*/
-
-/* Access the cache slot which should contain the desired node */
-#define bhash(tree, node) ((tree)->cache[(node) % HFS_CACHELEN])
-
-/* round up to multiple of sizeof(hfs_u16) */
-#define ROUND(X) ((X + sizeof(hfs_u16) - 1) & ~(sizeof(hfs_u16)-1))
-
-/* Refer to the (base-1) array of offsets in a bnode */
-#define RECTBL(X,N) \
-       (((hfs_u16 *)(hfs_buffer_data((X)->buf)+HFS_SECTOR_SIZE))-(N))
-
-/*================ Private data types ================*/
-
-/*
- * struct BTHdrRec
- *
- * The B-tree header record
- *
- * This data structure is stored in the first node (512-byte block) of
- * each B-tree file.  It contains important information about the
- * B-tree.  Most fields vary over the life of the tree and are
- * indicated by a 'V' in the comments. The other fields are fixed for
- * the life of the tree and are indicated by a 'F'.
- *
- * Reference: _Inside Macintosh: Files_ pp. 2-68 through 2-69 */
-struct BTHdrRec {
-       hfs_word_t  bthDepth;   /* (V) The number of levels in this B-tree */
-       hfs_lword_t bthRoot;    /* (V) The node number of the root node */
-       hfs_lword_t bthNRecs;   /* (V) The number of leaf records */
-       hfs_lword_t bthFNode;   /* (V) The number of the first leaf node */
-       hfs_lword_t bthLNode;   /* (V) The number of the last leaf node */
-       hfs_word_t  bthNodeSize;        /* (F) The number of bytes in a node (=512) */
-       hfs_word_t  bthKeyLen;  /* (F) The length of a key in an index node */
-       hfs_lword_t bthNNodes;  /* (V) The total number of nodes */
-       hfs_lword_t bthFree;    /* (V) The number of unused nodes */
-        hfs_word_t  bthResv1;   /* reserved */
-        hfs_lword_t bthClpSiz;  /* (F) clump size. not usually used. */
-        hfs_byte_t  bthType;    /* (F) BTree type */
-        hfs_byte_t  bthResv2;   /* reserved */
-        hfs_lword_t bthAtrb;    /* (F) attributes */
-        hfs_lword_t bthResv3[16]; /* Reserved */
-} __attribute__((packed));
-
-/*
- * struct NodeDescriptor
- *
- * The B-tree node descriptor.
- *
- * This structure begins each node in the B-tree file. It contains
- * important information about the node's contents.  'V' and 'F' in
- * the comments indicate fields that are variable or fixed over the
- * life of a node, where the 'life' of a node is defined as the period
- * between leaving and reentering the free pool.
- *
- * Reference: _Inside Macintosh: Files_ p. 2-64
- */
-struct NodeDescriptor {
-       hfs_lword_t ndFLink;    /* (V) Number of the next node at this level */
-       hfs_lword_t ndBLink;    /* (V) Number of the prev node at this level */
-       hfs_byte_t  ndType;     /* (F) The type of node */
-       hfs_byte_t  ndNHeight;  /* (F) The level of this node (leaves=1) */
-       hfs_word_t  ndNRecs;    /* (V) The number of records in this node */
-       hfs_word_t  ndResv2;    /* Reserved */
-} __attribute__((packed));
-
-/*
- * typedef hfs_cmpfn
- *
- * The type 'hfs_cmpfn' is a comparison function taking 2 keys and
- * returning a positive, negative or zero integer according to the
- * ordering of the two keys (just like strcmp() does for strings).
- */
-typedef int (*hfs_cmpfn)(const void *, const void *);
-
-/*
- * struct hfs_bnode
- *
- * An in-core B-tree node
- *
- * This structure holds information from the NodeDescriptor in native
- * byte-order, a pointer to the buffer which contains the actual
- * node and fields necessary for locking access to the node during
- * updates.  The use of the locking fields is explained with the
- * locking functions.
- */
-struct hfs_bnode {
-       int                 magic;   /* Magic number to guard against
-                                       wild pointers */
-       hfs_buffer          buf;     /* The buffer containing the
-                                       actual node */
-       struct hfs_btree    *tree;   /* The tree to which this node
-                                       belongs */
-       struct hfs_bnode    *prev;   /* Next node in this hash bucket */
-       struct hfs_bnode    *next;   /* Previous node in this hash
-                                       bucket */
-       int                 sticky;  /* Boolean: non-zero means keep
-                                       this node in-core (set for
-                                       root and head) */
-       hfs_u32             node;    /* Node number */
-       hfs_u16             nodeSize; /* node size */
-        hfs_u16             keyLen;  /* key length */
-       /* locking related fields: */
-       hfs_wait_queue      wqueue;  /* Wait queue for write access */
-       hfs_wait_queue      rqueue;  /* Wait queue for read or reserve
-                                       access */
-       int                 count;   /* Number of processes accessing
-                                       this node */
-       int                 resrv;   /* Boolean, true means a process
-                                       had placed a 'reservation' on
-                                       this node */
-       int                 lock;    /* Boolean, true means some
-                                       process has exclusive access,
-                                       so KEEP OUT */
-       /* fields from the NodeDescriptor in native byte-order: */
-       hfs_u32             ndFLink;
-       hfs_u32             ndBLink;
-       hfs_u16             ndNRecs;
-       hfs_u8              ndType;
-       hfs_u8              ndNHeight;
-};
-
-/*
- * struct hfs_btree
- *
- * An in-core B-tree.
- *
- * This structure holds information from the BTHdrRec, MDB
- * (superblock) and other information needed to work with the B-tree.
- */
-struct hfs_btree {
-       int                     magic;         /* Magic number to
-                                                 guard against wild
-                                                 pointers */
-       hfs_cmpfn               compare;       /* Comparison function
-                                                 for this tree */
-       struct hfs_bnode        head;          /* in-core copy of node 0 */
-       struct hfs_bnode        *root;         /* Pointer to the in-core
-                                                 copy of the root node */
-       hfs_sysmdb              sys_mdb;       /* The "device" holding
-                                                 the filesystem */
-       int                     reserved;      /* bnodes claimed but
-                                                 not yet used */
-       struct hfs_bnode                       /* The bnode cache */
-                               *cache[HFS_CACHELEN];
-       struct hfs_cat_entry    entry;         /* Fake catalog entry */
-       struct semaphore        sem;
-       int                     dirt;
-       int                     keySize;   
-       /* Fields from the BTHdrRec in native byte-order: */
-       hfs_u32                 bthRoot;
-       hfs_u32                 bthNRecs;
-       hfs_u32                 bthFNode;
-       hfs_u32                 bthLNode;
-       hfs_u32                 bthNNodes;
-       hfs_u32                 bthFree;
-       hfs_u16                 bthKeyLen;
-       hfs_u16                 bthDepth;
-};
-
-/*================ Global functions ================*/
-
-/* Convert a (struct hfs_bnode *) and an index to the value of the
-   n-th offset in the bnode (N >= 1) to the offset */
-extern inline hfs_u16 bnode_offset(const struct hfs_bnode *bnode, int n)
-{ return hfs_get_hs(RECTBL(bnode,n)); }
-
-/* Convert a (struct hfs_bnode *) and an index to the size of the
-   n-th record in the bnode (N >= 1) */
-extern inline hfs_u16 bnode_rsize(const struct hfs_bnode *bnode, int n)
-{ return bnode_offset(bnode, n+1) - bnode_offset(bnode, n); }
-
-/* Convert a (struct hfs_bnode *) to the offset of the empty part */
-extern inline hfs_u16 bnode_end(const struct hfs_bnode *bnode)
-{ return bnode_offset(bnode, bnode->ndNRecs + 1); }
-
-/* Convert a (struct hfs_bnode *) to the number of free bytes it contains */
-extern inline hfs_u16 bnode_freespace(const struct hfs_bnode *bnode)
-{ return HFS_SECTOR_SIZE - bnode_end(bnode)
-         - (bnode->ndNRecs + 1)*sizeof(hfs_u16); }
-
-/* Convert a (struct hfs_bnode *) X and an index N to
-   the address of the record N in the bnode (N >= 1) */
-extern inline void *bnode_datastart(const struct hfs_bnode *bnode)
-{ return (void *)(hfs_buffer_data(bnode->buf)+sizeof(struct NodeDescriptor)); }
-
-/* Convert a (struct hfs_bnode *) to the address of the empty part */
-extern inline void *bnode_dataend(const struct hfs_bnode *bnode)
-{ return (void *)(hfs_buffer_data(bnode->buf) + bnode_end(bnode)); }
-
-/* Convert various pointers to address of record's key */
-extern inline void *bnode_key(const struct hfs_bnode *bnode, int n)
-{ return (void *)(hfs_buffer_data(bnode->buf) + bnode_offset(bnode, n)); }
-extern inline void *belem_key(const struct hfs_belem *elem)
-{ return bnode_key(elem->bnr.bn, elem->record); }
-extern inline void *brec_key(const struct hfs_brec *brec)
-{ return belem_key(brec->bottom); }
-
-/* Convert various pointers to the address of a record */
-extern inline void *bkey_record(const struct hfs_bkey *key)
-{ return (void *)key + ROUND(key->KeyLen + 1); }
-extern inline void *bnode_record(const struct hfs_bnode *bnode, int n)
-{ return bkey_record(bnode_key(bnode, n)); }
-extern inline void *belem_record(const struct hfs_belem *elem)
-{ return bkey_record(belem_key(elem)); }
-extern inline void *brec_record(const struct hfs_brec *brec)
-{ return bkey_record(brec_key(brec)); }
-
-/*================ Function Prototypes ================*/
-
-/* balloc.c */
-extern int hfs_bnode_bitop(struct hfs_btree *, hfs_u32, int);
-extern struct hfs_bnode_ref hfs_bnode_alloc(struct hfs_btree *);
-extern int hfs_bnode_free(struct hfs_bnode_ref *);
-extern void hfs_btree_extend(struct hfs_btree *);
-
-/* bins_del.c */
-extern void hfs_bnode_update_key(struct hfs_brec *, struct hfs_belem *,
-                                struct hfs_bnode *, int);
-extern void hfs_bnode_shift_right(struct hfs_bnode *, struct hfs_bnode *, int);
-extern void hfs_bnode_shift_left(struct hfs_bnode *, struct hfs_bnode *, int);
-extern int hfs_bnode_in_brec(hfs_u32 node, const struct hfs_brec *brec);
-
-/* bnode.c */
-extern void hfs_bnode_read(struct hfs_bnode *, struct hfs_btree *,
-                          hfs_u32, int);
-extern void hfs_bnode_relse(struct hfs_bnode_ref *);
-extern struct hfs_bnode_ref hfs_bnode_find(struct hfs_btree *, hfs_u32, int);
-extern void hfs_bnode_lock(struct hfs_bnode_ref *, int);
-extern void hfs_bnode_delete(struct hfs_bnode *);
-extern void hfs_bnode_commit(struct hfs_bnode *);
-
-/* brec.c */
-extern void hfs_brec_lock(struct hfs_brec *, struct hfs_belem *);
-extern struct hfs_belem *hfs_brec_init(struct hfs_brec *, struct hfs_btree *,
-                                      int);
-extern struct hfs_belem *hfs_brec_next(struct hfs_brec *);
-
-#endif
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
new file mode 100644 (file)
index 0000000..33876db
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ *  linux/fs/hfs/hfs_fs.h
+ *
+ * Copyright (C) 1995-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
+ * This file may be distributed under the terms of the GNU General Public License.
+ */
+
+#ifndef _LINUX_HFS_FS_H
+#define _LINUX_HFS_FS_H
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/buffer_head.h>
+#include <linux/fs.h>
+
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include "hfs.h"
+
+#define DBG_BNODE_REFS 0x00000001
+#define DBG_BNODE_MOD  0x00000002
+#define DBG_CAT_MOD    0x00000004
+#define DBG_INODE      0x00000008
+#define DBG_SUPER      0x00000010
+#define DBG_EXTENT     0x00000020
+#define DBG_BITMAP     0x00000040
+
+//#define DBG_MASK     (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD|DBG_CAT_MOD|DBG_BITMAP)
+//#define DBG_MASK     (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
+//#define DBG_MASK     (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
+#define DBG_MASK       (0)
+
+#define dprint(flg, fmt, args...) \
+       if (flg & DBG_MASK) printk(fmt , ## args)
+
+#define hfs_warn(format, args...) printk(KERN_WARNING format , ## args)
+#define hfs_error(format, args...) printk(KERN_ERR format , ## args)
+
+/*
+ * struct hfs_inode_info
+ *
+ * The HFS-specific part of a Linux (struct inode)
+ */
+struct hfs_inode_info {
+       atomic_t opencnt;
+
+       unsigned int flags;
+
+       /* to deal with localtime ugliness */
+       int tz_secondswest;
+
+       struct hfs_cat_key cat_key;
+
+       struct list_head open_dir_list;
+       struct inode *rsrc_inode;
+
+       struct semaphore extents_lock;
+
+       u16 alloc_blocks, clump_blocks;
+       /* Allocation extents from catlog record or volume header */
+       hfs_extent_rec first_extents;
+       u16 first_blocks;
+       hfs_extent_rec cached_extents;
+       u16 cached_start, cached_blocks;
+
+       loff_t phys_size;
+       struct inode vfs_inode;
+};
+
+#define HFS_FLG_RSRC           0x0001
+#define HFS_FLG_EXT_DIRTY      0x0002
+#define HFS_FLG_EXT_NEW                0x0004
+
+#define HFS_IS_RSRC(inode)     (HFS_I(inode)->flags & HFS_FLG_RSRC)
+
+/*
+ * struct hfs_sb_info
+ *
+ * The HFS-specific part of a Linux (struct super_block)
+ */
+struct hfs_sb_info {
+       struct buffer_head *mdb_bh;             /* The hfs_buffer
+                                                  holding the real
+                                                  superblock (aka VIB
+                                                  or MDB) */
+       struct hfs_mdb *mdb;
+       struct buffer_head *alt_mdb_bh;         /* The hfs_buffer holding
+                                                  the alternate superblock */
+       struct hfs_mdb *alt_mdb;
+       u32 *bitmap;                            /* The page holding the
+                                                  allocation bitmap */
+       struct hfs_btree *ext_tree;                     /* Information about
+                                                  the extents b-tree */
+       struct hfs_btree *cat_tree;                     /* Information about
+                                                  the catalog b-tree */
+       u32 file_count;                         /* The number of
+                                                  regular files in
+                                                  the filesystem */
+       u32 folder_count;                       /* The number of
+                                                  directories in the
+                                                  filesystem */
+       u32 next_id;                            /* The next available
+                                                  file id number */
+       u32 clumpablks;                         /* The number of allocation
+                                                  blocks to try to add when
+                                                  extending a file */
+       u32 fs_start;                           /* The first 512-byte
+                                                  block represented
+                                                  in the bitmap */
+       u32 part_start;
+       u16 root_files;                         /* The number of
+                                                  regular
+                                                  (non-directory)
+                                                  files in the root
+                                                  directory */
+       u16 root_dirs;                          /* The number of
+                                                  directories in the
+                                                  root directory */
+       u16 fs_ablocks;                         /* The number of
+                                                  allocation blocks
+                                                  in the filesystem */
+       u16 free_ablocks;                       /* the number of unused
+                                                  allocation blocks
+                                                  in the filesystem */
+       u32 alloc_blksz;                        /* The size of an
+                                                  "allocation block" */
+       int s_quiet;                            /* Silent failure when
+                                                  changing owner or mode? */
+       u32 s_type;                             /* Type for new files */
+       u32 s_creator;                          /* Creator for new files */
+       umode_t s_file_umask;                   /* The umask applied to the
+                                                  permissions on all files */
+       umode_t s_dir_umask;                    /* The umask applied to the
+                                                  permissions on all dirs */
+       uid_t s_uid;                            /* The uid of all files */
+       gid_t s_gid;                            /* The gid of all files */
+
+       int session, part;
+
+       struct semaphore bitmap_lock;
+
+       unsigned long flags;
+
+       u16 blockoffset;
+
+       int fs_div;
+
+       struct hlist_head rsrc_inodes;
+};
+
+#define HFS_FLG_BITMAP_DIRTY   0
+#define HFS_FLG_MDB_DIRTY      1
+#define HFS_FLG_ALT_MDB_DIRTY  2
+
+/* bitmap.c */
+extern u32 hfs_vbm_search_free(struct super_block *, u32, u32 *);
+extern int hfs_clear_vbm_bits(struct super_block *, u16, u16);
+
+/* catalog.c */
+extern int hfs_cat_keycmp(const btree_key *, const btree_key *);
+struct hfs_find_data;
+extern int hfs_cat_find_brec(struct super_block *, u32, struct hfs_find_data *);
+extern int hfs_cat_create(u32, struct inode *, struct qstr *, struct inode *);
+extern int hfs_cat_delete(u32, struct inode *, struct qstr *);
+extern int hfs_cat_move(u32, struct inode *, struct qstr *,
+                       struct inode *, struct qstr *);
+extern void hfs_cat_build_key(btree_key *, u32, struct qstr *);
+
+/* dir.c */
+extern struct file_operations hfs_dir_operations;
+extern struct inode_operations hfs_dir_inode_operations;
+
+extern int hfs_mkdir(struct inode *, struct dentry *, int);
+extern int hfs_unlink(struct inode *, struct dentry *);
+extern int hfs_rmdir(struct inode *, struct dentry *);
+extern int hfs_rename(struct inode *, struct dentry *,
+                     struct inode *, struct dentry *);
+
+/* extent.c */
+extern int hfs_ext_keycmp(const btree_key *, const btree_key *);
+extern int hfs_free_fork(struct super_block *, struct hfs_cat_file *, int);
+extern void hfs_ext_write_extent(struct inode *);
+extern int hfs_extend_file(struct inode *);
+extern void hfs_file_truncate(struct inode *);
+
+/* file.c */
+extern struct inode_operations hfs_file_inode_operations;
+extern struct file_operations hfs_file_operations;
+
+extern int hfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
+
+/* inode.c */
+extern struct address_space_operations hfs_aops;
+extern struct address_space_operations hfs_btree_aops;
+
+extern struct inode *hfs_new_inode(struct inode *, struct qstr *, int);
+extern void hfs_inode_write_fork(struct inode *, struct hfs_extent *, u32 *, u32 *);
+extern void hfs_write_inode(struct inode *, int);
+extern int hfs_inode_setattr(struct dentry *, struct iattr *);
+extern void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext,
+                               u32 log_size, u32 phys_size, u32 clump_size);
+extern struct inode *hfs_iget(struct super_block *, struct hfs_cat_key *, hfs_cat_rec *);
+extern void hfs_clear_inode(struct inode *);
+extern void hfs_delete_inode(struct inode *);
+
+/* mdb.c */
+extern int hfs_mdb_get(struct super_block *);
+extern void hfs_mdb_commit(struct super_block *);
+extern void hfs_mdb_close(struct super_block *);
+extern void hfs_mdb_put(struct super_block *);
+
+/* part_tbl.c */
+extern int hfs_part_find(struct super_block *, sector_t *, sector_t *);
+
+/* string.c */
+extern struct dentry_operations hfs_dentry_operations;
+
+extern int hfs_hash_dentry(struct dentry *, struct qstr *);
+extern int hfs_strcmp(const unsigned char *, unsigned int,
+                     const unsigned char *, unsigned int);
+extern int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
+
+/* super.c */
+extern struct super_block *hfs_read_super(struct super_block *,void *,int);
+
+/* trans.c */
+extern void hfs_triv2mac(struct hfs_name *, struct qstr *);
+extern int hfs_mac2triv(char *, const struct hfs_name *);
+
+extern struct timezone sys_tz;
+
+/*
+ * There are two time systems.  Both are based on seconds since
+ * a particular time/date.
+ *     Unix:   unsigned lil-endian since 00:00 GMT, Jan. 1, 1970
+ *     mac:    unsigned big-endian since 00:00 GMT, Jan. 1, 1904
+ *
+ */
+#define __hfs_u_to_mtime(sec)  cpu_to_be32(sec + 2082844800U - sys_tz.tz_minuteswest * 60)
+#define __hfs_m_to_utime(sec)  (be32_to_cpu(sec) - 2082844800U  + sys_tz.tz_minuteswest * 60)
+
+#define HFS_I(inode)   (list_entry(inode, struct hfs_inode_info, vfs_inode))
+#define HFS_SB(sb)     ((struct hfs_sb_info *)(sb)->s_fs_info)
+
+#define hfs_m_to_utime(time)   (struct timespec){ .tv_sec = __hfs_m_to_utime(time) }
+#define hfs_u_to_mtime(time)   __hfs_u_to_mtime((time).tv_sec)
+#define hfs_mtime()            __hfs_u_to_mtime(get_seconds())
+
+static inline const char *hfs_mdb_name(struct super_block *sb)
+{
+       return sb->s_id;
+}
+
+static inline void hfs_bitmap_dirty(struct super_block *sb)
+{
+       set_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags);
+       sb->s_dirt = 1;
+}
+
+static inline void hfs_buffer_sync(struct buffer_head *bh)
+{
+       while (buffer_locked(bh)) {
+               wait_on_buffer(bh);
+       }
+       if (buffer_dirty(bh)) {
+               ll_rw_block(WRITE, 1, &bh);
+               wait_on_buffer(bh);
+       }
+}
+
+#define sb_bread512(sb, sec, data) ({                  \
+       struct buffer_head *__bh;                       \
+       sector_t __block;                               \
+       loff_t __start;                                 \
+       int __offset;                                   \
+                                                       \
+       __start = (loff_t)(sec) << HFS_SECTOR_SIZE_BITS;\
+       __block = __start >> (sb)->s_blocksize_bits;    \
+       __offset = __start & ((sb)->s_blocksize - 1);   \
+       __bh = sb_bread((sb), __block);                 \
+       if (likely(__bh != NULL))                       \
+               data = (void *)(__bh->b_data + __offset);\
+       else                                            \
+               data = NULL;                            \
+       __bh;                                           \
+})
+
+#endif
index 398de286c3e73dd45ff7f75165db44138b3e839a..e6a2ea549dba64f242f5bebecae23b4ce37b34d6 100644 (file)
 /*
- * linux/fs/hfs/inode.c
+ *  linux/fs/hfs/inode.c
  *
  * Copyright (C) 1995-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * This file contains inode-related functions which do not depend on
  * which scheme is being used to represent forks.
  *
  * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
  */
 
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
+#include <linux/version.h>
+#include <linux/mpage.h>
+
+#include "hfs_fs.h"
+#include "btree.h"
 
 /*================ Variable-like macros ================*/
 
 #define HFS_VALID_MODE_BITS  (S_IFREG | S_IFDIR | S_IRWXUGO)
 
-/*================ File-local functions ================*/
+static int hfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+       return block_write_full_page(page, hfs_get_block, wbc);
+}
 
-/*
- * init_file_inode()
- *
- * Given an HFS catalog entry initialize an inode for a file.
- */
-static void init_file_inode(struct inode *inode, hfs_u8 fork)
+static int hfs_readpage(struct file *file, struct page *page)
 {
-       struct hfs_fork *fk;
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
+       return block_read_full_page(page, hfs_get_block);
+}
 
-       if (fork == HFS_FK_DATA) {
-               inode->i_mode = S_IRWXUGO | S_IFREG;
-       } else {
-               inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
-       }
+static int hfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+{
+       return cont_prepare_write(page, from, to, hfs_get_block,
+                                 &HFS_I(page->mapping->host)->phys_size);
+}
 
-       if (fork == HFS_FK_DATA) {
-#if 0 /* XXX: disable crlf translations for now */
-               hfs_u32 type = hfs_get_nl(entry->info.file.finfo.fdType);
-
-               HFS_I(inode)->convert =
-                       ((HFS_SB(inode->i_sb)->s_conv == 't') ||
-                        ((HFS_SB(inode->i_sb)->s_conv == 'a') &&
-                         ((type == htonl(0x54455854)) ||   /* "TEXT" */
-                          (type == htonl(0x7474726f)))));  /* "ttro" */
-#else
-               HFS_I(inode)->convert = 0;
-#endif
-               fk = &entry->u.file.data_fork;
+static sector_t hfs_bmap(struct address_space *mapping, sector_t block)
+{
+       return generic_block_bmap(mapping, block, hfs_get_block);
+}
+
+int hfs_releasepage(struct page *page, int mask)
+{
+       struct inode *inode = page->mapping->host;
+       struct super_block *sb = inode->i_sb;
+       struct hfs_btree *tree;
+       struct hfs_bnode *node;
+       u32 nidx;
+       int i, res = 1;
+
+       switch (inode->i_ino) {
+       case HFS_EXT_CNID:
+               tree = HFS_SB(sb)->ext_tree;
+               break;
+       case HFS_CAT_CNID:
+               tree = HFS_SB(sb)->cat_tree;
+               break;
+       default:
+               BUG();
+               return 0;
+       }
+       if (tree->node_size >= PAGE_CACHE_SIZE) {
+               nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT);
+               spin_lock(&tree->hash_lock);
+               node = hfs_bnode_findhash(tree, nidx);
+               if (!node)
+                       ;
+               else if (atomic_read(&node->refcnt))
+                       res = 0;
+               else for (i = 0; i < tree->pages_per_bnode; i++) {
+                       if (PageActive(node->page[i])) {
+                               res = 0;
+                               break;
+                       }
+               }
+               if (res && node) {
+                       hfs_bnode_unhash(node);
+                       hfs_bnode_free(node);
+               }
+               spin_unlock(&tree->hash_lock);
        } else {
-               fk = &entry->u.file.rsrc_fork;
-               HFS_I(inode)->convert = 0;
+               nidx = page->index << (PAGE_CACHE_SHIFT - tree->node_size_shift);
+               i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
+               spin_lock(&tree->hash_lock);
+               do {
+                       node = hfs_bnode_findhash(tree, nidx++);
+                       if (!node)
+                               continue;
+                       if (atomic_read(&node->refcnt)) {
+                               res = 0;
+                               break;
+                       }
+                       hfs_bnode_unhash(node);
+                       hfs_bnode_free(node);
+               } while (--i);
+               spin_unlock(&tree->hash_lock);
        }
-       HFS_I(inode)->fork = fk;
-       inode->i_size = fk->lsize;
-       inode->i_blocks = fk->psize;
-       inode->i_nlink = 1;
+       //printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
+       return res;
 }
 
-/*================ Global functions ================*/
+static int hfs_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
+                         struct buffer_head *bh_result, int create)
+{
+       int ret;
 
-/*
* hfs_put_inode()
- *
- * This is the put_inode() entry in the super_operations for HFS
- * filesystems.  The purpose is to perform any filesystem-dependent 
- * cleanup necessary when the use-count of an inode falls to zero.
- */
-void hfs_put_inode(struct inode * inode)
+       ret = hfs_get_block(inode, iblock, bh_result, create);
      if (!ret)
+               bh_result->b_size = (1 << inode->i_blkbits);
+       return ret;
+}
+
+static int hfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
+                        loff_t offset, unsigned long nr_segs)
 {
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
 
-       lock_kernel();
-       hfs_cat_put(entry);
-       if (atomic_read(&inode->i_count) == 1) {
-         struct hfs_hdr_layout *tmp = HFS_I(inode)->layout;
+       return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+                                 offset, nr_segs, hfs_get_blocks, NULL);
+}
 
-         if (tmp) {
-               HFS_I(inode)->layout = NULL;
-               HFS_DELETE(tmp);
-         }
-       }
-       unlock_kernel();
+static int hfs_writepages(struct address_space *mapping,
+                         struct writeback_control *wbc)
+{
+       return mpage_writepages(mapping, wbc, hfs_get_block);
 }
 
+struct address_space_operations hfs_btree_aops = {
+       .readpage       = hfs_readpage,
+       .writepage      = hfs_writepage,
+       .sync_page      = block_sync_page,
+       .prepare_write  = hfs_prepare_write,
+       .commit_write   = generic_commit_write,
+       .bmap           = hfs_bmap,
+       .releasepage    = hfs_releasepage,
+};
+
+struct address_space_operations hfs_aops = {
+       .readpage       = hfs_readpage,
+       .writepage      = hfs_writepage,
+       .sync_page      = block_sync_page,
+       .prepare_write  = hfs_prepare_write,
+       .commit_write   = generic_commit_write,
+       .bmap           = hfs_bmap,
+       .direct_IO      = hfs_direct_IO,
+       .writepages     = hfs_writepages,
+};
+
 /*
- * hfs_notify_change()
- *
- * Based very closely on fs/msdos/inode.c by Werner Almesberger
- *
- * This is the notify_change() field in the super_operations structure
- * for HFS file systems.  The purpose is to take that changes made to
- * an inode and apply then in a filesystem-dependent manner.  In this
- * case the process has a few of tasks to do:
- *  1) prevent changes to the i_uid and i_gid fields.
- *  2) map file permissions to the closest allowable permissions
- *  3) Since multiple Linux files can share the same on-disk inode under
- *     HFS (for instance the data and resource forks of a file) a change
- *     to permissions must be applied to all other in-core inodes which 
- *     correspond to the same HFS file.
+ * hfs_new_inode
  */
-enum {HFS_NORM, HFS_HDR, HFS_CAP};
-
-static int __hfs_notify_change(struct dentry *dentry, struct iattr * attr, int kind)
+struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode)
 {
-       struct inode *inode = dentry->d_inode;
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
-       struct dentry **de = entry->sys_entry;
-       struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
-       int error=0, i;
-
-       lock_kernel();
+       struct super_block *sb = dir->i_sb;
+       struct inode *inode = new_inode(sb);
+       if (!inode)
+               return NULL;
 
-       error = inode_change_ok(inode, attr); /* basic permission checks */
-       if (error) {
-               /* Let netatalk's afpd think chmod() always succeeds */
-               if (hsb->s_afpd &&
-                   (attr->ia_valid == (ATTR_MODE | ATTR_CTIME))) {
-                       error = 0;
-               }
-               goto out; 
+       init_MUTEX(&HFS_I(inode)->extents_lock);
+       INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
+       hfs_cat_build_key((btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
+       inode->i_ino = HFS_SB(sb)->next_id++;
+       inode->i_mode = mode;
+       inode->i_uid = current->fsuid;
+       inode->i_gid = current->fsgid;
+       inode->i_nlink = 1;
+       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+       HFS_I(inode)->flags = 0;
+       HFS_I(inode)->rsrc_inode = NULL;
+       if (S_ISDIR(inode->i_mode)) {
+               inode->i_size = 2;
+               HFS_SB(sb)->folder_count++;
+               if (dir->i_ino == HFS_ROOT_CNID)
+                       HFS_SB(sb)->root_dirs++;
+               inode->i_op = &hfs_dir_inode_operations;
+               inode->i_fop = &hfs_dir_operations;
+       } else if (S_ISREG(inode->i_mode)) {
+               HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks;
+               HFS_SB(sb)->file_count++;
+               if (dir->i_ino == HFS_ROOT_CNID)
+                       HFS_SB(sb)->root_files++;
+               inode->i_op = &hfs_file_inode_operations;
+               inode->i_fop = &hfs_file_operations;
+               inode->i_mapping->a_ops = &hfs_aops;
+               HFS_I(inode)->phys_size = 0;
+               HFS_I(inode)->alloc_blocks = 0;
+               HFS_I(inode)->first_blocks = 0;
+               HFS_I(inode)->cached_start = 0;
+               HFS_I(inode)->cached_blocks = 0;
+               memset(HFS_I(inode)->first_extents, 0, sizeof(hfs_extent_rec));
+               memset(HFS_I(inode)->cached_extents, 0, sizeof(hfs_extent_rec));
        }
+       insert_inode_hash(inode);
+       mark_inode_dirty(inode);
+       set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
+       sb->s_dirt = 1;
 
-       /* no uig/gid changes and limit which mode bits can be set */
-       if (((attr->ia_valid & ATTR_UID) && 
-            (attr->ia_uid != hsb->s_uid)) ||
-           ((attr->ia_valid & ATTR_GID) && 
-            (attr->ia_gid != hsb->s_gid)) ||
-           ((attr->ia_valid & ATTR_MODE) &&
-            (((entry->type == HFS_CDR_DIR) &&
-              (attr->ia_mode != inode->i_mode))||
-             (attr->ia_mode & ~HFS_VALID_MODE_BITS)))) {
-               if( hsb->s_quiet ) { 
-                       error = 0;
-                       goto out;
-               }
-       }
-       
-       if (entry->type == HFS_CDR_DIR) {
-               attr->ia_valid &= ~ATTR_MODE;
-       } else if (attr->ia_valid & ATTR_MODE) {
-               /* Only the 'w' bits can ever change and only all together. */
-               if (attr->ia_mode & S_IWUSR) {
-                       attr->ia_mode = inode->i_mode | S_IWUGO;
-               } else {
-                       attr->ia_mode = inode->i_mode & ~S_IWUGO;
-               }
-               attr->ia_mode &= ~hsb->s_umask;
-       }
-       /*
-        * Normal files handle size change in normal way.
-        * Oddballs are served here.
-        */
-       if (attr->ia_valid & ATTR_SIZE) {
-               if (kind == HFS_CAP) {
-                       inode->i_size = attr->ia_size;
-                       if (inode->i_size > HFS_FORK_MAX)
-                               inode->i_size = HFS_FORK_MAX;
-                       mark_inode_dirty(inode);
-                       attr->ia_valid &= ~ATTR_SIZE;
-               } else if (kind == HFS_HDR) {
-                       hdr_truncate(inode, attr->ia_size);
-                       attr->ia_valid &= ~ATTR_SIZE;
-               }
-       }
-       error = inode_setattr(inode, attr);
-       if (error) 
-               goto out;
-       
-       /* We wouldn't want to mess with the sizes of the other fork */
-       attr->ia_valid &= ~ATTR_SIZE;
-
-       /* We must change all in-core inodes corresponding to this file. */
-       for (i = 0; i < 4; ++i) {
-         if (de[i] && (de[i] != dentry)) {
-               inode_setattr(de[i]->d_inode, attr);
-         }
-       }
+       return inode;
+}
 
-       /* Change the catalog entry if needed */
-       if (attr->ia_valid & ATTR_MTIME) {
-               entry->modify_date = hfs_u_to_mtime(inode->i_mtime.tv_sec);
-               hfs_cat_mark_dirty(entry);
+void hfs_delete_inode(struct inode *inode)
+{
+       struct super_block *sb = inode->i_sb;
+
+       dprint(DBG_INODE, "delete_inode: %lu\n", inode->i_ino);
+       if (S_ISDIR(inode->i_mode)) {
+               HFS_SB(sb)->folder_count--;
+               if (HFS_I(inode)->cat_key.ParID == be32_to_cpu(HFS_ROOT_CNID))
+                       HFS_SB(sb)->root_dirs--;
+               set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
+               sb->s_dirt = 1;
+               return;
        }
-       if (attr->ia_valid & ATTR_MODE) {
-               hfs_u8 new_flags;
-
-               if (inode->i_mode & S_IWUSR) {
-                       new_flags = entry->u.file.flags & ~HFS_FIL_LOCK;
-               } else {
-                       new_flags = entry->u.file.flags | HFS_FIL_LOCK;
-               }
-
-               if (new_flags != entry->u.file.flags) {
-                       entry->u.file.flags = new_flags;
-                       hfs_cat_mark_dirty(entry);
+       HFS_SB(sb)->file_count--;
+       if (HFS_I(inode)->cat_key.ParID == be32_to_cpu(HFS_ROOT_CNID))
+               HFS_SB(sb)->root_files--;
+       if (S_ISREG(inode->i_mode)) {
+               if (!inode->i_nlink) {
+                       inode->i_size = 0;
+                       hfs_file_truncate(inode);
                }
        }
-       /* size changes handled in hfs_extent_adj() */
-
-out:
-       unlock_kernel();
-       return error;
+       set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
+       sb->s_dirt = 1;
 }
 
-int hfs_notify_change(struct dentry *dentry, struct iattr * attr)
+void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext,
+                        u32 log_size, u32 phys_size, u32 clump_size)
 {
-       return __hfs_notify_change(dentry, attr, HFS_NORM);
+       struct super_block *sb = inode->i_sb;
+       u16 count;
+       int i;
+
+       memcpy(HFS_I(inode)->first_extents, ext, sizeof(hfs_extent_rec));
+       for (count = 0, i = 0; i < 3; i++)
+               count += be16_to_cpu(ext[i].count);
+       HFS_I(inode)->first_blocks = count;
+
+       log_size = be32_to_cpu(log_size);
+       inode->i_size = HFS_I(inode)->phys_size = log_size;
+       inode->i_blocks = (log_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+       HFS_I(inode)->alloc_blocks = be32_to_cpu(phys_size) /
+                                    HFS_SB(sb)->alloc_blksz;
+       HFS_I(inode)->clump_blocks = clump_size / HFS_SB(sb)->alloc_blksz;
+       if (!HFS_I(inode)->clump_blocks)
+               HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks;
 }
 
-int hfs_notify_change_cap(struct dentry *dentry, struct iattr * attr)
-{
-       return __hfs_notify_change(dentry, attr, HFS_CAP);
-}
+struct hfs_iget_data {
+       struct hfs_cat_key *key;
+       hfs_cat_rec *rec;
+};
 
-int hfs_notify_change_hdr(struct dentry *dentry, struct iattr * attr)
+int hfs_test_inode(struct inode *inode, void *data)
 {
-       return __hfs_notify_change(dentry, attr, HFS_HDR);
+       struct hfs_iget_data *idata = data;
+       hfs_cat_rec *rec;
+
+       rec = idata->rec;
+       switch (rec->type) {
+       case HFS_CDR_DIR:
+               return inode->i_ino == be32_to_cpu(rec->dir.DirID);
+       case HFS_CDR_FIL:
+               return inode->i_ino == be32_to_cpu(rec->file.FlNum);
+       default:
+               BUG();
+               return 1;
+       }
 }
 
-static int hfs_writepage(struct page *page, struct writeback_control *wbc)
-{
-       return block_write_full_page(page,hfs_get_block, wbc);
-}
-static int hfs_readpage(struct file *file, struct page *page)
-{
-       return block_read_full_page(page,hfs_get_block);
-}
-static int hfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
-{
-       return cont_prepare_write(page,from,to,hfs_get_block,
-               &HFS_I(page->mapping->host)->mmu_private);
-}
-static sector_t hfs_bmap(struct address_space *mapping, sector_t block)
+/*
+ * hfs_read_inode
+ */
+int hfs_read_inode(struct inode *inode, void *data)
 {
-       return generic_block_bmap(mapping,block,hfs_get_block);
+       struct hfs_iget_data *idata = data;
+       struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
+       hfs_cat_rec *rec;
+
+       HFS_I(inode)->flags = 0;
+       HFS_I(inode)->rsrc_inode = NULL;
+       init_MUTEX(&HFS_I(inode)->extents_lock);
+       INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
+
+       /* Initialize the inode */
+       inode->i_uid = hsb->s_uid;
+       inode->i_gid = hsb->s_gid;
+       inode->i_nlink = 1;
+
+       if (idata->key)
+               HFS_I(inode)->cat_key = *idata->key;
+       else
+               HFS_I(inode)->flags |= HFS_FLG_RSRC;
+       HFS_I(inode)->tz_secondswest = sys_tz.tz_minuteswest * 60;
+
+       rec = idata->rec;
+       switch (rec->type) {
+       case HFS_CDR_FIL:
+               if (!HFS_IS_RSRC(inode)) {
+                       hfs_inode_read_fork(inode, rec->file.ExtRec, rec->file.LgLen,
+                                           rec->file.PyLen, be16_to_cpu(rec->file.ClpSize));
+               } else {
+                       hfs_inode_read_fork(inode, rec->file.RExtRec, rec->file.RLgLen,
+                                           rec->file.RPyLen, be16_to_cpu(rec->file.ClpSize));
+               }
+
+               inode->i_ino = be32_to_cpu(rec->file.FlNum);
+               inode->i_mode = S_IRUGO | S_IXUGO;
+               if (!(rec->file.Flags & HFS_FIL_LOCK))
+                       inode->i_mode |= S_IWUGO;
+               inode->i_mode &= hsb->s_file_umask;
+               inode->i_mode |= S_IFREG;
+               inode->i_ctime = inode->i_atime = inode->i_mtime =
+                               hfs_m_to_utime(rec->file.MdDat);
+               inode->i_op = &hfs_file_inode_operations;
+               inode->i_fop = &hfs_file_operations;
+               inode->i_mapping->a_ops = &hfs_aops;
+               HFS_I(inode)->phys_size = inode->i_size;
+               break;
+       case HFS_CDR_DIR:
+               inode->i_ino = be32_to_cpu(rec->dir.DirID);
+               inode->i_blocks = 0;
+               inode->i_size = be16_to_cpu(rec->dir.Val) + 2;
+               inode->i_mode = S_IFDIR | (S_IRWXUGO & hsb->s_dir_umask);
+               inode->i_ctime = inode->i_atime = inode->i_mtime =
+                               hfs_m_to_utime(rec->file.MdDat);
+               inode->i_op = &hfs_dir_inode_operations;
+               inode->i_fop = &hfs_dir_operations;
+               break;
+       default:
+               make_bad_inode(inode);
+       }
+       return 0;
 }
-struct address_space_operations hfs_aops = {
-       .readpage = hfs_readpage,
-       .writepage = hfs_writepage,
-       .sync_page = block_sync_page,
-       .prepare_write = hfs_prepare_write,
-       .commit_write = generic_commit_write,
-       .bmap = hfs_bmap
-};
 
 /*
  * __hfs_iget()
@@ -263,253 +346,277 @@ struct address_space_operations hfs_aops = {
  * inode for that file/directory or NULL.  Note that 'type' indicates
  * whether we want the actual file or directory, or the corresponding
  * metadata (AppleDouble header file or CAP metadata file).
- *
- * In an ideal world we could call iget() and would not need this
- * function.  However, since there is no way to even know the inode
- * number until we've found the file/directory in the catalog B-tree
- * that simply won't happen.
- *
- * The main idea here is to look in the catalog B-tree to get the
- * vital info about the file or directory (including the file id which
- * becomes the inode number) and then to call iget() and return the
- * inode if it is complete.  If it is not then we use the catalog
- * entry to fill in the missing info, by calling the appropriate
- * 'fillin' function.  Note that these fillin functions are
- * essentially hfs_*_read_inode() functions, but since there is no way
- * to pass the catalog entry through iget() to such a read_inode()
- * function, we have to call them after iget() returns an incomplete
- * inode to us.         This is pretty much the same problem faced in the NFS
- * code, and pretty much the same solution. The SMB filesystem deals
- * with this in a different way: by using the address of the
- * kmalloc()'d space which holds the data as the inode number.
- *
- * XXX: Both this function and NFS's corresponding nfs_fhget() would
- * benefit from a way to pass an additional (void *) through iget() to
- * the VFS read_inode() function.
- *
- * this will hfs_cat_put() the entry if it fails.
  */
-struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type,
-                      struct dentry *dentry)
+struct inode *hfs_iget(struct super_block *sb, struct hfs_cat_key *key, hfs_cat_rec *rec)
 {
-       struct dentry **sys_entry;
-       struct super_block *sb;
+       struct hfs_iget_data data = { key, rec };
        struct inode *inode;
-
-       if (!entry) {
+       u32 cnid;
+
+       switch (rec->type) {
+       case HFS_CDR_DIR:
+               cnid = be32_to_cpu(rec->dir.DirID);
+               break;
+       case HFS_CDR_FIL:
+               cnid = be32_to_cpu(rec->file.FlNum);
+               break;
+       default:
                return NULL;
        }
+       inode = iget5_locked(sb, cnid, hfs_test_inode, hfs_read_inode, &data);
+       if (inode && (inode->i_state & I_NEW))
+               unlock_new_inode(inode);
+       return inode;
+}
+
+void hfs_inode_write_fork(struct inode *inode, struct hfs_extent *ext,
+                         u32 *log_size, u32 *phys_size)
+{
+       memcpy(ext, HFS_I(inode)->first_extents, sizeof(hfs_extent_rec));
+
+       if (log_size)
+               *log_size = cpu_to_be32(inode->i_size);
+       if (phys_size)
+               *phys_size = cpu_to_be32(HFS_I(inode)->alloc_blocks *
+                                        HFS_SB(inode->i_sb)->alloc_blksz);
+}
+
+void hfs_write_inode(struct inode *inode, int unused)
+{
+       struct hfs_find_data fd;
+       hfs_cat_rec rec;
+
+       dprint(DBG_INODE, "hfs_write_inode: %lu\n", inode->i_ino);
+       hfs_ext_write_extent(inode);
+
+       if (inode->i_ino < HFS_FIRSTUSER_CNID) {
+               switch (inode->i_ino) {
+               case HFS_ROOT_CNID:
+                       break;
+               case HFS_EXT_CNID:
+                       hfs_btree_write(HFS_SB(inode->i_sb)->ext_tree);
+                       return;
+               case HFS_CAT_CNID:
+                       hfs_btree_write(HFS_SB(inode->i_sb)->cat_tree);
+                       return;
+               default:
+                       BUG();
+                       return;
+               }
+       }
 
-       /* If there are several processes all calling __iget() for
-          the same inode then they will all get the same one back.
-          The first one to return from __iget() will notice that the
-          i_mode field of the inode is blank and KNOW that it is
-          the first to return.  Therefore, it will set the appropriate
-          'sys_entry' field in the entry and initialize the inode.
-          All the initialization must be done without sleeping,
-          or else other processes could end up using a partially
-          initialized inode.                           */
-
-       sb = entry->mdb->sys_mdb;
-       sys_entry = &entry->sys_entry[HFS_ITYPE_TO_INT(type)];
-
-       if (!(inode = iget(sb, ntohl(entry->cnid) | type))) {
-               hfs_cat_put(entry);
-               return NULL;
+       if (HFS_IS_RSRC(inode)) {
+               mark_inode_dirty(HFS_I(inode)->rsrc_inode);
+               return;
        }
 
-       if (!inode->i_mode || (*sys_entry == NULL)) {
-               /* Initialize the inode */
-               struct hfs_sb_info *hsb = HFS_SB(sb);
-
-               inode->i_ctime.tv_sec = inode->i_atime.tv_sec = inode->i_mtime.tv_sec =
-                                       hfs_m_to_utime(entry->modify_date);
-               inode->i_ctime.tv_nsec = 0;
-               inode->i_mtime.tv_nsec = 0;
-               inode->i_atime.tv_nsec = 0;
-               inode->i_blksize = HFS_SECTOR_SIZE;
-               inode->i_uid = hsb->s_uid;
-               inode->i_gid = hsb->s_gid;
-
-               HFS_I(inode)->mmu_private = 0;
-               HFS_I(inode)->fork = NULL;
-               HFS_I(inode)->convert = 0;
-               HFS_I(inode)->file_type = 0;
-               HFS_I(inode)->dir_size = 0;
-               HFS_I(inode)->default_layout = NULL;
-               HFS_I(inode)->layout = NULL;
-               HFS_I(inode)->magic = HFS_INO_MAGIC;
-               HFS_I(inode)->entry = entry;
-               HFS_I(inode)->tz_secondswest = hfs_to_utc(0);
-
-               hsb->s_ifill(inode, type, hsb->s_version);
-               if (!hsb->s_afpd && (entry->type == HFS_CDR_FIL) &&
-                   (entry->u.file.flags & HFS_FIL_LOCK)) {
-                       inode->i_mode &= ~S_IWUGO;
+       if (!inode->i_nlink)
+               return;
+
+       if (hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd))
+               /* panic? */
+               return;
+
+       fd.search_key->cat = HFS_I(inode)->cat_key;
+       if (hfs_brec_find(&fd))
+               /* panic? */
+               goto out;
+
+       if (S_ISDIR(inode->i_mode)) {
+               if (fd.entrylength < sizeof(struct hfs_cat_dir))
+                       /* panic? */;
+               hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
+                          sizeof(struct hfs_cat_dir));
+               if (rec.type != HFS_CDR_DIR ||
+                   be32_to_cpu(rec.dir.DirID) != inode->i_ino) {
                }
-               inode->i_mode &= ~hsb->s_umask;
 
-               if (!inode->i_mode) {
-                       iput(inode); /* does an hfs_cat_put */
-                       inode = NULL;
-               } else
-                       *sys_entry = dentry; /* cache dentry */
+               rec.dir.MdDat = hfs_u_to_mtime(inode->i_mtime);
+               rec.dir.Val = cpu_to_be16(inode->i_size - 2);
 
-       }
+               hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
+                           sizeof(struct hfs_cat_dir));
+       } else {
+               if (fd.entrylength < sizeof(struct hfs_cat_file))
+                       /* panic? */;
+               hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
+                          sizeof(struct hfs_cat_file));
+               if (rec.type != HFS_CDR_FIL ||
+                   be32_to_cpu(rec.file.FlNum) != inode->i_ino) {
+               }
 
-       return inode;
+               if (inode->i_mode & S_IWUSR)
+                       rec.file.Flags &= ~HFS_FIL_LOCK;
+               else
+                       rec.file.Flags |= HFS_FIL_LOCK;
+               hfs_inode_write_fork(inode, rec.file.ExtRec, &rec.file.LgLen, &rec.file.PyLen);
+               if (HFS_I(inode)->rsrc_inode)
+                       hfs_inode_write_fork(HFS_I(inode)->rsrc_inode, rec.file.RExtRec,
+                                            &rec.file.RLgLen, &rec.file.RPyLen);
+               rec.file.MdDat = hfs_u_to_mtime(inode->i_mtime);
+
+               hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
+                           sizeof(struct hfs_cat_file));
+       }
+out:
+       hfs_find_exit(&fd);
 }
 
-/*================ Scheme-specific functions ================*/
-
-/* 
- * hfs_cap_ifill()
- *
- * This function serves the same purpose as a read_inode() function does
- * in other filesystems.  It is called by __hfs_iget() to fill in
- * the missing fields of an uninitialized inode under the CAP scheme.
- */
-void hfs_cap_ifill(struct inode * inode, ino_t type, const int version)
+static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
+                                     struct nameidata *nd)
 {
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
+       struct inode *inode = NULL;
+       hfs_cat_rec rec;
+       struct hfs_find_data fd;
+       int res;
 
-       HFS_I(inode)->d_drop_op = hfs_cap_drop_dentry;
-       if (type == HFS_CAP_FNDR) {
-               inode->i_size = sizeof(struct hfs_cap_info);
-               inode->i_blocks = 0;
-               inode->i_nlink = 1;
-               inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
-               inode->i_op = &hfs_cap_info_inode_operations;
-               inode->i_fop = &hfs_cap_info_operations;
-       } else if (entry->type == HFS_CDR_FIL) {
-               init_file_inode(inode, (type == HFS_CAP_DATA) ?
-                                               HFS_FK_DATA : HFS_FK_RSRC);
-               inode->i_op = &hfs_file_inode_operations;
-               inode->i_fop = &hfs_file_operations;
-               inode->i_mapping->a_ops = &hfs_aops;
-               HFS_I(inode)->mmu_private = inode->i_size;
-       } else { /* Directory */
-               struct hfs_dir *hdir = &entry->u.dir;
+       if (HFS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
+               goto out;
 
-               inode->i_blocks = 0;
-               inode->i_size = hdir->files + hdir->dirs + 5;
-               HFS_I(inode)->dir_size = 1;
-               if (type == HFS_CAP_NDIR) {
-                       inode->i_mode = S_IRWXUGO | S_IFDIR;
-                       inode->i_nlink = hdir->dirs + 4;
-                       inode->i_op = &hfs_cap_ndir_inode_operations;
-                       inode->i_fop = &hfs_cap_dir_operations;
-                       HFS_I(inode)->file_type = HFS_CAP_NORM;
-               } else if (type == HFS_CAP_FDIR) {
-                       inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
-                       inode->i_nlink = 2;
-                       inode->i_op = &hfs_cap_fdir_inode_operations;
-                       inode->i_fop = &hfs_cap_dir_operations;
-                       HFS_I(inode)->file_type = HFS_CAP_FNDR;
-               } else if (type == HFS_CAP_RDIR) {
-                       inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
-                       inode->i_nlink = 2;
-                       inode->i_op = &hfs_cap_rdir_inode_operations;
-                       inode->i_fop = &hfs_cap_dir_operations;
-                       HFS_I(inode)->file_type = HFS_CAP_RSRC;
-               }
+       inode = HFS_I(dir)->rsrc_inode;
+       if (inode)
+               goto out;
+
+       inode = new_inode(dir->i_sb);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+
+       hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
+       fd.search_key->cat = HFS_I(dir)->cat_key;
+       res = hfs_brec_read(&fd, &rec, sizeof(rec));
+       if (!res) {
+               struct hfs_iget_data idata = { NULL, &rec };
+               hfs_read_inode(inode, &idata);
        }
+       hfs_find_exit(&fd);
+       if (res) {
+               iput(inode);
+               return ERR_PTR(res);
+       }
+       HFS_I(inode)->rsrc_inode = dir;
+       HFS_I(dir)->rsrc_inode = inode;
+       igrab(dir);
+       hlist_add_head(&inode->i_hash, &HFS_SB(dir->i_sb)->rsrc_inodes);
+       mark_inode_dirty(inode);
+out:
+       d_add(dentry, inode);
+       return NULL;
 }
 
-/* 
- * hfs_dbl_ifill()
- *
- * This function serves the same purpose as a read_inode() function does
- * in other filesystems.  It is called by __hfs_iget() to fill in
- * the missing fields of an uninitialized inode under the AppleDouble
- * scheme.
- */
-void hfs_dbl_ifill(struct inode * inode, ino_t type, const int version)
+void hfs_clear_inode(struct inode *inode)
 {
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
-
-       HFS_I(inode)->d_drop_op = hfs_dbl_drop_dentry;
-       if (type == HFS_DBL_HDR) {
-               if (entry->type == HFS_CDR_FIL) {
-                       init_file_inode(inode, HFS_FK_RSRC);
-                       inode->i_size += HFS_DBL_HDR_LEN;
-                       HFS_I(inode)->default_layout = &hfs_dbl_fil_hdr_layout;
-               } else {
-                       inode->i_size = HFS_DBL_HDR_LEN;
-                       inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
-                       inode->i_nlink = 1;
-                       HFS_I(inode)->default_layout = &hfs_dbl_dir_hdr_layout;
-               }
-               inode->i_op = &hfs_hdr_inode_operations;
-               inode->i_fop = &hfs_hdr_operations;
-       } else if (entry->type == HFS_CDR_FIL) {
-               init_file_inode(inode, HFS_FK_DATA);
-               inode->i_op = &hfs_file_inode_operations;
-               inode->i_fop = &hfs_file_operations;
-               inode->i_mapping->a_ops = &hfs_aops;
-               HFS_I(inode)->mmu_private = inode->i_size;
-       } else { /* Directory */
-               struct hfs_dir *hdir = &entry->u.dir;
+       if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) {
+               HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
+               iput(HFS_I(inode)->rsrc_inode);
+       }
+}
 
-               inode->i_blocks = 0;
-               inode->i_nlink = hdir->dirs + 2;
-               inode->i_size = 3 + 2 * (hdir->dirs + hdir->files);
-               inode->i_mode = S_IRWXUGO | S_IFDIR;
-               inode->i_op = &hfs_dbl_dir_inode_operations;
-               inode->i_fop = &hfs_dbl_dir_operations;
-               HFS_I(inode)->file_type = HFS_DBL_NORM;
-               HFS_I(inode)->dir_size = 2;
+static int hfs_permission(struct inode *inode, int mask,
+                         struct nameidata *nd)
+{
+       if (S_ISREG(inode->i_mode) && mask & MAY_EXEC)
+               return 0;
+       return vfs_permission(inode, mask);
+}
+
+static int hfs_file_open(struct inode *inode, struct file *file)
+{
+       if (HFS_IS_RSRC(inode))
+               inode = HFS_I(inode)->rsrc_inode;
+       if (atomic_read(&file->f_count) != 1)
+               return 0;
+       atomic_inc(&HFS_I(inode)->opencnt);
+       return 0;
+}
+
+static int hfs_file_release(struct inode *inode, struct file *file)
+{
+       //struct super_block *sb = inode->i_sb;
+
+       if (HFS_IS_RSRC(inode))
+               inode = HFS_I(inode)->rsrc_inode;
+       if (atomic_read(&file->f_count) != 0)
+               return 0;
+       if (atomic_dec_and_test(&HFS_I(inode)->opencnt)) {
+               down(&inode->i_sem);
+               hfs_file_truncate(inode);
+               //if (inode->i_flags & S_DEAD) {
+               //      hfs_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL);
+               //      hfs_delete_inode(inode);
+               //}
+               up(&inode->i_sem);
        }
+       return 0;
 }
 
-/* 
- * hfs_nat_ifill()
+/*
+ * hfs_notify_change()
+ *
+ * Based very closely on fs/msdos/inode.c by Werner Almesberger
  *
- * This function serves the same purpose as a read_inode() function does
- * in other filesystems.  It is called by __hfs_iget() to fill in
- * the missing fields of an uninitialized inode under the Netatalk
- * scheme.
+ * This is the notify_change() field in the super_operations structure
+ * for HFS file systems.  The purpose is to take that changes made to
+ * an inode and apply then in a filesystem-dependent manner.  In this
+ * case the process has a few of tasks to do:
+ *  1) prevent changes to the i_uid and i_gid fields.
+ *  2) map file permissions to the closest allowable permissions
+ *  3) Since multiple Linux files can share the same on-disk inode under
+ *     HFS (for instance the data and resource forks of a file) a change
+ *     to permissions must be applied to all other in-core inodes which
+ *     correspond to the same HFS file.
  */
-void hfs_nat_ifill(struct inode * inode, ino_t type, const int version)
+
+int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
 {
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
+       struct inode *inode = dentry->d_inode;
+       struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
+       int error;
 
-       HFS_I(inode)->d_drop_op = hfs_nat_drop_dentry;
-       if (type == HFS_NAT_HDR) {
-               if (entry->type == HFS_CDR_FIL) {
-                       init_file_inode(inode, HFS_FK_RSRC);
-                       inode->i_size += HFS_NAT_HDR_LEN;
-               } else {
-                       inode->i_size = HFS_NAT_HDR_LEN;
-                       inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
-                       inode->i_nlink = 1;
-               }
-               inode->i_op = &hfs_hdr_inode_operations;
-               inode->i_fop = &hfs_hdr_operations;
-               HFS_I(inode)->default_layout = (version == 2) ?
-                       &hfs_nat2_hdr_layout : &hfs_nat_hdr_layout;
-       } else if (entry->type == HFS_CDR_FIL) {
-               init_file_inode(inode, HFS_FK_DATA);
-               inode->i_op = &hfs_file_inode_operations;
-               inode->i_fop = &hfs_file_operations;
-               inode->i_mapping->a_ops = &hfs_aops;
-               HFS_I(inode)->mmu_private = inode->i_size;
-       } else { /* Directory */
-               struct hfs_dir *hdir = &entry->u.dir;
+       error = inode_change_ok(inode, attr); /* basic permission checks */
+       if (error)
+               return error;
 
-               inode->i_blocks = 0;
-               inode->i_size = hdir->files + hdir->dirs + 4;
-               inode->i_mode = S_IRWXUGO | S_IFDIR;
-               HFS_I(inode)->dir_size = 1;
-               if (type == HFS_NAT_NDIR) {
-                       inode->i_nlink = hdir->dirs + 3;
-                       inode->i_op = &hfs_nat_ndir_inode_operations;
-                       HFS_I(inode)->file_type = HFS_NAT_NORM;
-               } else if (type == HFS_NAT_HDIR) {
-                       inode->i_nlink = 2;
-                       inode->i_op = &hfs_nat_hdir_inode_operations;
-                       HFS_I(inode)->file_type = HFS_NAT_HDR;
-               }
-               inode->i_fop = &hfs_nat_dir_operations;
+       /* no uig/gid changes and limit which mode bits can be set */
+       if (((attr->ia_valid & ATTR_UID) &&
+            (attr->ia_uid != hsb->s_uid)) ||
+           ((attr->ia_valid & ATTR_GID) &&
+            (attr->ia_gid != hsb->s_gid)) ||
+           ((attr->ia_valid & ATTR_MODE) &&
+            ((S_ISDIR(inode->i_mode) &&
+              (attr->ia_mode != inode->i_mode)) ||
+             (attr->ia_mode & ~HFS_VALID_MODE_BITS)))) {
+               return hsb->s_quiet ? 0 : error;
        }
+
+       if (attr->ia_valid & ATTR_MODE) {
+               /* Only the 'w' bits can ever change and only all together. */
+               if (attr->ia_mode & S_IWUSR)
+                       attr->ia_mode = inode->i_mode | S_IWUGO;
+               else
+                       attr->ia_mode = inode->i_mode & ~S_IWUGO;
+               attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask;
+       }
+       error = inode_setattr(inode, attr);
+       if (error)
+               return error;
+
+       return 0;
 }
+
+
+struct file_operations hfs_file_operations = {
+       .llseek         = generic_file_llseek,
+       .read           = generic_file_read,
+       .write          = generic_file_write,
+       .mmap           = generic_file_mmap,
+       .fsync          = file_fsync,
+       .open           = hfs_file_open,
+       .release        = hfs_file_release,
+};
+
+struct inode_operations hfs_file_inode_operations = {
+       .lookup         = hfs_file_lookup,
+       .truncate       = hfs_file_truncate,
+       .setattr        = hfs_inode_setattr,
+       .permission     = hfs_permission,
+};
index b3f8477f58cbd0cb9b10e5726f7fb87a3a150881..cedb9ab184c38090decb8c28f812fd295a30e969 100644 (file)
@@ -1,28 +1,22 @@
 /*
- * linux/fs/hfs/mdb.c
+ *  linux/fs/hfs/mdb.c
  *
  * Copyright (C) 1995-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * This file contains functions for reading/writing the MDB.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- *
- * The code in this file initializes some structures which contain
- * pointers by calling memset(&foo, 0, sizeof(foo)).
- * This produces the desired behavior only due to the non-ANSI
- * assumption that the machine representation of NULL is all zeros.
  */
 
-#include "hfs.h"
+#include <linux/cdrom.h>
+#include <linux/genhd.h>
+
+#include "hfs_fs.h"
+#include "btree.h"
 
 /*================ File-local data types ================*/
 
-/* 
+/*
  * The HFS Master Directory Block (MDB).
  *
  * Also known as the Volume Information Block (VIB), this structure is
  *
  * modified for HFS Extended
  */
-struct raw_mdb {
-       hfs_word_t      drSigWord;      /* Signature word indicating fs type */
-       hfs_lword_t     drCrDate;       /* fs creation date/time */
-       hfs_lword_t     drLsMod;        /* fs modification date/time */
-       hfs_word_t      drAtrb;         /* fs attributes */
-       hfs_word_t      drNmFls;        /* number of files in root directory */
-       hfs_word_t      drVBMSt;        /* location (in 512-byte blocks)
-                                          of the volume bitmap */
-       hfs_word_t      drAllocPtr;     /* location (in allocation blocks)
-                                          to begin next allocation search */
-       hfs_word_t      drNmAlBlks;     /* number of allocation blocks */
-       hfs_lword_t     drAlBlkSiz;     /* bytes in an allocation block */
-       hfs_lword_t     drClpSiz;       /* clumpsize, the number of bytes to
-                                          allocate when extending a file */
-       hfs_word_t      drAlBlSt;       /* location (in 512-byte blocks)
-                                          of the first allocation block */
-       hfs_lword_t     drNxtCNID;      /* CNID to assign to the next
-                                          file or directory created */
-       hfs_word_t      drFreeBks;      /* number of free allocation blocks */
-       hfs_byte_t      drVN[28];       /* the volume label */
-       hfs_lword_t     drVolBkUp;      /* fs backup date/time */
-       hfs_word_t      drVSeqNum;      /* backup sequence number */
-       hfs_lword_t     drWrCnt;        /* fs write count */
-       hfs_lword_t     drXTClpSiz;     /* clumpsize for the extents B-tree */
-       hfs_lword_t     drCTClpSiz;     /* clumpsize for the catalog B-tree */
-       hfs_word_t      drNmRtDirs;     /* number of directories in
-                                          the root directory */
-       hfs_lword_t     drFilCnt;       /* number of files in the fs */
-       hfs_lword_t     drDirCnt;       /* number of directories in the fs */
-       hfs_byte_t      drFndrInfo[32]; /* data used by the Finder */
-       hfs_word_t      drEmbedSigWord; /* embedded volume signature */
-       hfs_lword_t     drEmbedExtent;  /* starting block number (xdrStABN) 
-                                          and number of allocation blocks 
-                                          (xdrNumABlks) occupied by embedded
-                                          volume */
-       hfs_lword_t     drXTFlSize;     /* bytes in the extents B-tree */
-       hfs_byte_t      drXTExtRec[12]; /* extents B-tree's first 3 extents */
-       hfs_lword_t     drCTFlSize;     /* bytes in the catalog B-tree */
-       hfs_byte_t      drCTExtRec[12]; /* catalog B-tree's first 3 extents */
-} __attribute__((packed));
-
-/*================ Global functions ================*/
+
+static int hfs_get_last_session(struct super_block *sb,
+                               sector_t *start, sector_t *size)
+{
+       struct cdrom_multisession ms_info;
+       struct cdrom_tocentry te;
+       int res;
+
+       /* default values */
+       *start = 0;
+       *size = sb->s_bdev->bd_inode->i_size >> 9;
+
+       if (HFS_SB(sb)->session >= 0) {
+               te.cdte_track = HFS_SB(sb)->session;
+               te.cdte_format = CDROM_LBA;
+               res = ioctl_by_bdev(sb->s_bdev, CDROMREADTOCENTRY, (unsigned long)&te);
+               if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) {
+                       *start = (sector_t)te.cdte_addr.lba << 2;
+                       return 0;
+               }
+               printk(KERN_ERR "HFS: Invalid session number or type of track\n");
+               return -EINVAL;
+       }
+       ms_info.addr_format = CDROM_LBA;
+       res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION, (unsigned long)&ms_info);
+       if (!res && ms_info.xa_flag)
+               *start = (sector_t)ms_info.addr.lba << 2;
+       return 0;
+}
 
 /*
  * hfs_mdb_get()
@@ -81,135 +62,172 @@ struct raw_mdb {
  * Build the in-core MDB for a filesystem, including
  * the B-trees and the volume bitmap.
  */
-struct hfs_mdb *hfs_mdb_get(hfs_sysmdb sys_mdb, int readonly,
-                           hfs_s32 part_start)
+int hfs_mdb_get(struct super_block *sb)
 {
-       struct hfs_mdb *mdb;
-       hfs_buffer buf;
-       struct raw_mdb *raw;
-       unsigned int bs, block;
-       int lcv, limit;
-       hfs_buffer *bmbuf;
-
-       if (!HFS_NEW(mdb)) {
-               hfs_warn("hfs_fs: out of memory\n");
-               return NULL;
-       }
+       struct buffer_head *bh;
+       struct hfs_mdb *mdb, *mdb2;
+       unsigned int block;
+       char *ptr;
+       int off2, len, size, sect;
+       sector_t part_start, part_size;
+       loff_t off;
+       u16 attrib;
 
-       memset(mdb, 0, sizeof(*mdb));
-       mdb->magic = HFS_MDB_MAGIC;
-       mdb->sys_mdb = sys_mdb;
-       INIT_LIST_HEAD(&mdb->entry_dirty);
-       init_MUTEX(&mdb->bitmap_sem);
-
-       /* See if this is an HFS filesystem */
-       buf = hfs_buffer_get(sys_mdb, part_start + HFS_MDB_BLK, 1);
-       if (!hfs_buffer_ok(buf)) {
-               hfs_warn("hfs_fs: Unable to read superblock\n");
-               HFS_DELETE(mdb);
-               goto bail2;
+       /* set the device driver to 512-byte blocks */
+       size = sb_min_blocksize(sb, HFS_SECTOR_SIZE);
+       if (!size)
+               return -EINVAL;
+
+       if (hfs_get_last_session(sb, &part_start, &part_size))
+               return -EINVAL;
+       while (1) {
+               /* See if this is an HFS filesystem */
+               bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb);
+               if (!bh)
+                       goto out;
+
+               if (mdb->drSigWord == cpu_to_be16(HFS_SUPER_MAGIC))
+                       break;
+               brelse(bh);
+
+               /* check for a partition block
+                * (should do this only for cdrom/loop though)
+                */
+               if (hfs_part_find(sb, &part_start, &part_size))
+                       goto out;
        }
 
-       raw = (struct raw_mdb *)hfs_buffer_data(buf);
-       if (hfs_get_ns(raw->drSigWord) != htons(HFS_SUPER_MAGIC)) {
-               hfs_buffer_put(buf);
-               HFS_DELETE(mdb);
-               goto bail2;
+       HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz);
+       if (!size || (size & (HFS_SECTOR_SIZE - 1))) {
+               hfs_warn("hfs_fs: bad allocation block size %d\n", size);
+               goto out_bh;
        }
-       mdb->buf = buf;
-       
-       bs = hfs_get_hl(raw->drAlBlkSiz);
-       if (!bs || (bs & (HFS_SECTOR_SIZE-1))) {
-               hfs_warn("hfs_fs: bad allocation block size %d != 512\n", bs);
-               hfs_buffer_put(buf);
-               HFS_DELETE(mdb);
-               goto bail2;
+
+       size = min(HFS_SB(sb)->alloc_blksz, (u32)PAGE_SIZE);
+       /* size must be a multiple of 512 */
+       while (size & (size - 1))
+               size -= HFS_SECTOR_SIZE;
+       sect = be16_to_cpu(mdb->drAlBlSt) + part_start;
+       /* align block size to first sector */
+       while (sect & ((size - 1) >> HFS_SECTOR_SIZE_BITS))
+               size >>= 1;
+       /* align block size to weird alloc size */
+       while (HFS_SB(sb)->alloc_blksz & (size - 1))
+               size >>= 1;
+       brelse(bh);
+       if (!sb_set_blocksize(sb, size)) {
+               printk("hfs_fs: unable to set blocksize to %u\n", size);
+               goto out;
        }
-       mdb->alloc_blksz = bs >> HFS_SECTOR_SIZE_BITS;
+
+       bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb);
+       if (!bh)
+               goto out;
+       if (mdb->drSigWord != cpu_to_be16(HFS_SUPER_MAGIC))
+               goto out_bh;
+
+       HFS_SB(sb)->mdb_bh = bh;
+       HFS_SB(sb)->mdb = mdb;
 
        /* These parameters are read from the MDB, and never written */
-       mdb->create_date = hfs_get_hl(raw->drCrDate);
-       mdb->fs_ablocks  = hfs_get_hs(raw->drNmAlBlks);
-       mdb->fs_start    = hfs_get_hs(raw->drAlBlSt) + part_start;
-       mdb->backup_date = hfs_get_hl(raw->drVolBkUp);
-       mdb->clumpablks  = (hfs_get_hl(raw->drClpSiz) / mdb->alloc_blksz)
-                                                >> HFS_SECTOR_SIZE_BITS;
-       memcpy(mdb->vname, raw->drVN, sizeof(raw->drVN));
+       HFS_SB(sb)->part_start = part_start;
+       HFS_SB(sb)->fs_ablocks = be16_to_cpu(mdb->drNmAlBlks);
+       HFS_SB(sb)->fs_div = HFS_SB(sb)->alloc_blksz >> sb->s_blocksize_bits;
+       HFS_SB(sb)->clumpablks = be32_to_cpu(mdb->drClpSiz) /
+                                HFS_SB(sb)->alloc_blksz;
+       if (!HFS_SB(sb)->clumpablks)
+               HFS_SB(sb)->clumpablks = 1;
+       HFS_SB(sb)->fs_start = (be16_to_cpu(mdb->drAlBlSt) + part_start) >>
+                              (sb->s_blocksize_bits - HFS_SECTOR_SIZE_BITS);
 
        /* These parameters are read from and written to the MDB */
-       mdb->modify_date  = hfs_get_nl(raw->drLsMod);
-       mdb->attrib       = hfs_get_ns(raw->drAtrb);
-       mdb->free_ablocks = hfs_get_hs(raw->drFreeBks);
-       mdb->next_id      = hfs_get_hl(raw->drNxtCNID);
-       mdb->write_count  = hfs_get_hl(raw->drWrCnt);
-       mdb->root_files   = hfs_get_hs(raw->drNmFls);
-       mdb->root_dirs    = hfs_get_hs(raw->drNmRtDirs);
-       mdb->file_count   = hfs_get_hl(raw->drFilCnt);
-       mdb->dir_count    = hfs_get_hl(raw->drDirCnt);
+       HFS_SB(sb)->free_ablocks = be16_to_cpu(mdb->drFreeBks);
+       HFS_SB(sb)->next_id = be32_to_cpu(mdb->drNxtCNID);
+       HFS_SB(sb)->root_files = be16_to_cpu(mdb->drNmFls);
+       HFS_SB(sb)->root_dirs = be16_to_cpu(mdb->drNmRtDirs);
+       HFS_SB(sb)->file_count = be32_to_cpu(mdb->drFilCnt);
+       HFS_SB(sb)->folder_count = be32_to_cpu(mdb->drDirCnt);
 
        /* TRY to get the alternate (backup) MDB. */
-       lcv = mdb->fs_start + mdb->fs_ablocks * mdb->alloc_blksz;
-       limit = lcv + mdb->alloc_blksz;
-       for (; lcv < limit; ++lcv) {
-               buf = hfs_buffer_get(sys_mdb, lcv, 1);
-               if (hfs_buffer_ok(buf)) {
-                       struct raw_mdb *tmp =
-                               (struct raw_mdb *)hfs_buffer_data(buf);
-                       
-                       if (hfs_get_ns(tmp->drSigWord) ==
-                           htons(HFS_SUPER_MAGIC)) {
-                               mdb->alt_buf = buf;
-                               break;
-                       }
-               }
-               hfs_buffer_put(buf);
+       sect = part_start + part_size - 2;
+       bh = sb_bread512(sb, sect, mdb2);
+       if (bh) {
+               if (mdb2->drSigWord == cpu_to_be16(HFS_SUPER_MAGIC)) {
+                       HFS_SB(sb)->alt_mdb_bh = bh;
+                       HFS_SB(sb)->alt_mdb = mdb2;
+               } else
+                       brelse(bh);
        }
-       
-       if (mdb->alt_buf == NULL) {
+
+       if (!HFS_SB(sb)->alt_mdb) {
                hfs_warn("hfs_fs: unable to locate alternate MDB\n");
                hfs_warn("hfs_fs: continuing without an alternate MDB\n");
        }
-       
+
+       HFS_SB(sb)->bitmap = (u32 *)__get_free_pages(GFP_KERNEL, PAGE_SIZE < 8192 ? 1 : 0);
+       if (!HFS_SB(sb)->bitmap)
+               goto out;
+
        /* read in the bitmap */
-       block = hfs_get_hs(raw->drVBMSt) + part_start;
-       bmbuf = mdb->bitmap;
-       lcv = (mdb->fs_ablocks + 4095) / 4096;
-       for ( ; lcv; --lcv, ++bmbuf, ++block) {
-               if (!hfs_buffer_ok(*bmbuf =
-                                  hfs_buffer_get(sys_mdb, block, 1))) {
+       block = be16_to_cpu(mdb->drVBMSt) + part_start;
+       off = (loff_t)block << HFS_SECTOR_SIZE_BITS;
+       size = (HFS_SB(sb)->fs_ablocks + 8) / 8;
+       ptr = (u8 *)HFS_SB(sb)->bitmap;
+       while (size) {
+               bh = sb_bread(sb, off >> sb->s_blocksize_bits);
+               if (!bh) {
                        hfs_warn("hfs_fs: unable to read volume bitmap\n");
-                       goto bail1;
+                       goto out;
                }
+               off2 = off & (sb->s_blocksize - 1);
+               len = min((int)sb->s_blocksize - off2, size);
+               memcpy(ptr, bh->b_data + off2, len);
+               brelse(bh);
+               ptr += len;
+               off += len;
+               size -= len;
        }
 
-       if (!(mdb->ext_tree = hfs_btree_init(mdb, htonl(HFS_EXT_CNID),
-                                            raw->drXTExtRec,
-                                            hfs_get_hl(raw->drXTFlSize),
-                                            hfs_get_hl(raw->drXTClpSiz))) ||
-           !(mdb->cat_tree = hfs_btree_init(mdb, htonl(HFS_CAT_CNID),
-                                            raw->drCTExtRec,
-                                            hfs_get_hl(raw->drCTFlSize),
-                                            hfs_get_hl(raw->drCTClpSiz)))) {
-               hfs_warn("hfs_fs: unable to initialize data structures\n");
-               goto bail1;
+       HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp);
+       if (!HFS_SB(sb)->ext_tree) {
+               hfs_warn("hfs_fs: unable to open extent tree\n");
+               goto out;
+       }
+       HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp);
+       if (!HFS_SB(sb)->cat_tree) {
+               hfs_warn("hfs_fs: unable to open catalog tree\n");
+               goto out;
        }
 
-       if (!(mdb->attrib & htons(HFS_SB_ATTRIB_CLEAN))) {
-               hfs_warn("hfs_fs: WARNING: mounting unclean filesystem.\n");
-       } else if (!readonly) {
+       attrib = mdb->drAtrb;
+       if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))
+           || (attrib & cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT))) {
+               hfs_warn("HFS-fs warning: Filesystem was not cleanly unmounted, "
+                        "running fsck.hfs is recommended.  mounting read-only.\n");
+               sb->s_flags |= MS_RDONLY;
+       }
+       if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) {
+               hfs_warn("HFS-fs: Filesystem is marked locked, mounting read-only.\n");
+               sb->s_flags |= MS_RDONLY;
+       }
+       if (!(sb->s_flags & MS_RDONLY)) {
                /* Mark the volume uncleanly unmounted in case we crash */
-               hfs_put_ns(mdb->attrib & htons(~HFS_SB_ATTRIB_CLEAN),
-                          raw->drAtrb);
-               hfs_buffer_dirty(mdb->buf);
-               hfs_buffer_sync(mdb->buf);
+               mdb->drAtrb = attrib & cpu_to_be16(~HFS_SB_ATTRIB_UNMNT);
+               mdb->drAtrb = attrib | cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT);
+               mdb->drWrCnt = cpu_to_be32(be32_to_cpu(mdb->drWrCnt) + 1);
+               mdb->drLsMod = hfs_mtime();
+
+               mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
+               hfs_buffer_sync(HFS_SB(sb)->mdb_bh);
        }
 
-       return mdb;
+       return 0;
 
-bail1:
-       hfs_mdb_put(mdb, readonly);
-bail2:
-       return NULL;
+out_bh:
+       brelse(bh);
+out:
+       hfs_mdb_put(sb);
+       return -EIO;
 }
 
 /*
@@ -236,84 +254,90 @@ bail2:
  *   If 'backup' is non-zero then the alternate MDB is also written
  *   and the function doesn't return until it is actually on disk.
  */
-void hfs_mdb_commit(struct hfs_mdb *mdb, int backup)
+void hfs_mdb_commit(struct super_block *sb)
 {
-       struct raw_mdb *raw = (struct raw_mdb *)hfs_buffer_data(mdb->buf);
-
-       /* Commit catalog entries to buffers */
-       hfs_cat_commit(mdb);
-
-       /* Commit B-tree data to buffers */
-       hfs_btree_commit(mdb->cat_tree, raw->drCTExtRec, raw->drCTFlSize);
-       hfs_btree_commit(mdb->ext_tree, raw->drXTExtRec, raw->drXTFlSize);
-
-       /* Update write_count and modify_date */
-       ++mdb->write_count;
-       mdb->modify_date = hfs_time();
-
-       /* These parameters may have been modified, so write them back */
-       hfs_put_nl(mdb->modify_date,   raw->drLsMod);
-       hfs_put_hs(mdb->free_ablocks,  raw->drFreeBks);
-       hfs_put_hl(mdb->next_id,       raw->drNxtCNID);
-       hfs_put_hl(mdb->write_count,   raw->drWrCnt);
-       hfs_put_hs(mdb->root_files,    raw->drNmFls);
-       hfs_put_hs(mdb->root_dirs,     raw->drNmRtDirs);
-       hfs_put_hl(mdb->file_count,    raw->drFilCnt);
-       hfs_put_hl(mdb->dir_count,     raw->drDirCnt);
-
-       /* write MDB to disk */
-       hfs_buffer_dirty(mdb->buf);
-
-               /* write the backup MDB, not returning until it is written. 
-         * we only do this when either the catalog or extents overflow
-         * files grow. */
-        if (backup && hfs_buffer_ok(mdb->alt_buf)) {
-               struct raw_mdb *tmp = (struct raw_mdb *)
-                       hfs_buffer_data(mdb->alt_buf);
-               
-               if ((hfs_get_hl(tmp->drCTFlSize) < 
-                    hfs_get_hl(raw->drCTFlSize)) ||
-                   (hfs_get_hl(tmp->drXTFlSize) <
-                    hfs_get_hl(raw->drXTFlSize))) {
-                       memcpy(hfs_buffer_data(mdb->alt_buf), 
-                              hfs_buffer_data(mdb->buf), HFS_SECTOR_SIZE); 
-                       hfs_buffer_dirty(mdb->alt_buf);
-                       hfs_buffer_sync(mdb->alt_buf);
+       struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
+
+       if (test_and_clear_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags)) {
+               /* These parameters may have been modified, so write them back */
+               mdb->drLsMod = hfs_mtime();
+               mdb->drFreeBks = cpu_to_be16(HFS_SB(sb)->free_ablocks);
+               mdb->drNxtCNID = cpu_to_be32(HFS_SB(sb)->next_id);
+               mdb->drNmFls = cpu_to_be16(HFS_SB(sb)->root_files);
+               mdb->drNmRtDirs = cpu_to_be16(HFS_SB(sb)->root_dirs);
+               mdb->drFilCnt = cpu_to_be32(HFS_SB(sb)->file_count);
+               mdb->drDirCnt = cpu_to_be32(HFS_SB(sb)->folder_count);
+
+               /* write MDB to disk */
+               mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
+       }
+
+       /* write the backup MDB, not returning until it is written.
+        * we only do this when either the catalog or extents overflow
+        * files grow. */
+       if (test_and_clear_bit(HFS_FLG_ALT_MDB_DIRTY, &HFS_SB(sb)->flags) &&
+           HFS_SB(sb)->alt_mdb) {
+               hfs_inode_write_fork(HFS_SB(sb)->ext_tree->inode, mdb->drXTExtRec,
+                                    &mdb->drXTFlSize, NULL);
+               hfs_inode_write_fork(HFS_SB(sb)->cat_tree->inode, mdb->drCTExtRec,
+                                    &mdb->drCTFlSize, NULL);
+               memcpy(HFS_SB(sb)->alt_mdb, HFS_SB(sb)->mdb, HFS_SECTOR_SIZE);
+               HFS_SB(sb)->alt_mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
+               HFS_SB(sb)->alt_mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
+               mark_buffer_dirty(HFS_SB(sb)->alt_mdb_bh);
+               hfs_buffer_sync(HFS_SB(sb)->alt_mdb_bh);
+       }
+
+       if (test_and_clear_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags)) {
+               struct buffer_head *bh;
+               sector_t block;
+               char *ptr;
+               int off, size, len;
+
+               block = be16_to_cpu(HFS_SB(sb)->mdb->drVBMSt) + HFS_SB(sb)->part_start;
+               off = (block << HFS_SECTOR_SIZE_BITS) & (sb->s_blocksize - 1);
+               block >>= sb->s_blocksize_bits - HFS_SECTOR_SIZE_BITS;
+               size = (HFS_SB(sb)->fs_ablocks + 7) / 8;
+               ptr = (u8 *)HFS_SB(sb)->bitmap;
+               while (size) {
+                       bh = sb_bread(sb, block);
+                       if (!bh) {
+                               hfs_warn("hfs_fs: unable to read volume bitmap\n");
+                               break;
+                       }
+                       len = min((int)sb->s_blocksize - off, size);
+                       memcpy(bh->b_data + off, ptr, len);
+                       mark_buffer_dirty(bh);
+                       brelse(bh);
+                       block++;
+                       off = 0;
+                       ptr += len;
+                       size -= len;
                }
-        }
+       }
+}
+
+void hfs_mdb_close(struct super_block *sb)
+{
+       /* update volume attributes */
+       if (sb->s_flags & MS_RDONLY)
+               return;
+       HFS_SB(sb)->mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
+       HFS_SB(sb)->mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
+       mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
 }
 
 /*
  * hfs_mdb_put()
  *
  * Release the resources associated with the in-core MDB.  */
-void hfs_mdb_put(struct hfs_mdb *mdb, int readonly) {
-       int lcv;
-
-       /* invalidate cached catalog entries */
-       hfs_cat_invalidate(mdb);
-
+void hfs_mdb_put(struct super_block *sb)
+{
        /* free the B-trees */
-       hfs_btree_free(mdb->ext_tree);
-       hfs_btree_free(mdb->cat_tree);
-
-       /* free the volume bitmap */
-       for (lcv = 0; lcv < HFS_BM_MAXBLOCKS; ++lcv) {
-               hfs_buffer_put(mdb->bitmap[lcv]);
-       }
-
-       /* update volume attributes */
-       if (!readonly) {
-               struct raw_mdb *raw = 
-                               (struct raw_mdb *)hfs_buffer_data(mdb->buf);
-               hfs_put_ns(mdb->attrib, raw->drAtrb);
-               hfs_buffer_dirty(mdb->buf);
-       }
+       hfs_btree_close(HFS_SB(sb)->ext_tree);
+       hfs_btree_close(HFS_SB(sb)->cat_tree);
 
        /* free the buffers holding the primary and alternate MDBs */
-       hfs_buffer_put(mdb->buf);
-       hfs_buffer_put(mdb->alt_buf);
-
-       /* free the MDB */
-       HFS_DELETE(mdb);
+       brelse(HFS_SB(sb)->mdb_bh);
+       brelse(HFS_SB(sb)->alt_mdb_bh);
 }
index 2211572262bded02c41301a93dee08f2877e0ecc..19c189dc74bfd97d70b5f64450f5e057ebb7289c 100644 (file)
@@ -1,40 +1,17 @@
 /*
- * linux/fs/hfs/part_tbl.c
+ *  linux/fs/hfs/part_tbl.c
  *
  * Copyright (C) 1996-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * Original code to handle the new style Mac partition table based on
  * a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- *
- * The code in this file initializes some structures which contain
- * pointers by calling memset(&foo, 0, sizeof(foo)).
- * This produces the desired behavior only due to the non-ANSI
- * assumption that the machine representation of NULL is all zeros.
  */
 
-#include "hfs.h"
-
-/*================ File-local data types ================*/
+#include "hfs_fs.h"
 
 /*
- * The Macintosh Driver Descriptor Block
- *
- * On partitioned Macintosh media this is block 0.
- * We really only need the "magic number" to check for partitioned media.
- */
-struct hfs_drvr_desc {
-       hfs_word_t      ddSig;          /* The signature word */
-       /* a bunch more stuff we don't need */
-};
-
-/* 
  * The new style Mac partition map
  *
  * For each partition on the media there is a physical block (512-byte
@@ -42,28 +19,21 @@ struct hfs_drvr_desc {
  * contiguous starting at block 1.
  */
 struct new_pmap {
-       hfs_word_t      pmSig;          /* Signature bytes to verify
-                                          that this is a partition
-                                          map block */
-       hfs_word_t      reSigPad;       /* padding */
-       hfs_lword_t     pmMapBlkCnt;    /* (At least in block 1) this
-                                          is the number of partition
-                                          map blocks */
-       hfs_lword_t     pmPyPartStart;  /* The physical block number
-                                          of the first block in this
-                                          partition */
-       hfs_lword_t     pmPartBlkCnt;   /* The number of physical
-                                          blocks in this partition */
-       hfs_byte_t      pmPartName[32]; /* (null terminated?) string
-                                          giving the name of this
-                                          partition */
-       hfs_byte_t      pmPartType[32]; /* (null terminated?) string
-                                          giving the type of this
-                                          partition */
+       u16     pmSig;          /* signature */
+       u16     reSigPad;       /* padding */
+       u32     pmMapBlkCnt;    /* partition blocks count */
+       u32     pmPyPartStart;  /* physical block start of partition */
+       u32     pmPartBlkCnt;   /* physical block count of partition */
+       u8      pmPartName[32]; /* (null terminated?) string
+                                  giving the name of this
+                                  partition */
+       u8      pmPartType[32]; /* (null terminated?) string
+                                  giving the type of this
+                                  partition */
        /* a bunch more stuff we don't need */
-};
+} __packed;
 
-/* 
+/*
  * The old style Mac partition map
  *
  * The partition map consists for a 2-byte signature followed by an
@@ -71,95 +41,13 @@ struct new_pmap {
  * one of these.
  */
 struct old_pmap {
-       hfs_word_t              pdSig;  /* Signature bytes */
+       u16             pdSig;  /* Signature bytes */
        struct  old_pmap_entry {
-               hfs_lword_t     pdStart;
-               hfs_lword_t     pdSize;
-               hfs_lword_t     pdFSID;
+               u32     pdStart;
+               u32     pdSize;
+               u32     pdFSID;
        }       pdEntry[42];
-} __attribute__((packed));
-
-/*================ File-local functions ================*/
-
-/*
- * parse_new_part_table()
- *
- * Parse a new style partition map looking for the
- * start and length of the 'part'th HFS partition.
- */
-static int parse_new_part_table(hfs_sysmdb sys_mdb, hfs_buffer buf,
-                               int part, hfs_s32 *size, hfs_s32 *start)
-{
-       struct new_pmap *pm = (struct new_pmap *)hfs_buffer_data(buf);
-       hfs_u32 pmap_entries = hfs_get_hl(pm->pmMapBlkCnt);
-       int hfs_part = 0;
-       int entry;
-
-       for (entry = 0; (entry < pmap_entries) && !(*start); ++entry) {
-               if (entry) {
-                       /* read the next partition map entry */
-                       buf = hfs_buffer_get(sys_mdb, HFS_PMAP_BLK + entry, 1);
-                       if (!hfs_buffer_ok(buf)) {
-                               hfs_warn("hfs_fs: unable to "
-                                        "read partition map.\n");
-                               goto bail;
-                       }
-                       pm = (struct new_pmap *)hfs_buffer_data(buf);
-                       if (hfs_get_ns(pm->pmSig) !=
-                                               htons(HFS_NEW_PMAP_MAGIC)) {
-                               hfs_warn("hfs_fs: invalid "
-                                        "entry in partition map\n");
-                               hfs_buffer_put(buf);
-                               goto bail;
-                       }
-               }
-
-               /* look for an HFS partition */
-               if (!memcmp(pm->pmPartType,"Apple_HFS",9) && 
-                   ((hfs_part++) == part)) {
-                       /* Found it! */
-                       *start = hfs_get_hl(pm->pmPyPartStart);
-                       *size = hfs_get_hl(pm->pmPartBlkCnt);
-               }
-
-               hfs_buffer_put(buf);
-       }
-
-       return 0;
-
-bail:
-       return 1;
-}
-
-/*
- * parse_old_part_table()
- *
- * Parse a old style partition map looking for the
- * start and length of the 'part'th HFS partition.
- */
-static int parse_old_part_table(hfs_sysmdb sys_mdb, hfs_buffer buf,
-                               int part, hfs_s32 *size, hfs_s32 *start)
-{
-       struct old_pmap *pm = (struct old_pmap *)hfs_buffer_data(buf);
-       struct old_pmap_entry *p = &pm->pdEntry[0];
-       int hfs_part = 0;
-
-       while ((p->pdStart || p->pdSize || p->pdFSID) && !(*start)) {
-               /* look for an HFS partition */
-               if ((hfs_get_nl(p->pdFSID) == htonl(0x54465331)/*"TFS1"*/) &&
-                   ((hfs_part++) == part)) {
-                       /* Found it! */
-                       *start = hfs_get_hl(p->pdStart);
-                       *size = hfs_get_hl(p->pdSize);
-               }
-               ++p;
-       }
-       hfs_buffer_put(buf);
-
-       return 0;
-}
-
-/*================ Global functions ================*/
+} __packed;
 
 /*
  * hfs_part_find()
@@ -167,78 +55,63 @@ static int parse_old_part_table(hfs_sysmdb sys_mdb, hfs_buffer buf,
  * Parse the partition map looking for the
  * start and length of the 'part'th HFS partition.
  */
-int hfs_part_find(hfs_sysmdb sys_mdb, int part, int silent,
-                 hfs_s32 *size, hfs_s32 *start)
+int hfs_part_find(struct super_block *sb,
+                 sector_t *part_start, sector_t *part_size)
 {
-       hfs_buffer buf;
-       hfs_u16 sig;
-       int dd_found = 0;
-       int retval = 1;
-
-       /* Read block 0 to see if this media is partitioned */
-       buf = hfs_buffer_get(sys_mdb, HFS_DD_BLK, 1);
-       if (!hfs_buffer_ok(buf)) {
-               hfs_warn("hfs_fs: Unable to read block 0.\n");
-               goto done;
-       }
-       sig = hfs_get_ns(((struct hfs_drvr_desc *)hfs_buffer_data(buf))->ddSig);
-       hfs_buffer_put(buf);
-
-        if (sig == htons(HFS_DRVR_DESC_MAGIC)) {
-               /* We are definitely on partitioned media. */
-               dd_found = 1;
-       }
-
-       buf = hfs_buffer_get(sys_mdb, HFS_PMAP_BLK, 1);
-       if (!hfs_buffer_ok(buf)) {
-               hfs_warn("hfs_fs: Unable to read block 1.\n");
-               goto done;
-       }
-
-       *size = *start = 0;
-
-       switch (hfs_get_ns(hfs_buffer_data(buf))) {
-       case __constant_htons(HFS_OLD_PMAP_MAGIC):
-               retval = parse_old_part_table(sys_mdb, buf, part, size, start);
-               break;
-
-       case __constant_htons(HFS_NEW_PMAP_MAGIC):
-               retval = parse_new_part_table(sys_mdb, buf, part, size, start);
-               break;
-
-       default:
-               if (dd_found) {
-                       /* The media claimed to have a partition map */
-                       if (!silent) {
-                               hfs_warn("hfs_fs: This disk has an "
-                                        "unrecognized partition map type.\n");
+       struct buffer_head *bh;
+       u16 *data;
+       int i, size, res;
+
+       res = -ENOENT;
+       bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK, data);
+       if (!bh)
+               return -EIO;
+
+       switch (be16_to_cpu(*data)) {
+       case HFS_OLD_PMAP_MAGIC:
+         {
+               struct old_pmap *pm;
+               struct old_pmap_entry *p;
+
+               pm = (struct old_pmap *)bh->b_data;
+               p = pm->pdEntry;
+               size = 42;
+               for (i = 0; i < size; p++, i++) {
+                       if (p->pdStart && p->pdSize &&
+                           p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
+                           (HFS_SB(sb)->part < 0 || HFS_SB(sb)->part == i)) {
+                               *part_start += be32_to_cpu(p->pdStart);
+                               *part_size = be32_to_cpu(p->pdSize);
+                               res = 0;
                        }
-               } else {
-                       /* Conclude that the media is not partitioned */
-                       retval = 0;
                }
-               goto done;
-       }
-
-       if (!retval) {
-               if (*start == 0) {
-                       if (part) {
-                               hfs_warn("hfs_fs: unable to locate "
-                                        "HFS partition number %d.\n", part);
-                       } else {
-                               hfs_warn("hfs_fs: unable to locate any "
-                                        "HFS partitions.\n");
+               break;
+         }
+       case HFS_NEW_PMAP_MAGIC:
+         {
+               struct new_pmap *pm;
+
+               pm = (struct new_pmap *)bh->b_data;
+               size = be32_to_cpu(pm->pmMapBlkCnt);
+               for (i = 0; i < size;) {
+                       if (!memcmp(pm->pmPartType,"Apple_HFS", 9) &&
+                           (HFS_SB(sb)->part < 0 || HFS_SB(sb)->part == i)) {
+                               *part_start += be32_to_cpu(pm->pmPyPartStart);
+                               *part_size = be32_to_cpu(pm->pmPartBlkCnt);
+                               res = 0;
+                               break;
                        }
-                       retval = 1;
-               } else if (*size < 0) {
-                       hfs_warn("hfs_fs: Partition size > 1 Terabyte.\n");
-                       retval = 1;
-               } else if (*start < 0) {
-                       hfs_warn("hfs_fs: Partition begins beyond 1 "
-                                "Terabyte.\n");
-                       retval = 1;
+                       brelse(bh);
+                       bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK + ++i, pm);
+                       if (!bh)
+                               return -EIO;
+                       if (pm->pmSig != cpu_to_be16(HFS_NEW_PMAP_MAGIC))
+                               break;
                }
+               break;
+         }
        }
-done:
-       return retval;
+       brelse(bh);
+
+       return res;
 }
index f499b9a805bbdeefb911c7b255af3d541c35d3ba..927a5af794284b4023b60dc3b27f9216157184b6 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * linux/fs/hfs/string.c
+ *  linux/fs/hfs/string.c
  *
  * Copyright (C) 1995-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * This file contains the string comparison function for the
  * The code in this file is derived from code which is copyright
  * 1986, 1989, 1990 by Abacus Research and Development, Inc. (ARDI)
  * It is used here by the permission of ARDI's president Cliff Matthews.
- *
- * If you discover bugs in this code please notify both the author of the
- * Linux HFS file system: hargrove@sccm.stanford.edu (Paul H. Hargrove)
- * and the author of ARDI's HFS code: ctm@ardi.com (Clifford T. Matthews)
- *
- * "XXX" in a comment is a note to myself to consider changing something.
  */
 
-#include "hfs.h"
+#include "hfs_fs.h"
+#include <linux/dcache.h>
 
 /*================ File-local variables ================*/
 
  * special case for those two characters.
  */
 static unsigned char caseorder[256] = {
-0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
-0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
-0x20,0x22,0x23,0x28,0x29,0x2A,0x2B,0x2C,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,
-0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
-0x47,0x48,0x57,0x59,0x5D,0x5F,0x66,0x68,0x6A,0x6C,0x72,0x74,0x76,0x78,0x7A,0x7E,
-0x8C,0x8E,0x90,0x92,0x95,0x97,0x9E,0xA0,0xA2,0xA4,0xA7,0xA9,0xAA,0xAB,0xAC,0xAD,
-0x4E,0x48,0x57,0x59,0x5D,0x5F,0x66,0x68,0x6A,0x6C,0x72,0x74,0x76,0x78,0x7A,0x7E,
-0x8C,0x8E,0x90,0x92,0x95,0x97,0x9E,0xA0,0xA2,0xA4,0xA7,0xAF,0xB0,0xB1,0xB2,0xB3,
-0x4A,0x4C,0x5A,0x60,0x7B,0x7F,0x98,0x4F,0x49,0x51,0x4A,0x4B,0x4C,0x5A,0x60,0x63,
-0x64,0x65,0x6E,0x6F,0x70,0x71,0x7B,0x84,0x85,0x86,0x7F,0x80,0x9A,0x9B,0x9C,0x98,
-0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0x94,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0x4D,0x81,
-0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0x55,0x8A,0xCC,0x4D,0x81,
-0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0x26,0x27,0xD4,0x20,0x49,0x4B,0x80,0x82,0x82,
-0xD5,0xD6,0x24,0x25,0x2D,0x2E,0xD7,0xD8,0xA6,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
-0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
-0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
-};
-
-/*
- * unsigned char casefold[]
- *
- * Defines the mapping to lowercase characters on the Macintosh
- *
- * "Inverse" of the 'casefold' from ARDI's code.
- */
-static unsigned char casefold[256] = {
-0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
-0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
-0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
-0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
-0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
-0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x5B,0x5C,0x5D,0x5E,0x5F,
-0x41,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
-0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
-0x8A,0x8C,0x8D,0x8E,0x96,0x9A,0x9F,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
-0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
-0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xBE,0xBF,
-0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
-0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0x88,0x8B,0x9B,0xCF,0xCF,
-0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
-0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
-0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+       0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
+       0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+       0x20,0x22,0x23,0x28,0x29,0x2A,0x2B,0x2C,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,
+       0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
+       0x47,0x48,0x57,0x59,0x5D,0x5F,0x66,0x68,0x6A,0x6C,0x72,0x74,0x76,0x78,0x7A,0x7E,
+       0x8C,0x8E,0x90,0x92,0x95,0x97,0x9E,0xA0,0xA2,0xA4,0xA7,0xA9,0xAA,0xAB,0xAC,0xAD,
+       0x4E,0x48,0x57,0x59,0x5D,0x5F,0x66,0x68,0x6A,0x6C,0x72,0x74,0x76,0x78,0x7A,0x7E,
+       0x8C,0x8E,0x90,0x92,0x95,0x97,0x9E,0xA0,0xA2,0xA4,0xA7,0xAF,0xB0,0xB1,0xB2,0xB3,
+       0x4A,0x4C,0x5A,0x60,0x7B,0x7F,0x98,0x4F,0x49,0x51,0x4A,0x4B,0x4C,0x5A,0x60,0x63,
+       0x64,0x65,0x6E,0x6F,0x70,0x71,0x7B,0x84,0x85,0x86,0x7F,0x80,0x9A,0x9B,0x9C,0x98,
+       0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0x94,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0x4D,0x81,
+       0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0x55,0x8A,0xCC,0x4D,0x81,
+       0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0x26,0x27,0xD4,0x20,0x49,0x4B,0x80,0x82,0x82,
+       0xD5,0xD6,0x24,0x25,0x2D,0x2E,0xD7,0xD8,0xA6,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+       0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+       0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
 };
 
 /*================ Global functions ================*/
@@ -81,14 +51,19 @@ static unsigned char casefold[256] = {
 /*
  * Hash a string to an integer in a case-independent way
  */
-unsigned int hfs_strhash(const unsigned char *name, unsigned int len)
+int hfs_hash_dentry(struct dentry *dentry, struct qstr *this)
 {
-       unsigned long hash = init_name_hash();
+       const unsigned char *name = this->name;
+       unsigned int hash, len = this->len;
 
-       while (len--)
-               hash = partial_name_hash(caseorder[*name++],
-                                        hash);
-       return end_name_hash(hash);
+       if (len > HFS_NAMELEN)
+               len = HFS_NAMELEN;
+
+       hash = init_name_hash();
+       for (; len; len--)
+               hash = partial_name_hash(caseorder[*name++], hash);
+       this->hash = end_name_hash(hash);
+       return 0;
 }
 
 /*
@@ -106,39 +81,35 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1,
        len = (len1 > len2) ? len2 : len1;
 
        while (len--) {
-               if ((tmp = (int)caseorder[*(s1++)] -
-                    (int)caseorder[*(s2++)])) {
+               tmp = (int)caseorder[*(s1++)] - (int)caseorder[*(s2++)];
+               if (tmp)
                        return tmp;
-               }
        }
        return len1 - len2;
 }
 
 /*
  * Test for equality of two strings in the HFS filename character ordering.
+ * return 1 on failure and 0 on success
  */
-int hfs_streq(const unsigned char *s1, unsigned int len1,
-             const unsigned char *s2, unsigned int len2)
+int hfs_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2)
 {
-       if (len1 != len2) {
-               return 0;
-       }
+       const unsigned char *n1, *n2;
+       int len;
 
-       while (len1--) {
-               if (caseorder[*(s1++)] != caseorder[*(s2++)]) {
-                       return 0;
-               }
-       }
-       return 1;
-}
+       len = s1->len;
+       if (len >= HFS_NAMELEN) {
+               if (s2->len < HFS_NAMELEN)
+                       return 1;
+               len = HFS_NAMELEN;
+       } else if (len != s2->len)
+               return 1;
 
-/*
- * Convert a string to the Macintosh version of lower case.
- */
-void hfs_tolower(unsigned char *p, int len)
-{
+       n1 = s1->name;
+       n2 = s2->name;
        while (len--) {
-               *p = casefold[*p];
-               ++p;
+               if (caseorder[*n1++] != caseorder[*n2++])
+                       return 1;
        }
+       return 0;
 }
index e66e4ac9c1e23d5d5e8d95f5222cb1a59a2229d9..86e02098ac4f9e22fabee4d500b895155ea4835b 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * linux/fs/hfs/super.c
+ *  linux/fs/hfs/super.c
  *
  * Copyright (C) 1995-1997  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * This file contains hfs_read_super(), some of the super_ops and
  * inode.c since they deal with inodes.
  *
  * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- *
- * The code in this file initializes some structures which contain
- * pointers by calling memset(&foo, 0, sizeof(foo)).
- * This produces the desired behavior only due to the non-ANSI
- * assumption that the machine representation of NULL is all zeros.
  */
 
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
-
-#include <linux/config.h> /* for CONFIG_MAC_PARTITION */
-#include <linux/blkdev.h>
+#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/blkdev.h>
 #include <linux/init.h>
-#include <linux/parser.h>
-#include <linux/smp_lock.h>
 #include <linux/vfs.h>
 
-MODULE_LICENSE("GPL");
-
-/*================ Forward declarations ================*/
-
-static void hfs_read_inode(struct inode *);
-static void hfs_put_super(struct super_block *);
-static int hfs_statfs(struct super_block *, struct kstatfs *);
-static void hfs_write_super(struct super_block *);
-
-static kmem_cache_t * hfs_inode_cachep;
-
-static struct inode *hfs_alloc_inode(struct super_block *sb)
-{
-       struct hfs_inode_info *ei;
-       ei = (struct hfs_inode_info *)kmem_cache_alloc(hfs_inode_cachep, SLAB_KERNEL);
-       if (!ei)
-               return NULL;
-       return &ei->vfs_inode;
-}
-
-static void hfs_destroy_inode(struct inode *inode)
-{
-       kmem_cache_free(hfs_inode_cachep, HFS_I(inode));
-}
-
-static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
-{
-       struct hfs_inode_info *ei = (struct hfs_inode_info *) foo;
-
-       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-           SLAB_CTOR_CONSTRUCTOR)
-               inode_init_once(&ei->vfs_inode);
-}
-static int init_inodecache(void)
-{
-       hfs_inode_cachep = kmem_cache_create("hfs_inode_cache",
-                                            sizeof(struct hfs_inode_info),
-                                            0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
-                                            init_once, NULL);
-       if (hfs_inode_cachep == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-static void destroy_inodecache(void)
-{
-       if (kmem_cache_destroy(hfs_inode_cachep))
-               printk(KERN_INFO "hfs_inode_cache: not all structures were freed\n");
-}
-
-/*================ Global variables ================*/
-
-static struct super_operations hfs_super_operations = { 
-       .alloc_inode    = hfs_alloc_inode,
-       .destroy_inode  = hfs_destroy_inode,
-       .read_inode     = hfs_read_inode,
-       .put_inode      = hfs_put_inode,
-       .put_super      = hfs_put_super,
-       .write_super    = hfs_write_super,
-       .statfs         = hfs_statfs,
-};
-
-/*================ File-local variables ================*/
+#include "hfs_fs.h"
+#include "btree.h"
 
-static struct super_block *hfs_get_sb(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
-{
-       return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super);
-}
+const char hfs_version[]="0.96";
 
-static struct file_system_type hfs_fs = {
-       .owner          = THIS_MODULE,
-       .name           = "hfs",
-       .get_sb         = hfs_get_sb,
-       .kill_sb        = kill_block_super,
-       .fs_flags       = FS_REQUIRES_DEV,
-};
-
-/*================ File-local functions ================*/
+static kmem_cache_t *hfs_inode_cachep;
 
-/* 
- * hfs_read_inode()
- *
- * this doesn't actually do much. hfs_iget actually fills in the 
- * necessary inode information.
- */
-static void hfs_read_inode(struct inode *inode)
-{
-  inode->i_mode = 0;
-}
+MODULE_LICENSE("GPL");
 
 /*
  * hfs_write_super()
@@ -148,20 +48,11 @@ static void hfs_read_inode(struct inode *inode)
  */
 static void hfs_write_super(struct super_block *sb)
 {
-       struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb;
-       lock_kernel();
-       /* is this a valid hfs superblock? */
-       if (!sb || sb->s_magic != HFS_SUPER_MAGIC) {
-               unlock_kernel();
-               return;
-       }
-
-       if (!(sb->s_flags & MS_RDONLY)) {
-               /* sync everything to the buffers */
-               hfs_mdb_commit(mdb, 0);
-       }
        sb->s_dirt = 0;
-       unlock_kernel();
+       if (sb->s_flags & MS_RDONLY)
+               return;
+       /* sync everything to the buffers */
+       hfs_mdb_commit(sb);
 }
 
 /*
@@ -173,18 +64,9 @@ static void hfs_write_super(struct super_block *sb)
  */
 static void hfs_put_super(struct super_block *sb)
 {
-       struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb;
-       if (!(sb->s_flags & MS_RDONLY)) {
-               hfs_mdb_commit(mdb, 0);
-               sb->s_dirt = 0;
-       }
-
+       hfs_mdb_close(sb);
        /* release the MDB's resources */
-       hfs_mdb_put(mdb, sb->s_flags & MS_RDONLY);
-
-       kfree(sb->s_fs_info);
-       sb->s_fs_info = NULL;
+       hfs_mdb_put(sb);
 }
 
 /*
@@ -198,294 +80,161 @@ static void hfs_put_super(struct super_block *sb)
  */
 static int hfs_statfs(struct super_block *sb, struct kstatfs *buf)
 {
-       struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb;
-
        buf->f_type = HFS_SUPER_MAGIC;
-       buf->f_bsize = HFS_SECTOR_SIZE;
-       buf->f_blocks = mdb->alloc_blksz * mdb->fs_ablocks;
-       buf->f_bfree = mdb->alloc_blksz * mdb->free_ablocks;
+       buf->f_bsize = sb->s_blocksize;
+       buf->f_blocks = (u32)HFS_SB(sb)->fs_ablocks * HFS_SB(sb)->fs_div;
+       buf->f_bfree = (u32)HFS_SB(sb)->free_ablocks * HFS_SB(sb)->fs_div;
        buf->f_bavail = buf->f_bfree;
-       buf->f_files = mdb->fs_ablocks;  
-       buf->f_ffree = mdb->free_ablocks;
+       buf->f_files = HFS_SB(sb)->fs_ablocks;
+       buf->f_ffree = HFS_SB(sb)->free_ablocks;
        buf->f_namelen = HFS_NAMELEN;
 
        return 0;
 }
 
-enum {
-       Opt_version, Opt_uid, Opt_gid, Opt_umask, Opt_part,
-       Opt_type, Opt_creator, Opt_quiet, Opt_afpd,
-       Opt_names_netatalk, Opt_names_trivial, Opt_names_alpha, Opt_names_latin,
-       Opt_names_7bit, Opt_names_8bit, Opt_names_cap,
-       Opt_fork_netatalk, Opt_fork_single, Opt_fork_double, Opt_fork_cap,
-       Opt_case_lower, Opt_case_asis,
-       Opt_conv_binary, Opt_conv_text, Opt_conv_auto,
-};
+int hfs_remount(struct super_block *sb, int *flags, char *data)
+{
+       if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+               return 0;
+       if (!(*flags & MS_RDONLY)) {
+               if (!(HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))
+                   || (HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT))) {
+                       printk("HFS-fs warning: Filesystem was not cleanly unmounted, "
+                              "running fsck.hfs is recommended.  leaving read-only.\n");
+                       sb->s_flags |= MS_RDONLY;
+                       *flags |= MS_RDONLY;
+               } else if (HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_SLOCK)) {
+                       printk("HFS-fs: Filesystem is marked locked, leaving read-only.\n");
+                       sb->s_flags |= MS_RDONLY;
+                       *flags |= MS_RDONLY;
+               }
+       }
+       return 0;
+}
 
-static match_table_t tokens = {
-       {Opt_version, "version=%u"},
-       {Opt_uid, "uid=%u"},
-       {Opt_gid, "gid=%u"},
-       {Opt_umask, "umask=%o"},
-       {Opt_part, "part=%u"},
-       {Opt_type, "type=%s"},
-       {Opt_creator, "creator=%s"},
-       {Opt_quiet, "quiet"},
-       {Opt_afpd, "afpd"},
-       {Opt_names_netatalk, "names=netatalk"},
-       {Opt_names_trivial, "names=trivial"},
-       {Opt_names_alpha, "names=alpha"},
-       {Opt_names_latin, "names=latin"},
-       {Opt_names_7bit, "names=7bit"},
-       {Opt_names_8bit, "names=8bit"},
-       {Opt_names_cap, "names=cap"},
-       {Opt_names_netatalk, "names=n"},
-       {Opt_names_trivial, "names=t"},
-       {Opt_names_alpha, "names=a"},
-       {Opt_names_latin, "names=l"},
-       {Opt_names_7bit, "names=7"},
-       {Opt_names_8bit, "names=8"},
-       {Opt_names_cap, "names=c"},
-       {Opt_fork_netatalk, "fork=netatalk"},
-       {Opt_fork_single, "fork=single"},
-       {Opt_fork_double, "fork=double"},
-       {Opt_fork_cap, "fork=cap"},
-       {Opt_fork_netatalk, "fork=n"},
-       {Opt_fork_single, "fork=s"},
-       {Opt_fork_double, "fork=d"},
-       {Opt_fork_cap, "fork=c"},
-       {Opt_case_lower, "case=lower"},
-       {Opt_case_asis, "case=asis"},
-       {Opt_case_lower, "case=l"},
-       {Opt_case_asis, "case=a"},
-       {Opt_conv_binary, "conv=binary"},
-       {Opt_conv_text, "conv=text"},
-       {Opt_conv_auto, "conv=auto"},
-       {Opt_conv_binary, "conv=b"},
-       {Opt_conv_text, "conv=t"},
-       {Opt_conv_auto, "conv=a"},
+static struct inode *hfs_alloc_inode(struct super_block *sb)
+{
+       struct hfs_inode_info *i;
+
+       i = kmem_cache_alloc(hfs_inode_cachep, SLAB_KERNEL);
+       return i ? &i->vfs_inode : NULL;
+}
+
+static void hfs_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(hfs_inode_cachep, HFS_I(inode));
+}
+
+static struct super_operations hfs_super_operations = {
+       .alloc_inode    = hfs_alloc_inode,
+       .destroy_inode  = hfs_destroy_inode,
+       .write_inode    = hfs_write_inode,
+       .clear_inode    = hfs_clear_inode,
+       .put_super      = hfs_put_super,
+       .write_super    = hfs_write_super,
+       .statfs         = hfs_statfs,
+       .remount_fs     = hfs_remount,
 };
 
 /*
  * parse_options()
- * 
+ *
  * adapted from linux/fs/msdos/inode.c written 1992,93 by Werner Almesberger
  * This function is called by hfs_read_super() to parse the mount options.
  */
-static int parse_options(char *options, struct hfs_sb_info *hsb, int *part)
+static int parse_options(char *options, struct hfs_sb_info *hsb)
 {
-       char *p;
-       char names, fork;
-       substring_t args[MAX_OPT_ARGS];
-       int option;
+       char *this_char, *value;
 
        /* initialize the sb with defaults */
-       memset(hsb, 0, sizeof(*hsb));
-       hsb->magic = HFS_SB_MAGIC;
-       hsb->s_uid   = current->uid;
-       hsb->s_gid   = current->gid;
-       hsb->s_umask = current->fs->umask;
-       hsb->s_type    = 0x3f3f3f3f;    /* == '????' */
+       hsb->s_uid = current->uid;
+       hsb->s_gid = current->gid;
+       hsb->s_file_umask = 0644;
+       hsb->s_dir_umask = 0755;
+       hsb->s_type = 0x3f3f3f3f;       /* == '????' */
        hsb->s_creator = 0x3f3f3f3f;    /* == '????' */
-       hsb->s_lowercase = 0;
-       hsb->s_quiet     = 0;
-       hsb->s_afpd      = 0;
-        /* default version. 0 just selects the defaults */
-       hsb->s_version   = 0; 
-       hsb->s_conv = 'b';
-       names = '?';
-       fork = '?';
-       *part = 0;
-
-       if (!options) {
-               goto done;
-       }
-       while ((p = strsep(&options,",")) != NULL) {
-               int token;
-               if (!*p)
+       hsb->s_quiet = 0;
+       hsb->part = -1;
+       hsb->session = -1;
+
+       if (!options)
+               return 1;
+
+       while ((this_char = strsep(&options, ","))) {
+               if (!*this_char)
                        continue;
+               value = strchr(this_char, '=');
+               if (value)
+                       *value++ = 0;
 
-               token = match_token(p, tokens, args);
-               switch (token) {
-               /* Numeric-valued options */
-               case Opt_version:
-                       if (match_int(&args[0], &option))
+       /* Numeric-valued options */
+               if (!strcmp(this_char, "uid")) {
+                       if (!value || !*value)
+                               return 0;
+                       hsb->s_uid = simple_strtoul(value, &value, 0);
+                       if (*value)
+                               return 0;
+               } else if (!strcmp(this_char, "gid")) {
+                       if (!value || !*value)
                                return 0;
-                       hsb->s_version = option;
-                       break;
-               case Opt_uid:
-                       if (match_int(&args[0], &option))
+                       hsb->s_gid = simple_strtoul(value, &value, 0);
+                       if (*value)
                                return 0;
-                       hsb->s_uid = option;
-                       break;
-               case Opt_gid:
-                       if (match_int(&args[0], &option))
+               } else if (!strcmp(this_char, "umask")) {
+                       if (!value || !*value)
                                return 0;
-                       hsb->s_gid = option;
-                       break;
-               case Opt_umask:
-                       if (match_octal(&args[0], &option))
+                       hsb->s_file_umask = simple_strtoul(value, &value, 8);
+                       hsb->s_dir_umask = hsb->s_file_umask;
+                       if (*value)
                                return 0;
-                       hsb->s_umask = option;
-                       break;
-               case Opt_part:
-                       if (match_int(&args[0], &option))
+               } else if (!strcmp(this_char, "file_umask")) {
+                       if (!value || !*value)
                                return 0;
-                       *part = option;
-                       break;
-               /* String-valued options */
-               case Opt_type:
-                       if (strlen(args[0].from) != 4) {
+                       hsb->s_file_umask = simple_strtoul(value, &value, 8);
+                       if (*value)
                                return 0;
-                       }
-                       hsb->s_type = hfs_get_nl(args[0].from);
-                       break;
-               case Opt_creator:
-                       if (strlen(args[0].from) != 4) {
+               } else if (!strcmp(this_char, "dir_umask")) {
+                       if (!value || !*value)
+                               return 0;
+                       hsb->s_dir_umask = simple_strtoul(value, &value, 8);
+                       if (*value)
+                               return 0;
+               } else if (!strcmp(this_char, "part")) {
+                       if (!value || !*value)
+                               return 0;
+                       hsb->part = simple_strtoul(value, &value, 0);
+                       if (*value)
+                               return 0;
+               } else if (!strcmp(this_char, "session")) {
+                       if (!value || !*value)
+                               return 0;
+                       hsb->session = simple_strtoul(value, &value, 0);
+                       if (*value)
+                               return 0;
+       /* String-valued options */
+               } else if (!strcmp(this_char, "type") && value) {
+                       if (strlen(value) != 4)
+                               return 0;
+                       hsb->s_type = *(u32 *)value;
+               } else if (!strcmp(this_char, "creator") && value) {
+                       if (strlen(value) != 4)
+                               return 0;
+                       hsb->s_creator = *(u32 *)value;
+       /* Boolean-valued options */
+               } else if (!strcmp(this_char, "quiet")) {
+                       if (value)
                                return 0;
-                       }
-                       hsb->s_creator = hfs_get_nl(args[0].from);
-                       break;
-               /* Boolean-valued options */
-               case Opt_quiet:
                        hsb->s_quiet = 1;
-                       break;
-               case Opt_afpd:
-                       hsb->s_afpd = 1;
-                       break;
-               /* Multiple choice options */
-               case Opt_names_netatalk:
-                       names = 'n';
-                       break;
-               case Opt_names_trivial:
-                       names = 't';
-                       break;
-               case Opt_names_alpha:
-                       names = 'a';
-                       break;
-               case Opt_names_latin:
-                       names = 'l';
-                       break;
-               case Opt_names_7bit:
-                       names = '7';
-                       break;
-               case Opt_names_8bit:
-                       names = '8';
-                       break;
-               case Opt_names_cap:
-                       names = 'c';
-                       break;
-               case Opt_fork_netatalk:
-                       fork = 'n';
-                       break;
-               case Opt_fork_single:
-                       fork = 's';
-                       break;
-               case Opt_fork_double:
-                       fork = 'd';
-                       break;
-               case Opt_fork_cap:
-                       fork = 'c';
-                       break;
-               case Opt_case_lower:
-                       hsb->s_lowercase = 1;
-                       break;
-               case Opt_case_asis:
-                       hsb->s_lowercase = 0;
-                       break;
-               case Opt_conv_binary:
-                       hsb->s_conv = 'b';
-                       break;
-               case Opt_conv_text:
-                       hsb->s_conv = 't';
-                       break;
-               case Opt_conv_auto:
-                       hsb->s_conv = 'a';
-                       break;
-               default:
+               } else
                        return 0;
-               }
        }
 
-done:
-       /* Parse the "fork" and "names" options */
-       if (fork == '?') {
-               fork = hsb->s_afpd ? 'n' : 'c';
-       }
-       switch (fork) {
-       default:
-       case 'c':
-               hsb->s_ifill = hfs_cap_ifill;
-               hsb->s_reserved1 = hfs_cap_reserved1;
-               hsb->s_reserved2 = hfs_cap_reserved2;
-               break;
-
-       case 's':
-               hfs_warn("hfs_fs: AppleSingle not yet implemented.\n");
-               return 0;
-               /* break; */
-       
-       case 'd':
-               hsb->s_ifill = hfs_dbl_ifill;
-               hsb->s_reserved1 = hfs_dbl_reserved1;
-               hsb->s_reserved2 = hfs_dbl_reserved2;
-               break;
-
-       case 'n':
-               hsb->s_ifill = hfs_nat_ifill;
-               hsb->s_reserved1 = hfs_nat_reserved1;
-               hsb->s_reserved2 = hfs_nat_reserved2;
-               break;
-       }
-
-       if (names == '?') {
-               names = fork;
-       }
-       switch (names) {
-       default:
-       case 'n':
-               hsb->s_nameout = hfs_colon2mac;
-               hsb->s_namein = hfs_mac2nat;
-               break;
-
-       case 'c':
-               hsb->s_nameout = hfs_colon2mac;
-               hsb->s_namein = hfs_mac2cap;
-               break;
-
-       case 't':
-               hsb->s_nameout = hfs_triv2mac;
-               hsb->s_namein = hfs_mac2triv;
-               break;
-
-       case '7':
-               hsb->s_nameout = hfs_prcnt2mac;
-               hsb->s_namein = hfs_mac2seven;
-               break;
-
-       case '8':
-               hsb->s_nameout = hfs_prcnt2mac;
-               hsb->s_namein = hfs_mac2eight;
-               break;
-
-       case 'l':
-               hsb->s_nameout = hfs_latin2mac;
-               hsb->s_namein = hfs_mac2latin;
-               break;
-
-       case 'a':       /* 's' and 'd' are unadvertised aliases for 'alpha', */
-       case 's':       /* since 'alpha' is the default if fork=s or fork=d. */
-       case 'd':       /* (It is also helpful for poor typists!)           */
-               hsb->s_nameout = hfs_prcnt2mac;
-               hsb->s_namein = hfs_mac2alpha;
-               break;
-       }
+       hsb->s_dir_umask &= 0777;
+       hsb->s_file_umask &= 0777;
 
        return 1;
 }
 
-/*================ Global functions ================*/
-
 /*
  * hfs_read_super()
  *
@@ -497,122 +246,113 @@ done:
  * hfs_btree_init() to get the necessary data about the extents and
  * catalog B-trees and, finally, reading the root inode into memory.
  */
-int hfs_fill_super(struct super_block *s, void *data, int silent)
+static int hfs_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct hfs_sb_info *sbi;
-       struct hfs_mdb *mdb;
-       struct hfs_cat_key key;
-       hfs_s32 part_size, part_start;
+       struct hfs_find_data fd;
+       hfs_cat_rec rec;
        struct inode *root_inode;
-       int part;
+       int res;
 
        sbi = kmalloc(sizeof(struct hfs_sb_info), GFP_KERNEL);
        if (!sbi)
                return -ENOMEM;
-       s->s_fs_info = sbi;
+       sb->s_fs_info = sbi;
        memset(sbi, 0, sizeof(struct hfs_sb_info));
+       INIT_HLIST_HEAD(&sbi->rsrc_inodes);
 
-       if (!parse_options((char *)data, sbi, &part)) {
+       res = -EINVAL;
+       if (!parse_options((char *)data, sbi)) {
                hfs_warn("hfs_fs: unable to parse mount options.\n");
-               goto bail2;
+               goto bail3;
        }
 
-       /* set the device driver to 512-byte blocks */
-       sb_set_blocksize(s, HFS_SECTOR_SIZE);
+       sb->s_op = &hfs_super_operations;
+       init_MUTEX(&sbi->bitmap_lock);
 
-#ifdef CONFIG_MAC_PARTITION
-       /* check to see if we're in a partition */
-       mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, 0);
-
-       /* erk. try parsing the partition table ourselves */
-       if (!mdb) {
-               if (hfs_part_find(s, part, silent, &part_size, &part_start)) {
-                       goto bail2;
-               }
-               mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, part_start);
-       }
-#else
-       if (hfs_part_find(s, part, silent, &part_size, &part_start)) {
-               goto bail2;
-       }
-
-       mdb = hfs_mdb_get(s, s->s_flags & MS_RDONLY, part_start);
-#endif
-
-       if (!mdb) {
-               if (!silent) {
+       res = hfs_mdb_get(sb);
+       if (res) {
+               if (!silent)
                        hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n",
-                              s->s_id);
-               }
+                               hfs_mdb_name(sb));
                goto bail2;
        }
 
-       sbi->s_mdb = mdb;
-       if (HFS_ITYPE(mdb->next_id) != 0) {
-               hfs_warn("hfs_fs: too many files.\n");
-               goto bail1;
-       }
-
-       s->s_magic = HFS_SUPER_MAGIC;
-       s->s_op = &hfs_super_operations;
-
        /* try to get the root inode */
-       hfs_cat_build_key(htonl(HFS_POR_CNID),
-                         (struct hfs_name *)(mdb->vname), &key);
-
-       root_inode = hfs_iget(hfs_cat_get(mdb, &key), HFS_ITYPE_NORM, NULL);
-       if (!root_inode) 
+       hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+       res = hfs_cat_find_brec(sb, HFS_ROOT_CNID, &fd);
+       if (!res)
+               hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, fd.entrylength);
+       if (res) {
+               hfs_find_exit(&fd);
                goto bail_no_root;
-         
-       s->s_root = d_alloc_root(root_inode);
-       if (!s->s_root) 
+       }
+       root_inode = hfs_iget(sb, &fd.search_key->cat, &rec);
+       hfs_find_exit(&fd);
+       if (!root_inode)
                goto bail_no_root;
 
-       /* fix up pointers. */
-       HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] =
-         s->s_root;
-       s->s_root->d_op = &hfs_dentry_operations;
+       sb->s_root = d_alloc_root(root_inode);
+       if (!sb->s_root)
+               goto bail_no_root;
+
+       sb->s_root->d_op = &hfs_dentry_operations;
 
        /* everything's okay */
        return 0;
 
-bail_no_root: 
+bail_no_root:
        hfs_warn("hfs_fs: get root inode failed.\n");
-       iput(root_inode);
-bail1:
-       hfs_mdb_put(mdb, s->s_flags & MS_RDONLY);
+       hfs_mdb_put(sb);
 bail2:
+bail3:
        kfree(sbi);
-       s->s_fs_info = NULL;
-       return -EINVAL; 
+       return res;
+}
+
+static struct super_block *hfs_get_sb(struct file_system_type *fs_type,
+                                     int flags, const char *dev_name, void *data)
+{
+       return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super);
+}
+
+static struct file_system_type hfs_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "hfs",
+       .get_sb         = hfs_get_sb,
+       .kill_sb        = kill_block_super,
+       .fs_flags       = FS_REQUIRES_DEV,
+};
+
+static void hfs_init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
+{
+       struct hfs_inode_info *i = p;
+
+       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR)
+               inode_init_once(&i->vfs_inode);
 }
 
 static int __init init_hfs_fs(void)
 {
-       int err = init_inodecache();
-       if (err)
-               goto out1;
-        hfs_cat_init();
-       err = register_filesystem(&hfs_fs);
+       int err;
+
+       hfs_inode_cachep = kmem_cache_create("hfs_inode_cache",
+               sizeof(struct hfs_inode_info), 0, SLAB_HWCACHE_ALIGN,
+               hfs_init_once, NULL);
+       if (!hfs_inode_cachep)
+               return -ENOMEM;
+       err = register_filesystem(&hfs_fs_type);
        if (err)
-               goto out;
-       return 0;
-out:
-       hfs_cat_free();
-       destroy_inodecache();
-out1:
+               kmem_cache_destroy(hfs_inode_cachep);
        return err;
 }
 
-static void __exit exit_hfs_fs(void) {
-       hfs_cat_free();
-       unregister_filesystem(&hfs_fs);
-       destroy_inodecache();
+static void __exit exit_hfs_fs(void)
+{
+       unregister_filesystem(&hfs_fs_type);
+       if (kmem_cache_destroy(hfs_inode_cachep))
+               printk(KERN_INFO "hfs_inode_cache: not all structures were freed\n");
 }
 
 module_init(init_hfs_fs)
 module_exit(exit_hfs_fs)
-
-#if defined(DEBUG_ALL) || defined(DEBUG_MEM)
-long int hfs_alloc = 0;
-#endif
index 1b083b8b9a2f43bfcf1d8785294d175fc973f046..5bf89ec01cd4476ddf17d088aa7a58d8e303edc3 100644 (file)
 /*
- * linux/fs/hfs/sysdep.c
+ *  linux/fs/hfs/sysdep.c
  *
  * Copyright (C) 1996  Paul H. Hargrove
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * This file contains the code to do various system dependent things.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
  */
 
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
-#include <linux/smp_lock.h>
-
-static int hfs_revalidate_dentry(struct dentry *, struct nameidata *);
-static int hfs_hash_dentry(struct dentry *, struct qstr *);
-static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
-static void hfs_dentry_iput(struct dentry *, struct inode *);
-struct dentry_operations hfs_dentry_operations =
-{
-       .d_revalidate   = hfs_revalidate_dentry,        
-       .d_hash         = hfs_hash_dentry,
-       .d_compare      = hfs_compare_dentry,
-       .d_iput         = hfs_dentry_iput,
-};
-
-/*
- * hfs_buffer_get()
- *
- * Return a buffer for the 'block'th block of the media.
- * If ('read'==0) then the buffer is not read from disk.
- */
-hfs_buffer hfs_buffer_get(hfs_sysmdb sys_mdb, int block, int read) {
-       hfs_buffer tmp = HFS_BAD_BUFFER;
-
-       if (read) {
-               tmp = sb_bread(sys_mdb, block);
-       } else {
-               tmp = sb_getblk(sys_mdb, block);
-               if (tmp) {
-                       set_buffer_uptodate(tmp);
-               }
-       }
-       if (!tmp) {
-               hfs_error("hfs_fs: unable to read block 0x%08x from dev %s\n",
-                         block, hfs_mdb_name(sys_mdb));
-       }
-
-       return tmp;
-}
+#include "hfs_fs.h"
 
 /* dentry case-handling: just lowercase everything */
 
-/* hfs_strhash now uses the same hashing function as the dcache. */
-static int hfs_hash_dentry(struct dentry *dentry, struct qstr *this)
-{
-       if (this->len > HFS_NAMELEN)
-               return 0;
-       
-       this->hash = hfs_strhash(this->name, this->len);
-       return 0;
-}
-
-/* return 1 on failure and 0 on success */
-static int hfs_compare_dentry(struct dentry *dentry, struct qstr *a, 
-                             struct qstr *b)
-{
-       if (a->len != b->len) return 1;
-
-       if (a->len > HFS_NAMELEN)
-         return 1;
-
-       return !hfs_streq(a->name, a->len, b->name, b->len);
-}
-
-static void hfs_dentry_iput(struct dentry *dentry, struct inode *inode)
-{
-       struct hfs_cat_entry *entry = HFS_I(inode)->entry;
-
-       lock_kernel();
-       entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL;
-       unlock_kernel();
-       iput(inode);
-}
-
 static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
        int diff;
 
+       if(!inode)
+               return 1;
+
        /* fix up inode on a timezone change */
-       lock_kernel();
-       if (inode && 
-           (diff = (hfs_to_utc(0) - HFS_I(inode)->tz_secondswest))) {
+       diff = sys_tz.tz_minuteswest * 60 - HFS_I(inode)->tz_secondswest;
+       if (diff) {
                inode->i_ctime.tv_sec += diff;
                inode->i_atime.tv_sec += diff;
                inode->i_mtime.tv_sec += diff;
                HFS_I(inode)->tz_secondswest += diff;
        }
-       unlock_kernel();
        return 1;
 }
+
+struct dentry_operations hfs_dentry_operations =
+{
+       .d_revalidate   = hfs_revalidate_dentry,
+       .d_hash         = hfs_hash_dentry,
+       .d_compare      = hfs_compare_dentry,
+};
+
index 64adf73fc5c6755b062c0f5b98514fd1cd6e03b8..fb9720abbadd64ff572f58b4533302247347e50c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/hfs/trans.c
+ *  linux/fs/hfs/trans.c
  *
  * Copyright (C) 1995-1997  Paul H. Hargrove
  * This file may be distributed under the terms of the GNU General Public License.
  * This file contains routines for converting between the Macintosh
  * character set and various other encodings.  This includes dealing
  * with ':' vs. '/' as the path-element separator.
- *
- * Latin-1 translation based on code contributed by Holger Schemel
- * (aeglos@valinor.owl.de).
- *
- * The '8-bit', '7-bit ASCII' and '7-bit alphanumeric' encodings are
- * implementations of the three encodings recommended by Apple in the
- * document "AppleSingle/AppleDouble Formats: Developer's Note
- * (9/94)".  This document is available from Apple's Technical
- * Information Library from the World Wide Web server
- * www.info.apple.com.
- *
- * The 'CAP' encoding is an implementation of the naming scheme used
- * by the Columbia AppleTalk Package, available for anonymous FTP from
- * ????.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
  */
 
-#include "hfs.h"
-#include <linux/hfs_fs_sb.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs.h>
-
-/*================ File-local variables ================*/
-
-/* int->ASCII map for a single hex digit */
-static char hex[16] = {'0','1','2','3','4','5','6','7',
-                      '8','9','a','b','c','d','e','f'};
-/*
- * Latin-1 to Mac character set map
- *
- * For the sake of consistency this map is generated from the Mac to
- * Latin-1 map the first time it is needed.  This means there is just
- * one map to maintain.
- */
-static unsigned char latin2mac_map[128]; /* initially all zero */
-
-/*
- * Mac to Latin-1 map for the upper 128 characters (both have ASCII in
- * the lower 128 positions)
- */
-static unsigned char mac2latin_map[128] = {
-       0xC4, 0xC5, 0xC7, 0xC9, 0xD1, 0xD6, 0xDC, 0xE1,
-       0xE0, 0xE2, 0xE4, 0xE3, 0xE5, 0xE7, 0xE9, 0xE8,
-       0xEA, 0xEB, 0xED, 0xEC, 0xEE, 0xEF, 0xF1, 0xF3,
-       0xF2, 0xF4, 0xF6, 0xF5, 0xFA, 0xF9, 0xFB, 0xFC,
-       0x00, 0xB0, 0xA2, 0xA3, 0xA7, 0xB7, 0xB6, 0xDF,
-       0xAE, 0xA9, 0x00, 0xB4, 0xA8, 0x00, 0xC6, 0xD8,
-       0x00, 0xB1, 0x00, 0x00, 0xA5, 0xB5, 0xF0, 0x00, 
-       0x00, 0x00, 0x00, 0xAA, 0xBA, 0x00, 0xE6, 0xF8,
-       0xBF, 0xA1, 0xAC, 0x00, 0x00, 0x00, 0x00, 0xAB,
-       0xBB, 0x00, 0xA0, 0xC0, 0xC3, 0xD5, 0x00, 0x00, 
-       0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0x00, 
-       0xFF, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0x00, 
-       0x00, 0x00, 0xB8, 0x00, 0x00, 0xC2, 0xCA, 0xC1,
-       0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0xD3, 0xD4,
-       0x00, 0xD2, 0xDA, 0xDB, 0xD9, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-/*================ File-local functions ================*/
-
-/*
- * dehex()
- *
- * Given a hexadecimal digit in ASCII, return the integer representation.
- */
-static inline const unsigned char dehex(char c) {
-       if ((c>='0')&&(c<='9')) {
-               return c-'0';
-       }
-       if ((c>='a')&&(c<='f')) {
-               return c-'a'+10;
-       }
-       if ((c>='A')&&(c<='F')) {
-               return c-'A'+10;
-       }
-       return 0xff;
-}
+#include "hfs_fs.h"
 
 /*================ Global functions ================*/
 
-/*
- * hfs_mac2nat()
- *
- * Given a 'Pascal String' (a string preceded by a length byte) in
- * the Macintosh character set produce the corresponding filename using
- * the Netatalk name-mangling scheme, returning the length of the
- * mangled filename.  Note that the output string is not NULL terminated.
- *
- * The name-mangling works as follows:
- * Characters 32-126 (' '-'~') except '/' and any initial '.' are passed
- * unchanged from input to output.  The remaining characters are replaced
- * by three characters: ':xx' where xx is the hexadecimal representation
- * of the character, using lowercase 'a' through 'f'.
- */
-int hfs_mac2nat(char *out, const struct hfs_name *in) {
-       unsigned char c;
-       const unsigned char *p = in->Name;
-       int len = in->Len;
-       int count = 0;
-
-       /* Special case for .AppleDesktop which in the
-          distant future may be a pseudodirectory. */
-       if (strncmp(".AppleDesktop", p, len) == 0) {
-               strncpy(out, p, 13);
-               return 13;
-       }
-
-       while (len--) {
-               c = *p++;
-               if ((c<32) || (c=='/') || (c>126) || (!count && (c=='.'))) {
-                       *out++ = ':';
-                       *out++ = hex[(c>>4) & 0xf];
-                       *out++ = hex[c & 0xf];
-                       count += 3;
-               } else {
-                       *out++ = c;
-                       count++;
-               }
-       }
-       return count;
-}
-
-/*
- * hfs_mac2cap()
- *
- * Given a 'Pascal String' (a string preceded by a length byte) in
- * the Macintosh character set produce the corresponding filename using
- * the CAP name-mangling scheme, returning the length of the mangled
- * filename.  Note that the output string is not NULL terminated.
- *
- * The name-mangling works as follows:
- * Characters 32-126 (' '-'~') except '/' are passed unchanged from
- * input to output.  The remaining characters are replaced by three
- * characters: ':xx' where xx is the hexadecimal representation of the
- * character, using lowercase 'a' through 'f'.
- */
-int hfs_mac2cap(char *out, const struct hfs_name *in) {
-       unsigned char c;
-       const unsigned char *p = in->Name;
-       int len = in->Len;
-       int count = 0;
-
-       while (len--) {
-               c = *p++;
-               if ((c<32) || (c=='/') || (c>126)) {
-                       *out++ = ':';
-                       *out++ = hex[(c>>4) & 0xf];
-                       *out++ = hex[c & 0xf];
-                       count += 3;
-               } else {
-                       *out++ = c;
-                       count++;
-               }
-       }
-       return count;
-}
-
-/*
- * hfs_mac2eight()
- *
- * Given a 'Pascal String' (a string preceded by a length byte) in
- * the Macintosh character set produce the corresponding filename using
- * the '8-bit' name-mangling scheme, returning the length of the
- * mangled filename.  Note that the output string is not NULL
- * terminated.
- *
- * This is one of the three recommended naming conventions described
- * in Apple's document "AppleSingle/AppleDouble Formats: Developer's
- * Note (9/94)"
- *
- * The name-mangling works as follows:
- * Characters 0, '%' and '/' are replaced by three characters: '%xx'
- * where xx is the hexadecimal representation of the character, using
- * lowercase 'a' through 'f'.  All other characters are passed
- * unchanged from input to output.  Note that this format is mainly
- * implemented for completeness and is rather hard to read.
- */
-int hfs_mac2eight(char *out, const struct hfs_name *in) {
-       unsigned char c;
-       const unsigned char *p = in->Name;
-       int len = in->Len;
-       int count = 0;
-
-       while (len--) {
-               c = *p++;
-               if (!c || (c=='/') || (c=='%')) {
-                       *out++ = '%';
-                       *out++ = hex[(c>>4) & 0xf];
-                       *out++ = hex[c & 0xf];
-                       count += 3;
-               } else {
-                       *out++ = c;
-                       count++;
-               }
-       }
-       return count;
-}
-
-/*
- * hfs_mac2seven()
- *
- * Given a 'Pascal String' (a string preceded by a length byte) in
- * the Macintosh character set produce the corresponding filename using
- * the '7-bit ASCII' name-mangling scheme, returning the length of the
- * mangled filename.  Note that the output string is not NULL
- * terminated.
- *
- * This is one of the three recommended naming conventions described
- * in Apple's document "AppleSingle/AppleDouble Formats: Developer's
- * Note (9/94)"
- *
- * The name-mangling works as follows:
- * Characters 0, '%', '/' and 128-255 are replaced by three
- * characters: '%xx' where xx is the hexadecimal representation of the
- * character, using lowercase 'a' through 'f'. All other characters
- * are passed unchanged from input to output.  Note that control
- * characters (including newline) and space are unchanged make reading
- * these filenames difficult.
- */
-int hfs_mac2seven(char *out, const struct hfs_name *in) {
-       unsigned char c;
-       const unsigned char *p = in->Name;
-       int len = in->Len;
-       int count = 0;
-
-       while (len--) {
-               c = *p++;
-               if (!c || (c=='/') || (c=='%') || (c&0x80)) {
-                       *out++ = '%';
-                       *out++ = hex[(c>>4) & 0xf];
-                       *out++ = hex[c & 0xf];
-                       count += 3;
-               } else {
-                       *out++ = c;
-                       count++;
-               }
-       }
-       return count;
-}
-
-/*
- * hfs_mac2alpha()
- *
- * Given a 'Pascal String' (a string preceded by a length byte) in
- * the Macintosh character set produce the corresponding filename using
- * the '7-bit alphanumeric' name-mangling scheme, returning the length
- * of the mangled filename.  Note that the output string is not NULL
- * terminated.
- *
- * This is one of the three recommended naming conventions described
- * in Apple's document "AppleSingle/AppleDouble Formats: Developer's
- * Note (9/94)"
- *
- * The name-mangling works as follows:
- * The characters 'a'-'z', 'A'-'Z', '0'-'9', '_' and the last '.' in
- * the filename are passed unchanged from input to output.  All
- * remaining characters (including any '.'s other than the last) are
- * replaced by three characters: '%xx' where xx is the hexadecimal
- * representation of the character, using lowercase 'a' through 'f'.
- */
-int hfs_mac2alpha(char *out, const struct hfs_name *in) {
-       unsigned char c;
-       const unsigned char *p = in->Name;
-       int len = in->Len;
-       int count = 0;
-       const unsigned char *lp;        /* last period */
-
-       /* strrchr() would be good here, but 'in' is not null-terminated */
-       for (lp=p+len-1; (lp>=p)&&(*lp!='.'); --lp) {}
-       ++lp;
-
-       while (len--) {
-               c = *p++;
-               if ((p==lp) || ((c>='0')&&(c<='9')) || ((c>='A')&&(c<='Z')) ||
-                               ((c>='a')&&(c<='z')) || (c=='_')) {
-                       *out++ = c;
-                       count++;
-               } else {
-                       *out++ = '%';
-                       *out++ = hex[(c>>4) & 0xf];
-                       *out++ = hex[c & 0xf];
-                       count += 3;
-               }
-       }
-       return count;
-}
-
 /*
  * hfs_mac2triv()
  *
@@ -314,154 +27,19 @@ int hfs_mac2alpha(char *out, const struct hfs_name *in) {
  * by ':' which never appears in HFS filenames.         All other characters
  * are passed unchanged from input to output.
  */
-int hfs_mac2triv(char *out, const struct hfs_name *in) {
-       unsigned char c;
-       const unsigned char *p = in->Name;
-       int len = in->Len;
-       int count = 0;
-
-       while (len--) {
-               c = *p++;
-               if (c=='/') {
-                       *out++ = ':';
-               } else {
-                       *out++ = c;
-               }
-               count++;
-       }
-       return count;
-}
-
-/*
- * hfs_mac2latin()
- *
- * Given a 'Pascal String' (a string preceded by a length byte) in
- * the Macintosh character set produce the corresponding filename using
- * the 'Latin-1' name-mangling scheme, returning the length of the
- * mangled filename.  Note that the output string is not NULL
- * terminated.
- *
- * The Macintosh character set and Latin-1 are both extensions of the
- * ASCII character set.         Some, but certainly not all, of the characters
- * in the Macintosh character set are also in Latin-1 but not with the
- * same encoding.  This name-mangling scheme replaces the characters in
- * the Macintosh character set that have Latin-1 equivalents by those
- * equivalents; the characters 32-126, excluding '/' and '%', are
- * passed unchanged from input to output.  The remaining characters
- * are replaced by three characters: '%xx' where xx is the hexadecimal
- * representation of the character, using lowercase 'a' through 'f'.
- *
- * The array mac2latin_map[] indicates the correspondence between the
- * two character sets. The byte in element x-128 gives the Latin-1
- * encoding of the character with encoding x in the Macintosh
- * character set.  A value of zero indicates Latin-1 has no
- * corresponding character.
- */
-int hfs_mac2latin(char *out, const struct hfs_name *in) {
-       unsigned char c;
-       const unsigned char *p = in->Name;
-       int len = in->Len;
-       int count = 0;
+int hfs_mac2triv(char *out, const struct hfs_name *in)
+{
+       const char *p;
+       char c;
+       int i, len;
 
-       while (len--) {
+       len = in->len;
+       p = in->name;
+       for (i = 0; i < len; i++) {
                c = *p++;
-
-               if ((c & 0x80) && mac2latin_map[c & 0x7f]) {
-                       *out++ = mac2latin_map[c & 0x7f];
-                       count++;
-               } else if ((c>=32) && (c<=126) && (c!='/') && (c!='%')) {
-                       *out++ =  c;
-                       count++;
-               } else {
-                       *out++ = '%';
-                       *out++ = hex[(c>>4) & 0xf];
-                       *out++ = hex[c & 0xf];
-                       count += 3;
-               }
-       }
-       return count;
-}
-
-/*
- * hfs_colon2mac()
- *
- * Given an ASCII string (not null-terminated) and its length,
- * generate the corresponding filename in the Macintosh character set
- * using the 'CAP' name-mangling scheme, returning the length of the
- * mangled filename.  Note that the output string is not NULL
- * terminated.
- *
- * This routine is a inverse to hfs_mac2cap() and hfs_mac2nat().
- * A ':' not followed by a 2-digit hexadecimal number (or followed
- * by the codes for NULL or ':') is replaced by a '|'.
- */
-void hfs_colon2mac(struct hfs_name *out, const char *in, int len) {
-       int hi, lo;
-       unsigned char code, c, *count;
-       unsigned char *p = out->Name;
-
-       out->Len = 0;
-       count = &out->Len;
-       while (len-- && (*count < HFS_NAMELEN)) {
-               c = *in++;
-               (*count)++;
-               if (c!=':') {
-                       *p++ = c;
-               } else if ((len<2) ||
-                          ((hi=dehex(in[0])) & 0xf0) ||
-                          ((lo=dehex(in[1])) & 0xf0) ||
-                          !(code = (hi << 4) | lo) ||
-                          (code == ':')) {
-                       *p++ = '|';
-               } else {
-                       *p++ = code;
-                       len -= 2;
-                       in += 2;
-               }
-       }
-}
-
-/*
- * hfs_prcnt2mac()
- *
- * Given an ASCII string (not null-terminated) and its length,
- * generate the corresponding filename in the Macintosh character set
- * using Apple's three recommended name-mangling schemes, returning
- * the length of the mangled filename. Note that the output string is
- * not NULL terminated.
- *
- * This routine is a inverse to hfs_mac2alpha(), hfs_mac2seven() and
- * hfs_mac2eight().
- * A '%' not followed by a 2-digit hexadecimal number (or followed
- * by the code for NULL or ':') is unchanged.
- * A ':' is replaced by a '|'.
- */
-void hfs_prcnt2mac(struct hfs_name *out, const char *in, int len) {
-       int hi, lo;
-       unsigned char code, c, *count;
-       unsigned char *p = out->Name;
-
-       out->Len = 0;
-       count = &out->Len;
-       while (len-- && (*count < HFS_NAMELEN)) {
-               c = *in++;
-               (*count)++;
-               if (c==':') {
-                       *p++ = '|';
-               } else if (c!='%') {
-                       *p++ = c;
-               } else if ((len<2) ||
-                          ((hi=dehex(in[0])) & 0xf0) ||
-                          ((lo=dehex(in[1])) & 0xf0) ||
-                          !(code = (hi << 4) | lo) ||
-                          (code == ':')) {
-                       *p++ = '%';
-               } else {
-                       *p++ = code;
-                       len -= 2;
-                       in += 2;
-               }
+               *out++ = c == '/' ? ':' : c;
        }
+       return i;
 }
 
 /*
@@ -476,81 +54,19 @@ void hfs_prcnt2mac(struct hfs_name *out, const char *in, int len) {
  * This routine is a inverse to hfs_mac2triv().
  * A ':' is replaced by a '/'.
  */
-void hfs_triv2mac(struct hfs_name *out, const char *in, int len) {
-       unsigned char c, *count;
-       unsigned char *p = out->Name;
-
-       out->Len = 0;
-       count = &out->Len;
-       while (len-- && (*count < HFS_NAMELEN)) {
-               c = *in++;
-               (*count)++;
-               if (c==':') {
-                       *p++ = '/';
-               } else {
-                       *p++ = c;
-               }
-       }
-}
-
-/*
- * hfs_latin2mac()
- *
- * Given an Latin-1 string (not null-terminated) and its length,
- * generate the corresponding filename in the Macintosh character set
- * using the 'Latin-1' name-mangling scheme, returning the length of
- * the mangled filename.  Note that the output string is not NULL
- * terminated.
- *
- * This routine is a inverse to hfs_latin2cap().
- * A '%' not followed by a 2-digit hexadecimal number (or followed
- * by the code for NULL or ':') is unchanged.
- * A ':' is replaced by a '|'.
- *
- * Note that the character map is built the first time it is needed.
- */
-void hfs_latin2mac(struct hfs_name *out, const char *in, int len)
+void hfs_triv2mac(struct hfs_name *out, struct qstr *in)
 {
-       int hi, lo;
-       unsigned char code, c, *count;
-       unsigned char *p = out->Name;
-       static int map_initialized;
-
-       if (!map_initialized) {
-               int i;
-
-               /* build the inverse mapping at run time */
-               for (i = 0; i < 128; i++) {
-                       if ((c = mac2latin_map[i])) {
-                               latin2mac_map[(int)c - 128] = i + 128;
-                       }
-               }
-               map_initialized = 1;
-       }
-
-       out->Len = 0;
-       count = &out->Len;
-       while (len-- && (*count < HFS_NAMELEN)) {
-               c = *in++;
-               (*count)++;
-
-               if (c==':') {
-                       *p++ = '|';
-               } else if (c!='%') {
-                       if (c<128 || !(*p = latin2mac_map[c-128])) {
-                               *p = c;
-                       }
-                       p++;
-               } else if ((len<2) ||
-                          ((hi=dehex(in[0])) & 0xf0) ||
-                          ((lo=dehex(in[1])) & 0xf0) ||
-                          !(code = (hi << 4) | lo) ||
-                          (code == ':')) {
-                       *p++ = '%';
-               } else {
-                       *p++ = code;
-                       len -= 2;
-                       in += 2;
-               }
-       }
+       const char *src;
+       char *dst, c;
+       int i, len;
+
+       out->len = len = min((unsigned int)HFS_NAMELEN, in->len);
+       src = in->name;
+       dst = out->name;
+       for (i = 0; i < len; i++) {
+               c = *src++;
+               *dst++ = c == ':' ? '/' : c;
+       }
+       for (; i < HFS_NAMELEN; i++)
+               *dst++ = 0;
 }
diff --git a/fs/hfs/version.c b/fs/hfs/version.c
deleted file mode 100644 (file)
index ef0283e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * linux/fs/hfs/version.c
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains the version string for this release.
- */
-
-const char hfs_version[]="0.96";
diff --git a/include/linux/hfs_fs.h b/include/linux/hfs_fs.h
deleted file mode 100644 (file)
index 6cddc47..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/* 
- * linux/include/linux/hfs_fs.h
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * The source code distribution of the Columbia AppleTalk Package for
- * UNIX, version 6.0, (CAP) was used as a specification of the
- * location and format of files used by CAP's Aufs.  No code from CAP
- * appears in hfs_fs.  hfs_fs is not a work ``derived'' from CAP in
- * the sense of intellectual property law.
- *
- * The source code distributions of Netatalk, versions 1.3.3b2 and
- * 1.4b2, were used as a specification of the location and format of
- * files used by Netatalk's afpd.  No code from Netatalk appears in
- * hfs_fs.  hfs_fs is not a work ``derived'' from Netatalk in the
- * sense of intellectual property law.
- */
-
-#ifndef _LINUX_HFS_FS_H
-#define _LINUX_HFS_FS_H
-
-#include <linux/hfs_sysdep.h>
-
-/* magic numbers for Apple Double header files */
-#define HFS_DBL_MAGIC          0x00051607
-#define HFS_SNGL_MAGIC         0x00051600
-#define HFS_HDR_VERSION_1      0x00010000
-#define HFS_HDR_VERSION_2      0x00020000
-
-/* magic numbers for various internal structures */
-#define HFS_INO_MAGIC          0x4821
-#define HFS_SB_MAGIC           0x4822
-
-/* The space used for the AppleDouble or AppleSingle headers */
-#define HFS_DBL_HDR_LEN                1024
-
-/* The space used for the Netatalk header */
-#define HFS_NAT_HDR_LEN                1024  /* 589 for an exact match */
-
-/* Macros to extract CNID and file "type" from the Linux inode number */
-#define HFS_CNID(X)    ((X) & 0x3FFFFFFF)
-#define HFS_ITYPE(X)   ((X) & 0xC0000000)
-
-/* Macros to enumerate types */
-#define HFS_ITYPE_TO_INT(X)    ((X) >> 30)
-#define HFS_INT_TO_ITYPE(X)    ((X) << 30)
-
-/* generic ITYPEs */
-#define HFS_ITYPE_0    0x00000000
-#define HFS_ITYPE_1    0x40000000
-#define HFS_ITYPE_2    0x80000000
-#define HFS_ITYPE_3    0xC0000000
-#define HFS_ITYPE_NORM HFS_ITYPE_0     /* "normal" directory or file */
-
-/* ITYPEs for CAP */
-#define HFS_CAP_NORM   HFS_ITYPE_0     /* data fork or normal directory */
-#define HFS_CAP_DATA   HFS_ITYPE_0     /* data fork of file */
-#define HFS_CAP_NDIR   HFS_ITYPE_0     /* normal directory */
-#define HFS_CAP_FNDR   HFS_ITYPE_1     /* finder info for file or dir */
-#define HFS_CAP_RSRC   HFS_ITYPE_2     /* resource fork of file */
-#define HFS_CAP_RDIR   HFS_ITYPE_2     /* .resource directory */
-#define HFS_CAP_FDIR   HFS_ITYPE_3     /* .finderinfo directory */
-
-/* ITYPEs for Apple Double */
-#define HFS_DBL_NORM   HFS_ITYPE_0     /* data fork or directory */
-#define HFS_DBL_DATA   HFS_ITYPE_0     /* data fork of file */
-#define HFS_DBL_DIR    HFS_ITYPE_0     /* directory */
-#define HFS_DBL_HDR    HFS_ITYPE_1     /* AD header of file or dir */
-
-/* ITYPEs for netatalk */
-#define HFS_NAT_NORM   HFS_ITYPE_0     /* data fork or directory */
-#define HFS_NAT_DATA   HFS_ITYPE_0     /* data fork of file */
-#define HFS_NAT_NDIR   HFS_ITYPE_0     /* normal directory */
-#define HFS_NAT_HDR    HFS_ITYPE_1     /* AD header of file or dir */
-#define HFS_NAT_HDIR   HFS_ITYPE_2     /* directory holding AD headers */
-
-/* ITYPEs for Apple Single */
-#define HFS_SGL_NORM   HFS_ITYPE_0     /* AppleSingle file or directory */
-#define HFS_SGL_SNGL   HFS_ITYPE_0     /* AppleSingle file */
-#define HFS_SGL_DIR    HFS_ITYPE_0     /* directory */
-#define HFS_SGL_DINF   HFS_ITYPE_1     /* %DirInfo for directory */
-
-/* IDs for elements of an AppleDouble or AppleSingle header */
-#define HFS_HDR_DATA   1   /* data fork */
-#define HFS_HDR_RSRC   2   /* resource fork */
-#define HFS_HDR_FNAME  3   /* full (31-character) name */
-#define HFS_HDR_COMNT  4   /* comment */
-#define HFS_HDR_BWICN  5   /* b/w icon */
-#define HFS_HDR_CICON  6   /* color icon info */
-#define HFS_HDR_OLDI   7   /* old file info */
-#define HFS_HDR_DATES  8   /* file dates info */
-#define HFS_HDR_FINFO  9   /* Finder info */
-#define HFS_HDR_MACI   10  /* Macintosh info */
-#define HFS_HDR_PRODOSI 11  /* ProDOS info */
-#define HFS_HDR_MSDOSI  12  /* MSDOS info */
-#define HFS_HDR_SNAME   13  /* short name */
-#define HFS_HDR_AFPI    14  /* AFP file info */
-#define HFS_HDR_DID     15  /* directory id */
-#define HFS_HDR_MAX    16
-
-/*
- * There are three time systems.  All three are based on seconds since
- * a particular time/date.
- *     Unix:   unsigned lil-endian since 00:00 GMT, Jan. 1, 1970
- *     mac:    unsigned big-endian since 00:00 GMT, Jan. 1, 1904
- *     header:   SIGNED big-endian since 00:00 GMT, Jan. 1, 2000
- *
- */
-#define hfs_h_to_mtime(ARG)    htonl((hfs_s32)ntohl(ARG)+3029529600U)
-#define hfs_m_to_htime(ARG)    ((hfs_s32)htonl(ntohl(ARG)-3029529600U))
-#define hfs_h_to_utime(ARG)    ((hfs_s32)hfs_to_utc(ntohl(ARG)+946684800U))
-#define hfs_u_to_htime(ARG)    ((hfs_s32)htonl(hfs_from_utc(ARG)-946684800U))
-#define hfs_u_to_mtime(ARG)    htonl(hfs_from_utc(ARG)+2082844800U)
-#define hfs_m_to_utime(ARG)    (hfs_to_utc(ntohl(ARG)-2082844800U))
-
-/*======== Data structures kept in memory ========*/
-
-/*
- * A descriptor for a single entry within the header of an
- * AppleDouble or AppleSingle header file.
- * An array of these make up a table of contents for the file.
- */
-struct hfs_hdr_descr {
-       hfs_u32 id;     /* The Apple assigned ID for the entry type */
-       hfs_u32 offset; /* The offset to reach the entry */
-       hfs_u32 length; /* The length of the entry */
-};
-
-/*
- * The info needed to reconstruct a given header layout
- */
-struct hfs_hdr_layout {
-       hfs_u32         magic;                  /* AppleSingle or AppleDouble */
-       hfs_u32         version;                /* 0x00010000 or 0x00020000 */
-       hfs_u16         entries;                /* How many entries used */
-       struct hfs_hdr_descr    
-                       descr[HFS_HDR_MAX];     /* Descriptors */
-       struct hfs_hdr_descr    
-                       *order[HFS_HDR_MAX];    /* 'descr' ordered by offset */
-};
-
-/* header layout for netatalk's v1 appledouble file format */
-struct hfs_nat_hdr {
-       hfs_lword_t     magic;
-       hfs_lword_t     version;
-       hfs_byte_t      homefs[16];
-       hfs_word_t      entries;
-       hfs_byte_t      descrs[12*5];
-       hfs_byte_t      real_name[255]; /* id=3 */
-       hfs_byte_t      comment[200];   /* id=4 XXX: not yet implemented */
-       hfs_byte_t      old_info[16];   /* id=7 */
-       hfs_u8          finderinfo[32]; /* id=9 */
-};
-
-/* 
- * Default header layout for Netatalk and AppleDouble
- */
-struct hfs_dbl_hdr {
-       hfs_lword_t     magic;
-       hfs_lword_t     version;
-       hfs_byte_t      filler[16];
-       hfs_word_t      entries;
-       hfs_byte_t      descrs[12*HFS_HDR_MAX];
-       hfs_byte_t      real_name[255]; /* id=3 */
-       hfs_byte_t      comment[200];   /* id=4 XXX: not yet implemented */
-       hfs_u32         create_time;    /* \              */
-       hfs_u32         modify_time;    /*  | id=8 (or 7) */
-       hfs_u32         backup_time;    /*  |             */
-       hfs_u32         access_time;    /* /  (attributes with id=7) */
-       hfs_u8          finderinfo[32]; /* id=9 */
-       hfs_u32         fileinfo;       /* id=10 */
-        hfs_u32         cnid;           /* id=15 */
-       hfs_u8          short_name[12]; /* id=13 */
-       hfs_u8          prodosi[8];     /* id=11 */
-};
-
-
-/* finder metadata for CAP */
-struct hfs_cap_info {
-       hfs_byte_t      fi_fndr[32];    /* Finder's info */
-       hfs_word_t      fi_attr;        /* AFP attributes (f=file/d=dir) */
-#define HFS_AFP_INV             0x001   /* Invisible bit (f/d) */
-#define HFS_AFP_EXPFOLDER       0x002   /* exported folder (d) */
-#define HFS_AFP_MULTI           0x002   /* Multiuser bit (f) */
-#define HFS_AFP_SYS             0x004   /* System bit (f/d) */
-#define HFS_AFP_DOPEN           0x008   /* data fork already open (f) */
-#define HFS_AFP_MOUNTED         0x008   /* mounted folder (d) */
-#define HFS_AFP_ROPEN           0x010   /* resource fork already open (f) */
-#define HFS_AFP_INEXPFOLDER     0x010   /* folder in shared area (d) */
-#define HFS_AFP_WRI            0x020   /* Write inhibit bit (readonly) (f) */
-#define HFS_AFP_BACKUP          0x040   /* backup needed bit (f/d)  */
-#define HFS_AFP_RNI            0x080   /* Rename inhibit bit (f/d) */
-#define HFS_AFP_DEI            0x100   /* Delete inhibit bit (f/d) */
-#define HFS_AFP_NOCOPY          0x400   /* Copy protect bit (f) */
-#define HFS_AFP_RDONLY (       HFS_AFP_WRI|HFS_AFP_RNI|HFS_AFP_DEI)
-       hfs_byte_t      fi_magic1;      /* Magic number: */
-#define HFS_CAP_MAGIC1         0xFF
-       hfs_byte_t      fi_version;     /* Version of this structure: */
-#define HFS_CAP_VERSION                0x10
-       hfs_byte_t      fi_magic;       /* Another magic number: */
-#define HFS_CAP_MAGIC          0xDA
-       hfs_byte_t      fi_bitmap;      /* Bitmap of which names are valid: */
-#define HFS_CAP_SHORTNAME      0x01
-#define HFS_CAP_LONGNAME       0x02
-       hfs_byte_t      fi_shortfilename[12+1]; /* "short name" (unused) */
-       hfs_byte_t      fi_macfilename[32+1];   /* Original (Macintosh) name */
-       hfs_byte_t      fi_comln;       /* Length of comment (always 0) */
-       hfs_byte_t      fi_comnt[200];  /* Finder comment (unused) */
-       /* optional:    used by aufs only if compiled with USE_MAC_DATES */
-       hfs_byte_t      fi_datemagic;   /* Magic number for dates extension: */
-#define HFS_CAP_DMAGIC         0xDA
-       hfs_byte_t      fi_datevalid;   /* Bitmap of which dates are valid: */
-#define HFS_CAP_MDATE          0x01
-#define HFS_CAP_CDATE          0x02
-       hfs_lword_t     fi_ctime;       /* Creation date (in AFP format) */
-       hfs_lword_t     fi_mtime;       /* Modify date (in AFP format) */
-       hfs_lword_t     fi_utime;       /* Un*x time of last mtime change */
-       hfs_byte_t      pad;
-};
-
-#ifdef __KERNEL__
-
-typedef ssize_t hfs_rwret_t;
-typedef size_t hfs_rwarg_t;
-
-#include <asm/uaccess.h>
-
-/* Some forward declarations */
-struct hfs_fork;
-struct hfs_cat_key;
-struct hfs_cat_entry;
-extern struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *,
-                                        const struct hfs_cat_key *);
-
-/* dir.c */
-extern int hfs_create(struct inode *, struct dentry *, int, struct nameidata *);
-extern int hfs_mkdir(struct inode *, struct dentry *, int);
-extern int hfs_unlink(struct inode *, struct dentry *);
-extern int hfs_rmdir(struct inode *, struct dentry *);
-extern int hfs_rename(struct inode *, struct dentry *,
-                     struct inode *, struct dentry *);
-
-/* dir_cap.c */
-extern const struct hfs_name hfs_cap_reserved1[];
-extern const struct hfs_name hfs_cap_reserved2[];
-extern struct inode_operations hfs_cap_ndir_inode_operations;
-extern struct inode_operations hfs_cap_fdir_inode_operations;
-extern struct inode_operations hfs_cap_rdir_inode_operations;
-extern struct file_operations hfs_cap_dir_operations;
-extern void hfs_cap_drop_dentry(struct dentry *, const ino_t);
-
-/* dir_dbl.c */
-extern const struct hfs_name hfs_dbl_reserved1[];
-extern const struct hfs_name hfs_dbl_reserved2[];
-extern struct inode_operations hfs_dbl_dir_inode_operations;
-extern struct file_operations hfs_dbl_dir_operations;
-extern void hfs_dbl_drop_dentry(struct dentry *, const ino_t);
-
-/* dir_nat.c */
-extern const struct hfs_name hfs_nat_reserved1[];
-extern const struct hfs_name hfs_nat_reserved2[];
-extern struct inode_operations hfs_nat_ndir_inode_operations;
-extern struct inode_operations hfs_nat_hdir_inode_operations;
-extern struct file_operations hfs_nat_dir_operations;
-extern void hfs_nat_drop_dentry(struct dentry *, const ino_t);
-
-/* file.c */
-extern hfs_s32 hfs_do_read(struct inode *, struct hfs_fork *, hfs_u32,
-                          char __user *, hfs_u32);
-extern hfs_s32 hfs_do_write(struct inode *, struct hfs_fork *, hfs_u32,
-                           const char __user *, hfs_u32);
-extern void hfs_file_fix_mode(struct hfs_cat_entry *entry);
-extern struct inode_operations hfs_file_inode_operations;
-extern struct file_operations hfs_file_operations;
-
-/* file_cap.c */
-extern struct inode_operations hfs_cap_info_inode_operations;
-extern struct file_operations hfs_cap_info_operations;
-
-/* file_hdr.c */
-extern struct inode_operations hfs_hdr_inode_operations;
-extern struct file_operations hfs_hdr_operations;
-extern const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout;
-extern const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout;
-extern const struct hfs_hdr_layout hfs_nat_hdr_layout;
-extern const struct hfs_hdr_layout hfs_nat2_hdr_layout;
-extern const struct hfs_hdr_layout hfs_sngl_hdr_layout;
-extern void hdr_truncate(struct inode *,size_t);
-
-/* inode.c */
-extern void hfs_put_inode(struct inode *);
-extern int hfs_notify_change(struct dentry *, struct iattr *);
-extern int hfs_notify_change_cap(struct dentry *, struct iattr *);
-extern int hfs_notify_change_hdr(struct dentry *, struct iattr *);
-extern struct inode *hfs_iget(struct hfs_cat_entry *, ino_t, struct dentry *);
-
-extern void hfs_cap_ifill(struct inode *, ino_t, const int);
-extern void hfs_dbl_ifill(struct inode *, ino_t, const int);
-extern void hfs_nat_ifill(struct inode *, ino_t, const int);
-extern void hfs_sngl_ifill(struct inode *, ino_t, const int);
-
-/* super.c */
-extern int hfs_fill_super(struct super_block *,void *,int);
-
-/* trans.c */
-extern void hfs_colon2mac(struct hfs_name *, const char *, int);
-extern void hfs_prcnt2mac(struct hfs_name *, const char *, int);
-extern void hfs_triv2mac(struct hfs_name *, const char *, int);
-extern void hfs_latin2mac(struct hfs_name *, const char *, int);
-extern int hfs_mac2cap(char *, const struct hfs_name *);
-extern int hfs_mac2nat(char *, const struct hfs_name *);
-extern int hfs_mac2latin(char *, const struct hfs_name *);
-extern int hfs_mac2seven(char *, const struct hfs_name *);
-extern int hfs_mac2eight(char *, const struct hfs_name *);
-extern int hfs_mac2alpha(char *, const struct hfs_name *);
-extern int hfs_mac2triv(char *, const struct hfs_name *);
-extern void hfs_tolower(unsigned char *, int);
-
-#include <linux/hfs_fs_i.h>
-#include <linux/hfs_fs_sb.h>
-
-static inline struct hfs_inode_info *HFS_I(struct inode *inode)
-{
-       return container_of(inode, struct hfs_inode_info, vfs_inode);
-}
-
-static inline struct hfs_sb_info *HFS_SB(struct super_block *sb)
-{
-       return sb->s_fs_info;
-}
-
-static inline void hfs_nameout(struct inode *dir, struct hfs_name *out,
-                                  const char *in, int len) {
-       HFS_SB(dir->i_sb)->s_nameout(out, in, len);
-}
-
-static inline int hfs_namein(struct inode *dir, char *out,
-                                const struct hfs_name *in) {
-       int len = HFS_SB(dir->i_sb)->s_namein(out, in);
-       if (HFS_SB(dir->i_sb)->s_lowercase) {
-               hfs_tolower(out, len);
-       }
-       return len;
-}
-
-#endif /* __KERNEL__ */
-#endif
diff --git a/include/linux/hfs_fs_i.h b/include/linux/hfs_fs_i.h
deleted file mode 100644 (file)
index 119cc52..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* 
- * linux/include/linux/hfs_fs_i.h
- *
- * Copyright (C) 1995, 1996  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file defines the type (struct hfs_inode_info) and the two
- * subordinate types hfs_extent and hfs_file.
- */
-
-#ifndef _LINUX_HFS_FS_I_H
-#define _LINUX_HFS_FS_I_H
-
-/*
- * struct hfs_inode_info
- *
- * The HFS-specific part of a Linux (struct inode)
- */
-struct hfs_inode_info {
-       int                             magic;     /* A magic number */
-
-       loff_t                          mmu_private;
-       struct hfs_cat_entry            *entry;
-
-       /* For a regular or header file */
-       struct hfs_fork                 *fork;
-       int                             convert;
-
-       /* For a directory */
-       ino_t                           file_type;
-       char                            dir_size;
-
-       /* For header files */
-       const struct hfs_hdr_layout     *default_layout;
-       struct hfs_hdr_layout           *layout;
-
-       /* to deal with localtime ugliness */
-       int                             tz_secondswest;
-
-        /* for dentry cleanup */
-        void (*d_drop_op)(struct dentry *, const ino_t);
-       struct inode vfs_inode;
-};
-
-#endif
diff --git a/include/linux/hfs_fs_sb.h b/include/linux/hfs_fs_sb.h
deleted file mode 100644 (file)
index 037ebd4..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* 
- * linux/include/linux/hfs_fs_sb.h
- *
- * Copyright (C) 1995-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file defines the type (struct hfs_sb_info) which contains the
- * HFS-specific information in the in-core superblock.
- */
-
-#ifndef _LINUX_HFS_FS_SB_H
-#define _LINUX_HFS_FS_SB_H
-
-/* forward declaration: */
-struct hfs_name;
-
-typedef int (*hfs_namein_fn) (char *, const struct hfs_name *);
-typedef void (*hfs_nameout_fn) (struct hfs_name *, const char *, int);
-typedef void (*hfs_ifill_fn) (struct inode *, ino_t, const int);
-
-/*
- * struct hfs_sb_info
- *
- * The HFS-specific part of a Linux (struct super_block)
- */
-struct hfs_sb_info {
-       int                     magic;          /* A magic number */
-       struct hfs_mdb          *s_mdb;         /* The HFS MDB */
-       int                     s_quiet;        /* Silent failure when 
-                                                  changing owner or mode? */
-       int                     s_lowercase;    /* Map names to lowercase? */
-       int                     s_afpd;         /* AFPD compatible mode? */
-       int                     s_version;      /* version info */
-       hfs_namein_fn           s_namein;       /* The function used to
-                                                  map Mac filenames to
-                                                  Linux filenames */
-       hfs_nameout_fn          s_nameout;      /* The function used to
-                                                   map Linux filenames
-                                                   to Mac filenames */
-       hfs_ifill_fn            s_ifill;        /* The function used
-                                                  to fill in inode fields */
-       const struct hfs_name   *s_reserved1;   /* Reserved names */
-       const struct hfs_name   *s_reserved2;   /* Reserved names */
-       __u32                   s_type;         /* Type for new files */
-       __u32                   s_creator;      /* Creator for new files */
-       umode_t                 s_umask;        /* The umask applied to the
-                                                  permissions on all files */
-       uid_t                   s_uid;          /* The uid of all files */
-       gid_t                   s_gid;          /* The gid of all files */
-       char                    s_conv;         /* Type of text conversion */
-};
-
-#endif
diff --git a/include/linux/hfs_sysdep.h b/include/linux/hfs_sysdep.h
deleted file mode 100644 (file)
index 4c4e3eb..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * linux/include/linux/hfs_sysdep.h
- *
- * Copyright (C) 1996-1997  Paul H. Hargrove
- * This file may be distributed under the terms of the GNU General Public License.
- *
- * This file contains constants, types and inline
- * functions for various system dependent things.
- *
- * "XXX" in a comment is a note to myself to consider changing something.
- *
- * In function preconditions the term "valid" applied to a pointer to
- * a structure means that the pointer is non-NULL and the structure it
- * points to has all fields initialized to consistent values.
- */
-
-#ifndef _HFS_SYSDEP_H
-#define _HFS_SYSDEP_H
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/buffer_head.h>
-
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-
-extern struct timezone sys_tz;
-
-/* Typedefs for integer types by size and signedness */
-typedef __u8            hfs_u8;
-typedef __u16           hfs_u16;
-typedef __u32           hfs_u32;
-typedef __s8            hfs_s8;
-typedef __s16           hfs_s16;
-typedef __s32           hfs_s32;
-
-/* Typedefs for unaligned integer types */
-typedef unsigned char hfs_byte_t;
-typedef unsigned char hfs_word_t[2];
-typedef unsigned char hfs_lword_t[4];
-
-/* these funny looking things are GCC variable argument macros */
-#define hfs_warn(format, args...) printk(KERN_WARNING format , ## args)
-#define hfs_error(format, args...) printk(KERN_ERR format , ## args)
-
-
-#if defined(DEBUG_ALL) || defined(DEBUG_MEM)
-extern long int hfs_alloc;
-#endif
-
-static inline void *hfs_malloc(unsigned int size) {
-#if defined(DEBUG_ALL) || defined(DEBUG_MEM)
-       hfs_warn("%ld bytes allocation at %s:%u\n",
-                (hfs_alloc += size), __FILE__, __LINE__);
-#endif
-       return kmalloc(size, GFP_KERNEL);
-}
-
-static inline void hfs_free(void *ptr, unsigned int size) {
-       kfree(ptr);
-#if defined(DEBUG_ALL) || defined(DEBUG_MEM)
-       hfs_warn("%ld bytes allocation at %s:%u\n",
-                 (hfs_alloc -= ptr ? size : 0), __FILE__, __LINE__);
-#endif
-}
-
-
-/* handle conversion between times. 
- *
- * NOTE: hfs+ doesn't need this. also, we don't use tz_dsttime as that's
- *       not a good thing to do. instead, we depend upon tz_minuteswest
- *       having the correct daylight savings correction. 
- */
-static inline hfs_u32 hfs_from_utc(hfs_s32 time)
-{
-       return time - sys_tz.tz_minuteswest*60; 
-}
-
-static inline hfs_s32 hfs_to_utc(hfs_u32 time)
-{
-       return time + sys_tz.tz_minuteswest*60;
-}
-
-static inline hfs_u32 hfs_time(void) {
-       return htonl(hfs_from_utc(get_seconds())+2082844800U);
-}
-
-
-/*
- * hfs_wait_queue 
- */
-typedef wait_queue_head_t hfs_wait_queue;
-
-static inline void hfs_init_waitqueue(hfs_wait_queue *queue) {
-        init_waitqueue_head(queue);
-}
-
-static inline void hfs_sleep_on(hfs_wait_queue *queue) {
-       sleep_on(queue);
-}
-
-static inline void hfs_wake_up(hfs_wait_queue *queue) {
-       wake_up(queue);
-}
-
-static inline void hfs_relinquish(void) {
-       schedule();
-}
-
-
-/*
- * hfs_sysmdb 
- */
-typedef struct super_block *hfs_sysmdb;
-
-static inline void hfs_mdb_dirty(hfs_sysmdb sys_mdb) {
-       sys_mdb->s_dirt = 1;
-}
-
-static inline const char *hfs_mdb_name(hfs_sysmdb sys_mdb) {
-       return sys_mdb->s_id;
-}
-
-
-/*
- * hfs_sysentry
- */
-typedef struct dentry *hfs_sysentry[4];
-
-/*
- * hfs_buffer
- */
-typedef struct buffer_head *hfs_buffer;
-
-#define HFS_BAD_BUFFER NULL
-
-/* In sysdep.c, since it needs HFS_SECTOR_SIZE */
-extern hfs_buffer hfs_buffer_get(hfs_sysmdb, int, int);
-
-static inline int hfs_buffer_ok(hfs_buffer buffer) {
-       return (buffer != NULL);
-}
-
-static inline void hfs_buffer_put(hfs_buffer buffer) {
-       brelse(buffer);
-}
-
-static inline void hfs_buffer_dirty(hfs_buffer buffer) {
-       mark_buffer_dirty(buffer);
-}
-
-static inline void hfs_buffer_sync(hfs_buffer buffer) {
-       if (buffer_dirty(buffer))
-               sync_dirty_buffer(buffer);
-}
-
-static inline void *hfs_buffer_data(const hfs_buffer buffer) {
-       return buffer->b_data;
-}
-
-
-/*
- * bit operations
- */
-
-#undef BITNR
-#if defined(__BIG_ENDIAN)
-#      define BITNR(X) ((X)^31)
-#      if !defined(__constant_htonl)
-#              define __constant_htonl(x) (x)
-#      endif
-#      if !defined(__constant_htons)
-#              define __constant_htons(x) (x)
-#      endif
-#elif defined(__LITTLE_ENDIAN)
-#      define BITNR(X) ((X)^7)
-#      if !defined(__constant_htonl)
-#              define __constant_htonl(x) \
-        ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
-                             (((unsigned long int)(x) & 0x0000ff00U) <<  8) | \
-                             (((unsigned long int)(x) & 0x00ff0000U) >>  8) | \
-                             (((unsigned long int)(x) & 0xff000000U) >> 24)))
-#      endif
-#      if !defined(__constant_htons)
-#              define __constant_htons(x) \
-        ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
-                              (((unsigned short int)(x) & 0xff00) >> 8)))
-#      endif
-#else
-#      error "Don't know if bytes are big- or little-endian!"
-#endif
-
-static inline int hfs_clear_bit(int bitnr, hfs_u32 *lword) {
-       return test_and_clear_bit(BITNR(bitnr), (unsigned long *)lword);
-}
-
-static inline int hfs_set_bit(int bitnr, hfs_u32 *lword) {
-       return test_and_set_bit(BITNR(bitnr), (unsigned long *)lword);
-}
-
-static inline int hfs_test_bit(int bitnr, const hfs_u32 *lword) {
-       /* the kernel should declare the second arg of test_bit as const */
-       return test_bit(BITNR(bitnr), (unsigned long *)lword);
-}
-
-#undef BITNR
-
-/*
- * HFS structures have fields aligned to 16-bit boundaries.
- * So, 16-bit get/put are easy while 32-bit get/put need
- * some care on architectures like the DEC Alpha.
- *
- * In what follows:
- *     ns  = 16-bit integer in network byte-order w/ 16-bit alignment
- *     hs  = 16-bit integer in host byte-order w/ 16-bit alignment
- *     nl  = 32-bit integer in network byte-order w/ unknown alignment
- *     hl  = 32-bit integer in host byte-order w/ unknown alignment
- *     anl = 32-bit integer in network byte-order w/ 32-bit alignment
- *     ahl = 32-bit integer in host byte-order w/ 32-bit alignment
- * Example: hfs_get_hl() gets an unaligned 32-bit integer converting
- *     it to host byte-order.
- */
-#define hfs_get_hs(addr)       ntohs(*((hfs_u16 *)(addr)))
-#define hfs_get_ns(addr)       (*((hfs_u16 *)(addr)))
-#define hfs_get_hl(addr)       ntohl(get_unaligned((hfs_u32 *)(addr)))
-#define hfs_get_nl(addr)       get_unaligned((hfs_u32 *)(addr))
-#define hfs_get_ahl(addr)      ntohl(*((hfs_u32 *)(addr)))
-#define hfs_get_anl(addr)      (*((hfs_u32 *)(addr)))
-#define hfs_put_hs(val, addr)  ((void)(*((hfs_u16 *)(addr)) = ntohs(val)))
-#define hfs_put_ns(val, addr)  ((void)(*((hfs_u16 *)(addr)) = (val)))
-#define hfs_put_hl(val, addr)  put_unaligned(htonl(val), (hfs_u32 *)(addr))
-#define hfs_put_nl(val, addr)  put_unaligned((val), (hfs_u32 *)(addr))
-#define hfs_put_ahl(val, addr)         ((void)(*((hfs_u32 *)(addr)) = ntohl(val)))
-#define hfs_put_anl(val, addr)         ((void)(*((hfs_u32 *)(addr)) = (val)))
-
-#endif