~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/openbios/fs/hfs/hfs.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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., 51 Franklin Street - Fifth Floor, Boston,
 
18
 * MA 02110-1301, USA.
 
19
 *
 
20
 * $Id: hfs.c,v 1.15 1998/11/02 22:09:00 rob Exp $
 
21
 */
 
22
 
 
23
#include "config.h"
 
24
#include "libhfs.h"
 
25
#include "data.h"
 
26
#include "block.h"
 
27
#include "medium.h"
 
28
#include "file.h"
 
29
#include "btree.h"
 
30
#include "node.h"
 
31
#include "record.h"
 
32
#include "volume.h"
 
33
 
 
34
const char *hfs_error = "no error";     /* static error string */
 
35
 
 
36
hfsvol *hfs_mounts;                     /* linked list of mounted volumes */
 
37
 
 
38
static
 
39
hfsvol *curvol;                         /* current volume */
 
40
 
 
41
 
 
42
/*
 
43
 * NAME:        getvol()
 
44
 * DESCRIPTION: validate a volume reference
 
45
 */
 
46
static
 
47
int getvol(hfsvol **vol)
 
48
{
 
49
  if (*vol == NULL)
 
50
    {
 
51
      if (curvol == NULL)
 
52
        ERROR(EINVAL, "no volume is current");
 
53
 
 
54
      *vol = curvol;
 
55
    }
 
56
 
 
57
  return 0;
 
58
 
 
59
fail:
 
60
  return -1;
 
61
}
 
62
 
 
63
/* High-Level Volume Routines ============================================== */
 
64
 
 
65
/*
 
66
 * NAME:        hfs->mount()
 
67
 * DESCRIPTION: open an HFS volume; return volume descriptor or 0 (error)
 
68
 */
 
69
hfsvol *hfs_mount( int os_fd, int pnum)
 
70
{
 
71
  hfsvol *vol, *check;
 
72
  int mode = HFS_MODE_RDONLY;
 
73
 
 
74
  /* see if the volume is already mounted */
 
75
  for (check = hfs_mounts; check; check = check->next)
 
76
    {
 
77
      if (check->pnum == pnum && v_same(check, os_fd) == 1)
 
78
        {
 
79
            vol = check;
 
80
            goto done;
 
81
        }
 
82
    }
 
83
 
 
84
  vol = ALLOC(hfsvol, 1);
 
85
  if (vol == NULL)
 
86
    ERROR(ENOMEM, NULL);
 
87
 
 
88
  v_init(vol, mode);
 
89
 
 
90
  vol->flags |= HFS_VOL_READONLY;
 
91
  if( v_open(vol, os_fd) == -1 )
 
92
          goto fail;
 
93
 
 
94
  /* mount the volume */
 
95
 
 
96
  if (v_geometry(vol, pnum) == -1 ||
 
97
      v_mount(vol) == -1)
 
98
    goto fail;
 
99
 
 
100
  /* add to linked list of volumes */
 
101
 
 
102
  vol->prev = NULL;
 
103
  vol->next = hfs_mounts;
 
104
 
 
105
  if (hfs_mounts)
 
106
    hfs_mounts->prev = vol;
 
107
 
 
108
  hfs_mounts = vol;
 
109
 
 
110
done:
 
111
  ++vol->refs;
 
112
  curvol = vol;
 
113
 
 
114
  return vol;
 
115
 
 
116
fail:
 
117
  if (vol)
 
118
    {
 
119
      v_close(vol);
 
120
      FREE(vol);
 
121
    }
 
122
 
 
123
  return NULL;
 
124
}
 
125
 
 
126
 
 
127
/*
 
128
 * NAME:        hfs->umount()
 
129
 * DESCRIPTION: close an HFS volume
 
130
 */
 
131
int hfs_umount(hfsvol *vol)
 
