4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU Public License.
7 * This file contains functions for reading/writing the MDB.
9 * "XXX" in a comment is a note to myself to consider changing something.
11 * In function preconditions the term "valid" applied to a pointer to
12 * a structure means that the pointer is non-NULL and the structure it
13 * points to has all fields initialized to consistent values.
15 * The code in this file initializes some structures which contain
16 * pointers by calling memset(&foo, 0, sizeof(foo)).
17 * This produces the desired behavior only due to the non-ANSI
18 * assumption that the machine representation of NULL is all zeros.
23 /*================ File-local data types ================*/
26 * The HFS Master Directory Block (MDB).
28 * Also known as the Volume Information Block (VIB), this structure is
29 * the HFS equivalent of a superblock.
31 * Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62
33 * modified for HFS Extended
36 hfs_word_t drSigWord
; /* Signature word indicating fs type */
37 hfs_lword_t drCrDate
; /* fs creation date/time */
38 hfs_lword_t drLsMod
; /* fs modification date/time */
39 hfs_word_t drAtrb
; /* fs attributes */
40 hfs_word_t drNmFls
; /* number of files in root directory */
41 hfs_word_t drVBMSt
; /* location (in 512-byte blocks)
42 of the volume bitmap */
43 hfs_word_t drAllocPtr
; /* location (in allocation blocks)
44 to begin next allocation search */
45 hfs_word_t drNmAlBlks
; /* number of allocation blocks */
46 hfs_lword_t drAlBlkSiz
; /* bytes in an allocation block */
47 hfs_lword_t drClpSiz
; /* clumpsize, the number of bytes to
48 allocate when extending a file */
49 hfs_word_t drAlBlSt
; /* location (in 512-byte blocks)
50 of the first allocation block */
51 hfs_lword_t drNxtCNID
; /* CNID to assign to the next
52 file or directory created */
53 hfs_word_t drFreeBks
; /* number of free allocation blocks */
54 hfs_byte_t drVN
[28]; /* the volume label */
55 hfs_lword_t drVolBkUp
; /* fs backup date/time */
56 hfs_word_t drVSeqNum
; /* backup sequence number */
57 hfs_lword_t drWrCnt
; /* fs write count */
58 hfs_lword_t drXTClpSiz
; /* clumpsize for the extents B-tree */
59 hfs_lword_t drCTClpSiz
; /* clumpsize for the catalog B-tree */
60 hfs_word_t drNmRtDirs
; /* number of directories in
62 hfs_lword_t drFilCnt
; /* number of files in the fs */
63 hfs_lword_t drDirCnt
; /* number of directories in the fs */
64 hfs_byte_t drFndrInfo
[32]; /* data used by the Finder */
65 hfs_word_t drEmbedSigWord
; /* embedded volume signature */
66 hfs_lword_t drEmbedExtent
; /* starting block number (xdrStABN)
67 and number of allocation blocks
68 (xdrNumABlks) occupied by embedded
70 hfs_lword_t drXTFlSize
; /* bytes in the extents B-tree */
71 hfs_byte_t drXTExtRec
[12]; /* extents B-tree's first 3 extents */
72 hfs_lword_t drCTFlSize
; /* bytes in the catalog B-tree */
73 hfs_byte_t drCTExtRec
[12]; /* catalog B-tree's first 3 extents */
76 /*================ Global functions ================*/
81 * Build the in-core MDB for a filesystem, including
82 * the B-trees and the volume bitmap.
84 struct hfs_mdb
*hfs_mdb_get(hfs_sysmdb sys_mdb
, int readonly
,
90 unsigned int bs
, block
;
95 hfs_warn("hfs_fs: out of memory\n");
99 memset(mdb
, 0, sizeof(*mdb
));
100 mdb
->magic
= HFS_MDB_MAGIC
;
101 mdb
->sys_mdb
= sys_mdb
;
102 INIT_LIST_HEAD(&mdb
->entry_dirty
);
103 hfs_init_waitqueue(&mdb
->rename_wait
);
104 hfs_init_waitqueue(&mdb
->bitmap_wait
);
106 /* See if this is an HFS filesystem */
107 buf
= hfs_buffer_get(sys_mdb
, part_start
+ HFS_MDB_BLK
, 1);
108 if (!hfs_buffer_ok(buf
)) {
109 hfs_warn("hfs_fs: Unable to read superblock\n");
114 raw
= (struct raw_mdb
*)hfs_buffer_data(buf
);
115 if (hfs_get_ns(raw
->drSigWord
) != htons(HFS_SUPER_MAGIC
)) {
122 bs
= hfs_get_hl(raw
->drAlBlkSiz
);
123 if (!bs
|| (bs
& (HFS_SECTOR_SIZE
-1))) {
124 hfs_warn("hfs_fs: bad allocation block size %d != 512\n", bs
);
129 mdb
->alloc_blksz
= bs
>> HFS_SECTOR_SIZE_BITS
;
131 /* These parameters are read from the MDB, and never written */
132 mdb
->create_date
= hfs_get_hl(raw
->drCrDate
);
133 mdb
->fs_ablocks
= hfs_get_hs(raw
->drNmAlBlks
);
134 mdb
->fs_start
= hfs_get_hs(raw
->drAlBlSt
) + part_start
;
135 mdb
->backup_date
= hfs_get_hl(raw
->drVolBkUp
);
136 mdb
->clumpablks
= (hfs_get_hl(raw
->drClpSiz
) / mdb
->alloc_blksz
)
137 >> HFS_SECTOR_SIZE_BITS
;
138 memcpy(mdb
->vname
, raw
->drVN
, sizeof(raw
->drVN
));
140 /* These parameters are read from and written to the MDB */
141 mdb
->modify_date
= hfs_get_nl(raw
->drLsMod
);
142 mdb
->attrib
= hfs_get_ns(raw
->drAtrb
);
143 mdb
->free_ablocks
= hfs_get_hs(raw
->drFreeBks
);
144 mdb
->next_id
= hfs_get_hl(raw
->drNxtCNID
);
145 mdb
->write_count
= hfs_get_hl(raw
->drWrCnt
);
146 mdb
->root_files
= hfs_get_hs(raw
->drNmFls
);
147 mdb
->root_dirs
= hfs_get_hs(raw
->drNmRtDirs
);
148 mdb
->file_count
= hfs_get_hl(raw
->drFilCnt
);
149 mdb
->dir_count
= hfs_get_hl(raw
->drDirCnt
);
151 /* TRY to get the alternate (backup) MDB. */
152 lcv
= mdb
->fs_start
+ mdb
->fs_ablocks
* mdb
->alloc_blksz
;
153 limit
= lcv
+ mdb
->alloc_blksz
;
154 for (; lcv
< limit
; ++lcv
) {
155 buf
= hfs_buffer_get(sys_mdb
, lcv
, 1);
156 if (hfs_buffer_ok(buf
)) {
157 struct raw_mdb
*tmp
=
158 (struct raw_mdb
*)hfs_buffer_data(buf
);
160 if (hfs_get_ns(tmp
->drSigWord
) ==
161 htons(HFS_SUPER_MAGIC
)) {
169 if (mdb
->alt_buf
== NULL
) {
170 hfs_warn("hfs_fs: unable to locate alternate MDB\n");
171 hfs_warn("hfs_fs: continuing without an alternate MDB\n");
174 /* read in the bitmap */
175 block
= hfs_get_hs(raw
->drVBMSt
) + part_start
;
177 lcv
= (mdb
->fs_ablocks
+ 4095) / 4096;
178 for ( ; lcv
; --lcv
, ++bmbuf
, ++block
) {
179 if (!hfs_buffer_ok(*bmbuf
=
180 hfs_buffer_get(sys_mdb
, block
, 1))) {
181 hfs_warn("hfs_fs: unable to read volume bitmap\n");
186 if (!(mdb
->ext_tree
= hfs_btree_init(mdb
, htonl(HFS_EXT_CNID
),
188 hfs_get_hl(raw
->drXTFlSize
),
189 hfs_get_hl(raw
->drXTClpSiz
))) ||
190 !(mdb
->cat_tree
= hfs_btree_init(mdb
, htonl(HFS_CAT_CNID
),
192 hfs_get_hl(raw
->drCTFlSize
),
193 hfs_get_hl(raw
->drCTClpSiz
)))) {
194 hfs_warn("hfs_fs: unable to initialize data structures\n");
198 if (!(mdb
->attrib
& htons(HFS_SB_ATTRIB_CLEAN
))) {
199 hfs_warn("hfs_fs: WARNING: mounting unclean filesystem.\n");
200 } else if (!readonly
) {
201 /* Mark the volume uncleanly unmounted in case we crash */
202 hfs_put_ns(mdb
->attrib
& htons(~HFS_SB_ATTRIB_CLEAN
),
204 hfs_buffer_dirty(mdb
->buf
);
205 hfs_buffer_sync(mdb
->buf
);
211 hfs_mdb_put(mdb
, readonly
);
220 * This updates the MDB on disk (look also at hfs_write_super()).
221 * It does not check, if the superblock has been modified, or
222 * if the filesystem has been mounted read-only. It is mainly
223 * called by hfs_write_super() and hfs_btree_extend().
225 * struct hfs_mdb *mdb: Pointer to the hfs MDB
227 * Output Variable(s):
232 * 'mdb' points to a "valid" (struct hfs_mdb).
234 * The HFS MDB and on disk will be updated, by copying the possibly
235 * modified fields from the in memory MDB (in native byte order) to
236 * the disk block buffer.
237 * If 'backup' is non-zero then the alternate MDB is also written
238 * and the function doesn't return until it is actually on disk.
240 void hfs_mdb_commit(struct hfs_mdb
*mdb
, int backup
)
242 struct raw_mdb
*raw
= (struct raw_mdb
*)hfs_buffer_data(mdb
->buf
);
244 /* Commit catalog entries to buffers */
247 /* Commit B-tree data to buffers */
248 hfs_btree_commit(mdb
->cat_tree
, raw
->drCTExtRec
, raw
->drCTFlSize
);
249 hfs_btree_commit(mdb
->ext_tree
, raw
->drXTExtRec
, raw
->drXTFlSize
);
251 /* Update write_count and modify_date */
253 mdb
->modify_date
= hfs_time();
255 /* These parameters may have been modified, so write them back */
256 hfs_put_nl(mdb
->modify_date
, raw
->drLsMod
);
257 hfs_put_hs(mdb
->free_ablocks
, raw
->drFreeBks
);
258 hfs_put_hl(mdb
->next_id
, raw
->drNxtCNID
);
259 hfs_put_hl(mdb
->write_count
, raw
->drWrCnt
);
260 hfs_put_hs(mdb
->root_files
, raw
->drNmFls
);
261 hfs_put_hs(mdb
->root_dirs
, raw
->drNmRtDirs
);
262 hfs_put_hl(mdb
->file_count
, raw
->drFilCnt
);
263 hfs_put_hl(mdb
->dir_count
, raw
->drDirCnt
);
265 /* write MDB to disk */
266 hfs_buffer_dirty(mdb
->buf
);
268 /* write the backup MDB, not returning until it is written.
269 * we only do this when either the catalog or extents overflow
271 if (backup
&& hfs_buffer_ok(mdb
->alt_buf
)) {
272 struct raw_mdb
*tmp
= (struct raw_mdb
*)
273 hfs_buffer_data(mdb
->alt_buf
);
275 if ((hfs_get_hl(tmp
->drCTFlSize
) <
276 hfs_get_hl(raw
->drCTFlSize
)) ||
277 (hfs_get_hl(tmp
->drXTFlSize
) <
278 hfs_get_hl(raw
->drXTFlSize
))) {
279 memcpy(hfs_buffer_data(mdb
->alt_buf
),
280 hfs_buffer_data(mdb
->buf
), HFS_SECTOR_SIZE
);
281 hfs_buffer_dirty(mdb
->alt_buf
);
282 hfs_buffer_sync(mdb
->alt_buf
);
290 * Release the resources associated with the in-core MDB. */
291 void hfs_mdb_put(struct hfs_mdb
*mdb
, int readonly
) {
294 /* invalidate cached catalog entries */
295 hfs_cat_invalidate(mdb
);
297 /* free the B-trees */
298 hfs_btree_free(mdb
->ext_tree
);
299 hfs_btree_free(mdb
->cat_tree
);
301 /* free the volume bitmap */
302 for (lcv
= 0; lcv
< HFS_BM_MAXBLOCKS
; ++lcv
) {
303 hfs_buffer_put(mdb
->bitmap
[lcv
]);
306 /* update volume attributes */
308 struct raw_mdb
*raw
=
309 (struct raw_mdb
*)hfs_buffer_data(mdb
->buf
);
310 hfs_put_ns(mdb
->attrib
, raw
->drAtrb
);
311 hfs_buffer_dirty(mdb
->buf
);
314 /* free the buffers holding the primary and alternate MDBs */
315 hfs_buffer_put(mdb
->buf
);
316 hfs_buffer_put(mdb
->alt_buf
);