1 /*
2  * hfsutils - tools for reading and writing Macintosh HFS volumes
3  * Copyright (C) 1996, 1997 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 # include <string.h>
21 # include <errno.h>
22 # include <stdlib.h>
23 
24 # include "internal.h"
25 # include "data.h"
26 # include "record.h"
27 
28 /*
29  * NAME:	record->packcatkey()
30  * DESCRIPTION:	pack a catalog record key
31  */
32 void r_packcatkey(CatKeyRec *key, unsigned char *pkey, int *len)
33 {
34   unsigned char *start = pkey;
35 
36   d_storeb(&pkey, key->ckrKeyLen);
37   d_storeb(&pkey, key->ckrResrv1);
38   d_storel(&pkey, key->ckrParID);
39   d_stores(&pkey, key->ckrCName, sizeof(key->ckrCName));
40 
41   if (len)
42     *len = HFS_RECKEYSKIP(start);
43 }
44 
45 /*
46  * NAME:	record->unpackcatkey()
47  * DESCRIPTION:	unpack a catalog record key
48  */
49 void r_unpackcatkey(unsigned char *pkey, CatKeyRec *key)
50 {
51   d_fetchb(&pkey, (char *) &key->ckrKeyLen);
52   d_fetchb(&pkey, (char *) &key->ckrResrv1);
53   d_fetchl(&pkey, (long *) &key->ckrParID);
54   d_fetchs(&pkey, key->ckrCName, sizeof(key->ckrCName));
55 }
56 
57 /*
58  * NAME:	record->packextkey()
59  * DESCRIPTION:	pack an extents record key
60  */
61 void r_packextkey(ExtKeyRec *key, unsigned char *pkey, int *len)
62 {
63   unsigned char *start = pkey;
64 
65   d_storeb(&pkey, key->xkrKeyLen);
66   d_storeb(&pkey, key->xkrFkType);
67   d_storel(&pkey, key->xkrFNum);
68   d_storew(&pkey, key->xkrFABN);
69 
70   if (len)
71     *len = HFS_RECKEYSKIP(start);
72 }
73 
74 /*
75  * NAME:	record->unpackextkey()
76  * DESCRIPTION:	unpack an extents record key
77  */
78 void r_unpackextkey(unsigned char *pkey, ExtKeyRec *key)
79 {
80   d_fetchb(&pkey, (char *) &key->xkrKeyLen);
81   d_fetchb(&pkey, (char *) &key->xkrFkType);
82   d_fetchl(&pkey, (long *) &key->xkrFNum);
83   d_fetchw(&pkey, (short *) &key->xkrFABN);
84 }
85 
86 /*
87  * NAME:	record->comparecatkeys()
88  * DESCRIPTION:	compare two (packed) catalog record keys
89  */
90 int r_comparecatkeys(unsigned char *pkey1, unsigned char *pkey2)
91 {
92   CatKeyRec key1;
93   CatKeyRec key2;
94   int diff;
95 
96   r_unpackcatkey(pkey1, &key1);
97   r_unpackcatkey(pkey2, &key2);
98 
99   diff = key1.ckrParID - key2.ckrParID;
100   if (diff)
101     return diff;
102 
103   return d_relstring(key1.ckrCName, key2.ckrCName);
104 }
105 
106 /*
107  * NAME:	record->compareextkeys()
108  * DESCRIPTION:	compare two (packed) extents record keys
109  */
110 int r_compareextkeys(unsigned char *pkey1, unsigned char *pkey2)
111 {
112   ExtKeyRec key1;
113   ExtKeyRec key2;
114   int diff;
115 
116   r_unpackextkey(pkey1, &key1);
117   r_unpackextkey(pkey2, &key2);
118 
119   diff = key1.xkrFNum - key2.xkrFNum;
120   if (diff)
121     return diff;
122 
123   diff = (unsigned char) key1.xkrFkType -
124          (unsigned char) key2.xkrFkType;
125   if (diff)
126     return diff;
127 
128   return key1.xkrFABN - key2.xkrFABN;
129 }
130 
131 /*
132  * NAME:	record->packcatdata()
133  * DESCRIPTION:	pack catalog record data
134  */
135 void r_packcatdata(CatDataRec *data, unsigned char *pdata, int *len)
136 {
137   unsigned char *start = pdata;
138   int i;
139 
140   d_storeb(&pdata, data->cdrType);
141   d_storeb(&pdata, data->cdrResrv2);
142 
143   switch (data->cdrType)
144     {
145     case cdrDirRec:
146       d_storew(&pdata, data->u.dir.dirFlags);
147       d_storew(&pdata, data->u.dir.dirVal);
148       d_storel(&pdata, data->u.dir.dirDirID);
149       d_storel(&pdata, data->u.dir.dirCrDat);
150       d_storel(&pdata, data->u.dir.dirMdDat);
151       d_storel(&pdata, data->u.dir.dirBkDat);
152 
153       d_storew(&pdata, data->u.dir.dirUsrInfo.frRect.top);
154       d_storew(&pdata, data->u.dir.dirUsrInfo.frRect.left);
155       d_storew(&pdata, data->u.dir.dirUsrInfo.frRect.bottom);
156       d_storew(&pdata, data->u.dir.dirUsrInfo.frRect.right);
157       d_storew(&pdata, data->u.dir.dirUsrInfo.frFlags);
158       d_storew(&pdata, data->u.dir.dirUsrInfo.frLocation.v);
159       d_storew(&pdata, data->u.dir.dirUsrInfo.frLocation.h);
160       d_storew(&pdata, data->u.dir.dirUsrInfo.frView);
161 
162       d_storew(&pdata, data->u.dir.dirFndrInfo.frScroll.v);
163       d_storew(&pdata, data->u.dir.dirFndrInfo.frScroll.h);
164       d_storel(&pdata, data->u.dir.dirFndrInfo.frOpenChain);
165       d_storew(&pdata, data->u.dir.dirFndrInfo.frUnused);
166       d_storew(&pdata, data->u.dir.dirFndrInfo.frComment);
167       d_storel(&pdata, data->u.dir.dirFndrInfo.frPutAway);
168 
169       for (i = 0; i < 4; ++i)
170 	d_storel(&pdata, data->u.dir.dirResrv[i]);
171 
172       break;
173 
174     case cdrFilRec:
175       d_storeb(&pdata, data->u.fil.filFlags);
176       d_storeb(&pdata, data->u.fil.filTyp);
177 
178       d_storel(&pdata, data->u.fil.filUsrWds.fdType);
179       d_storel(&pdata, data->u.fil.filUsrWds.fdCreator);
180       d_storew(&pdata, data->u.fil.filUsrWds.fdFlags);
181       d_storew(&pdata, data->u.fil.filUsrWds.fdLocation.v);
182       d_storew(&pdata, data->u.fil.filUsrWds.fdLocation.h);
183       d_storew(&pdata, data->u.fil.filUsrWds.fdFldr);
184 
185       d_storel(&pdata, data->u.fil.filFlNum);
186 
187       d_storew(&pdata, data->u.fil.filStBlk);
188       d_storel(&pdata, data->u.fil.filLgLen);
189       d_storel(&pdata, data->u.fil.filPyLen);
190 
191       d_storew(&pdata, data->u.fil.filRStBlk);
192       d_storel(&pdata, data->u.fil.filRLgLen);
193       d_storel(&pdata, data->u.fil.filRPyLen);
194 
195       d_storel(&pdata, data->u.fil.filCrDat);
196       d_storel(&pdata, data->u.fil.filMdDat);
197       d_storel(&pdata, data->u.fil.filBkDat);
198 
199       d_storew(&pdata, data->u.fil.filFndrInfo.fdIconID);
200       for (i = 0; i < 4; ++i)
201 	d_storew(&pdata, data->u.fil.filFndrInfo.fdUnused[i]);
202       d_storew(&pdata, data->u.fil.filFndrInfo.fdComment);
203       d_storel(&pdata, data->u.fil.filFndrInfo.fdPutAway);
204 
205       d_storew(&pdata, data->u.fil.filClpSize);
206 
207       for (i = 0; i < 3; ++i)
208 	{
209 	  d_storew(&pdata, data->u.fil.filExtRec[i].xdrStABN);
210 	  d_storew(&pdata, data->u.fil.filExtRec[i].xdrNumABlks);
211 	}
212 
213       for (i = 0; i < 3; ++i)
214 	{
215 	  d_storew(&pdata, data->u.fil.filRExtRec[i].xdrStABN);
216 	  d_storew(&pdata, data->u.fil.filRExtRec[i].xdrNumABlks);
217 	}
218 
219       d_storel(&pdata, data->u.fil.filResrv);
220       break;
221 
222     case cdrThdRec:
223       for (i = 0; i < 2; ++i)
224 	d_storel(&pdata, data->u.dthd.thdResrv[i]);
225 
226       d_storel(&pdata, data->u.dthd.thdParID);
227       d_stores(&pdata, data->u.dthd.thdCName, sizeof(data->u.dthd.thdCName));
228       break;
229 
230     case cdrFThdRec:
231       for (i = 0; i < 2; ++i)
232 	d_storel(&pdata, data->u.fthd.fthdResrv[i]);
233 
234       d_storel(&pdata, data->u.fthd.fthdParID);
235       d_stores(&pdata, data->u.fthd.fthdCName, sizeof(data->u.fthd.fthdCName));
236       break;
237 
238     default:
239       abort();
240     }
241 
242   if (len)
243     *len += pdata - start;
244 }
245 
246 /*
247  * NAME:	record->unpackcatdata()
248  * DESCRIPTION:	unpack catalog record data
249  */
250 void r_unpackcatdata(unsigned char *pdata, CatDataRec *data)
251 {
252   int i;
253 
254   d_fetchb(&pdata, (char *) &data->cdrType);
255   d_fetchb(&pdata, (char *) &data->cdrResrv2);
256 
257   switch (data->cdrType)
258     {
259     case cdrDirRec:
260       d_fetchw(&pdata, &data->u.dir.dirFlags);
261       d_fetchw(&pdata, (short *) &data->u.dir.dirVal);
262       d_fetchl(&pdata, (long *) &data->u.dir.dirDirID);
263       d_fetchl(&pdata, &data->u.dir.dirCrDat);
264       d_fetchl(&pdata, &data->u.dir.dirMdDat);
265       d_fetchl(&pdata, &data->u.dir.dirBkDat);
266 
267       d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frRect.top);
268       d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frRect.left);
269       d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frRect.bottom);
270       d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frRect.right);
271       d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frFlags);
272       d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frLocation.v);
273       d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frLocation.h);
274       d_fetchw(&pdata, &data->u.dir.dirUsrInfo.frView);
275 
276       d_fetchw(&pdata, &data->u.dir.dirFndrInfo.frScroll.v);
277       d_fetchw(&pdata, &data->u.dir.dirFndrInfo.frScroll.h);
278       d_fetchl(&pdata, &data->u.dir.dirFndrInfo.frOpenChain);
279       d_fetchw(&pdata, &data->u.dir.dirFndrInfo.frUnused);
280       d_fetchw(&pdata, &data->u.dir.dirFndrInfo.frComment);
281       d_fetchl(&pdata, &data->u.dir.dirFndrInfo.frPutAway);
282 
283       for (i = 0; i < 4; ++i)
284 	d_fetchl(&pdata, &data->u.dir.dirResrv[i]);
285 
286       break;
287 
288     case cdrFilRec:
289       d_fetchb(&pdata, (char *) &data->u.fil.filFlags);
290       d_fetchb(&pdata, (char *) &data->u.fil.filTyp);
291 
292       d_fetchl(&pdata, &data->u.fil.filUsrWds.fdType);
293       d_fetchl(&pdata, &data->u.fil.filUsrWds.fdCreator);
294       d_fetchw(&pdata, &data->u.fil.filUsrWds.fdFlags);
295       d_fetchw(&pdata, &data->u.fil.filUsrWds.fdLocation.v);
296       d_fetchw(&pdata, &data->u.fil.filUsrWds.fdLocation.h);
297       d_fetchw(&pdata, &data->u.fil.filUsrWds.fdFldr);
298 
299       d_fetchl(&pdata, (long *) &data->u.fil.filFlNum);
300 
301       d_fetchw(&pdata, (short *) &data->u.fil.filStBlk);
302       d_fetchl(&pdata, (long *) &data->u.fil.filLgLen);
303       d_fetchl(&pdata, (long *) &data->u.fil.filPyLen);
304 
305       d_fetchw(&pdata, (short *) &data->u.fil.filRStBlk);
306       d_fetchl(&pdata, (long *) &data->u.fil.filRLgLen);
307       d_fetchl(&pdata, (long *) &data->u.fil.filRPyLen);
308 
309       d_fetchl(&pdata, &data->u.fil.filCrDat);
310       d_fetchl(&pdata, &data->u.fil.filMdDat);
311       d_fetchl(&pdata, &data->u.fil.filBkDat);
312 
313       d_fetchw(&pdata, &data->u.fil.filFndrInfo.fdIconID);
314       for (i = 0; i < 4; ++i)
315 	d_fetchw(&pdata, &data->u.fil.filFndrInfo.fdUnused[i]);
316       d_fetchw(&pdata, &data->u.fil.filFndrInfo.fdComment);
317       d_fetchl(&pdata, &data->u.fil.filFndrInfo.fdPutAway);
318 
319       d_fetchw(&pdata, (short *) &data->u.fil.filClpSize);
320 
321       for (i = 0; i < 3; ++i)
322 	{
323 	  d_fetchw(&pdata, (short *) &data->u.fil.filExtRec[i].xdrStABN);
324 	  d_fetchw(&pdata, (short *) &data->u.fil.filExtRec[i].xdrNumABlks);
325 	}
326 
327       for (i = 0; i < 3; ++i)
328 	{
329 	  d_fetchw(&pdata, (short *) &data->u.fil.filRExtRec[i].xdrStABN);
330 	  d_fetchw(&pdata, (short *) &data->u.fil.filRExtRec[i].xdrNumABlks);
331 	}
332 
333       d_fetchl(&pdata, &data->u.fil.filResrv);
334       break;
335 
336     case cdrThdRec:
337       for (i = 0; i < 2; ++i)
338 	d_fetchl(&pdata, &data->u.dthd.thdResrv[i]);
339 
340       d_fetchl(&pdata, (long *) &data->u.dthd.thdParID);
341       d_fetchs(&pdata, data->u.dthd.thdCName, sizeof(data->u.dthd.thdCName));
342       break;
343 
344     case cdrFThdRec:
345       for (i = 0; i < 2; ++i)
346 	d_fetchl(&pdata, &data->u.fthd.fthdResrv[i]);
347 
348       d_fetchl(&pdata, (long *) &data->u.fthd.fthdParID);
349       d_fetchs(&pdata, data->u.fthd.fthdCName, sizeof(data->u.fthd.fthdCName));
350       break;
351 
352     default:
353       abort();
354     }
355 }
356 
357 /*
358  * NAME:	record->packextdata()
359  * DESCRIPTION:	pack extent record data
360  */
361 void r_packextdata(ExtDataRec *data, unsigned char *pdata, int *len)
362 {
363   unsigned char *start = pdata;
364   int i;
365 
366   for (i = 0; i < 3; ++i)
367     {
368       d_storew(&pdata, (*data)[i].xdrStABN);
369       d_storew(&pdata, (*data)[i].xdrNumABlks);
370     }
371 
372   if (len)
373     *len += pdata - start;
374 }
375 
376 /*
377  * NAME:	record->unpackextdata()
378  * DESCRIPTION:	unpack extent record data
379  */
380 void r_unpackextdata(unsigned char *pdata, ExtDataRec *data)
381 {
382   int i;
383 
384   for (i = 0; i < 3; ++i)
385     {
386       d_fetchw(&pdata, (short *) &(*data)[i].xdrStABN);
387       d_fetchw(&pdata, (short *) &(*data)[i].xdrNumABlks);
388     }
389 }
390 
391 /*
392  * NAME:	record->makecatkey()
393  * DESCRIPTION:	construct a catalog record key
394  */
395 void r_makecatkey(CatKeyRec *key, long parid, char *name)
396 {
397   int len;
398 
399   len = strlen(name) + 1;
400 
401   key->ckrKeyLen = 0x05 + len + (len & 1);
402   key->ckrResrv1 = 0;
403   key->ckrParID  = parid;
404 
405   strcpy(key->ckrCName, name);
406 }
407 
408 /*
409  * NAME:	record->makeextkey()
410  * DESCRIPTION:	construct an extents record key
411  */
412 void r_makeextkey(ExtKeyRec *key, int fork, long fnum, unsigned int fabn)
413 {
414   key->xkrKeyLen = 0x07;
415   key->xkrFkType = fork;
416   key->xkrFNum   = fnum;
417   key->xkrFABN   = fabn;
418 }
419 
420 /*
421  * NAME:	record->unpackdirent()
422  * DESCRIPTION:	unpack catalog information into hfsdirent structure
423  */
424 void r_unpackdirent(long parid, char *name, CatDataRec *data, hfsdirent *ent)
425 {
426   strcpy(ent->name, name);
427   ent->parid = parid;
428 
429   switch (data->cdrType)
430     {
431     case cdrDirRec:
432       ent->flags   = HFS_ISDIR;
433       ent->cnid    = data->u.dir.dirDirID;
434       ent->crdate  = d_toutime(data->u.dir.dirCrDat);
435       ent->mddate  = d_toutime(data->u.dir.dirMdDat);
436       ent->dsize   = data->u.dir.dirVal;
437       ent->rsize   = 0;
438 
439       ent->type[0] = ent->creator[0] = 0;
440 
441       ent->fdflags = data->u.dir.dirUsrInfo.frFlags;
442       break;
443 
444     case cdrFilRec:
445       ent->flags   = (data->u.fil.filFlags & (1 << 0)) ? HFS_ISLOCKED : 0;
446       ent->cnid    = data->u.fil.filFlNum;
447       ent->crdate  = d_toutime(data->u.fil.filCrDat);
448       ent->mddate  = d_toutime(data->u.fil.filMdDat);
449       ent->dsize   = data->u.fil.filLgLen;
450       ent->rsize   = data->u.fil.filRLgLen;
451 
452       d_putl((unsigned char *) ent->type,    data->u.fil.filUsrWds.fdType);
453       d_putl((unsigned char *) ent->creator, data->u.fil.filUsrWds.fdCreator);
454 
455       ent->type[4] = ent->creator[4] = 0;
456 
457       ent->fdflags = data->u.fil.filUsrWds.fdFlags;
458       break;
459     }
460 }
461 
462 /*
463  * NAME:	record->packdirent()
464  * DESCRIPTION:	make changes to a catalog record
465  */
466 void r_packdirent(CatDataRec *data, hfsdirent *ent)
467 {
468   switch (data->cdrType)
469     {
470     case cdrDirRec:
471       data->u.dir.dirCrDat = d_tomtime(ent->crdate);
472       data->u.dir.dirMdDat = d_tomtime(ent->mddate);
473 
474       data->u.dir.dirUsrInfo.frFlags = ent->fdflags;
475       break;
476 
477     case cdrFilRec:
478       if (ent->flags & HFS_ISLOCKED)
479 	data->u.fil.filFlags |=  (1 << 0);
480       else
481 	data->u.fil.filFlags &= ~(1 << 0);
482 
483       data->u.fil.filCrDat = d_tomtime(ent->crdate);
484       data->u.fil.filMdDat = d_tomtime(ent->mddate);
485 
486       data->u.fil.filUsrWds.fdType    = d_getl((unsigned char *) ent->type);
487       data->u.fil.filUsrWds.fdCreator = d_getl((unsigned char *) ent->creator);
488 
489       data->u.fil.filUsrWds.fdFlags   = ent->fdflags;
490       break;
491     }
492 }
493