Implement extendedStatByRFN(), accessReplica(), and getReplicaByRFN().
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Sun, 8 Dec 2013 22:59:55 +0000 (23:59 +0100)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Sun, 23 Feb 2014 13:16:21 +0000 (14:16 +0100)
src/VfsNs.cpp
src/VfsNs.h

index 73cca7a..e6f5d81 100644 (file)
@@ -401,6 +401,77 @@ ExtendedStat VfsCatalog::extendedStat(const std::string& path, bool follow) thro
 
 
 
+std::string VfsCatalog::vfsPathByRFN(const std::string& rfn) throw (DmException)
+{
+  std::string curdir, path;
+  struct stat entry;
+  FILE *f;
+
+  curdir = rfn2path(rfn);
+  if (curdir.empty())
+    vfsThrow(EINVAL, "server or path required in replica file name");
+
+  if (vfsCheckPermissions("", S_IREAD))
+    vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
+
+  // read the catalog path
+  curdir = this->prefix_ + "/" + VFS_REPLICAS_TREE + curdir;
+  try {
+    wrapCall(stat(curdir.c_str(), &entry), "could not stat replica entry '%s'", rfn.c_str());
+    if (!S_ISREG(entry.st_mode))
+      vfsThrow(DMLITE_NO_SUCH_REPLICA, "replica entry '%s' is not valid", rfn.c_str());
+    if ((f = fopen(curdir.c_str(), "r")) == NULL)
+      vfsThrowErrno("could not open replica entry '%s'", rfn.c_str());
+  } catch (DmException e) {
+    if (e.code() == ENOTDIR || e.code() == ENOENT)
+      vfsThrow(DMLITE_NO_SUCH_REPLICA, "replica entry '%s' not found", rfn.c_str());
+    throw;
+  }
+  try {
+    fgets(this->buffer, sizeof this->buffer, f);
+    wrapCall(ferror(f), "error reading replica entry '%s'", rfn.c_str());
+  } catch (DmException e) {
+    fclose(f);
+    throw;
+  }
+  wrapCall(fclose(f), "could not close replica entry '%s'", rfn.c_str());
+
+  path = this->buffer;
+
+  return path;
+}
+
+
+
+ExtendedStat VfsCatalog::extendedStatByRFN(const std::string& rfn) throw (DmException)
+{
+  ExtendedStat meta;
+  std::string path;
+  Extensible xattrs;
+
+  path = vfsPathByRFN(rfn);
+  meta = vfsExtendedStat(path, true, false, false);
+
+  //
+  // User extended attributes are not supported on symlinks. We need the same
+  // owner, permissions and other atributes like the original file anyway.
+  // ==> always follow the symlinks.
+  //
+  try {
+    xattrs = vfsGetXattrs(path, getLocalPath(path), true, VFS_XATTR_TYPE_ALL);
+  } catch (DmException& e) {
+    // ignore - default owner and no ACLs
+  }
+  // use the retrieved xattrs
+  vfsUpdateExtendedStat(meta, xattrs);
+
+  vfsUpdateInode(meta, path);
+
+  return meta;
+}
+
+
+
 bool VfsCatalog::access(const std::string& path, int mode) throw (DmException)
 {
   ExtendedStat meta;
@@ -447,8 +518,10 @@ bool VfsCatalog::access(const std::string& path, int mode) throw (DmException)
 
 bool VfsCatalog::accessReplica(const std::string& replica, int mode) throw (DmException)
 {
-  vfsThrow(ENOSYS, "searching by replica file names not supported");
-  return false;
+  std::string path;
+
+  path = vfsPathByRFN(replica);
+  return this->access(path, mode);
 }
 
 
@@ -1426,25 +1499,42 @@ void VfsCatalog::removeDir(const std::string& path) throw (DmException)
 
 Replica VfsCatalog::getReplicaByRFN(const std::string& rfn) throw (DmException)
 {
+  std::string path;
+  ExtendedStat meta;
   Replica replica;
-  struct stat fstat;
-  
-  if (vfsCheckPermissions(rfn, S_IREAD))
-    vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
+  Extensible::const_iterator it;
 
-  wrapCall(stat(getLocalPath(rfn).c_str(), &fstat));
-  
-  replica.atime      = fstat.st_atime;
-  replica.fileid     = fstat.st_ino;
-  replica.ltime      = 0;
-  replica.nbaccesses = 0;
-  replica.ptime      = 0;
-  replica.replicaid  = 0;
-  replica.rfn        = rfn;
-  replica.server     = this->hostName_;
-  replica.status     = Replica::kAvailable;
-  replica.type       = Replica::kPermanent;
+  path = vfsPathByRFN(rfn);
+  meta = vfsExtendedStat(path, true, false, true);
+
+  vfsUpdateInode(meta, path);
+
+  // look for rfn in replicas
+  for (it = meta.begin(); it != meta.end(); it++) {
+    std::string key, value, value2, repidstr;
+
+    key = it->first;
+    if (key.compare(0, VFS_XATTR_LENGTH + 8, VFS_XATTR "replica.") == 0) {
+      repidstr = key.c_str() + VFS_XATTR_LENGTH + 8;
+      value = Extensible::anyToString(it->second);
+      value2 = meta.getString(VFS_XATTR "repattrs." + repidstr, "");
+
+      replica = replicaDeserialize(value, value2);
+      replica.replicaid = atoll(repidstr.c_str());
+      replica.fileid = meta.stat.st_ino;
   
+      if (rfn.compare(replica.rfn) == 0) break;
+    }
+  }
+
+  if (it == meta.end()) {
+    //
+    // Internal Inconsistency:
+    // Replica entry found but detailed info is missing in attributes.
+    //
+    vfsThrow(DMLITE_NO_SUCH_REPLICA, "replica entry '%s' found in '%s', but detailed info missing", rfn.c_str(), path.c_str());
+  }
+
   return replica;
 }
         
index 7338211..1cef2a6 100644 (file)
@@ -49,6 +49,7 @@ namespace dmlite {
     std::string getWorkingDir (void)               throw (DmException);
 
     ExtendedStat extendedStat(const std::string&, bool = true) throw (DmException);
+    ExtendedStat extendedStatByRFN(const std::string& rfn) throw (DmException);
     bool access(const std::string& path, int mode) throw (DmException);
     bool accessReplica(const std::string& replica, int mode) throw (DmException);
 
@@ -110,6 +111,7 @@ namespace dmlite {
     void vfsUpdateExtendedStat(ExtendedStat &xStat, Extensible xattrs) throw (DmException);
     ExtendedStat vfsSimpleStat(const std::string& name, const std::string& path, const std::string& lpath, bool follow, bool perms, bool replicas) throw (DmException);
     ExtendedStat vfsExtendedStat(const std::string& path, bool follow = true, bool perms = true, bool replicas = false) throw (DmException);
+    std::string vfsPathByRFN(const std::string& rfn) throw (DmException);
     PrivateDir* vfsOpenDir(const std::string& lpath, const std::string& path) throw (DmException);
     Extensible vfsGetXattrs(const std::string& path, const std::string& lpath, bool follow, int amount) throw (DmException);
     std::string vfsGetXattr(const std::string& path, const std::string &lpath, const std::string key, int flags);