1// Node.cpp 2 3#include <errno.h> 4#include <fcntl.h> 5#include <new> 6#include <unistd.h> 7#include <sys/stat.h> 8 9#include <AutoDeleter.h> 10#include <fs_attr.h> 11 12#include "DebugSupport.h" 13#include "Entry.h" 14#include "FDManager.h" 15#include "Node.h" 16#include "NodeHandle.h" 17#include "Path.h" 18#include "VolumeManager.h" 19 20// constructor 21Node::Node(Volume* volume, const struct stat& st) 22 : AttributeDirectory(), 23 fVolume(volume), 24 fStat(st), 25 fReferringEntries() 26{ 27} 28 29// destructor 30Node::~Node() 31{ 32} 33 34// GetVolume 35Volume* 36Node::GetVolume() const 37{ 38 return fVolume; 39} 40 41// GetNodeRef 42node_ref 43Node::GetNodeRef() const 44{ 45 node_ref ref; 46 ref.device = fStat.st_dev; 47 ref.node = fStat.st_ino; 48 return ref; 49} 50 51// GetVolumeID 52dev_t 53Node::GetVolumeID() const 54{ 55 return fStat.st_dev; 56} 57 58// GetID 59ino_t 60Node::GetID() const 61{ 62 return fStat.st_ino; 63} 64 65// AddReferringEntry 66void 67Node::AddReferringEntry(Entry* entry) 68{ 69 if (!entry) 70 return; 71 fReferringEntries.Insert(entry); 72} 73 74// RemoveReferringEntry 75void 76Node::RemoveReferringEntry(Entry* entry) 77{ 78 if (entry) 79 fReferringEntries.Remove(entry); 80} 81 82// GetFirstReferringEntry 83Entry* 84Node::GetFirstReferringEntry() const 85{ 86 return fReferringEntries.First(); 87} 88 89// GetNextReferringEntry 90Entry* 91Node::GetNextReferringEntry(Entry* entry) const 92{ 93 return (entry ? fReferringEntries.GetNext(entry) : NULL); 94} 95 96// FindReferringEntry 97Entry* 98Node::FindReferringEntry(dev_t volumeID, ino_t directoryID, const char* name) 99{ 100 if (!name) 101 return NULL; 102 103 NoAllocEntryRef ref(volumeID, directoryID, name); 104 return FindReferringEntry(ref); 105} 106 107// FindReferringEntry 108Entry* 109Node::FindReferringEntry(const entry_ref& entryRef) 110{ 111 for (Entry* entry = GetFirstReferringEntry(); 112 entry; 113 entry = GetNextReferringEntry(entry)) { 114 NoAllocEntryRef ref(entry->GetEntryRef()); 115 if (ref == entryRef) 116 return entry; 117 } 118 119 return NULL; 120} 121 122// GetActualReferringEntry 123Entry* 124Node::GetActualReferringEntry() const 125{ 126 return GetFirstReferringEntry(); 127} 128 129// GetStat 130const struct stat& 131Node::GetStat() const 132{ 133 return fStat; 134} 135 136// UpdateStat 137status_t 138Node::UpdateStat() 139{ 140 // get a path 141 Path path; 142 status_t error = GetPath(&path); 143 if (error != B_OK) 144 return error; 145 146 // read stat 147 struct stat st; 148 if (lstat(path.GetPath(), &st) < 0) 149 return errno; 150 151 // check if it is the same node 152 if (st.st_dev != fStat.st_dev || st.st_ino != fStat.st_ino) { 153 ERROR("Node::UpdateStat(): ERROR: GetPath() returned path that " 154 "doesn't point to this node: node: (%ld, %lld), path: `%s'\n", 155 GetVolumeID(), GetID(), path.GetPath()); 156 return B_ENTRY_NOT_FOUND; 157 } 158 159 fStat = st; 160 return B_OK; 161} 162 163// IsDirectory 164bool 165Node::IsDirectory() const 166{ 167 return S_ISDIR(fStat.st_mode); 168} 169 170// IsFile 171bool 172Node::IsFile() const 173{ 174 return S_ISREG(fStat.st_mode); 175} 176 177// IsSymlink 178bool 179Node::IsSymlink() const 180{ 181 return S_ISLNK(fStat.st_mode); 182} 183 184// GetPath 185status_t 186Node::GetPath(Path* path) 187{ 188 return VolumeManager::GetDefault()->GetPath(this, path); 189} 190 191// Open 192status_t 193Node::Open(int openMode, FileHandle** _fileHandle) 194{ 195 if (!_fileHandle) 196 return B_BAD_VALUE; 197 198 // allocate the file handle 199 FileHandle* fileHandle = new(std::nothrow) FileHandle; 200 if (!fileHandle) 201 return B_NO_MEMORY; 202 ObjectDeleter<FileHandle> fileHandleDeleter(fileHandle); 203 204 // open the file 205 status_t error = fileHandle->Open(this, openMode); 206 if (error != B_OK) 207 return error; 208 209 // check, if it really belongs to this node 210 error = _CheckNodeHandle(fileHandle); 211 if (error != B_OK) 212 return error; 213 214 fileHandleDeleter.Detach(); 215 *_fileHandle = fileHandle; 216 return B_OK; 217} 218 219// OpenAttrDir 220status_t 221Node::OpenAttrDir(AttrDirIterator** _iterator) 222{ 223 if (!_iterator) 224 return B_BAD_VALUE; 225 226 // allocate the file handle 227 AttrDirIterator* iterator = new(std::nothrow) AttrDirIterator; 228 if (!iterator) 229 return B_NO_MEMORY; 230 ObjectDeleter<AttrDirIterator> iteratorDeleter(iterator); 231 232 // open the attr dir 233 status_t error = iterator->Open(this); 234 if (error != B_OK) 235 return error; 236 237 // check, if it really belongs to this node 238 error = _CheckNodeHandle(iterator); 239 if (error != B_OK) 240 return error; 241 242 iteratorDeleter.Detach(); 243 *_iterator = iterator; 244 return B_OK; 245} 246 247// OpenNode 248status_t 249Node::OpenNode(BNode& node) 250{ 251 Entry* entry = GetActualReferringEntry(); 252 if (!entry) 253 return B_ENTRY_NOT_FOUND; 254 255 NoAllocEntryRef entryRef(entry->GetEntryRef()); 256 return FDManager::SetNode(&node, &entryRef); 257} 258 259// ReadSymlink 260status_t 261Node::ReadSymlink(char* buffer, int32 bufferSize, int32* _bytesRead) 262{ 263 if (!buffer || bufferSize < 1) 264 return B_BAD_VALUE; 265 266 // get a path 267 Path path; 268 status_t error = GetPath(&path); 269 if (error != B_OK) 270 return error; 271 272 // read the symlink 273 ssize_t bytesRead = readlink(path.GetPath(), buffer, bufferSize); 274 if (bytesRead < 0) 275 return bytesRead; 276 if (bytesRead < bufferSize) 277 buffer[bytesRead] = '\0'; 278 else 279 buffer[bufferSize - 1] = '\0'; 280 281 if (_bytesRead) 282 *_bytesRead = bytesRead; 283 return B_OK; 284} 285 286// _CheckNodeHandle 287status_t 288Node::_CheckNodeHandle(NodeHandle* nodeHandle) 289{ 290 if (!nodeHandle) 291 return B_BAD_VALUE; 292 293 // read the stat 294 struct stat st; 295 status_t error = nodeHandle->GetStat(&st); 296 if (error != B_OK) 297 return error; 298 299 // check if it is the same node 300 if (st.st_dev != fStat.st_dev || st.st_ino != fStat.st_ino) 301 return B_ENTRY_NOT_FOUND; 302 return B_OK; 303} 304 305