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: (%" B_PRIdDEV ", %" B_PRIdINO "), " 155 "path: `%s'\n", 156 GetVolumeID(), GetID(), path.GetPath()); 157 return B_ENTRY_NOT_FOUND; 158 } 159 160 fStat = st; 161 return B_OK; 162} 163 164// IsDirectory 165bool 166Node::IsDirectory() const 167{ 168 return S_ISDIR(fStat.st_mode); 169} 170 171// IsFile 172bool 173Node::IsFile() const 174{ 175 return S_ISREG(fStat.st_mode); 176} 177 178// IsSymlink 179bool 180Node::IsSymlink() const 181{ 182 return S_ISLNK(fStat.st_mode); 183} 184 185// GetPath 186status_t 187Node::GetPath(Path* path) 188{ 189 return VolumeManager::GetDefault()->GetPath(this, path); 190} 191 192// Open 193status_t 194Node::Open(int openMode, FileHandle** _fileHandle) 195{ 196 if (!_fileHandle) 197 return B_BAD_VALUE; 198 199 // allocate the file handle 200 FileHandle* fileHandle = new(std::nothrow) FileHandle; 201 if (!fileHandle) 202 return B_NO_MEMORY; 203 ObjectDeleter<FileHandle> fileHandleDeleter(fileHandle); 204 205 // open the file 206 status_t error = fileHandle->Open(this, openMode); 207 if (error != B_OK) 208 return error; 209 210 // check, if it really belongs to this node 211 error = _CheckNodeHandle(fileHandle); 212 if (error != B_OK) 213 return error; 214 215 fileHandleDeleter.Detach(); 216 *_fileHandle = fileHandle; 217 return B_OK; 218} 219 220// OpenAttrDir 221status_t 222Node::OpenAttrDir(AttrDirIterator** _iterator) 223{ 224 if (!_iterator) 225 return B_BAD_VALUE; 226 227 // allocate the file handle 228 AttrDirIterator* iterator = new(std::nothrow) AttrDirIterator; 229 if (!iterator) 230 return B_NO_MEMORY; 231 ObjectDeleter<AttrDirIterator> iteratorDeleter(iterator); 232 233 // open the attr dir 234 status_t error = iterator->Open(this); 235 if (error != B_OK) 236 return error; 237 238 // check, if it really belongs to this node 239 error = _CheckNodeHandle(iterator); 240 if (error != B_OK) 241 return error; 242 243 iteratorDeleter.Detach(); 244 *_iterator = iterator; 245 return B_OK; 246} 247 248// OpenNode 249status_t 250Node::OpenNode(BNode& node) 251{ 252 Entry* entry = GetActualReferringEntry(); 253 if (!entry) 254 return B_ENTRY_NOT_FOUND; 255 256 NoAllocEntryRef entryRef(entry->GetEntryRef()); 257 return FDManager::SetNode(&node, &entryRef); 258} 259 260// ReadSymlink 261status_t 262Node::ReadSymlink(char* buffer, int32 bufferSize, int32* _bytesRead) 263{ 264 if (!buffer || bufferSize < 1) 265 return B_BAD_VALUE; 266 267 // get a path 268 Path path; 269 status_t error = GetPath(&path); 270 if (error != B_OK) 271 return error; 272 273 // read the symlink 274 ssize_t bytesRead = readlink(path.GetPath(), buffer, bufferSize); 275 if (bytesRead < 0) 276 return bytesRead; 277 if (bytesRead < bufferSize) 278 buffer[bytesRead] = '\0'; 279 else 280 buffer[bufferSize - 1] = '\0'; 281 282 if (_bytesRead) 283 *_bytesRead = bytesRead; 284 return B_OK; 285} 286 287// _CheckNodeHandle 288status_t 289Node::_CheckNodeHandle(NodeHandle* nodeHandle) 290{ 291 if (!nodeHandle) 292 return B_BAD_VALUE; 293 294 // read the stat 295 struct stat st; 296 status_t error = nodeHandle->GetStat(&st); 297 if (error != B_OK) 298 return error; 299 300 // check if it is the same node 301 if (st.st_dev != fStat.st_dev || st.st_ino != fStat.st_ino) 302 return B_ENTRY_NOT_FOUND; 303 return B_OK; 304} 305 306