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