1// NodeHandle.cpp
2
3#include "NodeHandle.h"
4
5#include <errno.h>
6#include <fcntl.h>
7#include <string.h>
8#include <unistd.h>
9#include <sys/stat.h>
10
11#include <fs_attr.h>
12
13#include "Compatibility.h"
14#include "Directory.h"
15#include "FDManager.h"
16#include "Path.h"
17
18// TODO: Do the FD creation via the FDManager.
19
20// NodeHandle
21
22// constructor
23NodeHandle::NodeHandle()
24	: BReferenceable(),
25	  Lockable(),
26	  fCookie(-1),
27	  fNodeRef()
28{
29}
30
31// destructor
32NodeHandle::~NodeHandle()
33{
34}
35
36// GetStat
37status_t
38NodeHandle::GetStat(struct stat* st)
39{
40	int fd = GetFD();
41	if (fd < 0)
42		return B_ENTRY_NOT_FOUND;
43
44	if (fstat(fd, st) < 0)
45		return errno;
46
47	return B_OK;
48}
49
50// SetCookie
51void
52NodeHandle::SetCookie(int32 cookie)
53{
54	fCookie = cookie;
55}
56
57// GetCookie
58int32
59NodeHandle::GetCookie() const
60{
61	return fCookie;
62}
63
64// GetNodeRef
65const NodeRef&
66NodeHandle::GetNodeRef() const
67{
68	return fNodeRef;
69}
70
71// GetFD
72int
73NodeHandle::GetFD() const
74{
75	return -1;
76}
77
78
79// #pragma mark -
80
81// FileHandle
82
83// constructor
84FileHandle::FileHandle()
85	: fFD(-1)
86{
87}
88
89// destructor
90FileHandle::~FileHandle()
91{
92	Close();
93}
94
95// Open
96status_t
97FileHandle::Open(Node* node, int openMode)
98{
99	if (!node)
100		return B_BAD_VALUE;
101
102	openMode &= O_RWMASK | O_TRUNC | O_APPEND;
103
104	// get a path
105	Path path;
106	status_t error = node->GetPath(&path);
107	if (error != B_OK)
108		return error;
109
110	// open the file
111	error = FDManager::Open(path.GetPath(), openMode | O_NOTRAVERSE, 0, fFD);
112	if (error != B_OK)
113		return error;
114
115	fNodeRef = node->GetNodeRef();
116
117	return B_OK;
118}
119
120// Close
121status_t
122FileHandle::Close()
123{
124	if (fFD < 0)
125		return B_BAD_VALUE;
126
127	status_t error = B_OK;
128	if (close(fFD) < 0)
129		error = errno;
130	fFD = -1;
131
132	return error;
133}
134
135// Read
136status_t
137FileHandle::Read(off_t pos, void* buffer, size_t size, size_t* _bytesRead)
138{
139	if (fFD < 0)
140		return B_BAD_VALUE;
141
142	ssize_t bytesRead = read_pos(fFD, pos, buffer, size);
143	if (bytesRead < 0)
144		return errno;
145
146	*_bytesRead = bytesRead;
147	return B_OK;
148}
149
150// Write
151status_t
152FileHandle::Write(off_t pos, const void* buffer, size_t size,
153	size_t* _bytesWritten)
154{
155	if (fFD < 0)
156		return B_BAD_VALUE;
157
158	ssize_t bytesWritten = write_pos(fFD, pos, buffer, size);
159	if (bytesWritten < 0)
160		return errno;
161
162	*_bytesWritten = bytesWritten;
163	return B_OK;
164}
165
166// ReadAttr
167status_t
168FileHandle::ReadAttr(const char* name, uint32 type, off_t pos, void* buffer,
169	size_t size, size_t* _bytesRead)
170{
171	if (fFD < 0)
172		return B_BAD_VALUE;
173
174	ssize_t bytesRead = fs_read_attr(fFD, name, type, pos, buffer, size);
175	if (bytesRead < 0)
176		return errno;
177
178	*_bytesRead = bytesRead;
179	return B_OK;
180}
181
182// WriteAttr
183status_t
184FileHandle::WriteAttr(const char* name, uint32 type, off_t pos,
185	const void* buffer, size_t size, size_t* _bytesWritten)
186{
187	if (fFD < 0)
188		return B_BAD_VALUE;
189
190	ssize_t bytesWritten = fs_write_attr(fFD, name, type, pos, buffer, size);
191	if (bytesWritten < 0)
192		return errno;
193
194	*_bytesWritten = bytesWritten;
195	return B_OK;
196}
197
198// RemoveAttr
199status_t
200FileHandle::RemoveAttr(const char* name)
201{
202	if (fFD < 0)
203		return B_BAD_VALUE;
204
205	return (fs_remove_attr(fFD, name) == 0 ? B_OK : errno);
206}
207
208// StatAttr
209status_t
210FileHandle::StatAttr(const char* name, attr_info* info)
211{
212	if (fFD < 0)
213		return B_BAD_VALUE;
214
215	return (fs_stat_attr(fFD, name, info) == 0 ? B_OK : errno);
216}
217
218// GetFD
219int
220FileHandle::GetFD() const
221{
222	return fFD;
223}
224
225
226// #pragma mark -
227
228// DirIterator
229
230// constructor
231DirIterator::DirIterator()
232	: fDirectory(NULL)
233{
234}
235
236// destructor
237DirIterator::~DirIterator()
238{
239	if (fDirectory)
240		fDirectory->RemoveDirIterator(this);
241}
242
243// IsValid
244bool
245DirIterator::IsValid() const
246{
247	return fDirectory;
248}
249
250
251// #pragma mark -
252
253// AttrDirIterator
254
255// constructor
256AttrDirIterator::AttrDirIterator()
257	: NodeHandle(),
258	  fDir(NULL)
259{
260}
261
262// destructor
263AttrDirIterator::~AttrDirIterator()
264{
265	Close();
266}
267
268// Open
269status_t
270AttrDirIterator::Open(Node* node)
271{
272	if (!node)
273		return B_BAD_VALUE;
274
275	// get a path
276	Path path;
277	status_t error = node->GetPath(&path);
278	if (error != B_OK)
279		return error;
280
281	// open the attribute directory
282	error = FDManager::OpenAttrDir(path.GetPath(), fDir);
283	if (error != B_OK)
284		return errno;
285
286	fNodeRef = node->GetNodeRef();
287
288	return B_OK;
289}
290
291// Close
292status_t
293AttrDirIterator::Close()
294{
295	if (!fDir)
296		return B_BAD_VALUE;
297
298	status_t error = B_OK;
299	if (fs_close_attr_dir(fDir) < 0)
300		error = errno;
301
302	fDir = NULL;
303	return error;
304}
305
306// ReadDir
307status_t
308AttrDirIterator::ReadDir(dirent* _entry, int32 bufferSize,
309	int32 count, int32* countRead, bool* done)
310{
311// TODO: Burst read.
312	if (!fDir)
313		return B_ENTRY_NOT_FOUND;
314
315	*countRead = 0;
316	*done = false;
317
318	if (count == 0)
319		return B_OK;
320
321	if (struct dirent* entry = fs_read_attr_dir(fDir)) {
322		size_t entryLen = entry->d_name + strlen(entry->d_name) + 1
323			- (char*)entry;
324		memcpy(_entry, entry, entryLen);
325		*countRead = 1;
326	} else {
327		*countRead = 0;
328		*done = true;
329	}
330	return B_OK;
331}
332
333// RewindDir
334status_t
335AttrDirIterator::RewindDir()
336{
337	if (!fDir)
338		return B_ENTRY_NOT_FOUND;
339
340	fs_rewind_attr_dir(fDir);
341
342	return B_OK;
343}
344
345// GetFD
346int
347AttrDirIterator::GetFD() const
348{
349	return dirfd(fDir);
350}
351
352
353// #pragma mark -
354
355// QueryListener
356
357// constructor
358QueryListener::QueryListener()
359{
360}
361
362// destructor
363QueryListener::~QueryListener()
364{
365}
366
367
368// #pragma mark -
369
370// QueryHandle
371
372// constructor
373QueryHandle::QueryHandle(port_id remotePort, int32 remoteToken)
374	: NodeHandle(),
375	  fRemotePort(remotePort),
376	  fRemoteToken(remoteToken),
377	  fQueries(),
378	  fCurrentQuery(NULL),
379	  fListener(NULL),
380	  fClosed(false)
381{
382}
383
384// destructor
385QueryHandle::~QueryHandle()
386{
387	Close();
388}
389
390// SetQueryListener
391void
392QueryHandle::SetQueryListener(QueryListener* listener)
393{
394	fListener = listener;
395}
396
397// GetQueryListener
398QueryListener*
399QueryHandle::GetQueryListener() const
400{
401	return fListener;
402}
403
404// AddQuery
405void
406QueryHandle::AddQuery(Query* query)
407{
408	if (query) {
409		fQueries.Insert(query);
410		if (!fCurrentQuery)
411			fCurrentQuery = query;
412	}
413}
414
415// RemoveQuery
416void
417QueryHandle::RemoveQuery(Query* query)
418{
419	if (query) {
420		if (query == fCurrentQuery)
421			fCurrentQuery = fQueries.GetNext(query);
422		fQueries.Remove(query);
423	}
424}
425
426// GetRemotePort
427port_id
428QueryHandle::GetRemotePort() const
429{
430	return fRemotePort;
431}
432
433// GetRemoteToken
434int32
435QueryHandle::GetRemoteToken() const
436{
437	return fRemoteToken;
438}
439
440// Close
441status_t
442QueryHandle::Close()
443{
444	if (fClosed)
445		return B_OK;
446
447	fCurrentQuery = NULL;
448
449	// delete all queries
450	for (DoublyLinkedList<Query>::Iterator it = fQueries.GetIterator();
451			it.HasNext();) {
452		Query* query = it.Next();
453		it.Remove();
454		delete query;
455	}
456
457	fClosed = true;
458
459	if (fListener)
460		fListener->QueryHandleClosed(this);
461
462	return B_OK;
463}
464
465// ReadDir
466status_t
467QueryHandle::ReadDir(dirent* entry, int32 count, int32* countRead)
468{
469	if (count == 0) {
470		*countRead = 0;
471		return B_OK;
472	}
473	while (fCurrentQuery) {
474		int32 readEntries = fCurrentQuery->GetNextDirents(entry,
475			offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH, 1);
476		if (readEntries < 0)
477			return readEntries;
478		if (readEntries > 0) {
479			*countRead = 1;
480			return B_OK;
481		}
482		fCurrentQuery = fQueries.GetNext(fCurrentQuery);
483	}
484	*countRead = 0;
485	return B_OK;
486}
487
488