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