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