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