132
{
 
133
  int result = 0;
 
134
 
 
135
  if (getvol(&vol) == -1)
 
136
    goto fail;
 
137
 
 
138
  if (--vol->refs)
 
139
    {
 
140
      goto done;
 
141
    }
 
142
 
 
143
  /* close all open files and directories */
 
144
 
 
145
  while (vol->files)
 
146
    {
 
147
      if (hfs_close(vol->files) == -1)
 
148
        result = -1;
 
149
    }
 
150
 
 
151
  while (vol->dirs)
 
152
    {
 
153
      if (hfs_closedir(vol->dirs) == -1)
 
154
        result = -1;
 
155
    }
 
156
 
 
157
  /* close medium */
 
158
 
 
159
  if (v_close(vol) == -1)
 
160
    result = -1;
 
161
 
 
162
  /* remove from linked list of volumes */
 
163
 
 
164
  if (vol->prev)
 
165
    vol->prev->next = vol->next;
 
166
  if (vol->next)
 
167
    vol->next->prev = vol->prev;
 
168
 
 
169
  if (vol == hfs_mounts)
 
170
    hfs_mounts = vol->next;
 
171
  if (vol == curvol)
 
172
    curvol = NULL;
 
173
 
 
174
  FREE(vol);
 
175
 
 
176
done:
 
177
  return result;
 
178
 
 
179
fail:
 
180
  return -1;
 
181
}
 
182
 
 
183
/*
 
184
 * NAME:        hfs->umountall()
 
185
 * DESCRIPTION: unmount all mounted volumes
 
186
 */
 
187
void hfs_umountall(void)
 
188
{
 
189
  while (hfs_mounts)
 
190
    hfs_umount(hfs_mounts);
 
191
}
 
192
 
 
193
/*
 
194
 * NAME:        hfs->getvol()
 
195
 * DESCRIPTION: return a pointer to a mounted volume
 
196
 */
 
197
hfsvol *hfs_getvol(const char *name)
 
198
{
 
199
  hfsvol *vol;
 
200
 
 
201
  if (name == NULL)
 
202
    return curvol;
 
203
 
 
204
  for (vol = hfs_mounts; vol; vol = vol->next)
 
205
    {
 
206
      if (d_relstring(name, vol->mdb.drVN) == 0)
 
207
        return vol;
 
208
    }
 
209
 
 
210
  return NULL;
 
211
}
 
212
 
 
213
/*
 
214
 * NAME:        hfs->setvol()
 
215
 * DESCRIPTION: change the current volume
 
216
 */
 
217
void hfs_setvol(hfsvol *vol)
 
218
{
 
219
  curvol = vol;
 
220
}
 
221
 
 
222
/*
 
223
 * NAME:        hfs->vstat()
 
224
 * DESCRIPTION: return volume statistics
 
225
 */
 
226
int hfs_vstat(hfsvol *vol, hfsvolent *ent)
 
227
{
 
228
  if (getvol(&vol) == -1)
 
229
    goto fail;
 
230
 
 
231
  strcpy(ent->name, vol->mdb.drVN);
 
232
 
 
233
  ent->flags     = (vol->flags & HFS_VOL_READONLY) ? HFS_ISLOCKED : 0;
 
234
 
 
235
  ent->totbytes  = vol->mdb.drNmAlBlks * vol->mdb.drAlBlkSiz;
 
236
  ent->freebytes = vol->mdb.drFreeBks  * vol->mdb.drAlBlkSiz;
 
237
 
 
238
  ent->alblocksz = vol->mdb.drAlBlkSiz;
 
239
  ent->clumpsz   = vol->mdb.drClpSiz;
 
240
 
 
241
  ent->numfiles  = vol->mdb.drFilCnt;
 
242
  ent->numdirs   = vol->mdb.drDirCnt;
 
243
 
 
244
  ent->crdate    = d_ltime(vol->mdb.drCrDate);
 
245
  ent->mddate    = d_ltime(vol->mdb.drLsMod);
 
246
  ent->bkdate    = d_ltime(vol->mdb.drVolBkUp);
 
247
 
 
248
  ent->blessed   = vol->mdb.drFndrInfo[0];
 
249
 
 
250
  return 0;
 
251
 
 
252
fail:
 
253
  return -1;
 
254
}
 
255
 
 
256
 
 
257
/* High-Level Directory Routines =========================================== */
 
