xref: /haiku/src/add-ons/kernel/file_systems/netfs/server/Node.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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