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

Files.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 /* File: Files.C                                               */
00020 
00021 #include "Files.H"
00022 #include "EvalBasics.H"
00023 #include "ModelState.H"
00024 #include "Err.H"
00025 #include <ReposUI.H>
00026 #include <Replicator.H>
00027 
00028 using std::fstream;
00029 using std::cout;
00030 using std::cerr;
00031 using std::endl;
00032 
00033 extern "C" {void *opendir(const char *);}
00034 extern "C" {int closedir(void *);}
00035 
00036 const char UnixDelimiter = '/';
00037 
00038 bool IsDelimiter(const char c) {
00039   return (c == '/' || c == '\\');
00040 }
00041 
00042 Text Canonical(const Text& path) {
00043   // Platform-dependent.  Take a Vesta path (with either kind of
00044   // delimiter) and convert to the appropriate delimiter for the
00045   // underlying file system.
00046   int len = path.Length();
00047   const char *p = path.cchars();
00048   char *s = NEW_PTRFREE_ARRAY(char, len+1);
00049   int i;
00050 
00051   for (i = 0; i < len; i++) {
00052     if (IsDelimiter(p[i])) s[i] = UnixDelimiter;
00053     else s[i] = p[i];
00054   }
00055   s[i] = 0;
00056   return Text(s);
00057 }
00058   
00059 Text setSuffix(const Text& s, const Text& suff) {
00060   bool sf = false;
00061 
00062   if (s == "/dev/null") return s;   // hack: Unix only
00063   for (int i = 0; i < s.Length(); i++) {
00064     if (s[i] == '.') sf = true;
00065     else if (IsDelimiter(s[i])) sf = false;
00066   }
00067   return (sf) ? s : s + suff;
00068 }
00069 
00070 bool IsAbsolutePath(const Text& path) {
00071   return !path.Empty() && IsDelimiter(path[0]);
00072 }
00073 
00074 void SplitPath(const Text& path, Text& prefix, Text& name) {
00075   int n = path.Length() - 1; 
00076   while (n >= 0 && !IsDelimiter(path[n])) n--;
00077   prefix = path.Sub(0, n+1);
00078   name = path.Sub(n+1);
00079   return;
00080 }
00081 
00082 VestaSource::errorCode LookupPath(const Text& path, VestaSource *mRoot,
00083                                   VestaSource*& newRoot) {
00084   Text relPath;
00085   VestaSource *tempRoot;
00086   VestaSource::errorCode code = VestaSource::ok;
00087 
00088   if (IsAbsolutePath(path)) {
00089     int i = 1;
00090     while (!IsDelimiter(path[i]) && i < path.Length()) i++;
00091     relPath = path.Sub(i+1);  // strip off first arc
00092     tempRoot = rRoot;
00093   }
00094   else {
00095     relPath = path;
00096     tempRoot = mRoot;
00097   }
00098   if (relPath.Empty())
00099     newRoot = tempRoot;
00100   else {
00101     code = tempRoot->lookupPathname(relPath.cchars(), newRoot);
00102     if((code == VestaSource::notFound) && autoRepl) {
00103       if(ReplicateMissing(tempRoot, relPath, newRoot)) 
00104         code = VestaSource::ok;
00105     }  
00106   }
00107   return code;
00108 }
00109 
00110 // Split up a whitespace-delimited set of main model names to try in
00111 // sequence.
00112 TextSeq SplitDefaultMains(const Text& defaultmain) throw()
00113 {
00114   TextSeq l_result;
00115   // Start at the beginning and go until we run out of text.
00116   unsigned int l_i = 0;
00117   while(l_i < defaultmain.Length())
00118     {
00119       // Remember where we started.
00120       unsigned int l_start = l_i;
00121       // Skip forward until we rech whictespace or the end of the
00122       // string.
00123       while(!isspace(defaultmain[l_i]) &&
00124             (l_i < defaultmain.Length()))
00125         {
00126           l_i++;
00127         }
00128       // If we found a non-whitespace chunk, add that to the list.
00129       if(l_i > l_start)
00130         {
00131           l_result.addhi(defaultmain.Sub(l_start, (l_i - l_start)));
00132         }
00133       // Skip over any whitespace after the filename.
00134       while(isspace(defaultmain[l_i]) &&
00135             (l_i < defaultmain.Length()))
00136         {
00137           l_i++;
00138         }
00139     }
00140   // Return the collected filenames.
00141   return l_result;
00142 }
00143 
00144 // Try a sequence of default model names in order.  Return the first
00145 // one that exists.
00146 Text FindExistingModel(const TextSeq &p_defaults, const Text& p_dir = "")
00147 {
00148   Text l_result;
00149   // Try the default model names in sequence.
00150   for(unsigned int l_i = 0; l_i < p_defaults.size(); l_i++)
00151     {
00152       l_result = p_dir + p_defaults.get(l_i);
00153       // If this one exists, accept it.
00154       if(FS::Exists(l_result))
00155         {
00156           break;
00157         }
00158     }
00159   return l_result;
00160 }
00161 
00162 Text MainModel(const Text& filename, const Text& defaultmain) {
00163   Text modelname(Canonical(filename));
00164   TextSeq l_defaults = SplitDefaultMains(defaultmain);
00165   if(modelname.Length() == 0)
00166     {
00167       // No model was specified.  Chose a default in the current
00168       // working directory.
00169       modelname = FindExistingModel(l_defaults);
00170     }
00171   else
00172     {
00173       char c = modelname[modelname.Length()-1];
00174       if (IsDelimiter(c))
00175         {
00176           // Assume it's a directory and append the default model
00177           // name.
00178           modelname = FindExistingModel(l_defaults, modelname);
00179         }
00180       else
00181         {
00182           // See if this is a directory.
00183           void *d = opendir(modelname.cchars());
00184           if (d == NULL)
00185             {
00186               // Not a directory, assume it's a file.  Make sure it
00187               // has the right suffix.
00188               modelname = setSuffix(modelname, ".ves");
00189             }
00190           else
00191             {
00192               (void)closedir(d);
00193               // A directory was specified, append the default model
00194               // name.
00195               modelname = FindExistingModel(l_defaults,
00196                                             modelname + PathnameSep);
00197             }
00198         }
00199     }
00200   return modelname;
00201 }
00202 
00203 bool IsDirectory(VestaSource *mRoot, Text& path, VestaSource*& vSource,
00204                  VestaSource::errorCode& vSourceErr) {
00205   vSourceErr = LookupPath(path, mRoot, vSource);
00206   return (vSourceErr == VestaSource::ok &&
00207           vSource->type != VestaSource::immutableFile &&
00208           vSource->type != VestaSource::mutableFile);
00209 }
00210 
00211 bool OpenSource(VestaSource *mRoot, const Text& fname, SrcLoc *loc,
00212                 fstream*& iFile, VestaSource*& newRoot, ShortId& shortId,
00213                 VestaSource*& vSource) {
00214   Text prefix, tail;
00215   VestaSource::errorCode err;
00216 
00217   shortId = NullShortId;
00218   SplitPath(fname, prefix, tail);
00219   err = LookupPath(prefix, mRoot, newRoot);
00220   if(err != VestaSource::ok) {
00221     outputMu.lock();      
00222     Error(VestaSourceErrorMsg(err) + " opening directory `" + prefix + "'.\n",
00223           loc);
00224     outputMu.unlock();      
00225     return false;
00226   }
00227   err = newRoot->lookup(tail.cchars(), vSource);
00228   if (err != VestaSource::ok) {
00229     outputMu.lock();      
00230     Error(VestaSourceErrorMsg(err) + " opening `" + fname + "'.\n", loc);
00231     outputMu.unlock();      
00232     return false;
00233   }
00234   iFile = NULL;
00235   shortId = vSource->shortId();
00236   return true;
00237 }
00238 
00239 bool ReplicateMissing(VestaSource* root, const Text& name, 
00240                       /*OUT*/VestaSource*& vSource)
00241 {
00242   assert(autoRepl);
00243   if(!RootLongId.isAncestorOf(root->longid))
00244     return false;
00245   try {
00246     Text path = ReposUI::vsToFilename(root) + "/" + name;
00247     const int vlen = 7; // ==strlen("/vesta/")
00248 
00249     outputMu.lock();
00250     cout << "Trying to find a copy of " << path << endl; 
00251     outputMu.unlock(); 
00252 
00253     Text defhints;
00254     (void) VestaConfig::get("UserInterface", "DefaultHints", defhints);
00255     VestaSource* real_source = ReposUI::filenameToRealVS(path, defhints);
00256     
00257     outputMu.lock();
00258     cout << "Replicating " << path << " from "
00259          << real_source->host() << ":" << real_source->port() << endl;
00260     outputMu.unlock(); 
00261 
00262     Replicator repl(real_source->host(), real_source->port(), 
00263                     rRoot->host(), rRoot->port());
00264     Replicator::Directive d('+', path.Sub(vlen));
00265     Replicator::DirectiveSeq direcs;
00266     direcs.addhi(d);
00267     Replicator::Flags flags = (Replicator::Flags) 
00268       (Replicator::attrNew | Replicator::attrOld | Replicator::attrAccess |
00269        Replicator::revive | Replicator::inclStubs | Replicator::latest);
00270     repl.replicate(&direcs, flags);
00271     vSource = ReposUI::filenameToVS(path, rRoot->host(), rRoot->port());
00272     delete real_source;
00273     return true;
00274   }
00275   catch(ReposUI::failure f){
00276     outputMu.lock();
00277     cerr << "ReposUI failure during replication of " << name << ": "
00278          << f.msg << endl;
00279     outputMu.unlock();
00280     return false;
00281   }
00282   catch(VestaConfig::failure f){
00283     outputMu.lock();
00284     cerr << "VestaConfig failure during replication of " << name << ": "
00285          << f.msg << endl;
00286     outputMu.unlock();
00287     return false;
00288   }
00289   catch(SRPC::failure f){
00290     outputMu.lock();
00291     cerr << "SRPC failure during replication of " << name << ": "
00292          << f.msg << " (" << f.r << ")" << endl;
00293     outputMu.unlock();
00294     return false;
00295   }
00296   catch(Replicator::Failure f){
00297     if(f.code == (VestaSource::errorCode) -1) {
00298       outputMu.lock();
00299       cerr << "Failure during replication of " << name << ": " << f.msg << endl;
00300       outputMu.unlock();
00301     } 
00302     else {
00303       outputMu.lock();
00304       cerr << "Failure during replication of " << name << ": " 
00305            << ReposUI::errorCodeText(f.code) << ", " << f.msg << endl;
00306       outputMu.unlock();
00307     }
00308     return false;
00309   }
00310 }

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