Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

VDirChangeable.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 //
00020 // VDirChangeable.C
00021 //
00022 // Derived class for in-memory representation of Vesta directories
00023 // that can change, including appendable and mutable.  The
00024 // representation is also adequate for immutable directories.  (The
00025 // original plan was to use a separate class for immutable
00026 // directories, but that has not been done.)
00027 //
00028 // The purpose of this class is to provide methods that operate on the
00029 // special packed representation.  Most of the directories that exist
00030 // at any moment will not have objects of this class corresponding to
00031 // them; they will exist only in the packed representation.
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"); // Same prefix used in evaluator (FP by UID)
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 /*static*/ 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); // cannot happen
00158         break;
00159     }
00160     switch (dir->VestaSource::type) {
00161       case VestaSource::appendableDirectory:
00162         // Use own master flag
00163         result->VestaSource::master = dir->masterFlag(entry);
00164         break;
00165       case VestaSource::immutableDirectory:
00166         // Inherit parent master flag
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         // Nonreplicated -- always master
00175         result->VestaSource::master = true;
00176         break;
00177       default:
00178         assert(false); // cannot happen
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     // Note that special treatment of search/execute bits
00194     // for files is not handled here.  A file's executable
00195     // flag is recorded in the underlying file system as a 
00196     // property of the SourceOrDerived.  Through the 
00197     // VestaSource interface, the 111 bits of the mode are 
00198     // always search permission.
00199     if ((val = result->getAttribConst("#mode")) == NULL) {
00200         // setuid and setgid bits are not inherited
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   // Start by initializing the result, in case we fail before setting
00214   // it to something useful.
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; // so that we can change cur.rep
00223   for (;;) {
00224     entry = cur.findArc(arc, rawIndex, true);
00225     if (entry == NULL) {
00226       // Look in base directory
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         // Recurse: base has different object type
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         // Iterate: base has same object type.
00253         // This is essentially an optimized tail recursion, to avoid
00254         // stack overflow when the base chain is long.
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   // Check for LongId overflow
00276   if (result->longid ==  NullLongId)
00277     {
00278       delete result;
00279       result = 0;
00280       return VestaSource::longIdOverflow;
00281     }
00282   if (sameAsBase(entry)) {
00283     // Have to look in base to get the old longid and use that.
00284     // Avoids having two different longids (NFS file handles) for
00285     // the same file, which would cause NFS cache incoherency.
00286     // Recursion is OK here because we go at most one level deep.
00287     assert(cur.VestaSource::type != VestaSource::immutableDirectory);
00288     assert(indexOffset == 0);
00289     assert(cur.rep == rep); // i.e., we are at the top of the base chain
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   // Start by initializing the result, in case we fail before setting
00329   // it to something useful.
00330   result = 0;
00331 
00332   Bit8* entry;
00333   Bit8* repBlock; // storage for unused return value
00334   VestaSource* replaced = NULL;
00335   unsigned int indexOffset = 0;
00336   if (VestaSource::type == VestaSource::immutableDirectory) {
00337     // An immutableDirectory has only even indices
00338     if (index & 1) {
00339       // Odd: invalid index
00340       entry = NULL;
00341     } else {
00342       // Even:
00343       VDirChangeable cur = *this; // so we can change cur.rep
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         // This is essentially an optimized tail recursion, to
00357         // avoid stack overflow when the base chain is long.
00358         cur.rep = baseRep;
00359         cur.repEndCache = NULL;
00360       }
00361     }
00362   } else {
00363     if (index & 1) {
00364       // Odd index; look in the rep
00365       entry = findRawIndex((index + 1) >> 1, repBlock);
00366     } else {
00367       // Even index; look in the base
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       // Correct the pseudoInode if needed
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       // Is the entry found in the base shadowed by a sameAsBase entry
00405       // in the current rep?
00406       unsigned int dummyRawIndex;
00407       entry = findArc(myarcbuf, dummyRawIndex, true, true);
00408       if (entry != NULL && sameAsBase(entry)) {
00409         // Yes, need to use the value from the new entry together
00410         // with the longid and pseudoInode for the replaced entry.
00411         // The case where the replacement is a forwarding pointer
00412         // must also be handled (below).
00413         replaced = result;
00414       } else {
00415         // No, result from base is correct.
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     // Use old longid, checking for overflow
00429     LongId result_longid = longid.append(index);
00430     if(result_longid == NullLongId)
00431       {
00432         return VestaSource::longIdOverflow;
00433       }
00434     // Follow forwarding pointer
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     // Correct the pseudoInode if needed
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   // Check for LongId overflow
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     // Access check
00485     if (!ac.check(who, AccessControl::write) &&
00486         !ac.check(who, AccessControl::ownership))
00487       return VestaSource::noPermission;
00488 
00489     // Log the operation
00490     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
00491         VestaSource::type != VestaSource::volatileROEDirectory) {
00492         char logrec[512];
00493         OBufStream ost(logrec, sizeof(logrec));
00494         // ('time' longid timestamp)
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   // If the current binding of arc is recorded in the mutable part
00529   // of its directory, reallyDelete modifies the directory entry to
00530   // have type tag VestaSource::deleted, with null forwarding
00531   // pointer.  If the current binding is recorded in the base
00532   // directory, a new entry of type deleted is created with
00533   // the sameAsBase flag set.  A deleted entry is not a ghost; it is
00534   // strictly an artifact of the representation, invisible at higher
00535   // layers.  
00536   //
00537   // If the current binding was to a mutable file and the directory is
00538   // mutable or volatile, decrement the reference count for this
00539   // mutable shortid.  If the reference count reaches zero, unlink the
00540   // underlying sid file.  This supports multiple hard links to the
00541   // same mutable file, which are permitted in mutable and volatile
00542   // directories.
00543   //
00544   // If VRLogVersion is high enough, we always look in the base
00545   // (even if existCheck is off), and if this arc does not exist
00546   // there, we set the entry in the mutable rep to outdated (or
00547   // don't create it).  This is a trifle slower than the old way but
00548   // saves memory.  It also removes the oddity that list() in
00549   // deltaOnly mode can return deleted entries for things that
00550   // existed transiently but were not in the base.  We need to
00551   // preserve the old behavior if VRLogVersion says that we are
00552   // replaying a log from before the change, since otherwise
00553   // replaying an old log would sometimes create fewer entries in a
00554   // directory (either because we did not create an entry here, or
00555   // because we marked an entry as outdated here causing
00556   // copyMutableToImmutable not to copy it), so objects later in
00557   // that directory would have different LongIds than before.
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   // Access check on parent directory
00567   if (VestaSource::master &&
00568       VestaSource::type == VestaSource::appendableDirectory) {
00569     // Violates the agreement invariant if any other repository
00570     // has a replica of this name (even as a ghost or stub).
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   // Look for the arc in the rep
00579   unsigned int rawIndex;
00580   Bit8* entry = findArc(arc, rawIndex, true);
00581 
00582   // Look for the arc in the base
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         // Avoid making a needless "deleted" entry
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   // Log the deletion
00628   if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
00629       VestaSource::type != VestaSource::volatileROEDirectory) {
00630     char logrec[512];
00631     OBufStream ost(logrec, sizeof(logrec));
00632     // ('del' longid arc timestamp)
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     // If the entry is not shadowing anything, set it to outdated
00644     // right away.  This allows it to be compressed as part of a gap
00645     // when we next take a checkpoint.
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       // doLogging implies that we're past recovery and the mutable
00655       // tree should have a shortid reference counter.  (See
00656       // VestaSource::recoveryDone().)
00657       assert(!doLogging || (sidref != 0));
00658 
00659       // Decrement reference count on shortid and if it goes to 0...
00660       if((sidref != 0) &&
00661          (sidref->Decrement(value(entry), false) == 0))
00662         {
00663          // Unlink the unused mutable shortid.  We must not do this
00664          // unlink unless we're out of recoovery and until after the
00665          // log entry is committed.  If we're still inside a
00666          // transaction, the log entry is not committed yet; otherwise
00667          // it is.
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       // Decrement reference count on shortid and unlink if it goes to 0
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       // Recursively free the memory used by this volatile/mutable
00683       // directory, decrement the reference counts of any mutable
00684       // shortids, and unlink any which reach 0.  Note that this
00685       // assumes that this is the only reference to this directory,
00686       // which should be the case for mutable and volatile
00687       // directories.
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 // Returns != ok if there is a problem.  May modify the data
00705 // structure, so do not call if any error checking remains to be done.
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; // matches Unix
00719 
00720     // Require write access to the directory being inserted into.
00721     // Do we really want to require this for replacing stubs, though?
00722     if (!ac.check(who, AccessControl::write))
00723       return VestaSource::noPermission;
00724 
00725     // Lookup arc.
00726     // Note: if the directory is appendable, entry != NULL iff there
00727     // is an existing entry for arc.  Otherwise there could also be a
00728     // base to look in.
00729     Bit8* entry = findArc(arc, rawIndex, true);
00730 
00731     // Require agreement access for changes that could break the
00732     // agreement invariant unless checked against another repository.
00733     if (VestaSource::type == appendableDirectory) {
00734       if (entry) {
00735         // Replacing an entry in an appendable directory is safe only
00736         // in the following cases:
00737         // - Old entry is a master stub and new is master anything
00738         // - Old entry is a master anything and new is a master ghost
00739         // - Old entry is a nonmaster anything and new is a nonmaster
00740         //   ghost or nonmaster stub
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         // If an existing entry is being replaced with a ghost, the
00753         // user must have delete permission.  (This ensures that the
00754         // policy set with [Repository]restrict_delete is applied.)
00755         if(newtype == ghost)
00756           {
00757             if (!ac.check(who, AccessControl::del))
00758               return VestaSource::noPermission;
00759           }
00760         // Provide the attributes of the object being replaced to the
00761         // caller if it is a stub or if the type of the new object is
00762         // stub or ghost
00763         if(attribs &&
00764            (type(entry) == stub || newtype == stub || newtype == ghost)) {
00765             *attribs = attrib(entry);
00766         }
00767       } else {
00768         // Inserting a new entry into an appendable directory is safe
00769         // only if the directory and new entry are both master.
00770         if (!(this->VestaSource::master && mast)) {
00771           if (!ac.check(who, AccessControl::agreement))
00772             return VestaSource::notMaster;
00773         }
00774       }
00775     }
00776 
00777     // Handle dupeCheck actions, and if necessary
00778     // delete/outdate existing entry.
00779     switch (chk) {
00780       case VestaSource::replaceDiff:
00781       case VestaSource::replaceNonMaster:
00782         // If an entry was found, need to delete and outdate it
00783         if (entry != NULL) {
00784             if (chk == VestaSource::replaceNonMaster && masterFlag(entry)) {
00785               return VestaSource::nameInUse;
00786             }
00787             // Check if old sid can be deleted
00788             if (type(entry) == VestaSource::mutableFile) {
00789               if (VestaSource::type == mutableDirectory) {
00790                 // doLogging implies that we're past recovery and
00791                 // the mutable tree should have a shortid reference
00792                 // counter.  (See VestaSource::recoveryDone().)
00793                 assert(!doLogging || (sidref != 0));
00794 
00795                 // Decrement reference count on shortid, and if it
00796                 // goes to 0...
00797                 if((sidref != 0) &&
00798                    (sidref->Decrement(value(entry), false) == 0))
00799                   {
00800                     if(doLogging && VRLog.nesting() == 0)
00801                       // Delete after transaction commits
00802                       *delsid = value(entry);
00803                   }
00804 
00805               } else if (VestaSource::type == volatileDirectory ||
00806                          VestaSource::type == volatileROEDirectory) {
00807                 assert(sidref != 0);
00808 
00809                 // Decrement reference count on shortid and unlink
00810                 // if it goes to 0
00811                 if(sidref->Decrement(value(entry), false) == 0)
00812                   {
00813                     unlinkSid(value(entry));
00814                   }
00815               }
00816             }
00817             // Mark entry outdated
00818             if (type(entry) != VestaSource::deleted) {
00819               setValue(entry, 0);  // if deleted, this is a VForward
00820               setAttrib(entry, 0); // if deleted, this is already 0
00821             }
00822             setType(entry, VestaSource::outdated);
00823         }
00824         break;
00825         
00826       case VestaSource::dontReplace:
00827         // Error if arc is bound
00828         if (entry == NULL) {
00829             // Must check if arc is bound in base
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                 // Need to outdate the deleted entry
00865                 setType(entry, VestaSource::outdated);
00866             } else {
00867                 assert(type(entry) != VestaSource::outdated);
00868                 return VestaSource::nameInUse;
00869             }
00870         }
00871         break;
00872     }
00873 
00874     // See if owner needs to be set.  !!Current semantics might not be
00875     // the best; each choice point is marked with "!?": If user(0)
00876     // (other users are not checked!?) is a co-owner of the parent,
00877     // let the same ownership be inherited by the new child (including
00878     // other co-owners!?).  Otherwise, make user(0) the sole (!?)
00879     // owner of the new child.
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; // in case of error
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     // Check for LongId overflow.  (We can skip this if our type is
00917     // volatileROEDirectory, as then the inserted object will get a
00918     // ShortId derived LongId.)
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()); // nonreplayable OK because not logged
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; // LongId computed during error checks
00966             newvs->pseudoInode = sid;
00967         } else {
00968             newvs->longid = new_longid; // LongId computed during error checks
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     // Log the operation
00978     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
00979         VestaSource::type != VestaSource::volatileROEDirectory) {
00980         char logrec[512];
00981         OBufStream ost(logrec, sizeof(logrec));
00982         // ('insf' longid arc sid master timestamp) or
00983         // ('insf' longid arc sid master timestamp fptag)
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           // generates another log record, handled separately by recovery
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; // in case of error
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     // Check for LongId overflow.  (We can skip this if our type is
01033     // volatileROEDirectory, as then the inserted object will get a
01034     // ShortId derived LongId.)
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         // Assign a sid.  Note that this is done before logging the
01051         // arguments, so upon replay, the same sid will be used again.
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()); // nonreplayable OK because not logged
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; // LongId computed during error checks
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     // Log the operation
01096     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01097         VestaSource::type != VestaSource::volatileROEDirectory) {
01098         char logrec[512];
01099         OBufStream ost(logrec, sizeof(logrec));
01100         // ('insu' longid arc sid master timestamp)
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           // generates another log record, handled separately by recovery
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; // in case of error
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         // Wrong parent type, or wrong type for child prototype
01140         return VestaSource::inappropriateOp;
01141     }
01142     
01143     if (dir != NULL && !dir->ac.check(who, AccessControl::read))
01144       return VestaSource::noPermission;
01145     
01146     // Perform dupeCheck and find existing entry to modify if any.
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     // Check for LongId overflow.
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             // Make a new, empty immutable directory.
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 /*(dir->VestaSource::type == VestaSource::mutableDirectory)*/ {
01200             // Deep copy dir to a new immutable directory.
01201             // Keep the same immutable bases, and don't make a new immutable
01202             // directory at all if there are no changes to a base.
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; // LongId computed during error checks
01218     newvs->master = mast;
01219     newvs->attribs = (Bit8*) attribAddr(entry);
01220 
01221     newvs->ac = this->ac;
01222     newvs->pseudoInode = indexToPseudoInode(index);
01223     
01224     // Log the operation
01225     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01226         VestaSource::type != VestaSource::volatileROEDirectory) {
01227         char logrec[512];
01228         OBufStream ost(logrec, sizeof(logrec));
01229         // dirlongid = (dir == NULL) ? NullLongId : dir->longid
01230         // ('insi' longid arc dirlongid master timestamp) or
01231         // ('insi' longid arc dirlongid master timestamp fptag)
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             // generates another log record, handled separately by recovery
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; // in case of error
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     // Check for LongId overflow.
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; // LongId computed during error checks
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     // Log the operation
01320     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01321         VestaSource::type != VestaSource::volatileROEDirectory) {
01322         char logrec[512];
01323         OBufStream ost(logrec, sizeof(logrec));
01324         // ('insa' longid arc master timestamp)
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             // generates another log record, handled separately by recovery
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; // in case of error
01357     // Parent or prototype child of wrong type?
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     // Check for LongId overflow.
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); // base
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; // LongId computed during error checks
01432     newvs->VestaSource::master = mast;
01433     newvs->attribs = (Bit8*) attribAddr(entry);
01434     newvs->ac = this->ac;
01435     newvs->sidref = this->sidref;
01436 
01437     // Log the operation
01438     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01439         VestaSource::type != VestaSource::volatileROEDirectory) {
01440         char logrec[512];
01441         OBufStream ost(logrec, sizeof(logrec));
01442         // dir==NULL: ('insm' longid arc NullLongId master timestamp)
01443         // otherwise: ('insm' longid arc dir->longid master timestamp)
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             // generates another log record, handled separately by recovery
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; // in case of error
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     // Check for LongId overflow.
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; // LongId computed during error checks
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     // Log the operation
01518     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01519         VestaSource::type != VestaSource::volatileROEDirectory) {
01520         char logrec[512];
01521         OBufStream ost(logrec, sizeof(logrec));
01522         // ('insg' longid arc master timestamp)
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             // generates another log record, handled separately by recovery
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; // in case of error
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     // Check for LongId overflow.
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; // LongId computed during error checks
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     // Log the operation
01594     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01595         VestaSource::type != VestaSource::volatileROEDirectory) {
01596         char logrec[512];
01597         OBufStream ost(logrec, sizeof(logrec));
01598         // ('inss' longid arc master timestamp)
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             // generates another log record, handled separately by recovery
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         // fromDir and "this" are the same directory
01651         fromDir->resync(); // discard cache for our caller's benefit
01652         fromDir = this;
01653     }
01654     
01655     // Look up the existing object
01656     VestaSource::errorCode err;
01657     VestaSource* target;
01658     err = fromDir->lookup(fromArc, target, who);
01659     if (err != VestaSource::ok) return err;
01660     
01661     // Check that fromDir is writeable
01662     if (!fromDir->ac.check(who, AccessControl::write)) {
01663         delete target;
01664         return VestaSource::noPermission;
01665     }
01666     
01667     // Be sure we are not creating a loop.  We need consider only
01668     // loops of mutable directories and loops of appendable
01669     // directories: An immutable directory cannot contain an
01670     // appendable or mutable child, an appendable directory cannot
01671     // contain a mutable child, and a mutable directory cannot contain
01672     // an appendable child.  A mutable or appendable directory can
01673     // have only one parent, because there is no operation that gives
01674     // a second parent to an existing one.  So we can test for
01675     // ancestry simply by checking whether one directory's longid is a
01676     // prefix of the other.
01677     if (target->longid.isAncestorOf(longid)) {
01678         delete target;
01679         return VestaSource::invalidArgs;
01680     }
01681 
01682     // Information needed to compute the LongId of the newly inserted
01683     // object.
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       // In this case, we'll be inserting a forwarding pointer first,
01690       // so the index of the renamed object will actually be the next
01691       // one after this.
01692       index += 2;
01693     }
01694 
01695     // Predict longid to be used for the new entry and check for
01696     // LongId overflow.
01697     LongId new_longid = longid.append(index);
01698     if(new_longid == NullLongId)
01699       {
01700         return VestaSource::longIdOverflow;
01701       }
01702 
01703     // Find where the new entry goes and do more error checking
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     // Log the operation
01713     bool needOwner = false, needCommit = false;
01714     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
01715         VestaSource::type != VestaSource::volatileROEDirectory) {
01716 
01717         // Copy the owner(s) in case those that would be inherited
01718         // from the new parent are different.
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         // ('ren' longid arc fromLongid fromArc timestamp)
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         // We need to commit this log entry before returning.
01734         needCommit = true;
01735     }
01736     Bit32 oldAttrib = target->firstAttrib();
01737     
01738     // Delete from the old parent, possibly with forwarding pointer
01739     if (fromDir->type == VestaSource::appendableDirectory) {
01740         if (oldEntry != NULL) {
01741             // assert(type(oldEntry) != VestaSource::deleted);
01742             fromVDC->setEntry(oldEntry, true, sameAsBase(oldEntry),
01743                               VestaSource::outdated, 0, 0, NULL);
01744         }
01745         // Leave a ghost if fromDir was master, else leave nothing.
01746         // Maybe latter case should leave a stub as a matter of policy?
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                   // If there is no base, the entry can't be shadowing
01762                   // anything, so set it to outdated right away.  This
01763                   // allows it to be compressed as part of a gap when
01764                   // we next take a checkpoint.
01765                   dtype = VestaSource::outdated;
01766               } else if (VRLogVersion >= 3) {
01767                   // If there is a base, look in it to see if the
01768                   // entry is shadowing anything.  Tedious, but it
01769                   // helps us give clean semantics to a _run_tool that
01770                   // deletes things from its directory: only names
01771                   // that existed in the initial binding and were
01772                   // deleted/renamed are bound to FALSE in the result,
01773                   // never names that were created and then deleted.
01774                   // It also helps a little with compression, as in
01775                   // the simpler-to-check NULL case just above.
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     // copy-on-write target if needed
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); // base
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     // Insert in the new parent
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); // cannot happen
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     // If we need to commit the change to the log..
01886     if(needCommit)
01887       {
01888         // If the object needs to have an #owner attribute added, do
01889         // that now.  We do this after the rename, as we're sure the
01890         // object will have attributes now (i.e. not be an obejct that
01891         // exists only in the immutable base).  We do this before
01892         // committing the rename to the log, as this will generate
01893         // additional log records handled separately by recovery.
01894         if(needOwner)
01895           {
01896             VestaSource *new_target = VDCLookupResult(this, newEntry, index);
01897             // This is only done in mutable and appendable
01898             // directories, so this object must have attributes.
01899             assert(new_target->hasAttribs());
01900             fromDir->ac.owner.getAttrib("#owner", copyOwnerCallback,
01901                                         new_target);
01902             delete new_target;
01903           }
01904         // Commit the change (or changes) to the log.
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         // An entry in the main rep hides this one in the base; skip it
01933         return true;
01934     } else {
01935         // Invoke the original callback
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   // Access check
01953   if (!ac.check(who, AccessControl::read))
01954     return VestaSource::noPermission;
01955     
01956   VDirChangeable cur = *this; // so that we can change cur.rep
01957   ArcTable hidden;
01958   // Iterate down the base chain (tail recursion elimination)
01959   for (;;) {
01960     // An immutableDirectory has only even indices; a mutableDirectory
01961     // has odd indices for its rep, even indices in its base chain.
01962     // The odd part of the index space precedes the even part.
01963     if (cur.VestaSource::type == VestaSource::immutableDirectory) {
01964       index = 2;
01965     } else {
01966       index = 1;
01967     }
01968     // Iterate through the rep blocks in this rep
01969     repBlock = cur.rep;
01970     for (;;) {
01971       // Iterate through the entries in this rep block
01972       entry = firstEntry(repBlock);
01973       while (!isEndMark(entry)) {
01974         bool skip = false;
01975 
01976         // Check if we need to skip this entry due to its
01977         // being deleted or outdated.
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         // Eliminate duplicates found in the base chain
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         // Skip entries before firstIndex
02003         if (firstIndex != 0) {
02004           if (index & 1) {
02005             // In a mutable rep.  Skip if firstIndex is even, or
02006             // odd but beyond where we are.
02007             if ((firstIndex & 1) == 0 ||
02008                 firstIndex > (index + indexOffset)) {
02009               skip = true;
02010             }
02011           } else {
02012             // In an immutable rep.  Skip if firstIndex is even
02013             // and beyond where we are.
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           // Get the correct pseudo-inode and shortid
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             // Ugh, need to find pseudo-inode of entry in base
02057             assert(cur.VestaSource::type != VestaSource::immutableDirectory);
02058             assert(indexOffset == 0);
02059             assert(cur.rep == rep); // i.e., at top of base chain
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           // Call the client back with this entry
02098           if (!callback(closure, type(entry), arcbuf, index + indexOffset,
02099                         pseudi, filesid, masterFlag(entry))) {
02100             // we are requested to stop
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       // end of rep block loop
02112 
02113       if (isMoreOrBase(repBlock) == isMore) {
02114         // Loop back to continue with next rep block
02115         repBlock =
02116           (Bit8*) VMemPool::lengthenPointer(moreOrBase(repBlock));
02117       } else {
02118         // Exit from rep loop
02119         break;
02120       }
02121     }
02122     // end of rep loop
02123 
02124     if (cur.VestaSource::type == VestaSource::immutableDirectory) {
02125       // Indices in rep are prepended to index space of base
02126       baseIndexOffset = indexOffset + ((cur.nextRawIndex() << 1) - 2);
02127     } else {        
02128       assert(indexOffset == 0);
02129       baseIndexOffset = 0;
02130     }
02131     
02132     // List the part in the base, if any.  We have to filter out
02133     // names that are hidden by something in the current rep.  This
02134     // is taken care of by the "hidden" table.
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       // Recurse: base has different object type
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       // Iterate: base has same object type.
02171       // This is essentially an optimized tail recursion, to
02172       // avoid stack overflow when the base chain is long.
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   //return VestaSource::ok;    // Not reached
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     // Access check
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         // Odd index; look in the rep
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         // Even index; look in the base first
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; //unused
02294         } else {
02295             oldValue = VMemPool::shortenPointer(baseres->rep);
02296         }
02297         oldMaster = baseres->master;
02298         delete baseres;
02299         
02300         // Check whether the name in arc has a sameAsBase entry
02301         // in the current rep, and if so, use the latter entry.
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         // Assign a sid.  Note that this is done before logging the
02321         // arguments, so upon replay, the same sid will be used again
02322         // and no copying will be done.
02323         int err;
02324         sid = CopyShortId(oldValue, err, copyMax);
02325         assert(sid != NullShortId);
02326     }
02327 
02328     // If entry is NULL, we need to make a new sameAsBase entry;
02329     // otherwise we need to modify the existing entry.
02330     
02331     // First log the change
02332     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
02333         VestaSource::type != VestaSource::volatileROEDirectory) {
02334         char logrec[512];
02335         OBufStream ost(logrec, sizeof(logrec));
02336         // ('makm' longid index sid)
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     // Then make the change
02345     Bit32 newValue;
02346     if (oldType == VestaSource::immutableFile) {
02347         newType = VestaSource::mutableFile;
02348         newValue = (Bit32) sid;
02349     } else {
02350         //      assert(oldType == VestaSource::immutableDirectory ||
02351         //             oldType == VestaSource::evaluatorDirectory ||
02352         //             oldType == VestaSource::evaluatorROEDirectory);
02353         newType = VestaSource::type;
02354         VDirChangeable* dest = NEW_CONSTR(VDirChangeable,
02355                                           (newType, defaultRepSize));
02356         dest->setIsMoreOrBase(dest->rep, isBase); // base
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     // If this directory has a shortid reference count, update it.
02374     if(sidref)
02375       {
02376         // If this used to be an immutable file, then its shortid
02377         // should not be present in the reference counter
02378         assert((oldType != VestaSource::immutableFile) ||
02379                (sidref->GetCount(oldValue) == 0));
02380 
02381         // The old type should not be a mutable file.
02382         assert(oldType != VestaSource::mutableFile);
02383 
02384         // If the new type is a mutable file, increment the reference
02385         // count for the mutable shortid.
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     // Check for LongId overflow
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     // Work around a past bug: ignore attempts to make a file in a
02420     // mutable directory immutable without supplying a fingerprint
02421     // (even from log!).
02422     if (newfptag == NULL &&
02423         VestaSource::type == VestaSource::mutableDirectory) {
02424       return;
02425     }
02426 
02427     // First log the change
02428     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
02429         VestaSource::type != VestaSource::volatileROEDirectory) {
02430         char logrec[512];
02431         OBufStream ost(logrec, sizeof(logrec));
02432         // ('maki' longid index) or
02433         // ('maki' longid index newfptag) or
02434         // ('maki' longid index newfptag newsid)
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     // If this directory has a shortid reference count, update it.
02451     if(sidref)
02452       sidref->Decrement(value(entry), false);
02453 
02454     // Then make the change
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         // Odd index; already in the mutable rep
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     // Find the immutable entry in the base
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     // Check whether the name in arc has an entry in the current rep.
02520     unsigned int dummyRawIndex;
02521     entry = findArc(arc, dummyRawIndex, true);
02522     if (entry != NULL) {
02523       // If there's an entry in the mutable portion with the same
02524       // name, the object from the immutable portion has been replaced
02525       // or deleted.
02526       return VestaSource::inappropriateOp;
02527     }
02528 
02529     // (What if there's an outdated sameAsBase entry?  If the file was
02530     // previously made mutable, then deleted, then replaced with
02531     // something else with the same name, that could happen.  However,
02532     // there would still have to be an entry with the same name.)
02533 
02534     // We need to make a new sameAsBase entry.
02535     
02536     // First log the change
02537     if (doLogging) {
02538         char logrec[512];
02539         OBufStream ost(logrec, sizeof(logrec));
02540         // ('copy2m' longid index)
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     // The mutable directory has changed, so we can't re-use a
02553     // previous snapshot of it.
02554     setSnapshot(0);
02555     
02556     result = VDCLookupResult(this, entry, index);
02557     if (result == NULL) return VestaSource::notFound;
02558     // Check for LongId overflow
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     // Avoid logging null changes
02592     if (state == masterFlag(entry)) return VestaSource::ok;
02593 
02594     // First log the change
02595     if (doLogging && VestaSource::type != VestaSource::volatileDirectory &&
02596         VestaSource::type != VestaSource::volatileROEDirectory) {
02597         char logrec[512];
02598         OBufStream ost(logrec, sizeof(logrec));
02599         // ('mast' longid index state)
02600         ost << "(mast " << longid << " " << index << " "
02601           << (int) state << ")\n";
02602         VRLog.start();
02603         VRLog.put(ost.str());
02604         VRLog.commit();
02605     }
02606     
02607     // Then make the change
02608     setMasterFlag(entry, state);
02609     return VestaSource::ok;
02610 }
02611 
02612 
02613 
02614 // Garbage collection support
02615 // These methods tend to know more about the packed representation
02616 void
02617 VDirChangeable::mark(bool byName, ArcTable* hidden) throw ()
02618 {
02619     bool newHidden = (hidden == NULL);
02620     if (newHidden) hidden = NEW(ArcTable);
02621     
02622     // Loop through entries to set inUse flags of entries, set
02623     //  hasName flags of child directories, and mark attributes.
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); // must set in more blocks for sweep
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                         // Attributes in a non-appendable non-mutable
02654                         // directory?  Not supposed to happen.
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                                 // Must visit later byName.  OK to
02676                                 // leave visited true in more blocks
02677                                 // of child, because it is set there
02678                                 // only to tell the sweep phase the
02679                                 // blocks are not garbage.
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); // must visit byName
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             // Iterate on more block, or on base directory that is not
02712             // already known to have a name of its own.  In the latter
02713             // case, we either have visited the directory by name already
02714             // or will do so later, so it's OK to skip it here.  (In fact,
02715             // we *must* skip it here, or we will incorrectly mark it as
02716             // having been visited by name!  This was formerly a bug,
02717             // fixed in /vesta/src.dec.com/vesta/repos/91.
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; // implement above comment
02725         } else if (isMoreOrBase(curRepBlock) == isBase) {
02726             // Recurse on base
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     // Loop through entries to recurse on child directories.
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                         // value should not be here; leftover in checkpoint
02784                         // from a bug that is now fixed.
02785                         setValue(entry, 0);
02786                       } else {
02787                         VForward* vf =
02788                           (VForward*) VMemPool::lengthenPointer(value(entry));
02789                         assert(VMemPool::type(vf) == VMemPool::vForward);
02790                         // Check if vf still points to anything useful
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             // Iterate on more block, or on base directory that is not
02812             // already known to have a name of its own.  See comment on
02813             // previous loop.
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     // Recurse on snapshot if any
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 /* Statistics; examine in debugger */
02838 /* Accurate only immediately after a sweep (source weed). */
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 /* end statistics */
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                 // Quit early if write to sidfile fails
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                 // Subtract kept dirsids from table to produce a list
02944                 //  of reusable ones.
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     // Rebuild the DirShortId table by adding all extant immutable
02977     // directories, and rebuild the FPShortId table by adding every
02978     // immutableDirectory and every immutable or appendable directory
02979     // entry for an immutableFile.  Because this is a sweep of raw
02980     // memory, we don't get to process each directory as a whole; we
02981     // see the more-blocks separately from the first block.
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     // Rebuild file fp => sid table, and get the size of this block.
02997     Bit8* entry = vs.firstEntry(vs.rep);
02998     while (!vs.isEndMark(entry)) {
02999         if ((immutable || appendable) &&
03000             VDirChangeable::type(entry) == VestaSource::immutableFile) {
03001             // Safe to point to this entry
03002             SetFPFileShortId(entry);
03003         }
03004         entry = nextEntry(entry);
03005     }
03006 
03007     // Compute size
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));    // type
03017   ckpt.write((const char*)&gapsize, sizeof(gapsize)); // gapsize
03018   gapsize = 0;
03019   ckpt.write((const char*)&gapsize, sizeof(gapsize)); // attribs = 0
03020   ckpt.put(0);                                        // arcLen = 0
03021   nextSP += 10;
03022 }
03023 
03024 Bit32
03025 VDirChangeable::checkpoint(Bit32& nextSP, fstream& ckpt) throw ()
03026 {
03027     // Postorder walk of the directory DAG
03028     if (visited(rep)) return moreOrBase(rep); // reused field
03029     
03030     // Loop through entries to recurse on child directories
03031     //  and to checkpoint attributes.
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                   // Attributes in a non-appendable non-mutable
03094                   // directory?  Not supposed to happen.
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     // Recurse on base
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     // Recurse on snapshot
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     // Finally, write this object to the checkpoint file
03163     Bit32 newSP = nextSP; // remember starting point
03164     
03165     // Write flags
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     // Write base pointer
03175     ckpt.write((char *) &newBaseSP, sizeof(newBaseSP));
03176     
03177     // Write other information that comes before the entries
03178     ckpt.write((char *) &rep[VDIRCH_TIMESTAMP], VDIRCH_ENTRIES - VDIRCH_TIMESTAMP);
03179     nextSP += VDIRCH_ENTRIES;
03180     
03181     // Write all the entries, converting runs of outdated entries
03182     // with no forwarding pointer into gaps.
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         // Accumulate existing gaps into current gap.
03203         gapsize += value(entry);
03204       } else if (etype == VestaSource::outdated &&
03205                  value(entry) == 0 && !sameAsBase(entry)) {
03206         // Accumulate outdated entries with no VForward into current gap.
03207         gapsize++;
03208       } else if (VRLogVersion >= 2 && etype == VestaSource::deleted &&
03209                  value(entry) == 0 && base() == NULL) {
03210         // No need for a deleted entry if there is no base for it to
03211         // shadow something in and no VForward.  With VRLogVersion >=
03212         // 2, the only place where such entries formerly made a
03213         // difference when replaying a log (copyMutableToImmutable)
03214         // now ignores them, so we can safely crush them out here.
03215         // (In fact, such entries can exist only if created under an
03216         // old log version, so the test here is useful only during the
03217         // transition period between the old and new versions.)
03218         gapsize++;
03219       } else {
03220         // Write out other entries      
03221         // First flush the last gap
03222         if (gapsize > 0) {
03223           VDCWriteGap(nextSP, ckpt, gapsize);
03224           gapsize = 0;
03225         }
03226         // Then write the entry
03227         ckpt.write((char *) entry, next - entry);
03228         nextSP += next - entry;
03229       }
03230       entry = next;
03231     }
03232 
03233     // Write the end mark
03234     ckpt << (Bit8) 0xff;
03235     nextSP++;
03236     
03237     Bit32 newFreeLen;
03238 #if 0
03239     // Write out some free space
03240     if (VestaSource::type == VestaSource::immutableDirectory) {
03241         newFreeLen = 0;
03242     } else {
03243         newFreeLen = defaultRepSize / 4; // arbitrary amount
03244     }
03245 #else
03246     // Don't write out any free space; saves memory overall
03247     newFreeLen = 0;
03248 #endif
03249     // Pad to the required alignment
03250     // Assumes 2's complement negation
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     // Crash if writing to the checkpoint file is failing
03258     if (!ckpt.good()) {
03259         Repos::dprintf(DBG_ALWAYS, 
03260                        "write to checkpoint file failed: errno %d\n", errno);
03261         assert(ckpt.good());    // crash
03262     }
03263     
03264     setVisited(rep, true);
03265     setMoreOrBase(rep, newSP);  // reuse (smash) this field 
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     // Loop through entries
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                     // We can unlink this shortid if this is a
03295                     // volatile directory or if this isn't a nested
03296                     // log transaction.  (If this is a mutable
03297                     // directory and we're in a nested log
03298                     // transaction, it's not safe to unlink it yet, so
03299                     // we leave it around for the weeder to clean up.)
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                   // Child should be the same type as this directory
03311                   assert(type(entry) == VestaSource::type);
03312 
03313                   // Recurse on entry
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                 // Can't happen; we never put an entry in volatile
03325                 // directory that points directly to an evalutor directory.
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             // Free current rep block
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     // Do not recurse on base; normally base will be referenced from
03352     // an entry of the parent directory's base and deleted from there.
03353     
03354     // Free last rep block
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   // This operation is only appropriate on mutable and immutable
03366   // directories.
03367   if(VestaSource::type != VestaSource::immutableDirectory &&
03368      VestaSource::type != VestaSource::mutableDirectory)
03369     return VestaSource::inappropriateOp;
03370 
03371   // Access check: ownership required to collapse the base of a
03372   // directory.
03373   if(!ac.check(who, AccessControl::ownership))
03374     return VestaSource::noPermission;
03375 
03376   // If we have no basis directory, there's nothing to do.
03377   if(base() == 0)
03378     return VestaSource::ok;
03379 
03380   // This is our original base directory.  We'll be collapsing it and
03381   // replacing our pointer to it with an identical version with no
03382   // base behind it.
03383   VDirChangeable originalBase(VestaSource::immutableDirectory, base());
03384 
03385   // If our base has no base, then collapsing our base won't make for
03386   // a more efficient representation, so there's nothing to do.
03387   // (Also, if we actually did anything in this case, we could open
03388   // ourselves up to a denial of service attack.)
03389   if(originalBase.base() == 0)
03390     return VestaSource::ok;
03391 
03392   // Create the collapsed representation of our base.
03393   VDirChangeable *collapsedBase = originalBase.collapse();
03394 
03395   // Set the base pointer of this object to the collapsed version of
03396   // the base.
03397   assert((repEndCache != 0) && (lastRepBlockCache != 0));
03398   setMoreOrBase(lastRepBlockCache,
03399                 VMemPool::shortenPointer(collapsedBase->rep));
03400 
03401   // Log the operation
03402   if (doLogging)
03403     {
03404       char logrec[128];  // Should actually max out at 73 characters
03405       OBufStream ost(logrec, sizeof(logrec));
03406       // ('colb' longid)
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   // Directory of the current list call
03420   VestaSource *vs;
03421   // Mutable shortid referenc count we're accumulating
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       // Mutable files are what we're looking for.  Note the reference
03436       // ot this one.
03437       cl->sidref->Increment(filesid);
03438       break;
03439     case VestaSource::mutableDirectory:
03440       // Recurse into mutable directories
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                              /*who=*/ NULL, /*deltaOnly=*/ true);
03448         assert(err == VestaSource::ok);
03449         delete newcl.vs;
03450       }
03451       break;
03452 
03453       // Note that we don't need to process any other types.
03454       // Immutable files don't go into the reference counter.
03455       // Immutable directories can't contain mutable files.  Nothing
03456       // else exists in mutable directories.
03457     }
03458 
03459   return true;
03460 }
03461 
03462 ShortIdRefCount *VDirChangeable::rebuildMutableSidref() throw()
03463 {
03464   // This can only be used on the mutable root
03465   assert(this->VestaSource::type == VestaSource::mutableDirectory);
03466   assert(this->longid == MutableRootLongId);
03467 
03468   // Recursively build the shoritd refcount for this directory
03469   buildMutableSidrefClosure cl;
03470   cl.vs = this;
03471   cl.sidref = new ShortIdRefCount;
03472   VestaSource::errorCode err = this->list(0, buildMutableSidrefCallback, &cl,
03473                                           /*who=*/ NULL, /*deltaOnly=*/ true);
03474   assert(err == VestaSource::ok);
03475 
03476   return cl.sidref;
03477 }
03478 
03479 void VDirChangeable::buildMutableSidref() throw()
03480 {
03481   // This can only be used once to initialize sidref
03482   assert(this->sidref == 0);
03483 
03484   this->sidref = this->rebuildMutableSidref();
03485 }
03486 
03487 void VDirChangeable::checkMutableSidref(bool correct) throw()
03488 {
03489   // This can only be used once sidref has already been initialized
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; // endMark
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                 // Found
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     // Not found
03655     // Might as well fill the caches while we're here
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         // Found
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   // Not found
03701   // Might as well fill the caches while we're here
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   // cannot use setEntry to change between gaps and non-gaps
03725   assert((type(entry) == VestaSource::gap) == (newType == VestaSource::gap));
03726   // preserve hasEFPTag bit
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         // Add another block
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; // endMark
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); // caches were valid, need update
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;      // new endMark
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 // Knows about the packed representation
03798 // Warning: return value does not have a valid LongId, master flag, etc.;
03799 //  of the VestaSource fields, only the rep field is valid.
03800 // fptag is the FP::Tag to use if a new immutable directory is created;
03801 //  it is ignored if an existing immutable directory is reused.
03802 VDirChangeable*
03803 VDirChangeable::copyMutableToImmutable(const FP::Tag& fptag) throw ()
03804 {
03805     if (nextRawIndex() == 1 && base() != NULL) {
03806         // This directory has no new entries but has a base, so
03807         // return the base.  Note: if the timestamp differs from the
03808         // base, we lose that information.
03809         return NEW_CONSTR(VDirChangeable,
03810                           (VestaSource::immutableDirectory, base()));
03811     }
03812     
03813     // Make the new directory.  We have to make it now to save the
03814     //  results of the recursion.  We will delete it later if it turns
03815     //  out we can reuse an old snapshot.  (Ugh.)
03816     int size = totalRepSize();
03817     VDirChangeable* dest =
03818       NEW_CONSTR(VDirChangeable, (VestaSource::immutableDirectory, size));
03819     
03820     // Copy base and timestamp
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     // Copy the entries.  A deep copy is required, except that it is
03831     // okay to share an immutable base (or descendent).
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                     // Recursively copy this subdirectory
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                         // Recursive call made a new snapshot;
03858                         // current call must do so too.
03859                         setSnapshot(0);
03860                     }
03861                     delete thisChild;
03862                     delete destChild;
03863                 }                            
03864                 break;
03865               case VestaSource::mutableFile:
03866                 {
03867                     // Set the file to be immutable in the *source* as
03868                     // well as the destination.  There had better be no
03869                     // mutableFile entries that point to the same shortId
03870                     // outside the tree being copied.
03871                     setType(entry, VestaSource::immutableFile);
03872                     if (doLogging) {
03873                         ShortId sid = (ShortId) value(entry);
03874                         // Note: we need a writable file descriptor to
03875                         // call fsync.  (Maybe not on all systems, but
03876                         // definitely on some.)
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                         // Now that it's read-only on disk, get rid of
03885                         // any writable file descriptors in the
03886                         // FdCache.
03887                         FdCache::flush(sid, FdCache::rw);
03888                         // Flush any pending writes to disk.
03889                         res = fsync(fd);
03890                         assert(res != -1);
03891                         // Rather than returning this writable file
03892                         // descriptor to the FdCache, close it.
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                 // Don't copy this entry
03910                 entry = next;
03911                 continue;
03912               case VestaSource::immutableFile:
03913                 // One more chance to notice we have a duplicate file.
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                     // Safe to record this mapping only if we are sure
03921                     // we will not discard the snapshot we are making now
03922                     // in favor of an older one.  If there is an older
03923                     // snapshot, this fingerprint should already be mapped
03924                     // to an entry in that one, so not recording it again
03925                     // is OK.
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                   // No need to copy a deleted entry if there is no base
03935                   // for it to shadow something in.
03936                   entry = next;
03937                   continue;
03938                 }
03939                 memcpy(p, entry, next - entry);
03940                 setValue(p, 0);  // drop pointer to VForward if any
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     // Is the snapshot we just made identical to the previous one?
03958     if (snapshot() != 0) {
03959         // Yes; discard this one and use the old one.
03960         // Note: we use the old one even if the timestamp has 
03961         // changed, as long as nothing else has.
03962         // Note: it is safe to delete the new snapshot only because
03963         // we know there are no pointers into it.  In particular, the
03964         // FPShortId table cannot point into it.
03965         VMemPool::free(dest->rep, size, VMemPool::vDirImmutable);
03966         dest->rep = (Bit8*) VMemPool::lengthenPointer(snapshot());
03967         dest->repEndCache = NULL;
03968     } else {
03969         // No; complete this one and use it.
03970         setSnapshot(VMemPool::shortenPointer(dest->rep));
03971         
03972         // Allocate a ShortId
03973         dest->setID(NewDirShortId(fptag, VMemPool::shortenPointer(dest->rep)));
03974 
03975         // Add entry to reverse lookup table (fp => sid)
03976         SetFPDirShortId(dest->rep);
03977         
03978         // Fill in the end
03979         *p = 0xff; // endMark
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(/*OUT*/VestaSource::directoryStats &result,
03994                                  AccessControl::Identity who)
03995   throw (SRPC::failure)
03996 {
03997   // Zero the result
03998   result.baseChainLength = result.usedEntryCount = result.usedEntrySize =
03999     result.totalEntryCount = result.totalEntrySize = 0;
04000 
04001   // Access check
04002   if (!ac.check(who, AccessControl::read))      
04003     return VestaSource::noPermission;
04004 
04005   // Set of names seen so far during our counting.
04006   ArcTable used;
04007     
04008   // Loop over more and base blocks.
04009   Bit8* curRepBlock = rep;
04010   for (;;) {
04011     Bit8 *entry, *next;
04012     entry = firstEntry(curRepBlock);
04013     // Loop over entries in this rep block.
04014     while (!isEndMark(entry))
04015       {
04016         result.totalEntryCount++;
04017         next = nextEntry(entry);
04018         // If this is an entry type that has a name...
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             // If we haven't marked this name as used yet...
04027             if (!used.Get(k, v))
04028               {
04029                 used.Put(k, ArcValue());
04030                 // We need to record the name of deleted entries as
04031                 // used so we don't count a shadowed entry as used,
04032                 // but we don't count the deleted entry as used.
04033                 if(type(entry) != VestaSource::deleted)
04034                   {
04035                     result.usedEntryCount++;
04036                     result.usedEntrySize += (next-entry);
04037                   }
04038               }
04039           }
04040         entry = next;
04041       }
04042     // Add the size of all entries in this rep block to the total
04043     // entry size.
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       // When we're following the base chain, increment the base
04050       // count.
04051       if(isMoreOrBase(curRepBlock) == isBase)
04052         result.baseChainLength++;
04053       // Iterate on more block, or on base directory.
04054       curRepBlock =
04055         (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
04056     } else {
04057       // Otherwise no more blocks and no (suitable) base, so we're
04058       // done.
04059       break;
04060     }
04061   }
04062 
04063   // All is well.
04064   return VestaSource::ok;
04065 }
04066 
04067 VDirChangeable*
04068 VDirChangeable::collapse(unsigned int newSize)
04069   throw()
04070 {
04071   // This operation only makes sense on immutable directories.
04072   assert(VestaSource::type == VestaSource::immutableDirectory);
04073 
04074   // Set of names seen so far during our counting.
04075   ArcTable used;
04076 
04077   // If we've been told to allocate a block smaller than we know our
04078   // entries use, ignore the requested size.
04079   if(repEndCache && (totalRepSizeCache > newSize))
04080     newSize = totalRepSizeCache;
04081 
04082   // Make the new directory.
04083   VDirChangeable* dest =
04084     NEW_CONSTR(VDirChangeable, (VestaSource::immutableDirectory, newSize));
04085 
04086   // Copy the original fptag, directory shortid, and timestamp.
04087   dest->VestaSource::fptag = this->fptag();
04088   dest->setFPTag(dest->VestaSource::fptag);
04089   dest->setID(this->getID()); // Note: identical dir shortid
04090   dest->setTimestampField(this->timestamp());
04091 
04092   // Update the directory shortid and fp=>rep mapping.
04093   SetDirShortId(this->getID(), VMemPool::shortenPointer(dest->rep));
04094   SetFPDirShortId(dest->rep);
04095 
04096   // Loop over more and base blocks.
04097   Bit8* curRepBlock = rep;
04098   Bit32 gapsize = 0;
04099   for (;;) {
04100     Bit8 *entry;
04101     entry = firstEntry(curRepBlock);
04102     // Loop over entries in this rep block.
04103     while (!isEndMark(entry))
04104       {
04105         if(type(entry) == VestaSource::gap)
04106           {
04107             // Accumulate existing gaps into current gap.
04108             gapsize += value(entry);
04109           }
04110         else if(type(entry) == VestaSource::outdated)
04111           {
04112             // Treat an outdated like a size 1 gap.
04113             gapsize++;
04114           }
04115         // If this is an entry type that has a name...
04116         else
04117           {
04118             ArcKey k;
04119             ArcValue v;
04120             k.s = arc(entry);
04121             k.slen = arcLen(entry);
04122 
04123             // If we haven't marked this name as used yet, do so.
04124             if (!used.Get(k, v))
04125               {
04126                 used.Put(k, ArcValue());
04127 
04128                 // If this is not a deleted entry, we need to copy it
04129                 // to dest.
04130                 if(type(entry) != VestaSource::deleted)
04131                   {
04132                     // If we need to insert a gap, do so.
04133                     if(gapsize > 0)
04134                       {
04135                         dest->appendEntry(false, false, VestaSource::gap,
04136                                           gapsize, 0, 0, "", 0);
04137                         gapsize = 0;
04138                       }
04139 
04140                     // Append a copy of this entry to the destination.
04141                     // Note: because this is an immutable directory,
04142                     // sameAsBase is always false and there are no
04143                     // attributes.
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                     // Treat deleted entries as a gap of 1.
04154                     gapsize++;
04155                   }
04156               }
04157             else
04158               {
04159                 // Treat entries with shadowed names as a gap of 1.
04160                 gapsize++;
04161               }
04162           }
04163         entry = nextEntry(entry);
04164       }
04165     // If there are no more blocks, we're done.
04166     if(isMoreOrBase(curRepBlock) == isNeither)
04167       break;
04168     // Iterate on more block, or on base directory.
04169     curRepBlock =
04170       (Bit8*) VMemPool::lengthenPointer(moreOrBase(curRepBlock));
04171   }
04172 
04173   return dest;
04174 }

Generated on Mon May 8 00:48:48 2006 for Vesta by  doxygen 1.4.2