DirNode.cpp (encfs-1.9.4) | : | DirNode.cpp (encfs-1.9.5) | ||
---|---|---|---|---|
skipping to change at line 55 | skipping to change at line 55 | |||
using namespace std; | using namespace std; | |||
namespace encfs { | namespace encfs { | |||
class DirDeleter { | class DirDeleter { | |||
public: | public: | |||
void operator()(DIR *d) { ::closedir(d); } | void operator()(DIR *d) { ::closedir(d); } | |||
}; | }; | |||
DirTraverse::DirTraverse(std::shared_ptr<DIR> _dirPtr, uint64_t _iv, | DirTraverse::DirTraverse(std::shared_ptr<DIR> _dirPtr, uint64_t _iv, | |||
std::shared_ptr<NameIO> _naming) | std::shared_ptr<NameIO> _naming, bool _root) | |||
: dir(std::move(_dirPtr)), iv(_iv), naming(std::move(_naming)) {} | : dir(std::move(_dirPtr)), iv(_iv), naming(std::move(_naming)), root(_root) | |||
{} | ||||
DirTraverse &DirTraverse::operator=(const DirTraverse &src) = default; | DirTraverse &DirTraverse::operator=(const DirTraverse &src) = default; | |||
DirTraverse::~DirTraverse() { | DirTraverse::~DirTraverse() { | |||
dir.reset(); | dir.reset(); | |||
iv = 0; | iv = 0; | |||
naming.reset(); | naming.reset(); | |||
root = false; | ||||
} | } | |||
static bool _nextName(struct dirent *&de, const std::shared_ptr<DIR> &dir, | static bool _nextName(struct dirent *&de, const std::shared_ptr<DIR> &dir, | |||
int *fileType, ino_t *inode) { | int *fileType, ino_t *inode) { | |||
de = ::readdir(dir.get()); | de = ::readdir(dir.get()); | |||
if (de != nullptr) { | if (de != nullptr) { | |||
if (fileType != nullptr) { | if (fileType != nullptr) { | |||
#if defined(HAVE_DIRENT_D_TYPE) | #if defined(HAVE_DIRENT_D_TYPE) | |||
*fileType = de->d_type; | *fileType = de->d_type; | |||
skipping to change at line 93 | skipping to change at line 94 | |||
} | } | |||
if (fileType != nullptr) { | if (fileType != nullptr) { | |||
*fileType = 0; | *fileType = 0; | |||
} | } | |||
return false; | return false; | |||
} | } | |||
std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) { | std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) { | |||
struct dirent *de = nullptr; | struct dirent *de = nullptr; | |||
while (_nextName(de, dir, fileType, inode)) { | while (_nextName(de, dir, fileType, inode)) { | |||
if (root && (strcmp(".encfs6.xml", de->d_name) == 0)) { | ||||
VLOG(1) << "skipping filename: " << de->d_name; | ||||
continue; | ||||
} | ||||
try { | try { | |||
uint64_t localIv = iv; | uint64_t localIv = iv; | |||
return naming->decodePath(de->d_name, &localIv); | return naming->decodePath(de->d_name, &localIv); | |||
} catch (encfs::Error &ex) { | } catch (encfs::Error &ex) { | |||
// .. .problem decoding, ignore it and continue on to next name.. | // .. .problem decoding, ignore it and continue on to next name.. | |||
VLOG(1) << "error decoding filename: " << de->d_name; | VLOG(1) << "error decoding filename: " << de->d_name; | |||
} | } | |||
} | } | |||
return string(); | return string(); | |||
} | } | |||
std::string DirTraverse::nextInvalid() { | std::string DirTraverse::nextInvalid() { | |||
struct dirent *de = nullptr; | struct dirent *de = nullptr; | |||
// find the first name which produces a decoding error... | // find the first name which produces a decoding error... | |||
while (_nextName(de, dir, (int *)nullptr, (ino_t *)nullptr)) { | while (_nextName(de, dir, (int *)nullptr, (ino_t *)nullptr)) { | |||
if (root && (strcmp(".encfs6.xml", de->d_name) == 0)) { | ||||
VLOG(1) << "skipping filename: " << de->d_name; | ||||
continue; | ||||
} | ||||
try { | try { | |||
uint64_t localIv = iv; | uint64_t localIv = iv; | |||
naming->decodePath(de->d_name, &localIv); | naming->decodePath(de->d_name, &localIv); | |||
continue; | continue; | |||
} catch (encfs::Error &ex) { | } catch (encfs::Error &ex) { | |||
return string(de->d_name); | return string(de->d_name); | |||
} | } | |||
} | } | |||
return string(); | return string(); | |||
skipping to change at line 358 | skipping to change at line 367 | |||
} | } | |||
} | } | |||
DirTraverse DirNode::openDir(const char *plaintextPath) { | DirTraverse DirNode::openDir(const char *plaintextPath) { | |||
string cyName = rootDir + naming->encodePath(plaintextPath); | string cyName = rootDir + naming->encodePath(plaintextPath); | |||
DIR *dir = ::opendir(cyName.c_str()); | DIR *dir = ::opendir(cyName.c_str()); | |||
if (dir == nullptr) { | if (dir == nullptr) { | |||
int eno = errno; | int eno = errno; | |||
VLOG(1) << "opendir error " << strerror(eno); | VLOG(1) << "opendir error " << strerror(eno); | |||
return DirTraverse(shared_ptr<DIR>(), 0, std::shared_ptr<NameIO>()); | return DirTraverse(shared_ptr<DIR>(), 0, std::shared_ptr<NameIO>(), false); | |||
} | } | |||
std::shared_ptr<DIR> dp(dir, DirDeleter()); | std::shared_ptr<DIR> dp(dir, DirDeleter()); | |||
uint64_t iv = 0; | uint64_t iv = 0; | |||
// if we're using chained IV mode, then compute the IV at this | // if we're using chained IV mode, then compute the IV at this | |||
// directory level.. | // directory level.. | |||
try { | try { | |||
if (naming->getChainedNameIV()) { | if (naming->getChainedNameIV()) { | |||
naming->encodePath(plaintextPath, &iv); | naming->encodePath(plaintextPath, &iv); | |||
} | } | |||
} catch (encfs::Error &err) { | } catch (encfs::Error &err) { | |||
RLOG(ERROR) << "encode err: " << err.what(); | RLOG(ERROR) << "encode err: " << err.what(); | |||
} | } | |||
return DirTraverse(dp, iv, naming); | return DirTraverse(dp, iv, naming, (strlen(plaintextPath) == 1)); | |||
} | } | |||
bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP, | bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP, | |||
const char *toP) { | const char *toP) { | |||
uint64_t fromIV = 0, toIV = 0; | uint64_t fromIV = 0, toIV = 0; | |||
// compute the IV for both paths | // compute the IV for both paths | |||
string fromCPart = naming->encodePath(fromP, &fromIV); | string fromCPart = naming->encodePath(fromP, &fromIV); | |||
string toCPart = naming->encodePath(toP, &toIV); | string toCPart = naming->encodePath(toP, &toIV); | |||
skipping to change at line 593 | skipping to change at line 602 | |||
res = ::rename(fromCName.c_str(), toCName.c_str()); | res = ::rename(fromCName.c_str(), toCName.c_str()); | |||
if (res == -1) { | if (res == -1) { | |||
// undo | // undo | |||
res = -errno; | res = -errno; | |||
renameNode(toPlaintext, fromPlaintext, false); | renameNode(toPlaintext, fromPlaintext, false); | |||
if (renameOp) { | if (renameOp) { | |||
renameOp->undo(); | renameOp->undo(); | |||
} | } | |||
} else if (preserve_mtime) { | } | |||
struct utimbuf ut; | else { | |||
ut.actime = st.st_atime; | #ifdef __CYGWIN__ | |||
ut.modtime = st.st_mtime; | // When renaming a file, Windows first opens it, renames it and then close | |||
::utime(toCName.c_str(), &ut); | s it | |||
// We then must decrease the target openFiles count | ||||
// We could recreate the source so that close will not (silently) fails, | ||||
// however it will update modification time of the file, so break what we | ||||
do below. | ||||
// Let's simply warn in eraseNode(). | ||||
if (!isDirectory(toCName.c_str())) { | ||||
std::shared_ptr<FileNode> toNode = findOrCreate(toPlaintext); | ||||
ctx->eraseNode(toPlaintext, toNode); | ||||
//ctx->putNode(fromPlaintext, toNode); | ||||
} | ||||
#endif | ||||
if (preserve_mtime) { | ||||
struct utimbuf ut; | ||||
ut.actime = st.st_atime; | ||||
ut.modtime = st.st_mtime; | ||||
::utime(toCName.c_str(), &ut); | ||||
} | ||||
} | } | |||
} catch (encfs::Error &err) { | } catch (encfs::Error &err) { | |||
// exception from renameNode, just show the error and continue.. | // exception from renameNode, just show the error and continue.. | |||
RLOG(WARNING) << err.what(); | RLOG(WARNING) << err.what(); | |||
res = -EIO; | res = -EIO; | |||
} | } | |||
if (res != 0) { | if (res != 0) { | |||
VLOG(1) << "rename failed: " << strerror(-res); | VLOG(1) << "rename failed: " << strerror(-res); | |||
} | } | |||
return res; | return res; | |||
} | } | |||
int DirNode::link(const char *from, const char *to) { | int DirNode::link(const char *to, const char *from) { | |||
Lock _lock(mutex); | Lock _lock(mutex); | |||
string fromCName = rootDir + naming->encodePath(from); | ||||
string toCName = rootDir + naming->encodePath(to); | string toCName = rootDir + naming->encodePath(to); | |||
string fromCName = rootDir + naming->encodePath(from); | ||||
rAssert(!fromCName.empty()); | ||||
rAssert(!toCName.empty()); | rAssert(!toCName.empty()); | |||
rAssert(!fromCName.empty()); | ||||
VLOG(1) << "link " << fromCName << " -> " << toCName; | VLOG(1) << "link " << fromCName << " -> " << toCName; | |||
int res = -EPERM; | int res = -EPERM; | |||
if (fsConfig->config->externalIVChaining) { | if (fsConfig->config->externalIVChaining) { | |||
VLOG(1) << "hard links not supported with external IV chaining!"; | VLOG(1) << "hard links not supported with external IV chaining!"; | |||
} else { | } else { | |||
res = ::link(fromCName.c_str(), toCName.c_str()); | res = ::link(toCName.c_str(), fromCName.c_str()); | |||
if (res == -1) { | if (res == -1) { | |||
res = -errno; | res = -errno; | |||
} else { | } else { | |||
res = 0; | res = 0; | |||
} | } | |||
} | } | |||
return res; | return res; | |||
} | } | |||
skipping to change at line 733 | skipping to change at line 757 | |||
} | } | |||
return std::shared_ptr<FileNode>(); | return std::shared_ptr<FileNode>(); | |||
} | } | |||
int DirNode::unlink(const char *plaintextName) { | int DirNode::unlink(const char *plaintextName) { | |||
string cyName = naming->encodePath(plaintextName); | string cyName = naming->encodePath(plaintextName); | |||
VLOG(1) << "unlink " << cyName; | VLOG(1) << "unlink " << cyName; | |||
Lock _lock(mutex); | Lock _lock(mutex); | |||
int res = 0; | // Windows does not allow deleting opened files, so no need to check | |||
// There is this "issue" however : https://github.com/billziss-gh/winfsp/issues/ | ||||
157 | ||||
#ifndef __CYGWIN__ | ||||
if ((ctx != nullptr) && ctx->lookupNode(plaintextName)) { | if ((ctx != nullptr) && ctx->lookupNode(plaintextName)) { | |||
// If FUSE is running with "hard_remove" option where it doesn't | // If FUSE is running with "hard_remove" option where it doesn't | |||
// hide open files for us, then we can't allow an unlink of an open | // hide open files for us, then we can't allow an unlink of an open | |||
// file.. | // file.. | |||
RLOG(WARNING) << "Refusing to unlink open file: " << cyName | RLOG(WARNING) << "Refusing to unlink open file: " << cyName | |||
<< ", hard_remove option " | << ", hard_remove option " | |||
"is probably in effect"; | "is probably in effect"; | |||
res = -EBUSY; | return -EBUSY; | |||
} else { | } | |||
string fullName = rootDir + cyName; | #endif | |||
res = ::unlink(fullName.c_str()); | ||||
if (res == -1) { | int res = 0; | |||
res = -errno; | string fullName = rootDir + cyName; | |||
VLOG(1) << "unlink error: " << strerror(-res); | res = ::unlink(fullName.c_str()); | |||
} | if (res == -1) { | |||
res = -errno; | ||||
VLOG(1) << "unlink error: " << strerror(-res); | ||||
} | } | |||
return res; | return res; | |||
} | } | |||
} // namespace encfs | } // namespace encfs | |||
End of changes. 15 change blocks. | ||||
22 lines changed or deleted | 54 lines changed or added |