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 */
32void 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 */
49void 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 */
61void 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 */
78void 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 */
90int 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 */
110int 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 */
135void 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 */
250void 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 */
361void 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 */
380void 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 */
395void 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 */
412void 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 */
424void 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 */
466void 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