258
 
 
259
/*
 
260
 * NAME:        hfs->chdir()
 
261
 * DESCRIPTION: change current HFS directory
 
262
 */
 
263
int hfs_chdir(hfsvol *vol, const char *path)
 
264
{
 
265
  CatDataRec data;
 
266
 
 
267
  if (getvol(&vol) == -1 ||
 
268
      v_resolve(&vol, path, &data, NULL, NULL, NULL) <= 0)
 
269
    goto fail;
 
270
 
 
271
  if (data.cdrType != cdrDirRec)
 
272
    ERROR(ENOTDIR, NULL);
 
273
 
 
274
  vol->cwd = data.u.dir.dirDirID;
 
275
 
 
276
  return 0;
 
277
 
 
278
fail:
 
279
  return -1;
 
280
}
 
281
 
 
282
/*
 
283
 * NAME:        hfs->getcwd()
 
284
 * DESCRIPTION: return the current working directory ID
 
285
 */
 
286
unsigned long hfs_getcwd(hfsvol *vol)
 
287
{
 
288
  if (getvol(&vol) == -1)
 
289
    return 0;
 
290
 
 
291
  return vol->cwd;
 
292
}
 
293
 
 
294
/*
 
295
 * NAME:        hfs->setcwd()
 
296
 * DESCRIPTION: set the current working directory ID
 
297
 */
 
298
int hfs_setcwd(hfsvol *vol, unsigned long id)
 
299
{
 
300
  if (getvol(&vol) == -1)
 
301
    goto fail;
 
302
 
 
303
  if (id == vol->cwd)
 
304
    goto done;
 
305
 
 
306
  /* make sure the directory exists */
 
307
 
 
308
  if (v_getdthread(vol, id, NULL, NULL) <= 0)
 
309
    goto fail;
 
310
 
 
311
  vol->cwd = id;
 
312
 
 
313
done:
 
314
  return 0;
 
315
 
 
316
fail:
 
317
  return -1;
 
318
}
 
319
 
 
320
/*
 
321
 * NAME:        hfs->dirinfo()
 
322
 * DESCRIPTION: given a directory ID, return its (name and) parent ID
 
323
 */
 
324
int hfs_dirinfo(hfsvol *vol, unsigned long *id, char *name)
 
325
{
 
326
  CatDataRec thread;
 
327
 
 
328
  if (getvol(&vol) == -1 ||
 
329
      v_getdthread(vol, *id, &thread, NULL) <= 0)
 
330
    goto fail;
 
331
 
 
332
  *id = thread.u.dthd.thdParID;
 
333
 
 
334
  if (name)
 
335
    strcpy(name, thread.u.dthd.thdCName);
 
336
 
 
337
  return 0;
 
338
 
 
339
fail:
 
340
  return -1;
 
341
}
 
342
 
 
343
/*
 
344
 * NAME:        hfs->opendir()
 
345
 * DESCRIPTION: prepare to read the contents of a directory
 
346
 */
 
347
hfsdir *hfs_opendir(hfsvol *vol, const char *path)
 
348
{
 
349
  hfsdir *dir = NULL;
 
350
  CatKeyRec key;
 
351
  CatDataRec data;
 
352
  byte pkey[HFS_CATKEYLEN];
 
353
 
 
354
  if (getvol(&vol) == -1)
 
355
    goto fail;
 
356
 
 
357
  dir = ALLOC(hfsdir, 1);
 
358
  if (dir == NULL)
 
359
    ERROR(ENOMEM, NULL);
 
360
 
 
361
  dir->vol = vol;
 
362
 
 
363
  if (*path == 0)
 
364
    {
 
365
      /* meta-directory containing root dirs from all mounted volumes */
 
366
 
 
367
      dir->dirid = 0;
 
368
      dir->vptr  = hfs_mounts;
 
369
    }
 
370
  else
 
371
    {
 
372
      if (v_resolve(&vol, path, &data, NULL, NULL, NULL) <= 0)
 
373
        goto fail;
 
374
 
 
375
      if (data.cdrType != cdrDirRec)
 
376
        ERROR(ENOTDIR, NULL);
 
377
 
 
378
      dir->dirid = data.u.dir.dirDirID;
 
379
      dir->vptr  = NULL;
 
380
 
 
381
      r_makecatkey(&key, dir->dirid, "");
 
382
      r_packcatkey(&key, pkey, NULL);
 
383
 
 
384
      if (bt_search(&vol->cat, pkey, &dir->n) <= 0)
 
385
        goto fail;
 
386
    }
 
387
 
 
388
  dir->prev = NULL;
 
389
  dir->next = vol->dirs;
 
390
 
 
391
  if (vol->dirs)
 
392
    vol->dirs->prev = dir;
 
393
 
 
394
  vol->dirs = dir;
 
395
 
 
396
  return dir;
 
397
 
 
398
fail:
 
399
  FREE(dir);
 
400
  return NULL;
 
401
}
 
