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
Node(Volume * volume,const struct stat & st)21 Node::Node(Volume* volume, const struct stat& st)
22 : AttributeDirectory(),
23 fVolume(volume),
24 fStat(st),
25 fReferringEntries()
26 {
27 }
28
29 // destructor
~Node()30 Node::~Node()
31 {
32 }
33
34 // GetVolume
35 Volume*
GetVolume() const36 Node::GetVolume() const
37 {
38 return fVolume;
39 }
40
41 // GetNodeRef
42 node_ref
GetNodeRef() const43 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
GetVolumeID() const53 Node::GetVolumeID() const
54 {
55 return fStat.st_dev;
56 }
57
58 // GetID
59 ino_t
GetID() const60 Node::GetID() const
61 {
62 return fStat.st_ino;
63 }
64
65 // AddReferringEntry
66 void
AddReferringEntry(Entry * entry)67 Node::AddReferringEntry(Entry* entry)
68 {
69 if (!entry)
70 return;
71 fReferringEntries.Insert(entry);
72 }
73
74 // RemoveReferringEntry
75 void
RemoveReferringEntry(Entry * entry)76 Node::RemoveReferringEntry(Entry* entry)
77 {
78 if (entry)
79 fReferringEntries.Remove(entry);
80 }
81
82 // GetFirstReferringEntry
83 Entry*
GetFirstReferringEntry() const84 Node::GetFirstReferringEntry() const
85 {
86 return fReferringEntries.First();
87 }
88
89 // GetNextReferringEntry
90 Entry*
GetNextReferringEntry(Entry * entry) const91 Node::GetNextReferringEntry(Entry* entry) const
92 {
93 return (entry ? fReferringEntries.GetNext(entry) : NULL);
94 }
95
96 // FindReferringEntry
97 Entry*
FindReferringEntry(dev_t volumeID,ino_t directoryID,const char * name)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*
FindReferringEntry(const entry_ref & entryRef)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*
GetActualReferringEntry() const124 Node::GetActualReferringEntry() const
125 {
126 return GetFirstReferringEntry();
127 }
128
129 // GetStat
130 const struct stat&
GetStat() const131 Node::GetStat() const
132 {
133 return fStat;
134 }
135
136 // UpdateStat
137 status_t
UpdateStat()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
IsDirectory() const166 Node::IsDirectory() const
167 {
168 return S_ISDIR(fStat.st_mode);
169 }
170
171 // IsFile
172 bool
IsFile() const173 Node::IsFile() const
174 {
175 return S_ISREG(fStat.st_mode);
176 }
177
178 // IsSymlink
179 bool
IsSymlink() const180 Node::IsSymlink() const
181 {
182 return S_ISLNK(fStat.st_mode);
183 }
184
185 // GetPath
186 status_t
GetPath(Path * path)187 Node::GetPath(Path* path)
188 {
189 return VolumeManager::GetDefault()->GetPath(this, path);
190 }
191
192 // Open
193 status_t
Open(int openMode,FileHandle ** _fileHandle)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
OpenAttrDir(AttrDirIterator ** _iterator)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
OpenNode(BNode & node)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
ReadSymlink(char * buffer,int32 bufferSize,int32 * _bytesRead)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
_CheckNodeHandle(NodeHandle * nodeHandle)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