1 |
1275 |
phoenix |
/*
|
2 |
|
|
* linux/fs/hfs/mdb.c
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 1995-1997 Paul H. Hargrove
|
5 |
|
|
* This file may be distributed under the terms of the GNU General Public License.
|
6 |
|
|
*
|
7 |
|
|
* This file contains functions for reading/writing the MDB.
|
8 |
|
|
*
|
9 |
|
|
* "XXX" in a comment is a note to myself to consider changing something.
|
10 |
|
|
*
|
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.
|
14 |
|
|
*
|
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.
|
19 |
|
|
*/
|
20 |
|
|
|
21 |
|
|
#include "hfs.h"
|
22 |
|
|
|
23 |
|
|
/*================ File-local data types ================*/
|
24 |
|
|
|
25 |
|
|
/*
|
26 |
|
|
* The HFS Master Directory Block (MDB).
|
27 |
|
|
*
|
28 |
|
|
* Also known as the Volume Information Block (VIB), this structure is
|
29 |
|
|
* the HFS equivalent of a superblock.
|
30 |
|
|
*
|
31 |
|
|
* Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62
|
32 |
|
|
*
|
33 |
|
|
* modified for HFS Extended
|
34 |
|
|
*/
|
35 |
|
|
struct raw_mdb {
|
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
|
61 |
|
|
the root directory */
|
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
|
69 |
|
|
volume */
|
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 */
|
74 |
|
|
} __attribute__((packed));
|
75 |
|
|
|
76 |
|
|
/*================ Global functions ================*/
|
77 |
|
|
|
78 |
|
|
/*
|
79 |
|
|
* hfs_mdb_get()
|
80 |
|
|
*
|
81 |
|
|
* Build the in-core MDB for a filesystem, including
|
82 |
|
|
* the B-trees and the volume bitmap.
|
83 |
|
|
*/
|
84 |
|
|
struct hfs_mdb *hfs_mdb_get(hfs_sysmdb sys_mdb, int readonly,
|
85 |
|
|
hfs_s32 part_start)
|
86 |
|
|
{
|
87 |
|
|
struct hfs_mdb *mdb;
|
88 |
|
|
hfs_buffer buf;
|
89 |
|
|
struct raw_mdb *raw;
|
90 |
|
|
unsigned int bs, block;
|
91 |
|
|
int lcv, limit;
|
92 |
|
|
hfs_buffer *bmbuf;
|
93 |
|
|
|
94 |
|
|
if (!HFS_NEW(mdb)) {
|
95 |
|
|
hfs_warn("hfs_fs: out of memory\n");
|
96 |
|
|
return NULL;
|
97 |
|
|
}
|
98 |
|
|
|
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);
|
105 |
|
|
|
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");
|
110 |
|
|
HFS_DELETE(mdb);
|
111 |
|
|
goto bail2;
|
112 |
|
|
}
|
113 |
|
|
|
114 |
|
|
raw = (struct raw_mdb *)hfs_buffer_data(buf);
|
115 |
|
|
if (hfs_get_ns(raw->drSigWord) != htons(HFS_SUPER_MAGIC)) {
|
116 |
|
|
hfs_buffer_put(buf);
|
117 |
|
|
HFS_DELETE(mdb);
|
118 |
|
|
goto bail2;
|
119 |
|
|
}
|
120 |
|
|
mdb->buf = buf;
|
121 |
|
|
|
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);
|
125 |
|
|
hfs_buffer_put(buf);
|
126 |
|
|
HFS_DELETE(mdb);
|
127 |
|
|
goto bail2;
|
128 |
|
|
}
|
129 |
|
|
mdb->alloc_blksz = bs >> HFS_SECTOR_SIZE_BITS;
|
130 |
|
|
|
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));
|
139 |
|
|
|
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);
|
150 |
|
|
|
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);
|
159 |
|
|
|
160 |
|
|
if (hfs_get_ns(tmp->drSigWord) ==
|
161 |
|
|
htons(HFS_SUPER_MAGIC)) {
|
162 |
|
|
mdb->alt_buf = buf;
|
163 |
|
|
break;
|
164 |
|
|
}
|
165 |
|
|
}
|
166 |
|
|
hfs_buffer_put(buf);
|
167 |
|
|
}
|
168 |
|
|
|
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");
|
172 |
|
|
}
|
173 |
|
|
|
174 |
|
|
/* read in the bitmap */
|
175 |
|
|
block = hfs_get_hs(raw->drVBMSt) + part_start;
|
176 |
|
|
bmbuf = mdb->bitmap;
|
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");
|
182 |
|
|
goto bail1;
|
183 |
|
|
}
|
184 |
|
|
}
|
185 |
|
|
|
186 |
|
|
if (!(mdb->ext_tree = hfs_btree_init(mdb, htonl(HFS_EXT_CNID),
|
187 |
|
|
raw->drXTExtRec,
|
188 |
|
|
hfs_get_hl(raw->drXTFlSize),
|
189 |
|
|
hfs_get_hl(raw->drXTClpSiz))) ||
|
190 |
|
|
!(mdb->cat_tree = hfs_btree_init(mdb, htonl(HFS_CAT_CNID),
|
191 |
|
|
raw->drCTExtRec,
|
192 |
|
|
hfs_get_hl(raw->drCTFlSize),
|
193 |
|
|
hfs_get_hl(raw->drCTClpSiz)))) {
|
194 |
|
|
hfs_warn("hfs_fs: unable to initialize data structures\n");
|
195 |
|
|
goto bail1;
|
196 |
|
|
}
|
197 |
|
|
|
198 |
|
|
if (!(mdb->attrib & htons(HFS_SB_ATTRIB_CLEAN))) {
|
199 |
|
|
hfs_warn("hfs_fs: WARNING: mounting unclean filesystem.\n");
|
200 |
|
|
} else if (!readonly && !(mdb->attrib & (HFS_SB_ATTRIB_HLOCK | HFS_SB_ATTRIB_SLOCK))) {
|
201 |
|
|
/* Mark the volume uncleanly unmounted in case we crash */
|
202 |
|
|
hfs_put_ns(mdb->attrib & htons(~HFS_SB_ATTRIB_CLEAN),
|
203 |
|
|
raw->drAtrb);
|
204 |
|
|
hfs_buffer_dirty(mdb->buf);
|
205 |
|
|
hfs_buffer_sync(mdb->buf);
|
206 |
|
|
}
|
207 |
|
|
|
208 |
|
|
return mdb;
|
209 |
|
|
|
210 |
|
|
bail1:
|
211 |
|
|
hfs_mdb_put(mdb, readonly);
|
212 |
|
|
bail2:
|
213 |
|
|
return NULL;
|
214 |
|
|
}
|
215 |
|
|
|
216 |
|
|
/*
|
217 |
|
|
* hfs_mdb_commit()
|
218 |
|
|
*
|
219 |
|
|
* Description:
|
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().
|
224 |
|
|
* Input Variable(s):
|
225 |
|
|
* struct hfs_mdb *mdb: Pointer to the hfs MDB
|
226 |
|
|
* int backup;
|
227 |
|
|
* Output Variable(s):
|
228 |
|
|
* NONE
|
229 |
|
|
* Returns:
|
230 |
|
|
* void
|
231 |
|
|
* Preconditions:
|
232 |
|
|
* 'mdb' points to a "valid" (struct hfs_mdb).
|
233 |
|
|
* Postconditions:
|
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.
|
239 |
|
|
*/
|
240 |
|
|
void hfs_mdb_commit(struct hfs_mdb *mdb, int backup)
|
241 |
|
|
{
|
242 |
|
|
struct raw_mdb *raw = (struct raw_mdb *)hfs_buffer_data(mdb->buf);
|
243 |
|
|
|
244 |
|
|
/* Commit catalog entries to buffers */
|
245 |
|
|
hfs_cat_commit(mdb);
|
246 |
|
|
|
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);
|
250 |
|
|
|
251 |
|
|
/* Update write_count and modify_date */
|
252 |
|
|
++mdb->write_count;
|
253 |
|
|
mdb->modify_date = hfs_time();
|
254 |
|
|
|
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);
|
264 |
|
|
|
265 |
|
|
/* write MDB to disk */
|
266 |
|
|
hfs_buffer_dirty(mdb->buf);
|
267 |
|
|
|
268 |
|
|
/* write the backup MDB, not returning until it is written.
|
269 |
|
|
* we only do this when either the catalog or extents overflow
|
270 |
|
|
* files grow. */
|
271 |
|
|
if (backup && hfs_buffer_ok(mdb->alt_buf)) {
|
272 |
|
|
struct raw_mdb *tmp = (struct raw_mdb *)
|
273 |
|
|
hfs_buffer_data(mdb->alt_buf);
|
274 |
|
|
|
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);
|
283 |
|
|
}
|
284 |
|
|
}
|
285 |
|
|
}
|
286 |
|
|
|
287 |
|
|
/*
|
288 |
|
|
* hfs_mdb_put()
|
289 |
|
|
*
|
290 |
|
|
* Release the resources associated with the in-core MDB. */
|
291 |
|
|
void hfs_mdb_put(struct hfs_mdb *mdb, int readonly) {
|
292 |
|
|
int lcv;
|
293 |
|
|
|
294 |
|
|
/* invalidate cached catalog entries */
|
295 |
|
|
hfs_cat_invalidate(mdb);
|
296 |
|
|
|
297 |
|
|
/* free the B-trees */
|
298 |
|
|
hfs_btree_free(mdb->ext_tree);
|
299 |
|
|
hfs_btree_free(mdb->cat_tree);
|
300 |
|
|
|
301 |
|
|
/* free the volume bitmap */
|
302 |
|
|
for (lcv = 0; lcv < HFS_BM_MAXBLOCKS; ++lcv) {
|
303 |
|
|
hfs_buffer_put(mdb->bitmap[lcv]);
|
304 |
|
|
}
|
305 |
|
|
|
306 |
|
|
/* update volume attributes */
|
307 |
|
|
if (!readonly) {
|
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);
|
312 |
|
|
}
|
313 |
|
|
|
314 |
|
|
/* free the buffers holding the primary and alternate MDBs */
|
315 |
|
|
hfs_buffer_put(mdb->buf);
|
316 |
|
|
hfs_buffer_put(mdb->alt_buf);
|
317 |
|
|
|
318 |
|
|
/* free the MDB */
|
319 |
|
|
HFS_DELETE(mdb);
|
320 |
|
|
}
|