void VirtualDiskNode::deleteDir(MyString path) { if (!isNormalizedPath(path)) { assert(0); return; } path = path.toLower(); MyString dir_path = dirname(path); DirNode* parent = getDirNode(dir_path); if (!parent) return; MyString dir_name = basename(path); assert(!dir_name.isEmpty()); int dir = parent->findSubDir(dir_name); if (dir != -1) { parent->removeSubDir(dir); } return; }
void VirtualDiskNode::deleteFile(MyString path) { if (!isNormalizedPath(path)) { assert(0); return; } path = path.toLower(); MyString dir_path = dirname(path); DirNode* parent = getDirNode(dir_path); if (!parent) return; MyString file_name = basename(path); assert(!file_name.isEmpty()); int file = parent->findFile(file_name); if (file != -1) { parent->removeFile(file); } return; }
void FsDirectoryImpl::deleteDir(const std::string& dirName) { Path path(dirName+"/"); DirNode* pDirNode; //#TODO, lock pDirNode = m_pDirTree->findDirNode(path.getDirName()); if(!pDirNode) { LOG4CPLUS_WARN(m_logger, "directory not exist : " << path.getDirName()); throw NoSuchFileOrDir("deleteDir:"); } else if(pDirNode == m_pDirTree->getRoot()){ //don't delete root node LOG4CPLUS_WARN(m_logger, "deleting ROOT directory canceled"); throw InvalidFileOrDirName("deleteDir: ROOT directory can't be deleted"); } //check empty directory INodeIterator iter = pDirNode->getFilesBegin(); if( iter != pDirNode->getFilesEnd()) { LOG4CPLUS_WARN(m_logger, "directory not empty"); throw InvalidFileOrDirName("deleteDir: dir not empty"); } DirNodeIterator iterDir = pDirNode->getChildrenBegin(); if( iterDir != pDirNode->getChildrenEnd()) { LOG4CPLUS_WARN(m_logger, "directory not empty"); throw InvalidFileOrDirName("deleteDir: dir not empty"); } pDirNode->getParent()->deleteChild(pDirNode); }
DirNode* VirtualDiskNode::getDirNode(const MyString& path) { assert(isNormalizedPath(path)); Vector<MyString> dirnames = split(path); DirNode* ret = &m_root; if (dirnames[0] != ret->get_name().toLower() || ret->get_type() == FILE_TYPE) return nullptr; for (int i = 1; i < dirnames.size(); ++i) { int subdir = ret->findSubDir(dirnames[i]); if (subdir == -1) { return nullptr; } else { ret = ret->getSubDirRef(subdir); } } return ret; }
FileHandler VirtualDiskNode::createFile(MyString path) { if (!isNormalizedPath(path)) { assert(0); return FileHandler(nullptr); } MyString dir_path = dirname(path).toLower(); DirNode* parent = getDirNode(dir_path); if (!parent) return FileHandler(nullptr); // 文件名创建时保留大小写 MyString file_name = basename(path); if (parent->findFile(file_name) != -1) { return FileHandler(nullptr); } FileNode* nfile = parent->addFile(); assert(nfile); nfile->set_name(file_name); nfile->set_path(path.toLower()); return FileHandler(nfile); }
bool VirtualDiskNode::isExist(MyString path) const { if (!isNormalizedPath(path)) { assert(0); return false; } path = path.toLower(); MyString dir_path = dirname(path); DirNode* parent = const_cast<VirtualDiskNode*>(this)->getDirNode(dir_path); if (!parent) return false; MyString name = basename(path); if (name.isEmpty()) return true; int file = parent->findFile(name); if (file != -1) return true; int dir = parent->findSubDir(name); if (dir != -1) return true; return false; }
bool RenameOp::apply() { try { while (last != renameList->end()) { // backing store rename. rDebug("renaming %s -> %s", last->oldCName.c_str(), last->newCName.c_str()); struct stat st; bool preserve_mtime = unix::stat(last->oldCName.c_str(), &st) == 0; // internal node rename.. dn->renameNode(last->oldPName.c_str(), last->newPName.c_str()); // rename on disk.. if (unix::rename(last->oldCName.c_str(), last->newCName.c_str()) == -1) { rWarning("Error renaming %s: %s", last->oldCName.c_str(), strerror(errno)); dn->renameNode(last->newPName.c_str(), last->oldPName.c_str(), false); return false; } if (preserve_mtime) { struct utimbuf ut; ut.actime = st.st_atime; ut.modtime = st.st_mtime; unix::utime(last->newCName.c_str(), &ut); } ++last; } return true; } catch (rlog::Error &err) { err.log(_RLWarningChannel); } }
void RenameOp::undo() { rDebug("in undoRename"); if(last == renameList->begin()) { rDebug("nothing to undo"); return; // nothing to undo } // list has to be processed backwards, otherwise we may rename // directories and directory contents in the wrong order! int undoCount = 0; list<RenameEl>::const_iterator it = last; while( it != renameList->begin() ) { --it; rDebug("undo: renaming %s -> %s", it->newCName.c_str(), it->oldCName.c_str()); unix::rename( it->newCName.c_str(), it->oldCName.c_str() ); try { dn->renameNode( it->newPName.c_str(), it->oldPName.c_str(), false ); } catch( rlog::Error &err ) { err.log( _RLWarningChannel ); // continue on anyway... } ++undoCount; }; rWarning("Undo rename count: %i", undoCount); }
INode* DirTree::findINode(const std::string &name) const { DirNode *pNode; INode *pInode; Path path(name); if ( (pNode = findDirNode(name)) ) { if (path.isPureDir()) { return pNode->getINode(); } else { //try file node first pInode = pNode->findFile(path.getFileName()); if(pInode) return pInode; //try dir node then DirNode *pDirNode = pNode->findChild(path.getFileName()); if(pDirNode) return pDirNode->getINode(); else return NULL; } } return NULL; }
static bool testNameCoding( DirNode &dirNode, bool verbose, bool collisionTest = false ) { // encrypt a name const char *name[] = { "1234567", "12345678", "123456789", "123456789ABCDEF", "123456789ABCDEF0", "123456789ABCDEF01", "test-name", "test-name2", "test", "../test", "/foo/bar/blah", "test-name.21", "test-name.22", "test-name.o", "1.test", "2.test", "a/b/c/d", "a/c/d/e", "b/c/d/e", "b/a/c/d", NULL }; const char **orig = name; while(*orig) { if(verbose) cerr << " coding name \"" << *orig << "\""; string encName = dirNode.relativeCipherPath( *orig ); if(verbose) cerr << " -> \"" << encName.c_str() << "\""; // decrypt name string decName = dirNode.plainPath( encName.c_str() ); if(decName == *orig) { if(verbose) cerr << " OK\n"; } else { if(verbose) cerr << " FAILED (got " << decName << ")\n"; return false; } orig++; } if (collisionTest) { if (verbose) cerr << "Checking for name collections, this will take a while..\n"; // check for collision rate char buf[64]; unordered_set<string> encryptedNames; for (long i=0; i < 10000000; i++) { snprintf(buf, sizeof(buf), "%li", i); string encName = dirNode.relativeCipherPath( buf ); // simulate a case-insisitive filesystem.. std::transform(encName.begin(), encName.end(), encName.begin(), ::toupper); if (encryptedNames.insert(encName).second == false) { cerr << "collision detected after " << i << " iterations"; break; } } cerr << "NO collisions detected"; } return true; }