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 21 Node::Node(Volume* volume, const struct stat& st) 22 : AttributeDirectory(), 23 fVolume(volume), 24 fStat(st), 25 fReferringEntries() 26 { 27 } 28 29 // destructor 30 Node::~Node() 31 { 32 } 33 34 // GetVolume 35 Volume* 36 Node::GetVolume() const 37 { 38 return fVolume; 39 } 40 41 // GetNodeRef 42 node_ref 43 Node::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 52 dev_t 53 Node::GetVolumeID() const 54 { 55 return fStat.st_dev; 56 } 57 58 // GetID 59 ino_t 60 Node::GetID() const 61 { 62 return fStat.st_ino; 63 } 64 65 // AddReferringEntry 66 void 67 Node::AddReferringEntry(Entry* entry) 68 { 69 if (!entry) 70 return; 71 fReferringEntries.Insert(entry); 72 } 73 74 // RemoveReferringEntry 75 void 76 Node::RemoveReferringEntry(Entry* entry) 77 { 78 if (entry) 79 fReferringEntries.Remove(entry); 80 } 81 82 // GetFirstReferringEntry 83 Entry* 84 Node::GetFirstReferringEntry() const 85 { 86 return fReferringEntries.First(); 87 } 88 89 // GetNextReferringEntry 90 Entry* 91 Node::GetNextReferringEntry(Entry* entry) const 92 { 93 return (entry ? fReferringEntries.GetNext(entry) : NULL); 94 } 95 96 // FindReferringEntry 97 Entry* 98 Node::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 108 Entry* 109 Node::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 123 Entry* 124 Node::GetActualReferringEntry() const 125 { 126 return GetFirstReferringEntry(); 127 } 128 129 // GetStat 130 const struct stat& 131 Node::GetStat() const 132 { 133 return fStat; 134 } 135 136 // UpdateStat 137 status_t 138 Node::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 164 bool 165 Node::IsDirectory() const 166 { 167 return S_ISDIR(fStat.st_mode); 168 } 169 170 // IsFile 171 bool 172 Node::IsFile() const 173 { 174 return S_ISREG(fStat.st_mode); 175 } 176 177 // IsSymlink 178 bool 179 Node::IsSymlink() const 180 { 181 return S_ISLNK(fStat.st_mode); 182 } 183 184 // GetPath 185 status_t 186 Node::GetPath(Path* path) 187 { 188 return VolumeManager::GetDefault()->GetPath(this, path); 189 } 190 191 // Open 192 status_t 193 Node::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 220 status_t 221 Node::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 248 status_t 249 Node::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 260 status_t 261 Node::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 287 status_t 288 Node::_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