402
 
 
403
/*
 
404
 * NAME:        hfs->readdir()
 
405
 * DESCRIPTION: return the next entry in the directory
 
406
 */
 
407
int hfs_readdir(hfsdir *dir, hfsdirent *ent)
 
408
{
 
409
  CatKeyRec key;
 
410
  CatDataRec data;
 
411
  const byte *ptr;
 
412
 
 
413
  if (dir->dirid == 0)
 
414
    {
 
415
      hfsvol *vol;
 
416
      char cname[HFS_MAX_FLEN + 1];
 
417
 
 
418
      for (vol = hfs_mounts; vol; vol = vol->next)
 
419
        {
 
420
          if (vol == dir->vptr)
 
421
            break;
 
422
        }
 
423
 
 
424
      if (vol == NULL)
 
425
        ERROR(ENOENT, "no more entries");
 
426
 
 
427
      if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, NULL) <= 0 ||
 
428
          v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName,
 
429
                      &data, cname, NULL) <= 0)
 
430
        goto fail;
 
431
 
 
432
      r_unpackdirent(HFS_CNID_ROOTPAR, cname, &data, ent);
 
433
 
 
434
      dir->vptr = vol->next;
 
435
 
 
436
      goto done;
 
437
    }
 
438
 
 
439
  if (dir->n.rnum == -1)
 
440
    ERROR(ENOENT, "no more entries");
 
441
 
 
442
  while (1)
 
443
    {
 
444
      ++dir->n.rnum;
 
445
 
 
446
      while (dir->n.rnum >= dir->n.nd.ndNRecs)
 
447
        {
 
448
          if (dir->n.nd.ndFLink == 0)
 
449
            {
 
450
              dir->n.rnum = -1;
 
451
              ERROR(ENOENT, "no more entries");
 
452
            }
 
453
 
 
454
          if (bt_getnode(&dir->n, dir->n.bt, dir->n.nd.ndFLink) == -1)
 
455
            {
 
456
              dir->n.rnum = -1;
 
457
              goto fail;
 
458
            }
 
459
 
 
460
          dir->n.rnum = 0;
 
461
        }
 
462
 
 
463
      ptr = HFS_NODEREC(dir->n, dir->n.rnum);
 
464
 
 
465
      r_unpackcatkey(ptr, &key);
 
466
 
 
467
      if (key.ckrParID != dir->dirid)
 
468
        {
 
469
          dir->n.rnum = -1;
 
470
          ERROR(ENOENT, "no more entries");
 
471
        }
 
472
 
 
473
      r_unpackcatdata(HFS_RECDATA(ptr), &data);
 
474
 
 
475
      switch (data.cdrType)
 
476
        {
 
477
        case cdrDirRec:
 
478
        case cdrFilRec:
 
479
          r_unpackdirent(key.ckrParID, key.ckrCName, &data, ent);
 
480
          goto done;
 
481
 
 
482
        case cdrThdRec:
 
483
        case cdrFThdRec:
 
484
          break;
 
485
 
 
486
        default:
 
487
          dir->n.rnum = -1;
 
488
          ERROR(EIO, "unexpected directory entry found");
 
489
        }
 
490
    }
 
491
 
 
492
done:
 
493
  return 0;
 
494
 
 
495
fail:
 
496
  return -1;
 
497
}
 
