1 /*
2 * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6 #include "BeOSKernelVolume.h"
7
8 #include <new>
9
10 #include <fcntl.h>
11 #include <unistd.h>
12
13 #include "Debug.h"
14
15 #include "../kernel_emu.h"
16
17 #include "BeOSKernelFileSystem.h"
18 #include "fs_interface.h"
19
20
21 using std::nothrow;
22
23 static int open_mode_to_access(int openMode);
24
25
26 // AttributeCookie
27 class BeOSKernelVolume::AttributeCookie {
28 public:
AttributeCookie(const char * name,uint32 type,int openMode,bool exists,bool create)29 AttributeCookie(const char* name, uint32 type, int openMode, bool exists,
30 bool create)
31 : fType(type),
32 fOpenMode(openMode),
33 fExists(exists),
34 fCreate(create)
35 {
36 strcpy(fName, name);
37 }
38
39 char fName[B_ATTR_NAME_LENGTH];
40 uint32 fType;
41 int fOpenMode;
42 bool fExists;
43 bool fCreate;
44 };
45
46
47 // _FileSystem
48 inline BeOSKernelFileSystem*
_FileSystem() const49 BeOSKernelVolume::_FileSystem() const
50 {
51 return static_cast<BeOSKernelFileSystem*>(fFileSystem);
52 }
53
54
55 // constructor
BeOSKernelVolume(FileSystem * fileSystem,dev_t id,beos_vnode_ops * fsOps,const FSVolumeCapabilities & capabilities)56 BeOSKernelVolume::BeOSKernelVolume(FileSystem* fileSystem, dev_t id,
57 beos_vnode_ops* fsOps, const FSVolumeCapabilities& capabilities)
58 :
59 Volume(fileSystem, id),
60 fFSOps(fsOps),
61 fVolumeCookie(NULL),
62 fMounted(false)
63 {
64 fCapabilities = capabilities;
65 }
66
67 // destructor
~BeOSKernelVolume()68 BeOSKernelVolume::~BeOSKernelVolume()
69 {
70 }
71
72 // #pragma mark -
73 // #pragma mark ----- FS -----
74
75 // Mount
76 status_t
Mount(const char * device,uint32 flags,const char * parameters,ino_t * rootID)77 BeOSKernelVolume::Mount(const char* device, uint32 flags,
78 const char* parameters, ino_t* rootID)
79 {
80 if (!fFSOps->mount)
81 return B_BAD_VALUE;
82
83 size_t len = (parameters ? strlen(parameters) : 0);
84 status_t error = fFSOps->mount(GetID(), device, flags, (void*)parameters,
85 len, &fVolumeCookie, rootID);
86 if (error != B_OK)
87 return error;
88
89 fMounted = true;
90 return B_OK;
91 }
92
93 // Unmount
94 status_t
Unmount()95 BeOSKernelVolume::Unmount()
96 {
97 if (!fFSOps->unmount)
98 return B_BAD_VALUE;
99 return fFSOps->unmount(fVolumeCookie);
100 }
101
102 // Sync
103 status_t
Sync()104 BeOSKernelVolume::Sync()
105 {
106 if (!fFSOps->sync)
107 return B_BAD_VALUE;
108 return fFSOps->sync(fVolumeCookie);
109 }
110
111 // ReadFSInfo
112 status_t
ReadFSInfo(fs_info * info)113 BeOSKernelVolume::ReadFSInfo(fs_info* info)
114 {
115 if (!fFSOps->rfsstat)
116 return B_BAD_VALUE;
117
118 // Haiku's fs_info equals BeOS's version
119 return fFSOps->rfsstat(fVolumeCookie, (beos_fs_info*)info);
120 }
121
122 // WriteFSInfo
123 status_t
WriteFSInfo(const struct fs_info * info,uint32 mask)124 BeOSKernelVolume::WriteFSInfo(const struct fs_info* info, uint32 mask)
125 {
126 if (!fFSOps->wfsstat)
127 return B_BAD_VALUE;
128
129 // Haiku's fs_info equals BeOS's version
130 return fFSOps->wfsstat(fVolumeCookie, (beos_fs_info*)info, (long)mask);
131 }
132
133
134 // #pragma mark - vnodes
135
136
137 // Lookup
138 status_t
Lookup(void * dir,const char * entryName,ino_t * vnid)139 BeOSKernelVolume::Lookup(void* dir, const char* entryName, ino_t* vnid)
140 {
141 if (!fFSOps->walk)
142 return B_BAD_VALUE;
143 return fFSOps->walk(fVolumeCookie, dir, entryName, NULL, vnid);
144 }
145
146
147 // GetVNodeType
148 status_t
GetVNodeType(void * node,int * type)149 BeOSKernelVolume::GetVNodeType(void* node, int* type)
150 {
151 if (fMounted) {
152 // The volume is mounted. We can stat() the node to get its type.
153 struct stat st;
154 status_t error = ReadStat(node, &st);
155 if (error != B_OK)
156 return error;
157
158 *type = st.st_mode & S_IFMT;
159 } else {
160 // Not mounted yet. That particularly means we don't have a volume
161 // cookie yet and cannot use calls into the FS to get the node type.
162 // Just assume the node is a directory. That definitely is the case for
163 // the root node and shouldn't do harm for the index directory or
164 // indices, which could get published while mounting as well.
165 *type = S_IFDIR;
166 // TODO: Store the concerned nodes and check their type as soon as
167 // possible (at the end of Mount()). The incorrect ones could be
168 // corrected in the kernel: remove_vnode(), x*put_vnode() (catching
169 // the "remove_vnode()" callback), publish_vnode(),
170 // (x-1)*get_vnode().
171 }
172
173 return B_OK;
174 }
175
176
177 // ReadVNode
178 status_t
ReadVNode(ino_t vnid,bool reenter,void ** node,int * type,uint32 * flags,FSVNodeCapabilities * _capabilities)179 BeOSKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** node, int* type,
180 uint32* flags, FSVNodeCapabilities* _capabilities)
181 {
182 if (!fFSOps->read_vnode)
183 return B_BAD_VALUE;
184
185 // get the node
186 status_t error = fFSOps->read_vnode(fVolumeCookie, vnid, (char)reenter,
187 node);
188 if (error != B_OK)
189 return error;
190
191 // stat it -- we need to get the node type
192 struct stat st;
193 error = ReadStat(*node, &st);
194 if (error != B_OK) {
195 WriteVNode(*node, reenter);
196 return error;
197 }
198
199 *type = (st.st_mode & S_IFMT);
200 *flags = 0;
201 _FileSystem()->GetNodeCapabilities(*_capabilities);
202
203 return B_OK;
204 }
205
206 // WriteVNode
207 status_t
WriteVNode(void * node,bool reenter)208 BeOSKernelVolume::WriteVNode(void* node, bool reenter)
209 {
210 if (!fFSOps->write_vnode)
211 return B_BAD_VALUE;
212 return fFSOps->write_vnode(fVolumeCookie, node, (char)reenter);
213 }
214
215 // RemoveVNode
216 status_t
RemoveVNode(void * node,bool reenter)217 BeOSKernelVolume::RemoveVNode(void* node, bool reenter)
218 {
219 if (!fFSOps->remove_vnode)
220 return B_BAD_VALUE;
221 return fFSOps->remove_vnode(fVolumeCookie, node, (char)reenter);
222 }
223
224
225 // #pragma mark - nodes
226
227
228 // IOCtl
229 status_t
IOCtl(void * node,void * cookie,uint32 command,void * buffer,size_t size)230 BeOSKernelVolume::IOCtl(void* node, void* cookie, uint32 command,
231 void* buffer, size_t size)
232 {
233 if (!fFSOps->ioctl)
234 return B_BAD_VALUE;
235 return fFSOps->ioctl(fVolumeCookie, node, cookie, (int)command, buffer,
236 size);
237 }
238
239 // SetFlags
240 status_t
SetFlags(void * node,void * cookie,int flags)241 BeOSKernelVolume::SetFlags(void* node, void* cookie, int flags)
242 {
243 if (!fFSOps->setflags)
244 return B_BAD_VALUE;
245 return fFSOps->setflags(fVolumeCookie, node, cookie, flags);
246 }
247
248 // Select
249 status_t
Select(void * node,void * cookie,uint8 event,selectsync * sync)250 BeOSKernelVolume::Select(void* node, void* cookie, uint8 event,
251 selectsync* sync)
252 {
253 if (!fFSOps->select) {
254 UserlandFS::KernelEmu::notify_select_event(sync, event, false);
255 return B_OK;
256 }
257 return fFSOps->select(fVolumeCookie, node, cookie, event, 0, sync);
258 }
259
260 // Deselect
261 status_t
Deselect(void * node,void * cookie,uint8 event,selectsync * sync)262 BeOSKernelVolume::Deselect(void* node, void* cookie, uint8 event,
263 selectsync* sync)
264 {
265 if (!fFSOps->select || !fFSOps->deselect)
266 return B_OK;
267 return fFSOps->deselect(fVolumeCookie, node, cookie, event, sync);
268 }
269
270 // FSync
271 status_t
FSync(void * node)272 BeOSKernelVolume::FSync(void* node)
273 {
274 if (!fFSOps->fsync)
275 return B_BAD_VALUE;
276 return fFSOps->fsync(fVolumeCookie, node);
277 }
278
279 // ReadSymlink
280 status_t
ReadSymlink(void * node,char * buffer,size_t bufferSize,size_t * bytesRead)281 BeOSKernelVolume::ReadSymlink(void* node, char* buffer, size_t bufferSize,
282 size_t* bytesRead)
283 {
284 if (!fFSOps->readlink)
285 return B_BAD_VALUE;
286 *bytesRead = bufferSize;
287 return fFSOps->readlink(fVolumeCookie, node, buffer, bytesRead);
288 }
289
290 // CreateSymlink
291 status_t
CreateSymlink(void * dir,const char * name,const char * target,int mode)292 BeOSKernelVolume::CreateSymlink(void* dir, const char* name,
293 const char* target, int mode)
294 {
295 if (!fFSOps->symlink)
296 return B_BAD_VALUE;
297 // TODO: Don't ignore mode?
298 return fFSOps->symlink(fVolumeCookie, dir, name, target);
299 }
300
301 // Link
302 status_t
Link(void * dir,const char * name,void * node)303 BeOSKernelVolume::Link(void* dir, const char* name, void* node)
304 {
305 if (!fFSOps->link)
306 return B_BAD_VALUE;
307 return fFSOps->link(fVolumeCookie, dir, name, node);
308 }
309
310 // Unlink
311 status_t
Unlink(void * dir,const char * name)312 BeOSKernelVolume::Unlink(void* dir, const char* name)
313 {
314 if (!fFSOps->unlink)
315 return B_BAD_VALUE;
316 return fFSOps->unlink(fVolumeCookie, dir, name);
317 }
318
319 // Rename
320 status_t
Rename(void * oldDir,const char * oldName,void * newDir,const char * newName)321 BeOSKernelVolume::Rename(void* oldDir, const char* oldName, void* newDir,
322 const char* newName)
323 {
324 if (!fFSOps->rename)
325 return B_BAD_VALUE;
326 return fFSOps->rename(fVolumeCookie, oldDir, oldName, newDir, newName);
327 }
328
329 // Access
330 status_t
Access(void * node,int mode)331 BeOSKernelVolume::Access(void* node, int mode)
332 {
333 if (!fFSOps->access)
334 return B_OK;
335 return fFSOps->access(fVolumeCookie, node, mode);
336 }
337
338 // ReadStat
339 status_t
ReadStat(void * node,struct stat * st)340 BeOSKernelVolume::ReadStat(void* node, struct stat* st)
341 {
342 if (!fFSOps->rstat)
343 return B_BAD_VALUE;
344
345 // Haiku's struct stat has an additional st_type field (for an attribute
346 // type), but that doesn't matter here
347 return fFSOps->rstat(fVolumeCookie, node, (struct beos_stat*)st);
348 }
349
350 // WriteStat
351 status_t
WriteStat(void * node,const struct stat * st,uint32 mask)352 BeOSKernelVolume::WriteStat(void* node, const struct stat *st, uint32 mask)
353 {
354 if (!fFSOps->wstat)
355 return B_BAD_VALUE;
356
357 // Haiku's struct stat has an additional st_type field (for an attribute
358 // type), but that doesn't matter here
359 return fFSOps->wstat(fVolumeCookie, node, (struct beos_stat*)st,
360 (long)mask);
361 }
362
363
364 // #pragma mark - files
365
366
367 // Create
368 status_t
Create(void * dir,const char * name,int openMode,int mode,void ** cookie,ino_t * vnid)369 BeOSKernelVolume::Create(void* dir, const char* name, int openMode, int mode,
370 void** cookie, ino_t* vnid)
371 {
372 if (!fFSOps->create)
373 return B_BAD_VALUE;
374 return fFSOps->create(fVolumeCookie, dir, name, openMode, mode, vnid,
375 cookie);
376 }
377
378 // Open
379 status_t
Open(void * node,int openMode,void ** cookie)380 BeOSKernelVolume::Open(void* node, int openMode, void** cookie)
381 {
382 if (!fFSOps->open)
383 return B_BAD_VALUE;
384 return fFSOps->open(fVolumeCookie, node, openMode, cookie);
385 }
386
387 // Close
388 status_t
Close(void * node,void * cookie)389 BeOSKernelVolume::Close(void* node, void* cookie)
390 {
391 if (!fFSOps->close)
392 return B_OK;
393 return fFSOps->close(fVolumeCookie, node, cookie);
394 }
395
396 // FreeCookie
397 status_t
FreeCookie(void * node,void * cookie)398 BeOSKernelVolume::FreeCookie(void* node, void* cookie)
399 {
400 if (!fFSOps->free_cookie)
401 return B_OK;
402 return fFSOps->free_cookie(fVolumeCookie, node, cookie);
403 }
404
405 // Read
406 status_t
Read(void * node,void * cookie,off_t pos,void * buffer,size_t bufferSize,size_t * bytesRead)407 BeOSKernelVolume::Read(void* node, void* cookie, off_t pos, void* buffer,
408 size_t bufferSize, size_t* bytesRead)
409 {
410 if (!fFSOps->read)
411 return B_BAD_VALUE;
412 *bytesRead = bufferSize;
413 return fFSOps->read(fVolumeCookie, node, cookie, pos, buffer, bytesRead);
414 }
415
416 // Write
417 status_t
Write(void * node,void * cookie,off_t pos,const void * buffer,size_t bufferSize,size_t * bytesWritten)418 BeOSKernelVolume::Write(void* node, void* cookie, off_t pos,
419 const void* buffer, size_t bufferSize, size_t* bytesWritten)
420 {
421 if (!fFSOps->write)
422 return B_BAD_VALUE;
423 *bytesWritten = bufferSize;
424 return fFSOps->write(fVolumeCookie, node, cookie, pos, buffer,
425 bytesWritten);
426 }
427
428
429 // #pragma mark - directories
430
431
432 // CreateDir
433 status_t
CreateDir(void * dir,const char * name,int mode)434 BeOSKernelVolume::CreateDir(void* dir, const char* name, int mode)
435 {
436 if (!fFSOps->mkdir)
437 return B_BAD_VALUE;
438
439 return fFSOps->mkdir(fVolumeCookie, dir, name, mode);
440 }
441
442 // RemoveDir
443 status_t
RemoveDir(void * dir,const char * name)444 BeOSKernelVolume::RemoveDir(void* dir, const char* name)
445 {
446 if (!fFSOps->rmdir)
447 return B_BAD_VALUE;
448 return fFSOps->rmdir(fVolumeCookie, dir, name);
449 }
450
451 // OpenDir
452 status_t
OpenDir(void * node,void ** cookie)453 BeOSKernelVolume::OpenDir(void* node, void** cookie)
454 {
455 if (!fFSOps->opendir)
456 return B_BAD_VALUE;
457 return fFSOps->opendir(fVolumeCookie, node, cookie);
458 }
459
460 // CloseDir
461 status_t
CloseDir(void * node,void * cookie)462 BeOSKernelVolume::CloseDir(void* node, void* cookie)
463 {
464 if (!fFSOps->closedir)
465 return B_OK;
466 return fFSOps->closedir(fVolumeCookie, node, cookie);
467 }
468
469 // FreeDirCookie
470 status_t
FreeDirCookie(void * node,void * cookie)471 BeOSKernelVolume::FreeDirCookie(void* node, void* cookie)
472 {
473 if (!fFSOps->free_dircookie)
474 return B_OK;
475 return fFSOps->free_dircookie(fVolumeCookie, node, cookie);
476 }
477
478 // ReadDir
479 status_t
ReadDir(void * node,void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)480 BeOSKernelVolume::ReadDir(void* node, void* cookie, void* buffer,
481 size_t bufferSize, uint32 count, uint32* countRead)
482 {
483 if (!fFSOps->readdir)
484 return B_BAD_VALUE;
485
486 *countRead = count;
487
488 // Haiku's struct dirent equals BeOS's version
489 return fFSOps->readdir(fVolumeCookie, node, cookie, (long*)countRead,
490 (beos_dirent*)buffer, bufferSize);
491 }
492
493 // RewindDir
494 status_t
RewindDir(void * node,void * cookie)495 BeOSKernelVolume::RewindDir(void* node, void* cookie)
496 {
497 if (!fFSOps->rewinddir)
498 return B_BAD_VALUE;
499 return fFSOps->rewinddir(fVolumeCookie, node, cookie);
500 }
501
502
503 // #pragma mark - attribute directories
504
505
506 // OpenAttrDir
507 status_t
OpenAttrDir(void * node,void ** cookie)508 BeOSKernelVolume::OpenAttrDir(void* node, void** cookie)
509 {
510 if (!fFSOps->open_attrdir)
511 return B_BAD_VALUE;
512 return fFSOps->open_attrdir(fVolumeCookie, node, cookie);
513 }
514
515 // CloseAttrDir
516 status_t
CloseAttrDir(void * node,void * cookie)517 BeOSKernelVolume::CloseAttrDir(void* node, void* cookie)
518 {
519 if (!fFSOps->close_attrdir)
520 return B_OK;
521 return fFSOps->close_attrdir(fVolumeCookie, node, cookie);
522 }
523
524 // FreeAttrDirCookie
525 status_t
FreeAttrDirCookie(void * node,void * cookie)526 BeOSKernelVolume::FreeAttrDirCookie(void* node, void* cookie)
527 {
528 if (!fFSOps->free_attrdircookie)
529 return B_OK;
530 return fFSOps->free_attrdircookie(fVolumeCookie, node, cookie);
531 }
532
533 // ReadAttrDir
534 status_t
ReadAttrDir(void * node,void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)535 BeOSKernelVolume::ReadAttrDir(void* node, void* cookie, void* buffer,
536 size_t bufferSize, uint32 count, uint32* countRead)
537 {
538 if (!fFSOps->read_attrdir)
539 return B_BAD_VALUE;
540
541 *countRead = count;
542
543 // Haiku's struct dirent equals BeOS's version
544 return fFSOps->read_attrdir(fVolumeCookie, node, cookie, (long*)countRead,
545 (struct beos_dirent*)buffer, bufferSize);
546 }
547
548 // RewindAttrDir
549 status_t
RewindAttrDir(void * node,void * cookie)550 BeOSKernelVolume::RewindAttrDir(void* node, void* cookie)
551 {
552 if (!fFSOps->rewind_attrdir)
553 return B_BAD_VALUE;
554 return fFSOps->rewind_attrdir(fVolumeCookie, node, cookie);
555 }
556
557
558 // #pragma mark - attributes
559
560
561 // CreateAttr
562 status_t
CreateAttr(void * node,const char * name,uint32 type,int openMode,void ** cookie)563 BeOSKernelVolume::CreateAttr(void* node, const char* name, uint32 type,
564 int openMode, void** cookie)
565 {
566 return _OpenAttr(node, name, type, openMode, true, cookie);
567 }
568
569 // OpenAttr
570 status_t
OpenAttr(void * node,const char * name,int openMode,void ** cookie)571 BeOSKernelVolume::OpenAttr(void* node, const char* name, int openMode,
572 void** cookie)
573 {
574 return _OpenAttr(node, name, 0, openMode, false, cookie);
575 }
576
577 // CloseAttr
578 status_t
CloseAttr(void * node,void * cookie)579 BeOSKernelVolume::CloseAttr(void* node, void* cookie)
580 {
581 return B_OK;
582 }
583
584 // FreeAttrCookie
585 status_t
FreeAttrCookie(void * node,void * _cookie)586 BeOSKernelVolume::FreeAttrCookie(void* node, void* _cookie)
587 {
588 AttributeCookie* cookie = (AttributeCookie*)_cookie;
589
590 // If the attribute doesn't exist yet and it was opened with
591 // CreateAttr(), we could create it now. We have a race condition here
592 // though, since someone else could have created it in the meantime.
593
594 delete cookie;
595
596 return B_OK;
597 }
598
599 // ReadAttr
600 status_t
ReadAttr(void * node,void * _cookie,off_t pos,void * buffer,size_t bufferSize,size_t * bytesRead)601 BeOSKernelVolume::ReadAttr(void* node, void* _cookie, off_t pos,
602 void* buffer, size_t bufferSize, size_t* bytesRead)
603 {
604 AttributeCookie* cookie = (AttributeCookie*)_cookie;
605
606 // check, if open mode allows reading
607 if ((open_mode_to_access(cookie->fOpenMode) & R_OK) == 0)
608 return B_FILE_ERROR;
609
610 // read
611 if (!fFSOps->read_attr)
612 return B_BAD_VALUE;
613
614 *bytesRead = bufferSize;
615 return fFSOps->read_attr(fVolumeCookie, node, cookie->fName, cookie->fType,
616 buffer, bytesRead, pos);
617 }
618
619 // WriteAttr
620 status_t
WriteAttr(void * node,void * _cookie,off_t pos,const void * buffer,size_t bufferSize,size_t * bytesWritten)621 BeOSKernelVolume::WriteAttr(void* node, void* _cookie, off_t pos,
622 const void* buffer, size_t bufferSize, size_t* bytesWritten)
623 {
624 AttributeCookie* cookie = (AttributeCookie*)_cookie;
625
626 // check, if open mode allows writing
627 if ((open_mode_to_access(cookie->fOpenMode) & W_OK) == 0)
628 return B_FILE_ERROR;
629
630 // write
631 if (!fFSOps->write_attr)
632 return B_BAD_VALUE;
633
634 *bytesWritten = bufferSize;
635 return fFSOps->write_attr(fVolumeCookie, node, cookie->fName, cookie->fType,
636 buffer, bytesWritten, pos);
637 }
638
639 // ReadAttrStat
640 status_t
ReadAttrStat(void * node,void * _cookie,struct stat * st)641 BeOSKernelVolume::ReadAttrStat(void* node, void* _cookie,
642 struct stat *st)
643 {
644 AttributeCookie* cookie = (AttributeCookie*)_cookie;
645
646 // get the stats
647 beos_attr_info attrInfo;
648 if (!fFSOps->stat_attr)
649 return B_BAD_VALUE;
650
651 status_t error = fFSOps->stat_attr(fVolumeCookie, node, cookie->fName,
652 &attrInfo);
653 if (error != B_OK)
654 return error;
655
656 // translate to struct stat
657 st->st_size = attrInfo.size;
658 st->st_type = attrInfo.type;
659
660 return B_OK;
661 }
662
663 // RenameAttr
664 status_t
RenameAttr(void * oldNode,const char * oldName,void * newNode,const char * newName)665 BeOSKernelVolume::RenameAttr(void* oldNode, const char* oldName,
666 void* newNode, const char* newName)
667 {
668 if (!fFSOps->rename_attr)
669 return B_BAD_VALUE;
670 if (oldNode != newNode)
671 return B_BAD_VALUE;
672
673 return fFSOps->rename_attr(fVolumeCookie, oldNode, oldName, newName);
674 }
675
676 // RemoveAttr
677 status_t
RemoveAttr(void * node,const char * name)678 BeOSKernelVolume::RemoveAttr(void* node, const char* name)
679 {
680 if (!fFSOps->remove_attr)
681 return B_BAD_VALUE;
682 return fFSOps->remove_attr(fVolumeCookie, node, name);
683 }
684
685
686 // #pragma mark - indices
687
688
689 // OpenIndexDir
690 status_t
OpenIndexDir(void ** cookie)691 BeOSKernelVolume::OpenIndexDir(void** cookie)
692 {
693 if (!fFSOps->open_indexdir)
694 return B_BAD_VALUE;
695 return fFSOps->open_indexdir(fVolumeCookie, cookie);
696 }
697
698 // CloseIndexDir
699 status_t
CloseIndexDir(void * cookie)700 BeOSKernelVolume::CloseIndexDir(void* cookie)
701 {
702 if (!fFSOps->close_indexdir)
703 return B_OK;
704 return fFSOps->close_indexdir(fVolumeCookie, cookie);
705 }
706
707 // FreeIndexDirCookie
708 status_t
FreeIndexDirCookie(void * cookie)709 BeOSKernelVolume::FreeIndexDirCookie(void* cookie)
710 {
711 if (!fFSOps->free_indexdircookie)
712 return B_OK;
713 return fFSOps->free_indexdircookie(fVolumeCookie, NULL, cookie);
714 }
715
716 // ReadIndexDir
717 status_t
ReadIndexDir(void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)718 BeOSKernelVolume::ReadIndexDir(void* cookie, void* buffer,
719 size_t bufferSize, uint32 count, uint32* countRead)
720 {
721 if (!fFSOps->read_indexdir)
722 return B_BAD_VALUE;
723
724 *countRead = count;
725
726 // Haiku's struct dirent equals BeOS's version
727 return fFSOps->read_indexdir(fVolumeCookie, cookie, (long*)countRead,
728 (struct beos_dirent*)buffer, bufferSize);
729 }
730
731 // RewindIndexDir
732 status_t
RewindIndexDir(void * cookie)733 BeOSKernelVolume::RewindIndexDir(void* cookie)
734 {
735 if (!fFSOps->rewind_indexdir)
736 return B_BAD_VALUE;
737 return fFSOps->rewind_indexdir(fVolumeCookie, cookie);
738 }
739
740 // CreateIndex
741 status_t
CreateIndex(const char * name,uint32 type,uint32 flags)742 BeOSKernelVolume::CreateIndex(const char* name, uint32 type, uint32 flags)
743 {
744 if (!fFSOps->create_index)
745 return B_BAD_VALUE;
746 return fFSOps->create_index(fVolumeCookie, name, (int)type, (int)flags);
747 }
748
749 // RemoveIndex
750 status_t
RemoveIndex(const char * name)751 BeOSKernelVolume::RemoveIndex(const char* name)
752 {
753 if (!fFSOps->remove_index)
754 return B_BAD_VALUE;
755 return fFSOps->remove_index(fVolumeCookie, name);
756 }
757
758 // StatIndex
759 status_t
ReadIndexStat(const char * name,struct stat * st)760 BeOSKernelVolume::ReadIndexStat(const char *name, struct stat *st)
761 {
762 if (!fFSOps->stat_index)
763 return B_BAD_VALUE;
764
765 beos_index_info indexInfo;
766 status_t error = fFSOps->stat_index(fVolumeCookie, name, &indexInfo);
767 if (error != B_OK)
768 return error;
769
770 // translate index_info into struct stat
771 st->st_type = indexInfo.type;
772 st->st_size = indexInfo.size;
773 st->st_mtime = indexInfo.modification_time;
774 st->st_crtime = indexInfo.creation_time;
775 st->st_uid = indexInfo.uid;
776 st->st_gid = indexInfo.gid;
777
778 return B_OK;
779 }
780
781
782 // #pragma mark - queries
783
784
785 // OpenQuery
786 status_t
OpenQuery(const char * queryString,uint32 flags,port_id port,uint32 token,void ** cookie)787 BeOSKernelVolume::OpenQuery(const char* queryString, uint32 flags, port_id port,
788 uint32 token, void** cookie)
789 {
790 if (!fFSOps->open_query)
791 return B_BAD_VALUE;
792 return fFSOps->open_query(fVolumeCookie, queryString, flags, port,
793 (long)token, cookie);
794 }
795
796 // CloseQuery
797 status_t
CloseQuery(void * cookie)798 BeOSKernelVolume::CloseQuery(void* cookie)
799 {
800 if (!fFSOps->close_query)
801 return B_OK;
802 return fFSOps->close_query(fVolumeCookie, cookie);
803 }
804
805 // FreeQueryCookie
806 status_t
FreeQueryCookie(void * cookie)807 BeOSKernelVolume::FreeQueryCookie(void* cookie)
808 {
809 if (!fFSOps->free_querycookie)
810 return B_OK;
811 return fFSOps->free_querycookie(fVolumeCookie, NULL, cookie);
812 }
813
814 // ReadQuery
815 status_t
ReadQuery(void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)816 BeOSKernelVolume::ReadQuery(void* cookie, void* buffer, size_t bufferSize,
817 uint32 count, uint32* countRead)
818 {
819 if (!fFSOps->read_query)
820 return B_BAD_VALUE;
821
822 *countRead = count;
823
824 // Haiku's struct dirent equals BeOS's version
825 return fFSOps->read_query(fVolumeCookie, cookie, (long*)countRead,
826 (struct beos_dirent*)buffer, bufferSize);
827 }
828
829
830 // #pragma mark - Private
831
832
833 // _OpenAttr
834 status_t
_OpenAttr(void * node,const char * name,uint32 type,int openMode,bool create,void ** _cookie)835 BeOSKernelVolume::_OpenAttr(void* node, const char* name, uint32 type,
836 int openMode, bool create, void** _cookie)
837 {
838 // check permissions first
839 int accessMode = open_mode_to_access(openMode) | (create ? W_OK : 0);
840 status_t error = Access(node, accessMode);
841 if (error != B_OK)
842 return error;
843
844 // check whether the attribute already exists
845 beos_attr_info attrInfo;
846 if (!fFSOps->stat_attr)
847 return B_BAD_VALUE;
848 bool exists
849 = (fFSOps->stat_attr(fVolumeCookie, node, name, &attrInfo) == B_OK);
850
851 if (create) {
852 // create: fail, if attribute exists and non-existence was required
853 if (exists && (openMode & O_EXCL))
854 return B_FILE_EXISTS;
855 } else {
856 // open: fail, if attribute doesn't exist
857 if (!exists)
858 return B_ENTRY_NOT_FOUND;
859
860 // keep the attribute type
861 type = attrInfo.type;
862 }
863
864 // create an attribute cookie
865 AttributeCookie* cookie = new(nothrow) AttributeCookie(name, type,
866 openMode, exists, create);
867 if (!cookie)
868 return B_NO_MEMORY;
869
870 // TODO: If we want to support O_TRUNC, we should do that here.
871
872 *_cookie = cookie;
873 return B_OK;
874 }
875
876 // open_mode_to_access
877 static int
open_mode_to_access(int openMode)878 open_mode_to_access(int openMode)
879 {
880 switch (openMode & O_RWMASK) {
881 case O_RDONLY:
882 return R_OK;
883 case O_WRONLY:
884 return W_OK;
885 case O_RDWR:
886 default:
887 return W_OK | R_OK;
888 }
889 }
890
891