Home | History | Annotate | Line # | Download | only in libhfs_iso
      1  1.1  tsutsui /*
      2  1.1  tsutsui  * hfsutils - tools for reading and writing Macintosh HFS volumes
      3  1.1  tsutsui  * Copyright (C) 1996, 1997 Robert Leslie
      4  1.1  tsutsui  *
      5  1.1  tsutsui  * This program is free software; you can redistribute it and/or modify
      6  1.1  tsutsui  * it under the terms of the GNU General Public License as published by
      7  1.1  tsutsui  * the Free Software Foundation; either version 2 of the License, or
      8  1.1  tsutsui  * (at your option) any later version.
      9  1.1  tsutsui  *
     10  1.1  tsutsui  * This program is distributed in the hope that it will be useful,
     11  1.1  tsutsui  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  1.1  tsutsui  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  1.1  tsutsui  * GNU General Public License for more details.
     14  1.1  tsutsui  *
     15  1.1  tsutsui  * You should have received a copy of the GNU General Public License
     16  1.1  tsutsui  * along with this program; if not, write to the Free Software
     17  1.1  tsutsui  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     18  1.1  tsutsui  */
     19  1.1  tsutsui 
     20  1.1  tsutsui # include <stdlib.h>
     21  1.1  tsutsui # include <string.h>
     22  1.1  tsutsui # include <errno.h>
     23  1.1  tsutsui # include <time.h>
     24  1.1  tsutsui 
     25  1.1  tsutsui # include "internal.h"
     26  1.1  tsutsui # include "data.h"
     27  1.1  tsutsui # include "low.h"
     28  1.1  tsutsui # include "btree.h"
     29  1.1  tsutsui # include "record.h"
     30  1.1  tsutsui # include "volume.h"
     31  1.1  tsutsui 
     32  1.1  tsutsui /*
     33  1.1  tsutsui  * NAME:	vol->catsearch()
     34  1.1  tsutsui  * DESCRIPTION:	search catalog tree
     35  1.1  tsutsui  */
     36  1.1  tsutsui int v_catsearch(hfsvol *vol, long parid, char *name,
     37  1.1  tsutsui 		CatDataRec *data, char *cname, node *np)
     38  1.1  tsutsui {
     39  1.1  tsutsui   CatKeyRec key;
     40  1.1  tsutsui   unsigned char pkey[HFS_CATKEYLEN];
     41  1.1  tsutsui   node n;
     42  1.1  tsutsui   unsigned char *ptr;
     43  1.1  tsutsui   int found;
     44  1.1  tsutsui 
     45  1.1  tsutsui   if (np == 0)
     46  1.1  tsutsui     np = &n;
     47  1.1  tsutsui 
     48  1.1  tsutsui   r_makecatkey(&key, parid, name);
     49  1.1  tsutsui   r_packcatkey(&key, pkey, 0);
     50  1.1  tsutsui 
     51  1.1  tsutsui   found = bt_search(&vol->cat, pkey, np);
     52  1.1  tsutsui   if (found <= 0)
     53  1.1  tsutsui     return found;
     54  1.1  tsutsui 
     55  1.1  tsutsui   ptr = HFS_NODEREC(*np, np->rnum);
     56  1.1  tsutsui 
     57  1.1  tsutsui   if (cname)
     58  1.1  tsutsui     {
     59  1.1  tsutsui       r_unpackcatkey(ptr, &key);
     60  1.1  tsutsui       strcpy(cname, key.ckrCName);
     61  1.1  tsutsui     }
     62  1.1  tsutsui 
     63  1.1  tsutsui   if (data)
     64  1.1  tsutsui     r_unpackcatdata(HFS_RECDATA(ptr), data);
     65  1.1  tsutsui 
     66  1.1  tsutsui   return 1;
     67  1.1  tsutsui }
     68  1.1  tsutsui 
     69  1.1  tsutsui /*
     70  1.1  tsutsui  * NAME:	vol->extsearch()
     71  1.1  tsutsui  * DESCRIPTION:	search extents tree
     72  1.1  tsutsui  */
     73  1.1  tsutsui int v_extsearch(hfsfile *file, unsigned int fabn, ExtDataRec *data, node *np)
     74  1.1  tsutsui {
     75  1.1  tsutsui   ExtKeyRec key;
     76  1.1  tsutsui   ExtDataRec extsave;
     77  1.1  tsutsui   unsigned int fabnsave;
     78  1.1  tsutsui   unsigned char pkey[HFS_EXTKEYLEN];
     79  1.1  tsutsui   node n;
     80  1.1  tsutsui   unsigned char *ptr;
     81  1.1  tsutsui   int found;
     82  1.1  tsutsui 
     83  1.1  tsutsui   if (np == 0)
     84  1.1  tsutsui     np = &n;
     85  1.1  tsutsui 
     86  1.1  tsutsui   r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, fabn);
     87  1.1  tsutsui   r_packextkey(&key, pkey, 0);
     88  1.1  tsutsui 
     89  1.1  tsutsui   /* in case bt_search() clobbers these */
     90  1.1  tsutsui 
     91  1.1  tsutsui   memcpy(&extsave, &file->ext, sizeof(ExtDataRec));
     92  1.1  tsutsui   fabnsave = file->fabn;
     93  1.1  tsutsui 
     94  1.1  tsutsui   found = bt_search(&file->vol->ext, pkey, np);
     95  1.1  tsutsui 
     96  1.1  tsutsui   memcpy(&file->ext, &extsave, sizeof(ExtDataRec));
     97  1.1  tsutsui   file->fabn = fabnsave;
     98  1.1  tsutsui 
     99  1.1  tsutsui   if (found <= 0)
    100  1.1  tsutsui     return found;
    101  1.1  tsutsui 
    102  1.1  tsutsui   if (data)
    103  1.1  tsutsui     {
    104  1.1  tsutsui       ptr = HFS_NODEREC(*np, np->rnum);
    105  1.1  tsutsui       r_unpackextdata(HFS_RECDATA(ptr), data);
    106  1.1  tsutsui     }
    107  1.1  tsutsui 
    108  1.1  tsutsui   return 1;
    109  1.1  tsutsui }
    110  1.1  tsutsui 
    111  1.1  tsutsui /*
    112  1.1  tsutsui  * NAME:	vol->getthread()
    113  1.1  tsutsui  * DESCRIPTION:	retrieve catalog thread information for a file or directory
    114  1.1  tsutsui  */
    115  1.1  tsutsui int v_getthread(hfsvol *vol, long id, CatDataRec *thread, node *np, int type)
    116  1.1  tsutsui {
    117  1.1  tsutsui   CatDataRec rec;
    118  1.1  tsutsui   int found;
    119  1.1  tsutsui 
    120  1.1  tsutsui   if (thread == 0)
    121  1.1  tsutsui     thread = &rec;
    122  1.1  tsutsui 
    123  1.1  tsutsui   found = v_catsearch(vol, id, "", thread, 0, np);
    124  1.1  tsutsui   if (found <= 0)
    125  1.1  tsutsui     return found;
    126  1.1  tsutsui 
    127  1.1  tsutsui   if (thread->cdrType != type)
    128  1.1  tsutsui     {
    129  1.1  tsutsui       ERROR(EIO, "bad thread record");
    130  1.1  tsutsui       return -1;
    131  1.1  tsutsui     }
    132  1.1  tsutsui 
    133  1.1  tsutsui   return 1;
    134  1.1  tsutsui }
    135  1.1  tsutsui 
    136  1.1  tsutsui /*
    137  1.1  tsutsui  * NAME:	vol->putcatrec()
    138  1.1  tsutsui  * DESCRIPTION:	store catalog information
    139  1.1  tsutsui  */
    140  1.1  tsutsui int v_putcatrec(CatDataRec *data, node *np)
    141  1.1  tsutsui {
    142  1.1  tsutsui   unsigned char pdata[HFS_CATDATALEN], *ptr;
    143  1.1  tsutsui   int len = 0;
    144  1.1  tsutsui 
    145  1.1  tsutsui   r_packcatdata(data, pdata, &len);
    146  1.1  tsutsui 
    147  1.1  tsutsui   ptr = HFS_NODEREC(*np, np->rnum);
    148  1.1  tsutsui   memcpy(HFS_RECDATA(ptr), pdata, len);
    149  1.1  tsutsui 
    150  1.1  tsutsui   return bt_putnode(np);
    151  1.1  tsutsui }
    152  1.1  tsutsui 
    153  1.1  tsutsui /*
    154  1.1  tsutsui  * NAME:	vol->putextrec()
    155  1.1  tsutsui  * DESCRIPTION:	store extent information
    156  1.1  tsutsui  */
    157  1.1  tsutsui int v_putextrec(ExtDataRec *data, node *np)
    158  1.1  tsutsui {
    159  1.1  tsutsui   unsigned char pdata[HFS_EXTDATALEN], *ptr;
    160  1.1  tsutsui   int len = 0;
    161  1.1  tsutsui 
    162  1.1  tsutsui   r_packextdata(data, pdata, &len);
    163  1.1  tsutsui 
    164  1.1  tsutsui   ptr = HFS_NODEREC(*np, np->rnum);
    165  1.1  tsutsui   memcpy(HFS_RECDATA(ptr), pdata, len);
    166  1.1  tsutsui 
    167  1.1  tsutsui   return bt_putnode(np);
    168  1.1  tsutsui }
    169  1.1  tsutsui 
    170  1.1  tsutsui /*
    171  1.1  tsutsui  * NAME:	vol->allocblocks()
    172  1.1  tsutsui  * DESCRIPTION:	allocate a contiguous range of blocks
    173  1.1  tsutsui  */
    174  1.1  tsutsui int v_allocblocks(hfsvol *vol, ExtDescriptor *blocks)
    175  1.1  tsutsui {
    176  1.1  tsutsui   unsigned int request, found, foundat, start, end, pt;
    177  1.1  tsutsui   block *vbm;
    178  1.1  tsutsui   int wrap = 0;
    179  1.1  tsutsui 
    180  1.1  tsutsui   if (vol->mdb.drFreeBks == 0)
    181  1.1  tsutsui     {
    182  1.1  tsutsui       ERROR(ENOSPC, "volume full");
    183  1.1  tsutsui       return -1;
    184  1.1  tsutsui     }
    185  1.1  tsutsui 
    186  1.1  tsutsui   request = blocks->xdrNumABlks;
    187  1.1  tsutsui   found   = 0;
    188  1.1  tsutsui   foundat = 0;
    189  1.1  tsutsui   start   = vol->mdb.drAllocPtr;
    190  1.1  tsutsui   end     = vol->mdb.drNmAlBlks;
    191  1.1  tsutsui   pt      = start;
    192  1.1  tsutsui   vbm     = vol->vbm;
    193  1.1  tsutsui 
    194  1.1  tsutsui   if (request == 0)
    195  1.1  tsutsui     abort();
    196  1.1  tsutsui 
    197  1.1  tsutsui   while (1)
    198  1.1  tsutsui     {
    199  1.1  tsutsui       unsigned int mark;
    200  1.1  tsutsui 
    201  1.1  tsutsui       /* skip blocks in use */
    202  1.1  tsutsui 
    203  1.1  tsutsui       while (pt < end && BMTST(vbm, pt))
    204  1.1  tsutsui 	++pt;
    205  1.1  tsutsui 
    206  1.1  tsutsui       if (wrap && pt >= start)
    207  1.1  tsutsui 	break;
    208  1.1  tsutsui 
    209  1.1  tsutsui       /* count blocks not in use */
    210  1.1  tsutsui 
    211  1.1  tsutsui       mark = pt;
    212  1.1  tsutsui       while (pt < end && pt - mark < request && ! BMTST(vbm, pt))
    213  1.1  tsutsui 	++pt;
    214  1.1  tsutsui 
    215  1.1  tsutsui       if (pt - mark > found)
    216  1.1  tsutsui 	{
    217  1.1  tsutsui 	  found   = pt - mark;
    218  1.1  tsutsui 	  foundat = mark;
    219  1.1  tsutsui 	}
    220  1.1  tsutsui 
    221  1.1  tsutsui       if (pt == end)
    222  1.1  tsutsui 	pt = 0, wrap = 1;
    223  1.1  tsutsui 
    224  1.1  tsutsui       if (found == request)
    225  1.1  tsutsui 	break;
    226  1.1  tsutsui     }
    227  1.1  tsutsui 
    228  1.1  tsutsui   if (found == 0 || found > vol->mdb.drFreeBks)
    229  1.1  tsutsui     {
    230  1.1  tsutsui       ERROR(EIO, "bad volume bitmap or free block count");
    231  1.1  tsutsui       return -1;
    232  1.1  tsutsui     }
    233  1.1  tsutsui 
    234  1.1  tsutsui   blocks->xdrStABN    = foundat;
    235  1.1  tsutsui   blocks->xdrNumABlks = found;
    236  1.1  tsutsui 
    237  1.1  tsutsui   vol->mdb.drAllocPtr = pt;
    238  1.1  tsutsui   vol->mdb.drFreeBks -= found;
    239  1.1  tsutsui 
    240  1.1  tsutsui   for (pt = foundat; pt < foundat + found; ++pt)
    241  1.1  tsutsui     BMSET(vbm, pt);
    242  1.1  tsutsui 
    243  1.1  tsutsui   vol->flags |= HFS_UPDATE_MDB | HFS_UPDATE_VBM;
    244  1.1  tsutsui 
    245  1.1  tsutsui   return 0;
    246  1.1  tsutsui }
    247  1.1  tsutsui 
    248  1.1  tsutsui /*
    249  1.1  tsutsui  * NAME:	vol->freeblocks()
    250  1.1  tsutsui  * DESCRIPTION:	deallocate a contiguous range of blocks
    251  1.1  tsutsui  */
    252  1.1  tsutsui void v_freeblocks(hfsvol *vol, ExtDescriptor *blocks)
    253  1.1  tsutsui {
    254  1.1  tsutsui   unsigned int start, len, pt;
    255  1.1  tsutsui   block *vbm;
    256  1.1  tsutsui 
    257  1.1  tsutsui   start = blocks->xdrStABN;
    258  1.1  tsutsui   len   = blocks->xdrNumABlks;
    259  1.1  tsutsui   vbm   = vol->vbm;
    260  1.1  tsutsui 
    261  1.1  tsutsui   vol->mdb.drFreeBks += len;
    262  1.1  tsutsui 
    263  1.1  tsutsui   for (pt = start; pt < start + len; ++pt)
    264  1.1  tsutsui     BMCLR(vbm, pt);
    265  1.1  tsutsui 
    266  1.1  tsutsui   vol->flags |= HFS_UPDATE_MDB | HFS_UPDATE_VBM;
    267  1.1  tsutsui }
    268  1.1  tsutsui 
    269  1.1  tsutsui /*
    270  1.1  tsutsui  * NAME:	vol->resolve()
    271  1.1  tsutsui  * DESCRIPTION:	translate a pathname; return catalog information
    272  1.1  tsutsui  */
    273  1.1  tsutsui int v_resolve(hfsvol **vol, char *path, CatDataRec *data,
    274  1.1  tsutsui 	      long *parid, char *fname, node *np)
    275  1.1  tsutsui {
    276  1.1  tsutsui   long dirid;
    277  1.1  tsutsui   char name[HFS_MAX_FLEN + 1], *nptr;
    278  1.1  tsutsui   int found;
    279  1.1  tsutsui 
    280  1.1  tsutsui   if (*path == 0)
    281  1.1  tsutsui     {
    282  1.1  tsutsui       ERROR(ENOENT, "empty path");
    283  1.1  tsutsui       return -1;
    284  1.1  tsutsui     }
    285  1.1  tsutsui 
    286  1.1  tsutsui   if (parid)
    287  1.1  tsutsui     *parid = 0;
    288  1.1  tsutsui 
    289  1.1  tsutsui   nptr = strchr(path, ':');
    290  1.1  tsutsui 
    291  1.1  tsutsui   if (*path == ':' || nptr == 0)
    292  1.1  tsutsui     {
    293  1.1  tsutsui       dirid = (*vol)->cwd;  /* relative path */
    294  1.1  tsutsui 
    295  1.1  tsutsui       if (*path == ':')
    296  1.1  tsutsui 	++path;
    297  1.1  tsutsui 
    298  1.1  tsutsui       if (*path == 0)
    299  1.1  tsutsui 	{
    300  1.1  tsutsui 	  found = v_getdthread(*vol, dirid, data, 0);
    301  1.1  tsutsui 	  if (found <= 0)
    302  1.1  tsutsui 	    return found;
    303  1.1  tsutsui 
    304  1.1  tsutsui 	  if (parid)
    305  1.1  tsutsui 	    *parid = data->u.dthd.thdParID;
    306  1.1  tsutsui 
    307  1.1  tsutsui 	  return v_catsearch(*vol, data->u.dthd.thdParID,
    308  1.1  tsutsui 			     data->u.dthd.thdCName, data, fname, np);
    309  1.1  tsutsui 	}
    310  1.1  tsutsui     }
    311  1.1  tsutsui   else
    312  1.1  tsutsui     {
    313  1.1  tsutsui       hfsvol *check;
    314  1.1  tsutsui 
    315  1.1  tsutsui       dirid = HFS_CNID_ROOTPAR;  /* absolute path */
    316  1.1  tsutsui 
    317  1.1  tsutsui       if (nptr - path > HFS_MAX_VLEN)
    318  1.1  tsutsui 	{
    319  1.1  tsutsui 	  ERROR(ENAMETOOLONG, 0);
    320  1.1  tsutsui 	  return -1;
    321  1.1  tsutsui 	}
    322  1.1  tsutsui 
    323  1.1  tsutsui       strncpy(name, path, nptr - path);
    324  1.1  tsutsui       name[nptr - path] = 0;
    325  1.1  tsutsui 
    326  1.1  tsutsui       for (check = hfs_mounts; check; check = check->next)
    327  1.1  tsutsui 	{
    328  1.1  tsutsui 	  if (d_relstring(check->mdb.drVN, name) == 0)
    329  1.1  tsutsui 	    {
    330  1.1  tsutsui 	      *vol = check;
    331  1.1  tsutsui 	      break;
    332  1.1  tsutsui 	    }
    333  1.1  tsutsui 	}
    334  1.1  tsutsui     }
    335  1.1  tsutsui 
    336  1.1  tsutsui   while (1)
    337  1.1  tsutsui     {
    338  1.1  tsutsui       while (*path == ':')
    339  1.1  tsutsui 	{
    340  1.1  tsutsui 	  ++path;
    341  1.1  tsutsui 
    342  1.1  tsutsui 	  found = v_getdthread(*vol, dirid, data, 0);
    343  1.1  tsutsui 	  if (found <= 0)
    344  1.1  tsutsui 	    return found;
    345  1.1  tsutsui 
    346  1.1  tsutsui 	  dirid = data->u.dthd.thdParID;
    347  1.1  tsutsui 	}
    348  1.1  tsutsui 
    349  1.1  tsutsui       if (*path == 0)
    350  1.1  tsutsui 	{
    351  1.1  tsutsui 	  found = v_getdthread(*vol, dirid, data, 0);
    352  1.1  tsutsui 	  if (found <= 0)
    353  1.1  tsutsui 	    return found;
    354  1.1  tsutsui 
    355  1.1  tsutsui 	  if (parid)
    356  1.1  tsutsui 	    *parid = data->u.dthd.thdParID;
    357  1.1  tsutsui 
    358  1.1  tsutsui 	  return v_catsearch(*vol, data->u.dthd.thdParID,
    359  1.1  tsutsui 			     data->u.dthd.thdCName, data, fname, np);
    360  1.1  tsutsui 	}
    361  1.1  tsutsui 
    362  1.1  tsutsui       nptr = name;
    363  1.1  tsutsui       while (nptr < name + sizeof(name) - 1 && *path && *path != ':')
    364  1.1  tsutsui 	*nptr++ = *path++;
    365  1.1  tsutsui 
    366  1.1  tsutsui       if (*path && *path != ':')
    367  1.1  tsutsui 	{
    368  1.1  tsutsui 	  ERROR(ENAMETOOLONG, 0);
    369  1.1  tsutsui 	  return -1;
    370  1.1  tsutsui 	}
    371  1.1  tsutsui 
    372  1.1  tsutsui       *nptr = 0;
    373  1.1  tsutsui       if (*path == ':')
    374  1.1  tsutsui 	++path;
    375  1.1  tsutsui 
    376  1.1  tsutsui       if (parid)
    377  1.1  tsutsui 	*parid = dirid;
    378  1.1  tsutsui 
    379  1.1  tsutsui       found = v_catsearch(*vol, dirid, name, data, fname, np);
    380  1.1  tsutsui       if (found < 0)
    381  1.1  tsutsui 	return -1;
    382  1.1  tsutsui 
    383  1.1  tsutsui       if (found == 0)
    384  1.1  tsutsui 	{
    385  1.1  tsutsui 	  if (*path && parid)
    386  1.1  tsutsui 	    *parid = 0;
    387  1.1  tsutsui 
    388  1.1  tsutsui 	  if (*path == 0 && fname)
    389  1.1  tsutsui 	    strcpy(fname, name);
    390  1.1  tsutsui 
    391  1.1  tsutsui 	  return 0;
    392  1.1  tsutsui 	}
    393  1.1  tsutsui 
    394  1.1  tsutsui       switch (data->cdrType)
    395  1.1  tsutsui 	{
    396  1.1  tsutsui 	case cdrDirRec:
    397  1.1  tsutsui 	  if (*path == 0)
    398  1.1  tsutsui 	    return 1;
    399  1.1  tsutsui 
    400  1.1  tsutsui 	  dirid = data->u.dir.dirDirID;
    401  1.1  tsutsui 	  break;
    402  1.1  tsutsui 
    403  1.1  tsutsui 	case cdrFilRec:
    404  1.1  tsutsui 	  if (*path == 0)
    405  1.1  tsutsui 	    return 1;
    406  1.1  tsutsui 
    407  1.1  tsutsui 	  ERROR(ENOTDIR, "invalid pathname");
    408  1.1  tsutsui 	  return -1;
    409  1.1  tsutsui 
    410  1.1  tsutsui 	default:
    411  1.1  tsutsui 	  ERROR(EIO, "unexpected catalog record");
    412  1.1  tsutsui 	  return -1;
    413  1.1  tsutsui 	}
    414  1.1  tsutsui     }
    415  1.1  tsutsui }
    416  1.1  tsutsui 
    417  1.1  tsutsui /*
    418  1.1  tsutsui  * NAME:	vol->destruct()
    419  1.1  tsutsui  * DESCRIPTION:	free memory consumed by a volume descriptor
    420  1.1  tsutsui  */
    421  1.1  tsutsui void v_destruct(hfsvol *vol)
    422  1.1  tsutsui {
    423  1.1  tsutsui   FREE(vol->vbm);
    424  1.1  tsutsui 
    425  1.1  tsutsui   FREE(vol->ext.map);
    426  1.1  tsutsui   FREE(vol->cat.map);
    427  1.1  tsutsui 
    428  1.1  tsutsui   FREE(vol);
    429  1.1  tsutsui }
    430  1.1  tsutsui 
    431  1.1  tsutsui /*
    432  1.1  tsutsui  * NAME:	vol->getvol()
    433  1.1  tsutsui  * DESCRIPTION:	validate a volume reference
    434  1.1  tsutsui  */
    435  1.1  tsutsui int v_getvol(hfsvol **vol)
    436  1.1  tsutsui {
    437  1.1  tsutsui   if (*vol == 0)
    438  1.1  tsutsui     {
    439  1.1  tsutsui       if (hfs_curvol == 0)
    440  1.1  tsutsui 	{
    441  1.1  tsutsui 	  ERROR(EINVAL, "no volume is current");
    442  1.1  tsutsui 	  return -1;
    443  1.1  tsutsui 	}
    444  1.1  tsutsui 
    445  1.1  tsutsui       *vol = hfs_curvol;
    446  1.1  tsutsui     }
    447  1.1  tsutsui 
    448  1.1  tsutsui   return 0;
    449  1.1  tsutsui }
    450  1.1  tsutsui 
    451  1.1  tsutsui /*
    452  1.1  tsutsui  * NAME:	vol->flush()
    453  1.1  tsutsui  * DESCRIPTION:	flush all pending changes (B*-tree, MDB, VBM) to disk
    454  1.1  tsutsui  */
    455  1.1  tsutsui int v_flush(hfsvol *vol, int umounting)
    456  1.1  tsutsui {
    457  1.1  tsutsui   if (! (vol->flags & HFS_READONLY))
    458  1.1  tsutsui     {
    459  1.1  tsutsui       if ((vol->ext.flags & HFS_UPDATE_BTHDR) &&
    460  1.1  tsutsui 	  bt_writehdr(&vol->ext) < 0)
    461  1.1  tsutsui 	return -1;
    462  1.1  tsutsui 
    463  1.1  tsutsui       if ((vol->cat.flags & HFS_UPDATE_BTHDR) &&
    464  1.1  tsutsui 	  bt_writehdr(&vol->cat) < 0)
    465  1.1  tsutsui 	return -1;
    466  1.1  tsutsui 
    467  1.1  tsutsui       if ((vol->flags & HFS_UPDATE_VBM) &&
    468  1.1  tsutsui 	  l_writevbm(vol) < 0)
    469  1.1  tsutsui 	return -1;
    470  1.1  tsutsui 
    471  1.1  tsutsui       if (umounting &&
    472  1.1  tsutsui 	  ! (vol->mdb.drAtrb & HFS_ATRB_UMOUNTED))
    473  1.1  tsutsui 	{
    474  1.1  tsutsui 	  vol->mdb.drAtrb |= HFS_ATRB_UMOUNTED;
    475  1.1  tsutsui 	  vol->flags |= HFS_UPDATE_MDB;
    476  1.1  tsutsui 	}
    477  1.1  tsutsui 
    478  1.1  tsutsui       if ((vol->flags & (HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB)) &&
    479  1.1  tsutsui 	  l_writemdb(vol) < 0)
    480  1.1  tsutsui 	return -1;
    481  1.1  tsutsui     }
    482  1.1  tsutsui 
    483  1.1  tsutsui   return 0;
    484  1.1  tsutsui }
    485  1.1  tsutsui 
    486  1.1  tsutsui /*
    487  1.1  tsutsui  * NAME:	vol->adjvalence()
    488  1.1  tsutsui  * DESCRIPTION:	update a volume's valence counts
    489  1.1  tsutsui  */
    490  1.1  tsutsui int v_adjvalence(hfsvol *vol, long parid, int isdir, int adj)
    491  1.1  tsutsui {
    492  1.1  tsutsui   node n;
    493  1.1  tsutsui   CatDataRec data;
    494  1.1  tsutsui 
    495  1.1  tsutsui   if (isdir)
    496  1.1  tsutsui     vol->mdb.drDirCnt += adj;
    497  1.1  tsutsui   else
    498  1.1  tsutsui     vol->mdb.drFilCnt += adj;
    499  1.1  tsutsui 
    500  1.1  tsutsui   vol->flags |= HFS_UPDATE_MDB;
    501  1.1  tsutsui 
    502  1.1  tsutsui   if (parid == HFS_CNID_ROOTDIR)
    503  1.1  tsutsui     {
    504  1.1  tsutsui       if (isdir)
    505  1.1  tsutsui 	vol->mdb.drNmRtDirs += adj;
    506  1.1  tsutsui       else
    507  1.1  tsutsui 	vol->mdb.drNmFls    += adj;
    508  1.1  tsutsui     }
    509  1.1  tsutsui   else if (parid == HFS_CNID_ROOTPAR)
    510  1.1  tsutsui     return 0;
    511  1.1  tsutsui 
    512  1.1  tsutsui   if (v_getdthread(vol, parid, &data, 0) <= 0 ||
    513  1.1  tsutsui       v_catsearch(vol, data.u.dthd.thdParID, data.u.dthd.thdCName,
    514  1.1  tsutsui 		  &data, 0, &n) <= 0 ||
    515  1.1  tsutsui       data.cdrType != cdrDirRec)
    516  1.1  tsutsui     {
    517  1.1  tsutsui       ERROR(EIO, "can't find parent directory");
    518  1.1  tsutsui       return -1;
    519  1.1  tsutsui     }
    520  1.1  tsutsui 
    521  1.1  tsutsui   data.u.dir.dirVal  += adj;
    522  1.1  tsutsui   data.u.dir.dirMdDat = d_tomtime(time(0));
    523  1.1  tsutsui 
    524  1.1  tsutsui   return v_putcatrec(&data, &n);
    525  1.1  tsutsui }
    526  1.1  tsutsui 
    527  1.1  tsutsui /*
    528  1.1  tsutsui  * NAME:	vol->newfolder()
    529  1.1  tsutsui  * DESCRIPTION:	create a new HFS folder
    530  1.1  tsutsui  */
    531  1.1  tsutsui int v_newfolder(hfsvol *vol, long parid, char *name)
    532  1.1  tsutsui {
    533  1.1  tsutsui   CatKeyRec key;
    534  1.1  tsutsui   CatDataRec data;
    535  1.1  tsutsui   long id;
    536  1.1  tsutsui   unsigned char record[HFS_CATRECMAXLEN];
    537  1.1  tsutsui   int i, reclen;
    538  1.1  tsutsui 
    539  1.1  tsutsui   if (bt_space(&vol->cat, 2) < 0)
    540  1.1  tsutsui     return -1;
    541  1.1  tsutsui 
    542  1.1  tsutsui   id = vol->mdb.drNxtCNID++;
    543  1.1  tsutsui   vol->flags |= HFS_UPDATE_MDB;
    544  1.1  tsutsui 
    545  1.1  tsutsui   /* create directory record */
    546  1.1  tsutsui 
    547  1.1  tsutsui   data.cdrType   = cdrDirRec;
    548  1.1  tsutsui   data.cdrResrv2 = 0;
    549  1.1  tsutsui 
    550  1.1  tsutsui   data.u.dir.dirFlags = 0;
    551  1.1  tsutsui   data.u.dir.dirVal   = 0;
    552  1.1  tsutsui   data.u.dir.dirDirID = id;
    553  1.1  tsutsui   data.u.dir.dirCrDat = d_tomtime(time(0));
    554  1.1  tsutsui   data.u.dir.dirMdDat = data.u.dir.dirCrDat;
    555  1.1  tsutsui   data.u.dir.dirBkDat = 0;
    556  1.1  tsutsui 
    557  1.1  tsutsui   memset(&data.u.dir.dirUsrInfo,  0, sizeof(data.u.dir.dirUsrInfo));
    558  1.1  tsutsui   memset(&data.u.dir.dirFndrInfo, 0, sizeof(data.u.dir.dirFndrInfo));
    559  1.1  tsutsui   for (i = 0; i < 4; ++i)
    560  1.1  tsutsui     data.u.dir.dirResrv[i] = 0;
    561  1.1  tsutsui 
    562  1.1  tsutsui   r_makecatkey(&key, parid, name);
    563  1.1  tsutsui   r_packcatkey(&key, record, &reclen);
    564  1.1  tsutsui   r_packcatdata(&data, HFS_RECDATA(record), &reclen);
    565  1.1  tsutsui 
    566  1.1  tsutsui   if (bt_insert(&vol->cat, record, reclen) < 0)
    567  1.1  tsutsui     return -1;
    568  1.1  tsutsui 
    569  1.1  tsutsui   /* create thread record */
    570  1.1  tsutsui 
    571  1.1  tsutsui   data.cdrType   = cdrThdRec;
    572  1.1  tsutsui   data.cdrResrv2 = 0;
    573  1.1  tsutsui 
    574  1.1  tsutsui   data.u.dthd.thdResrv[0] = 0;
    575  1.1  tsutsui   data.u.dthd.thdResrv[1] = 0;
    576  1.1  tsutsui   data.u.dthd.thdParID    = parid;
    577  1.1  tsutsui   strcpy(data.u.dthd.thdCName, name);
    578  1.1  tsutsui 
    579  1.1  tsutsui   r_makecatkey(&key, id, "");
    580  1.1  tsutsui   r_packcatkey(&key, record, &reclen);
    581  1.1  tsutsui   r_packcatdata(&data, HFS_RECDATA(record), &reclen);
    582  1.1  tsutsui 
    583  1.1  tsutsui   if (bt_insert(&vol->cat, record, reclen) < 0 ||
    584  1.1  tsutsui       v_adjvalence(vol, parid, 1, 1) < 0)
    585  1.1  tsutsui     return -1;
    586  1.1  tsutsui 
    587  1.1  tsutsui   return 0;
    588  1.1  tsutsui }
    589  1.1  tsutsui 
    590  1.1  tsutsui /*
    591  1.1  tsutsui  * NAME:	markexts()
    592  1.1  tsutsui  * DESCRIPTION:	set bits from an extent record in the volume bitmap
    593  1.1  tsutsui  */
    594  1.1  tsutsui static
    595  1.1  tsutsui void markexts(block *vbm, ExtDataRec *exts)
    596  1.1  tsutsui {
    597  1.1  tsutsui   int i;
    598  1.1  tsutsui   unsigned int start, len;
    599  1.1  tsutsui 
    600  1.1  tsutsui   for (i = 0; i < 3; ++i)
    601  1.1  tsutsui     {
    602  1.1  tsutsui       for (start = (*exts)[i].xdrStABN,
    603  1.1  tsutsui 	     len = (*exts)[i].xdrNumABlks; len--; ++start)
    604  1.1  tsutsui 	BMSET(vbm, start);
    605  1.1  tsutsui     }
    606  1.1  tsutsui }
    607  1.1  tsutsui 
    608  1.1  tsutsui /*
    609  1.1  tsutsui  * NAME:	vol->scavenge()
    610  1.1  tsutsui  * DESCRIPTION:	safeguard blocks in the volume bitmap
    611  1.1  tsutsui  */
    612  1.1  tsutsui int v_scavenge(hfsvol *vol)
    613  1.1  tsutsui {
    614  1.1  tsutsui   block *vbm = vol->vbm;
    615  1.1  tsutsui   node n;
    616  1.1  tsutsui   unsigned int pt, blks;
    617  1.1  tsutsui 
    618  1.1  tsutsui   if (vbm == 0)
    619  1.1  tsutsui     return 0;
    620  1.1  tsutsui 
    621  1.1  tsutsui   markexts(vbm, &vol->mdb.drXTExtRec);
    622  1.1  tsutsui   markexts(vbm, &vol->mdb.drCTExtRec);
    623  1.1  tsutsui 
    624  1.1  tsutsui   vol->flags |= HFS_UPDATE_VBM;
    625  1.1  tsutsui 
    626  1.1  tsutsui   /* scavenge the extents overflow file */
    627  1.1  tsutsui 
    628  1.1  tsutsui   n.bt   = &vol->ext;
    629  1.1  tsutsui   n.nnum = vol->ext.hdr.bthFNode;
    630  1.1  tsutsui 
    631  1.1  tsutsui   if (n.nnum > 0)
    632  1.1  tsutsui     {
    633  1.1  tsutsui       if (bt_getnode(&n) < 0)
    634  1.1  tsutsui 	return -1;
    635  1.1  tsutsui 
    636  1.1  tsutsui       n.rnum = 0;
    637  1.1  tsutsui 
    638  1.1  tsutsui       while (1)
    639  1.1  tsutsui 	{
    640  1.1  tsutsui 	  ExtDataRec data;
    641  1.1  tsutsui 	  unsigned char *ptr;
    642  1.1  tsutsui 
    643  1.1  tsutsui 	  while (n.rnum >= n.nd.ndNRecs)
    644  1.1  tsutsui 	    {
    645  1.1  tsutsui 	      n.nnum = n.nd.ndFLink;
    646  1.1  tsutsui 	      if (n.nnum == 0)
    647  1.1  tsutsui 		break;
    648  1.1  tsutsui 
    649  1.1  tsutsui 	      if (bt_getnode(&n) < 0)
    650  1.1  tsutsui 		return -1;
    651  1.1  tsutsui 
    652  1.1  tsutsui 	      n.rnum = 0;
    653  1.1  tsutsui 	    }
    654  1.1  tsutsui 
    655  1.1  tsutsui 	  if (n.nnum == 0)
    656  1.1  tsutsui 	    break;
    657  1.1  tsutsui 
    658  1.1  tsutsui 	  ptr = HFS_NODEREC(n, n.rnum);
    659  1.1  tsutsui 	  r_unpackextdata(HFS_RECDATA(ptr), &data);
    660  1.1  tsutsui 
    661  1.1  tsutsui 	  markexts(vbm, &data);
    662  1.1  tsutsui 
    663  1.1  tsutsui 	  ++n.rnum;
    664  1.1  tsutsui 	}
    665  1.1  tsutsui     }
    666  1.1  tsutsui 
    667  1.1  tsutsui   /* scavenge the catalog file */
    668  1.1  tsutsui 
    669  1.1  tsutsui   n.bt   = &vol->cat;
    670  1.1  tsutsui   n.nnum = vol->cat.hdr.bthFNode;
    671  1.1  tsutsui 
    672  1.1  tsutsui   if (n.nnum > 0)
    673  1.1  tsutsui     {
    674  1.1  tsutsui       if (bt_getnode(&n) < 0)
    675  1.1  tsutsui 	return -1;
    676  1.1  tsutsui 
    677  1.1  tsutsui       n.rnum = 0;
    678  1.1  tsutsui 
    679  1.1  tsutsui       while (1)
    680  1.1  tsutsui 	{
    681  1.1  tsutsui 	  CatDataRec data;
    682  1.1  tsutsui 	  unsigned char *ptr;
    683  1.1  tsutsui 
    684  1.1  tsutsui 	  while (n.rnum >= n.nd.ndNRecs)
    685  1.1  tsutsui 	    {
    686  1.1  tsutsui 	      n.nnum = n.nd.ndFLink;
    687  1.1  tsutsui 	      if (n.nnum == 0)
    688  1.1  tsutsui 		break;
    689  1.1  tsutsui 
    690  1.1  tsutsui 	      if (bt_getnode(&n) < 0)
    691  1.1  tsutsui 		return -1;
    692  1.1  tsutsui 
    693  1.1  tsutsui 	      n.rnum = 0;
    694  1.1  tsutsui 	    }
    695  1.1  tsutsui 
    696  1.1  tsutsui 	  if (n.nnum == 0)
    697  1.1  tsutsui 	    break;
    698  1.1  tsutsui 
    699  1.1  tsutsui 	  ptr = HFS_NODEREC(n, n.rnum);
    700  1.1  tsutsui 	  r_unpackcatdata(HFS_RECDATA(ptr), &data);
    701  1.1  tsutsui 
    702  1.1  tsutsui 	  if (data.cdrType == cdrFilRec)
    703  1.1  tsutsui 	    {
    704  1.1  tsutsui 	      markexts(vbm, &data.u.fil.filExtRec);
    705  1.1  tsutsui 	      markexts(vbm, &data.u.fil.filRExtRec);
    706  1.1  tsutsui 	    }
    707  1.1  tsutsui 
    708  1.1  tsutsui 	  ++n.rnum;
    709  1.1  tsutsui 	}
    710  1.1  tsutsui     }
    711  1.1  tsutsui 
    712  1.1  tsutsui   for (blks = 0, pt = vol->mdb.drNmAlBlks; pt--; )
    713  1.1  tsutsui     {
    714  1.1  tsutsui       if (! BMTST(vbm, pt))
    715  1.1  tsutsui 	++blks;
    716  1.1  tsutsui     }
    717  1.1  tsutsui 
    718  1.1  tsutsui   if (vol->mdb.drFreeBks != blks)
    719  1.1  tsutsui     {
    720  1.1  tsutsui       vol->mdb.drFreeBks = blks;
    721  1.1  tsutsui       vol->flags |= HFS_UPDATE_MDB;
    722  1.1  tsutsui     }
    723  1.1  tsutsui 
    724  1.1  tsutsui   return 0;
    725  1.1  tsutsui }
    726