498
 
 
499
/*
 
500
 * NAME:        hfs->closedir()
 
501
 * DESCRIPTION: stop reading a directory
 
502
 */
 
503
int hfs_closedir(hfsdir *dir)
 
504
{
 
505
  hfsvol *vol = dir->vol;
 
506
 
 
507
  if (dir->prev)
 
508
    dir->prev->next = dir->next;
 
509
  if (dir->next)
 
510
    dir->next->prev = dir->prev;
 
511
  if (dir == vol->dirs)
 
512
    vol->dirs = dir->next;
 
513
 
 
514
  FREE(dir);
 
515
 
 
516
  return 0;
 
517
}
 
518
 
 
519
/* High-Level File Routines ================================================ */
 
520
 
 
521
/*
 
522
 * NAME:        hfs->open()
 
523
 * DESCRIPTION: prepare a file for I/O
 
524
 */
 
525
hfsfile *hfs_open(hfsvol *vol, const char *path)
 
526
{
 
527
  hfsfile *file = NULL;
 
528
 
 
529
  if (getvol(&vol) == -1)
 
530
    goto fail;
 
531
 
 
532
  file = ALLOC(hfsfile, 1);
 
533
  if (file == NULL)
 
534
    ERROR(ENOMEM, NULL);
 
535
 
 
536
  if (v_resolve(&vol, path, &file->cat, &file->parid, file->name, NULL) <= 0)
 
537
    goto fail;
 
538
 
 
539
  if (file->cat.cdrType != cdrFilRec)
 
540
    ERROR(EISDIR, NULL);
 
541
 
 
542
  /* package file handle for user */
 
543
 
 
544
  file->vol   = vol;
 
545
  file->flags = 0;
 
546
 
 
547
  f_selectfork(file, fkData);
 
548
 
 
549
  file->prev = NULL;
 
550
  file->next = vol->files;
 
551
 
 
552
  if (vol->files)
 
553
    vol->files->prev = file;
 
554
 
 
555
  vol->files = file;
 
556
 
 
557
  return file;
 
558
 
 
559
fail:
 
560
  FREE(file);
 
561
  return NULL;
 
562
}
 
563
 
 
564
/*
 
565
 * NAME:        hfs->setfork()
 
566
 * DESCRIPTION: select file fork for I/O operations
 
567
 */
 
568
int hfs_setfork(hfsfile *file, int fork)
 
569
{
 
570
  int result = 0;
 
571
 
 
572
  f_selectfork(file, fork ? fkRsrc : fkData);
 
573
 
 
574
  return result;
 
575
}
 
576
 
 
577
/*
 
578
 * NAME:        hfs->getfork()
 
579
 * DESCRIPTION: return the current fork for I/O operations
 
580
 */
 
581
int hfs_getfork(hfsfile *file)
 
582
{
 
583
  return file->fork != fkData;
 
584
}
 
585
 
 
586
/*
 
587
 * NAME:        hfs->read()
 
588
 * DESCRIPTION: read from an open file
 
589
 */
 
590
unsigned long hfs_read(hfsfile *file, void *buf, unsigned long len)
 
591
{
 
592
  unsigned long *lglen, count;
 
593
  byte *ptr = buf;
 
594
 
 
595
  f_getptrs(file, NULL, &lglen, NULL);
 
596
 
 
597
  if (file->pos + len > *lglen)
 
598
    len = *lglen - file->pos;
 
599
 
 
600
  count = len;
 
601
  while (count)
 
602
    {
 
603
      unsigned long bnum, offs, chunk;
 
604
 
 
605
      bnum  = file->pos >> HFS_BLOCKSZ_BITS;
 
606
      offs  = file->pos & (HFS_BLOCKSZ - 1);
 
607
 
 
608
      chunk = HFS_BLOCKSZ - offs;
 
609
      if (chunk > count)
 
610
        chunk = count;
 
611
 
 
612
      if (offs == 0 && chunk == HFS_BLOCKSZ)
 
613
        {
 
614
          if (f_getblock(file, bnum, (block *) ptr) == -1)
 
615
            goto fail;
 
616
        }
 
617
      else
 
618
        {
 
619
          block b;
 
620
 
 
621
          if (f_getblock(file, bnum, &b) == -1)
 
622
            goto fail;
 
623
 
 
624
          memcpy(ptr, b + offs, chunk);
 
625
        }
 
626
 
 
627
      ptr += chunk;
 
628
 
 
629
      file->pos += chunk;
 
630
      count     -= chunk;
 
631
    }
 
632
 
 
633
  return len;
 
634
 
 
635
fail:
 
636
  return -1;
 
637
}
 
638
 
 
639
/*
 
640
 * NAME:        hfs->seek()
 
641
 * DESCRIPTION: change file seek pointer
 
642
 */
 
643
unsigned long hfs_seek(hfsfile *file, long offset, int from)
 
644
{
 
645
  unsigned long *lglen, newpos;
 
646
 
 
647
  f_getptrs(file, NULL, &lglen, NULL);
 
648
 
 
649
  switch (from)
 
650
    {
 
651
    case HFS_SEEK_SET:
 
652
      newpos = (offset < 0) ? 0 : offset;
 
653
      break;
 
654
 
 
655
    case HFS_SEEK_CUR:
 
656
      if (offset < 0 && (unsigned long) -offset > file->pos)
 
657
        newpos = 0;
 
658
      else
 
659
        newpos = file->pos + offset;
 
660
      break;
 
661
 
 
662
    case HFS_SEEK_END:
 
663
      if (offset < 0 && (unsigned long) -offset > *lglen)
 
664
        newpos = 0;
 
665
      else
 
666
        newpos = *lglen + offset;
 
667
      break;
 
668
 
 
669
    default:
 
670
      ERROR(EINVAL, NULL);
 
671
    }
 
672
 
 
673
  if (newpos > *lglen)
 
674
    newpos = *lglen;
 
675
 
 
676
  file->pos = newpos;
 
677
 
 
678
  return newpos;
 
679
 
 
680
fail:
 
681
  return -1;
 
682
}
 
683
 
 
684
/*
 
685
 * NAME:        hfs->close()
 
686
 * DESCRIPTION: close a file
 
687
 */
 
688
int hfs_close(hfsfile *file)
 
689
{
 
690
  hfsvol *vol = file->vol;
 
691
  int result = 0;
 
692
 
 
693
  if (file->prev)
 
694
    file->prev->next = file->next;
 
695
  if (file->next)
 
696
    file->next->prev = file->prev;
 
697
  if (file == vol->files)
 
698
    vol->files = file->next;
 
699
 
 
700
  FREE(file);
 
701
 
 
702
  return result;
 
703
}
 
704
 
 
705
/* High-Level Catalog Routines ============================================= */
 
706
 
 
707
/*
 
708
 * NAME:        hfs->stat()
 
709
 * DESCRIPTION: return catalog information for an arbitrary path
 
710
 */
 
711
int hfs_stat(hfsvol *vol, const char *path, hfsdirent *ent)
 
712
{
 
713
  CatDataRec data;
 
714
  unsigned long parid;
 
715
  char name[HFS_MAX_FLEN + 1];
 
716
 
 
717
  if (getvol(&vol) == -1 ||
 
718
      v_resolve(&vol, path, &data, &parid, name, NULL) <= 0)
 
719
    goto fail;
 
720
 
 
721
  r_unpackdirent(parid, name, &data, ent);
 
722
 
 
723
  return 0;
 
724
 
 
725
fail:
 
726
  return -1;
 
727
}
 
728
 
 
729
/*
 
730
 * NAME:        hfs->fstat()
 
731
 * DESCRIPTION: return catalog information for an open file
 
732
 */
 
733
int hfs_fstat(hfsfile *file, hfsdirent *ent)
 
734
{
 
735
  r_unpackdirent(file->parid, file->name, &file->cat, ent);
 
736
 
 
737
  return 0;
 
738
}
 
739
 
 
740
/*
 
741
 * NAME:        hfs->probe()
 
742
 * DESCRIPTION: return whether a HFS filesystem is present at the given offset
 
743
 */
 
744
int hfs_probe(int fd, long long offset)
 
745
{
 
746
  return v_probe(fd, offset);
 
747
}