Back to index

nordugrid-arc-nox  1.1.0~rc6
DataPointLFC.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 #include <cstdlib>
00008 // NOTE: On Solaris errno is not working properly if cerrno is included first
00009 #include <cerrno>
00010 
00011 #include <sys/stat.h>
00012 #include <sys/types.h>
00013 #include <dirent.h>
00014 
00015 extern "C" {
00016 /* See http://goc.grid.sinica.edu.tw/gocwiki/UsingLiblfcWithThreads
00017  * for LFC threading info */
00018 
00019 /* use POSIX standard threads library */
00020 #include <pthread.h>
00021 extern int Cthread_init(); /* from <Cthread_api.h> */
00022 #define thread_t      pthread_t
00023 #define thread_create(tid_p, func, arg)  pthread_create(tid_p, NULL, func, arg)
00024 #define thread_join(tid)               pthread_join(tid, NULL)
00025 
00026 #include <lfc_api.h>
00027 
00028 #ifndef _THREAD_SAFE
00029 #define _THREAD_SAFE
00030 #endif
00031 #include <serrno.h>
00032 }
00033 
00034 #include <arc/GUID.h>
00035 #include <arc/Logger.h>
00036 #include <arc/StringConv.h>
00037 #include <arc/URL.h>
00038 #include <arc/Utils.h>
00039 
00040 #include "DataPointLFC.h"
00041 
00042 namespace Arc {
00043 
00044   Logger DataPointLFC::logger(DataPoint::logger, "LFC");
00045 
00046   DataPointLFC::DataPointLFC(const URL& url, const UserConfig& usercfg)
00047     : DataPointIndex(url, usercfg),
00048       guid("") {
00049     // set retry env variables (don't overwrite if set already)
00050     // connection timeout
00051     SetEnv("LFC_CONNTIMEOUT", "30", false);
00052     // number of retries
00053     SetEnv("LFC_CONRETRY", "1", false);
00054     // interval between retries
00055     SetEnv("LFC_CONRETRYINT", "10", false);
00056 
00057     // set host name env var
00058     SetEnv("LFC_HOST", url.Host());
00059   }
00060 
00061   DataPointLFC::~DataPointLFC() {}
00062 
00063   Plugin* DataPointLFC::Instance(PluginArgument *arg) {
00064     DataPointPluginArgument *dmcarg =
00065       dynamic_cast<DataPointPluginArgument*>(arg);
00066     if (!dmcarg)
00067       return NULL;
00068     if (((const URL&)(*dmcarg)).Protocol() != "lfc")
00069       return NULL;
00070     // Make this code non-unloadable because Globus
00071     // may have problems with unloading
00072     Glib::Module* module = dmcarg->get_module();
00073     PluginsFactory* factory = dmcarg->get_factory();
00074     if(factory && module) factory->makePersistent(module);
00075     return new DataPointLFC(*dmcarg, *dmcarg);
00076   }
00077 
00078   /* perform resolve operation, which can take long time */
00079   DataStatus DataPointLFC::Resolve(bool source) {
00080 
00081 #ifndef WITH_CTHREAD
00082     /* Initialize Cthread library - should be called before any LFC-API function */
00083     if (0 != Cthread_init()) {
00084       logger.msg(ERROR, "Cthread_init() error: %s", sstrerror(serrno));
00085       return DataStatus::SystemError;
00086     }
00087 #endif
00088 
00089     if (lfc_startsess(const_cast<char*>(url.Host().c_str()),
00090                       const_cast<char*>("ARC")) != 0) {
00091       logger.msg(ERROR, "Error starting session: %s", sstrerror(serrno));
00092       lfc_endsess();
00093       if (serrno == SECOMERR || serrno == ENSNACT || serrno == SETIMEDOUT)
00094         return source ? DataStatus::ReadResolveErrorRetryable : DataStatus::WriteResolveErrorRetryable;
00095       return source ? DataStatus::ReadResolveError : DataStatus::WriteResolveError;
00096     }
00097 
00098     std::string path;
00099 
00100     if (source) {
00101       path = ResolveGUIDToLFN();
00102       if (path.empty()) {
00103         lfc_endsess();
00104         return DataStatus::ReadResolveError;
00105       }
00106     }
00107     else
00108       path = url.Path();
00109 
00110     if (!source && !url.MetaDataOption("guid").empty()) {
00111       guid = url.MetaDataOption("guid");
00112       logger.msg(VERBOSE, "Using supplied guid %s", guid);
00113     }
00114 
00115     resolved = false;
00116     registered = false;
00117     if (source) {
00118       if (path.empty()) {
00119         logger.msg(ERROR, "Source must contain LFN");
00120         lfc_endsess();
00121         return DataStatus::ReadResolveError;
00122       }
00123     }
00124     else {
00125       if (path.empty()) {
00126         logger.msg(ERROR, "Destination must contain LFN");
00127         lfc_endsess();
00128         return DataStatus::WriteResolveError;
00129       }
00130       if (url.Locations().size() == 0) {
00131         logger.msg(ERROR, "Locations are missing in destination LFC URL");
00132         lfc_endsess();
00133         return DataStatus::WriteResolveError;
00134       }
00135     }
00136     int nbentries = 0;
00137     struct lfc_filereplica *entries = NULL;
00138     if (lfc_getreplica(path.c_str(), NULL, NULL, &nbentries, &entries) != 0) {
00139       if (source || ((serrno != ENOENT) && (serrno != ENOTDIR))) {
00140         logger.msg(ERROR, "Error finding replicas: %s", sstrerror(serrno));
00141         lfc_endsess();
00142         return source ? DataStatus::ReadResolveError : DataStatus::WriteResolveError;
00143       }
00144       nbentries = 0;
00145       entries = NULL;
00146     }
00147     else
00148       registered = true;
00149 
00150     if (source) { // add locations resolved above
00151       for (int n = 0; n < nbentries; n++) {
00152         URL uloc(entries[n].sfn);
00153         for (std::map<std::string, std::string>::const_iterator i = url.CommonLocOptions().begin();
00154              i != url.CommonLocOptions().end(); i++)
00155           uloc.AddOption(i->first, i->second, false);
00156         if (AddLocation(uloc, url.ConnectionURL()) == DataStatus::LocationAlreadyExistsError)
00157           logger.msg(WARNING, "Duplicate replica found in LFC: %s", uloc.str());
00158         else
00159           logger.msg(VERBOSE, "Adding location: %s - %s", url.ConnectionURL(), entries[n].sfn);
00160       }
00161     }
00162     else { // add given locations, checking they don't already exist
00163       for (std::list<URLLocation>::const_iterator loc = url.Locations().begin(); loc != url.Locations().end(); ++loc) {
00164         for (int n = 0; n < nbentries; n++) {
00165           if (std::string(entries[n].sfn) == loc->Name()) {
00166             logger.msg(ERROR, "Replica %s already exists for LFN %s", entries[n].sfn, url.str());
00167             return DataStatus::WriteResolveError;
00168           }
00169         }
00170         // Make pfn from loc + last part of LFN 
00171         std::string pfn = loc->fullstr();
00172         if (pfn.find_last_of("/") != pfn.length() - 1)
00173           pfn += "/"; 
00174         // take off leading dirs of LFN
00175         std::string::size_type slash_index = path.rfind("/", path.length() + 1);
00176         if (slash_index != std::string::npos)
00177           pfn += path.substr(slash_index + 1);
00178         else
00179           pfn += path;
00180         URL uloc(pfn);
00181         for (std::map<std::string, std::string>::const_iterator i = url.CommonLocOptions().begin();
00182              i != url.CommonLocOptions().end(); i++)
00183           uloc.AddOption(i->first, i->second, false);
00184         if (AddLocation(uloc, url.ConnectionURL()) == DataStatus::LocationAlreadyExistsError)
00185           logger.msg(WARNING, "Duplicate replica location: %s", uloc.str());
00186         else
00187           logger.msg(VERBOSE, "Adding location: %s - %s", url.ConnectionURL(), uloc.str());
00188       }
00189     }
00190     if (entries)
00191       free(entries);
00192 
00193     struct lfc_filestatg st;
00194     if (lfc_statg(path.c_str(), NULL, &st) == 0) {
00195       if (st.filemode & S_IFDIR) { // directory
00196         lfc_endsess();
00197         return DataStatus::Success;
00198       }
00199       registered = true;
00200       SetSize(st.filesize);
00201       SetCreated(st.mtime);
00202       if (st.csumtype[0] && st.csumvalue[0]) {
00203         std::string csum = st.csumtype;
00204         if (csum == "MD")
00205           csum = "md5";
00206         else if (csum == "AD") 
00207           csum = "adler32";
00208         csum += ":";
00209         csum += st.csumvalue;
00210         SetCheckSum(csum);
00211       }
00212       guid = st.guid;
00213     }
00214     lfc_endsess();
00215     if (!HaveLocations()) {
00216       logger.msg(ERROR, "No locations found for %s", url.str());
00217       return source ? DataStatus::ReadResolveError : DataStatus::WriteResolveError;
00218     }
00219     if (CheckCheckSum()) logger.msg(VERBOSE, "meta_get_data: checksum: %s", GetCheckSum());
00220     if (CheckSize()) logger.msg(VERBOSE, "meta_get_data: size: %llu", GetSize());
00221     if (CheckCreated()) logger.msg(VERBOSE, "meta_get_data: created: %s", GetCreated().str());
00222 
00223     resolved = true;
00224     return DataStatus::Success;
00225   }
00226 
00227   DataStatus DataPointLFC::PreRegister(bool replication, bool force) {
00228 
00229 #ifndef WITH_CTHREAD
00230     /* Initialize Cthread library - should be called before any LFC-API function */
00231     if (0 != Cthread_init()) {
00232       logger.msg(ERROR, "Cthread_init() error: %s", sstrerror(serrno));
00233       return DataStatus::SystemError;
00234     }
00235 #endif
00236 
00237     if (replication) { /* replicating inside same lfn */
00238       if (!registered) {
00239         logger.msg(ERROR, "LFN is missing in LFC (needed for replication)");
00240         return DataStatus::PreRegisterError;
00241       }
00242       return DataStatus::Success;
00243     }
00244     if (registered) {
00245       if (!force) {
00246         logger.msg(ERROR, "LFN already exists in LFC");
00247         return DataStatus::PreRegisterError;
00248       }
00249       return DataStatus::Success;
00250     }
00251     if (lfc_startsess(const_cast<char*>(url.Host().c_str()),
00252                       const_cast<char*>("ARC")) != 0) {
00253       logger.msg(ERROR, "Error starting session: %s", sstrerror(serrno));
00254       if (serrno == SECOMERR || serrno == ENSNACT || serrno == SETIMEDOUT)
00255         return DataStatus::PreRegisterErrorRetryable;      
00256       return DataStatus::PreRegisterError;
00257     }
00258     if (guid.empty())
00259       guid = UUID();
00260     else if (!url.MetaDataOption("guid").empty()) {
00261       guid = url.MetaDataOption("guid");
00262       logger.msg(VERBOSE, "Using supplied guid %s", guid);
00263     }
00264     if (lfc_creatg(url.Path().c_str(), guid.c_str(),
00265                    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 0) {
00266 
00267       // check error - if it is no such file or directory, try to create the
00268       // required dirs
00269       if (serrno == ENOENT) {
00270         std::string::size_type slashpos = url.Path().find("/", 1); // don't create root dir
00271         while (slashpos != std::string::npos) {
00272           std::string dirname = url.Path().substr(0, slashpos);
00273           // list dir to see if it exists
00274           struct lfc_filestat statbuf;
00275           if (lfc_stat(dirname.c_str(), &statbuf) == 0) {
00276             slashpos = url.Path().find("/", slashpos + 1);
00277             continue;
00278           }
00279 
00280           logger.msg(VERBOSE, "Creating LFC directory %s", dirname);
00281           if (lfc_mkdir(dirname.c_str(), 0775) != 0)
00282             if (serrno != EEXIST) {
00283               logger.msg(ERROR, "Error creating required LFC dirs: %s", sstrerror(serrno));
00284               lfc_endsess();
00285               return DataStatus::PreRegisterError;
00286             }
00287           slashpos = url.Path().find("/", slashpos + 1);
00288         }
00289         if (lfc_creatg(url.Path().c_str(), guid.c_str(),
00290                        S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 0 && serrno != EEXIST) {
00291           logger.msg(ERROR, "Error creating LFC entry: %s", sstrerror(serrno));
00292           lfc_endsess();
00293           return DataStatus::PreRegisterError;
00294         }
00295       }
00296       // LFN may already exist, caused by 2 uploaders simultaneously uploading to the same LFN
00297       // ignore the error if force is true and get the previously registered guid 
00298       else if (serrno == EEXIST && force) {
00299         struct lfc_filestatg st;
00300         if (lfc_statg(url.Path().c_str(), NULL, &st) == 0) {
00301           registered = true;
00302           guid = st.guid;
00303           lfc_endsess();
00304           return DataStatus::Success;
00305         }
00306         else {
00307           logger.msg(ERROR, "Error finding info on LFC entry %s which should exist: %s", url.Path(), sstrerror(serrno));
00308           lfc_endsess();
00309           return DataStatus::PreRegisterError;
00310         }
00311       }
00312       else {
00313         logger.msg(ERROR, "Error creating LFC entry %s, guid %s: %s", url.Path(), guid, sstrerror(serrno));
00314         lfc_endsess();
00315         return DataStatus::PreRegisterError;
00316       }
00317     }
00318     if (CheckCheckSum()) {
00319       std::string ckstype;
00320       std::string cksumvalue = GetCheckSum();
00321       std::string::size_type p = cksumvalue.find(':');
00322       if (p == std::string::npos)
00323         ckstype = "cksum";
00324       else {
00325         ckstype = cksumvalue.substr(0, p);
00326         cksumvalue = cksumvalue.substr(p + 1);
00327       }
00328       if (CheckSize()) {
00329         if (lfc_setfsizeg(guid.c_str(), GetSize(), ckstype.c_str(), const_cast<char*>(cksumvalue.c_str())) != 0)
00330           logger.msg(ERROR, "Error entering metadata: %s", sstrerror(serrno));
00331       }
00332       else if (lfc_setfsizeg(guid.c_str(), 0, ckstype.c_str(), const_cast<char*>(cksumvalue.c_str())) != 0)
00333           logger.msg(ERROR, "Error entering metadata: %s", sstrerror(serrno));
00334     }
00335     else if (CheckSize())
00336       if (lfc_setfsizeg(guid.c_str(), GetSize(), NULL, NULL) != 0)
00337         logger.msg(ERROR, "Error entering metadata: %s", sstrerror(serrno));
00338 
00339     lfc_endsess();
00340     return DataStatus::Success;
00341   }
00342 
00343   DataStatus DataPointLFC::PostRegister(bool replication) {
00344 
00345 #ifndef WITH_CTHREAD
00346     /* Initialize Cthread library - should be called before any LFC-API function */
00347     if (0 != Cthread_init()) {
00348       logger.msg(ERROR, "Cthread_init() error: %s", sstrerror(serrno));
00349       return DataStatus::SystemError;
00350     }
00351 #endif
00352 
00353     if (guid.empty()) {
00354       logger.msg(ERROR, "No GUID defined for LFN - probably not preregistered");
00355       return DataStatus::PostRegisterError;
00356     }
00357     std::string pfn(CurrentLocation().str());
00358     if (lfc_startsess(const_cast<char*>(url.Host().c_str()), const_cast<char*>("ARC")) != 0) {
00359       logger.msg(ERROR, "Error starting session: %s", sstrerror(serrno));
00360       if (serrno == SECOMERR || serrno == ENSNACT || serrno == SETIMEDOUT)
00361         return DataStatus::PostRegisterErrorRetryable;
00362       return DataStatus::PostRegisterError;
00363     }
00364     if (lfc_addreplica(guid.c_str(), NULL, CurrentLocation().Host().c_str(), CurrentLocation().str().c_str(), '-', 'P', NULL, NULL) != 0) {
00365       logger.msg(ERROR, "Error adding replica: %s", sstrerror(serrno));
00366       lfc_endsess();
00367       return DataStatus::PostRegisterError;
00368     }
00369     if (CheckCheckSum()) {
00370       std::string ckstype;
00371       std::string cksumvalue = GetCheckSum();
00372       std::string::size_type p = cksumvalue.find(':');
00373       if (p == std::string::npos)
00374         ckstype = "cksum";
00375       else {
00376         ckstype = cksumvalue.substr(0, p);
00377         if (ckstype == "md5")
00378           ckstype = "MD";
00379         if (ckstype == "adler32")
00380           ckstype = "AD";
00381         cksumvalue = cksumvalue.substr(p + 1);
00382         logger.msg(VERBOSE, "Entering checksum type %s, value %s, file size %llu", ckstype, cksumvalue, GetSize());
00383       }
00384       if (CheckSize()) {
00385         if (lfc_setfsizeg(guid.c_str(), GetSize(), ckstype.c_str(), const_cast<char*>(cksumvalue.c_str())) != 0)
00386           logger.msg(ERROR, "Error entering metadata: %s", sstrerror(serrno));
00387       }
00388       else if (lfc_setfsizeg(guid.c_str(), 0, ckstype.c_str(), const_cast<char*>(cksumvalue.c_str())) != 0)
00389         logger.msg(ERROR, "Error entering metadata: %s", sstrerror(serrno));
00390     }
00391     else if (CheckSize())
00392       if (lfc_setfsizeg(guid.c_str(), GetSize(), NULL, NULL) != 0)
00393         logger.msg(ERROR, "Error entering metadata: %s", sstrerror(serrno));
00394 
00395     lfc_endsess();
00396     return DataStatus::Success;
00397   }
00398 
00399   DataStatus DataPointLFC::PreUnregister(bool replication) {
00400 
00401 #ifndef WITH_CTHREAD
00402     /* Initialize Cthread library - should be called before any LFC-API function */
00403     if (0 != Cthread_init()) {
00404       logger.msg(ERROR, "Cthread_init() error: %s", sstrerror(serrno));
00405       return DataStatus::SystemError;
00406     }
00407 #endif
00408 
00409     if (replication)
00410       return DataStatus::Success;
00411     if (lfc_startsess(const_cast<char*>(url.Host().c_str()),
00412                       const_cast<char*>("ARC")) != 0) {
00413       logger.msg(ERROR, "Error starting session: %s", sstrerror(serrno));
00414       if (serrno == SECOMERR || serrno == ENSNACT || serrno == SETIMEDOUT)
00415         return DataStatus::UnregisterErrorRetryable;
00416       return DataStatus::UnregisterError;
00417     }
00418     std::string path = ResolveGUIDToLFN();
00419     if (path.empty()) {
00420       lfc_endsess();
00421       return DataStatus::UnregisterError;
00422     }
00423     if (lfc_unlink(path.c_str()) != 0)
00424       if ((serrno != ENOENT) && (serrno != ENOTDIR)) {
00425         logger.msg(ERROR, "Failed to remove LFN in LFC - You may need to do it by hand");
00426         lfc_endsess();
00427         return DataStatus::UnregisterError;
00428       }
00429     lfc_endsess();
00430     return DataStatus::Success;
00431   }
00432 
00433   DataStatus DataPointLFC::Unregister(bool all) {
00434 
00435 #ifndef WITH_CTHREAD
00436     /* Initialize Cthread library - should be called before any LFC-API function */
00437     if (0 != Cthread_init()) {
00438       logger.msg(ERROR, "Cthread_init() error: %s", sstrerror(serrno));
00439       return DataStatus::SystemError;
00440     }
00441 #endif
00442 
00443     if (!all && (!LocationValid())) {
00444       logger.msg(ERROR, "Location is missing");
00445       return DataStatus::UnregisterError;
00446     }
00447     if (lfc_startsess(const_cast<char*>(url.Host().c_str()),
00448                       const_cast<char*>("ARC")) != 0) {
00449       logger.msg(ERROR, "Error starting session: %s", sstrerror(serrno));
00450       if (serrno == SECOMERR || serrno == ENSNACT || serrno == SETIMEDOUT)
00451         return DataStatus::UnregisterErrorRetryable;
00452       return DataStatus::UnregisterError;
00453     }
00454     std::string path = ResolveGUIDToLFN();
00455     if (path.empty()) {
00456       lfc_endsess();
00457       return DataStatus::UnregisterError;
00458     }
00459     if (all) {
00460       int nbentries = 0;
00461       struct lfc_filereplica *entries = NULL;
00462       if (lfc_getreplica(path.c_str(), NULL, NULL, &nbentries, &entries) != 0) {
00463         lfc_endsess();
00464         if (serrno == ENOTDIR) {
00465           registered = false;
00466           ClearLocations();
00467           return DataStatus::Success;
00468         }
00469         logger.msg(ERROR, "Error getting replicas: %s", sstrerror(serrno));
00470         return DataStatus::UnregisterError;
00471       }
00472       for (int n = 0; n < nbentries; n++)
00473         if (lfc_delreplica(guid.c_str(), NULL, entries[n].sfn) != 0) {
00474           if (serrno == ENOENT)
00475             continue;
00476           lfc_endsess();
00477           logger.msg(ERROR, "Failed to remove location from LFC");
00478           return DataStatus::UnregisterError;
00479         }
00480       if (lfc_unlink(path.c_str()) != 0) {
00481         if (serrno == EPERM) { // we have a directory
00482           if (lfc_rmdir(path.c_str()) != 0) {
00483             if (serrno == EEXIST) { // still files in the directory
00484               logger.msg(ERROR, "Failed to remove LFC directory: directory is not empty");
00485               lfc_endsess();
00486               return DataStatus::UnregisterError;
00487             }
00488             logger.msg(ERROR, "Failed to remove LFC directory: %s", sstrerror(serrno));
00489             lfc_endsess();
00490             return DataStatus::UnregisterError;
00491           }
00492         }
00493         else if ((serrno != ENOENT) && (serrno != ENOTDIR)) {
00494           logger.msg(ERROR, "Failed to remove LFN in LFC: %s", sstrerror(serrno));
00495           lfc_endsess();
00496           return DataStatus::UnregisterError;
00497         }
00498       }
00499       registered = false;
00500     }
00501     else if (lfc_delreplica(guid.c_str(), NULL, CurrentLocation().str().c_str()) != 0) {
00502       lfc_endsess();
00503       logger.msg(ERROR, "Failed to remove location from LFC: %s", sstrerror(serrno));
00504       return DataStatus::UnregisterError;
00505     }
00506     lfc_endsess();
00507     return DataStatus::Success;
00508   }
00509 
00510 
00511   DataStatus DataPointLFC::ListFiles(std::list<FileInfo>& files,
00512                                      bool long_list,
00513                                      bool resolve,
00514                                      bool metadata) {
00515 
00516 #ifndef WITH_CTHREAD
00517     /* Initialize Cthread library - should be called before any LFC-API function */
00518     if (0 != Cthread_init()) {
00519       logger.msg(ERROR, "Cthread_init() error: %s", sstrerror(serrno));
00520       return DataStatus::SystemError;
00521     }
00522 #endif
00523 
00524     if (lfc_startsess(const_cast<char*>(url.Host().c_str()),
00525                       const_cast<char*>("ARC")) != 0) {
00526       logger.msg(ERROR, "Error starting session: %s", sstrerror(serrno));
00527       if (serrno == SECOMERR || serrno == ENSNACT || serrno == SETIMEDOUT)
00528         return DataStatus::ListErrorRetryable;
00529       return DataStatus::ListError;
00530     }
00531     std::string path = ResolveGUIDToLFN();
00532     if (path.empty()) {
00533       lfc_endsess();
00534       return DataStatus::ListError;
00535     }
00536     // first stat the url and see if it is a file or directory
00537     struct lfc_filestatg st;
00538 
00539     if (lfc_statg(path.c_str(), NULL, &st) != 0) {
00540       logger.msg(ERROR, "Error listing file or directory: %s", sstrerror(serrno));
00541       lfc_endsess();
00542       return DataStatus::ListError;
00543     }
00544 
00545     // if it's a directory, list entries
00546     if (st.filemode & S_IFDIR && !metadata) {
00547       lfc_DIR *dir = lfc_opendirxg(const_cast<char*>(url.Host().c_str()), path.c_str(), NULL);
00548       if (dir == NULL) {
00549         logger.msg(ERROR, "Error opening directory: %s", sstrerror(serrno));
00550         lfc_endsess();
00551         return DataStatus::ListError;
00552       }
00553 
00554       // list entries. If not long list use readdir
00555       // does funny things with pointers, so always use long listing for now
00556       if (false) { // if (!long_list) {
00557         struct dirent *direntry;
00558         while ((direntry = lfc_readdir(dir)))
00559           std::list<FileInfo>::iterator f = files.insert(files.end(), FileInfo(direntry->d_name));
00560       }
00561       else { // for long list use readdirg
00562         struct lfc_direnstatg *direntry;
00563         while ((direntry = lfc_readdirg(dir))) {
00564           std::list<FileInfo>::iterator f = files.insert(files.end(), FileInfo(direntry->d_name));
00565 
00566           f->SetSize(direntry->filesize);
00567           if (strcmp(direntry->csumtype, "") != 0 && strcmp(direntry->csumvalue, "") != 0) {
00568             std::string csum = direntry->csumtype;
00569             csum += ":";
00570             csum += direntry->csumvalue;
00571             f->SetCheckSum(csum);
00572           }
00573           f->SetCreated(direntry->ctime);
00574           f->SetType((direntry->filemode & S_IFDIR) ? FileInfo::file_type_dir : FileInfo::file_type_file);
00575         }
00576       }
00577       if (serrno) {
00578         logger.msg(ERROR, "Error listing directory: %s", sstrerror(serrno));
00579         lfc_closedir(dir);
00580         lfc_endsess();
00581         return DataStatus::ListError;
00582       }
00583 
00584       // if we want to resolve replicas call readdirxr
00585       if (resolve) {
00586         lfc_rewinddir(dir);
00587         struct lfc_direnrep *direntry;
00588 
00589         while ((direntry = lfc_readdirxr(dir, NULL)))
00590           for (std::list<FileInfo>::iterator f = files.begin();
00591                f != files.end();
00592                f++)
00593             if (f->GetName() == direntry->d_name) {
00594               for (int n = 0; n < direntry->nbreplicas; n++)
00595                 f->AddURL(URL(std::string(direntry->rep[n].sfn)));
00596               break;
00597             }
00598         if (serrno) {
00599           logger.msg(ERROR, "Error listing directory: %s", sstrerror(serrno));
00600           lfc_closedir(dir);
00601           lfc_endsess();
00602           return DataStatus::ListError;
00603         }
00604       }
00605       lfc_closedir(dir);
00606     } // if (dir)
00607     else {
00608       std::list<FileInfo>::iterator f = files.insert(files.end(), FileInfo(path.c_str()));
00609       f->SetMetaData("path", path);
00610       f->SetSize(st.filesize);
00611       f->SetMetaData("size", tostring(st.filesize));
00612       if (st.csumvalue[0]) {
00613         std::string csum = st.csumtype;
00614         csum += ":";
00615         csum += st.csumvalue;
00616         f->SetCheckSum(csum);
00617         f->SetMetaData("checksum", csum);
00618       }
00619       f->SetCreated(st.mtime);
00620       f->SetMetaData("mtime", f->GetCreated().str());
00621       f->SetType((st.filemode & S_IFDIR) ? FileInfo::file_type_dir : FileInfo::file_type_file);
00622       f->SetMetaData("type", (st.filemode & S_IFDIR) ? "dir" : "file");
00623       if (resolve) {
00624         int nbentries = 0;
00625         struct lfc_filereplica *entries = NULL;
00626 
00627         if (lfc_getreplica(path.c_str(), NULL, NULL, &nbentries, &entries) != 0) {
00628           logger.msg(ERROR, "Error listing replicas: %s", sstrerror(serrno));
00629           lfc_endsess();
00630           return DataStatus::ListError;
00631         }
00632         for (int n = 0; n < nbentries; n++)
00633           f->AddURL(URL(std::string(entries[n].sfn)));
00634       }
00635       // fill some more metadata
00636       if (st.guid[0] != '\0') f->SetMetaData("guid", std::string(st.guid));
00637       if(metadata) {
00638         char username[256];
00639         if (lfc_getusrbyuid(st.uid, username) == 0) f->SetMetaData("owner", username);
00640         char groupname[256];
00641         if (lfc_getgrpbygid(st.gid, groupname) == 0) f->SetMetaData("group", groupname);
00642       };
00643       mode_t mode = st.filemode;
00644       std::string perms;
00645       if (mode & S_IRUSR) perms += 'r'; else perms += '-';
00646       if (mode & S_IWUSR) perms += 'w'; else perms += '-';
00647       if (mode & S_IXUSR) perms += 'x'; else perms += '-';
00648       if (mode & S_IRGRP) perms += 'r'; else perms += '-';
00649       if (mode & S_IWGRP) perms += 'w'; else perms += '-';
00650       if (mode & S_IXGRP) perms += 'x'; else perms += '-';
00651       if (mode & S_IROTH) perms += 'r'; else perms += '-';
00652       if (mode & S_IWOTH) perms += 'w'; else perms += '-';
00653       if (mode & S_IXOTH) perms += 'x'; else perms += '-';
00654       f->SetMetaData("accessperm", perms);
00655       f->SetMetaData("ctime", (Time(st.ctime)).str());
00656       f->SetMetaData("atime", (Time(st.atime)).str());
00657     }
00658     lfc_endsess();
00659     return DataStatus::Success;
00660   }
00661 
00662   std::string DataPointLFC::ResolveGUIDToLFN() {
00663 
00664     // check if guid is already defined
00665     if (!guid.empty())
00666       return url.Path();
00667 
00668     // check for guid in the attributes
00669     if (url.MetaDataOption("guid").empty())
00670       return url.Path();
00671 
00672     guid = url.MetaDataOption("guid");
00673 
00674     lfc_list listp;
00675     struct lfc_linkinfo *info = lfc_listlinks(NULL, (char*)guid.c_str(),
00676                                               CNS_LIST_BEGIN, &listp);
00677     if (!info) {
00678       logger.msg(ERROR, "Error finding LFN from guid %s: %s",
00679                  guid, sstrerror(serrno));
00680       return "";
00681     }
00682 
00683     logger.msg(VERBOSE, "guid %s resolved to LFN %s", guid, info[0].path);
00684     std::string path = info[0].path;
00685     lfc_listlinks(NULL, (char*)guid.c_str(), CNS_LIST_END, &listp);
00686     return path;
00687   }
00688 
00689   const std::string DataPointLFC::DefaultCheckSum() const {
00690     return std::string("adler32");
00691   }
00692 
00693 } // namespace Arc
00694 
00695 Arc::PluginDescriptor PLUGINS_TABLE_NAME[] = {
00696   { "lfc", "HED:DMC", 0, &Arc::DataPointLFC::Instance },
00697   { NULL, NULL, 0, NULL }
00698 };