00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #if __linux__
00035 #include <stdint.h>
00036 #endif
00037 #include <assert.h>
00038 #include <stdlib.h>
00039 #include <BufStream.H>
00040 #include "VDirChangeable.H"
00041 #include "VDirEvaluator.H"
00042 #include "VLeaf.H"
00043 #include "VestaLog.H"
00044 #include "VForward.H"
00045 #include "VMemPool.H"
00046 #include "VRConcurrency.H"
00047 #include "VestaAttribsRep.H"
00048 #include "logging.H"
00049 #include "DirShortId.H"
00050 #include "UniqueId.H"
00051 #include "FdCache.H"
00052 #include "VLogHelp.H"
00053 #include "FPShortId.H"
00054 #include "CopyShortId.H"
00055 #include "timing.H"
00056
00057 using std::fstream;
00058 using std::hex;
00059 using std::dec;
00060 using Basics::OBufStream;
00061
00062 const FP::Tag nullFPTag("");
00063 const FP::Tag uidFPTag("Textd");
00064
00066
00067 ShortId
00068 VDirChangeable::shortId() throw ()
00069 {
00070 if (VestaSource::type == VestaSource::immutableDirectory) {
00071 return (ShortId) getID();
00072 } else {
00073 return NullShortId;
00074 }
00075 }
00076
00077 VestaSource*
00078 VDCLookupResult(VDirChangeable* dir, Bit8* entry, unsigned int index)
00079 {
00080 VestaSource* result;
00081 switch (dir->type(entry)) {
00082 case VestaSource::immutableFile:
00083 case VestaSource::mutableFile:
00084 result = NEW_CONSTR(VLeaf,
00085 (dir->type(entry), (ShortId) dir->value(entry),
00086 dir->getRefCount((ShortId) dir->value(entry), 1)));
00087 result->attribs = (Bit8*) dir->attribAddr(entry);
00088 result->fptag = dir->efptag(entry);
00089
00090 if (dir->VestaSource::type == VestaSource::volatileROEDirectory) {
00091 result->longid = LongId::fromShortId(result->shortId(),
00092 &result->fptag);
00093 result->pseudoInode = result->shortId();
00094 } else if (RootLongId.isAncestorOf(dir->longid)) {
00095 result->longid = dir->longid.append(index);
00096 result->pseudoInode = result->shortId();
00097 } else {
00098 result->longid = dir->longid.append(index);
00099 result->pseudoInode = dir->indexToPseudoInode(index);
00100 }
00101 break;
00102 case VestaSource::ghost:
00103 case VestaSource::stub:
00104 case VestaSource::device:
00105 result = NEW_CONSTR(VLeaf,
00106 (dir->type(entry), (ShortId) dir->value(entry)));
00107 result->attribs = (Bit8*) dir->attribAddr(entry);
00108 result->fptag = nullFPTag;
00109 result->longid = dir->longid.append(index);
00110 result->pseudoInode = dir->indexToPseudoInode(index);
00111 break;
00112 case VestaSource::immutableDirectory:
00113 case VestaSource::appendableDirectory:
00114 {
00115 VDirChangeable* vdc =
00116 NEW_CONSTR(VDirChangeable,
00117 (dir->type(entry),
00118 (Bit8*) VMemPool::lengthenPointer(dir->value(entry))));
00119 result = vdc;
00120 result->attribs = (Bit8*) dir->attribAddr(entry);
00121 result->VestaSource::fptag = vdc->fptag();
00122 result->longid = dir->longid.append(index);
00123 result->pseudoInode = dir->indexToPseudoInode(index);
00124 }
00125 break;
00126 case VestaSource::mutableDirectory:
00127 case VestaSource::volatileDirectory:
00128 case VestaSource::volatileROEDirectory:
00129 {
00130 VDirChangeable* vdc =
00131 NEW_CONSTR(VDirChangeable,
00132 (dir->type(entry),
00133 (Bit8*) VMemPool::lengthenPointer(dir->value(entry))));
00134 result = vdc;
00135 result->attribs = (Bit8*) dir->attribAddr(entry);
00136 result->VestaSource::fptag = vdc->fptag();
00137 result->longid = dir->longid.append(index);
00138 result->pseudoInode = vdc->getID();
00139 vdc->sidref = dir->sidref;
00140 }
00141 break;
00142 case VestaSource::evaluatorDirectory:
00143 case VestaSource::evaluatorROEDirectory:
00144 result = NEW_CONSTR(VDirEvaluator,
00145 (dir->type(entry),
00146 (Bit8*) VMemPool::lengthenPointer(dir->value(entry))));
00147 result->attribs = (Bit8*) dir->attribAddr(entry);
00148 result->fptag = nullFPTag;
00149 result->longid = dir->longid.append(index);
00150 result->pseudoInode = dir->indexToPseudoInode(index);
00151 break;
00152 case VestaSource::deleted:
00153 case VestaSource::outdated:
00154 case VestaSource::gap:
00155 return NULL;
00156 default:
00157 assert(false);
00158 break;
00159 }
00160 switch (dir->VestaSource::type) {
00161 case VestaSource::appendableDirectory:
00162
00163 result->VestaSource::master = dir->masterFlag(entry);
00164 break;
00165 case VestaSource::immutableDirectory:
00166
00167 result->VestaSource::master = dir->VestaSource::master;
00168 break;
00169 case VestaSource::mutableDirectory:
00170 case VestaSource::evaluatorDirectory:
00171 case VestaSource::evaluatorROEDirectory:
00172 case VestaSource::volatileDirectory:
00173 case VestaSource::volatileROEDirectory:
00174
00175 result->VestaSource::master = true;
00176 break;
00177 default:
00178 assert(false);
00179 break;
00180 }
00181
00182 const char* val;
00183 if ((val = result->getAttribConst("#owner")) == NULL) {
00184 result->ac.owner = dir->ac.owner;
00185 } else {
00186 result->ac.owner = *result;
00187 }
00188 if ((val = result->getAttribConst("#group")) == NULL) {
00189 result->ac.group = dir->ac.group;
00190 } else {
00191 result->ac.group = *result;
00192 }
00193
00194
00195
00196
00197
00198
00199 if ((val = result->getAttribConst("#mode")) == NULL) {
00200
00201 result->ac.mode = dir->ac.mode & 0777;
00202 } else {
00203 result->ac.mode = AccessControl::parseModeBits(val);
00204 }
00205 return result;
00206 }
00207
00208 VestaSource::errorCode
00209 VDirChangeable::lookup(Arc arc, VestaSource*& result,
00210 AccessControl::Identity who, unsigned int indexOffset)
00211 throw ()
00212 {
00213
00214
00215 result = 0;
00216
00217 if (!ac.check(who, AccessControl::search))
00218 return VestaSource::noPermission;
00219
00220 Bit8* entry;
00221 unsigned int rawIndex;
00222 VDirChangeable cur = *this;
00223 for (;;) {
00224 entry = cur.findArc(arc, rawIndex, true);
00225 if (entry == NULL) {
00226
00227 Bit8* baseRep = cur.base();
00228 if (baseRep == NULL) {
00229 result = NULL;
00230 return VestaSource::notFound;
00231 }
00232 if (VestaSource::type == VestaSource::volatileDirectory ||
00233 VestaSource::type == VestaSource::volatileROEDirectory) {
00234
00235
00236 VestaSource* baseVS =
00237 NEW_CONSTR(VDirEvaluator,
00238 (VestaSource::type == volatileDirectory ?
00239 VestaSource::evaluatorDirectory :
00240 VestaSource::evaluatorROEDirectory, baseRep));
00241 baseVS->longid = longid;
00242 baseVS->pseudoInode = pseudoInode;
00243 baseVS->ac = ac;
00244 baseVS->VestaSource::master = VestaSource::master;
00245 VestaSource::errorCode err;
00246 assert(indexOffset == 0);
00247 err = baseVS->lookup(arc, result, NULL, 0);
00248 delete baseVS;
00249 return err;
00250
00251 } else {
00252
00253
00254
00255 if (cur.VestaSource::type == VestaSource::immutableDirectory) {
00256 indexOffset += 2*(cur.nextRawIndex() - 1);
00257 }
00258 cur.rep = baseRep;
00259 cur.repEndCache = NULL;
00260 cur.VestaSource::type = VestaSource::immutableDirectory;
00261 continue;
00262 }
00263 }
00264 break;
00265 }
00266 unsigned int index;
00267 if (cur.VestaSource::type == VestaSource::immutableDirectory) {
00268 index = indexOffset + 2*rawIndex;
00269 } else {
00270 assert(indexOffset == 0);
00271 index = 2*rawIndex - 1;
00272 }
00273 result = VDCLookupResult(&cur, entry, index);
00274 if (result == NULL) return VestaSource::notFound;
00275
00276 if (result->longid == NullLongId)
00277 {
00278 delete result;
00279 result = 0;
00280 return VestaSource::longIdOverflow;
00281 }
00282 if (sameAsBase(entry)) {
00283
00284
00285
00286
00287 assert(cur.VestaSource::type != VestaSource::immutableDirectory);
00288 assert(indexOffset == 0);
00289 assert(cur.rep == rep);
00290 Bit8* baseRep = base();
00291 assert(baseRep != NULL);
00292 VestaSource* baseVS;
00293 VestaSource* baseResult;
00294 if (VestaSource::type == VestaSource::volatileDirectory) {
00295 baseVS = NEW_CONSTR(VDirEvaluator,
00296 (VestaSource::evaluatorDirectory, baseRep));
00297 } else if (VestaSource::type == VestaSource::volatileROEDirectory) {
00298 baseVS = NEW_CONSTR(VDirEvaluator,
00299 (VestaSource::evaluatorROEDirectory, baseRep));
00300 } else {
00301 baseVS = NEW_CONSTR(VDirChangeable,
00302 (VestaSource::immutableDirectory, baseRep));
00303 }
00304 baseVS->longid = longid;
00305 baseVS->pseudoInode = pseudoInode;
00306 baseVS->ac = ac;
00307 baseVS->VestaSource::master = VestaSource::master;
00308 VestaSource::errorCode err;
00309 err = baseVS->lookup(arc, baseResult, NULL);
00310 if (err == VestaSource::ok) {
00311 result->longid = baseResult->longid;
00312 unsigned int baseIndex;
00313 (void) result->longid.getParent(&baseIndex);
00314 result->pseudoInode = indexToPseudoInode(baseIndex);
00315 delete baseResult;
00316 }
00317 delete baseVS;
00318 return err;
00319 }
00320 return VestaSource::ok;
00321 }
00322
00323
00324 VestaSource::errorCode
00325 VDirChangeable::lookupIndex(unsigned int index, VestaSource*& result,
00326 char* arcbuf) throw ()
00327 {
00328
00329
00330 result = 0;
00331
00332 Bit8* entry;
00333 Bit8* repBlock;
00334 VestaSource* replaced = NULL;
00335 unsigned int indexOffset = 0;
00336 if (VestaSource::type == VestaSource::immutableDirectory) {
00337
00338 if (index & 1) {
00339
00340 entry = NULL;
00341 } else {
00342
00343 VDirChangeable cur = *this;
00344 for (;;) {
00345 entry = cur.findRawIndex((index - indexOffset) >> 1,
00346 repBlock);
00347 if (entry != NULL) break;
00348
00349 Bit8* baseRep = cur.base();
00350 if (baseRep == NULL) {
00351 return VestaSource::notFound;
00352 }
00353
00354 indexOffset += 2*(cur.nextRawIndex() - 1);
00355
00356
00357
00358 cur.rep = baseRep;
00359 cur.repEndCache = NULL;
00360 }
00361 }
00362 } else {
00363 if (index & 1) {
00364
00365 entry = findRawIndex((index + 1) >> 1, repBlock);
00366 } else {
00367
00368 Bit8* baseRep = base();
00369 if (baseRep == NULL) {
00370 return VestaSource::notFound;
00371 }
00372 VestaSource* baseVS;
00373 if (VestaSource::type == VestaSource::volatileDirectory) {
00374 baseVS =
00375 NEW_CONSTR(VDirEvaluator,
00376 (VestaSource::evaluatorDirectory, baseRep));
00377 } else if (VestaSource::type == VestaSource::volatileROEDirectory) {
00378 baseVS =
00379 NEW_CONSTR(VDirEvaluator,
00380 (VestaSource::evaluatorROEDirectory, baseRep));
00381 } else {
00382 baseVS =
00383 NEW_CONSTR(VDirChangeable,
00384 (VestaSource::immutableDirectory, baseRep));
00385 }
00386 baseVS->longid = longid;
00387 baseVS->pseudoInode = pseudoInode;
00388 baseVS->ac = ac;
00389 baseVS->VestaSource::master = VestaSource::master;
00390 char myarcbuf[MAX_ARC_LEN+1];
00391 VestaSource::errorCode err =
00392 baseVS->lookupIndex(index, result, myarcbuf);
00393 delete baseVS;
00394 if (err != VestaSource::ok) return err;
00395
00396
00397 if ((result->type == VestaSource::immutableFile ||
00398 result->type == VestaSource::mutableFile) &&
00399 !RootLongId.isAncestorOf(longid) &&
00400 VestaSource::type != VestaSource::volatileROEDirectory) {
00401 result->pseudoInode = indexToPseudoInode(index);
00402 }
00403
00404
00405
00406 unsigned int dummyRawIndex;
00407 entry = findArc(myarcbuf, dummyRawIndex, true, true);
00408 if (entry != NULL && sameAsBase(entry)) {
00409
00410
00411
00412
00413 replaced = result;
00414 } else {
00415
00416 if (arcbuf != NULL) strcpy(arcbuf, myarcbuf);
00417 return VestaSource::ok;
00418 }
00419 }
00420 }
00421 if (entry == NULL) {
00422 result = NULL;
00423 assert(replaced == NULL);
00424 return VestaSource::notFound;
00425 }
00426 if ((type(entry) == VestaSource::deleted ||
00427 type(entry) == VestaSource::outdated) && value(entry) != 0) {
00428
00429 LongId result_longid = longid.append(index);
00430 if(result_longid == NullLongId)
00431 {
00432 return VestaSource::longIdOverflow;
00433 }
00434
00435 VForward* vf = (VForward*) VMemPool::lengthenPointer(value(entry));
00436 result = vf->longid()->lookup();
00437 if (replaced != NULL) delete replaced;
00438 if (result == NULL) return VestaSource::notFound;
00439 result->longid = result_longid;
00440
00441 if ((result->type == VestaSource::immutableFile ||
00442 result->type == VestaSource::mutableFile) &&
00443 !RootLongId.isAncestorOf(longid) &&
00444 VestaSource::type != VestaSource::volatileROEDirectory) {
00445 result->pseudoInode = indexToPseudoInode(index);
00446 }
00447 return VestaSource::ok;
00448 }
00449 result = VDCLookupResult(this, entry, index);
00450 if (result == NULL) {
00451 if (replaced != NULL) delete replaced;
00452 return VestaSource::notFound;
00453 }
00454
00455 if (result->longid == NullLongId)
00456 {
00457 delete result;
00458 result = 0;
00459 return VestaSource::longIdOverflow;
00460 }
00461 if (arcbuf != NULL) {
00462 memcpy(arcbuf, arc(entry), arcLen(entry));
00463 arcbuf[arcLen(entry)] = '\000';
00464 }
00465 if (replaced != NULL) {
00466 result->longid = replaced->longid;
00467 result->pseudoInode = replaced->pseudoInode;
00468 delete replaced;
00469 }
00470 return VestaSource::ok;
00471 }
00472
00473 VestaSource::errorCode
00474 VDirChangeable::setTimestamp(time_t timestamp, AccessControl::Identity who)
00475 throw ()
00476 {
00477 if (VestaSource::type != VestaSource::mutableDirectory &&
00478 VestaSource::type != VestaSource::volatileDirectory &&
00479 VestaSource::type != VestaSource::volatileROEDirectory &&
00480 VestaSource::type != VestaSource::appendableDirectory) {
00481 return VestaSource::inappropriateOp;
00482 }
00483
00484
00485 if (!ac.check(who, AccessControl::write) &&
00486 !ac.check(who, AccessControl::ownership))
00487 return VestaSource::noPermission;
00488
00489
00490 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
00491 VestaSource::type != VestaSource::volatileROEDirectory) {
00492 char logrec[512];
00493 OBufStream ost(logrec, sizeof(logrec));
00494
00495 ost << "(time " << longid << " " << timestamp << ")\n";
00496 VRLog.start();
00497 VRLog.put(ost.str());
00498 VRLog.commit();
00499 }
00500
00501 setTimestampField(timestamp);
00502 if (VestaSource::type == VestaSource::mutableDirectory) setSnapshot(0);
00503 return VestaSource::ok;
00504 }
00505
00506 static void
00507 unlinkSid(ShortId sid)
00508 {
00509 FdCache::flush(sid, FdCache::any);
00510 char* name = SourceOrDerived::shortIdToName(sid);
00511 Repos::dprintf(DBG_SIDDISP, "unlinking: 0x%08x\n", sid);
00512 if (!Repos::isDebugLevel(DBG_SIDNODEL)) {
00513 int ret = unlink(name);
00514 int saved_errno = errno;
00515 if (ret < 0 && saved_errno != ENOENT) {
00516 Text err_txt = Basics::errno_Text(saved_errno);
00517 Repos::dprintf(DBG_ALWAYS, "unlink %s: %s (errno = %d)\n", name,
00518 err_txt.cchars(), saved_errno);
00519 }
00520 }
00521 delete[] name;
00522 }
00523
00524 VestaSource::errorCode
00525 VDirChangeable::reallyDelete(Arc arc, AccessControl::Identity who,
00526 bool existCheck, time_t timestamp) throw ()
00527 {
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559 if (VestaSource::type != VestaSource::mutableDirectory &&
00560 VestaSource::type != VestaSource::volatileDirectory &&
00561 VestaSource::type != VestaSource::volatileROEDirectory &&
00562 VestaSource::type != VestaSource::appendableDirectory) {
00563 return VestaSource::inappropriateOp;
00564 }
00565
00566
00567 if (VestaSource::master &&
00568 VestaSource::type == VestaSource::appendableDirectory) {
00569
00570
00571 if (!ac.check(who, AccessControl::agreement))
00572 return VestaSource::nameInUse;
00573 } else {
00574 if (!ac.check(who, AccessControl::write))
00575 return VestaSource::noPermission;
00576 }
00577
00578
00579 unsigned int rawIndex;
00580 Bit8* entry = findArc(arc, rawIndex, true);
00581
00582
00583 VestaSource::errorCode inbase = VestaSource::notFound;
00584 Bit8* baseRep = base();
00585 if (baseRep != NULL) {
00586 VestaSource* baseVS;
00587 if (VestaSource::type == VestaSource::volatileDirectory) {
00588 baseVS = NEW_CONSTR(VDirEvaluator,
00589 (VestaSource::evaluatorDirectory, baseRep));
00590 } else if (VestaSource::type==VestaSource::volatileROEDirectory) {
00591 baseVS = NEW_CONSTR(VDirEvaluator,
00592 (VestaSource::evaluatorROEDirectory, baseRep));
00593 } else {
00594 baseVS = NEW_CONSTR(VDirChangeable,
00595 (VestaSource::immutableDirectory, baseRep));
00596 }
00597 baseVS->longid = longid;
00598 baseVS->ac = ac;
00599 baseVS->VestaSource::master = VestaSource::master;
00600 VestaSource* vs;
00601 inbase = baseVS->lookup(arc, vs, NULL);
00602 delete baseVS;
00603 if (inbase == VestaSource::ok) {
00604 delete vs;
00605 }
00606 }
00607
00608 if (entry == NULL) {
00609 if (existCheck) {
00610 if (inbase != VestaSource::ok) return inbase;
00611 } else {
00612 if (VRLogVersion >= 2 && inbase == VestaSource::notFound) {
00613
00614 return VestaSource::ok;
00615 }
00616 }
00617 } else {
00618 if (type(entry) == VestaSource::deleted) {
00619 if (existCheck)
00620 return VestaSource::notFound;
00621 else
00622 return VestaSource::ok;
00623 }
00624 }
00625 if (timestamp == 0) timestamp = time(0);
00626
00627
00628 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
00629 VestaSource::type != VestaSource::volatileROEDirectory) {
00630 char logrec[512];
00631 OBufStream ost(logrec, sizeof(logrec));
00632
00633 ost << "(del " << longid << " ";
00634 PutQuotedString(ost, arc);
00635 ost << " " << timestamp << ")\n";
00636 VRLog.start();
00637 VRLog.put(ost.str());
00638 VRLog.commit();
00639 }
00640
00641 VestaSource::typeTag dtype = VestaSource::deleted;
00642 if (VRLogVersion >= 2 && inbase == VestaSource::notFound) {
00643
00644
00645
00646 dtype = VestaSource::outdated;
00647 }
00648 if (entry == NULL) {
00649 appendEntry(true, true, dtype, 0, 0, NULL, arc, strlen(arc));
00650 } else {
00651 VestaSource::typeTag etype = type(entry);
00652 if (etype == VestaSource::mutableFile &&
00653 VestaSource::type == VestaSource::mutableDirectory) {
00654
00655
00656
00657 assert(!doLogging || (sidref != 0));
00658
00659
00660 if((sidref != 0) &&
00661 (sidref->Decrement(value(entry), false) == 0))
00662 {
00663
00664
00665
00666
00667
00668 if(doLogging && (VRLog.nesting() == 0))
00669 unlinkSid((ShortId) value(entry));
00670 }
00671 } else if (etype == VestaSource::mutableFile &&
00672 (VestaSource::type == VestaSource::volatileDirectory ||
00673 VestaSource::type == VestaSource::volatileROEDirectory)) {
00674
00675 if(sidref->Decrement(value(entry), false) == 0)
00676 {
00677 unlinkSid(value(entry));
00678 }
00679 } else if (etype == VestaSource::volatileDirectory ||
00680 etype == VestaSource::volatileROEDirectory ||
00681 etype == VestaSource::mutableDirectory) {
00682
00683
00684
00685
00686
00687
00688 VDirChangeable vdc(etype,
00689 (Bit8*)VMemPool::lengthenPointer(value(entry)));
00690 vdc.sidref = this->sidref;
00691 vdc.freeTree();
00692 }
00693 setEntry(entry, true, sameAsBase(entry), dtype, 0, 0, NULL);
00694 }
00695 if (timestamp > this->timestamp()) {
00696 setTimestampField(timestamp);
00697 }
00698 if (VestaSource::type == VestaSource::mutableDirectory) setSnapshot(0);
00699
00700 return VestaSource::ok;
00701 }
00702
00703
00704
00705
00706 VestaSource::errorCode
00707 VDirChangeable::insertCommon(Arc arc, bool mast,
00708 VestaSource::typeTag newtype,
00709 AccessControl::Identity who,
00710 VestaSource::dupeCheck chk,
00711 const char** setOwner, ShortId* delsid,
00712 Bit32* attribs) throw ()
00713 {
00714 unsigned int rawIndex;
00715 VestaSource::errorCode err;
00716
00717 *delsid = NullShortId;
00718 if (arc[0] == '\0') return VestaSource::notFound;
00719
00720
00721
00722 if (!ac.check(who, AccessControl::write))
00723 return VestaSource::noPermission;
00724
00725
00726
00727
00728
00729 Bit8* entry = findArc(arc, rawIndex, true);
00730
00731
00732
00733 if (VestaSource::type == appendableDirectory) {
00734 if (entry) {
00735
00736
00737
00738
00739
00740
00741 if (masterFlag(entry) != mast) {
00742 if (!ac.check(who, AccessControl::agreement))
00743 return VestaSource::notMaster;
00744 }
00745 if (!((mast && type(entry) == stub) ||
00746 (mast && newtype == ghost) ||
00747 (!mast && newtype == stub) ||
00748 (!mast && newtype == ghost))) {
00749 if (!ac.check(who, AccessControl::agreement))
00750 return VestaSource::nameInUse;
00751 }
00752
00753
00754
00755 if(newtype == ghost)
00756 {
00757 if (!ac.check(who, AccessControl::del))
00758 return VestaSource::noPermission;
00759 }
00760
00761
00762
00763 if(attribs &&
00764 (type(entry) == stub || newtype == stub || newtype == ghost)) {
00765 *attribs = attrib(entry);
00766 }
00767 } else {
00768
00769
00770 if (!(this->VestaSource::master && mast)) {
00771 if (!ac.check(who, AccessControl::agreement))
00772 return VestaSource::notMaster;
00773 }
00774 }
00775 }
00776
00777
00778
00779 switch (chk) {
00780 case VestaSource::replaceDiff:
00781 case VestaSource::replaceNonMaster:
00782
00783 if (entry != NULL) {
00784 if (chk == VestaSource::replaceNonMaster && masterFlag(entry)) {
00785 return VestaSource::nameInUse;
00786 }
00787
00788 if (type(entry) == VestaSource::mutableFile) {
00789 if (VestaSource::type == mutableDirectory) {
00790
00791
00792
00793 assert(!doLogging || (sidref != 0));
00794
00795
00796
00797 if((sidref != 0) &&
00798 (sidref->Decrement(value(entry), false) == 0))
00799 {
00800 if(doLogging && VRLog.nesting() == 0)
00801
00802 *delsid = value(entry);
00803 }
00804
00805 } else if (VestaSource::type == volatileDirectory ||
00806 VestaSource::type == volatileROEDirectory) {
00807 assert(sidref != 0);
00808
00809
00810
00811 if(sidref->Decrement(value(entry), false) == 0)
00812 {
00813 unlinkSid(value(entry));
00814 }
00815 }
00816 }
00817
00818 if (type(entry) != VestaSource::deleted) {
00819 setValue(entry, 0);
00820 setAttrib(entry, 0);
00821 }
00822 setType(entry, VestaSource::outdated);
00823 }
00824 break;
00825
00826 case VestaSource::dontReplace:
00827
00828 if (entry == NULL) {
00829
00830 Bit8* baseRep = base();
00831 if (baseRep != NULL) {
00832 VestaSource* baseVS;
00833 if (VestaSource::type == VestaSource::volatileDirectory) {
00834 baseVS =
00835 NEW_CONSTR(VDirEvaluator,
00836 (VestaSource::evaluatorDirectory, baseRep));
00837 } else if (VestaSource::type ==
00838 VestaSource::volatileROEDirectory) {
00839 baseVS =
00840 NEW_CONSTR(VDirEvaluator,
00841 (VestaSource::evaluatorROEDirectory,
00842 baseRep));
00843 } else {
00844 baseVS =
00845 NEW_CONSTR(VDirChangeable,
00846 (VestaSource::immutableDirectory,
00847 baseRep));
00848 }
00849 baseVS->longid = longid;
00850 baseVS->ac = ac;
00851 baseVS->VestaSource::master = VestaSource::master;
00852 VestaSource* vs;
00853 err = baseVS->lookup(arc, vs, NULL);
00854 delete baseVS;
00855 if (err == VestaSource::ok) {
00856 delete vs;
00857 return VestaSource::nameInUse;
00858 } else if (err != VestaSource::notFound) {
00859 return err;
00860 }
00861 }
00862 } else {
00863 if (type(entry) == VestaSource::deleted) {
00864
00865 setType(entry, VestaSource::outdated);
00866 } else {
00867 assert(type(entry) != VestaSource::outdated);
00868 return VestaSource::nameInUse;
00869 }
00870 }
00871 break;
00872 }
00873
00874
00875
00876
00877
00878
00879
00880 if (setOwner) {
00881 if (mast && who && !ac.owner.inAttribs("#owner", who->user(0))) {
00882 *setOwner = who->user(0);
00883 } else {
00884 *setOwner = NULL;
00885 }
00886 }
00887 if (VestaSource::type == VestaSource::mutableDirectory) {
00888 setSnapshot(0);
00889 }
00890 return VestaSource::ok;
00891 }
00892
00893 VestaSource::errorCode
00894 VDirChangeable::insertFile(Arc arc, ShortId sid, bool mast,
00895 AccessControl::Identity who,
00896 VestaSource::dupeCheck chk,
00897 VestaSource** newvsp, time_t timestamp,
00898 FP::Tag* forceFPTag) throw ()
00899 {
00900 if (newvsp) *newvsp = NULL;
00901 if (VestaSource::type != VestaSource::appendableDirectory &&
00902 VestaSource::type != VestaSource::mutableDirectory &&
00903 VestaSource::type != VestaSource::volatileDirectory &&
00904 VestaSource::type != VestaSource::volatileROEDirectory) {
00905 return VestaSource::inappropriateOp;
00906 }
00907 int arcLen = strlen(arc);
00908 if (arcLen > MAX_ARC_LEN) return VestaSource::nameTooLong;
00909 if (sid == NullShortId) return VestaSource::invalidArgs;
00910
00911 VestaSource::errorCode err;
00912 const char* setOwner;
00913 ShortId delsid;
00914 Bit32 attribs = 0;
00915
00916
00917
00918
00919 LongId new_longid;
00920 unsigned int index = 2*nextRawIndex() - 1;
00921 if(VestaSource::type != VestaSource::volatileROEDirectory) {
00922 new_longid = longid.append(index);
00923 if(new_longid == NullLongId)
00924 {
00925 return VestaSource::longIdOverflow;
00926 }
00927 }
00928
00929 err = insertCommon(arc, mast, immutableFile, who, chk,
00930 &setOwner, &delsid, &attribs);
00931 if (err != VestaSource::ok) return err;
00932 if (timestamp == 0) timestamp = time(0);
00933
00934 FP::Tag childFPTag;
00935 if (forceFPTag != NULL) {
00936 childFPTag = *forceFPTag;
00937 } else if (VestaSource::type == VestaSource::appendableDirectory) {
00938 childFPTag = VestaSource::fptag;
00939 childFPTag.Extend("/");
00940 childFPTag.Extend(arc);
00941 } else if (VestaSource::type == VestaSource::volatileDirectory ||
00942 VestaSource::type == VestaSource::volatileROEDirectory) {
00943 childFPTag = uidFPTag;
00944 childFPTag.Extend(UniqueId());
00945 } else {
00946 childFPTag = nullFPTag;
00947 }
00948 Bit8* entry = appendEntry(mast, false, VestaSource::immutableFile,
00949 (Bit32) sid, attribs, &childFPTag, arc, arcLen);
00950 if (VestaSource::type == VestaSource::appendableDirectory) {
00951 SetFPFileShortId(entry);
00952 }
00953 if (timestamp > this->timestamp()) {
00954 setTimestampField(timestamp);
00955 } else {
00956 setTimestampField(this->timestamp() + 1);
00957 }
00958 VestaSource* newvs = NULL;
00959 if (newvsp || setOwner) {
00960 newvs = NEW_CONSTR(VLeaf, (VestaSource::immutableFile, sid));
00961 if (VestaSource::type == VestaSource::volatileROEDirectory) {
00962 newvs->longid = LongId::fromShortId(sid, &childFPTag);
00963 newvs->pseudoInode = sid;
00964 } else if (RootLongId.isAncestorOf(longid)) {
00965 newvs->longid = new_longid;
00966 newvs->pseudoInode = sid;
00967 } else {
00968 newvs->longid = new_longid;
00969 newvs->pseudoInode = indexToPseudoInode(index);
00970 }
00971 newvs->master = mast;
00972 newvs->attribs = (Bit8*) attribAddr(entry);
00973 newvs->ac = this->ac;
00974 newvs->fptag = childFPTag;
00975 }
00976
00977
00978 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
00979 VestaSource::type != VestaSource::volatileROEDirectory) {
00980 char logrec[512];
00981 OBufStream ost(logrec, sizeof(logrec));
00982
00983
00984 ost << "(insf " << longid << " ";
00985 PutQuotedString(ost, arc);
00986 ost << " 0x" << hex << sid << dec << " "
00987 << (int) mast << " " << timestamp;
00988 if (forceFPTag) {
00989 ost << " ";
00990 PutFPTag(ost, *forceFPTag);
00991 }
00992 ost << ")\n";
00993 VRLog.start();
00994 VRLog.put(ost.str());
00995 if (setOwner) {
00996
00997 newvs->setAttrib("#owner", setOwner, NULL);
00998 newvs->ac.owner = *newvs;
00999 }
01000 VRLog.commit();
01001 }
01002
01003 if (delsid != NullShortId) unlinkSid(delsid);
01004 if (newvsp) {
01005 *newvsp = newvs;
01006 } else {
01007 if (newvs) delete newvs;
01008 }
01009 return VestaSource::ok;
01010 }
01011
01012
01013 VestaSource::errorCode
01014 VDirChangeable::insertMutableFile(Arc arc, ShortId sid, bool mast,
01015 AccessControl::Identity who,
01016 VestaSource::dupeCheck chk,
01017 VestaSource** newvsp, time_t timestamp)
01018 throw ()
01019 {
01020 if (newvsp) *newvsp = NULL;
01021 if (VestaSource::type != VestaSource::mutableDirectory &&
01022 VestaSource::type != VestaSource::volatileDirectory &&
01023 VestaSource::type != VestaSource::volatileROEDirectory) {
01024 return VestaSource::inappropriateOp;
01025 }
01026 int arcLen = strlen(arc);
01027 if (arcLen > MAX_ARC_LEN) return VestaSource::nameTooLong;
01028 VestaSource::errorCode err;
01029 const char* setOwner;
01030 ShortId delsid;
01031
01032
01033
01034
01035 LongId new_longid;
01036 unsigned int index = 2*nextRawIndex() - 1;
01037 if(VestaSource::type != VestaSource::volatileROEDirectory) {
01038 new_longid = longid.append(index);
01039 if(new_longid == NullLongId)
01040 {
01041 return VestaSource::longIdOverflow;
01042 }
01043 }
01044
01045 err = insertCommon(arc, mast, mutableFile, who, chk,
01046 &setOwner, &delsid);
01047 if (err != VestaSource::ok) return err;
01048 if (timestamp == 0) timestamp = time(0);
01049 if (sid == NullShortId) {
01050
01051
01052 int fd = SourceOrDerived::fdcreate(sid);
01053 close(fd);
01054 }
01055
01056 FP::Tag childFPTag;
01057 if (VestaSource::type == VestaSource::volatileDirectory ||
01058 VestaSource::type == VestaSource::volatileROEDirectory) {
01059 childFPTag = uidFPTag;
01060 childFPTag.Extend(UniqueId());
01061 } else {
01062 childFPTag = nullFPTag;
01063 }
01064 unsigned int link_count = 1;
01065 if(sidref != 0)
01066 {
01067 RECORD_TIME_POINT;
01068 link_count = sidref->Increment(sid);
01069 RECORD_TIME_POINT;
01070 }
01071 Bit8* entry = appendEntry(mast, false, VestaSource::mutableFile,
01072 (Bit32) sid, 0, &childFPTag, arc, arcLen);
01073
01074 if (timestamp > this->timestamp()) {
01075 setTimestampField(timestamp);
01076 } else {
01077 setTimestampField(this->timestamp() + 1);
01078 }
01079 VestaSource* newvs = NULL;
01080 if (newvsp || setOwner) {
01081 newvs = NEW_CONSTR(VLeaf, (VestaSource::mutableFile, sid, link_count));
01082 if (VestaSource::type == VestaSource::volatileROEDirectory) {
01083 newvs->longid = LongId::fromShortId(sid, &childFPTag);
01084 newvs->pseudoInode = sid;
01085 } else {
01086 newvs->longid = new_longid;
01087 newvs->pseudoInode = indexToPseudoInode(index);
01088 }
01089 newvs->master = mast;
01090 newvs->attribs = (Bit8*) attribAddr(entry);
01091 newvs->ac = this->ac;
01092 newvs->fptag = childFPTag;
01093 }
01094
01095
01096 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01097 VestaSource::type != VestaSource::volatileROEDirectory) {
01098 char logrec[512];
01099 OBufStream ost(logrec, sizeof(logrec));
01100
01101 ost << "(insu " << longid << " ";
01102 PutQuotedString(ost, arc);
01103 ost << " 0x" << hex << sid << dec << " "
01104 << (int) mast << " " << timestamp << ")\n";
01105 VRLog.start();
01106 VRLog.put(ost.str());
01107 if (setOwner) {
01108
01109 newvs->setAttrib("#owner", setOwner, NULL);
01110 newvs->ac.owner = *newvs;
01111 }
01112 VRLog.commit();
01113 }
01114 if (delsid != NullShortId) unlinkSid(delsid);
01115 if (newvsp) {
01116 *newvsp = newvs;
01117 } else {
01118 if (newvs) delete newvs;
01119 }
01120 return VestaSource::ok;
01121 }
01122
01123
01124 VestaSource::errorCode
01125 VDirChangeable::insertImmutableDirectory(Arc arc, VestaSource* dir,
01126 bool mast,
01127 AccessControl::Identity who,
01128 VestaSource::dupeCheck chk,
01129 VestaSource** newvsp,
01130 time_t timestamp, FP::Tag* forceFPTag)
01131 throw ()
01132 {
01133 if (newvsp) *newvsp = NULL;
01134 if ((VestaSource::type != VestaSource::appendableDirectory &&
01135 VestaSource::type != VestaSource::mutableDirectory) ||
01136 (dir != NULL &&
01137 dir->VestaSource::type != VestaSource::mutableDirectory &&
01138 dir->VestaSource::type != VestaSource::immutableDirectory)) {
01139
01140 return VestaSource::inappropriateOp;
01141 }
01142
01143 if (dir != NULL && !dir->ac.check(who, AccessControl::read))
01144 return VestaSource::noPermission;
01145
01146
01147 int arcLen = strlen(arc);
01148 if (arcLen > MAX_ARC_LEN) return VestaSource::nameTooLong;
01149 VestaSource::errorCode err;
01150 const char* setOwner;
01151 ShortId delsid;
01152 Bit32 attribs = 0;
01153
01154
01155 unsigned int index = 2*nextRawIndex() - 1;
01156 LongId new_longid = longid.append(index);
01157 if(new_longid == NullLongId)
01158 {
01159 return VestaSource::longIdOverflow;
01160 }
01161
01162 err = insertCommon(arc, mast, immutableDirectory, who, chk,
01163 &setOwner, &delsid, &attribs);
01164 if (err != VestaSource::ok) return err;
01165 if (timestamp == 0) timestamp = time(0);
01166
01167 VestaSource* newvs;
01168 if (dir && dir->VestaSource::type == VestaSource::immutableDirectory) {
01169 VDirChangeable* newvdc =
01170 NEW_CONSTR(VDirChangeable,
01171 (VestaSource::immutableDirectory, dir->rep));
01172 newvs = newvdc;
01173 newvs->fptag = newvdc->fptag();
01174 if (forceFPTag && *forceFPTag != newvs->fptag) {
01175 delete newvdc;
01176 return VestaSource::invalidArgs;
01177 }
01178 } else {
01179 FP::Tag childFPTag;
01180 if (forceFPTag != NULL) {
01181 childFPTag = *forceFPTag;
01182 } else {
01183 childFPTag = VestaSource::fptag;
01184 childFPTag.Extend("/");
01185 childFPTag.Extend(arc);
01186 }
01187 if (dir == NULL) {
01188
01189 VDirChangeable* newvdc =
01190 NEW_CONSTR(VDirChangeable,
01191 (VestaSource::immutableDirectory, 0));
01192 newvdc->setTimestampField(timestamp);
01193 newvdc->setID(NewDirShortId(childFPTag,
01194 VMemPool::shortenPointer(newvdc->rep)));
01195 newvdc->setFPTag(childFPTag);
01196 newvs = newvdc;
01197 newvs->fptag = childFPTag;
01198 SetFPDirShortId(newvdc->rep);
01199 } else {
01200
01201
01202
01203 VDirChangeable* newvdc =
01204 ((VDirChangeable*) dir)->copyMutableToImmutable(childFPTag);
01205 newvs = newvdc;
01206 newvs->fptag = newvdc->fptag();
01207 }
01208 }
01209 Bit8* entry = appendEntry(mast, false, newvs->type,
01210 VMemPool::shortenPointer(newvs->rep),
01211 attribs, NULL, arc, arcLen);
01212 if (timestamp > this->timestamp()) {
01213 setTimestampField(timestamp);
01214 } else {
01215 setTimestampField(this->timestamp() + 1);
01216 }
01217 newvs->longid = new_longid;
01218 newvs->master = mast;
01219 newvs->attribs = (Bit8*) attribAddr(entry);
01220
01221 newvs->ac = this->ac;
01222 newvs->pseudoInode = indexToPseudoInode(index);
01223
01224
01225 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01226 VestaSource::type != VestaSource::volatileROEDirectory) {
01227 char logrec[512];
01228 OBufStream ost(logrec, sizeof(logrec));
01229
01230
01231
01232 ost << "(insi " << longid << " ";
01233 PutQuotedString(ost, arc);
01234 ost << " " << ((dir == NULL) ? NullLongId : dir->longid) << " "
01235 << (int) mast << " " << timestamp;
01236 if (forceFPTag) {
01237 ost << " ";
01238 PutFPTag(ost, *forceFPTag);
01239 }
01240 ost << ")\n";
01241 VRLog.start();
01242 VRLog.put(ost.str());
01243 if (setOwner) {
01244
01245 newvs->setAttrib("#owner", setOwner, NULL);
01246 newvs->ac.owner = *newvs;
01247 }
01248 VRLog.commit();
01249 }
01250
01251 if (delsid != NullShortId) unlinkSid(delsid);
01252 if (newvsp) {
01253 *newvsp = newvs;
01254 } else {
01255 delete newvs;
01256 }
01257 return VestaSource::ok;
01258 }
01259
01260
01261 VestaSource::errorCode
01262 VDirChangeable::insertAppendableDirectory(Arc arc, bool mast,
01263 AccessControl::Identity who,
01264 VestaSource::dupeCheck chk,
01265 VestaSource** newvsp,
01266 time_t timestamp) throw ()
01267 {
01268 if (newvsp) *newvsp = NULL;
01269 if (VestaSource::type != VestaSource::appendableDirectory) {
01270 return VestaSource::inappropriateOp;
01271 }
01272 int arcLen = strlen(arc);
01273 if (arcLen > MAX_ARC_LEN) return VestaSource::nameTooLong;
01274 VestaSource::errorCode err;
01275 const char* setOwner;
01276 ShortId delsid;
01277 Bit32 attribs = 0;
01278
01279
01280 unsigned int index = 2*nextRawIndex() - 1;
01281 LongId new_longid = longid.append(index);
01282 if(new_longid == NullLongId)
01283 {
01284 return VestaSource::longIdOverflow;
01285 }
01286
01287 err = insertCommon(arc, mast, appendableDirectory, who, chk,
01288 &setOwner, &delsid, &attribs);
01289 if (err != VestaSource::ok) return err;
01290 if (timestamp == 0) timestamp = time(0);
01291
01292 VDirChangeable* newvs =
01293 NEW_CONSTR(VDirChangeable,
01294 (VestaSource::appendableDirectory, defaultRepSize));
01295
01296 FP::Tag childFPTag = VestaSource::fptag;
01297 childFPTag.Extend("/");
01298 childFPTag.Extend(arc);
01299
01300 Bit8* entry =
01301 appendEntry(mast, false, VestaSource::appendableDirectory,
01302 VMemPool::shortenPointer(newvs->rep), attribs, NULL,
01303 arc, arcLen);
01304 if (timestamp > this->timestamp()) {
01305 setTimestampField(timestamp);
01306 } else {
01307 setTimestampField(this->timestamp() + 1);
01308 }
01309 newvs->setTimestampField(timestamp);
01310
01311 newvs->longid = new_longid;
01312 newvs->VestaSource::master = mast;
01313 newvs->attribs = (Bit8*) attribAddr(entry);
01314 newvs->ac = this->ac;
01315 newvs->pseudoInode = indexToPseudoInode(index);
01316 newvs->VestaSource::fptag = childFPTag;
01317 newvs->setFPTag(childFPTag);
01318
01319
01320 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01321 VestaSource::type != VestaSource::volatileROEDirectory) {
01322 char logrec[512];
01323 OBufStream ost(logrec, sizeof(logrec));
01324
01325 ost << "(insa " << longid << " ";
01326 PutQuotedString(ost, arc);
01327 ost << " " << (int) mast << " " << timestamp << ")\n";
01328 VRLog.start();
01329 VRLog.put(ost.str());
01330 if (setOwner) {
01331
01332 newvs->VestaSource::setAttrib("#owner", setOwner, NULL);
01333 newvs->ac.owner = *newvs;
01334 }
01335 VRLog.commit();
01336 }
01337
01338 assert(delsid == NullShortId);
01339 if (newvsp) {
01340 *newvsp = newvs;
01341 } else {
01342 delete newvs;
01343 }
01344 return VestaSource::ok;
01345 }
01346
01347
01348 VestaSource::errorCode
01349 VDirChangeable::insertMutableDirectory(Arc arc, VestaSource* dir,
01350 bool mast,
01351 AccessControl::Identity who,
01352 VestaSource::dupeCheck chk,
01353 VestaSource** newvsp, time_t timestamp)
01354 throw ()
01355 {
01356 if (newvsp) *newvsp = NULL;
01357
01358 switch (VestaSource::type) {
01359 case VestaSource::mutableDirectory:
01360 if (dir != NULL &&
01361 dir->VestaSource::type != VestaSource::immutableDirectory) {
01362 return VestaSource::inappropriateOp;
01363 }
01364 break;
01365 case VestaSource::volatileDirectory:
01366 if (dir != NULL &&
01367 dir->VestaSource::type != VestaSource::evaluatorDirectory) {
01368 return VestaSource::inappropriateOp;
01369 }
01370 break;
01371 case VestaSource::volatileROEDirectory:
01372 if (dir != NULL &&
01373 dir->VestaSource::type != VestaSource::evaluatorROEDirectory) {
01374 return VestaSource::inappropriateOp;
01375 }
01376 break;
01377 default:
01378 return VestaSource::inappropriateOp;
01379 }
01380 if (dir != NULL && !dir->ac.check(who, AccessControl::read))
01381 return VestaSource::noPermission;
01382
01383 int arcLen = strlen(arc);
01384 if (arcLen > MAX_ARC_LEN) return VestaSource::nameTooLong;
01385 VestaSource::errorCode err;
01386 const char* setOwner;
01387 ShortId delsid;
01388
01389
01390 unsigned int index = 2*nextRawIndex() - 1;
01391 LongId new_longid = longid.append(index);
01392 if(new_longid == NullLongId)
01393 {
01394 return VestaSource::longIdOverflow;
01395 }
01396
01397 err = insertCommon(arc, mast, mutableDirectory, who, chk,
01398 &setOwner, &delsid);
01399 if (err != VestaSource::ok) return err;
01400 if (timestamp == 0) timestamp = time(0);
01401
01402 VDirChangeable* newvs =
01403 NEW_CONSTR(VDirChangeable,
01404 (VestaSource::type, defaultRepSize));
01405 if (dir == NULL) {
01406 newvs->setIsMoreOrBase(newvs->rep, isNeither);
01407 newvs->setTimestampField(timestamp);
01408 newvs->setSnapshot(0);
01409 } else {
01410 newvs->setIsMoreOrBase(newvs->rep, isBase);
01411 Bit32 baseSP = VMemPool::shortenPointer(dir->rep);
01412 newvs->setMoreOrBase(newvs->rep, baseSP);
01413 newvs->baseCache = dir->rep;
01414 newvs->setTimestampField(dir->timestamp());
01415 newvs->setSnapshot(baseSP);
01416 }
01417 newvs->VestaSource::fptag = nullFPTag;
01418
01419 newvs->pseudoInode = indexToPseudoInode(index);
01420 newvs->setID(newvs->pseudoInode);
01421 Bit8* entry =
01422 appendEntry(mast, false,
01423 newvs->VestaSource::type,
01424 VMemPool::shortenPointer(newvs->rep), 0,
01425 NULL, arc, arcLen);
01426 if (timestamp > this->timestamp()) {
01427 setTimestampField(timestamp);
01428 } else {
01429 setTimestampField(this->timestamp() + 1);
01430 }
01431 newvs->longid = new_longid;
01432 newvs->VestaSource::master = mast;
01433 newvs->attribs = (Bit8*) attribAddr(entry);
01434 newvs->ac = this->ac;
01435 newvs->sidref = this->sidref;
01436
01437
01438 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01439 VestaSource::type != VestaSource::volatileROEDirectory) {
01440 char logrec[512];
01441 OBufStream ost(logrec, sizeof(logrec));
01442
01443
01444 ost << "(insm " << longid << " ";
01445 PutQuotedString(ost, arc);
01446 ost << " " << ((dir == NULL) ? NullLongId : dir->longid);
01447 ost << " " << (int) mast << " " << timestamp << ")\n";
01448 VRLog.start();
01449 VRLog.put(ost.str());
01450 if (setOwner) {
01451
01452 newvs->VestaSource::setAttrib("#owner", setOwner, NULL);
01453 newvs->ac.owner = *newvs;
01454 }
01455 VRLog.commit();
01456 }
01457
01458 if (delsid != NullShortId) unlinkSid(delsid);
01459 if (newvsp) {
01460 *newvsp = newvs;
01461 } else {
01462 delete newvs;
01463 }
01464 return VestaSource::ok;
01465 }
01466
01467 VestaSource::errorCode
01468 VDirChangeable::insertGhost(Arc arc, bool mast,
01469 AccessControl::Identity who,
01470 VestaSource::dupeCheck chk, VestaSource** newvsp,
01471 time_t timestamp) throw ()
01472 {
01473 if (newvsp) *newvsp = NULL;
01474 if (VestaSource::type != VestaSource::appendableDirectory) {
01475 return VestaSource::inappropriateOp;
01476 }
01477 int arcLen = strlen(arc);
01478 if (arcLen > MAX_ARC_LEN) return VestaSource::nameTooLong;
01479 VestaSource::errorCode err;
01480 const char* setOwner;
01481 ShortId delsid;
01482 Bit32 attribs = 0;
01483
01484
01485 unsigned int index = 2*nextRawIndex() - 1;
01486 LongId new_longid = longid.append(index);
01487 if(new_longid == NullLongId)
01488 {
01489 return VestaSource::longIdOverflow;
01490 }
01491
01492 err = insertCommon(arc, mast, ghost, who, chk,
01493 &setOwner, &delsid, &attribs);
01494 if (err != VestaSource::ok) return err;
01495 if (timestamp == 0) timestamp = time(0);
01496
01497 Bit8* entry =
01498 appendEntry(mast, false, VestaSource::ghost, 0, attribs, NULL,
01499 arc, arcLen);
01500 if (timestamp > this->timestamp()) {
01501 setTimestampField(timestamp);
01502 } else {
01503 setTimestampField(this->timestamp() + 1);
01504 }
01505 VestaSource* newvs = NULL;
01506 if (newvsp || setOwner) {
01507 newvs = NEW_CONSTR(VLeaf,
01508 (VestaSource::ghost, NullShortId));
01509 newvs->longid = new_longid;
01510 newvs->master = mast;
01511 newvs->attribs = (Bit8*) attribAddr(entry);
01512 newvs->ac = this->ac;
01513 newvs->pseudoInode = indexToPseudoInode(index);
01514 newvs->fptag = nullFPTag;
01515 }
01516
01517
01518 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01519 VestaSource::type != VestaSource::volatileROEDirectory) {
01520 char logrec[512];
01521 OBufStream ost(logrec, sizeof(logrec));
01522
01523 ost << "(insg " << longid << " ";
01524 PutQuotedString(ost, arc);
01525 ost << " " << (int) mast << " " << timestamp << ")\n";
01526 VRLog.start();
01527 VRLog.put(ost.str());
01528 if (setOwner) {
01529
01530 newvs->setAttrib("#owner", setOwner, NULL);
01531 newvs->ac.owner = *newvs;
01532 }
01533 VRLog.commit();
01534 }
01535
01536 assert(delsid == NullShortId);
01537 if (newvsp) {
01538 *newvsp = newvs;
01539 } else {
01540 if (newvs) delete newvs;
01541 }
01542 return VestaSource::ok;
01543 }
01544
01545 VestaSource::errorCode
01546 VDirChangeable::insertStub(Arc arc, bool mast, AccessControl::Identity who,
01547 VestaSource::dupeCheck chk,
01548 VestaSource** newvsp, time_t timestamp) throw ()
01549 {
01550 if (newvsp) *newvsp = NULL;
01551 if (VestaSource::type != VestaSource::appendableDirectory) {
01552 return VestaSource::inappropriateOp;
01553 }
01554 int arcLen = strlen(arc);
01555 if (arcLen > MAX_ARC_LEN) return VestaSource::nameTooLong;
01556 VestaSource::errorCode err;
01557 const char* setOwner;
01558 ShortId delsid;
01559 Bit32 attribs = 0;
01560
01561
01562 unsigned int index = 2*nextRawIndex() - 1;
01563 LongId new_longid = longid.append(index);
01564 if(new_longid == NullLongId)
01565 {
01566 return VestaSource::longIdOverflow;
01567 }
01568
01569 err = insertCommon(arc, mast, stub, who, chk,
01570 &setOwner, &delsid, &attribs);
01571 if (err != VestaSource::ok) return err;
01572 if (timestamp == 0) timestamp = time(0);
01573
01574 Bit8* entry =
01575 appendEntry(mast, false, VestaSource::stub, 0, attribs, NULL,
01576 arc, arcLen);
01577 if (timestamp > this->timestamp()) {
01578 setTimestampField(timestamp);
01579 } else {
01580 setTimestampField(this->timestamp() + 1);
01581 }
01582 VestaSource* newvs = NULL;
01583 if (newvsp || setOwner) {
01584 newvs = NEW_CONSTR(VLeaf, (VestaSource::stub, NullShortId));
01585 newvs->longid = new_longid;
01586 newvs->master = mast;
01587 newvs->attribs = (Bit8*) attribAddr(entry);
01588 newvs->ac = this->ac;
01589 newvs->pseudoInode = indexToPseudoInode(index);
01590 newvs->fptag = nullFPTag;
01591 }
01592
01593
01594 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01595 VestaSource::type != VestaSource::volatileROEDirectory) {
01596 char logrec[512];
01597 OBufStream ost(logrec, sizeof(logrec));
01598
01599 ost << "(inss " << longid << " ";
01600 PutQuotedString(ost, arc);
01601 ost << " " << (int) mast << " " << timestamp << ")\n";
01602 VRLog.start();
01603 VRLog.put(ost.str());
01604 if (setOwner) {
01605
01606 newvs->setAttrib("#owner", setOwner, NULL);
01607 newvs->ac.owner = *newvs;
01608 }
01609 VRLog.commit();
01610 }
01611
01612 assert(delsid == NullShortId);
01613 if (newvsp) {
01614 *newvsp = newvs;
01615 } else {
01616 if (newvs) delete newvs;
01617 }
01618 return VestaSource::ok;
01619 }
01620
01621
01622 bool
01623 copyOwnerCallback(void* closure, const char* value)
01624 {
01625 ((VestaSource*)closure)->addAttrib("#owner", value);
01626 return true;
01627 }
01628
01629 VestaSource::errorCode
01630 VDirChangeable::renameTo(Arc arc, VestaSource* fromDir, Arc fromArc,
01631 AccessControl::Identity who,
01632 VestaSource::dupeCheck chk, time_t timestamp) throw ()
01633 {
01634 switch (VestaSource::type) {
01635 case VestaSource::appendableDirectory:
01636 case VestaSource::mutableDirectory:
01637 case VestaSource::volatileDirectory:
01638 case VestaSource::volatileROEDirectory:
01639 if (fromDir->type != VestaSource::type ||
01640 fromDir->master != VestaSource::master) {
01641 return VestaSource::inappropriateOp;
01642 }
01643 break;
01644 default:
01645 return VestaSource::inappropriateOp;
01646 }
01647
01648 if (memcmp(&fromDir->longid.value, &this->longid.value,
01649 sizeof(LongId)) == 0) {
01650
01651 fromDir->resync();
01652 fromDir = this;
01653 }
01654
01655
01656 VestaSource::errorCode err;
01657 VestaSource* target;
01658 err = fromDir->lookup(fromArc, target, who);
01659 if (err != VestaSource::ok) return err;
01660
01661
01662 if (!fromDir->ac.check(who, AccessControl::write)) {
01663 delete target;
01664 return VestaSource::noPermission;
01665 }
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677 if (target->longid.isAncestorOf(longid)) {
01678 delete target;
01679 return VestaSource::invalidArgs;
01680 }
01681
01682
01683
01684 unsigned int rawIndex;
01685 VDirChangeable* fromVDC = (VDirChangeable*) fromDir;
01686 Bit8* oldEntry = fromVDC->findArc(fromArc, rawIndex);
01687 unsigned int index = 2*nextRawIndex() - 1;
01688 if((fromDir == this) && (oldEntry == NULL)) {
01689
01690
01691
01692 index += 2;
01693 }
01694
01695
01696
01697 LongId new_longid = longid.append(index);
01698 if(new_longid == NullLongId)
01699 {
01700 return VestaSource::longIdOverflow;
01701 }
01702
01703
01704 int arcLen = strlen(arc);
01705 if (arcLen > MAX_ARC_LEN) return VestaSource::nameTooLong;
01706 ShortId delsid;
01707 err = insertCommon(arc, target->master, target->VestaSource::type,
01708 who, chk, NULL, &delsid);
01709 if (err != VestaSource::ok) return err;
01710 if (timestamp == 0) timestamp = time(0);
01711
01712
01713 bool needOwner = false, needCommit = false;
01714 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01715 VestaSource::type != VestaSource::volatileROEDirectory) {
01716
01717
01718
01719 needOwner = (fromDir != this &&
01720 target->ac.owner.attribs != target->attribs &&
01721 this->ac.owner.attribs != target->ac.owner.attribs);
01722 assert(!needOwner || (target->ac.owner.attribs == fromDir->ac.owner.attribs));
01723 char logrec[1024];
01724 OBufStream ost(logrec, sizeof(logrec));
01725
01726 ost << "(ren " << longid << " ";
01727 PutQuotedString(ost, arc);
01728 ost << " " << fromDir->longid << " ";
01729 PutQuotedString(ost, fromArc);
01730 ost << " " << timestamp << ")\n";
01731 VRLog.start();
01732 VRLog.put(ost.str());
01733
01734 needCommit = true;
01735 }
01736 Bit32 oldAttrib = target->firstAttrib();
01737
01738
01739 if (fromDir->type == VestaSource::appendableDirectory) {
01740 if (oldEntry != NULL) {
01741
01742 fromVDC->setEntry(oldEntry, true, sameAsBase(oldEntry),
01743 VestaSource::outdated, 0, 0, NULL);
01744 }
01745
01746
01747 if (fromDir->master) {
01748 fromVDC->appendEntry(true, false, VestaSource::ghost, 0, 0,
01749 NULL, fromArc, strlen(fromArc));
01750 }
01751 } else {
01752 if (oldEntry == NULL) {
01753 fromVDC->appendEntry(true, true, VestaSource::deleted,
01754 VForward::create(new_longid),
01755 0, NULL, fromArc, strlen(fromArc));
01756 } else {
01757 VestaSource::typeTag dtype = VestaSource::deleted;
01758 if (VRLogVersion >= 2) {
01759 Bit8* baseRep = fromVDC->base();
01760 if (baseRep == NULL) {
01761
01762
01763
01764
01765 dtype = VestaSource::outdated;
01766 } else if (VRLogVersion >= 3) {
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776 VestaSource* baseVS;
01777 if (fromDir->type == VestaSource::volatileDirectory) {
01778 baseVS =
01779 NEW_CONSTR(VDirEvaluator,
01780 (VestaSource::evaluatorDirectory, baseRep));
01781 } else if (fromDir->type ==
01782 VestaSource::volatileROEDirectory) {
01783 baseVS =
01784 NEW_CONSTR(VDirEvaluator,
01785 (VestaSource::evaluatorROEDirectory, baseRep));
01786 } else {
01787 baseVS =
01788 NEW_CONSTR(VDirChangeable,
01789 (VestaSource::immutableDirectory, baseRep));
01790 }
01791 baseVS->longid = fromDir->longid;
01792 baseVS->ac = fromDir->ac;
01793 baseVS->master = fromDir->master;
01794 VestaSource* tmpVS;
01795 VestaSource::errorCode inbase =
01796 baseVS->lookup(fromArc, tmpVS, NULL);
01797 delete baseVS;
01798 if (inbase == VestaSource::ok) {
01799 delete tmpVS;
01800 } else {
01801 dtype = VestaSource::outdated;
01802 }
01803 }
01804 }
01805 fromVDC->setEntry(oldEntry, true, sameAsBase(oldEntry), dtype,
01806 VForward::create(new_longid),
01807 0, NULL);
01808 }
01809 if (fromDir->type == VestaSource::mutableDirectory) {
01810 fromVDC->setSnapshot(0);
01811 }
01812 }
01813 if (timestamp > fromVDC->timestamp()) {
01814 fromVDC->setTimestampField(timestamp);
01815 } else {
01816 fromVDC->setTimestampField(fromVDC->timestamp() + 1);
01817 }
01818
01819 if ((target->type == VestaSource::immutableDirectory &&
01820 fromDir->type == VestaSource::mutableDirectory) ||
01821 (target->type == VestaSource::evaluatorDirectory &&
01822 fromDir->type == VestaSource::volatileDirectory) ||
01823 (target->type == VestaSource::evaluatorROEDirectory &&
01824 fromDir->type == VestaSource::volatileROEDirectory)) {
01825 VDirChangeable* newtarget =
01826 NEW_CONSTR(VDirChangeable, (fromDir->type, defaultRepSize));
01827 newtarget->setIsMoreOrBase(newtarget->rep, isBase);
01828 newtarget->setMoreOrBase(newtarget->rep,
01829 VMemPool::shortenPointer(target->rep));
01830 newtarget->setID(target->pseudoInode);
01831 newtarget->setTimestampField(target->timestamp());
01832 delete target;
01833 target = newtarget;
01834 }
01835
01836
01837 Bit32 newval;
01838 switch (target->type) {
01839 case VestaSource::immutableFile:
01840 case VestaSource::mutableFile:
01841 case VestaSource::device:
01842 newval = target->shortId();
01843 break;
01844 case VestaSource::ghost:
01845 case VestaSource::stub:
01846 newval = 0;
01847 break;
01848 case VestaSource::immutableDirectory:
01849 case VestaSource::appendableDirectory:
01850 case VestaSource::mutableDirectory:
01851 case VestaSource::volatileDirectory:
01852 case VestaSource::volatileROEDirectory:
01853 case VestaSource::evaluatorDirectory:
01854 case VestaSource::evaluatorROEDirectory:
01855 newval = VMemPool::shortenPointer(target->rep);
01856 break;
01857 default:
01858 assert(false);
01859 break;
01860 }
01861 FP::Tag newFPTag;
01862 if (target->type == VestaSource::appendableDirectory) {
01863 newFPTag = VestaSource::fptag;
01864 newFPTag.Extend("/");
01865 newFPTag.Extend(arc);
01866 } else {
01867 newFPTag = target->fptag;
01868 }
01869 Bit8* newEntry =
01870 appendEntry(target->master, false, target->type, newval, oldAttrib,
01871 (target->type == VestaSource::immutableFile ||
01872 target->type == VestaSource::mutableFile) ?
01873 &newFPTag : NULL, arc, arcLen);
01874 if (VestaSource::type == VestaSource::appendableDirectory &&
01875 target->type == VestaSource::immutableFile) {
01876 SetFPFileShortId(newEntry);
01877 }
01878 if (timestamp > this->timestamp()) {
01879 setTimestampField(timestamp);
01880 } else {
01881 setTimestampField(this->timestamp() + 1);
01882 }
01883 if (delsid != NullShortId) unlinkSid(delsid);
01884
01885
01886 if(needCommit)
01887 {
01888
01889
01890
01891
01892
01893
01894 if(needOwner)
01895 {
01896 VestaSource *new_target = VDCLookupResult(this, newEntry, index);
01897
01898
01899 assert(new_target->hasAttribs());
01900 fromDir->ac.owner.getAttrib("#owner", copyOwnerCallback,
01901 new_target);
01902 delete new_target;
01903 }
01904
01905 VRLog.commit();
01906 }
01907
01908 delete target;
01909 return VestaSource::ok;
01910 }
01911
01912
01913 struct FilterListClosure {
01914 ArcTable* hidden;
01915 VestaSource::listCallback callback;
01916 void* closure;
01917 };
01918
01919 bool
01920 filterListCallback(void* closure, VestaSource::typeTag type,
01921 Arc arc, unsigned int index, Bit32 pseudoInode,
01922 ShortId filesid, bool mast) throw ()
01923 {
01924 FilterListClosure* cl = (FilterListClosure*) closure;
01925 unsigned int dummyRawIndex;
01926
01927 ArcKey k;
01928 ArcValue v;
01929 k.s = arc;
01930 k.slen = strlen(arc);
01931 if (cl->hidden->Get(k, v)) {
01932
01933 return true;
01934 } else {
01935
01936 return (cl->callback)(cl->closure, type, arc, index, pseudoInode,
01937 filesid, mast);
01938 }
01939 }
01940
01941 VestaSource::errorCode
01942 VDirChangeable::list(unsigned int firstIndex,
01943 VestaSource::listCallback callback, void* closure,
01944 AccessControl::Identity who,
01945 bool deltaOnly, unsigned int indexOffset) throw ()
01946 {
01947 unsigned int index, baseIndexOffset;
01948 Bit8* entry;
01949 Bit8* repBlock;
01950 assert((indexOffset & 1) == 0);
01951
01952
01953 if (!ac.check(who, AccessControl::read))
01954 return VestaSource::noPermission;
01955
01956 VDirChangeable cur = *this;
01957 ArcTable hidden;
01958
01959 for (;;) {
01960
01961
01962
01963 if (cur.VestaSource::type == VestaSource::immutableDirectory) {
01964 index = 2;
01965 } else {
01966 index = 1;
01967 }
01968
01969 repBlock = cur.rep;
01970 for (;;) {
01971
01972 entry = firstEntry(repBlock);
01973 while (!isEndMark(entry)) {
01974 bool skip = false;
01975
01976
01977
01978 switch (type(entry)) {
01979 default:
01980 break;
01981 case VestaSource::deleted:
01982 if (!deltaOnly) skip = true;
01983 break;
01984 case VestaSource::outdated:
01985 case VestaSource::gap:
01986 skip = true;
01987 break;
01988 }
01989
01990
01991 ArcKey k;
01992 ArcValue v;
01993 k.s = arc(entry);
01994 k.slen = arcLen(entry);
01995 if (hidden.Get(k, v)) {
01996 skip = true;
01997 } else if (type(entry) != VestaSource::outdated &&
01998 type(entry) != VestaSource::gap) {
01999 hidden.Put(k, ArcValue());
02000 }
02001
02002
02003 if (firstIndex != 0) {
02004 if (index & 1) {
02005
02006
02007 if ((firstIndex & 1) == 0 ||
02008 firstIndex > (index + indexOffset)) {
02009 skip = true;
02010 }
02011 } else {
02012
02013
02014 if ((firstIndex & 1) == 0 &&
02015 firstIndex > (index + indexOffset)) {
02016 skip = true;
02017 }
02018 }
02019 }
02020
02021 if (!skip) {
02022 char arcbuf[512];
02023 memcpy(arcbuf, arc(entry), arcLen(entry));
02024 arcbuf[arcLen(entry)] = '\000';
02025
02026
02027 Bit32 pseudi;
02028 ShortId filesid;
02029 switch (type(entry)) {
02030 case VestaSource::mutableDirectory:
02031 case VestaSource::volatileDirectory:
02032 case VestaSource::volatileROEDirectory:
02033 {
02034 filesid = NullShortId;
02035 VDirChangeable childVS(type(entry), (Bit8*) VMemPool::
02036 lengthenPointer(value(entry)));
02037 pseudi = childVS.getID();
02038 }
02039 break;
02040 case VestaSource::immutableFile:
02041 case VestaSource::mutableFile:
02042 filesid = (ShortId) value(entry);
02043 if (VestaSource::type == VestaSource::volatileROEDirectory ||
02044 RootLongId.isAncestorOf(longid)) {
02045 pseudi = filesid;
02046 } else {
02047 pseudi = indexToPseudoInode(index + indexOffset);
02048 }
02049 break;
02050 default:
02051 filesid = NullShortId;
02052 pseudi = indexToPseudoInode(index + indexOffset);
02053 break;
02054 }
02055 if (sameAsBase(entry)) {
02056
02057 assert(cur.VestaSource::type != VestaSource::immutableDirectory);
02058 assert(indexOffset == 0);
02059 assert(cur.rep == rep);
02060 Bit8* baseRep = base();
02061 VestaSource* baseVS;
02062 VestaSource* baseResult = 0;
02063 if (VestaSource::type == VestaSource::volatileDirectory) {
02064 baseVS = NEW_CONSTR(VDirEvaluator,
02065 (VestaSource::evaluatorDirectory,
02066 baseRep));
02067 } else if (VestaSource::type ==
02068 VestaSource::volatileROEDirectory) {
02069 baseVS = NEW_CONSTR(VDirEvaluator,
02070 (VestaSource::evaluatorROEDirectory,
02071 baseRep));
02072 } else {
02073 baseVS = NEW_CONSTR(VDirChangeable,
02074 (VestaSource::immutableDirectory,
02075 baseRep));
02076 }
02077 baseVS->longid = longid;
02078 baseVS->pseudoInode = pseudoInode;
02079 baseVS->ac = ac;
02080 baseVS->VestaSource::master = VestaSource::master;
02081 VestaSource::errorCode err;
02082 err = baseVS->lookup(arcbuf, baseResult, NULL);
02083 if (err != VestaSource::ok) {
02084 if(baseResult != 0)
02085 {
02086 delete baseResult;
02087 }
02088 delete baseVS;
02089 return err;
02090 }
02091 unsigned int baseIndex;
02092 (void) baseResult->longid.getParent(&baseIndex);
02093 pseudi = indexToPseudoInode(baseIndex);
02094 delete baseResult;
02095 delete baseVS;
02096 }
02097
02098 if (!callback(closure, type(entry), arcbuf, index + indexOffset,
02099 pseudi, filesid, masterFlag(entry))) {
02100
02101 return VestaSource::ok;
02102 }
02103 }
02104 if (type(entry) == VestaSource::gap) {
02105 index += 2*value(entry);
02106 } else {
02107 index += 2;
02108 }
02109 entry = nextEntry(entry);
02110 }
02111
02112
02113 if (isMoreOrBase(repBlock) == isMore) {
02114
02115 repBlock =
02116 (Bit8*) VMemPool::lengthenPointer(moreOrBase(repBlock));
02117 } else {
02118
02119 break;
02120 }
02121 }
02122
02123
02124 if (cur.VestaSource::type == VestaSource::immutableDirectory) {
02125
02126 baseIndexOffset = indexOffset + ((cur.nextRawIndex() << 1) - 2);
02127 } else {
02128 assert(indexOffset == 0);
02129 baseIndexOffset = 0;
02130 }
02131
02132
02133
02134
02135
02136 if (deltaOnly &&
02137 (VestaSource::type != VestaSource::immutableDirectory)) {
02138 return VestaSource::ok;
02139 }
02140
02141 Bit8* baseRep = cur.base();
02142 if (baseRep == NULL) return VestaSource::ok;
02143 VestaSource* baseVS;
02144 if (VestaSource::type == VestaSource::volatileDirectory ||
02145 VestaSource::type == VestaSource::volatileROEDirectory) {
02146
02147
02148 VestaSource* baseVS =
02149 NEW_CONSTR(VDirEvaluator,
02150 (VestaSource::type == volatileDirectory ?
02151 VestaSource::evaluatorDirectory :
02152 VestaSource::evaluatorROEDirectory, baseRep));
02153
02154 baseVS->longid = longid;
02155 baseVS->ac = ac;
02156 baseVS->pseudoInode = pseudoInode;
02157 baseVS->VestaSource::master = VestaSource::master;
02158 FilterListClosure cl;
02159 cl.hidden = &hidden;
02160 cl.callback = callback;
02161 cl.closure = closure;
02162 VestaSource::errorCode err =
02163 baseVS->list(((firstIndex & 1) ? 0 : firstIndex),
02164 filterListCallback, &cl, NULL,
02165 false, baseIndexOffset);
02166 delete baseVS;
02167 return err;
02168
02169 } else {
02170
02171
02172
02173 cur.rep = baseRep;
02174 cur.repEndCache = NULL;
02175 cur.VestaSource::type = VestaSource::immutableDirectory;
02176 indexOffset = baseIndexOffset;
02177 if (deltaOnly && cur.shortId() != NullShortId) {
02178 return VestaSource::ok;
02179 }
02180 }
02181 }
02182
02183
02184 }
02185
02186
02187 VestaSource::errorCode
02188 VDirChangeable::getBase(VestaSource*& result, AccessControl::Identity who)
02189 throw ()
02190 {
02191 VestaSource::errorCode ret = VestaSource::ok;
02192
02193
02194 if (!ac.check(who, AccessControl::read))
02195 return VestaSource::noPermission;
02196
02197 Bit8* baseRep = base();
02198 if (baseRep == NULL) return VestaSource::notFound;
02199
02200 if (VestaSource::type == VestaSource::volatileDirectory) {
02201 result = NEW_CONSTR(VDirEvaluator,
02202 (VestaSource::evaluatorDirectory, baseRep));
02203 } else if (VestaSource::type == VestaSource::volatileROEDirectory) {
02204 result = NEW_CONSTR(VDirEvaluator,
02205 (VestaSource::evaluatorROEDirectory,baseRep));
02206 } else {
02207 VDirChangeable *vdc =
02208 NEW_CONSTR(VDirChangeable,
02209 (VestaSource::immutableDirectory, baseRep));
02210 result = vdc;
02211 while (result->shortId() == NullShortId) {
02212 baseRep = vdc->base();
02213 if (baseRep == NULL) {
02214 delete vdc;
02215 result = NULL;
02216 return VestaSource::notFound;
02217 }
02218 vdc->rep = baseRep;
02219 vdc->repEndCache = NULL;
02220 }
02221 FP::Tag newtag;
02222 memcpy(newtag.Words(), &baseRep[VDIRCH_FPTAG], FP::ByteCnt);
02223 result->VestaSource::fptag = newtag;
02224 result->longid = LongId::fromShortId(result->shortId(), NULL);
02225 result->pseudoInode = result->shortId();
02226 }
02227 return ret;
02228 }
02229
02230 VestaSource::errorCode
02231 VDirChangeable::makeIndexMutable(unsigned int index,
02232 VestaSource*& result, ShortId sid,
02233 Basics::uint64 copyMax,
02234 AccessControl::Identity who) throw ()
02235 {
02236 if (VestaSource::type != VestaSource::mutableDirectory &&
02237 VestaSource::type != VestaSource::volatileDirectory &&
02238 VestaSource::type != VestaSource::volatileROEDirectory) {
02239 return VestaSource::inappropriateOp;
02240 }
02241
02242 if (!ac.check(who, AccessControl::write))
02243 return VestaSource::noPermission;
02244
02245 Bit8* entry;
02246 Bit8* repBlock;
02247 VestaSource::typeTag oldType, newType;
02248 Bit32 oldValue;
02249 bool oldMaster;
02250 char arc[MAX_ARC_LEN+1];
02251
02252 if (index & 1) {
02253
02254 entry = findRawIndex((index + 1) >> 1, repBlock);
02255 if (entry == NULL) return VestaSource::notFound;
02256 oldType = type(entry);
02257 oldValue = value(entry);
02258 oldMaster = masterFlag(entry);
02259 } else {
02260
02261 Bit8* baseRep = base();
02262 if (baseRep == NULL) return VestaSource::notFound;
02263
02264 VestaSource* baseVS;
02265 if (VestaSource::type == VestaSource::volatileDirectory) {
02266 baseVS =
02267 NEW_CONSTR(VDirEvaluator,
02268 (VestaSource::evaluatorDirectory, baseRep));
02269 } else if (VestaSource::type == VestaSource::volatileROEDirectory) {
02270 baseVS =
02271 NEW_CONSTR(VDirEvaluator,
02272 (VestaSource::evaluatorROEDirectory, baseRep));
02273 } else {
02274 baseVS =
02275 NEW_CONSTR(VDirChangeable,
02276 (VestaSource::immutableDirectory, baseRep));
02277 }
02278 baseVS->longid = longid;
02279 baseVS->ac = ac;
02280 baseVS->pseudoInode = pseudoInode;
02281 baseVS->VestaSource::master = VestaSource::master;
02282 VestaSource* baseres;
02283 VestaSource::errorCode err =
02284 baseVS->lookupIndex(index, baseres, arc);
02285 delete baseVS;
02286 if (err != VestaSource::ok) return err;
02287 assert(baseres->type != VestaSource::mutableDirectory &&
02288 baseres->type != VestaSource::volatileDirectory &&
02289 baseres->type != VestaSource::volatileROEDirectory);
02290
02291 oldType = baseres->type;
02292 if (oldType == VestaSource::immutableFile) {
02293 oldValue = NullShortId;
02294 } else {
02295 oldValue = VMemPool::shortenPointer(baseres->rep);
02296 }
02297 oldMaster = baseres->master;
02298 delete baseres;
02299
02300
02301
02302 unsigned int dummyRawIndex;
02303 entry = findArc(arc, dummyRawIndex, true, true);
02304 if (entry != NULL && !sameAsBase(entry)) {
02305 entry = NULL;
02306 }
02307 if (entry != NULL) {
02308 oldType = type(entry);
02309 oldValue = value(entry);
02310 oldMaster = masterFlag(entry);
02311 }
02312 }
02313 if (oldType != VestaSource::immutableFile &&
02314 oldType != VestaSource::immutableDirectory &&
02315 oldType != VestaSource::evaluatorDirectory &&
02316 oldType != VestaSource::evaluatorROEDirectory) {
02317 return VestaSource::inappropriateOp;
02318 }
02319 if (oldType == VestaSource::immutableFile && sid == NullShortId) {
02320
02321
02322
02323 int err;
02324 sid = CopyShortId(oldValue, err, copyMax);
02325 assert(sid != NullShortId);
02326 }
02327
02328
02329
02330
02331
02332 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
02333 VestaSource::type != VestaSource::volatileROEDirectory) {
02334 char logrec[512];
02335 OBufStream ost(logrec, sizeof(logrec));
02336
02337 ost << "(makm " << longid << " " << index
02338 << " 0x" << hex << sid << dec << ")\n";
02339 VRLog.start();
02340 VRLog.put(ost.str());
02341 VRLog.commit();
02342 }
02343
02344
02345 Bit32 newValue;
02346 if (oldType == VestaSource::immutableFile) {
02347 newType = VestaSource::mutableFile;
02348 newValue = (Bit32) sid;
02349 } else {
02350
02351
02352
02353 newType = VestaSource::type;
02354 VDirChangeable* dest = NEW_CONSTR(VDirChangeable,
02355 (newType, defaultRepSize));
02356 dest->setIsMoreOrBase(dest->rep, isBase);
02357 dest->setMoreOrBase(dest->rep, oldValue);
02358 dest->setTimestampField(timestamp());
02359 dest->setID(indexToPseudoInode(index));
02360 newValue = VMemPool::shortenPointer(dest->rep);
02361 delete dest;
02362 }
02363 if (entry == NULL) {
02364 entry = appendEntry(oldMaster, true, newType, newValue, 0,
02365 (newType == VestaSource::mutableFile ?
02366 &nullFPTag : NULL), arc, strlen(arc));
02367 } else {
02368 setType(entry, newType);
02369 setValue(entry, newValue);
02370 }
02371 if (VestaSource::type == VestaSource::mutableDirectory) setSnapshot(0);
02372
02373
02374 if(sidref)
02375 {
02376
02377
02378 assert((oldType != VestaSource::immutableFile) ||
02379 (sidref->GetCount(oldValue) == 0));
02380
02381
02382 assert(oldType != VestaSource::mutableFile);
02383
02384
02385
02386 if(newType == VestaSource::mutableFile)
02387 sidref->Increment(newValue);
02388 }
02389
02390 result = VDCLookupResult(this, entry, index);
02391 if (result == NULL) return VestaSource::notFound;
02392
02393 if (result->longid == NullLongId)
02394 {
02395 delete result;
02396 result = 0;
02397 return VestaSource::longIdOverflow;
02398 }
02399 return VestaSource::ok;
02400 }
02401
02402 void
02403 VDirChangeable::makeIndexImmutable(unsigned int index,
02404 const FP::Tag* newfptag, ShortId newsid)
02405 throw ()
02406 {
02407 assert(VestaSource::type == VestaSource::mutableDirectory ||
02408 VestaSource::type == VestaSource::volatileDirectory ||
02409 VestaSource::type == VestaSource::volatileROEDirectory);
02410
02411 Bit8* entry;
02412 Bit8* repBlock;
02413
02414 assert((index & 1) != 0);
02415 entry = findRawIndex((index + 1) >> 1, repBlock);
02416 assert(entry != NULL);
02417 assert(type(entry) == VestaSource::mutableFile);
02418
02419
02420
02421
02422 if (newfptag == NULL &&
02423 VestaSource::type == VestaSource::mutableDirectory) {
02424 return;
02425 }
02426
02427
02428 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
02429 VestaSource::type != VestaSource::volatileROEDirectory) {
02430 char logrec[512];
02431 OBufStream ost(logrec, sizeof(logrec));
02432
02433
02434
02435 ost << "(maki " << longid << " " << index;
02436 if (newfptag) {
02437 ost << " ";
02438 PutFPTag(ost, *newfptag);
02439 }
02440 if (newsid != NullShortId) {
02441 ost << " ";
02442 ost << "0x" << hex << newsid << dec;
02443 }
02444 ost << ")\n";
02445 VRLog.start();
02446 VRLog.put(ost.str());
02447 VRLog.commit();
02448 }
02449
02450
02451 if(sidref)
02452 sidref->Decrement(value(entry), false);
02453
02454
02455 setType(entry, VestaSource::immutableFile);
02456 if (newfptag) {
02457 setEFPTag(entry, *newfptag);
02458 }
02459 if (newsid != NullShortId) {
02460 setValue(entry, newsid);
02461 }
02462 if (VestaSource::type == VestaSource::mutableDirectory) {
02463 setSnapshot(0);
02464 }
02465 return;
02466 }
02467
02468 VestaSource::errorCode
02469 VDirChangeable::copyIndexToMutable(unsigned int index,
02470 VestaSource*& result,
02471 AccessControl::Identity who) throw ()
02472 {
02473 if (VestaSource::type != VestaSource::mutableDirectory) {
02474 return VestaSource::inappropriateOp;
02475 }
02476 if (index & 1) {
02477
02478 return VestaSource::inappropriateOp;
02479 }
02480
02481 if (!ac.check(who, AccessControl::write))
02482 return VestaSource::noPermission;
02483
02484 Bit8* entry;
02485 VestaSource::typeTag oldType;
02486 Bit32 oldValue;
02487 bool oldMaster;
02488 FP::Tag oldFptag = nullFPTag;
02489 char arc[MAX_ARC_LEN+1];
02490
02491
02492 Bit8* baseRep = base();
02493 if (baseRep == NULL) return VestaSource::notFound;
02494
02495 VestaSource* baseVS =
02496 NEW_CONSTR(VDirChangeable, (VestaSource::immutableDirectory, baseRep));
02497 baseVS->longid = longid;
02498 baseVS->ac = ac;
02499 baseVS->pseudoInode = pseudoInode;
02500 baseVS->VestaSource::master = VestaSource::master;
02501 VestaSource* baseres;
02502 VestaSource::errorCode err =
02503 baseVS->lookupIndex(index, baseres, arc);
02504 delete baseVS;
02505 if (err != VestaSource::ok) return err;
02506 assert(baseres->type == VestaSource::immutableDirectory ||
02507 baseres->type == VestaSource::immutableFile);
02508
02509 oldType = baseres->type;
02510 if (oldType == VestaSource::immutableFile) {
02511 oldValue = baseres->shortId();
02512 oldFptag = baseres->fptag;
02513 } else {
02514 oldValue = VMemPool::shortenPointer(baseres->rep);
02515 }
02516 oldMaster = baseres->master;
02517 delete baseres;
02518
02519
02520 unsigned int dummyRawIndex;
02521 entry = findArc(arc, dummyRawIndex, true);
02522 if (entry != NULL) {
02523
02524
02525
02526 return VestaSource::inappropriateOp;
02527 }
02528
02529
02530
02531
02532
02533
02534
02535
02536
02537 if (doLogging) {
02538 char logrec[512];
02539 OBufStream ost(logrec, sizeof(logrec));
02540
02541 ost << "(copy2m " << longid << " " << index << ")\n";
02542 VRLog.start();
02543 VRLog.put(ost.str());
02544 VRLog.commit();
02545 }
02546
02547 entry = appendEntry(oldMaster, true, oldType, oldValue, 0,
02548 (oldType == VestaSource::immutableFile ?
02549 &oldFptag : NULL),
02550 arc, strlen(arc));
02551
02552
02553
02554 setSnapshot(0);
02555
02556 result = VDCLookupResult(this, entry, index);
02557 if (result == NULL) return VestaSource::notFound;
02558
02559 if (result->longid == NullLongId)
02560 {
02561 delete result;
02562 result = 0;
02563 return VestaSource::longIdOverflow;
02564 }
02565 return VestaSource::ok;
02566 }
02567
02568 VestaSource::errorCode
02569 VDirChangeable::setIndexMaster(unsigned int index, bool state,
02570 AccessControl::Identity who) throw ()
02571 {
02572 if (VestaSource::type != VestaSource::appendableDirectory) {
02573 return inappropriateOp;
02574 }
02575 if (!ac.check(who, AccessControl::agreement))
02576 return VestaSource::noPermission;
02577 Bit8* entry;
02578 Bit8* repBlock;
02579
02580 if ((index & 1) == 0) return VestaSource::notFound;
02581 entry = findRawIndex((index + 1) >> 1, repBlock);
02582 if (entry == NULL) return VestaSource::notFound;
02583 switch (type(entry)) {
02584 case VestaSource::deleted:
02585 case VestaSource::outdated:
02586 case VestaSource::gap:
02587 return VestaSource::notFound;
02588 default:
02589 break;
02590 }
02591
02592 if (state == masterFlag(entry)) return VestaSource::ok;
02593
02594
02595 if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
02596 VestaSource::type != VestaSource::volatileROEDirectory) {
02597 char logrec[512];
02598 OBufStream ost(logrec, sizeof(logrec));
02599
02600 ost << "(mast " << longid << " " << index << " "
02601 << (int) state << ")\n";
02602 VRLog.start();
02603 VRLog.put(ost.str());
02604 VRLog.commit();
02605 }
02606
02607
02608 setMasterFlag(entry, state);
02609 return VestaSource::ok;
02610 }
02611
02612
02613
02614
02615
02616 void
02617 VDirChangeable::mark(bool byName, ArcTable* hidden) throw ()
02618 {
02619 bool newHidden = (hidden == NULL);
02620 if (newHidden) hidden = NEW(ArcTable);
02621
02622
02623
02624 Bit8* curRepBlock = rep;
02625 VMemPool::typeCode t = VMemPool::type(curRepBlock);
02626 assert(t == VMemPool::vDirChangeable ||
02627 t == VMemPool::vDirAppendable ||
02628 t == VMemPool::vDirImmutable);
02629 Bit8* entry;
02630 for (;;) {
02631 setVisited(curRepBlock, true);
02632 entry = firstEntry(curRepBlock);
02633 while (!isEndMark(entry)) {
02634 if (type(entry) != VestaSource::outdated &&
02635 type(entry) != VestaSource::gap) {
02636 ArcKey k;
02637 ArcValue v;
02638 k.s = arc(entry);
02639 k.slen = arcLen(entry);
02640 assert(k.slen != 0);
02641 if (!hidden->Get(k, v)) {
02642 setInUse(entry, true);
02643 hidden->Put(k, ArcValue());
02644 if(VestaSource::type == VestaSource::appendableDirectory ||
02645 VestaSource::type == VestaSource::mutableDirectory)
02646 {
02647 VestaAttribsRep* ar = (VestaAttribsRep*)
02648 VMemPool::lengthenPointer(attrib(entry));
02649 if (ar != NULL) ar->mark();
02650 }
02651 else if(attrib(entry) != 0)
02652 {
02653
02654
02655 Repos::dprintf(DBG_ALWAYS,
02656 "WARNING: attributes in a non-mutabe "
02657 "non-appendable directory; arc = \""
02658 "%.*s\", attrib short pointer = 0x%x\n",
02659 arcLen(entry), arc(entry),
02660 attrib(entry));
02661 setAttrib(entry, 0);
02662 }
02663 switch (type(entry)) {
02664 case VestaSource::immutableDirectory:
02665 case VestaSource::appendableDirectory:
02666 case VestaSource::mutableDirectory:
02667 case VestaSource::volatileDirectory:
02668 case VestaSource::volatileROEDirectory:
02669 {
02670 VDirChangeable
02671 childVS(type(entry), (Bit8*)
02672 VMemPool::lengthenPointer(value(entry)));
02673 if (!childVS.hasName()) {
02674 childVS.setHasName(true);
02675
02676
02677
02678
02679
02680 childVS.setVisited(false);
02681 }
02682 }
02683 break;
02684 case VestaSource::evaluatorDirectory:
02685 case VestaSource::evaluatorROEDirectory:
02686 {
02687 VDirEvaluator
02688 childVS(type(entry), (Bit8*)
02689 VMemPool::lengthenPointer(value(entry)));
02690 if (!childVS.hasName()) {
02691 childVS.setHasName(true);
02692 childVS.setVisited(false);
02693 }
02694 }
02695 break;
02696 case VestaSource::immutableFile:
02697 case VestaSource::mutableFile:
02698 assert((ShortId) value(entry) != NullShortId);
02699 break;
02700 default:
02701 break;
02702 }
02703 }
02704 }
02705 entry = nextEntry(entry);
02706 }
02707 if (isMoreOrBase(curRepBlock) == isMore ||
02708 (isMoreOrBase(curRepBlock) == isBase &&
02709 (VestaSource::type == VestaSource::immutableDirectory ||
02710 VestaSource::type == VestaSource::mutableDirectory))) {
02711
02712
02713
02714
02715
02716
02717
02718 curRepBlock =
02719 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
02720 VMemPool::typeCode t = VMemPool::type(curRepBlock);
02721 assert(t == VMemPool::vDirChangeable ||
02722 t == VMemPool::vDirAppendable ||
02723 t == VMemPool::vDirImmutable);
02724 if (hasName(curRepBlock)) break;
02725 } else if (isMoreOrBase(curRepBlock) == isBase) {
02726
02727 Bit8* baseRep =
02728 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
02729 if (VestaSource::type == VestaSource::volatileDirectory) {
02730 VDirEvaluator baseVS(VestaSource::evaluatorDirectory, baseRep);
02731 baseVS.mark(false, hidden);
02732 } else if (VestaSource::type == VestaSource::volatileROEDirectory){
02733 VDirEvaluator
02734 baseVS(VestaSource::evaluatorROEDirectory, baseRep);
02735 baseVS.mark(false, hidden);
02736 } else {
02737 assert(false);
02738 }
02739 break;
02740 } else {
02741 break;
02742 }
02743 }
02744
02745 if (newHidden) delete hidden;
02746
02747
02748 curRepBlock = rep;
02749 for (;;) {
02750 entry = firstEntry(curRepBlock);
02751 while (!isEndMark(entry)) {
02752 if (inUse(entry)) {
02753 switch (type(entry)) {
02754 case VestaSource::immutableDirectory:
02755 case VestaSource::appendableDirectory:
02756 case VestaSource::mutableDirectory:
02757 case VestaSource::volatileDirectory:
02758 case VestaSource::volatileROEDirectory:
02759 {
02760 VDirChangeable
02761 childVS(type(entry), (Bit8*)
02762 VMemPool::lengthenPointer(value(entry)));
02763 if (!childVS.visited()) {
02764 childVS.mark(true, NULL);
02765 }
02766 }
02767 break;
02768 case VestaSource::evaluatorDirectory:
02769 case VestaSource::evaluatorROEDirectory:
02770 {
02771 VDirEvaluator
02772 childVS(type(entry), (Bit8*)
02773 VMemPool::lengthenPointer(value(entry)));
02774 if (!childVS.visited()) {
02775 childVS.mark(true, NULL);
02776 }
02777 }
02778 break;
02779 case VestaSource::deleted:
02780 case VestaSource::outdated:
02781 if (value(entry) != 0) {
02782 if (VestaSource::type==VestaSource::immutableDirectory) {
02783
02784
02785 setValue(entry, 0);
02786 } else {
02787 VForward* vf =
02788 (VForward*) VMemPool::lengthenPointer(value(entry));
02789 assert(VMemPool::type(vf) == VMemPool::vForward);
02790
02791 VestaSource* referent = vf->longid()->lookup();
02792 if (referent == NULL) {
02793 setValue(entry, 0);
02794 } else {
02795 delete referent;
02796 vf->setVisited(true);
02797 }
02798 }
02799 }
02800 case VestaSource::gap:
02801 default:
02802 break;
02803 }
02804 }
02805 entry = nextEntry(entry);
02806 }
02807 if (isMoreOrBase(curRepBlock) == isMore ||
02808 (isMoreOrBase(curRepBlock) == isBase &&
02809 (VestaSource::type == VestaSource::immutableDirectory ||
02810 VestaSource::type == VestaSource::mutableDirectory))) {
02811
02812
02813
02814 curRepBlock =
02815 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
02816 VMemPool::typeCode t = VMemPool::type(curRepBlock);
02817 assert(t == VMemPool::vDirChangeable ||
02818 t == VMemPool::vDirAppendable ||
02819 t == VMemPool::vDirImmutable);
02820 if (hasName(curRepBlock)) break;
02821 } else {
02822 break;
02823 }
02824 }
02825
02826
02827 if (VestaSource::type == VestaSource::mutableDirectory) {
02828 Bit32 ssSP = snapshot();
02829 if (ssSP != 0) {
02830 VDirChangeable ssVS(VestaSource::immutableDirectory,
02831 (Bit8*) VMemPool::lengthenPointer(ssSP));
02832 ssVS.mark();
02833 }
02834 }
02835 }
02836
02837
02838
02839 struct {
02840 unsigned int entriesInUse;
02841 unsigned int sizeInUse;
02842 unsigned int entriesNotInUse;
02843 unsigned int sizeNotInUse;
02844 unsigned int sizeSpare;
02845 unsigned int sizeOverhead;
02846 unsigned int changeableDirs;
02847 unsigned int changeableRepBlocks;
02848 unsigned int immutableDirs;
02849 unsigned int immutableRepBlocks;
02850 unsigned int appendableDirs;
02851 unsigned int appendableRepBlocks;
02852 } VDCStats;
02853
02854
02855 void
02856 VDirChangeable::printStats() throw ()
02857 {
02858 Repos::dprintf(DBG_VMEMPOOL, "VDirChangeable size statistics:\n"
02859 "entriesInUse\t%u\n"
02860 "sizeInUse\t%u\n"
02861 "entriesNotInUse\t%u\n"
02862 "sizeNotInUse\t%u\n"
02863 "sizeSpare\t%u\n"
02864 "sizeOverhead\t%u\n"
02865 "changeableDirs\t%u\n"
02866 "changeableRepBl\t%u\n"
02867 "immutableDirs\t%u\n"
02868 "immutableRepBl\t%u\n"
02869 "appendableDirs\t%u\n"
02870 "appendableRepBl\t%u\n",
02871 VDCStats.entriesInUse,
02872 VDCStats.sizeInUse,
02873 VDCStats.entriesNotInUse,
02874 VDCStats.sizeNotInUse,
02875 VDCStats.sizeSpare,
02876 VDCStats.sizeOverhead,
02877 VDCStats.changeableDirs,
02878 VDCStats.changeableRepBlocks,
02879 VDCStats.immutableDirs,
02880 VDCStats.immutableRepBlocks,
02881 VDCStats.appendableDirs,
02882 VDCStats.appendableRepBlocks);
02883 }
02884
02885 void
02886 VDirChangeable::markCallback(void* closure, VMemPool::typeCode type) throw ()
02887 {
02888 VestaSource::repositoryRoot()->setHasName(true);
02889 VestaSource::repositoryRoot()->mark();
02890 VestaSource::mutableRoot()->setHasName(true);
02891 VestaSource::mutableRoot()->mark();
02892 VestaSource::volatileRoot()->mark();
02893 VDCStats.entriesInUse = VDCStats.sizeInUse =
02894 VDCStats.entriesNotInUse = VDCStats.sizeNotInUse =
02895 VDCStats.sizeSpare = VDCStats.sizeOverhead =
02896 VDCStats.changeableRepBlocks = VDCStats.changeableDirs =
02897 VDCStats.immutableRepBlocks = VDCStats.immutableDirs =
02898 VDCStats.appendableRepBlocks = VDCStats.appendableDirs = 0;
02899 }
02900
02901 bool
02902 VDirChangeable::sweepCallback(void* closure, VMemPool::typeCode type,
02903 void* addr, Bit32& size) throw ()
02904 {
02905 FILE* sidfile = *(FILE**) closure;
02906 bool immutable = (type == VMemPool::vDirImmutable);
02907 bool appendable = (type == VMemPool::vDirAppendable);
02908 VDirChangeable vs(immutable ? VestaSource::immutableDirectory :
02909 appendable ? VestaSource::appendableDirectory :
02910 VestaSource::unused, (Bit8*) addr);
02911 Bit8* entry = vs.firstEntry(vs.rep);
02912 Bit32 freelen;
02913 VDCStats.sizeOverhead += (entry - vs.rep) + 1 + sizeof(freelen);
02914 while (!vs.isEndMark(entry)) {
02915 Bit8* next = nextEntry(entry);
02916 if (vs.inUse(entry)) {
02917 if (vs.type(entry) == VestaSource::immutableFile ||
02918 vs.type(entry) == VestaSource::mutableFile) {
02919 ShortId sid = (ShortId) vs.value(entry);
02920 assert(sid != NullShortId);
02921 int res = fprintf(sidfile, "%08x\n", sid);
02922
02923 if (res == EOF) return true;
02924 }
02925 VDCStats.entriesInUse++;
02926 VDCStats.sizeInUse += next - entry;
02927 } else {
02928 if (vs.type(entry) != VestaSource::gap) {
02929 setType(entry, VestaSource::outdated);
02930 setValue(entry, 0);
02931 setAttrib(entry, 0);
02932 }
02933 VDCStats.entriesNotInUse++;
02934 VDCStats.sizeNotInUse += next - entry;
02935 }
02936 setInUse(entry, false);
02937 entry = next;
02938 }
02939 if (immutable) {
02940 if (vs.hasName()) {
02941 ShortId sid = (ShortId) vs.getID();
02942 if (sid != NullShortId) {
02943
02944
02945 DeleteDirShortId(sid);
02946 }
02947 VDCStats.immutableDirs++;
02948 } else {
02949 vs.setID(NullShortId);
02950 }
02951 VDCStats.immutableRepBlocks++;
02952 } else if (appendable) {
02953 if (vs.hasName()) {
02954 VDCStats.appendableDirs++;
02955 }
02956 VDCStats.appendableRepBlocks++;
02957 } else {
02958 if (vs.hasName()) {
02959 VDCStats.changeableDirs++;
02960 }
02961 VDCStats.changeableRepBlocks++;
02962 }
02963 memcpy(&freelen, entry + 1, sizeof(freelen));
02964 size = (entry - vs.rep) + 1 + sizeof(freelen) + freelen;
02965 bool ret = vs.visited();
02966 vs.setHasName(false);
02967 vs.setVisited(false);
02968 VDCStats.sizeSpare += freelen;
02969 return ret;
02970 }
02971
02972 void
02973 VDirChangeable::rebuildCallback(void* closure, VMemPool::typeCode type,
02974 void* addr, Bit32& size) throw ()
02975 {
02976
02977
02978
02979
02980
02981
02982
02983 bool immutable = (type == VMemPool::vDirImmutable);
02984 bool appendable = (type == VMemPool::vDirAppendable);
02985 VDirChangeable vs(immutable ? VestaSource::immutableDirectory :
02986 appendable ? VestaSource::appendableDirectory :
02987 VestaSource::unused, (Bit8*) addr);
02988 if (immutable) {
02989 ShortId sid = (ShortId) vs.getID();
02990 if (sid != NullShortId) {
02991 SetDirShortId(sid, VMemPool::shortenPointer(addr));
02992 SetFPDirShortId((Bit8*)addr);
02993 }
02994 }
02995
02996
02997 Bit8* entry = vs.firstEntry(vs.rep);
02998 while (!vs.isEndMark(entry)) {
02999 if ((immutable || appendable) &&
03000 VDirChangeable::type(entry) == VestaSource::immutableFile) {
03001
03002 SetFPFileShortId(entry);
03003 }
03004 entry = nextEntry(entry);
03005 }
03006
03007
03008 Bit32 freelen;
03009 memcpy(&freelen, entry + 1, sizeof(freelen));
03010 size = (entry - vs.rep) + 1 + sizeof(freelen) + freelen;
03011 }
03012
03013 static void
03014 VDCWriteGap(Bit32& nextSP, fstream& ckpt, Bit32 gapsize) throw ()
03015 {
03016 ckpt.put((char) (VestaSource::gap << 4));
03017 ckpt.write((const char*)&gapsize, sizeof(gapsize));
03018 gapsize = 0;
03019 ckpt.write((const char*)&gapsize, sizeof(gapsize));
03020 ckpt.put(0);
03021 nextSP += 10;
03022 }
03023
03024 Bit32
03025 VDirChangeable::checkpoint(Bit32& nextSP, fstream& ckpt) throw ()
03026 {
03027
03028 if (visited(rep)) return moreOrBase(rep);
03029
03030
03031
03032 Bit8* curRepBlock = rep;
03033 VMemPool::typeCode t = VMemPool::type(curRepBlock);
03034 assert(t == VMemPool::vDirChangeable ||
03035 t == VMemPool::vDirAppendable ||
03036 t == VMemPool::vDirImmutable);
03037 for (;;) {
03038 Bit8* entry;
03039 Bit32 newChildSP;
03040 entry = firstEntry(curRepBlock);
03041 while (!isEndMark(entry)) {
03042 switch (type(entry)) {
03043 case VestaSource::immutableDirectory:
03044 case VestaSource::mutableDirectory:
03045 case VestaSource::volatileDirectory:
03046 case VestaSource::volatileROEDirectory:
03047 case VestaSource::appendableDirectory:
03048 {
03049 VDirChangeable* childVS =
03050 NEW_CONSTR(VDirChangeable,
03051 (type(entry), (Bit8*)
03052 VMemPool::lengthenPointer(value(entry))));
03053 newChildSP = childVS->checkpoint(nextSP, ckpt);
03054 setValue(entry, newChildSP);
03055 delete childVS;
03056 }
03057 break;
03058 case VestaSource::evaluatorDirectory:
03059 case VestaSource::evaluatorROEDirectory:
03060 {
03061 VDirEvaluator* childVS =
03062 NEW_CONSTR(VDirEvaluator,
03063 (type(entry), (Bit8*)
03064 VMemPool::lengthenPointer(value(entry))));
03065 newChildSP = childVS->checkpoint(nextSP, ckpt);
03066 setValue(entry, newChildSP);
03067 delete childVS;
03068 }
03069 break;
03070 case VestaSource::deleted:
03071 case VestaSource::outdated:
03072 if (value(entry) != 0) {
03073 VForward* vf =
03074 (VForward*) VMemPool::lengthenPointer(value(entry));
03075 newChildSP = vf->checkpoint(nextSP, ckpt);
03076 setValue(entry, newChildSP);
03077 }
03078 case VestaSource::gap:
03079 default:
03080 break;
03081 }
03082 if (attrib(entry) != 0) {
03083 if(VestaSource::type == VestaSource::appendableDirectory ||
03084 VestaSource::type == VestaSource::mutableDirectory)
03085 {
03086 VestaAttribsRep* ar = (VestaAttribsRep*)
03087 VMemPool::lengthenPointer(attrib(entry));
03088 newChildSP = ar->checkpoint(nextSP, ckpt);
03089 setAttrib(entry, newChildSP);
03090 }
03091 else
03092 {
03093
03094
03095 Repos::dprintf(DBG_ALWAYS,
03096 "WARNING: attributes in a non-mutabe "
03097 "non-appendable directory; arc = \""
03098 "%.*s\", attrib short pointer = 0x%x\n",
03099 arcLen(entry), arc(entry),
03100 attrib(entry));
03101 setAttrib(entry, 0);
03102 }
03103 }
03104 entry = nextEntry(entry);
03105 }
03106 if (isMoreOrBase(curRepBlock) == isMore) {
03107 curRepBlock =
03108 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
03109 VMemPool::typeCode t = VMemPool::type(curRepBlock);
03110 assert(t == VMemPool::vDirChangeable ||
03111 t == VMemPool::vDirAppendable ||
03112 t == VMemPool::vDirImmutable);
03113
03114 } else {
03115 break;
03116 }
03117 }
03118
03119
03120 Bit32 newBaseSP;
03121 if (isMoreOrBase(curRepBlock) == isBase) {
03122 Bit8* baseRep =
03123 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
03124 if (VestaSource::type == VestaSource::volatileDirectory) {
03125 VDirEvaluator* baseVS =
03126 NEW_CONSTR(VDirEvaluator,
03127 (VestaSource::evaluatorDirectory, baseRep));
03128 newBaseSP = baseVS->checkpoint(nextSP, ckpt);
03129 delete baseVS;
03130 } else if (VestaSource::type == VestaSource::volatileROEDirectory) {
03131 VDirEvaluator* baseVS =
03132 NEW_CONSTR(VDirEvaluator,
03133 (VestaSource::evaluatorROEDirectory, baseRep));
03134 newBaseSP = baseVS->checkpoint(nextSP, ckpt);
03135 delete baseVS;
03136 } else {
03137 VDirChangeable* baseVS =
03138 NEW_CONSTR(VDirChangeable,
03139 (VestaSource::immutableDirectory, baseRep));
03140 newBaseSP = baseVS->checkpoint(nextSP, ckpt);
03141 delete baseVS;
03142 }
03143
03144 } else {
03145 newBaseSP = 0;
03146 }
03147
03148
03149 if (VestaSource::type == VestaSource::mutableDirectory) {
03150 Bit32 ssSP = snapshot();
03151 if (ssSP != 0) {
03152 VDirChangeable* ssVS =
03153 NEW_CONSTR(VDirChangeable,
03154 (VestaSource::immutableDirectory,
03155 (Bit8*) VMemPool::lengthenPointer(ssSP)));
03156 ssSP = ssVS->checkpoint(nextSP, ckpt);
03157 delete ssVS;
03158 setSnapshot(ssSP);
03159 }
03160 }
03161
03162
03163 Bit32 newSP = nextSP;
03164
03165
03166 Bit8 newFlags = rep[0];
03167 if (newBaseSP == 0) {
03168 setIsMoreOrBase(&newFlags, isNeither);
03169 } else {
03170 setIsMoreOrBase(&newFlags, isBase);
03171 }
03172 ckpt << newFlags;
03173
03174
03175 ckpt.write((char *) &newBaseSP, sizeof(newBaseSP));
03176
03177
03178 ckpt.write((char *) &rep[VDIRCH_TIMESTAMP], VDIRCH_ENTRIES - VDIRCH_TIMESTAMP);
03179 nextSP += VDIRCH_ENTRIES;
03180
03181
03182
03183 curRepBlock = rep;
03184 Bit8* entry = firstEntry(curRepBlock);
03185 Bit32 gapsize = 0;
03186 for (;;) {
03187 if (isEndMark(entry)) {
03188 if (isMoreOrBase(curRepBlock) == isMore) {
03189 curRepBlock =
03190 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
03191 entry = firstEntry(curRepBlock);
03192 continue;
03193 } else {
03194 if (gapsize > 0) VDCWriteGap(nextSP, ckpt, gapsize);
03195 break;
03196 }
03197 }
03198 VestaSource::typeTag etype = type(entry);
03199 Bit8* next = nextEntry(entry);
03200
03201 if (etype == VestaSource::gap) {
03202
03203 gapsize += value(entry);
03204 } else if (etype == VestaSource::outdated &&
03205 value(entry) == 0 && !sameAsBase(entry)) {
03206
03207 gapsize++;
03208 } else if (VRLogVersion >= 2 && etype == VestaSource::deleted &&
03209 value(entry) == 0 && base() == NULL) {
03210
03211
03212
03213
03214
03215
03216
03217
03218 gapsize++;
03219 } else {
03220
03221
03222 if (gapsize > 0) {
03223 VDCWriteGap(nextSP, ckpt, gapsize);
03224 gapsize = 0;
03225 }
03226
03227 ckpt.write((char *) entry, next - entry);
03228 nextSP += next - entry;
03229 }
03230 entry = next;
03231 }
03232
03233
03234 ckpt << (Bit8) 0xff;
03235 nextSP++;
03236
03237 Bit32 newFreeLen;
03238 #if 0
03239
03240 if (VestaSource::type == VestaSource::immutableDirectory) {
03241 newFreeLen = 0;
03242 } else {
03243 newFreeLen = defaultRepSize / 4;
03244 }
03245 #else
03246
03247 newFreeLen = 0;
03248 #endif
03249
03250
03251 newFreeLen += (-(nextSP + sizeof(newFreeLen) + newFreeLen - newSP)) &
03252 VMemPool::alignmentMask;
03253 ckpt.write((char *) &newFreeLen, sizeof(newFreeLen));
03254 ckpt.seekp(newFreeLen, fstream::cur);
03255 nextSP += sizeof(newFreeLen) + newFreeLen;
03256
03257
03258 if (!ckpt.good()) {
03259 Repos::dprintf(DBG_ALWAYS,
03260 "write to checkpoint file failed: errno %d\n", errno);
03261 assert(ckpt.good());
03262 }
03263
03264 setVisited(rep, true);
03265 setMoreOrBase(rep, newSP);
03266 return newSP;
03267 }
03268
03269
03270 void
03271 VDirChangeable::freeTree() throw ()
03272 {
03273 assert(VestaSource::type == VestaSource::volatileDirectory ||
03274 VestaSource::type == VestaSource::volatileROEDirectory ||
03275 VestaSource::type == VestaSource::mutableDirectory);
03276
03277
03278 Bit8* curRepBlock = rep;
03279 Bit8* entry;
03280 for (;;) {
03281 entry = firstEntry(curRepBlock);
03282 while (!isEndMark(entry)) {
03283 switch (type(entry)) {
03284 case VestaSource::deleted:
03285 case VestaSource::outdated:
03286 case VestaSource::immutableFile:
03287 case VestaSource::gap:
03288 break;
03289
03290 case VestaSource::mutableFile:
03291 if(sidref &&
03292 (sidref->Decrement(value(entry), false) == 0))
03293 {
03294
03295
03296
03297
03298
03299
03300 if((VestaSource::type != VestaSource::mutableDirectory) ||
03301 (doLogging && (VRLog.nesting() == 0)))
03302 unlinkSid((ShortId) value(entry));
03303 }
03304 break;
03305
03306 case VestaSource::volatileDirectory:
03307 case VestaSource::volatileROEDirectory:
03308 case VestaSource::mutableDirectory:
03309 {
03310
03311 assert(type(entry) == VestaSource::type);
03312
03313
03314 VDirChangeable
03315 childVS(type(entry), (Bit8*)
03316 VMemPool::lengthenPointer(value(entry)));
03317 childVS.sidref = this->sidref;
03318 childVS.freeTree();
03319 }
03320 break;
03321
03322 case VestaSource::evaluatorDirectory:
03323 case VestaSource::evaluatorROEDirectory:
03324
03325
03326 assert(false);
03327
03328 case VestaSource::immutableDirectory:
03329 assert(VestaSource::type == VestaSource::mutableDirectory);
03330 break;
03331
03332 default:
03333 assert(false);
03334 }
03335 entry = nextEntry(entry);
03336 }
03337 if (isMoreOrBase(curRepBlock) == isMore) {
03338 Bit8* nextRepBlock =
03339 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
03340
03341 Bit32 freelen;
03342 memcpy(&freelen, entry + 1, sizeof(freelen));
03343 int size = (entry - curRepBlock) + 1 + sizeof(freelen) + freelen;
03344 VMemPool::free(curRepBlock, size, VMemPool::vDirChangeable);
03345 curRepBlock = nextRepBlock;
03346 } else {
03347 break;
03348 }
03349 }
03350
03351
03352
03353
03354
03355 Bit32 freelen;
03356 memcpy(&freelen, entry + 1, sizeof(freelen));
03357 int size = (entry - curRepBlock) + 1 + sizeof(freelen) + freelen;
03358 VMemPool::free(curRepBlock, size, VMemPool::vDirChangeable);
03359 }
03360
03361 VestaSource::errorCode
03362 VDirChangeable::collapseBase(AccessControl::Identity who)
03363 throw (SRPC::failure)
03364 {
03365
03366
03367 if(VestaSource::type != VestaSource::immutableDirectory &&
03368 VestaSource::type != VestaSource::mutableDirectory)
03369 return VestaSource::inappropriateOp;
03370
03371
03372
03373 if(!ac.check(who, AccessControl::ownership))
03374 return VestaSource::noPermission;
03375
03376
03377 if(base() == 0)
03378 return VestaSource::ok;
03379
03380
03381
03382
03383 VDirChangeable originalBase(VestaSource::immutableDirectory, base());
03384
03385
03386
03387
03388
03389 if(originalBase.base() == 0)
03390 return VestaSource::ok;
03391
03392
03393 VDirChangeable *collapsedBase = originalBase.collapse();
03394
03395
03396
03397 assert((repEndCache != 0) && (lastRepBlockCache != 0));
03398 setMoreOrBase(lastRepBlockCache,
03399 VMemPool::shortenPointer(collapsedBase->rep));
03400
03401
03402 if (doLogging)
03403 {
03404 char logrec[128];
03405 OBufStream ost(logrec, sizeof(logrec));
03406
03407 ost << "(colb " << this->longid << ")\n";
03408 VRLog.start();
03409 VRLog.put(ost.str());
03410 VRLog.commit();
03411 }
03412
03413 delete collapsedBase;
03414 return VestaSource::ok;
03415 }
03416
03417 struct buildMutableSidrefClosure
03418 {
03419
03420 VestaSource *vs;
03421
03422 ShortIdRefCount *sidref;
03423 };
03424
03425 static bool
03426 buildMutableSidrefCallback(void* closure, VestaSource::typeTag type, Arc arc,
03427 unsigned int index, Bit32 pseudoInode,
03428 ShortId filesid, bool master)
03429 {
03430 buildMutableSidrefClosure *cl = (buildMutableSidrefClosure *) closure;
03431
03432 switch(type)
03433 {
03434 case VestaSource::mutableFile:
03435
03436
03437 cl->sidref->Increment(filesid);
03438 break;
03439 case VestaSource::mutableDirectory:
03440
03441 {
03442 buildMutableSidrefClosure newcl;
03443 newcl.sidref = cl->sidref;
03444 VestaSource::errorCode err = cl->vs->lookupIndex(index, newcl.vs);
03445 assert(err == VestaSource::ok);
03446 err = newcl.vs->list(0, buildMutableSidrefCallback, &newcl,
03447 NULL, true);
03448 assert(err == VestaSource::ok);
03449 delete newcl.vs;
03450 }
03451 break;
03452
03453
03454
03455
03456
03457 }
03458
03459 return true;
03460 }
03461
03462 ShortIdRefCount *VDirChangeable::rebuildMutableSidref() throw()
03463 {
03464
03465 assert(this->VestaSource::type == VestaSource::mutableDirectory);
03466 assert(this->longid == MutableRootLongId);
03467
03468
03469 buildMutableSidrefClosure cl;
03470 cl.vs = this;
03471 cl.sidref = new ShortIdRefCount;
03472 VestaSource::errorCode err = this->list(0, buildMutableSidrefCallback, &cl,
03473 NULL, true);
03474 assert(err == VestaSource::ok);
03475
03476 return cl.sidref;
03477 }
03478
03479 void VDirChangeable::buildMutableSidref() throw()
03480 {
03481
03482 assert(this->sidref == 0);
03483
03484 this->sidref = this->rebuildMutableSidref();
03485 }
03486
03487 void VDirChangeable::checkMutableSidref(bool correct) throw()
03488 {
03489
03490 assert(this->sidref != 0);
03491
03492 ShortIdRefCount *rebuilt = this->rebuildMutableSidref();
03493
03494 bool match = this->sidref->Compare(*rebuilt);
03495 if(!match)
03496 {
03497 Repos::dprintf(DBG_ALWAYS,
03498 "%s: shortid reference count mismatch!\n",
03499 correct?"WARNING":"FATAL ERROR");
03500
03501 if(correct)
03502 {
03503 delete this->sidref;
03504 this->sidref = rebuilt;
03505 rebuilt = 0;
03506 }
03507 else
03508 {
03509 abort();
03510 }
03511 }
03512
03513 if(rebuilt) delete rebuilt;
03514 }
03515
03517
03518 VDirChangeable::VDirChangeable(VestaSource::typeTag type, Bit8* existingRep,
03519 ShortIdRefCount *sidref)
03520 throw ()
03521 {
03522 rep = existingRep;
03523 repEndCache = NULL;
03524 VestaSource::type = type;
03525 VestaSource::master = false;
03526 VestaSource::attribs = NULL;
03527 this->sidref = sidref;
03528 }
03529
03530
03531 VDirChangeable::VDirChangeable(VestaSource::typeTag type, int size,
03532 ShortIdRefCount *sidref) throw ()
03533 {
03534 if (size < VDIRCH_MINSIZE) size = VDIRCH_MINSIZE;
03535 rep = (Bit8*)
03536 VMemPool::allocate(type == VestaSource::immutableDirectory ?
03537 VMemPool::vDirImmutable :
03538 type == VestaSource::appendableDirectory ?
03539 VMemPool::vDirAppendable :
03540 VMemPool::vDirChangeable, size);
03541 memset(rep + 1, 0, VDIRCH_ENTRIES - 1);
03542 rep[VDIRCH_ENDMARK] = 0xff;
03543 Bit32 freeLen = size - VDIRCH_MINSIZE;
03544 memcpy(&rep[VDIRCH_FREELEN], &freeLen, sizeof(freeLen));
03545 repEndCache = &rep[VDIRCH_ENDMARK];
03546 nextRawIndexCache = 1;
03547 baseCache = NULL;
03548 lastRepBlockCache = rep;
03549 totalRepSizeCache = VDIRCH_MINSIZE;
03550 VestaSource::type = type;
03551 VestaSource::master = false;
03552 VestaSource::attribs = NULL;
03553 this->sidref = sidref;
03554 }
03555
03556 VestaSource *VDirChangeable::copy() throw()
03557 {
03558 VDirChangeable *result = NEW_CONSTR(VDirChangeable,
03559 (this->VestaSource::type, this->rep, this->sidref));
03560 *result = *this;
03561 return result;
03562 }
03563
03564 void
03565 VDirChangeable::fillCaches() throw ()
03566 {
03567 Bit8* curRepBlock = rep;
03568 unsigned int rawIndex = 1;
03569 int totalRepSize = VDIRCH_MINSIZE;
03570 Bit8* entry;
03571 for (;;) {
03572 entry = firstEntry(curRepBlock);
03573 while (!isEndMark(entry)) {
03574 if (type(entry) == VestaSource::gap) {
03575 rawIndex += value(entry);
03576 } else {
03577 rawIndex++;
03578 }
03579 entry = nextEntry(entry);
03580 }
03581 totalRepSize += entry - firstEntry(curRepBlock);
03582 if (isMoreOrBase(curRepBlock) == isMore) {
03583 curRepBlock =
03584 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
03585 } else {
03586 break;
03587 }
03588 }
03589 repEndCache = entry;
03590 nextRawIndexCache = rawIndex;
03591 if (isMoreOrBase(curRepBlock) == isBase) {
03592 baseCache =
03593 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
03594 } else {
03595 baseCache = NULL;
03596 }
03597 lastRepBlockCache = curRepBlock;
03598 totalRepSizeCache = totalRepSize;
03599 }
03600
03601 void
03602 VDirChangeable::resync(AccessControl::Identity who) throw ()
03603 {
03604 repEndCache = NULL;
03605 }
03606
03607 Bit8* VDirChangeable::findArc(const char* arc, unsigned int& rawIndex,
03608 bool includeDeleted, bool includeOutdated)
03609 throw ()
03610 {
03611 if (arc[0] == '\0') {
03612 rawIndex = 0;
03613 return NULL;
03614 }
03615 Bit8* curRepBlock = rep;
03616 Bit8* entry;
03617 int totalRepSize = VDIRCH_MINSIZE;
03618 int len = strlen(arc);
03619 rawIndex = 1;
03620 for (;;) {
03621 entry = firstEntry(curRepBlock);
03622 while (!isEndMark(entry)) {
03623 if (arcLen(entry) == len
03624 && memcmp(VDirChangeable::arc(entry), arc, len) == 0) {
03625
03626 switch (type(entry)) {
03627 case VestaSource::deleted:
03628 if (includeDeleted) return entry;
03629 break;
03630 case VestaSource::outdated:
03631 if (includeOutdated) return entry;
03632 break;
03633 case VestaSource::gap:
03634 break;
03635 default:
03636 return entry;
03637 }
03638 }
03639 if (type(entry) == VestaSource::gap) {
03640 rawIndex += value(entry);
03641 } else {
03642 rawIndex++;
03643 }
03644 entry = nextEntry(entry);
03645 }
03646 totalRepSize += entry - firstEntry(curRepBlock);
03647 if (isMoreOrBase(curRepBlock) == isMore) {
03648 curRepBlock =
03649 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
03650 } else {
03651 break;
03652 }
03653 }
03654
03655
03656 if (!repEndCache) {
03657 repEndCache = entry;
03658 nextRawIndexCache = rawIndex;
03659 if (isMoreOrBase(curRepBlock) == isBase) {
03660 baseCache =
03661 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
03662 } else {
03663 baseCache = NULL;
03664 }
03665 lastRepBlockCache = curRepBlock;
03666 totalRepSizeCache = totalRepSize;
03667 }
03668 return NULL;
03669 }
03670
03671 Bit8*
03672 VDirChangeable::findRawIndex(unsigned int rawIndex, Bit8*& curRepBlock)
03673 throw ()
03674 {
03675 Bit8* entry;
03676 curRepBlock = rep;
03677 unsigned int ri = 1;
03678 int totalRepSize = VDIRCH_MINSIZE;
03679 for (;;) {
03680 entry = firstEntry(curRepBlock);
03681 while (!isEndMark(entry)) {
03682 if (type(entry) == VestaSource::gap) {
03683 ri += value(entry) - 1;
03684 }
03685 if (ri >= rawIndex) {
03686
03687 return entry;
03688 }
03689 entry = nextEntry(entry);
03690 ri++;
03691 }
03692 totalRepSize += entry - firstEntry(curRepBlock);
03693 if (isMoreOrBase(curRepBlock) == isMore) {
03694 curRepBlock =
03695 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
03696 } else {
03697 break;
03698 }
03699 }
03700
03701
03702 if (!repEndCache) {
03703 repEndCache = entry;
03704 nextRawIndexCache = ri;
03705 if (isMoreOrBase(curRepBlock) == isBase) {
03706 baseCache =
03707 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
03708 } else {
03709 baseCache = NULL;
03710 }
03711 lastRepBlockCache = curRepBlock;
03712 totalRepSizeCache = totalRepSize;
03713 }
03714 return NULL;
03715 }
03716
03717
03718 void
03719 VDirChangeable::setEntry(Bit8* entry, bool mast, bool sameAsBase,
03720 VestaSource::typeTag newType,
03721 Bit32 value, Bit32 attrib, const FP::Tag* efptag)
03722 throw ()
03723 {
03724
03725 assert((type(entry) == VestaSource::gap) == (newType == VestaSource::gap));
03726
03727 entry[VDIRCH_EFLAGS] =
03728 (entry[VDIRCH_EFLAGS] & 4) | mast | (sameAsBase << 3) | (newType << 4);
03729 setValue(entry, value);
03730 setAttrib(entry, attrib);
03731 if (efptag == NULL) {
03732 if (hasEFPTag(entry))
03733 setEFPTag(entry, nullFPTag);
03734 } else {
03735 assert(hasEFPTag(entry));
03736 setEFPTag(entry, *efptag);
03737 }
03738 }
03739
03740
03741 Bit8*
03742 VDirChangeable::appendEntry(bool mast, bool sameAsBase,
03743 VestaSource::typeTag type, Bit32 value,
03744 Bit32 attrib, const FP::Tag* efptag,
03745 const char* name, int nameLen) throw ()
03746 {
03747 assert(nameLen <= 255);
03748 Basics::int64 entryLen =
03749 nameLen + ((efptag == NULL) ? VDIRCH_E1MINSIZE : VDIRCH_E2MINSIZE);
03750 Basics::int64 newFreeLen = ((Basics::int64) freeLen()) - entryLen;
03751
03752 if (newFreeLen < 0) {
03753
03754 RECORD_TIME_POINT;
03755 Bit8* newBlock =
03756 (Bit8*) VMemPool::allocate(VMemPool::type(rep), defaultRepSize);
03757 RECORD_TIME_POINT;
03758 memset(newBlock + 1, 0, VDIRCH_ENTRIES + 1);
03759 newBlock[VDIRCH_ENTRIES] = 0xff;
03760 if (isMoreOrBase(lastRepBlock()) == isBase) {
03761 setIsMoreOrBase(newBlock, isBase);
03762 setMoreOrBase(newBlock, moreOrBase(lastRepBlock()));
03763 }
03764 setIsMoreOrBase(lastRepBlock(), isMore);
03765 setMoreOrBase(lastRepBlock(), VMemPool::shortenPointer(newBlock));
03766 assert(repEndCache != NULL);
03767 repEndCache = &newBlock[VDIRCH_ENTRIES];
03768 lastRepBlockCache = newBlock;
03769 newFreeLen = defaultRepSize - VDIRCH_MINSIZE - entryLen;
03770 }
03771
03772 Bit8* entry = repEnd();
03773 entry[VDIRCH_EFLAGS] =
03774 mast | ((efptag != NULL) << 2) | (sameAsBase << 3) | (type << 4);
03775 setValue(entry, value);
03776 setAttrib(entry, attrib);
03777 if (efptag == NULL) {
03778 entry[VDIRCH_E1ARCLEN] = nameLen;
03779 memcpy(&entry[VDIRCH_E1ARC], name, nameLen);
03780 } else {
03781 setEFPTag(entry, *efptag);
03782 entry[VDIRCH_E2ARCLEN] = nameLen;
03783 memcpy(&entry[VDIRCH_E2ARC], name, nameLen);
03784 }
03785 repEndCache = entry + entryLen;
03786 repEndCache[0] = 0xff;
03787 if (type == VestaSource::gap) {
03788 nextRawIndexCache += value;
03789 } else {
03790 nextRawIndexCache++;
03791 }
03792 setFreeLen(newFreeLen);
03793 totalRepSizeCache += entryLen;
03794 return entry;
03795 }
03796
03797
03798
03799
03800
03801
03802 VDirChangeable*
03803 VDirChangeable::copyMutableToImmutable(const FP::Tag& fptag) throw ()
03804 {
03805 if (nextRawIndex() == 1 && base() != NULL) {
03806
03807
03808
03809 return NEW_CONSTR(VDirChangeable,
03810 (VestaSource::immutableDirectory, base()));
03811 }
03812
03813
03814
03815
03816 int size = totalRepSize();
03817 VDirChangeable* dest =
03818 NEW_CONSTR(VDirChangeable, (VestaSource::immutableDirectory, size));
03819
03820
03821 if (base()) {
03822 dest->setIsMoreOrBase(dest->rep, isBase);
03823 dest->setMoreOrBase(dest->rep, VMemPool::shortenPointer(base()));
03824 } else {
03825 dest->setIsMoreOrBase(dest->rep, isNeither);
03826 }
03827 dest->setTimestampField(timestamp());
03828 dest->setFPTag(fptag);
03829
03830
03831
03832 Bit8* repBlock = rep;
03833 Bit8* p = firstEntry(dest->rep);
03834 for (;;) {
03835 Bit8* entry = firstEntry(repBlock);
03836 while (!isEndMark(entry)) {
03837 Bit8* next = nextEntry(entry);
03838 ShortId dupsid;
03839 switch (type(entry)) {
03840 case VestaSource::mutableDirectory:
03841 {
03842 memcpy(p, entry, next - entry);
03843
03844 VDirChangeable* thisChild =
03845 NEW_CONSTR(VDirChangeable,
03846 (type(entry), (Bit8*)
03847 VMemPool::lengthenPointer(value(entry))));
03848 Bit32 childOldSnapshot = thisChild->snapshot();
03849 FP::Tag childFPTag = fptag;
03850 childFPTag.Extend("/");
03851 childFPTag.Extend(arc(entry), arcLen(entry));
03852 VestaSource* destChild =
03853 thisChild->copyMutableToImmutable(childFPTag);
03854 setType(p, VestaSource::immutableDirectory);
03855 setValue(p, VMemPool::shortenPointer(destChild->rep));
03856 if (childOldSnapshot != thisChild->snapshot()) {
03857
03858
03859 setSnapshot(0);
03860 }
03861 delete thisChild;
03862 delete destChild;
03863 }
03864 break;
03865 case VestaSource::mutableFile:
03866 {
03867
03868
03869
03870
03871 setType(entry, VestaSource::immutableFile);
03872 if (doLogging) {
03873 ShortId sid = (ShortId) value(entry);
03874
03875
03876
03877 int fd = FdCache::open(sid, FdCache::rw);
03878 assert(fd != -1);
03879 struct stat st;
03880 int res = fstat(fd, &st);
03881 assert(res != -1);
03882 res = fchmod(fd, st.st_mode & ~0222);
03883 assert(res != -1);
03884
03885
03886
03887 FdCache::flush(sid, FdCache::rw);
03888
03889 res = fsync(fd);
03890 assert(res != -1);
03891
03892
03893 do
03894 res = close(fd);
03895 while ((res == -1) && (errno == EINTR));
03896 assert(res != -1);
03897 }
03898 FP::Tag childFPTag = fptag;
03899 childFPTag.Extend("/");
03900 childFPTag.Extend(arc(entry), arcLen(entry));
03901 setEFPTag(entry, childFPTag);
03902 memcpy(p, entry, next - entry);
03903 assert(snapshot() == 0);
03904 SetFPFileShortId(p);
03905 }
03906 break;
03907 case VestaSource::outdated:
03908 case VestaSource::gap:
03909
03910 entry = next;
03911 continue;
03912 case VestaSource::immutableFile:
03913
03914 dupsid = GetFPShortId(efptag(entry));
03915 if (dupsid != NullShortId) {
03916 setValue(entry, dupsid);
03917 }
03918 memcpy(p, entry, next - entry);
03919 if (snapshot() == 0) {
03920
03921
03922
03923
03924
03925
03926 SetFPFileShortId(p);
03927 }
03928 break;
03929 case VestaSource::immutableDirectory:
03930 memcpy(p, entry, next - entry);
03931 break;
03932 case VestaSource::deleted:
03933 if (VRLogVersion >= 2 && base() == NULL) {
03934
03935
03936 entry = next;
03937 continue;
03938 }
03939 memcpy(p, entry, next - entry);
03940 setValue(p, 0);
03941 break;
03942 default:
03943 assert(false);
03944 }
03945 setAttrib(p, 0);
03946 setSameAsBase(p, false);
03947 p += next - entry;
03948 entry = next;
03949 }
03950 if (isMoreOrBase(repBlock) == isMore) {
03951 repBlock = (Bit8*) VMemPool::lengthenPointer(moreOrBase(repBlock));
03952 } else {
03953 break;
03954 }
03955 }
03956
03957
03958 if (snapshot() != 0) {
03959
03960
03961
03962
03963
03964
03965 VMemPool::free(dest->rep, size, VMemPool::vDirImmutable);
03966 dest->rep = (Bit8*) VMemPool::lengthenPointer(snapshot());
03967 dest->repEndCache = NULL;
03968 } else {
03969
03970 setSnapshot(VMemPool::shortenPointer(dest->rep));
03971
03972
03973 dest->setID(NewDirShortId(fptag, VMemPool::shortenPointer(dest->rep)));
03974
03975
03976 SetFPDirShortId(dest->rep);
03977
03978
03979 *p = 0xff;
03980 Bit32 freeLen = size - (p + 1 + sizeof(freeLen) - dest->rep);
03981 memcpy(p + 1, &freeLen, sizeof(freeLen));
03982
03983 dest->repEndCache = p;
03984 dest->nextRawIndexCache = nextRawIndex();
03985 dest->baseCache = base();
03986 dest->lastRepBlockCache = dest->rep;
03987 dest->totalRepSizeCache = size - freeLen;
03988 }
03989 return dest;
03990 }
03991
03992 VestaSource::errorCode
03993 VDirChangeable::measureDirectory(VestaSource::directoryStats &result,
03994 AccessControl::Identity who)
03995 throw (SRPC::failure)
03996 {
03997
03998 result.baseChainLength = result.usedEntryCount = result.usedEntrySize =
03999 result.totalEntryCount = result.totalEntrySize = 0;
04000
04001
04002 if (!ac.check(who, AccessControl::read))
04003 return VestaSource::noPermission;
04004
04005
04006 ArcTable used;
04007
04008
04009 Bit8* curRepBlock = rep;
04010 for (;;) {
04011 Bit8 *entry, *next;
04012 entry = firstEntry(curRepBlock);
04013
04014 while (!isEndMark(entry))
04015 {
04016 result.totalEntryCount++;
04017 next = nextEntry(entry);
04018
04019 if (type(entry) != VestaSource::outdated &&
04020 type(entry) != VestaSource::gap)
04021 {
04022 ArcKey k;
04023 ArcValue v;
04024 k.s = arc(entry);
04025 k.slen = arcLen(entry);
04026
04027 if (!used.Get(k, v))
04028 {
04029 used.Put(k, ArcValue());
04030
04031
04032
04033 if(type(entry) != VestaSource::deleted)
04034 {
04035 result.usedEntryCount++;
04036 result.usedEntrySize += (next-entry);
04037 }
04038 }
04039 }
04040 entry = next;
04041 }
04042
04043
04044 result.totalEntrySize += (entry-firstEntry(curRepBlock));
04045 if (isMoreOrBase(curRepBlock) == isMore ||
04046 (isMoreOrBase(curRepBlock) == isBase &&
04047 (VestaSource::type == VestaSource::immutableDirectory ||
04048 VestaSource::type == VestaSource::mutableDirectory))) {
04049
04050
04051 if(isMoreOrBase(curRepBlock) == isBase)
04052 result.baseChainLength++;
04053
04054 curRepBlock =
04055 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
04056 } else {
04057
04058
04059 break;
04060 }
04061 }
04062
04063
04064 return VestaSource::ok;
04065 }
04066
04067 VDirChangeable*
04068 VDirChangeable::collapse(unsigned int newSize)
04069 throw()
04070 {
04071
04072 assert(VestaSource::type == VestaSource::immutableDirectory);
04073
04074
04075 ArcTable used;
04076
04077
04078
04079 if(repEndCache && (totalRepSizeCache > newSize))
04080 newSize = totalRepSizeCache;
04081
04082
04083 VDirChangeable* dest =
04084 NEW_CONSTR(VDirChangeable, (VestaSource::immutableDirectory, newSize));
04085
04086
04087 dest->VestaSource::fptag = this->fptag();
04088 dest->setFPTag(dest->VestaSource::fptag);
04089 dest->setID(this->getID());
04090 dest->setTimestampField(this->timestamp());
04091
04092
04093 SetDirShortId(this->getID(), VMemPool::shortenPointer(dest->rep));
04094 SetFPDirShortId(dest->rep);
04095
04096
04097 Bit8* curRepBlock = rep;
04098 Bit32 gapsize = 0;
04099 for (;;) {
04100 Bit8 *entry;
04101 entry = firstEntry(curRepBlock);
04102
04103 while (!isEndMark(entry))
04104 {
04105 if(type(entry) == VestaSource::gap)
04106 {
04107
04108 gapsize += value(entry);
04109 }
04110 else if(type(entry) == VestaSource::outdated)
04111 {
04112
04113 gapsize++;
04114 }
04115
04116 else
04117 {
04118 ArcKey k;
04119 ArcValue v;
04120 k.s = arc(entry);
04121 k.slen = arcLen(entry);
04122
04123
04124 if (!used.Get(k, v))
04125 {
04126 used.Put(k, ArcValue());
04127
04128
04129
04130 if(type(entry) != VestaSource::deleted)
04131 {
04132
04133 if(gapsize > 0)
04134 {
04135 dest->appendEntry(false, false, VestaSource::gap,
04136 gapsize, 0, 0, "", 0);
04137 gapsize = 0;
04138 }
04139
04140
04141
04142
04143
04144 dest->appendEntry(masterFlag(entry), false, type(entry),
04145 value(entry), 0,
04146 (hasEFPTag(entry)
04147 ? (FP::Tag *) &entry[VDIRCH_EFPTAG]
04148 : 0),
04149 arc(entry), arcLen(entry));
04150 }
04151 else
04152 {
04153
04154 gapsize++;
04155 }
04156 }
04157 else
04158 {
04159
04160 gapsize++;
04161 }
04162 }
04163 entry = nextEntry(entry);
04164 }
04165
04166 if(isMoreOrBase(curRepBlock) == isNeither)
04167 break;
04168
04169 curRepBlock =
04170 (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
04171 }
04172
04173 return dest;
04174 }