// Node.cpp #include #include #include #include #include #include #include #include "DebugSupport.h" #include "Entry.h" #include "FDManager.h" #include "Node.h" #include "NodeHandle.h" #include "Path.h" #include "VolumeManager.h" // constructor Node::Node(Volume* volume, const struct stat& st) : AttributeDirectory(), fVolume(volume), fStat(st), fReferringEntries() { } // destructor Node::~Node() { } // GetVolume Volume* Node::GetVolume() const { return fVolume; } // GetNodeRef node_ref Node::GetNodeRef() const { node_ref ref; ref.device = fStat.st_dev; ref.node = fStat.st_ino; return ref; } // GetVolumeID dev_t Node::GetVolumeID() const { return fStat.st_dev; } // GetID ino_t Node::GetID() const { return fStat.st_ino; } // AddReferringEntry void Node::AddReferringEntry(Entry* entry) { if (!entry) return; fReferringEntries.Insert(entry); } // RemoveReferringEntry void Node::RemoveReferringEntry(Entry* entry) { if (entry) fReferringEntries.Remove(entry); } // GetFirstReferringEntry Entry* Node::GetFirstReferringEntry() const { return fReferringEntries.First(); } // GetNextReferringEntry Entry* Node::GetNextReferringEntry(Entry* entry) const { return (entry ? fReferringEntries.GetNext(entry) : NULL); } // FindReferringEntry Entry* Node::FindReferringEntry(dev_t volumeID, ino_t directoryID, const char* name) { if (!name) return NULL; NoAllocEntryRef ref(volumeID, directoryID, name); return FindReferringEntry(ref); } // FindReferringEntry Entry* Node::FindReferringEntry(const entry_ref& entryRef) { for (Entry* entry = GetFirstReferringEntry(); entry; entry = GetNextReferringEntry(entry)) { NoAllocEntryRef ref(entry->GetEntryRef()); if (ref == entryRef) return entry; } return NULL; } // GetActualReferringEntry Entry* Node::GetActualReferringEntry() const { return GetFirstReferringEntry(); } // GetStat const struct stat& Node::GetStat() const { return fStat; } // UpdateStat status_t Node::UpdateStat() { // get a path Path path; status_t error = GetPath(&path); if (error != B_OK) return error; // read stat struct stat st; if (lstat(path.GetPath(), &st) < 0) return errno; // check if it is the same node if (st.st_dev != fStat.st_dev || st.st_ino != fStat.st_ino) { ERROR("Node::UpdateStat(): ERROR: GetPath() returned path that " "doesn't point to this node: node: (%" B_PRIdDEV ", %" B_PRIdINO "), " "path: `%s'\n", GetVolumeID(), GetID(), path.GetPath()); return B_ENTRY_NOT_FOUND; } fStat = st; return B_OK; } // IsDirectory bool Node::IsDirectory() const { return S_ISDIR(fStat.st_mode); } // IsFile bool Node::IsFile() const { return S_ISREG(fStat.st_mode); } // IsSymlink bool Node::IsSymlink() const { return S_ISLNK(fStat.st_mode); } // GetPath status_t Node::GetPath(Path* path) { return VolumeManager::GetDefault()->GetPath(this, path); } // Open status_t Node::Open(int openMode, FileHandle** _fileHandle) { if (!_fileHandle) return B_BAD_VALUE; // allocate the file handle FileHandle* fileHandle = new(std::nothrow) FileHandle; if (!fileHandle) return B_NO_MEMORY; ObjectDeleter fileHandleDeleter(fileHandle); // open the file status_t error = fileHandle->Open(this, openMode); if (error != B_OK) return error; // check, if it really belongs to this node error = _CheckNodeHandle(fileHandle); if (error != B_OK) return error; fileHandleDeleter.Detach(); *_fileHandle = fileHandle; return B_OK; } // OpenAttrDir status_t Node::OpenAttrDir(AttrDirIterator** _iterator) { if (!_iterator) return B_BAD_VALUE; // allocate the file handle AttrDirIterator* iterator = new(std::nothrow) AttrDirIterator; if (!iterator) return B_NO_MEMORY; ObjectDeleter iteratorDeleter(iterator); // open the attr dir status_t error = iterator->Open(this); if (error != B_OK) return error; // check, if it really belongs to this node error = _CheckNodeHandle(iterator); if (error != B_OK) return error; iteratorDeleter.Detach(); *_iterator = iterator; return B_OK; } // OpenNode status_t Node::OpenNode(BNode& node) { Entry* entry = GetActualReferringEntry(); if (!entry) return B_ENTRY_NOT_FOUND; NoAllocEntryRef entryRef(entry->GetEntryRef()); return FDManager::SetNode(&node, &entryRef); } // ReadSymlink status_t Node::ReadSymlink(char* buffer, int32 bufferSize, int32* _bytesRead) { if (!buffer || bufferSize < 1) return B_BAD_VALUE; // get a path Path path; status_t error = GetPath(&path); if (error != B_OK) return error; // read the symlink ssize_t bytesRead = readlink(path.GetPath(), buffer, bufferSize); if (bytesRead < 0) return bytesRead; if (bytesRead < bufferSize) buffer[bytesRead] = '\0'; else buffer[bufferSize - 1] = '\0'; if (_bytesRead) *_bytesRead = bytesRead; return B_OK; } // _CheckNodeHandle status_t Node::_CheckNodeHandle(NodeHandle* nodeHandle) { if (!nodeHandle) return B_BAD_VALUE; // read the stat struct stat st; status_t error = nodeHandle->GetStat(&st); if (error != B_OK) return error; // check if it is the same node if (st.st_dev != fStat.st_dev || st.st_ino != fStat.st_ino) return B_ENTRY_NOT_FOUND; return B_OK; }