patch-2.1.78 linux/fs/hfs/mdb.c

Next file: linux/fs/hfs/part_tbl.c
Previous file: linux/fs/hfs/inode.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.77/linux/fs/hfs/mdb.c linux/fs/hfs/mdb.c
@@ -0,0 +1,298 @@
+/*
+ * linux/fs/hfs/mdb.c
+ *
+ * Copyright (C) 1995-1997  Paul H. Hargrove
+ * This file may be distributed under the terms of the GNU 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"
+
+/*================ File-local data types ================*/
+
+/* 
+ * The HFS Master Directory Block (MDB).
+ *
+ * Also known as the Volume Information Block (VIB), this structure is
+ * the HFS equivalent of a superblock.
+ *
+ * Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62
+ */
+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	drVCSize;	/* MacOS caching parameter */
+	hfs_word_t	drVCBMSize;	/* MacOS caching parameter */
+	hfs_word_t	drCtlCSize;	/* MacOS caching parameter */
+	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 */
+};
+
+/*================ Global functions ================*/
+
+/*
+ * hfs_mdb_get()
+ *
+ * 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)
+{
+	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;
+	}
+
+	memset(mdb, 0, sizeof(*mdb));
+	mdb->magic = HFS_MDB_MAGIC;
+	mdb->sys_mdb = sys_mdb;
+
+	/* 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");
+		goto bail2;
+	}
+	raw = (struct raw_mdb *)hfs_buffer_data(buf);
+	if (hfs_get_ns(raw->drSigWord) != htons(HFS_SUPER_MAGIC)) {
+		hfs_buffer_put(buf);
+		goto bail2;
+	}
+	mdb->buf = buf;
+
+	bs = hfs_get_hl(raw->drAlBlkSiz);
+	if (!bs || bs > HFS_USHRT_MAX || (bs & (HFS_SECTOR_SIZE-1))) {
+		hfs_warn("hfs_fs: bad allocation block size %d != 512\n", bs);
+		goto bail1;
+	}
+	mdb->alloc_blksz = bs >> HFS_SECTOR_SIZE_BITS;
+
+	/* 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, 28);
+
+	/* 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);
+	
+	/* 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);
+		}
+	}
+	if (mdb->alt_buf == NULL) {
+		hfs_warn("hfs_fs: unable to locate alternate MDB\n");
+		hfs_warn("hfs_fs: continuing without an alternate MDB\n");
+	}
+
+	/* 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))) {
+			hfs_warn("hfs_fs: unable to read volume bitmap\n");
+			goto bail1;
+		}
+	}
+
+	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;
+	}
+
+	if (!(mdb->attrib & htons(HFS_SB_ATTRIB_CLEAN))) {
+		hfs_warn("hfs_fs: WARNING: mounting unclean filesystem.\n");
+	} else if (!readonly) {
+		/* 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);
+	}
+
+	return mdb;
+
+bail1:
+	hfs_mdb_put(mdb, readonly);
+bail2:
+	return NULL;
+}
+
+/*
+ * hfs_mdb_commit()
+ *
+ * Description:
+ *   This updates the MDB on disk (look also at hfs_write_super()).
+ *   It does not check, if the superblock has been modified, or
+ *   if the filesystem has been mounted read-only. It is mainly
+ *   called by hfs_write_super() and hfs_btree_extend().
+ * Input Variable(s):
+ *   struct hfs_mdb *mdb: Pointer to the hfs MDB
+ *   int backup;
+ * Output Variable(s):
+ *   NONE
+ * Returns:
+ *   void
+ * Preconditions:
+ *   'mdb' points to a "valid" (struct hfs_mdb).
+ * Postconditions:
+ *   The HFS MDB and on disk will be updated, by copying the possibly
+ *   modified fields from the in memory MDB (in native byte order) to
+ *   the disk block buffer.
+ *   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)
+{
+	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 */
+        if (backup && hfs_buffer_ok(mdb->alt_buf)) {
+                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);
+        }
+}
+
+/*
+ * 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);
+
+	/* 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);
+	}
+
+	/* 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);
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov