1 |
dpavlin |
1 |
/* |
2 |
|
|
* libhfs - library for reading and writing Macintosh HFS volumes |
3 |
|
|
* Copyright (C) 1996-1998 Robert Leslie |
4 |
|
|
* |
5 |
|
|
* This program is free software; you can redistribute it and/or modify |
6 |
|
|
* it under the terms of the GNU General Public License as published by |
7 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
8 |
|
|
* (at your option) any later version. |
9 |
|
|
* |
10 |
|
|
* This program is distributed in the hope that it will be useful, |
11 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
|
|
* GNU General Public License for more details. |
14 |
|
|
* |
15 |
|
|
* You should have received a copy of the GNU General Public License |
16 |
|
|
* along with this program; if not, write to the Free Software |
17 |
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
18 |
|
|
* |
19 |
|
|
*/ |
20 |
|
|
|
21 |
|
|
# include "hfs.h" |
22 |
|
|
# include "apple.h" |
23 |
|
|
|
24 |
|
|
extern int errno; |
25 |
|
|
|
26 |
|
|
# define ERROR(code, str) \ |
27 |
|
|
do { hfs_error = (str), errno = (code); goto fail; } while (0) |
28 |
|
|
|
29 |
|
|
#include "tools/debug.h" |
30 |
|
|
#if 0 |
31 |
|
|
# ifdef DEBUG |
32 |
|
|
# define ASSERT(cond) do { if (! (cond)) abort(); } while (0) |
33 |
|
|
# else |
34 |
|
|
# define ASSERT(cond) /* nothing */ |
35 |
|
|
# endif |
36 |
|
|
# endif |
37 |
|
|
|
38 |
|
|
|
39 |
|
|
# define SIZE(type, n) ((size_t) (sizeof(type) * (n))) |
40 |
|
|
# define ALLOC(type, n) ((type *) malloc(SIZE(type, n))) |
41 |
|
|
# define ALLOCX(type, n) ((n) ? ALLOC(type, n) : (type *) 0) |
42 |
|
|
# define FREE(ptr) ((ptr) ? (void) free((void *) ptr) : (void) 0) |
43 |
|
|
|
44 |
|
|
# define REALLOC(ptr, type, n) \ |
45 |
|
|
((type *) ((ptr) ? realloc(ptr, SIZE(type, n)) : malloc(SIZE(type, n)))) |
46 |
|
|
# define REALLOCX(ptr, type, n) \ |
47 |
|
|
((n) ? REALLOC(ptr, type, n) : (FREE(ptr), (type *) 0)) |
48 |
|
|
|
49 |
|
|
# define BMTST(bm, num) \ |
50 |
|
|
(((const byte *) (bm))[(num) >> 3] & (0x80 >> ((num) & 0x07))) |
51 |
|
|
# define BMSET(bm, num) \ |
52 |
|
|
(((byte *) (bm))[(num) >> 3] |= (0x80 >> ((num) & 0x07))) |
53 |
|
|
# define BMCLR(bm, num) \ |
54 |
|
|
(((byte *) (bm))[(num) >> 3] &= ~(0x80 >> ((num) & 0x07))) |
55 |
|
|
|
56 |
|
|
# define STRINGIZE(x) #x |
57 |
|
|
# define STR(x) STRINGIZE(x) |
58 |
|
|
|
59 |
|
|
typedef byte block[HFS_BLOCKSZ]; |
60 |
|
|
|
61 |
|
|
typedef struct _bucket_ { |
62 |
|
|
int flags; /* bit flags */ |
63 |
|
|
unsigned int count; /* number of times this block is requested */ |
64 |
|
|
|
65 |
|
|
unsigned long bnum; /* logical block number */ |
66 |
|
|
block *data; /* pointer to block contents */ |
67 |
|
|
|
68 |
|
|
struct _bucket_ *cnext; /* next bucket in cache chain */ |
69 |
|
|
struct _bucket_ *cprev; /* previous bucket in cache chain */ |
70 |
|
|
|
71 |
|
|
struct _bucket_ *hnext; /* next bucket in hash chain */ |
72 |
|
|
struct _bucket_ **hprev; /* previous bucket's pointer to this bucket */ |
73 |
|
|
} bucket; |
74 |
|
|
|
75 |
|
|
# define HFS_BUCKET_INUSE 0x01 |
76 |
|
|
# define HFS_BUCKET_DIRTY 0x02 |
77 |
|
|
|
78 |
|
|
# define HFS_CACHESZ 128 |
79 |
|
|
# define HFS_HASHSZ 32 |
80 |
|
|
# define HFS_BLOCKBUFSZ 16 |
81 |
|
|
|
82 |
|
|
typedef struct { |
83 |
|
|
struct _hfsvol_ *vol; /* volume to which cache belongs */ |
84 |
|
|
bucket *tail; /* end of bucket chain */ |
85 |
|
|
|
86 |
|
|
unsigned int hits; /* number of cache hits */ |
87 |
|
|
unsigned int misses; /* number of cache misses */ |
88 |
|
|
|
89 |
|
|
bucket chain[HFS_CACHESZ]; /* cache bucket chain */ |
90 |
|
|
bucket *hash[HFS_HASHSZ]; /* hash table for bucket chain */ |
91 |
|
|
|
92 |
|
|
block pool[HFS_CACHESZ]; /* physical blocks in cache */ |
93 |
|
|
} bcache; |
94 |
|
|
|
95 |
|
|
# define HFS_MAP1SZ 256 |
96 |
|
|
# define HFS_MAPXSZ 492 |
97 |
|
|
|
98 |
|
|
# define HFS_NODEREC(nd, rnum) ((nd).data + (nd).roff[rnum]) |
99 |
|
|
# define HFS_RECLEN(nd, rnum) ((nd).roff[(rnum) + 1] - (nd).roff[rnum]) |
100 |
|
|
|
101 |
|
|
# define HFS_RECKEYLEN(ptr) (*(const byte *) (ptr)) |
102 |
|
|
# define HFS_RECKEYSKIP(ptr) ((size_t) ((1 + HFS_RECKEYLEN(ptr) + 1) & ~1)) |
103 |
|
|
# define HFS_RECDATA(ptr) ((ptr) + HFS_RECKEYSKIP(ptr)) |
104 |
|
|
|
105 |
|
|
# define HFS_SETKEYLEN(ptr, x) (*(byte *) (ptr) = (x)) |
106 |
|
|
|
107 |
|
|
# define HFS_CATDATALEN sizeof(CatDataRec) |
108 |
|
|
# define HFS_EXTDATALEN sizeof(ExtDataRec) |
109 |
|
|
# define HFS_MAX_DATALEN (HFS_CATDATALEN > HFS_EXTDATALEN ? \ |
110 |
|
|
HFS_CATDATALEN : HFS_EXTDATALEN) |
111 |
|
|
|
112 |
|
|
# define HFS_CATKEYLEN sizeof(CatKeyRec) |
113 |
|
|
# define HFS_EXTKEYLEN sizeof(ExtKeyRec) |
114 |
|
|
# define HFS_MAX_KEYLEN (HFS_CATKEYLEN > HFS_EXTKEYLEN ? \ |
115 |
|
|
HFS_CATKEYLEN : HFS_EXTKEYLEN) |
116 |
|
|
|
117 |
|
|
# define HFS_MAX_CATRECLEN (HFS_CATKEYLEN + HFS_CATDATALEN) |
118 |
|
|
# define HFS_MAX_EXTRECLEN (HFS_EXTKEYLEN + HFS_EXTDATALEN) |
119 |
|
|
# define HFS_MAX_RECLEN (HFS_MAX_KEYLEN + HFS_MAX_DATALEN) |
120 |
|
|
|
121 |
|
|
# define HFS_SIGWORD 0x4244 |
122 |
|
|
# define HFS_SIGWORD_MFS ((APPLEInteger) 0xd2d7) |
123 |
|
|
|
124 |
|
|
# define HFS_ATRB_BUSY (1 << 6) |
125 |
|
|
# define HFS_ATRB_HLOCKED (1 << 7) |
126 |
|
|
# define HFS_ATRB_UMOUNTED (1 << 8) |
127 |
|
|
# define HFS_ATRB_BBSPARED (1 << 9) |
128 |
|
|
# define HFS_ATRB_BVINCONSIS (1 << 11) |
129 |
|
|
# define HFS_ATRB_COPYPROT (1 << 14) |
130 |
|
|
# define HFS_ATRB_SLOCKED (1 << 15) |
131 |
|
|
|
132 |
|
|
struct _hfsfile_ { |
133 |
|
|
struct _hfsvol_ *vol; /* pointer to volume descriptor */ |
134 |
|
|
unsigned long parid; /* parent directory ID of this file */ |
135 |
|
|
char name[HFS_MAX_FLEN + 1]; /* catalog name of this file */ |
136 |
|
|
CatDataRec cat; /* catalog information */ |
137 |
|
|
ExtDataRec ext; /* current extent record */ |
138 |
|
|
unsigned int fabn; /* starting file allocation block number */ |
139 |
|
|
int fork; /* current selected fork for I/O */ |
140 |
|
|
unsigned long pos; /* current file seek pointer */ |
141 |
|
|
int flags; /* bit flags */ |
142 |
|
|
|
143 |
|
|
struct _hfsfile_ *prev; |
144 |
|
|
struct _hfsfile_ *next; |
145 |
|
|
}; |
146 |
|
|
|
147 |
|
|
# define HFS_FILE_UPDATE_CATREC 0x01 |
148 |
|
|
|
149 |
|
|
# define HFS_MAX_NRECS 35 /* maximum based on minimum record size */ |
150 |
|
|
|
151 |
|
|
typedef struct _node_ { |
152 |
|
|
struct _btree_ *bt; /* btree to which this node belongs */ |
153 |
|
|
unsigned long nnum; /* node index */ |
154 |
|
|
NodeDescriptor nd; /* node descriptor */ |
155 |
|
|
int rnum; /* current record index */ |
156 |
|
|
UInteger roff[HFS_MAX_NRECS + 1]; |
157 |
|
|
/* record offsets */ |
158 |
|
|
block data; /* raw contents of node */ |
159 |
|
|
} node; |
160 |
|
|
|
161 |
|
|
struct _hfsdir_ { |
162 |
|
|
struct _hfsvol_ *vol; /* associated volume */ |
163 |
|
|
unsigned long dirid; /* directory ID of interest (or 0) */ |
164 |
|
|
|
165 |
|
|
node n; /* current B*-tree node */ |
166 |
|
|
struct _hfsvol_ *vptr; /* current volume pointer */ |
167 |
|
|
|
168 |
|
|
struct _hfsdir_ *prev; |
169 |
|
|
struct _hfsdir_ *next; |
170 |
|
|
}; |
171 |
|
|
|
172 |
|
|
typedef void (*keyunpackfunc)(const byte *, void *); |
173 |
|
|
typedef int (*keycomparefunc)(const void *, const void *); |
174 |
|
|
|
175 |
|
|
typedef struct _btree_ { |
176 |
|
|
hfsfile f; /* subset file information */ |
177 |
|
|
node hdrnd; /* header node */ |
178 |
|
|
BTHdrRec hdr; /* header record */ |
179 |
|
|
byte *map; /* usage bitmap */ |
180 |
|
|
unsigned long mapsz; /* number of bytes in bitmap */ |
181 |
|
|
int flags; /* bit flags */ |
182 |
|
|
|
183 |
|
|
keyunpackfunc keyunpack; /* key unpacking function */ |
184 |
|
|
keycomparefunc keycompare; /* key comparison function */ |
185 |
|
|
} btree; |
186 |
|
|
|
187 |
|
|
# define HFS_BT_UPDATE_HDR 0x01 |
188 |
|
|
|
189 |
|
|
struct _hfsvol_ { |
190 |
|
|
void *priv; /* OS-dependent private descriptor data */ |
191 |
|
|
int flags; /* bit flags */ |
192 |
|
|
|
193 |
|
|
int pnum; /* ordinal HFS partition number */ |
194 |
|
|
unsigned long vstart; /* logical block offset to start of volume */ |
195 |
|
|
unsigned long vlen; /* number of logical blocks in volume */ |
196 |
|
|
unsigned int lpa; /* number of logical blocks per allocation block */ |
197 |
|
|
|
198 |
|
|
bcache *cache; /* cache of recently used blocks */ |
199 |
|
|
|
200 |
|
|
MDB mdb; /* master directory block */ |
201 |
|
|
block *vbm; /* volume bitmap */ |
202 |
|
|
unsigned short vbmsz; /* number of blocks in bitmap */ |
203 |
|
|
|
204 |
|
|
btree ext; /* B*-tree control block for extents overflow file */ |
205 |
|
|
btree cat; /* B*-tree control block for catalog file */ |
206 |
|
|
|
207 |
|
|
unsigned long cwd; /* directory id of current working directory */ |
208 |
|
|
|
209 |
|
|
int refs; /* number of external references to this volume */ |
210 |
|
|
hfsfile *files; /* list of open files */ |
211 |
|
|
hfsdir *dirs; /* list of open directories */ |
212 |
|
|
|
213 |
|
|
struct _hfsvol_ *prev; |
214 |
|
|
struct _hfsvol_ *next; |
215 |
|
|
}; |
216 |
|
|
|
217 |
|
|
# define HFS_VOL_OPEN 0x0001 |
218 |
|
|
# define HFS_VOL_MOUNTED 0x0002 |
219 |
|
|
# define HFS_VOL_READONLY 0x0004 |
220 |
|
|
# define HFS_VOL_USINGCACHE 0x0008 |
221 |
|
|
|
222 |
|
|
# define HFS_VOL_UPDATE_MDB 0x0010 |
223 |
|
|
# define HFS_VOL_UPDATE_ALTMDB 0x0020 |
224 |
|
|
# define HFS_VOL_UPDATE_VBM 0x0040 |
225 |
|
|
|
226 |
|
|
# define HFS_VOL_OPT_MASK 0xff00 |
227 |
|
|
|
228 |
|
|
extern hfsvol *hfs_mounts; |