TDataSetManagerFile.cxx

Go to the documentation of this file.
00001 // @(#)root/base:$Id: TDataSetManagerFile.cxx 37940 2011-02-02 14:07:05Z ganis $
00002 // Author: Jan Fiete Grosse-Oetringhaus, 04.06.07
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TDataSetManagerFile                                             //
00015 //                                                                      //
00016 // Implementation of TDataSetManager handling datasets from root   //
00017 // files under a specific directory path                                //
00018 //                                                                      //
00019 //////////////////////////////////////////////////////////////////////////
00020 #include <sys/stat.h>
00021 
00022 #include "TDataSetManagerFile.h"
00023 
00024 #include "Riostream.h"
00025 #include "TDatime.h"
00026 #include "TEnv.h"
00027 #include "TFileCollection.h"
00028 #include "TFileInfo.h"
00029 #include "TFile.h"
00030 #include "TFileStager.h"
00031 #include "TLockFile.h"
00032 #include "TMap.h"
00033 #include "TRegexp.h"
00034 #include "TMD5.h"
00035 #include "TMacro.h"
00036 #include "TMessage.h"
00037 #include "TSystem.h"
00038 #include "TError.h"
00039 #include "TPRegexp.h"
00040 #include "TVirtualMonitoring.h"
00041 #include "TObjArray.h"
00042 #include "THashList.h"
00043 #include "TKey.h"
00044 #include "TTree.h"
00045 #include "TParameter.h"
00046 
00047 struct LsTreeEntry_t {
00048    TObjString  *fGrp;      // Group
00049    TObjString  *fUsr;      // User
00050    TObjString  *fMd5;      // Checksum
00051    TObjString  *fLss;      // 'ls' string
00052    Long64_t     fMtime;    // modification time
00053    LsTreeEntry_t(const char *g, const char *u, const char *cs, const char *ls, Long64_t m) :
00054          fMtime(m) { fGrp = new TObjString(g); fUsr = new TObjString(u);
00055                      fMd5 = new TObjString(cs); fLss = new TObjString(ls); }
00056    ~LsTreeEntry_t() { SafeDelete(fGrp); SafeDelete(fUsr); SafeDelete(fMd5); SafeDelete(fLss);}
00057 };
00058 
00059 ClassImp(TDataSetManagerFile)
00060 
00061 //_____________________________________________________________________________
00062 TDataSetManagerFile::TDataSetManagerFile(const char *group,
00063                                          const char *user, const char *ins)
00064                     : TDataSetManager(group, user, ins)
00065 {
00066    //
00067    // Main constructor
00068 
00069    // Parse options
00070    ParseInitOpts(ins);
00071 
00072    // Init the instance
00073    Init();
00074 }
00075 
00076 //_____________________________________________________________________________
00077 TDataSetManagerFile::TDataSetManagerFile(const char *ins)
00078                     : TDataSetManager("", "", ins)
00079 {
00080    //
00081    // Main constructor
00082 
00083    // Parse options
00084    ParseInitOpts(ins);
00085 
00086    // Init the instance
00087    Init();
00088 }
00089 
00090 //______________________________________________________________________________
00091 void TDataSetManagerFile::Init()
00092 {
00093    // Do the real inititialization
00094 
00095    fIsRemote = kFALSE;
00096    if (!fUser.IsNull() && !fGroup.IsNull() && !fDataSetDir.IsNull()) {
00097 
00098       // Make sure that the dataset dir exists
00099       TString dir;
00100       dir.Form("%s/%s/%s", fDataSetDir.Data(), fGroup.Data(), fUser.Data());
00101       if (gSystem->AccessPathName(dir)) {
00102          if (gSystem->mkdir(dir, kTRUE) != 0) {
00103             TString emsg = dir;
00104             // Read only dataset info system: switch to COMMON
00105             fUser = fCommonUser;
00106             fGroup = fCommonGroup;
00107             ResetBit(TDataSetManager::kCheckQuota);
00108             ResetBit(TDataSetManager::kAllowRegister);
00109             ResetBit(TDataSetManager::kAllowVerify);
00110             ResetBit(TDataSetManager::kTrustInfo);
00111             dir.Form("%s/%s/%s", fDataSetDir.Data(), fGroup.Data(), fUser.Data());
00112             if (gSystem->AccessPathName(dir)) {
00113                Error("Init",
00114                      "could not attach to a valid the dataset dir; paths tried:");
00115                Error("Init", "    %s", emsg.Data());
00116                Error("Init", "    %s", dir.Data());
00117                SetBit(TObject::kInvalidObject);
00118                return;
00119             }
00120          }
00121       }
00122 
00123       // If not in sandbox, construct the base URI using session defaults
00124       // (group, user) (syntax: /group/user/dsname[#[subdir/]objname])
00125       if (!TestBit(TDataSetManager::kIsSandbox))
00126          fBase.SetUri(TString(Form("/%s/%s/", fGroup.Data(), fUser.Data())));
00127 
00128       // Local or remote?
00129       TString locPath;
00130       TFile::EFileType pathType = TFile::GetType(fDataSetDir, "READ", &locPath);
00131       if (pathType == TFile::kLocal) {
00132          // Remote Url pointing to this machine
00133          fDataSetDir = locPath;
00134          if (gDebug > 0)
00135             Info("Init", "repository '%s' is local", fDataSetDir.Data());
00136       } else if (pathType != TFile::kDefault && pathType != TFile::kFile) {
00137          fIsRemote = kTRUE;
00138          if (gDebug > 0)
00139             Info("Init", "repository '%s' is remote", fDataSetDir.Data());
00140       }
00141 
00142       // Read locking path from kDataSet_LockLocation
00143       TString lockloc = TString::Format("%s/%s", fDataSetDir.Data(), kDataSet_LockLocation);
00144       if (!gSystem->AccessPathName(lockloc, kReadPermission)) {
00145          // Open the file in RAW mode
00146          lockloc += "?filetype=raw";
00147          TFile *f = TFile::Open(lockloc);
00148          if (f && !(f->IsZombie())) {
00149             const Int_t blen = 8192;
00150             char buf[blen];
00151             Long64_t rest = f->GetSize();
00152             while (rest > 0) {
00153                Long64_t len = (rest > blen - 1) ? blen - 1 : rest;
00154                if (f->ReadBuffer(buf, len)) {
00155                   fDataSetLockFile = "";
00156                   break;
00157                }
00158                buf[len] = '\0';
00159                fDataSetLockFile += buf;
00160                rest -= len;
00161             }
00162             f->Close();
00163             SafeDelete(f);
00164             fDataSetLockFile.ReplaceAll("\n","");
00165          } else {
00166             lockloc.ReplaceAll("?filetype=raw", "");
00167             Warning("Init", "could not open remore file '%s' with the lock location", lockloc.Data());
00168          }
00169       }
00170       if (fDataSetLockFile.IsNull()) {
00171          fDataSetLockFile.Form("%s-dataset-lock", fDataSetDir.Data());
00172          fDataSetLockFile.ReplaceAll("/","%");
00173          fDataSetLockFile.ReplaceAll(":","%");
00174          fDataSetLockFile.Insert(0, TString::Format("%s/", gSystem->TempDirectory()));
00175       }
00176       if (!fDataSetLockFile.IsNull() && fIsRemote) {
00177          TUrl lu(fDataSetLockFile, kTRUE);
00178          if (!strcmp(lu.GetProtocol(), "file")) {
00179             // Add host and port
00180             TUrl u(fDataSetDir);
00181             TString srv(fDataSetDir);
00182             srv.Remove(srv.Index(u.GetFile()));
00183             fDataSetLockFile.Insert(0, srv);
00184          }
00185       }
00186    }
00187 
00188    // Limit in seconds after a lock automatically expires
00189    fLockFileTimeLimit = 120;
00190 
00191    // Default validity of the cache
00192    fCacheUpdatePeriod = gEnv->GetValue("ProofDataSet.CacheUpdatePeriod", 0);
00193 
00194    // If the MSS url was not given, check if one is defined via env
00195    if (fMSSUrl.IsNull())
00196       fMSSUrl = gEnv->GetValue("ProofDataSet.MSSUrl", "");
00197    // Default highest priority for xrd-backends
00198    fStageOpts = gEnv->GetValue("DataSet.StageOpts", "p=3");
00199 
00200    // File to check updates and its locking path
00201    fListFile.Form("%s/%s", fDataSetDir.Data(), kDataSet_DataSetList);
00202 
00203    // Init the local cache directory if the repository is remote
00204    fUseCache = kFALSE;
00205    fLocalCacheDir = "";
00206    InitLocalCache();
00207 }
00208 //______________________________________________________________________________
00209 void TDataSetManagerFile::InitLocalCache()
00210 {
00211    // Init the local cache if required
00212 
00213    fUseCache = (fIsRemote) ? kTRUE : kFALSE;
00214    
00215    // Check if the caller has given specific instructions
00216    TString useCache;
00217    if (TestBit(TDataSetManager::kUseCache)) useCache = "yes";
00218    if (TestBit(TDataSetManager::kDoNotUseCache)) useCache = "no";
00219    if (useCache.IsNull()) useCache = gEnv->GetValue("DataSet.UseCache", "");
00220    if (useCache.IsNull() && gSystem->Getenv("DATASETCACHE"))
00221       useCache = gSystem->Getenv("DATASETCACHE");
00222    useCache.ToLower();
00223    if (!useCache.IsNull())
00224       fUseCache = (useCache == "no" || useCache == "0") ? kFALSE : kTRUE;
00225       
00226    if (fUseCache) {
00227       fLocalCacheDir = gSystem->Getenv("DATASETLOCALCACHEDIR");
00228       if (fLocalCacheDir.IsNull())
00229          fLocalCacheDir = gEnv->GetValue("DataSet.LocalCacheDir", "");
00230       if (!fLocalCacheDir.IsNull()) {
00231          // Make sure that the non-default local cache directory exists and is writable
00232          if (gSystem->AccessPathName(fLocalCacheDir)) {
00233             if (gSystem->mkdir(fLocalCacheDir, kTRUE) != 0) {
00234                // Switch to default
00235                Warning("InitLocalCache",
00236                         "non-default local cache directory '%s' could not be created"
00237                         " - switching to default", fLocalCacheDir.Data());
00238                fLocalCacheDir = "";
00239             }
00240          }
00241          if (!fLocalCacheDir.IsNull() &&
00242                gSystem->AccessPathName(fLocalCacheDir, kWritePermission)) {
00243             Warning("InitLocalCache",
00244                      "non-default local cache directory '%s' is not writable"
00245                      " - switching to default",
00246                      fDataSetDir.Data());
00247             fLocalCacheDir = "";
00248          }
00249       }
00250       // If not defined yet try the (unique) default
00251       if (fLocalCacheDir.IsNull()) {
00252          // Add something related to fDataSetDir
00253          TString uds(fDataSetDir.Data());
00254          uds.ReplaceAll("/","%");
00255          uds.ReplaceAll(":","%");
00256          if (TString(gSystem->TempDirectory()).EndsWith(fUser.Data())) {
00257             fLocalCacheDir.Form("%s/%s/%s", gSystem->TempDirectory(),
00258                                  kDataSet_LocalCache, uds.Data());
00259          } else {
00260             fLocalCacheDir.Form("%s/%s/%s/%s", gSystem->TempDirectory(),
00261                                  fUser.Data(), kDataSet_LocalCache, uds.Data());
00262          }
00263          // Make sure that the local cache dir exists and is writable
00264          if (gSystem->AccessPathName(fLocalCacheDir) && gSystem->mkdir(fLocalCacheDir, kTRUE) != 0) {
00265             // Disable
00266             Warning("InitLocalCache",
00267                      "local cache directory '%s' could not be created"
00268                      " - disabling cache", fLocalCacheDir.Data());
00269             fUseCache = kFALSE;
00270          }
00271          if (!fLocalCacheDir.IsNull() &&
00272              gSystem->AccessPathName(fLocalCacheDir, kWritePermission)) {
00273             Warning("InitLocalCache",
00274                      "local cache directory '%s' is not writable - disabling cache",
00275                      fDataSetDir.Data());
00276             fUseCache = kFALSE;
00277          }
00278          if (!fUseCache) fLocalCacheDir = "";
00279       }
00280    }
00281    // Done
00282    return;
00283 }
00284 
00285 //______________________________________________________________________________
00286 void TDataSetManagerFile::ParseInitOpts(const char *ins)
00287 {
00288    // Parse the input string and set the init bits accordingly
00289    // Format is
00290    //    dir:<datasetdir> [mss:<mss-url>] [opt:<base-options>]
00291    // The <datasetdir> is mandatory.
00292    // See TDataSetManager::ParseInitOpts for the available
00293    // base options.
00294    // The base options are laready initialized by the base constructor
00295 
00296    SetBit(TObject::kInvalidObject);
00297 
00298    // Needs something in
00299    if (!ins || strlen(ins) <= 0) return;
00300 
00301    // Extract elements
00302    Int_t from = 0;
00303    TString s(ins), tok;
00304    while (s.Tokenize(tok, from, " ")) {
00305       if (tok.BeginsWith("dir:"))
00306          fDataSetDir = tok(4, tok.Length());
00307       if (tok.BeginsWith("mss:"))
00308          fMSSUrl = tok(4, tok.Length());
00309    }
00310 
00311    // The directory is mandatory
00312    if (fDataSetDir.IsNull()) return;
00313 
00314    // Object is valid
00315    ResetBit(TObject::kInvalidObject);
00316 }
00317 
00318 //______________________________________________________________________________
00319 const char *TDataSetManagerFile::GetDataSetPath(const char *group,
00320                                                 const char *user,
00321                                                 const char *dsName,
00322                                                 TString &md5path, Bool_t local)
00323 {
00324    // Returns path of the indicated dataset. The extension is '.root' for all files
00325    // except for 'dsName==ls' which have extension '.txt'.
00326    // If 'local' is kTRUE the local cache path is returned instead in the form
00327    // <cachedir>/<group>.<user>.<dsName>.<ext>.
00328    // NB: contains a static TString for result, so copy result before using twice.
00329 
00330    if (fgCommonDataSetTag == group)
00331      group = fCommonGroup;
00332 
00333    if (fgCommonDataSetTag == user)
00334      user = fCommonUser;
00335 
00336    const char *ext = (!strcmp(dsName, "ls")) ? ".txt" : ".root";
00337    static TString result;
00338    if (local) {
00339       result.Form("%s/%s.%s.%s%s", fLocalCacheDir.Data(), group, user, dsName, ext);
00340       md5path.Form("%s/%s.%s.%s.md5sum", fLocalCacheDir.Data(), group, user, dsName);
00341    } else {
00342       result.Form("%s/%s/%s/%s%s", fDataSetDir.Data(), group, user, dsName, ext);
00343       md5path.Form("%s/%s/%s/%s.md5sum", fDataSetDir.Data(), group, user, dsName);
00344    }
00345    if (gDebug > 0)
00346       Info("GetDataSetPath","paths: %s, %s ", result.Data(), md5path.Data());
00347    return result;
00348 }
00349 
00350 //______________________________________________________________________________
00351 Int_t TDataSetManagerFile::NotifyUpdate(const char *group, const char *user,
00352                                         const char *dsName, Long_t mtime, const char *checksum)
00353 {
00354    // Save into the <datasetdir>/kDataSet_DataSetList file the name of the updated
00355    // or created or modified dataset. For still existing datasets, fill the
00356    // modification date in seconds anf the checksum.
00357    // Returns 0 on success, -1 on error
00358 
00359    // Update / create list for the owner
00360    Long_t lsmtime = 0;
00361    TString lschecksum;
00362    Int_t lsrc = -1;
00363    if ((lsrc = CreateLsFile(group, user, lsmtime, lschecksum)) < 0) {
00364       Warning("NotifyUpdate", "problems (re-)creating the dataset lists for '/%s/%s'",
00365                               group, user);
00366    }
00367 
00368    {  TLockFile lock(fDataSetLockFile, fLockFileTimeLimit);
00369       TString dspath = TString::Format("/%s/%s/%s", group, user, dsName);
00370       // Check if the global file exists
00371       Bool_t hasListFile = gSystem->AccessPathName(fListFile) ? kFALSE : kTRUE;
00372       // Load the info in form of TMacro
00373       TMD5 *oldMd5 = 0, *newMd5 = 0;
00374       if (hasListFile && !(oldMd5 = TMD5::FileChecksum(fListFile.Data()))) {
00375          Error("NotifyUpdate", "problems calculating old checksum of %s", fListFile.Data());
00376          return -1;
00377       }
00378       // Create the TMacro object, filling it with the existing file, if any
00379       TMacro mac;
00380       if (hasListFile) mac.ReadFile(fListFile.Data());
00381       // Locate the line to change or delete
00382       TObjString *os = mac.GetLineWith(dspath);
00383       if (os) {
00384          // Delete the line if required so
00385          if (!strcmp(checksum, "removed")) {
00386             mac.GetListOfLines()->Remove(os);
00387             SafeDelete(os);
00388          } else {
00389             // Update the information
00390             os->SetString(TString::Format("%ld %s %s", mtime, dspath.Data(), checksum));
00391          }
00392       } else {
00393          if (!strcmp(checksum, "removed")) {
00394             Warning("NotifyUpdate", "entry for removed dataset '%s' not found!", dspath.Data());
00395          } else {
00396             // Add new line
00397             mac.AddLine(TString::Format("%ld %s %s", mtime, dspath.Data(), checksum));
00398          }
00399       }
00400       // Locate the ls line now, is needed
00401       TString lspath = TString::Format("/%s/%s/ls", group, user);
00402       os = mac.GetLineWith(lspath);
00403       if (os) {
00404          // Delete the line if required so
00405          if (lsrc == 1) {
00406             mac.GetListOfLines()->Remove(os);
00407             SafeDelete(os);
00408          } else {
00409             // Update the information
00410             os->SetString(TString::Format("%ld %s %s", lsmtime, lspath.Data(), lschecksum.Data()));
00411          }
00412       } else {
00413          if (lsrc == 0) {
00414             // Add new line
00415             mac.AddLine(TString::Format("%ld %s %s", lsmtime, lspath.Data(), lschecksum.Data()));
00416          }
00417       }
00418       // Write off the new content
00419       mac.SaveSource(fListFile.Data());
00420       if (!(newMd5 = TMD5::FileChecksum(fListFile.Data()))) {
00421          Error("NotifyUpdate", "problems calculating new checksum of %s", fListFile.Data());
00422          SafeDelete(oldMd5);
00423          return -1;
00424       }
00425       if (oldMd5 && (*newMd5 == *oldMd5))
00426          Warning("NotifyUpdate", "checksum for %s did not change!", fListFile.Data());
00427       // Cleanup
00428       SafeDelete(oldMd5);
00429       SafeDelete(newMd5);
00430    }
00431    // Done
00432    return 0;
00433 }
00434 
00435 //______________________________________________________________________________
00436 Int_t TDataSetManagerFile::CreateLsFile(const char *group, const char *user,
00437                                         Long_t &mtime, TString &checksum)
00438 {
00439    // Create or recreate the dataset lists for 'uri'.
00440    // The list are saved in text form in 'uri'/ls.txt for fast browsing and in
00441    // 'uri'/ls.root in form of TMacro for optimized and portable transfer.
00442    // Return 0 on success, 1 if the file was empty, -1 on error
00443 
00444    mtime = 0;
00445    checksum = "";
00446    // Create temporary file; we cannot lock now because we would (dead-)lock
00447    // during ShowDataSets
00448    TString tmpfile;
00449    tmpfile.Form("%s/%s/%s/ls.tmp.txt", fDataSetDir.Data(), group, user);
00450 
00451    // Redirect output to 'tmpfile'
00452    RedirectHandle_t rh;
00453    if (gSystem->RedirectOutput(tmpfile.Data(), "w", &rh) != 0) {
00454       Error("CreateLsFile", "problems redirecting output to %s (errno: %d)",
00455                             tmpfile.Data(), TSystem::GetErrno());
00456       return -1;
00457    }
00458    // Create the list
00459    TString uri;
00460    uri.Form("/%s/%s", group, user);
00461    ShowDataSets(uri, "forcescan:noheader:");
00462    // Restore output to standard streams
00463    if (gSystem->RedirectOutput(0, 0, &rh) != 0) {
00464       Error("CreateLsFile", "problems restoring output to standard streams (errno: %d)",
00465                             TSystem::GetErrno());
00466       return -1;
00467    }
00468    // We can lock now
00469    TLockFile lock(fDataSetLockFile, fLockFileTimeLimit);
00470    // Rename the temp file
00471    TString lsfile;
00472    lsfile.Form("%s/%s/%s/ls.txt", fDataSetDir.Data(), group, user);
00473    // Remove the file, if existing
00474    if (!gSystem->AccessPathName(lsfile) && gSystem->Unlink(lsfile) != 0) {
00475       Error("CreateLsFile", "problems unlinking old file '%s' (errno: %d)",
00476                             lsfile.Data(), TSystem::GetErrno());
00477       return -1;
00478    }
00479    // Save the new file only if non empty
00480    FileStat_t st;
00481    if (gSystem->GetPathInfo(tmpfile, st) == 0 && st.fSize > 0) {
00482       if (gSystem->Rename(tmpfile, lsfile) != 0) {
00483          Error("CreateLsFile", "problems renaming '%s' to '%s' (errno: %d)",
00484                               tmpfile.Data(), lsfile.Data(), TSystem::GetErrno());
00485          return -1;
00486       }
00487 #ifndef WIN32
00488       // Make sure that the ownership and permissions are those expected
00489       FileStat_t udirst;
00490       if (!fIsRemote && gSystem->GetPathInfo(gSystem->DirName(tmpfile), udirst) == 0) {
00491          if (chown(lsfile.Data(), udirst.fUid, udirst.fGid) != 0) {
00492             Warning("CreateLsFile", "problems setting ownership on file '%s' (errno: %d)",
00493                                     lsfile.Data(), TSystem::GetErrno());
00494          }
00495          if (chmod(lsfile.Data(), 0644) != 0) {
00496             Warning("CreateLsFile", "problems setting permissions on file '%s' (errno: %d)",
00497                                     lsfile.Data(), TSystem::GetErrno());
00498          }
00499       }
00500 #endif
00501       mtime = st.fMtime;
00502       TMD5 *md5 = TMD5::FileChecksum(lsfile);
00503       if (!md5) {
00504          Error("CreateLsFile", "problems calculating checksum for '%s'", lsfile.Data());
00505       } else {
00506          checksum = md5->AsString();
00507          SafeDelete(md5);
00508       }
00509    } else {
00510       if (!gSystem->AccessPathName(tmpfile) && gSystem->Unlink(tmpfile) != 0) {
00511          Error("CreateLsFile", "problems unlinking temp file '%s' (errno: %d)",
00512                                tmpfile.Data(), TSystem::GetErrno());
00513          return -1;
00514       }
00515       // No datasets anymore
00516       return 1;
00517    }
00518    // Done
00519    return 0;
00520 }
00521 
00522 //______________________________________________________________________________
00523 Bool_t TDataSetManagerFile::BrowseDataSets(const char *group, const char *user,
00524                                            const char *dsName,
00525                                            UInt_t option, TObject *target)
00526 {
00527    // Adds the dataset in the folder of group, user to the list in target.
00528    // If dsName is defined, only the information about the specified dataset
00529    // is processed.
00530    //
00531    // The unsigned int 'option' is forwarded to GetDataSet and BrowseDataSet.
00532    // Available options (to be .or.ed):
00533    //    kPrint          print the dataset content
00534    //    kQuotaUpdate    update quotas
00535    //    kExport         use export naming
00536    //    kList           get a list of dataset names
00537    //
00538    // NB1: options "kPrint", "kQuoatUpdate" and "kExport" are mutually exclusive
00539    // NB2: for options "kPrint" and "kQuotaUpdate" return is null.
00540 
00541    TString userDirPath;
00542    userDirPath.Form("%s/%s/%s", fDataSetDir.Data(), group, user);
00543    void *userDir = gSystem->OpenDirectory(userDirPath);
00544    if (!userDir)
00545      return kFALSE;
00546 
00547    // Options
00548    Bool_t printing = (option & kPrint) ? kTRUE : kFALSE;
00549    Bool_t exporting = (option & kExport) ? kTRUE : kFALSE;
00550    Bool_t updating = (option & kQuotaUpdate) ? kTRUE : kFALSE;
00551    Bool_t printout = (printing && (option & kDebug)) ? kTRUE : kFALSE;
00552    Bool_t listing = (option & kList) ? kTRUE : kFALSE;
00553 
00554    // If printing is required add kReadShort to the options
00555    if (printing || updating)
00556       option |= kReadShort;
00557 
00558    // The last three options are mutually exclusive
00559    if (((Int_t)printing + (Int_t)exporting + (Int_t)updating + (Int_t)listing) > 1) {
00560       Error("BrowseDataSets",
00561             "only one of kPrint, kQuotaUpdate, kExport or kList can be specified at once");
00562       return kFALSE;
00563    }
00564    Bool_t fillmap = (!exporting && !printing && !updating) ? kTRUE : kFALSE;
00565 
00566    // Output object
00567    TMap *outmap = (fillmap || exporting || listing) ? (TMap *)target : (TMap *)0;
00568    TList *outlist = (printing) ? (TList *)target : (TList *)0;
00569 
00570    TRegexp rg("^[^./][^/]*.root$");  //check that it is a root file, not starting with "."
00571 
00572    TRegexp *reds = 0;
00573    if (dsName && strlen(dsName) > 0) reds = new TRegexp(dsName, kTRUE);
00574 
00575    TMap *userMap = 0, *datasetMap = 0;
00576    // loop over datasets
00577    const char *dsEnt = 0;
00578    while ((dsEnt = gSystem->GetDirEntry(userDir))) {
00579       TString datasetFile(dsEnt);
00580       if (datasetFile.Index(rg) != kNPOS) {
00581          TString datasetName(datasetFile(0, datasetFile.Length()-5));
00582 
00583          // Check dataset name, if required
00584          if (reds && datasetName.Index(*reds) == kNPOS) continue;
00585 
00586          if (gDebug > 0)
00587             Info("GetDataSets", "found dataset %s of user %s in group %s",
00588                                  datasetName.Data(), user, group);
00589 
00590          TFileCollection *fileList = GetDataSet(group, user, datasetName, option);
00591          if (!fileList) {
00592             Error("GetDataSets", "dataset %s (user %s, group %s) could not be opened",
00593                                  datasetName.Data(), user, group);
00594             continue;
00595          }
00596          if (gDebug > 0)
00597             fileList->Print();
00598 
00599          // We found a dataset, now add it to the map
00600 
00601          // COMMON dataset transition
00602          const char *mapGroup = group;
00603          if (fCommonGroup == mapGroup)
00604             mapGroup = fgCommonDataSetTag.Data();
00605          const char *mapUser = user;
00606          if (fCommonUser == mapUser)
00607             mapUser = fgCommonDataSetTag.Data();
00608 
00609          if (fillmap && !listing && outmap) {
00610             if (!(userMap = dynamic_cast<TMap*> (outmap->GetValue(mapGroup)))) {
00611                userMap = new TMap;
00612                userMap->SetOwner();
00613                outmap->Add(new TObjString(mapGroup), userMap);
00614             }
00615 
00616             if (!(datasetMap = dynamic_cast<TMap*> (userMap->GetValue(mapUser)))) {
00617                datasetMap = new TMap;
00618                datasetMap->SetOwner();
00619                userMap->Add(new TObjString(mapUser), datasetMap);
00620             }
00621          }
00622 
00623          // Action depends on option
00624          if (exporting) {
00625 
00626             // Just format the dataset name with group and user
00627             TString dsNameFormatted(Form("/%s/%s/%s", mapGroup,
00628                                                       mapUser, datasetName.Data()));
00629             if (outmap)
00630                outmap->Add(new TObjString(dsNameFormatted), fileList);
00631 
00632          } else if (updating) {
00633 
00634             // Update quotas
00635             GetQuota(mapGroup, mapUser, datasetName.Data(), fileList);
00636 
00637          } else if (printing) {
00638 
00639             // Prepare the output list
00640             if (outlist) {
00641                TString dsNameFormatted(Form("/%s/%s/%s", mapGroup,
00642                                                          mapUser, datasetName.Data()));
00643                // Magic number?
00644                if (dsNameFormatted.Length() < 42)
00645                   dsNameFormatted.Resize(42);
00646 
00647                // Done
00648                outlist->Add(fileList->ExportInfo(dsNameFormatted));
00649                if (printout) {
00650                   // Recreating the LS file
00651                   TObjString *os = (TObjString *) outlist->Last();
00652                   if (os) Printf("%s", os->GetName());
00653                }
00654             }
00655          } else if (listing) {
00656 
00657             // Just a list of available datasets
00658             if (outmap) {
00659                outmap->Add(new TObjString(TString::Format("/%s/%s/%s", mapGroup, mapUser, datasetName.Data())),
00660                            new TObjString(""));
00661             }
00662          } else {
00663             if (fillmap && datasetMap)
00664                datasetMap->Add(new TObjString(datasetName), fileList);
00665          }
00666       }
00667    }
00668    gSystem->FreeDirectory(userDir);
00669    SafeDelete(reds);
00670 
00671    return kTRUE;
00672 }
00673 
00674 //______________________________________________________________________________
00675 TMap *TDataSetManagerFile::GetDataSets(const char *group, const char *user,
00676                                        const char *dsName, UInt_t option)
00677 {
00678    // General purpose call to go through the existing datasets.
00679    // If <user> is 0 or "*", act on all datasets for the given <group>.
00680    // If <group> is 0 or "*", act on all datasets.
00681    // If <dsName> is defined, only the information about the specified dataset
00682    // is processed.
00683    // Action depends on option; available options:
00684    //
00685    //    kExport         Return a TMap object containing all the information about
00686    //                    datasets in the form:
00687    //                    { <group>, <map of users> }
00688    //                                     |
00689    //                             { <map of datasets>, <dataset>}
00690    //                    (<dataset> are TFileCollection objects)
00691    //    kShowDefault    as kExport with in addition a default selection including
00692    //                    the datasets from the current user, the ones from the group
00693    //                    and the common ones
00694    //
00695    //    kPrint          print the dataset content; no output is returned
00696    //    kList           get a list of available dataset names
00697    //    kForceScan      Re-open files while processing kPrint (do not use the
00698    //                    pre-processed information)
00699    //    kNoHeaderPrint  Labelling header is not printed
00700    //    kQuotaUpdate    update {group, user} quotas; no output is returned
00701    //
00702    // NB1: options "kPrint", "kQuoatUpdate" and "kExport" are mutually exclusive
00703    // NB2: for options "kPrint" and "kQuoatUpdate" return is null.
00704 
00705    if (group && fgCommonDataSetTag == group)
00706      group = fCommonGroup;
00707 
00708    if (user && fgCommonDataSetTag == user)
00709      user = fCommonUser;
00710 
00711    // Special treatment for the COMMON user
00712    Bool_t notCommonUser = kTRUE;
00713    if ((user && fCommonUser == user) &&
00714        (group && fCommonGroup == group)) notCommonUser = kFALSE;
00715 
00716    // convert * to "nothing"
00717    if (group && (strcmp(group, "*") == 0 || strlen(group) == 0))
00718       group = 0;
00719    if (user && (strcmp(user, "*") == 0 || strlen(user) == 0))
00720       user = 0;
00721 
00722    Bool_t printing = (option & kPrint) ? kTRUE : kFALSE;
00723    Bool_t forcescan = (option & kForceScan) ? kTRUE : kFALSE;
00724    Bool_t printheader = (option & kNoHeaderPrint) ? kFALSE : kTRUE;
00725    Bool_t exporting = (option & kExport) ? kTRUE : kFALSE;
00726    Bool_t updating = (option & kQuotaUpdate) ? kTRUE : kFALSE;
00727    Bool_t refreshingls = (option & kRefreshLs) ? kTRUE : kFALSE;
00728    Bool_t listing = (option & kList) ? kTRUE : kFALSE;
00729 
00730    // The last three options are mutually exclusive
00731    if (((Int_t)printing + (Int_t)exporting + (Int_t)updating + (Int_t)listing) > 1) {
00732       Error("GetDataSets", "only one of '?P', '?Q', '?E' or '?L' can be specified at once");
00733       return 0;
00734    }
00735 
00736    TObject *result = 0;
00737    if (printing) {
00738       // The output is a list of strings
00739       TList *ol = new TList();
00740       ol->SetOwner();
00741       result = ol;
00742    } else if (exporting || !updating || listing) {
00743       TMap *om = new TMap;
00744       om->SetOwner();
00745       result = om;
00746    }
00747 
00748    if (gDebug > 0)
00749       Info("GetDataSets", "opening dir %s", fDataSetDir.Data());
00750 
00751    Long_t m;
00752    TString s;
00753    if (option & kShowDefault) {
00754       // Add the common ones
00755       if (refreshingls) {
00756          if (CreateLsFile(fCommonGroup, fCommonUser, m, s) != 0)
00757             Warning("GetDataSets", "problems recreating 'ls' info for {%s,%s}",
00758                                    fCommonGroup.Data(), fCommonUser.Data());
00759       } else if (!printing || forcescan || (printing &&
00760                  FillLsDataSet(fCommonGroup, fCommonUser, dsName, (TList *)result, option) != 0)) {
00761          BrowseDataSets(fCommonGroup, fCommonUser, dsName, option, result);
00762       }
00763       user = 0;
00764    } else {
00765       // Fill the information at least once
00766       if (!notCommonUser) notCommonUser = kTRUE;
00767    }
00768 
00769    // Fill the information only once
00770    if (notCommonUser) {
00771       // group, user defined, no looping needed
00772       if (user && group && strchr(user, '*') && strchr(group, '*')) {
00773          if (refreshingls) {
00774             if (CreateLsFile(group, user, m, s) != 0)
00775                Warning("GetDataSets", "problems recreating 'ls' info for {%s,%s}",
00776                                       group, user);
00777          } else if (!printing || forcescan || (printing &&
00778                     FillLsDataSet(group, user, dsName, (TList *)result, option) != 0)) {
00779             BrowseDataSets(group, user, dsName, option, result);
00780          }
00781          if (!printing) return (TMap *)result;
00782       } else {
00783          TRegexp *reg = (group && strlen(group) > 0) ? new TRegexp(group, kTRUE) : 0;
00784          TRegexp *reu = (user && strlen(user) > 0) ? new TRegexp(user, kTRUE) : 0;
00785          // Loop needed, either on the local cache or on the real thing
00786          if (printing && !forcescan &&
00787              fUseCache && CheckLocalCache(group, user, 0, option) == 0) {
00788             // Loop on the local cache
00789             Int_t from = 0;
00790             TString locupdate, dsn, grp, usr;
00791             locupdate.Form("%s/%s", fLocalCacheDir.Data(), kDataSet_DataSetList);
00792             TMacro uptmac(locupdate);
00793             TIter nxl(uptmac.GetListOfLines());
00794             TObjString *os = 0;
00795             while ((os = (TObjString *) nxl())) {
00796                if (!(os->GetString().Contains("/ls"))) continue;
00797                from = 0;
00798                if (!(os->GetString().Tokenize(dsn, from, " "))) continue;
00799                if (!(os->GetString().Tokenize(dsn, from, " "))) continue;
00800                from = 0;
00801                // Get group and apply filter on group
00802                if (!(dsn.Tokenize(grp, from, "/")) || (reg && (grp.Index(*reg) == kNPOS))) continue;
00803                // Get user and apply filter on user
00804                if (!(dsn.Tokenize(usr, from, "/")) || (reu && (usr.Index(*reu) == kNPOS))) continue;
00805                // Now get the info
00806                if (FillLsDataSet(grp, usr, dsName, (TList *)result, option) != 0) {
00807                   // Use the standard way opening all the files
00808                   BrowseDataSets(grp, usr, dsName, option, result);
00809                }
00810             }
00811          } else {
00812             // Loop needed on the real thing
00813             void *dataSetDir = 0;
00814             if ((dataSetDir = gSystem->OpenDirectory(fDataSetDir))) {
00815                // loop over groups
00816                const char *eg = 0;
00817                while ((eg = gSystem->GetDirEntry(dataSetDir))) {
00818 
00819                   if (strcmp(eg, ".") == 0 || strcmp(eg, "..") == 0)
00820                      continue;
00821 
00822                   if (reg && (TString(eg).Index(*reg) == kNPOS))
00823                      continue;
00824 
00825                   TString groupDirPath;
00826                   groupDirPath.Form("%s/%s", fDataSetDir.Data(), eg);
00827 
00828                   // Make sure it is a directory
00829                   FileStat_t dirSt;
00830                   if (gSystem->GetPathInfo(groupDirPath, dirSt) != 0 || !R_ISDIR(dirSt.fMode))
00831                      continue;
00832 
00833                   void *groupDir = gSystem->OpenDirectory(groupDirPath);
00834                   if (!groupDir)
00835                      continue;
00836 
00837                   // loop over users
00838                   const char *eu = 0;
00839                   while ((eu = gSystem->GetDirEntry(groupDir))) {
00840 
00841                      if (strcmp(eu, ".") == 0 || strcmp(eu, "..") == 0)
00842                         continue;
00843 
00844                      if (reu && (TString(eu).Index(*reu) == kNPOS))
00845                         continue;
00846 
00847                      // If we have the ls.macro use that
00848                      if (refreshingls) {
00849                         if (CreateLsFile(eg, eu, m, s) != 0)
00850                            Warning("GetDataSets", "problems recreating 'ls' info for {%s,%s}",
00851                                                   eg, eu);
00852                      } else if (!printing || forcescan || (printing &&
00853                                  FillLsDataSet(eg, eu, dsName, (TList *)result, option) != 0)) {
00854                         // Use the standard way opening all the files
00855                         BrowseDataSets(eg, eu, dsName, option, result);
00856                      }
00857                   }
00858                   gSystem->FreeDirectory(groupDir);
00859                }
00860                gSystem->FreeDirectory(dataSetDir);
00861             }
00862          }
00863          SafeDelete(reg);
00864          SafeDelete(reu);
00865       }
00866    }
00867    // Print the result, if required
00868    if (printing) {
00869       TList *output = (TList *)result;
00870       output->Sort();
00871       if (printheader) {
00872          Printf("Dataset repository: %s", fDataSetDir.Data());
00873          Printf("Dataset URI                               | # Files | Default tree | # Events |   Disk   | Staged");
00874       }
00875       TIter iter4(output);
00876       TObjString *os = 0;
00877       while ((os = dynamic_cast<TObjString*> (iter4()))) {
00878          if (os->GetString().BeginsWith("file:")) {
00879             // Path of the file to be browsed
00880             TString path(os->GetString()(5, os->GetString().Length()));
00881             RedirectHandle_t rh(path.Data());
00882             gSystem->ShowOutput(&rh);
00883             fflush(stderr);
00884          } else {
00885             // Simple line
00886             Printf("%s", os->String().Data());
00887          }
00888       }
00889       // Cleanup
00890       SafeDelete(output);
00891       result = 0;
00892    }
00893 
00894    return (TMap *)result;
00895 }
00896 
00897 //______________________________________________________________________________
00898 Int_t TDataSetManagerFile::FillLsDataSet(const char *group, const char *user,
00899                                          const char *dsname, TList *out, UInt_t option)
00900 {
00901    // Check for the 'ls.txt' for 'group' and 'user' and fill the path for the
00902    // ls file in 'out'.
00903    // If 'dsname' is defined, open the file and extract the relevant line.
00904    // Return 0 on success, -1 on failure
00905 
00906    // Check inputs
00907    if (!group || strlen(group) <= 0 || !user || strlen(user) <= 0 || !out) {
00908       Error("FillLsDataSet", "at least one of the inputs is invalid (%s,%s,%p)", group, user, out);
00909       return -1;
00910    }
00911 
00912    // File with the TMacro
00913    Int_t crc = -1;
00914    TString lsfile, lsmd5file;
00915    if (!fUseCache || (fUseCache && (crc = CheckLocalCache(group, user, "ls", option)) <= 0)) {
00916       Bool_t local = (crc == 0) ? kTRUE : kFALSE;
00917       lsfile = GetDataSetPath(group, user, "ls", lsmd5file, local);
00918    } else {
00919       // The dataset does not exist anymore
00920       return 0;
00921    }
00922 
00923    if (gSystem->AccessPathName(lsfile, kFileExists)) {
00924       if (gDebug > 0)
00925          Info("FillLsDataSet", "file '%s' does not exists", lsfile.Data());
00926       return -1;
00927    }
00928    if (gSystem->AccessPathName(lsfile, kReadPermission)) {
00929       Warning("FillLsDataSet", "file '%s' exists cannot be read (permission denied)", lsfile.Data());
00930       return -1;
00931    }
00932 
00933    if (dsname && strlen(dsname) > 0) {
00934       // Read the macro
00935       TMacro *mac = new TMacro(lsfile.Data());
00936       if (!mac) {
00937          Error("FillLsDataSet", "could not initialize TMacro from '%s'", lsfile.Data());
00938          return -1;
00939       }
00940       // Prepare the string to search for
00941       TString fullname = TString::Format("/%s/%s/%s", group, user, dsname);
00942       Bool_t wc = (fullname.Contains("*")) ? kTRUE : kFALSE;
00943       if (wc) fullname.ReplaceAll("*", ".*");
00944       TRegexp reds(fullname);
00945       TIter nxl(mac->GetListOfLines());
00946       TObjString *o;
00947       Int_t nf = 0;
00948       while ((o = (TObjString *) nxl())) {
00949          if (o->GetString().Index(reds) != kNPOS) {
00950             out->Add(o->Clone());
00951             nf++;
00952             if (!wc) break;
00953          }
00954       }
00955       if (nf > 0 && gDebug > 0)
00956          Info("FillLsDataSet", "no match for dataset uri '/%s/%s/%s'", group, user, dsname);
00957       // Delete the macro
00958       SafeDelete(mac);
00959    } else {
00960       // Fill in the file information
00961       out->Add(new TObjString(TString::Format("file:%s", lsfile.Data())));
00962    }
00963    // Done
00964    return 0;
00965 }
00966 
00967 //______________________________________________________________________________
00968 TFileCollection *TDataSetManagerFile::GetDataSet(const char *group,
00969                                                  const char *user,
00970                                                  const char *dsName,
00971                                                  UInt_t option,
00972                                                  TMD5 **checksum)
00973 {
00974    //
00975    // Returns the dataset <dsName> of user <user> in group <group> .
00976    // If checksum is non-zero, it will contain the pointer to a TMD5 sum object
00977    // with the checksum of the file, has to be deleted by the user.
00978    // If option has the bi kReadShort set, the shortobject is read, that does not
00979    // contain the list of files. This is much faster.
00980 
00981    TFileCollection *fileList = 0;
00982    Bool_t readshort = (option & kReadShort) ? kTRUE : kFALSE;
00983    // Check is the file is in the cache
00984    Int_t crc = -1;
00985    TString path, md5path;
00986    if (readshort || !fUseCache ||
00987       (!readshort && fUseCache && (crc = CheckLocalCache(group, user, dsName, option)) <= 0)) {
00988       Bool_t local = (crc == 0) ? kTRUE : kFALSE;
00989       path = GetDataSetPath(group, user, dsName, md5path, local);
00990    } else {
00991       // The dataset does not exist (anymore?)
00992       if (gDebug > 0)
00993          Info("GetDataSet", "dataset %s does not exist", path.Data());
00994       return fileList;
00995    }
00996 
00997    // Now we lock because we are going to use the file, if there
00998    TLockFile lock(fDataSetLockFile, fLockFileTimeLimit);
00999 
01000    // Check if the file can be opened for reading
01001    if (gSystem->AccessPathName(path, kFileExists)) {
01002       if (gDebug > 0)
01003          Info("GetDataSet", "file '%s' does not exists", path.Data());
01004       return fileList;
01005    }
01006    if (gSystem->AccessPathName(path, kReadPermission)) {
01007       Warning("GetDataSet", "file '%s' exists cannot be read (permission denied)", path.Data());
01008       return fileList;
01009    }
01010 
01011    // Get checksum
01012    if (checksum) {
01013       // save md5 sum
01014       *checksum = TMD5::ReadChecksum(md5path);
01015       if (!(*checksum)) {
01016          Error("GetDataSet", "could not get checksum of %s from %s", path.Data(), md5path.Data());
01017          return fileList;
01018       }
01019    }
01020 
01021    TFile *f = TFile::Open(path.Data());
01022    if (!f) {
01023       Error("GetDataSet", "could not open file %s", path.Data());
01024       if (checksum) SafeDelete(*checksum);
01025       return fileList;
01026    }
01027 
01028    if (option & kReadShort)
01029      fileList = dynamic_cast<TFileCollection*> (f->Get("dataset_short"));
01030 
01031    if (!fileList)
01032      fileList = dynamic_cast<TFileCollection*> (f->Get("dataset"));
01033 
01034    f->Close();
01035    SafeDelete(f);
01036 
01037    return fileList;
01038 }
01039 
01040 //______________________________________________________________________________
01041 Int_t TDataSetManagerFile::CheckLocalCache(const char *group, const char *user,
01042                                            const char *dsName, UInt_t option)
01043 {
01044    // Check if the local cache information for group, user, dsName is up-to-date
01045    // If not, make the relevant updates
01046    // Return 0 if OK, 1 if the dataset does not exists anymore, -1 on failure
01047 
01048    // Check first if the global update info is uptodate
01049    static TMacro *uptmac = 0;
01050    Bool_t need_last_update = (option & kNoCacheUpdate) ? kFALSE : kTRUE;
01051    TString locupdtim, locupdate, remupdate;
01052    locupdtim.Form("%s/%s.update", fLocalCacheDir.Data(), kDataSet_DataSetList);
01053    locupdate.Form("%s/%s", fLocalCacheDir.Data(), kDataSet_DataSetList);
01054    remupdate.Form("%s/%s", fDataSetDir.Data(), kDataSet_DataSetList);
01055    need_last_update = (gSystem->AccessPathName(locupdate)) ? kTRUE : need_last_update;
01056    TDatime now;
01057    UInt_t tnow = now.Convert();
01058    FileStat_t timst, locst, remst;
01059    if (need_last_update && !gSystem->AccessPathName(locupdtim)) {
01060       if (gSystem->GetPathInfo(locupdtim, timst) == 0) {
01061          need_last_update = kFALSE;
01062          if ((Int_t)tnow > timst.fMtime + fCacheUpdatePeriod) need_last_update = kTRUE;
01063       }
01064    }
01065    if (need_last_update) {
01066       if (gSystem->GetPathInfo(remupdate, remst) != 0) {
01067          Error("CheckLocalCache", "cannot get info for remote file '%s' - ignoring", remupdate.Data());
01068          return -1;
01069       }
01070       if (gSystem->GetPathInfo(locupdate, locst) == 0) {
01071          need_last_update = kFALSE;
01072          if (remst.fMtime > locst.fMtime) {
01073             need_last_update = kTRUE;
01074          } else {
01075             if (!gSystem->AccessPathName(locupdtim))
01076                if (gSystem->Utime(locupdtim, tnow, 0) != 0)
01077                   Warning("CheckLocalCache",
01078                           "cannot set modification time on file '%s' (errno: %d)",
01079                           locupdtim.Data(), TSystem::GetErrno());
01080          }
01081       }
01082    }
01083    // Get the file, if needed
01084    if (need_last_update) {
01085       if (!TFile::Cp(remupdate, locupdate, kFALSE)) {
01086          Error("CheckLocalCache", "cannot get remote file '%s' - ignoring", remupdate.Data());
01087          return -1;
01088       }
01089       // Set the modification time
01090       if (gSystem->Utime(locupdate, remst.fMtime, 0) != 0) {
01091          Warning("CheckLocalCache", "cannot set modification time on file '%s' (errno: %d)",
01092                            locupdate.Data(), TSystem::GetErrno());
01093       }
01094       // Touch or create the file to control updates
01095       if (gSystem->AccessPathName(locupdtim)) {
01096          FILE *ftim = fopen(locupdtim.Data(), "w");
01097          if (!ftim) {
01098             Warning("CheckLocalCache", "problems create file '%s' (errno: %d)",
01099                                        locupdtim.Data(), TSystem::GetErrno());
01100          } else {
01101             if (fclose(ftim) != 0)
01102                Warning("CheckLocalCache", "problems close file '%s' (errno: %d)",
01103                                           locupdtim.Data(), TSystem::GetErrno());
01104             if (gSystem->Utime(locupdtim, now.Convert(), 0) != 0)
01105                Warning("CheckLocalCache",
01106                        "cannot set modification time on file '%s' (errno: %d)",
01107                        locupdtim.Data(), TSystem::GetErrno());
01108          }
01109       }
01110       // Update macro info
01111       SafeDelete(uptmac);
01112       uptmac = new TMacro(locupdate);
01113    } else {
01114       // Touch or create the file to control updates
01115       if (gSystem->AccessPathName(locupdtim)) {
01116          FILE *ftim = fopen(locupdtim.Data(), "w");
01117          if (!ftim) {
01118             Warning("CheckLocalCache", "problems create file '%s' (errno: %d)",
01119                                        locupdtim.Data(), TSystem::GetErrno());
01120          } else {
01121             if (fclose(ftim) != 0)
01122                Warning("CheckLocalCache", "problems close file '%s' (errno: %d)",
01123                                           locupdtim.Data(), TSystem::GetErrno());
01124             if (gSystem->GetPathInfo(locupdate, locst) == 0) {
01125                if (gSystem->Utime(locupdtim, locst.fMtime, 0) != 0)
01126                   Warning("CheckLocalCache",
01127                           "cannot set modification time on file '%s' (errno: %d)",
01128                           locupdtim.Data(), TSystem::GetErrno());
01129             } else {
01130                Warning("CheckLocalCache", "cannot get info for file '%s'"
01131                        " - will not touch '%s'", locupdate.Data(), locupdtim.Data());
01132             }
01133          }
01134       }
01135       if (!uptmac) uptmac = new TMacro(locupdate);
01136    }
01137 
01138    // If we are just interested in the global dataset list we are done
01139    if (!dsName || strlen(dsName) <= 0)
01140       return 0;
01141 
01142    // Read the information
01143    TString ds, locpath, path, locmd5path, md5path, remmd5s;
01144    TMD5 *locmd5 = 0;
01145    // The paths ...
01146    path = GetDataSetPath(group, user, dsName, md5path);
01147    locpath = GetDataSetPath(group, user, dsName, locmd5path, kTRUE);
01148    ds.Form("/%s/%s/%s", group, user, dsName);
01149    TObjString *os = uptmac->GetLineWith(ds);
01150    if (!os) {
01151       // DataSet does not exist anymore
01152       if (strcmp(dsName, "ls"))
01153          Warning("CheckLocalCache", "dataset '%s' does not exists anymore", ds.Data());
01154       return 1;
01155    }
01156    // Extract the relevant information
01157    TString s;
01158    Int_t from = 0;
01159    while (os->GetString().Tokenize(s, from, " ")) {
01160       if (!s.IsDigit() && s != ds) {
01161          remmd5s = s;
01162       }
01163    }
01164    if (remmd5s == "---") {
01165       // DataSet does not exist anymore
01166       if (strcmp(dsName, "ls"))
01167          Warning("CheckLocalCache", "dataset '%s' does not exists anymore", ds.Data());
01168       return 1;
01169    }
01170    Bool_t need_update = (option & kNoCacheUpdate) ? kFALSE : kTRUE;
01171    if (!gSystem->AccessPathName(locpath)) {
01172       if (need_update) {
01173          need_update = kFALSE;
01174          locmd5 = TMD5::ReadChecksum(locmd5path);
01175          if (!locmd5 && !(locmd5 = TMD5::FileChecksum(locpath))) {
01176             Warning("CheckLocalCache", "cannot get checksum of '%s' - assuming match failed", ds.Data());
01177             need_update = kTRUE;
01178          } else {
01179             if (remmd5s != locmd5->AsString()) need_update = kTRUE;
01180          }
01181       }
01182    } else {
01183       need_update = kTRUE;
01184    }
01185    // Get the file, if needed
01186    if (need_update) {
01187       SafeDelete(locmd5);
01188       if (!TFile::Cp(path, locpath, kFALSE)) {
01189          Error("CheckLocalCache", "cannot get remote file '%s' - ignoring", path.Data());
01190          return -1;
01191       }
01192       // Calculate and save the new checksum
01193       locmd5 = TMD5::FileChecksum(locpath);
01194       if (locmd5) {
01195          if (remmd5s != locmd5->AsString())
01196             Warning("CheckLocalCache", "checksum for freshly downloaded file '%s' does not match the"
01197                                " one posted in '%s'", locpath.Data(), kDataSet_DataSetList);
01198          if (TMD5::WriteChecksum(locmd5path, locmd5) != 0)
01199             Warning("CheckLocalCache", "problems saving checksum to '%s' (errno: %d)",
01200                                locmd5path.Data(), TSystem::GetErrno());
01201       } else {
01202          Warning("CheckLocalCache", "problems calculating checksum for '%s'", locpath.Data());
01203       }
01204    }
01205    SafeDelete(locmd5);
01206    // Done
01207    return 0;
01208 }
01209 
01210 //______________________________________________________________________________
01211 Int_t TDataSetManagerFile::ClearCache(const char *uri)
01212 {
01213    // Clear cached information matching uri
01214 
01215    // Open the top directory
01216    void *dirp = gSystem->OpenDirectory(fLocalCacheDir.Data());
01217    if (!dirp) {
01218       Error("ClearCache", "cannot open directory '%s' (errno: %d)",
01219                           fLocalCacheDir.Data(), TSystem::GetErrno());
01220       return -1;
01221    }
01222    TRegexp *re = 0;
01223    if (uri && strlen(uri) > 0) {
01224       if (strcmp(uri, "*") && strcmp(uri, "/*") && strcmp(uri, "/*/") &&
01225           strcmp(uri, "/*/*") && strcmp(uri, "/*/*/") && strcmp(uri, "/*/*/*")) {
01226          TString u(uri);
01227          // Remove leading '/'
01228          if (u(0) == '/') u.Remove(0,1);
01229          // Change '/' to '%'
01230          u.ReplaceAll("/", ".");
01231          // Init the regular expression
01232          u.ReplaceAll("*", ".*");
01233          re = new TRegexp(u.Data());
01234       }
01235    }
01236 
01237    Printf(" Dataset repository: %s", fDataSetDir.Data());
01238    Printf(" Local cache directory: %s", fLocalCacheDir.Data());
01239 
01240    Long64_t totsz = 0, nf = 0;
01241    FileStat_t st;
01242    TString path;
01243    const char *e = 0;
01244    while ((e = gSystem->GetDirEntry(dirp))) {
01245       // Skip basic entries
01246       if (!strcmp(e,".") || !strcmp(e,"..")) continue;
01247       // Apply regular expression, if requested
01248       if (re && TString(e).Index(*re) == kNPOS) continue;
01249       // Group directory
01250       path.Form("%s/%s", fLocalCacheDir.Data(), e);
01251       // Get file information
01252       if (gSystem->GetPathInfo(path, st) != 0) {
01253          Warning("ShowCache", "problems 'stat'-ing '%s' (errno: %d)",
01254                                path.Data(), TSystem::GetErrno());
01255          continue;
01256       }
01257       // Count
01258       totsz += st.fSize;
01259       nf++;
01260       // Remove the file
01261       if (gSystem->Unlink(path) != 0) {
01262          Warning("ClearCache", "problems unlinking '%s' (errno: %d)",
01263                                path.Data(), TSystem::GetErrno());
01264       }
01265    }
01266    gSystem->FreeDirectory(dirp);
01267    SafeDelete(re);
01268 
01269    // Notify totals
01270    Printf(" %lld bytes (%lld files) have been freed", totsz, nf);
01271 
01272    // Done
01273    return 0;
01274 }
01275 
01276 //______________________________________________________________________________
01277 Int_t TDataSetManagerFile::ShowCache(const char *uri)
01278 {
01279    // Show cached information matching uri
01280 
01281    // Open the top directory
01282    void *dirp = gSystem->OpenDirectory(fLocalCacheDir.Data());
01283    if (!dirp) {
01284       Error("ShowCache", "cannot open directory '%s' (errno: %d)",
01285                          fLocalCacheDir.Data(), TSystem::GetErrno());
01286       return -1;
01287    }
01288    TRegexp *re = 0;
01289    if (uri && strlen(uri) > 0) {
01290       if (strcmp(uri, "*") && strcmp(uri, "/*") && strcmp(uri, "/*/") &&
01291           strcmp(uri, "/*/*") && strcmp(uri, "/*/*/") && strcmp(uri, "/*/*/*")) {
01292          TString u(uri);
01293          // Remove leading '/'
01294          if (u(0) == '/') u.Remove(0,1);
01295          // Change '/' to '%'
01296          u.ReplaceAll("/", ".");
01297          // Init the regular expression
01298          u.ReplaceAll("*", ".*");
01299          re = new TRegexp(u.Data());
01300       }
01301    }
01302 
01303    Printf(" Dataset repository: %s", fDataSetDir.Data());
01304    Printf(" Local cache directory: %s", fLocalCacheDir.Data());
01305    Printf(" Last modified        Size(bytes)  File");
01306 
01307    Long64_t totsz = 0, nf = 0;
01308    FileStat_t st;
01309    TString path, sz;
01310    const char *e = 0;
01311    while ((e = gSystem->GetDirEntry(dirp))) {
01312       // Skip basic entries
01313       if (!strcmp(e,".") || !strcmp(e,"..")) continue;
01314       // Apply regular expression, if requested
01315       if (re && TString(e).Index(*re) == kNPOS) continue;
01316       // Group directory
01317       path.Form("%s/%s", fLocalCacheDir.Data(), e);
01318       // Get file information
01319       if (gSystem->GetPathInfo(path, st) != 0) {
01320          Warning("ShowCache", "problems 'stat'-ing '%s' (errno: %d)",
01321                                path.Data(), TSystem::GetErrno());
01322          continue;
01323       }
01324       // Count
01325       totsz += st.fSize;
01326       nf++;
01327       // Get modification time in human readable form
01328       TDatime tmod(st.fMtime);
01329       sz.Form("%lld", st.fSize);
01330       sz.Resize(12);
01331       Printf(" %s  %s %s", tmod.AsSQLString(), sz.Data(), e);
01332    }
01333    gSystem->FreeDirectory(dirp);
01334    SafeDelete(re);
01335 
01336    // Notify totals
01337    Printf(" %lld files, %lld bytes", nf, totsz);
01338 
01339    // Done
01340    return 0;
01341 }
01342 
01343 //______________________________________________________________________________
01344 Int_t TDataSetManagerFile::WriteDataSet(const char *group, const char *user,
01345                                         const char *dsName, TFileCollection *dataset,
01346                                         UInt_t option, TMD5 *checksum)
01347 {
01348    //
01349    // Writes indicated dataset.
01350    // If option has the bit kFileMustExist set, the file must still exist,
01351    // otherwise the new dataset is not written (returns 3 in this case).
01352    // If checksum is non-zero the files current checksum is checked against it,
01353    // if it does not match the file is not written (the function returns 2 in this
01354    // case, if the file has disappeared it is also not written (i.e. checksum
01355    // implies the bit kFileMustExist set in option).
01356    // Returns != 0 for success, 0 for error
01357 
01358    TString md5path, path, md5sum;
01359    Long_t mtime = 0;
01360    {  TLockFile lock(fDataSetLockFile, fLockFileTimeLimit);
01361 
01362       Bool_t checkIfExists = ((option & kFileMustExist) || checksum) ? kTRUE : kFALSE;
01363 
01364       path = GetDataSetPath(group, user, dsName, md5path);
01365 
01366       if (checkIfExists) {
01367          // check if file still exists, otherwise it was deleted in the meanwhile and is not written here
01368          Long_t tmp;
01369          if (gSystem->GetPathInfo(path, 0, (Long_t*) 0, 0, &tmp) != 0) {
01370             if (gDebug > 0)
01371                Info("WriteDataSet", "Dataset disappeared. Discarding update.");
01372             return 3;
01373          }
01374       }
01375 
01376       if (checksum) {
01377          // verify md5 sum, otherwise the file was changed in the meanwhile and is not overwritten here
01378          TMD5 *checksum2 = TMD5::FileChecksum(path);
01379          if (!checksum2) {
01380             Error("WriteDataSet", "Could not get checksum of %s", path.Data());
01381             return 0;
01382          }
01383 
01384          Bool_t checksumAgrees = (*checksum == *checksum2);
01385          delete checksum2;
01386 
01387          if (!checksumAgrees) {
01388             if (gDebug > 0)
01389                Info("WriteDataSet", "Dataset changed. Discarding update.");
01390             return 2;
01391          }
01392       }
01393 
01394       // write first in ".<file>" then rename to recover from crash during writing
01395       TString tempFile(path);
01396       Int_t index = -1;
01397       while (tempFile.Index("/", index+1) >= 0)
01398          index = tempFile.Index("/", index+1);
01399 
01400       tempFile.Insert(index+1, ".");
01401 
01402       TFile *f = TFile::Open(tempFile, "RECREATE");
01403       if (!f) {
01404          Error("WriteDataSet", "Could not open dataset for writing %s", tempFile.Data());
01405          return 0;
01406       }
01407 
01408       // write full TFileCollection
01409       dataset->Write("dataset", TObject::kSingleKey | TObject::kOverwrite);
01410 
01411       // write only metadata
01412       THashList *list = dataset->GetList();
01413       dataset->SetList(0);
01414       dataset->Write("dataset_short", TObject::kSingleKey | TObject::kOverwrite);
01415 
01416       f->Close();
01417       delete f;
01418 
01419       // Restore full list
01420       dataset->SetList(list);
01421 
01422       // file is written, rename to real filename
01423       if (gSystem->Rename(tempFile, path) != 0) {
01424          Error("WriteDataSet", "renaming %s to %s failed; dataset might be corrupted",
01425                               tempFile.Data(), path.Data());
01426          // Cleanup any MD5 sum information
01427          if (!gSystem->AccessPathName(md5path, kWritePermission) && gSystem->Unlink(md5path) != 0)
01428             Error("WriteDataSet", "unlink of %s failed", md5path.Data());
01429          return 0;
01430       }
01431       // Save md5 sum, otherwise the file was changed in the meanwhile and is not overwritten here
01432       if (ChecksumDataSet(path, md5path, md5sum) != 0) {
01433          Error("WriteDataSet", "problems calculating checksum of %s", path.Data());
01434          return 0;
01435       }
01436       FileStat_t st;
01437       if (gSystem->GetPathInfo(path, st) != 0) {
01438          Error("WriteDataSet", "could not 'stat' the version of '%s'!", path.Data());
01439          return 0;
01440       }
01441       mtime= st.fMtime;
01442    }
01443 
01444    // The repository was updated
01445    if (NotifyUpdate(group, user, dsName, mtime, md5sum) != 0)
01446       Warning("WriteDataSet", "problems notifying update with 'NotifyUpdate'");
01447 
01448    return 1;
01449 }
01450 
01451 //______________________________________________________________________________
01452 Int_t TDataSetManagerFile::ChecksumDataSet(const char *path,
01453                                            const char *md5path, TString &checksum)
01454 {
01455    // Calculate the checksum of the indicated dataset at 'path' and save it to the
01456    // appropriate file 'md5path'. The MD5 string is returned in 'md5sum'.
01457    // Return 0 on success, -1 on error.
01458 
01459    checksum = "";
01460    // Check inputs
01461    if (!path || strlen(path) <= 0 || !md5path || strlen(md5path) <= 0) {
01462       Error("ChecksumDataSet", "one or more inputs are invalid ('%s','%s')",
01463              path, md5path);
01464       return -1;
01465    }
01466    // Calculate md5 sum
01467    TMD5 *md5sum = TMD5::FileChecksum(path);
01468    if (!md5sum) {
01469       Error("ChecksumDataSet", "problems calculating checksum of '%s'", path);
01470       return -1;
01471    }
01472    // Save it to a file
01473    if (TMD5::WriteChecksum(md5path, md5sum) != 0) {
01474       Error("ChecksumDataSet", "problems saving checksum to '%s'", md5path);
01475       SafeDelete(md5sum);
01476       return -1;
01477    }
01478    // Fill output
01479    checksum = md5sum->AsString();
01480    // Done
01481    SafeDelete(md5sum);
01482    return 0;
01483 }
01484 
01485 //______________________________________________________________________________
01486 Bool_t TDataSetManagerFile::RemoveDataSet(const char *group, const char *user,
01487                                                const char *dsName)
01488 {
01489    // Removes the indicated dataset
01490 
01491    TString md5path, path;
01492    {  TLockFile lock(fDataSetLockFile, fLockFileTimeLimit);
01493 
01494       path = GetDataSetPath(group, user, dsName, md5path);
01495       Int_t rc = 0;
01496       // Remove the main file
01497       if ((rc = gSystem->Unlink(path)) != 0)
01498          Warning("RemoveDataSet", "problems removing main file '%s' (errno: %d)",
01499                                  path.Data(), TSystem::GetErrno());
01500       // Remove the checksum file
01501       if (gSystem->Unlink(md5path) != 0)
01502          Warning("RemoveDataSet", "problems removing chcksum file '%s' (errno: %d)",
01503                                  md5path.Data(), TSystem::GetErrno());
01504    }
01505 
01506    // The repository was updated
01507    if (gSystem->AccessPathName(path, kFileExists)) {
01508       if (NotifyUpdate(group, user, dsName, 0, "removed") != 0)
01509          Warning("RemoveDataSet", "problems notifying update with 'NotifyUpdate'");
01510       // Success
01511       return kTRUE;
01512    }
01513    // Failure
01514    return kFALSE;
01515 }
01516 
01517 //______________________________________________________________________________
01518 Bool_t TDataSetManagerFile::ExistsDataSet(const char *group, const char *user,
01519                                                const char *dsName)
01520 {
01521    // Checks if the indicated dataset exits
01522 
01523    TLockFile lock(fDataSetLockFile, fLockFileTimeLimit);
01524 
01525    TString md5path, path(GetDataSetPath(group, user, dsName, md5path));
01526 
01527    return (gSystem->AccessPathName(path) == kFALSE);
01528 }
01529 
01530 //______________________________________________________________________________
01531 Int_t TDataSetManagerFile::RegisterDataSet(const char *uri,
01532                                            TFileCollection *newDataSet,
01533                                            const char *opts)
01534 {
01535    // Register a dataset, perfoming quota checkings and verification, if required.
01536    // If a dataset with the same name already exists the action fails unless 'opts'
01537    // contains 'O', in which case the old dataset is overwritten, or contains 'U',
01538    // in which case 'newDataSet' is added to the existing dataset (duplications are
01539    // ignored, if any).
01540    // If 'opts' contains 'V' the dataset files are also verified (if the dataset manager
01541    // is configured to allow so). By default the dataset is not verified.
01542    // If 'opts' contains 'T' the in the dataset object (status bits, meta,...)
01543    // is trusted, i.e. not reset (if the dataset manager is configured to allow so).
01544    // Returns 0 on success, -1 on failure
01545 
01546    if (!TestBit(TDataSetManager::kAllowRegister))
01547       return -1;
01548 
01549    // Get the dataset name
01550    TString dsName;
01551    if (ParseUri(uri, 0, 0, &dsName, 0, kTRUE) == kFALSE) {
01552       Error("RegisterDataSet", "problem parsing uri: %s", uri);
01553       return -1;
01554    }
01555 
01556    // The dataset
01557    TFileCollection *dataSet = newDataSet;
01558    // Check option
01559    TString opt(opts);
01560    // If in update mode, retrieve the existing dataset, if any
01561    if (opt.Contains("U", TString::kIgnoreCase)) {
01562       // Fail if it exists already
01563       if (ExistsDataSet(fGroup, fUser, dsName)) {
01564          // Retrieve the dataset
01565          if (!(dataSet = GetDataSet(fGroup, fUser, dsName))) {
01566             // Dataset name does exist
01567             Warning("RegisterDataSet",
01568                     "dataset '%s' claimed to exists but retrieval failed - ignoring", uri);
01569             dataSet = newDataSet;
01570          } else {
01571             // Add new dataset to existing one
01572             dataSet->Add(newDataSet);
01573          }
01574       }
01575    } else if (!opt.Contains("O", TString::kIgnoreCase)) {
01576       // Fail if it exists already
01577       if (ExistsDataSet(fGroup, fUser, dsName)) {
01578          //Dataset name does exist
01579          Error("RegisterDataSet", "dataset '%s' exists already", uri);
01580          return -1;
01581       }
01582    }
01583 
01584    // We will save a sorted list
01585    dataSet->Sort();
01586 
01587    // A temporary list to hold the unique members (i.e. the very set)
01588    TList *uniqueFileList = new TList();
01589    TIter nextFile(dataSet->GetList());
01590    TFileInfo *prevFile = (TFileInfo*)nextFile();
01591    uniqueFileList->Add(prevFile);
01592    while (TFileInfo *obj = (TFileInfo*)nextFile()) {
01593       // Add entities only once to the temporary list
01594       if (prevFile->Compare(obj)) {
01595          uniqueFileList->Add(obj);
01596          prevFile = obj;
01597       }
01598    }
01599 
01600    // Clear dataSet and add contents of uniqueFileList needed otherwise
01601    // THashList deletes the objects even when nodelete is set
01602    dataSet->GetList()->SetOwner(0);
01603    dataSet->GetList()->Clear("nodelete");
01604    dataSet->GetList()->SetOwner(1);
01605    dataSet->GetList()->AddAll(uniqueFileList);
01606    uniqueFileList->SetOwner(kFALSE);
01607    delete uniqueFileList;
01608 
01609    // Enforce certain settings
01610    Bool_t reset = kTRUE;
01611    if (opt.Contains("T", TString::kIgnoreCase)) {
01612       if (!TestBit(TDataSetManager::kTrustInfo)) {
01613          Warning("RegisterDataSet", "configured to not trust the information"
01614                                     " provided by users: ignoring request");
01615       } else {
01616          reset = kFALSE;
01617       }
01618    }
01619    if (reset) {
01620       dataSet->SetName(dsName);
01621       dataSet->ResetBitAll(TFileInfo::kStaged);
01622       dataSet->ResetBitAll(TFileInfo::kCorrupted);
01623       dataSet->RemoveMetaData();
01624    }
01625 
01626    // Verify the dataset if required
01627    if (opt.Contains("V", TString::kIgnoreCase)) {
01628       if (TestBit(TDataSetManager::kAllowVerify)) {
01629          // Reopen files and notify
01630          if (TDataSetManager::ScanDataSet(dataSet, 1, 0, 0, kTRUE ) < 0) {
01631             Error("RegisterDataSet", "problems verifying the dataset");
01632             return -1;
01633          }
01634       } else {
01635          Warning("RegisterDataSet", "user-driven verification not allowed: ignoring request");
01636       }
01637    }
01638 
01639    // Update accumulated information
01640    dataSet->Update(fAvgFileSize);
01641 
01642    if (TestBit(TDataSetManager::kCheckQuota)) {
01643       if (dataSet->GetTotalSize() <= 0) {
01644          Error("RegisterDataSet", "datasets without size information are not accepted:");
01645          if (fAvgFileSize < 0) {
01646             Error("RegisterDataSet", "you may want to define an average"
01647                                      " file size to get an estimated dataset size");
01648          }
01649          return -1;
01650       }
01651       // now check the quota
01652       UpdateUsedSpace();
01653       Long64_t used = GetGroupUsed(fGroup) + dataSet->GetTotalSize();
01654 
01655       Info("RegisterDataSet", "your group %s uses %.1f GB + %.1f GB for the new dataset; "
01656                               "the available quota is %.1f GB", fGroup.Data(),
01657                               (Float_t) GetGroupUsed(fGroup)    / 1073741824,
01658                               (Float_t) dataSet->GetTotalSize() / 1073741824,
01659                               (Float_t) GetGroupQuota(fGroup)   / 1073741824);
01660       if (used > GetGroupQuota(fGroup)) {
01661          Error("RegisterDataSet", "quota exceeded");
01662          return -1;
01663       }
01664    }
01665 
01666    Bool_t success = WriteDataSet(fGroup, fUser, dsName, dataSet);
01667    if (!success)
01668       Error("RegisterDataSet", "could not write dataset: %s", dsName.Data());
01669 
01670    // Done
01671    return ((success) ? 0 : -1);
01672 }
01673 //______________________________________________________________________________
01674 Int_t TDataSetManagerFile::ScanDataSet(const char *uri, UInt_t opt)
01675 {
01676    // Scans the dataset indicated by <uri> and returns the number of missing files.
01677    // Returns -1 if any failure occurs, >= 0 on success.
01678    // For more details, see documentation of
01679    // ScanDataSet(TFileCollection *dataset, const char *option)
01680 
01681    TString dsName, dsTree;
01682    if ((opt & kSetDefaultTree)) {
01683       if (TestBit(TDataSetManager::kAllowRegister)) {
01684          if (ParseUri(uri, 0, 0, &dsName, &dsTree, kTRUE)) {
01685             TFileCollection *dataset = GetDataSet(fGroup, fUser, dsName);
01686             if (!dataset) return -1;
01687             dataset->SetDefaultTreeName(dsTree.Data());
01688             Int_t rc = WriteDataSet(fGroup, fUser, dsName, dataset);
01689             delete dataset;
01690             return (rc == 0) ? -1 : 0;
01691          }
01692       }
01693    } else {
01694       if (TestBit(TDataSetManager::kAllowVerify)) {
01695          if (ParseUri(uri, 0, 0, &dsName, 0, kTRUE, kTRUE)) {
01696             if (!(dsName.Contains("*"))) {
01697                if (ScanDataSet(fGroup, fUser, dsName, opt) > 0)
01698                   return GetNDisapparedFiles();
01699             } else {
01700                TString luri = TString::Format("/%s/%s/%s", fGroup.Data(), fUser.Data(), dsName.Data());
01701                TMap *fcs = GetDataSets(luri, kList);
01702                if (!fcs) return -1;
01703                fcs->Print();
01704                Int_t ndisappeared = 0;
01705                TIter nxd(fcs);
01706                TObjString *d = 0;
01707                while ((d = (TObjString *) nxd())) {
01708                   if (!(d->GetString().IsNull())) {
01709                      TString dsn(d->GetName());
01710                      if (dsn.Contains("/")) dsn.Remove(0, dsn.Last('/') + 1);
01711                      if (ScanDataSet(fGroup, fUser, dsn, opt) > 0) {
01712                         ndisappeared += GetNDisapparedFiles();
01713                      } else {
01714                         Warning("ScanDataSet", "problems processing dataset: %s", d->GetName());
01715                      }
01716                   } else {
01717                      Warning("ScanDataSet", "empty string found in map while processing: %s", uri);
01718                   }
01719                }
01720                SafeDelete(fcs);
01721                return ndisappeared;
01722             }
01723          }
01724       }
01725    }
01726    return -1;
01727 }
01728 
01729 //______________________________________________________________________________
01730 Int_t TDataSetManagerFile::ScanDataSet(const char *group, const char *user,
01731                                        const char *dsName, UInt_t option)
01732 {
01733    // See documentation of ScanDataSet(TFileCollection *dataset, UInt_t option)
01734 
01735    if (!TestBit(TDataSetManager::kAllowVerify))
01736       return -1;
01737 
01738    TFileCollection *dataset = GetDataSet(group, user, dsName);
01739    if (!dataset)
01740       return -1;
01741 
01742    // File selection
01743    Int_t fopt = ((option & kAllFiles)) ? -1 : 0;
01744    if (fopt >= 0) {
01745       if ((option & kStagedFiles)) {
01746          fopt = 10;
01747       } else {
01748          if ((option & kReopen)) fopt++;
01749          if ((option & kTouch)) fopt++;
01750       }
01751       if ((option & kNoStagedCheck)) fopt += 100;
01752    } else {
01753       if ((option & kStagedFiles) || (option & kReopen) || (option & kTouch)) {
01754          Warning("ScanDataSet", "kAllFiles mode: ignoring kStagedFiles or kReopen"
01755                                 " or kTouch requests");
01756       }
01757       if ((option & kNoStagedCheck)) fopt -= 100;
01758    }
01759 
01760    // Type of action
01761    Int_t sopt = ((option & kNoAction)) ? -1 : 0;
01762    if (sopt >= 0) {
01763       if ((option & kLocateOnly) && (option & kStageOnly)) {
01764          Error("ScanDataSet", "kLocateOnly and kStageOnly cannot be processed concurrently");
01765          return -1;
01766       }
01767       if ((option & kLocateOnly)) sopt = 1;
01768       if ((option & kStageOnly)) sopt = 2;
01769    } else if ((option & kLocateOnly) || (option & kStageOnly)) {
01770       Warning("ScanDataSet", "kNoAction mode: ignoring kLocateOnly or kStageOnly requests");
01771    }
01772 
01773    Bool_t dbg = ((option & kDebug)) ? kTRUE : kFALSE;
01774    // Do the scan
01775    Int_t result = TDataSetManager::ScanDataSet(dataset, fopt, sopt, 0, dbg,
01776                                    &fNTouchedFiles, &fNOpenedFiles, &fNDisappearedFiles,
01777                                    (TList *)0, fAvgFileSize, fMSSUrl.Data(), -1, fStageOpts.Data());
01778    if (result == 2) {
01779       if (WriteDataSet(group, user, dsName, dataset) == 0) {
01780          delete dataset;
01781          return -2;
01782       }
01783    }
01784    delete dataset;
01785 
01786    return result;
01787 }
01788 
01789 //______________________________________________________________________________
01790 TMap *TDataSetManagerFile::GetDataSets(const char *uri, UInt_t option)
01791 {
01792    //
01793    // Returns all datasets for the <group> and <user> specified by <uri>.
01794    // If <user> is 0, it returns all datasets for the given <group>.
01795    // If <group> is 0, it returns all datasets.
01796    // The returned TMap contains:
01797    //    <group> --> <map of users> --> <map of datasets> --> <dataset> (TFileCollection)
01798    //
01799    // The unsigned int 'option' is forwarded to GetDataSet and BrowseDataSet.
01800    // Available options (to be .or.ed):
01801    //    kShowDefault    a default selection is shown that include the ones from
01802    //                    the current user, the ones from the group and the common ones
01803    //    kPrint          print the dataset content
01804    //    kQuotaUpdate    update quotas
01805    //    kExport         use export naming
01806    //
01807    // NB1: options "kPrint", "kQuoatUpdate" and "kExport" are mutually exclusive
01808    // NB2: for options "kPrint" and "kQuoatUpdate" return is null.
01809 
01810    TString dsUser, dsGroup, dsName;
01811 
01812    if (((option & kPrint) || (option & kExport)) && strlen(uri) <= 0)
01813       option |= kShowDefault;
01814 
01815    if (ParseUri(uri, &dsGroup, &dsUser, &dsName, 0, kFALSE, kTRUE))
01816       return GetDataSets(dsGroup, dsUser, dsName, option);
01817    return (TMap *)0;
01818 }
01819 
01820 //______________________________________________________________________________
01821 TFileCollection *TDataSetManagerFile::GetDataSet(const char *uri, const char *opts)
01822 {
01823    // Utility function used in various methods for user dataset upload.
01824 
01825    TString dsUser, dsGroup, dsName, ss(opts);
01826 
01827    TFileCollection *fc = 0;
01828    if (!strchr(uri, '*')) {
01829       if (!ParseUri(uri, &dsGroup, &dsUser, &dsName)) return fc;
01830       UInt_t opt = (ss.Contains("S:") || ss.Contains("short:")) ? kReadShort : 0;
01831       ss.ReplaceAll("S:","");
01832       ss.ReplaceAll("short:","");
01833       fc = GetDataSet(dsGroup, dsUser, dsName, opt);
01834    } else {
01835       TMap *fcs = GetDataSets(uri);
01836       if (!fcs) return fc;
01837       TIter nxd(fcs);
01838       TObject *k = 0;
01839       TFileCollection *xfc = 0;
01840       while ((k = nxd()) && (xfc = (TFileCollection *) fcs->GetValue(k))) {
01841          if (!fc) {
01842             // The first one
01843             fc = xfc;
01844             fcs->Remove(k);
01845          } else {
01846             // Add
01847             fc->Add(xfc);
01848          }
01849       }
01850    }
01851 
01852    if (fc && !ss.IsNull()) {
01853       // Build up the subset
01854       TFileCollection *sfc = 0;
01855       TString s;
01856       Int_t from = 0;
01857       while (ss.Tokenize(s, from, ",")) {
01858          TFileCollection *xfc = fc->GetFilesOnServer(s.Data());
01859          if (xfc) {
01860             if (sfc) {
01861                sfc->Add(xfc);
01862                delete xfc;
01863             } else {
01864                sfc = xfc;
01865             }
01866          }
01867       }
01868       // Cleanup
01869       delete fc;
01870       fc = sfc;
01871    }
01872    // Done
01873    return fc;
01874 }
01875 
01876 //______________________________________________________________________________
01877 Bool_t TDataSetManagerFile::RemoveDataSet(const char *uri)
01878 {
01879    // Removes the indicated dataset
01880 
01881    TString dsName;
01882 
01883    if (TestBit(TDataSetManager::kAllowRegister)) {
01884       if (ParseUri(uri, 0, 0, &dsName, 0, kTRUE)) {
01885          Bool_t rc = RemoveDataSet(fGroup, fUser, dsName);
01886          if (rc) return kTRUE;
01887          Error("RemoveDataSet", "error removing dataset %s", dsName.Data());
01888       }
01889    }
01890    return kFALSE;
01891 }
01892 
01893 //______________________________________________________________________________
01894 Bool_t TDataSetManagerFile::ExistsDataSet(const char *uri)
01895 {
01896    // Checks if the indicated dataset exits
01897 
01898    TString dsUser, dsGroup, dsName;
01899 
01900    if (ParseUri(uri, &dsGroup, &dsUser, &dsName))
01901       return ExistsDataSet(dsGroup, dsUser, dsName);
01902    return kFALSE;
01903 }
01904 
01905 //______________________________________________________________________________
01906 void TDataSetManagerFile::UpdateUsedSpace()
01907 {
01908    // updates the used space maps
01909 
01910    // Clear used space entries
01911    fGroupUsed.DeleteAll();
01912    fUserUsed.DeleteAll();
01913 
01914    // Scan the existing datasets
01915    GetDataSets(0, 0, 0, (UInt_t)kQuotaUpdate);
01916 }

Generated on Tue Jul 5 14:51:36 2011 for ROOT_528-00b_version by  doxygen 1.5.1