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

VestaSource.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 // VestaSource.C
00021 //
00022 // Server-side implementation for VestaSource.H
00023 //
00024 
00025 #include <assert.h>
00026 #include <iostream>
00027 #include <iomanip>
00028 #include "VestaSource.H"
00029 #include "VDirChangeable.H"
00030 #include "VDirVolatileRoot.H"
00031 #include "VDirEvaluator.H"
00032 #include "VForward.H"
00033 #include "SourceOrDerived.H"
00034 #include "Recovery.H"
00035 #include "VRWeed.H"
00036 #include "VRConcurrency.H"
00037 #include "VestaConfig.H"
00038 #include "VLeaf.H"
00039 #include "DirShortId.H"
00040 #include "FdCache.H"
00041 #include "VLogHelp.H"
00042 #include "FPShortId.H"
00043 #include "logging.H"
00044 #include "UniqueId.H"
00045 #include "VestaSourceImpl.H"
00046 #include "CopyShortId.H"
00047 #include "MutableSidref.H"
00048 
00049 #include "timing.H"
00050 #include "lock_timing.H"
00051 
00052 #include <BufStream.H>
00053 #include <FdStream.H>
00054 
00055 using std::cerr;
00056 using std::endl;
00057 using std::fstream;
00058 using Basics::OBufStream;
00059 
00060 // Exported globals
00061 VestaLog VRLog;
00062 int VRLogVersion = 1; // for recovering logs from the beginning of time
00063 static const int LogMaxVersion = 3;  // version 2 avoids some "deleted" entries
00064                                      // version 3 avoids more of them
00065 ReadersWritersLock StableLock(true);
00066 ReadersWritersLock VolatileRootLock(true);
00067 
00068 // Module globals
00069 static VestaSource* repositoryRoot; // the /vesta directory
00070 static VestaSource* mutableRoot;    // directory of mutable directories
00071 static VDirVolatileRoot* volatileRoot;  // directory of volatile directories
00072 static Bit32 repositoryRootAttribsRep = 0;  // really a VestaAttribsRep@
00073 static Bit32 mutableRootAttribsRep = 0;     // really a VestaAttribsRep@
00074 static Bit32 volatileRootAttribsRep = 0;
00075 static Bit32 emptyAttribsRep = 0;
00076 
00077 // The prefix TextD is also used in the evaluator for the same purpose;
00078 // TextX and (PATHNAME) are not used in the evaluator.  (PATHNAME) is
00079 // used instead of something like TextP for historical reasons.
00080 const FP::Tag contentsFPTag("TextD");    // FP a nonexecutable file by content
00081 const FP::Tag executableFPTag("TextX");  // FP an executable file by content
00082 const FP::Tag pathnameFPTag("(PATHNAME)/vesta");  // FP by initial pathname
00083 
00084 // A LongId encodes a Name.  Each Arc is represented as the 1-origin
00085 // index of the Arc within the underlying Vesta directory
00086 // representation.  (Thus that index must remain constant at a given
00087 // site.)  Indices are assigned in a somewhat strange way to deal with
00088 // the fact that some kinds of directory consist of a base immutable
00089 // part plus a mutable part that records modifications:  All indices
00090 // in an immutableDirectory are even, and all indices within (the
00091 // mutable part of) any other type of directory are odd.
00092 //
00093 // The indices are packed into the LongId using a
00094 // variable-length code.  An index is stored in a sequence of bytes,
00095 // with the low-order 7 bits in the first byte, the next 7 bits in the
00096 // second byte, etc.  The high-order bit of each byte is 0 if this is
00097 // the last byte in the given index, 1 otherwise. 
00098 //
00099 // LongIds for names in the repository (descendents of /vesta) have
00100 // the Arc within /vesta as their first index, and are terminated by
00101 // the first 0 index.  LongIds for names in the mutable directory tree
00102 // at a site have 0, 1 as their first two indices and are terminated
00103 // by the next 0 index.  Those in the volatile tree have 0, 2, etc.
00104 
00105 bool VestaSource::doLogging = false;
00106 
00107 // Look up LongId to get a VestaSource.  Return NULL if the LongId
00108 // does not correspond to any extant VestaSource.  Assumes the LongId
00109 // is of valid format.
00110 VestaSource*
00111 LongId::lookup(LongId::lockKindTag lockKind, ReadersWritersLock** lock)
00112   throw (SRPC::failure /*can't really happen*/)
00113 {
00114     VestaSource* vs;
00115     VestaSource* child;
00116     const Bit8* next = &value.byte[0];
00117     int kind;
00118     if (*next == 0) {
00119         kind = next[1];
00120         switch (kind) {
00121           case 0:
00122             // RepositoryRoot
00123             vs = VestaSource::repositoryRoot(lockKind, lock);
00124             if (vs == NULL) return NULL;
00125             break;
00126           case 1:
00127             // Mutable
00128             vs = VestaSource::mutableRoot(lockKind, lock);
00129             if (vs == NULL) return NULL;
00130             next += 2;
00131             break;
00132           case 2:
00133             // Volatile
00134             if (next[2] == 0) {
00135               // Looking up the root itself
00136               vs = VestaSource::volatileRoot(lockKind, lock);
00137             } else {
00138               ReadersWritersLock* dummy;
00139               // Below the volatile root
00140               switch (lockKind) {
00141               case LongId::writeLock:
00142               case LongId::readLock:
00143                 // We need a read lock on the root, but that is not
00144                 // the lock our caller is interested in.  We don't
00145                 // need to save the pointer; we know it will be
00146                 // &VolatileRootLock.  We will release this lock
00147                 // after traversing into the root of the subtree.
00148                 vs = VestaSource::volatileRoot(LongId::readLock, &dummy);
00149                 RWLOCK_LOCKED_REASON(dummy, "LongId::lookup below volatile");
00150                 break;
00151               case LongId::writeLockV:
00152               case LongId::readLockV:
00153               case LongId::checkLock:
00154               case LongId::noLock:
00155                 // We already have a lock on the root
00156                 vs = VestaSource::volatileRoot(LongId::noLock);
00157                 break;
00158               }
00159             }
00160             if (vs == NULL) return NULL;
00161             next += 2;
00162             break;
00163           case 3:
00164             // ShortId for an immutable directory
00165             // Lock the repository root.
00166             vs = VestaSource::repositoryRoot(lockKind, lock);
00167             if (vs == NULL) return NULL;
00168             next += 2;
00169             break;
00170           case 4:
00171             // ShortId for a file
00172             // No lock needed
00173             vs = NULL;
00174             if (lockKind == LongId::readLock ||
00175                 lockKind == LongId::writeLock ||
00176                 lockKind == LongId::readLockV ||
00177                 lockKind == LongId::writeLockV) {
00178                 *lock = NULL;
00179             }
00180             next += 2;
00181 
00182             break;
00183           case 255:
00184             // Must be NullLongId
00185           default:
00186             if (lockKind == LongId::readLock ||
00187                 lockKind == LongId::writeLock ||
00188                 lockKind == LongId::readLockV ||
00189                 lockKind == LongId::writeLockV) {
00190                 *lock = NULL;
00191             }
00192             return NULL;
00193         }
00194     } else {
00195         // Must be a child of RepositoryRoot
00196         kind = 0;
00197         vs = VestaSource::repositoryRoot(lockKind, lock);
00198         if (vs == NULL) return NULL;
00199     }
00200     for (;;) {
00201         // Extract the next index
00202         unsigned int index = 0;
00203         int shift = 0;
00204         while (next < &value.byte[sizeof(value)]) {
00205             index |= (*next & 0x7f) << shift;
00206             shift += 7;
00207             if ((*next++ & 0x80) == 0) break;
00208         }
00209         if (index == 0) break;
00210         VestaSource::errorCode err;
00211         switch (kind) {
00212           default:
00213             err = vs->lookupIndex(index, child, NULL);
00214             break;
00215 
00216           case 2:
00217             // Special code to look up in the volatile root
00218             RECORD_TIME_POINT;
00219             err = ((VDirVolatileRoot*)vs)->
00220               lookupIndexAndLock(index, child, lockKind, lock);
00221             RECORD_TIME_POINT;
00222             if (lockKind == LongId::readLock ||
00223                 lockKind == LongId::writeLock) {
00224               VolatileRootLock.releaseRead();
00225               RECORD_TIME_POINT;
00226             }
00227             kind = -2; // force into default case on further iterations
00228             break;
00229 
00230           case 3:
00231             // Special code to look up dir shortid
00232             if (SourceOrDerived::dirShortId((ShortId) index)) {
00233               Bit32 childSP = GetDirShortId((ShortId) index);
00234               if (childSP == 0) {
00235                 err = VestaSource::notFound;
00236               } else {
00237                 VDirChangeable* vdc = 
00238                   NEW_CONSTR(VDirChangeable,
00239                              (VestaSource::immutableDirectory,
00240                               (Bit8*) VMemPool::lengthenPointer(childSP)));
00241                 child = vdc;
00242                 memset(child->longid.value.byte, 0, sizeof(value));
00243                 memcpy(child->longid.value.byte, value.byte, next - value.byte);
00244                 child->master = true;
00245                 child->fptag = vdc->fptag();
00246                 child->ac.owner.attribs = (Bit8*) &emptyAttribsRep;
00247                 child->ac.group.attribs = (Bit8*) &emptyAttribsRep;
00248                 child->ac.mode = 0555;
00249                 child->pseudoInode = index;
00250                 err = VestaSource::ok;
00251               }
00252               kind = -2; // force into default case on further iterations
00253             } else {
00254               err = VestaSource::notFound;
00255             }
00256             break;
00257 
00258           case 4:
00259             // Special code to look up file shortid
00260             if (!SourceOrDerived::dirShortId((ShortId) index)) {
00261               // Assume mutable by default; glue.C corrects if needed
00262               child = NEW_CONSTR(VLeaf,
00263                                  (VestaSource::mutableFile, (ShortId)index));
00264               child->longid = *this;
00265               child->master = true;
00266               child->fptag.FromBytes(&this->value.byte[8]);
00267               child->ac.owner.attribs = (Bit8*) &volatileRootAttribsRep;
00268               child->ac.group.attribs = (Bit8*) &volatileRootAttribsRep;
00269               child->ac.mode = 0666;
00270               child->pseudoInode = index;
00271               err = VestaSource::ok;
00272               next = &this->value.byte[24]; // end loop
00273             } else {
00274               err = VestaSource::notFound;
00275             }
00276             break;
00277         }
00278         if (vs != ::repositoryRoot && vs != ::mutableRoot &&
00279             vs != ::volatileRoot && vs != NULL)
00280           delete vs;
00281         if (err != VestaSource::ok) {
00282             if (lock && *lock &&
00283                 (lockKind == LongId::readLock ||
00284                  lockKind == LongId::writeLock ||
00285                  lockKind == LongId::readLockV ||
00286                  lockKind == LongId::writeLockV)) {
00287               (*lock)->release();
00288               *lock = NULL;
00289             }
00290             return NULL;
00291         }
00292         vs = child;
00293     }
00294     if (vs == ::repositoryRoot || vs == ::mutableRoot || vs == ::volatileRoot) {
00295         // Avoid sharing, so caller can safely delete return value
00296         vs = vs->copy();
00297     }
00298     return vs;
00299 }
00300 
00301 
00302 bool
00303 LongId::valid()
00304   throw (SRPC::failure /*can't really happen*/)
00305 {
00306   // It would be nicer if this routine avoided doing an allocation and
00307   // free in the case where the longid is valid.  However, at present
00308   // this implementation is not actually ever called, so there is no
00309   // point in optimizing it.  It is included only for completeness.
00310   // The client-side implementation does avoid an allocation within
00311   // the client address space, for what that's worth.
00312   VestaSource *vs = lookup();
00313   if (vs) {
00314     delete vs;
00315     return true;
00316   } else {
00317     return false;
00318   }
00319 }
00320 
00321 // Recovery code
00322 
00323 static void
00324 VersCallback(RecoveryReader* rr, char& c)
00325      throw(VestaLog::Error, VestaLog::Eof)
00326 {
00327     long lversion;
00328     rr->getLong(c, lversion);
00329     VRLogVersion = lversion;
00330     if (VRLogVersion > LogMaxVersion) {
00331       Repos::dprintf(DBG_ALWAYS, "log version is %d; max supported version is %d\n",
00332                      VRLogVersion, LogMaxVersion);
00333       exit(2);
00334     }
00335 }
00336 
00337 static void
00338 DelCallback(RecoveryReader* rr, char& c)
00339      throw(VestaLog::Error, VestaLog::Eof)
00340 {
00341     LongId longid;
00342     char arc[MAX_ARC_LEN+1];
00343     long ltimestamp;
00344     rr->getLongId(c, longid.value);
00345     rr->getQuotedString(c, arc, sizeof(arc));
00346     rr->getLong(c, ltimestamp);
00347     VestaSource* vs = longid.lookup();
00348     // Sanity check for validity of the LongId
00349     if(vs == 0)
00350       {
00351         cerr << "FATAL ERROR in recovery: invalid LongId in \"del\":" << endl
00352              << "\tlongid = " << longid << endl;
00353         abort();
00354       }
00355     VestaSource::errorCode
00356       err = vs->reallyDelete(arc, NULL, false, ltimestamp);
00357     assert(err == VestaSource::ok);
00358     delete vs;
00359 }
00360 
00361 static void
00362 InsfCallback(RecoveryReader* rr, char& c)
00363      throw(VestaLog::Error, VestaLog::Eof)
00364 {
00365     LongId longid;
00366     char arc[MAX_ARC_LEN+1];
00367     unsigned long ulsid;
00368     long lmaster;
00369     long ltimestamp;
00370     FP::Tag fptag;
00371     FP::Tag* pfptag;
00372 
00373     rr->getLongId(c, longid.value);
00374     rr->getQuotedString(c, arc, sizeof(arc));
00375     rr->getULong(c, ulsid);
00376     rr->getLong(c, lmaster);
00377     rr->getLong(c, ltimestamp);
00378     rr->skipWhite(c);
00379     if (c == ')') {
00380         pfptag = NULL;
00381     } else {
00382         GetFPTag(rr, c, fptag);
00383         pfptag = &fptag;
00384     }
00385     VestaSource* vs = longid.lookup();
00386     // Sanity check for validity of the LongId
00387     if(vs == 0)
00388       {
00389         cerr << "FATAL ERROR in recovery: invalid LongId in \"insf\":" << endl
00390              << "\tlongid = " << longid << endl;
00391         abort();
00392       }
00393     VestaSource::errorCode err = 
00394       vs->insertFile(arc, (ShortId) ulsid, (bool) lmaster,
00395                      NULL, VestaSource::replaceDiff, NULL, ltimestamp, pfptag);
00396     assert(err == VestaSource::ok);
00397     delete vs;
00398 }
00399 
00400 static void
00401 InsuCallback(RecoveryReader* rr, char& c)
00402      throw(VestaLog::Error, VestaLog::Eof)
00403 {
00404     LongId longid;
00405     char arc[MAX_ARC_LEN+1];
00406     unsigned long ulsid;
00407     long lmaster;
00408     long ltimestamp;
00409     rr->getLongId(c, longid.value);
00410     rr->getQuotedString(c, arc, sizeof(arc));
00411     rr->getULong(c, ulsid);
00412     rr->getLong(c, lmaster);
00413     rr->getLong(c, ltimestamp);
00414     VestaSource* vs = longid.lookup();
00415     // Sanity check for validity of the LongId
00416     if(vs == 0)
00417       {
00418         cerr << "FATAL ERROR in recovery: invalid LongId in \"insu\":" << endl
00419              << "\tlongid = " << longid << endl;
00420         abort();
00421       }
00422     VestaSource::errorCode err =
00423       vs->insertMutableFile(arc, (ShortId) ulsid, (bool) lmaster,
00424                             NULL, VestaSource::replaceDiff, NULL, ltimestamp);
00425     assert(err == VestaSource::ok);
00426     delete vs;
00427 }
00428 
00429 static void
00430 InsiCallback(RecoveryReader* rr, char& c)
00431      throw(VestaLog::Error, VestaLog::Eof)
00432 {
00433     LongId pLongid, cLongid;
00434     char arc[MAX_ARC_LEN+1];
00435     long lmaster;
00436     long ltimestamp;
00437     FP::Tag fptag;
00438     FP::Tag* pfptag;
00439 
00440     rr->getLongId(c, pLongid.value);
00441     rr->getQuotedString(c, arc, sizeof(arc));
00442     rr->getLongId(c, cLongid.value);
00443     rr->getLong(c, lmaster);
00444     rr->getLong(c, ltimestamp);
00445     rr->skipWhite(c);
00446     if (c == ')') {
00447         pfptag = NULL;
00448     } else {
00449         GetFPTag(rr, c, fptag);
00450         pfptag = &fptag;
00451     }
00452     VestaSource* pvs = pLongid.lookup();
00453     // Sanity check for validity of the parent LongId
00454     if(pvs == 0)
00455       {
00456         cerr << "FATAL ERROR in recovery: invalid parent LongId in \"insi\":"
00457              << endl
00458              << "\tparent longid = " << pLongid << endl;
00459         abort();
00460       }
00461     VestaSource* cvs = cLongid.lookup();
00462     // Sanity check for validity of the LongId
00463     if(!(cLongid == NullLongId) && (cvs == 0))
00464       {
00465         cerr << "FATAL ERROR in recovery: invalid child LongId in \"insi\":"
00466              << endl
00467              << "\tchild longid = " << cLongid << endl;
00468         abort();
00469       }
00470     VestaSource::errorCode err =
00471       pvs->insertImmutableDirectory(arc, cvs, (bool) lmaster,
00472         NULL, VestaSource::replaceDiff, NULL, ltimestamp, pfptag);
00473     assert(err == VestaSource::ok);
00474     delete pvs;
00475     delete cvs;
00476 }
00477 
00478 static void
00479 InsmCallback(RecoveryReader* rr, char& c)
00480      throw(VestaLog::Error, VestaLog::Eof)
00481 {
00482     LongId pLongid, cLongid;
00483     char arc[MAX_ARC_LEN+1];
00484     long lmaster;
00485     long ltimestamp;
00486     rr->getLongId(c, pLongid.value);
00487     rr->getQuotedString(c, arc, sizeof(arc));
00488     rr->getLongId(c, cLongid.value);
00489     rr->getLong(c, lmaster);
00490     rr->getLong(c, ltimestamp);
00491     VestaSource* pvs = pLongid.lookup();
00492     // Sanity check for validity of the parent LongId
00493     if(pvs == 0)
00494       {
00495         cerr << "FATAL ERROR in recovery: invalid parent LongId in \"insm\":"
00496              << endl
00497              << "\tparent longid = " << pLongid << endl;
00498         abort();
00499       }
00500     VestaSource* cvs = cLongid.lookup();
00501     // Sanity check for validity of the LongId
00502     if(!(cLongid == NullLongId) && (cvs == 0))
00503       {
00504         cerr << "FATAL ERROR in recovery: invalid child LongId in \"insm\":"
00505              << endl
00506              << "\tchild longid = " << cLongid << endl;
00507         abort();
00508       }
00509     VestaSource::errorCode err =
00510       pvs->insertMutableDirectory(arc, cvs, (bool) lmaster, NULL,
00511                                   VestaSource::replaceDiff, NULL, ltimestamp);
00512     assert(err == VestaSource::ok);
00513     delete pvs;
00514     delete cvs;
00515 }
00516 
00517 static void
00518 InsaCallback(RecoveryReader* rr, char& c)
00519      throw(VestaLog::Error, VestaLog::Eof)
00520 {
00521     LongId longid;
00522     char arc[MAX_ARC_LEN+1];
00523     long lmaster;
00524     long ltimestamp;
00525     rr->getLongId(c, longid.value);
00526     rr->getQuotedString(c, arc, sizeof(arc));
00527     rr->getLong(c, lmaster);
00528     rr->getLong(c, ltimestamp);
00529     VestaSource* vs = longid.lookup();
00530     // Sanity check for validity of the LongId
00531     if(vs == 0)
00532       {
00533         cerr << "FATAL ERROR in recovery: invalid LongId in \"insa\":" << endl
00534              << "\tlongid = " << longid << endl;
00535         abort();
00536       }
00537     VestaSource::errorCode err =
00538       vs->insertAppendableDirectory(arc, (bool) lmaster, NULL,
00539                             VestaSource::replaceDiff, NULL, ltimestamp);
00540     assert(err == VestaSource::ok);
00541     delete vs;
00542 }
00543 
00544 static void
00545 InsgCallback(RecoveryReader* rr, char& c)
00546      throw(VestaLog::Error, VestaLog::Eof)
00547 {
00548     LongId longid;
00549     char arc[MAX_ARC_LEN+1];
00550     long lmaster;
00551     long ltimestamp;
00552     rr->getLongId(c, longid.value);
00553     rr->getQuotedString(c, arc, sizeof(arc));
00554     rr->getLong(c, lmaster);
00555     rr->getLong(c, ltimestamp);
00556     VestaSource* vs = longid.lookup();
00557     // Sanity check for validity of the LongId
00558     if(vs == 0)
00559       {
00560         cerr << "FATAL ERROR in recovery: invalid LongId in \"insg\":" << endl
00561              << "\tlongid = " << longid << endl;
00562         abort();
00563       }
00564     VestaSource::errorCode err =
00565       vs->insertGhost(arc, (bool) lmaster, NULL,
00566                       VestaSource::replaceDiff, NULL, ltimestamp);
00567     assert(err == VestaSource::ok);
00568     delete vs;
00569 }
00570 
00571 static void
00572 InssCallback(RecoveryReader* rr, char& c)
00573      throw(VestaLog::Error, VestaLog::Eof)
00574 {
00575     LongId longid;
00576     char arc[MAX_ARC_LEN+1];
00577     long lmaster;
00578     long ltimestamp;
00579     rr->getLongId(c, longid.value);
00580     rr->getQuotedString(c, arc, sizeof(arc));
00581     rr->getLong(c, lmaster);
00582     rr->getLong(c, ltimestamp);
00583     VestaSource* vs = longid.lookup();
00584     // Sanity check for validity of the LongId
00585     if(vs == 0)
00586       {
00587         cerr << "FATAL ERROR in recovery: invalid LongId in \"inss\":" << endl
00588              << "\tlongid = " << longid << endl;
00589         abort();
00590       }
00591     VestaSource::errorCode err =
00592       vs->insertStub(arc, (bool) lmaster, NULL,
00593                      VestaSource::replaceDiff, NULL, ltimestamp);
00594     assert(err == VestaSource::ok);
00595     delete vs;
00596 }
00597 
00598 static void
00599 RenCallback(RecoveryReader* rr, char& c)
00600      throw(VestaLog::Error, VestaLog::Eof)
00601 {
00602     LongId tLongid, fLongid;
00603     char tArc[MAX_ARC_LEN+1], fArc[MAX_ARC_LEN+1];
00604     long ltimestamp;
00605     rr->getLongId(c, tLongid.value);
00606     rr->getQuotedString(c, tArc, sizeof(tArc));
00607     rr->getLongId(c, fLongid.value);
00608     rr->getQuotedString(c, fArc, sizeof(fArc));
00609     rr->getLong(c, ltimestamp);
00610     VestaSource* tvs = tLongid.lookup();
00611     // Sanity check for validity of the LongId
00612     if(tvs == 0)
00613       {
00614         cerr << "FATAL ERROR in recovery: invalid 'to' LongId in \"ren\":"
00615              << endl
00616              << "\t'to' longid = " << tLongid << endl;
00617         abort();
00618       }
00619     VestaSource* fvs = fLongid.lookup();
00620     // Sanity check for validity of the LongId
00621     if(fvs == 0)
00622       {
00623         cerr << "FATAL ERROR in recovery: invalid 'from' LongId in \"ren\":"
00624              << endl
00625              << "\t'from' longid = " << fLongid << endl;
00626         abort();
00627       }
00628     VestaSource::errorCode err =
00629       tvs->renameTo(tArc, fvs, fArc, NULL,
00630                     VestaSource::replaceDiff, ltimestamp);
00631     assert(err == VestaSource::ok);
00632     delete tvs;
00633     delete fvs;
00634 }
00635 
00636 static void
00637 MakmCallback(RecoveryReader* rr, char& c)
00638      throw(VestaLog::Error, VestaLog::Eof)
00639 {
00640     LongId longid;
00641     unsigned long ulindex, ulsid;
00642     rr->getLongId(c, longid.value);
00643     rr->getULong(c, ulindex);
00644     rr->getULong(c, ulsid);
00645     VestaSource* vs = longid.lookup();
00646     // Sanity check for validity of the LongId
00647     if(vs == 0)
00648       {
00649         cerr << "FATAL ERROR in recovery: invalid LongId in \"makm\":" << endl
00650              << "\tlongid = " << longid << endl;
00651         abort();
00652       }
00653     VestaSource* newvs;
00654     VestaSource::errorCode err =
00655       ((VDirChangeable*) vs)->makeIndexMutable((unsigned int) ulindex, newvs,
00656                                                (ShortId) ulsid);
00657     assert(err == VestaSource::ok);
00658     delete vs;
00659     delete newvs;
00660 }
00661 
00662 static void
00663 MakiCallback(RecoveryReader* rr, char& c)
00664      throw(VestaLog::Error, VestaLog::Eof)
00665 {
00666     LongId longid;
00667     unsigned long ulindex;
00668     unsigned long ulsid;
00669     FP::Tag fptag;
00670     FP::Tag* pfptag;
00671 
00672     rr->getLongId(c, longid.value);
00673     rr->getULong(c, ulindex);
00674     rr->skipWhite(c);
00675     pfptag = NULL;
00676     ulsid = NullShortId;
00677     if (c != ')') {
00678         GetFPTag(rr, c, fptag);
00679         pfptag = &fptag;
00680         rr->skipWhite(c);
00681         if (c != ')') {
00682             rr->getULong(c, ulsid);
00683         }
00684     }
00685     VestaSource* vs = longid.lookup();
00686     // Sanity check for validity of the LongId
00687     if(vs == 0)
00688       {
00689         cerr << "FATAL ERROR in recovery: invalid LongId in \"maki\":" << endl
00690              << "\tlongid = " << longid << endl;
00691         abort();
00692       }
00693     ((VDirChangeable*) vs)->
00694       makeIndexImmutable((unsigned int) ulindex, pfptag, (ShortId) ulsid);
00695     delete vs;
00696 }
00697 
00698 static void
00699 Copy2mCallback(RecoveryReader* rr, char& c)
00700      throw(VestaLog::Error, VestaLog::Eof)
00701 {
00702     LongId longid;
00703     unsigned long ulindex, ulsid;
00704     rr->getLongId(c, longid.value);
00705     rr->getULong(c, ulindex);
00706     VestaSource* vs = longid.lookup();
00707     // Sanity check for validity of the LongId
00708     if(vs == 0)
00709       {
00710         cerr << "FATAL ERROR in recovery: invalid LongId in \"copy2m\":" << endl
00711              << "\tlongid = " << longid << endl;
00712         abort();
00713       }
00714     VestaSource* newvs;
00715     VestaSource::errorCode err =
00716       ((VDirChangeable*) vs)->copyIndexToMutable((unsigned int) ulindex, newvs);
00717     assert(err == VestaSource::ok);
00718     delete vs;
00719     delete newvs;
00720 }
00721 
00722 static void
00723 MastCallback(RecoveryReader* rr, char& c)
00724      throw(VestaLog::Error, VestaLog::Eof)
00725 {
00726     LongId longid;
00727     unsigned long ulindex, ulstate;
00728 
00729     rr->getLongId(c, longid.value);
00730     rr->getULong(c, ulindex);
00731     rr->getULong(c, ulstate);
00732     VestaSource* vs = longid.lookup();
00733     // Sanity check for validity of the LongId
00734     if(vs == 0)
00735       {
00736         cerr << "FATAL ERROR in recovery: invalid LongId in \"mast\":" << endl
00737              << "\tlongid = " << longid << endl;
00738         abort();
00739       }
00740     VestaSource::errorCode err =
00741       ((VDirChangeable*) vs)->
00742       setIndexMaster((unsigned int) ulindex, (bool)ulstate);
00743     assert(err == VestaSource::ok);
00744     delete vs;
00745 }
00746 
00747 static void
00748 AttrCallback(RecoveryReader* rr, char& c)
00749      throw(VestaLog::Error, VestaLog::Eof)
00750 {
00751     LongId longid;
00752     long lop, ltimestamp;
00753     char* name;
00754     char* value;
00755     rr->getLongId(c, longid.value);
00756     rr->getLong(c, lop);
00757     rr->getNewQuotedString(c, name);
00758     rr->getNewQuotedString(c, value);
00759     rr->getLong(c, ltimestamp);
00760     VestaSource* vs = longid.lookup();
00761     // Sanity check for validity of the LongId
00762     if(vs == 0)
00763       {
00764         cerr << "FATAL ERROR in recovery: invalid LongId in \"attr\":" << endl
00765              << "\tlongid = " << longid << endl;
00766         abort();
00767       }
00768 
00769     // Handle a log entry created by an old repository with a bug that
00770     // could add attributes to obejcts in an immutable base directory.
00771     // If this is an object under the mutable root that doesn't have
00772     // attributes, just print a message and continue.  (Unfortunately,
00773     // we can't do anything to fix this, as making the object mutable
00774     // could change indexes of other directory entries added later,
00775     // and screw up the rest of the log replay!)
00776     if(!vs->hasAttribs() && MutableRootLongId.isAncestorOf(vs->longid))
00777       {
00778         char longid_buf[65];
00779         OBufStream longid_ost(longid_buf, sizeof(longid_buf));
00780         longid_ost << longid;
00781         Repos::dprintf(DBG_ALWAYS, 
00782                        "WARNING: skipping replay of attribute write"
00783                        "on object below mutable root without attributes: "
00784                        "(attr %s %d \"%s\" \"%s\" %d)\n",
00785                        longid_ost.str(), lop, name, value, ltimestamp);
00786       }
00787     else
00788       {
00789         VestaSource::errorCode err =
00790           vs->writeAttrib((VestaSource::attribOp) lop, name, value, NULL,
00791                           ltimestamp);
00792         assert(err == VestaSource::ok);
00793       }
00794     delete [] name;
00795     delete [] value;
00796     delete vs;
00797 }
00798 
00799 static void
00800 TimeCallback(RecoveryReader* rr, char& c)
00801      throw(VestaLog::Error, VestaLog::Eof)
00802 {
00803     LongId longid;
00804     unsigned long ultime;
00805 
00806     rr->getLongId(c, longid.value);
00807     rr->getULong(c, ultime);
00808     VestaSource* vs = longid.lookup();
00809     // Sanity check for validity of the LongId
00810     if(vs == 0)
00811       {
00812         cerr << "FATAL ERROR in recovery: invalid LongId in \"time\":" << endl
00813              << "\tlongid = " << longid << endl;
00814         abort();
00815       }
00816     VestaSource::errorCode err =
00817       ((VDirChangeable*) vs)->setTimestamp((time_t)ultime);
00818     assert(err == VestaSource::ok);
00819     delete vs;
00820 }
00821 
00822 static void
00823 ColbCallback(RecoveryReader* rr, char& c)
00824      throw(VestaLog::Error, VestaLog::Eof)
00825 {
00826     LongId cLongid;
00827 
00828     rr->getLongId(c, cLongid.value);
00829     VestaSource *cvs = cLongid.lookup();
00830     // Sanity check for validity of the LongId
00831     if(cvs == 0)
00832       {
00833         cerr << "FATAL ERROR in recovery: invalid LongId in \"colb\":"
00834              << endl
00835              << "\tlongid = " << cLongid << endl;
00836         abort();
00837       }
00838     VestaSource::errorCode err = cvs->collapseBase();
00839     assert(err == VestaSource::ok);
00840     delete cvs;
00841 }
00842 
00843 static void 
00844 CorrectRootModes(VestaSource* dir)
00845 {
00846     const char* val;
00847     if ((val = dir->getAttribConst("#mode")) == NULL) {
00848         dir->ac.mode = 0755;
00849     } else {
00850         dir->ac.mode = AccessControl::parseModeBits(val);
00851     }
00852 }
00853 
00854 // Real methods
00855 
00856 VestaSource*
00857 VestaSource::repositoryRoot(LongId::lockKindTag lockKind,
00858                             ReadersWritersLock** lock)
00859   throw (SRPC::failure /*can't really happen*/)
00860 {
00861     switch (lockKind) {
00862       case LongId::noLock:
00863         if (lock != NULL) *lock = NULL;
00864         break;
00865       case LongId::readLock:
00866       case LongId::readLockV:
00867         RECORD_TIME_POINT;
00868         StableLock.acquireRead();
00869         RECORD_TIME_POINT;
00870         *lock = &StableLock;
00871         break;
00872       case LongId::writeLock:
00873       case LongId::writeLockV:
00874         RECORD_TIME_POINT;
00875         StableLock.acquireWrite();
00876         RECORD_TIME_POINT;
00877         *lock = &StableLock;
00878         break;
00879       case LongId::checkLock:
00880         if (*lock != &StableLock) return NULL;
00881         break;
00882     }   
00883     ::repositoryRoot->resync();
00884     CorrectRootModes(::repositoryRoot);
00885     return ::repositoryRoot;
00886 }
00887 
00888 VestaSource*
00889 VestaSource::mutableRoot(LongId::lockKindTag lockKind,
00890                          ReadersWritersLock** lock)
00891   throw (SRPC::failure /*can't really happen*/)
00892 {
00893     switch (lockKind) {
00894       case LongId::noLock:
00895         if (lock != NULL) *lock = NULL;
00896         break;
00897       case LongId::readLock:
00898       case LongId::readLockV:
00899         RECORD_TIME_POINT;
00900         StableLock.acquireRead();
00901         RECORD_TIME_POINT;
00902         *lock = &StableLock;
00903         break;
00904       case LongId::writeLock:
00905       case LongId::writeLockV:
00906         RECORD_TIME_POINT;
00907         StableLock.acquireWrite();
00908         RECORD_TIME_POINT;
00909         *lock = &StableLock;
00910         break;
00911       case LongId::checkLock:
00912         if (*lock != &StableLock) return NULL;
00913         break;
00914     }   
00915     ::mutableRoot->resync();
00916     CorrectRootModes(::mutableRoot);
00917     return ::mutableRoot;
00918 }
00919 
00920 VestaSource*
00921 VestaSource::volatileRoot(LongId::lockKindTag lockKind,
00922                           ReadersWritersLock** lock)
00923   throw (SRPC::failure /*can't really happen*/)
00924 {
00925     switch (lockKind) {
00926       case LongId::noLock:
00927       case LongId::readLockV:
00928       case LongId::writeLockV:
00929         if (lock != NULL) *lock = NULL;
00930         break;
00931       case LongId::readLock:
00932         RECORD_TIME_POINT;
00933         VolatileRootLock.acquireRead();
00934         RECORD_TIME_POINT;
00935         *lock = &VolatileRootLock;
00936         break;
00937       case LongId::writeLock:
00938         RECORD_TIME_POINT;
00939         VolatileRootLock.acquireWrite();
00940         RECORD_TIME_POINT;
00941         *lock = &VolatileRootLock;
00942         break;
00943       case LongId::checkLock:
00944         if (*lock != &VolatileRootLock) return NULL;
00945         break;
00946     }   
00947     return ::volatileRoot;
00948 }
00949 
00950 void 
00951 VestaSource::init() throw ()
00952 {
00953     // Don't log during recovery
00954     doLogging = false;
00955 
00956     // Create RepositoryRoot and MutableRoot empty, to be populated
00957     // by recovery.
00958     ::repositoryRoot = NEW_CONSTR(VDirChangeable,
00959                                   (VestaSource::appendableDirectory));
00960     ::repositoryRoot->longid = RootLongId;
00961     ::repositoryRoot->pseudoInode = 1;
00962     ::repositoryRoot->attribs = (Bit8*) &repositoryRootAttribsRep;
00963     ::repositoryRoot->ac.owner.attribs = (Bit8*) &repositoryRootAttribsRep;
00964     ::repositoryRoot->ac.group.attribs = (Bit8*) &repositoryRootAttribsRep;
00965     ::repositoryRoot->fptag = pathnameFPTag;
00966     
00967     ::mutableRoot = NEW_CONSTR(VDirChangeable,
00968                                (VestaSource::mutableDirectory));
00969     ::mutableRoot->longid = MutableRootLongId;
00970     ::mutableRoot->pseudoInode = 2;
00971     ::mutableRoot->attribs = (Bit8*) &mutableRootAttribsRep;
00972     ::mutableRoot->ac.owner.attribs = (Bit8*) &mutableRootAttribsRep;
00973     ::mutableRoot->ac.group.attribs = (Bit8*) &mutableRootAttribsRep;
00974     ::mutableRoot->fptag = FP::Tag("");
00975     ::mutableRoot->master = true;
00976     
00977     VDirVolatileRoot::init();
00978     ::volatileRoot = NEW(VDirVolatileRoot);
00979     ::volatileRoot->type = VestaSource::volatileDirectory; //not exactly...
00980     ::volatileRoot->longid = VolatileRootLongId;
00981     ::volatileRoot->pseudoInode = 3;
00982     ::volatileRoot->fptag = FP::Tag("");
00983     ::volatileRoot->attribs = (Bit8*) &volatileRootAttribsRep;
00984     ::volatileRoot->ac.owner.attribs = (Bit8*) &volatileRootAttribsRep;
00985     ::volatileRoot->ac.group.attribs = (Bit8*) &volatileRootAttribsRep;
00986     ::volatileRoot->ac.mode = 0755;
00987     ::volatileRoot->master = true;
00988 
00989     // Register recovery routines
00990     RegisterRecoveryCallback("del", DelCallback);
00991     RegisterRecoveryCallback("insf", InsfCallback);
00992     RegisterRecoveryCallback("insu", InsuCallback);
00993     RegisterRecoveryCallback("insi", InsiCallback);
00994     RegisterRecoveryCallback("insm", InsmCallback);
00995     RegisterRecoveryCallback("insa", InsaCallback);
00996     RegisterRecoveryCallback("insg", InsgCallback);
00997     RegisterRecoveryCallback("inss", InssCallback);
00998     RegisterRecoveryCallback("ren", RenCallback);
00999     RegisterRecoveryCallback("makm", MakmCallback);
01000     RegisterRecoveryCallback("maki", MakiCallback);
01001     RegisterRecoveryCallback("copy2m", Copy2mCallback);
01002     RegisterRecoveryCallback("mast", MastCallback);
01003     RegisterRecoveryCallback("attr", AttrCallback);
01004     RegisterRecoveryCallback("time", TimeCallback);
01005     RegisterRecoveryCallback("vers", VersCallback);
01006     RegisterRecoveryCallback("colb", ColbCallback);
01007 
01008     // Initialize weeding (garbage collection) machinery
01009     InitVRWeed();
01010 }
01011 
01012 void 
01013 VestaSource::recoveryDone() throw ()
01014 {
01015     ::repositoryRoot->resync();
01016     ::mutableRoot->resync();
01017 
01018     // Set volatile root owner and group -- not logged, so we have to
01019     // reset them after each recovery.  They do go into the volatile
01020     // portion of a checkpoint, so we don't have to do this after
01021     // checkpointing.
01022     ::volatileRoot->writeAttrib(VestaAttribs::opSet, "#owner",
01023                                 AccessControl::runtoolUser);
01024     ::volatileRoot->writeAttrib(VestaAttribs::opSet, "#group",
01025                                 AccessControl::vadminGroup);
01026 
01027     // Rebuild the mutable root shortid reference count if it wasn't
01028     // rebuilt earlier
01029     if(!MutableSidrefRecoveryCheck())
01030       {
01031         MutableSidrefInit();
01032       }
01033     doLogging = true;
01034     if (VRLogVersion < LogMaxVersion) {
01035       // use latest version of semantics for new entries
01036       VRLogVersion = LogMaxVersion;
01037       char logrec[512];
01038       OBufStream ost(logrec, sizeof(logrec));
01039       // ('vers' version)
01040       ost << "(vers " << VRLogVersion << ")\n";
01041       VRLog.start();
01042       VRLog.put(ost.str());
01043       VRLog.commit();
01044     }
01045 
01046 }
01047 
01048 VestaSource::errorCode
01049 VestaSource::makeMutable(VestaSource*& result, ShortId sid,
01050                          Basics::uint64 copyMax,
01051                          AccessControl::Identity who)
01052   throw (SRPC::failure /*can't really happen*/)
01053 {
01054     if (!ac.check(who, AccessControl::write))
01055       return VestaSource::noPermission;
01056     if (!(MutableRootLongId.isAncestorOf(longid) ||
01057           VolatileRootLongId.isAncestorOf(longid))) {
01058         return VestaSource::inappropriateOp;
01059     }
01060     unsigned int index;
01061     VestaSource* parent = longid.getParent(&index).lookup();
01062     if (parent == NULL)
01063       return VestaSource::inappropriateOp;
01064     VestaSource::errorCode err;
01065     if (parent->type == VestaSource::immutableDirectory ||
01066         parent->type == VestaSource::evaluatorDirectory ||
01067         parent->type == VestaSource::evaluatorROEDirectory) {
01068         VestaSource* muparent;
01069         err = parent->makeMutable(muparent, NullShortId,
01070                                   (Basics::uint64) -1, who);
01071         if (err != VestaSource::ok) return err;
01072         delete parent;
01073         parent = muparent;
01074     }
01075     err = ((VDirChangeable*) parent)->
01076       makeIndexMutable(index, result, sid, copyMax, who);
01077     delete parent;
01078     return err;
01079 }
01080 
01081 VestaSource::errorCode
01082 VestaSource::copyToMutable(VestaSource*& result,
01083                            AccessControl::Identity who)
01084   throw (SRPC::failure /*can't really happen*/)
01085 {
01086     if (!ac.check(who, AccessControl::write))
01087       return VestaSource::noPermission;
01088     if (!MutableRootLongId.isAncestorOf(longid)) {
01089         return VestaSource::inappropriateOp;
01090     }
01091     unsigned int index;
01092     VestaSource* parent = longid.getParent(&index).lookup();
01093     if (parent == NULL)
01094       return VestaSource::inappropriateOp;
01095     VestaSource::errorCode err;
01096     if (parent->type != VestaSource::mutableDirectory) {
01097         VestaSource* muparent;
01098         err = parent->makeMutable(muparent, NullShortId,
01099                                   (Basics::uint64) -1, who);
01100         if (err != VestaSource::ok) return err;
01101         delete parent;
01102         parent = muparent;
01103     }
01104     err = ((VDirChangeable*) parent)->
01105       copyIndexToMutable(index, result, who);
01106     delete parent;
01107     return err;
01108 }
01109 
01110 struct MakeFilesImmutableClosure {
01111     VestaSource *vs;
01112     VestaSource::errorCode err;
01113     unsigned int fpThreshold;
01114 };
01115 
01116 const FP::Tag uidFPTag("Textd"); // Same prefix used in evaluator
01117 
01118 static bool
01119 MakeFilesImmutableCallback(void* closure, VestaSource::typeTag type, Arc arc,
01120                            unsigned int index, Bit32 pseudoInode,
01121                            ShortId filesid, bool master)
01122 {
01123     MakeFilesImmutableClosure *cl = (MakeFilesImmutableClosure *) closure;
01124     MakeFilesImmutableClosure newcl;
01125     int fd, res;
01126     FP::Tag fptag;
01127     FP::Tag* newfptag = NULL;
01128     FdCache::OFlag ofl;
01129     struct stat st;
01130     ShortId dupsid = NullShortId;
01131 
01132     switch (type) {
01133       case VestaSource::mutableFile:
01134         // Note that we need a writable file descriptor so that we can
01135         // call fsync before making this file immutable (in the case
01136         // that it's not a duplicate).
01137         fd = FdCache::open(filesid, FdCache::rw, &ofl);
01138         if(fd < 0)
01139           // Can this actually happen?
01140           fd = FdCache::open(filesid, FdCache::any, &ofl);
01141         assert(fd >= 0);
01142         res = fstat(fd, &st);
01143         assert(res >= 0);
01144         if(cl->vs->type != VestaSource::mutableDirectory &&
01145            cl->vs->type != VestaSource::volatileDirectory &&
01146            cl->vs->type != VestaSource::volatileROEDirectory)
01147           {
01148             // This shouldn't happen, but just in case it does, log a
01149             // message about it.
01150             Repos::dprintf(DBG_ALWAYS, 
01151                            "warning: makeFilesImmutable found mutable file "
01152                            "\"%s\" in unexpected directory type (%s)\n",
01153                            arc, VestaSource::typeTagString(cl->vs->type));
01154           }
01155         if (st.st_size < cl->fpThreshold) {
01156             // Fingerprint content and check for duplication.
01157             lseek(fd, 0, SEEK_SET);
01158             FS::IFdStream fs(fd);
01159             if (st.st_mode & 0111) {
01160               fptag = executableFPTag;
01161             } else {
01162               fptag = contentsFPTag;
01163             }
01164             // exceptions indicate fatal server trouble, so leave uncaught
01165             FP::FileContents(fs, /*inout*/ fptag);
01166             newfptag = &fptag;
01167             dupsid = GetFPShortId(fptag);
01168         }
01169 
01170         if (dupsid == NullShortId) {
01171           // Not a duplicate.  check to see if there's more than one
01172           // reference.
01173           if(((VDirChangeable*)cl->vs)->getRefCount(filesid) > 1)
01174             {
01175               // more than one link to this mutable file.  We can't
01176               // make this one immutable, so we'll have to copy it to
01177               // a new shortid.
01178               int err;
01179               dupsid = CopyShortId(filesid, err,
01180                                    ((Basics::uint64)-1), ((Basics::uint64 *) 0),
01181                                    false);
01182               assert(dupsid != NullShortId);
01183             }
01184           else
01185             {
01186               // No other references.  Make immutable.
01187               if (st.st_mode & 0222)
01188               {
01189                 // We must have a writable file descriptor.
01190                 assert(ofl == FdCache::rw);
01191                 // Make it read-only on disk.
01192                 res = fchmod(fd, st.st_mode & ~0222);
01193                 assert(res >= 0);
01194                 // Now that it's read-only on disk, get rid of any
01195                 // writable file descriptors in the FdCache.
01196                 FdCache::flush(filesid, FdCache::rw);
01197                 // Flush any pending writes to disk.
01198                 res = fsync(fd);
01199                 assert(res != -1);
01200 
01201               }
01202             }
01203 
01204             // Dispose of the file descriptor.
01205             if(ofl == FdCache::rw)
01206               {
01207                 // Rather than returning this writable file descriptor
01208                 // to the FdCache, close it.
01209                 do
01210                   res = close(fd);
01211                 while ((res == -1) && (errno == EINTR));
01212                 assert(res != -1);
01213               }
01214             else
01215               {
01216                 // Maybe this shortid was already marked as read-only?
01217                 // I'm not sure this can happen, but if it does it
01218                 // should be OK to return this file descriptor to the
01219                 // FdCache.
01220                 FdCache::close(filesid, fd, ofl);
01221               }
01222             if (newfptag == NULL)
01223               {
01224                 // Not fingerprinted by content.  We must invent a
01225                 // unique fingerprint at this point.  We can't base it
01226                 // on the name, because the parent directory is not
01227                 // yet immutable, so we choose a unique ID instead.
01228                 // For mutable directories the unique ID will be
01229                 // logged, so recovery will still work, and there is
01230                 // no other particular advantage to basing
01231                 // fingerprints on names, so this is OK.
01232                 fptag = uidFPTag;
01233                 fptag.Extend(UniqueId());
01234                 newfptag = &fptag;
01235               }
01236 
01237             // Note: dupsid may have been set above.
01238             ((VDirChangeable*)cl->vs)->makeIndexImmutable(index, newfptag, dupsid);
01239         } else {
01240             // We already had a file with this fingerprint; use it instead.
01241             FdCache::close(filesid, fd, ofl);
01242             ((VDirChangeable*)cl->vs)->
01243               makeIndexImmutable(index, newfptag, dupsid);
01244             // Unlink the newer file.  We must not do this unlink
01245             // unless the log entry is committed, however.  If
01246             // the makeIndexMutable above was done as an independent
01247             // transaction, it is committed now, but if it was done as
01248             // a nested transaction, it is not committed yet.
01249             // The latter case doesn't really occur in current repository
01250             // usage, so we haven't bothered creating machinery to unlink 
01251             // the file when the transaction commits; instead, if this
01252             // ever happens, the file will stay around until the next weed.
01253             // This temporarily wastes some disk space but is harmless.
01254             if ((VRLog.nesting() == 0) &&
01255                 // Note, we should only unlink the shortid if there
01256                 // are no additional references to it.
01257                 (((VDirChangeable*)cl->vs)->getRefCount(filesid) == 0))
01258               {
01259               
01260               FdCache::flush(filesid, FdCache::any);
01261               char* name = SourceOrDerived::shortIdToName(filesid);
01262               Repos::dprintf(DBG_SIDDISP, "unlinking: 0x%08x\n", filesid);
01263               int ret = unlink(name);
01264               if (ret < 0) {
01265                 int saved_errno = errno;
01266                 Text err_txt = Basics::errno_Text(saved_errno);
01267                 Repos::dprintf(DBG_ALWAYS, 
01268                                "unlink %s: %s (errno = %d)\n", name,
01269                                err_txt.cchars(), saved_errno);
01270               }
01271               delete[] name;
01272             }
01273         }
01274         break;
01275 
01276       case VestaSource::mutableDirectory:
01277       case VestaSource::volatileDirectory:
01278       case VestaSource::volatileROEDirectory:
01279         cl->err = cl->vs->lookupIndex(index, newcl.vs); 
01280         if (cl->err != VestaSource::ok) return false;
01281         newcl.err = VestaSource::ok;
01282         newcl.fpThreshold = cl->fpThreshold;
01283         cl->err =
01284           newcl.vs->list(0, MakeFilesImmutableCallback, &newcl, NULL, true);
01285         delete newcl.vs;
01286         if (cl->err != VestaSource::ok) return false;
01287         if (newcl.err != VestaSource::ok) {
01288             cl->err = newcl.err;
01289             return false;
01290         }
01291         break;
01292 
01293       default:
01294         break;
01295     }
01296     return true;
01297 }
01298 
01299 
01300 VestaSource::errorCode
01301 VestaSource::makeFilesImmutable(unsigned int fpThreshold,
01302                                 AccessControl::Identity who)
01303   throw (SRPC::failure /*can't really happen*/)
01304 {
01305     if (!ac.check(who, AccessControl::write))
01306       return VestaSource::noPermission;
01307 
01308     MakeFilesImmutableClosure cl;
01309     switch (type) {
01310       case VestaSource::mutableDirectory:
01311       case VestaSource::volatileDirectory:
01312       case VestaSource::volatileROEDirectory:
01313         break;
01314       case VestaSource::immutableFile:
01315         return VestaSource::ok;
01316       case VestaSource::mutableFile:
01317         {
01318             unsigned int index;
01319             LongId plongid = this->longid.getParent(&index);
01320             cl.vs = plongid.lookup();
01321             if (cl.vs == NULL) return VestaSource::inappropriateOp;
01322             cl.err = VestaSource::ok;
01323             cl.fpThreshold = fpThreshold;
01324             MakeFilesImmutableCallback(&cl, type, NULL, index,
01325                                        pseudoInode, shortId(), master);
01326             delete cl.vs;
01327             return cl.err;
01328         }
01329       default:
01330         return VestaSource::inappropriateOp;
01331     }
01332     cl.vs = this;
01333     cl.err = VestaSource::ok;
01334     cl.fpThreshold = fpThreshold;
01335     VestaSource::errorCode err =
01336       list(0, MakeFilesImmutableCallback, &cl, NULL, true);
01337     if (err != VestaSource::ok) return err;
01338     return cl.err;
01339 }    
01340 
01341 VestaSource::errorCode
01342 VestaSource::lookupPathname(const char* pathname, VestaSource*& result,
01343                             AccessControl::Identity who, char pathnameSep)
01344   throw (SRPC::failure /*can't really happen*/)
01345 {
01346     VestaSource* cur = this;
01347     while (*pathname) {
01348         char arcbuf[MAX_ARC_LEN+1];
01349         char* slash = strchr(pathname, pathnameSep);
01350         if (slash != NULL) {
01351             strncpy(arcbuf, pathname, slash - pathname);
01352             arcbuf[slash - pathname] = '\000';
01353             pathname = slash + 1;
01354         } else {
01355             strcpy(arcbuf, pathname);
01356             pathname = "";
01357         }
01358         if (*arcbuf) {
01359             VestaSource* child;
01360             VestaSource::errorCode err = cur->lookup(arcbuf, child, who);
01361             if (cur != this) delete cur;
01362             cur = child;
01363             if (err != VestaSource::ok) return err;
01364         }
01365     }
01366     if (cur == this) {
01367         // Need a fresh copy of this so caller can free it -- ugh
01368         result = cur->longid.lookup();
01369     } else {
01370         result = cur;
01371     }
01372     return VestaSource::ok;
01373 }
01374 
01375 VestaSource::errorCode
01376 VestaSource::writeAttrib(VestaAttribs::attribOp op, const char* name,
01377                          const char* value,
01378                          AccessControl::Identity who, time_t timestamp)
01379   throw (SRPC::failure /*can't really happen*/)
01380 {
01381     if (!hasAttribs()) return VestaSource::invalidArgs;
01382 
01383     VestaSource::errorCode err = VestaSource::ok;
01384     if (name[0] == '#') {
01385         AccessControl::Class acc;
01386         if (strcmp(name, "#replicate-from") == 0 ||
01387             strcmp(name, "#mastership-from") == 0 ||
01388             strcmp(name, "#mastership-to") == 0) {
01389           acc = AccessControl::administrative;
01390         } else if ((op == opSet || op == opAdd) &&
01391                    strcmp(name, "#setuid") == 0) {
01392           acc = AccessControl::setuid;
01393         } else if ((op == opSet || op == opAdd) &&
01394                    strcmp(name, "#setgid") == 0) {
01395           acc = AccessControl::setgid;
01396         } else {
01397           acc = AccessControl::ownership;
01398         }
01399         if (!ac.check(who, acc, value)) {
01400           err = VestaSource::noPermission;
01401         }
01402     } else {
01403         if (!ac.check(who, AccessControl::write)) {
01404             err = VestaSource::noPermission;
01405         }
01406     }
01407     if (err != VestaSource::ok) {
01408       // Return a permission error only if this write would
01409       // actually change the history.
01410       if (wouldWriteAttrib(op, name, value, timestamp)) {
01411         return err;
01412       } else {
01413         return VestaSource::ok;
01414       }
01415     }
01416 
01417     err = VestaAttribs::writeAttrib(op, name, value, timestamp);
01418 
01419     if (err == VestaSource::ok && VestaSource::doLogging &&
01420         !VolatileRootLongId.isAncestorOf(longid)) {
01421         // Operation succeeded; log it.
01422         char buf[512];
01423         // ('attr' longid op name value timestamp)
01424         VRLog.start();
01425         {
01426           OBufStream ost(buf, sizeof(buf));
01427           ost << "(attr " << longid << " " << ((int) op) << " ";
01428           VRLog.put(ost.str());
01429         }
01430         LogPutQuotedString(VRLog, name);
01431         VRLog.put(" ");
01432         LogPutQuotedString(VRLog, value);
01433         {
01434           OBufStream ost(buf, sizeof(buf));
01435           ost << " " << timestamp << ")\n";
01436           VRLog.put(ost.str());
01437         }
01438         VRLog.commit();
01439     }
01440     // Special case: write had no effect so we don't log it; convert
01441     // to no error.
01442     if(err == VestaSource::nameInUse)
01443       err = VestaSource::ok;
01444 
01445     return err;
01446 }

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