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: (%" 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 165 bool 166 Node::IsDirectory() const 167 { 168 return S_ISDIR(fStat.st_mode); 169 } 170 171 // IsFile 172 bool 173 Node::IsFile() const 174 { 175 return S_ISREG(fStat.st_mode); 176 } 177 178 // IsSymlink 179 bool 180 Node::IsSymlink() const 181 { 182 return S_ISLNK(fStat.st_mode); 183 } 184 185 // GetPath 186 status_t 187 Node::GetPath(Path* path) 188 { 189 return VolumeManager::GetDefault()->GetPath(this, path); 190 } 191 192 // Open 193 status_t 194 Node::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 221 status_t 222 Node::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 249 status_t 250 Node::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 261 status_t 262 Node::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 288 status_t 289 Node::_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