1 /*
2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include "kernel_interface.h"
8
9 #include <dirent.h>
10
11 #include <new>
12
13 #include <fs_info.h>
14 #include <fs_interface.h>
15 #include <KernelExport.h>
16 #include <io_requests.h>
17 #include <slab/Slab.h>
18
19 #include <AutoDeleter.h>
20
21 #include <package/hpkg/PackageFileHeapAccessorBase.h>
22 #include "util/TwoKeyAVLTree.h"
23
24 #include "AttributeCookie.h"
25 #include "AttributeDirectoryCookie.h"
26 #include "DebugSupport.h"
27 #include "Directory.h"
28 #include "Query.h"
29 #include "PackageFSRoot.h"
30 #include "StringConstants.h"
31 #include "StringPool.h"
32 #include "Utils.h"
33 #include "Volume.h"
34
35
36 template<> object_cache* TwoKeyAVLTreeNode<void*>::sNodeCache = NULL;
37
38 static const uint32 kOptimalIOSize = 64 * 1024;
39
40
41 // #pragma mark - helper functions
42
43
44 static bool
lock_directory_for_node(Volume * volume,Node * node,DirectoryReadLocker & locker)45 lock_directory_for_node(Volume* volume, Node* node, DirectoryReadLocker& locker)
46 {
47 if (Directory* directory = dynamic_cast<Directory*>(node)) {
48 locker.SetTo(directory, false, true);
49 return locker.IsLocked();
50 } else {
51 BReference<Directory> parentRef = node->GetParent();
52 if (!parentRef.IsSet())
53 return false;
54 locker.SetTo(parentRef.Get(), false, true);
55 return locker.IsLocked() && node->GetParentUnchecked() == locker.Get();
56 }
57 }
58
59
60 static status_t
check_access(Node * node,int mode)61 check_access(Node* node, int mode)
62 {
63 // write access requested?
64 if (mode & W_OK)
65 return B_READ_ONLY_DEVICE;
66
67 return check_access_permissions(mode, node->Mode(), node->GroupID(),
68 node->UserID());
69 }
70
71
72 // #pragma mark - Volume
73
74
75 static status_t
packagefs_mount(fs_volume * fsVolume,const char * device,uint32 flags,const char * parameters,ino_t * _rootID)76 packagefs_mount(fs_volume* fsVolume, const char* device, uint32 flags,
77 const char* parameters, ino_t* _rootID)
78 {
79 FUNCTION("fsVolume: %p, device: \"%s\", flags: %#" B_PRIx32 ", parameters: "
80 "\"%s\"\n", fsVolume, device, flags, parameters);
81
82 // create a Volume object
83 Volume* volume = new(std::nothrow) Volume(fsVolume);
84 if (volume == NULL)
85 RETURN_ERROR(B_NO_MEMORY);
86 VolumeWriteLocker volumeWriteLocker(volume);
87
88 // Initialize the fs_volume now already, so it is mostly usable in during
89 // mounting.
90 fsVolume->private_volume = volume;
91 fsVolume->ops = &gPackageFSVolumeOps;
92
93 status_t error = volume->Mount(parameters);
94 if (error != B_OK) {
95 volumeWriteLocker.Unlock();
96 delete volume;
97 return error;
98 }
99
100 // set return values
101 *_rootID = volume->RootDirectory()->ID();
102
103 return B_OK;
104 }
105
106
107 static status_t
packagefs_unmount(fs_volume * fsVolume)108 packagefs_unmount(fs_volume* fsVolume)
109 {
110 Volume* volume = (Volume*)fsVolume->private_volume;
111
112 FUNCTION("volume: %p\n", volume);
113
114 volume->WriteLock();
115 volume->Unmount();
116 delete volume;
117
118 return B_OK;
119 }
120
121
122 static status_t
packagefs_read_fs_info(fs_volume * fsVolume,struct fs_info * info)123 packagefs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
124 {
125 Volume* volume = (Volume*)fsVolume->private_volume;
126
127 FUNCTION("volume: %p, info: %p\n", volume, info);
128
129 info->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY | B_FS_HAS_MIME
130 | B_FS_HAS_ATTR | B_FS_HAS_QUERY | B_FS_SUPPORTS_NODE_MONITORING;
131 info->block_size = 4096;
132 info->io_size = kOptimalIOSize;
133 info->total_blocks = info->free_blocks = 0;
134 strlcpy(info->volume_name, volume->RootDirectory()->Name(),
135 sizeof(info->volume_name));
136 return B_OK;
137 }
138
139
140 // #pragma mark - VNodes
141
142
143 static status_t
packagefs_lookup(fs_volume * fsVolume,fs_vnode * fsDir,const char * entryName,ino_t * _vnid)144 packagefs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName,
145 ino_t* _vnid)
146 {
147 Volume* volume = (Volume*)fsVolume->private_volume;
148 Node* node = (Node*)fsDir->private_node;
149
150 FUNCTION("volume: %p, dir: %p (%" B_PRId64 "), entry: \"%s\"\n", volume,
151 node, node->ID(), entryName);
152
153 if (!S_ISDIR(node->Mode()))
154 return B_NOT_A_DIRECTORY;
155
156 Directory* dir = dynamic_cast<Directory*>(node);
157
158 // resolve "."
159 if (strcmp(entryName, ".") == 0) {
160 Node* self;
161 *_vnid = dir->ID();
162 return volume->GetVNode(*_vnid, self);
163 }
164
165 // resolve ".."
166 if (strcmp(entryName, "..") == 0) {
167 Node* parent;
168 *_vnid = dir->GetParentUnchecked()->ID();
169 return volume->GetVNode(*_vnid, parent);
170 }
171
172 // resolve normal entries -- look up the node
173 DirectoryReadLocker dirLocker(dir);
174 String entryNameString;
175 Node* child = dir->FindChild(StringKey(entryName));
176 if (child == NULL)
177 return B_ENTRY_NOT_FOUND;
178 BReference<Node> childReference(child);
179 dirLocker.Unlock();
180
181 // get the vnode reference
182 *_vnid = child->ID();
183 RETURN_ERROR(volume->GetVNode(*_vnid, child));
184 }
185
186
187 static status_t
packagefs_get_vnode_name(fs_volume * fsVolume,fs_vnode * fsNode,char * buffer,size_t bufferSize)188 packagefs_get_vnode_name(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
189 size_t bufferSize)
190 {
191 Node* node = (Node*)fsNode->private_node;
192
193 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), %p, %zu\n",
194 fsVolume->private_volume, node, node->ID(), buffer, bufferSize);
195
196 if (strlcpy(buffer, node->Name(), bufferSize) >= bufferSize)
197 return B_BUFFER_OVERFLOW;
198
199 return B_OK;
200 }
201
202
203 static status_t
packagefs_get_vnode(fs_volume * fsVolume,ino_t vnid,fs_vnode * fsNode,int * _type,uint32 * _flags,bool reenter)204 packagefs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode,
205 int* _type, uint32* _flags, bool reenter)
206 {
207 Volume* volume = (Volume*)fsVolume->private_volume;
208
209 FUNCTION("volume: %p, vnid: %" B_PRId64 "\n", volume, vnid);
210
211 VolumeReadLocker volumeLocker(volume);
212 Node* node = volume->FindNode(vnid);
213 if (node == NULL)
214 return B_ENTRY_NOT_FOUND;
215 BReference<Node> nodeReference(node);
216
217 DirectoryWriteLocker dirLocker;
218 if (Directory* directory = dynamic_cast<Directory*>(node)) {
219 dirLocker.SetTo(directory, false, true);
220 if (!dirLocker.IsLocked())
221 return B_NO_INIT;
222 } else {
223 dirLocker.SetTo(node->GetParentUnchecked(), false, true);
224 if (!dirLocker.IsLocked())
225 return B_NO_INIT;
226 }
227 volumeLocker.Unlock();
228
229 status_t error = node->VFSInit(volume->ID());
230 if (error != B_OK)
231 RETURN_ERROR(error);
232 dirLocker.Unlock();
233
234 fsNode->private_node = nodeReference.Detach();
235 fsNode->ops = &gPackageFSVnodeOps;
236 *_type = node->Mode() & S_IFMT;
237 *_flags = 0;
238
239 return B_OK;
240 }
241
242
243 static status_t
packagefs_put_vnode(fs_volume * fsVolume,fs_vnode * fsNode,bool reenter)244 packagefs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
245 {
246 Volume* volume = (Volume*)fsVolume->private_volume;
247 Node* node = (Node*)fsNode->private_node;
248
249 FUNCTION("volume: %p, node: %p\n", volume, node);
250 TOUCH(volume);
251
252 VolumeReadLocker volumeLocker(volume);
253 DirectoryWriteLocker dirLocker;
254 if (Directory* directory = dynamic_cast<Directory*>(node)) {
255 dirLocker.SetTo(directory, false, true);
256 ASSERT(dirLocker.IsLocked());
257 } else {
258 dirLocker.SetTo(node->GetParentUnchecked(), false, true);
259 if (dirLocker.Get() == NULL) {
260 // This node does not have a parent. This should only happen during
261 // removal, in which case we should either have the Volume write lock,
262 // or the node should have only one reference remaining.
263 ASSERT(volume->IsWriteLocked() || node->CountReferences() == 1);
264 }
265 }
266 volumeLocker.Unlock();
267
268 node->VFSUninit();
269 dirLocker.Unlock();
270
271 node->ReleaseReference();
272
273 return B_OK;
274 }
275
276
277 // #pragma mark - Request I/O
278
279
280 static status_t
packagefs_io(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,io_request * request)281 packagefs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
282 io_request* request)
283 {
284 Volume* volume = (Volume*)fsVolume->private_volume;
285 Node* node = (Node*)fsNode->private_node;
286
287 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p, request: %p\n",
288 volume, node, node->ID(), cookie, request);
289 TOUCH(volume);
290
291 if (io_request_is_write(request))
292 RETURN_ERROR(B_READ_ONLY_DEVICE);
293
294 status_t error = node->Read(request);
295 notify_io_request(request, error);
296 return error;
297 }
298
299
300 // #pragma mark - Nodes
301
302
303 status_t
packagefs_ioctl(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,uint32 operation,void * buffer,size_t size)304 packagefs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
305 uint32 operation, void* buffer, size_t size)
306 {
307 Volume* volume = (Volume*)fsVolume->private_volume;
308 Node* node = (Node*)fsNode->private_node;
309
310 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p, operation: %"
311 B_PRIu32 ", buffer: %p, size: %zu\n", volume, node, node->ID(), cookie,
312 operation, buffer, size);
313 TOUCH(cookie);
314
315 return volume->IOCtl(node, operation, buffer, size);
316 }
317
318
319 static status_t
packagefs_read_symlink(fs_volume * fsVolume,fs_vnode * fsNode,char * buffer,size_t * _bufferSize)320 packagefs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
321 size_t* _bufferSize)
322 {
323 Volume* volume = (Volume*)fsVolume->private_volume;
324 Node* node = (Node*)fsNode->private_node;
325
326 FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
327 node->ID());
328 TOUCH(volume);
329
330 DirectoryReadLocker dirLocker;
331 if (!lock_directory_for_node(volume, node, dirLocker))
332 return B_NO_INIT;
333
334 if (!S_ISLNK(node->Mode()))
335 return B_BAD_VALUE;
336
337 return node->ReadSymlink(buffer, _bufferSize);
338 }
339
340
341 static status_t
packagefs_access(fs_volume * fsVolume,fs_vnode * fsNode,int mode)342 packagefs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode)
343 {
344 Volume* volume = (Volume*)fsVolume->private_volume;
345 Node* node = (Node*)fsNode->private_node;
346
347 FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
348 node->ID());
349 TOUCH(volume);
350
351 DirectoryReadLocker dirLocker;
352 if (!lock_directory_for_node(volume, node, dirLocker))
353 return B_NO_INIT;
354
355 return check_access(node, mode);
356 }
357
358
359 static status_t
packagefs_read_stat(fs_volume * fsVolume,fs_vnode * fsNode,struct stat * st)360 packagefs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st)
361 {
362 Volume* volume = (Volume*)fsVolume->private_volume;
363 Node* node = (Node*)fsNode->private_node;
364
365 FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
366 node->ID());
367 TOUCH(volume);
368
369 DirectoryReadLocker dirLocker;
370 if (!lock_directory_for_node(volume, node, dirLocker))
371 return B_NO_INIT;
372
373 st->st_mode = node->Mode();
374 st->st_nlink = 1;
375 st->st_uid = node->UserID();
376 st->st_gid = node->GroupID();
377 st->st_size = node->FileSize();
378 st->st_blksize = kOptimalIOSize;
379 st->st_mtim = node->ModifiedTime();
380 st->st_atim = st->st_mtim;
381 st->st_ctim = st->st_mtim;
382 // TODO: Perhaps manage a changed time (particularly for directories)?
383 st->st_crtim = st->st_mtim;
384 st->st_blocks = (st->st_size + 511) / 512;
385
386 return B_OK;
387 }
388
389
390 // #pragma mark - Files
391
392
393 struct FileCookie {
394 int openMode;
395
FileCookieFileCookie396 FileCookie(int openMode)
397 :
398 openMode(openMode)
399 {
400 }
401 };
402
403
404 static status_t
packagefs_open(fs_volume * fsVolume,fs_vnode * fsNode,int openMode,void ** _cookie)405 packagefs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode,
406 void** _cookie)
407 {
408 Volume* volume = (Volume*)fsVolume->private_volume;
409 Node* node = (Node*)fsNode->private_node;
410
411 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), openMode %#x\n",
412 volume, node, node->ID(), openMode);
413 TOUCH(volume);
414
415 DirectoryReadLocker dirLocker;
416 if (!lock_directory_for_node(volume, node, dirLocker))
417 return B_NO_INIT;
418
419 // check the open mode and permissions
420 if (S_ISDIR(node->Mode()) && (openMode & O_RWMASK) != O_RDONLY)
421 return B_IS_A_DIRECTORY;
422
423 if ((openMode & O_RWMASK) != O_RDONLY)
424 return B_NOT_ALLOWED;
425
426 status_t error = check_access(node, R_OK);
427 if (error != B_OK)
428 return error;
429
430 // allocate the cookie
431 FileCookie* cookie = new(std::nothrow) FileCookie(openMode);
432 if (cookie == NULL)
433 RETURN_ERROR(B_NO_MEMORY);
434
435 *_cookie = cookie;
436
437 return B_OK;
438 }
439
440
441 static status_t
packagefs_close(fs_volume * fs,fs_vnode * _node,void * cookie)442 packagefs_close(fs_volume* fs, fs_vnode* _node, void* cookie)
443 {
444 return B_OK;
445 }
446
447
448 static status_t
packagefs_free_cookie(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie)449 packagefs_free_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
450 {
451 Volume* volume = (Volume*)fsVolume->private_volume;
452 Node* node = (Node*)fsNode->private_node;
453 FileCookie* cookie = (FileCookie*)_cookie;
454
455 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
456 node->ID(), cookie);
457 TOUCH(volume);
458 TOUCH(node);
459
460 delete cookie;
461
462 return B_OK;
463 }
464
465
466 static status_t
packagefs_read(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie,off_t offset,void * buffer,size_t * bufferSize)467 packagefs_read(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
468 off_t offset, void* buffer, size_t* bufferSize)
469 {
470 Volume* volume = (Volume*)fsVolume->private_volume;
471 Node* node = (Node*)fsNode->private_node;
472 FileCookie* cookie = (FileCookie*)_cookie;
473
474 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p, offset: %"
475 B_PRId64 ", buffer: %p, size: %" B_PRIuSIZE "\n", volume, node,
476 node->ID(), cookie, offset, buffer, *bufferSize);
477 TOUCH(volume);
478
479 if ((cookie->openMode & O_RWMASK) != O_RDONLY)
480 return EBADF;
481
482 return node->Read(offset, buffer, bufferSize);
483 }
484
485
486 // #pragma mark - Directories
487
488
489 struct DirectoryCookie : DirectoryIterator {
490 Directory* directory;
491 int32 state;
492 bool registered;
493
DirectoryCookieDirectoryCookie494 DirectoryCookie(Directory* directory)
495 :
496 directory(directory),
497 state(0),
498 registered(false)
499 {
500 Rewind();
501 }
502
~DirectoryCookieDirectoryCookie503 ~DirectoryCookie()
504 {
505 if (registered)
506 directory->RemoveDirectoryIterator(this);
507 }
508
RewindDirectoryCookie509 void Rewind()
510 {
511 if (registered)
512 directory->RemoveDirectoryIterator(this);
513 registered = false;
514
515 state = 0;
516 node = directory;
517 }
518
CurrentDirectoryCookie519 Node* Current(const char*& _name) const
520 {
521 if (node == NULL)
522 return NULL;
523
524 if (state == 0)
525 _name = ".";
526 else if (state == 1)
527 _name = "..";
528 else
529 _name = node->Name();
530
531 return node;
532 }
533
NextDirectoryCookie534 Node* Next()
535 {
536 if (state == 0) {
537 state = 1;
538 node = directory->GetParentUnchecked();
539 if (node == NULL)
540 node = directory;
541 return node;
542 }
543
544 if (state == 1) {
545 node = directory->FirstChild();
546 state = 2;
547 } else {
548 if (node != NULL)
549 node = directory->NextChild(node);
550 }
551
552 if (node == NULL) {
553 if (registered) {
554 directory->RemoveDirectoryIterator(this);
555 registered = false;
556 }
557
558 return NULL;
559 }
560
561 if (!registered) {
562 directory->AddDirectoryIterator(this);
563 registered = true;
564 }
565
566 return node;
567 }
568 };
569
570
571 static status_t
packagefs_open_dir(fs_volume * fsVolume,fs_vnode * fsNode,void ** _cookie)572 packagefs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
573 {
574 Volume* volume = (Volume*)fsVolume->private_volume;
575 Node* node = (Node*)fsNode->private_node;
576
577 FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
578 node->ID());
579 TOUCH(volume);
580
581 if (!S_ISDIR(node->Mode()))
582 return B_NOT_A_DIRECTORY;
583
584 Directory* dir = dynamic_cast<Directory*>(node);
585
586 status_t error = check_access(dir, R_OK);
587 if (error != B_OK)
588 return error;
589
590 // create a cookie
591 DirectoryWriteLocker dirLocker(dir);
592 DirectoryCookie* cookie = new(std::nothrow) DirectoryCookie(dir);
593 if (cookie == NULL)
594 RETURN_ERROR(B_NO_MEMORY);
595
596 *_cookie = cookie;
597 return B_OK;
598 }
599
600
601 static status_t
packagefs_close_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)602 packagefs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
603 {
604 return B_OK;
605 }
606
607
608 static status_t
packagefs_free_dir_cookie(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie)609 packagefs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
610 {
611 Volume* volume = (Volume*)fsVolume->private_volume;
612 Node* node = (Node*)fsNode->private_node;
613 DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
614
615 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
616 node->ID(), cookie);
617 TOUCH(volume);
618 TOUCH(node);
619
620 DirectoryWriteLocker dirLocker(dynamic_cast<Directory*>(node));
621 delete cookie;
622
623 return B_OK;
624 }
625
626
627 static status_t
packagefs_read_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie,struct dirent * buffer,size_t bufferSize,uint32 * _count)628 packagefs_read_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
629 struct dirent* buffer, size_t bufferSize, uint32* _count)
630 {
631 Volume* volume = (Volume*)fsVolume->private_volume;
632 Node* node = (Node*)fsNode->private_node;
633 DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
634
635 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
636 node->ID(), cookie);
637 TOUCH(volume);
638 TOUCH(node);
639
640 DirectoryWriteLocker dirLocker(cookie->directory);
641
642 uint32 maxCount = *_count;
643 uint32 count = 0;
644
645 dirent* previousEntry = NULL;
646
647 const char* name;
648 while (Node* child = cookie->Current(name)) {
649 // don't read more entries than requested
650 if (count >= maxCount)
651 break;
652
653 // align the buffer for subsequent entries
654 if (count > 0) {
655 addr_t offset = (addr_t)buffer % 8;
656 if (offset > 0) {
657 offset = 8 - offset;
658 if (bufferSize <= offset)
659 break;
660
661 previousEntry->d_reclen += offset;
662 buffer = (dirent*)((addr_t)buffer + offset);
663 bufferSize -= offset;
664 }
665 }
666
667 // fill in the entry name -- checks whether the entry fits into the
668 // buffer
669 if (!set_dirent_name(buffer, bufferSize, name)) {
670 if (count == 0)
671 RETURN_ERROR(B_BUFFER_OVERFLOW);
672 break;
673 }
674
675 // fill in the other data
676 buffer->d_dev = volume->ID();
677 buffer->d_ino = child->ID();
678
679 count++;
680 previousEntry = buffer;
681 bufferSize -= buffer->d_reclen;
682 buffer = (dirent*)((addr_t)buffer + buffer->d_reclen);
683
684 cookie->Next();
685 }
686
687 *_count = count;
688 return B_OK;
689 }
690
691
692 static status_t
packagefs_rewind_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie)693 packagefs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
694 {
695 Volume* volume = (Volume*)fsVolume->private_volume;
696 Node* node = (Node*)fsNode->private_node;
697 DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
698
699 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
700 node->ID(), cookie);
701 TOUCH(volume);
702 TOUCH(node);
703
704 DirectoryWriteLocker dirLocker(dynamic_cast<Directory*>(node));
705 cookie->Rewind();
706
707 return B_OK;
708 }
709
710
711 // #pragma mark - Attribute Directories
712
713
714 status_t
packagefs_open_attr_dir(fs_volume * fsVolume,fs_vnode * fsNode,void ** _cookie)715 packagefs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
716 {
717 Volume* volume = (Volume*)fsVolume->private_volume;
718 Node* node = (Node*)fsNode->private_node;
719
720 FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
721 node->ID());
722 TOUCH(volume);
723
724 status_t error = check_access(node, R_OK);
725 if (error != B_OK)
726 return error;
727
728 // create a cookie
729 DirectoryReadLocker dirLocker;
730 if (!lock_directory_for_node(volume, node, dirLocker))
731 return B_NO_INIT;
732
733 AttributeDirectoryCookie* cookie;
734 error = node->OpenAttributeDirectory(cookie);
735 if (error != B_OK)
736 RETURN_ERROR(error);
737
738 *_cookie = cookie;
739 return B_OK;
740 }
741
742
743 status_t
packagefs_close_attr_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie)744 packagefs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
745 {
746 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
747 return cookie->Close();
748 }
749
750
751 status_t
packagefs_free_attr_dir_cookie(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie)752 packagefs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode,
753 void* _cookie)
754 {
755 Volume* volume = (Volume*)fsVolume->private_volume;
756 Node* node = (Node*)fsNode->private_node;
757 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
758
759 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
760 node->ID(), cookie);
761 TOUCH(volume);
762 TOUCH(node);
763
764 delete cookie;
765
766 return B_OK;
767 }
768
769
770 status_t
packagefs_read_attr_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie,struct dirent * buffer,size_t bufferSize,uint32 * _count)771 packagefs_read_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
772 struct dirent* buffer, size_t bufferSize, uint32* _count)
773 {
774 Volume* volume = (Volume*)fsVolume->private_volume;
775 Node* node = (Node*)fsNode->private_node;
776 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
777
778 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
779 node->ID(), cookie);
780 TOUCH(volume);
781 TOUCH(node);
782
783 return cookie->Read(volume->ID(), node->ID(), buffer, bufferSize, _count);
784 }
785
786
787 status_t
packagefs_rewind_attr_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie)788 packagefs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
789 {
790 Volume* volume = (Volume*)fsVolume->private_volume;
791 Node* node = (Node*)fsNode->private_node;
792 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
793
794 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
795 node->ID(), cookie);
796 TOUCH(volume);
797 TOUCH(node);
798
799 return cookie->Rewind();
800 }
801
802
803 // #pragma mark - Attribute Operations
804
805
806 status_t
packagefs_open_attr(fs_volume * fsVolume,fs_vnode * fsNode,const char * name,int openMode,void ** _cookie)807 packagefs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name,
808 int openMode, void** _cookie)
809 {
810 Volume* volume = (Volume*)fsVolume->private_volume;
811 Node* node = (Node*)fsNode->private_node;
812
813 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), name: \"%s\", openMode "
814 "%#x\n", volume, node, node->ID(), name, openMode);
815 TOUCH(volume);
816
817 DirectoryReadLocker dirLocker;
818 if (!lock_directory_for_node(volume, node, dirLocker))
819 return B_NO_INIT;
820
821 // check the open mode and permissions
822 if ((openMode & O_RWMASK) != O_RDONLY)
823 return B_NOT_ALLOWED;
824
825 status_t error = check_access(node, R_OK);
826 if (error != B_OK)
827 return error;
828
829 AttributeCookie* cookie;
830 error = node->OpenAttribute(StringKey(name), openMode, cookie);
831 if (error != B_OK)
832 return error;
833
834 *_cookie = cookie;
835 return B_OK;
836 }
837
838
839 status_t
packagefs_close_attr(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie)840 packagefs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
841 {
842 AttributeCookie* cookie = (AttributeCookie*)_cookie;
843 RETURN_ERROR(cookie->Close());
844 }
845
846
847 status_t
packagefs_free_attr_cookie(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie)848 packagefs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
849 {
850 Volume* volume = (Volume*)fsVolume->private_volume;
851 Node* node = (Node*)fsNode->private_node;
852 AttributeCookie* cookie = (AttributeCookie*)_cookie;
853
854 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
855 node->ID(), cookie);
856 TOUCH(volume);
857 TOUCH(node);
858
859 delete cookie;
860
861 return B_OK;
862 }
863
864
865 status_t
packagefs_read_attr(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie,off_t offset,void * buffer,size_t * bufferSize)866 packagefs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
867 off_t offset, void* buffer, size_t* bufferSize)
868 {
869 Volume* volume = (Volume*)fsVolume->private_volume;
870 Node* node = (Node*)fsNode->private_node;
871 AttributeCookie* cookie = (AttributeCookie*)_cookie;
872
873 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
874 node->ID(), cookie);
875 TOUCH(volume);
876 TOUCH(node);
877
878 return cookie->ReadAttribute(offset, buffer, bufferSize);
879 }
880
881
882 status_t
packagefs_read_attr_stat(fs_volume * fsVolume,fs_vnode * fsNode,void * _cookie,struct stat * st)883 packagefs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode,
884 void* _cookie, struct stat* st)
885 {
886 Volume* volume = (Volume*)fsVolume->private_volume;
887 Node* node = (Node*)fsNode->private_node;
888 AttributeCookie* cookie = (AttributeCookie*)_cookie;
889
890 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
891 node->ID(), cookie);
892 TOUCH(volume);
893 TOUCH(node);
894
895 return cookie->ReadAttributeStat(st);
896 }
897
898
899 // #pragma mark - index directory & index operations
900
901
902 // NOTE: We don't do any locking in the index dir hooks, since once mounted
903 // the index directory is immutable.
904
905
906 status_t
packagefs_open_index_dir(fs_volume * fsVolume,void ** _cookie)907 packagefs_open_index_dir(fs_volume* fsVolume, void** _cookie)
908 {
909 Volume* volume = (Volume*)fsVolume->private_volume;
910
911 FUNCTION("volume: %p\n", volume);
912
913 IndexDirIterator* iterator = new(std::nothrow) IndexDirIterator(
914 volume->GetIndexDirIterator());
915 if (iterator == NULL)
916 return B_NO_MEMORY;
917
918 *_cookie = iterator;
919 return B_OK;
920 }
921
922
923 status_t
packagefs_close_index_dir(fs_volume * fsVolume,void * cookie)924 packagefs_close_index_dir(fs_volume* fsVolume, void* cookie)
925 {
926 return B_OK;
927 }
928
929
930 status_t
packagefs_free_index_dir_cookie(fs_volume * fsVolume,void * cookie)931 packagefs_free_index_dir_cookie(fs_volume* fsVolume, void* cookie)
932 {
933 FUNCTION("volume: %p, cookie: %p\n", fsVolume->private_volume, cookie);
934
935 delete (IndexDirIterator*)cookie;
936 return B_OK;
937 }
938
939
940 status_t
packagefs_read_index_dir(fs_volume * fsVolume,void * cookie,struct dirent * buffer,size_t bufferSize,uint32 * _num)941 packagefs_read_index_dir(fs_volume* fsVolume, void* cookie,
942 struct dirent* buffer, size_t bufferSize, uint32* _num)
943 {
944 Volume* volume = (Volume*)fsVolume->private_volume;
945
946 FUNCTION("volume: %p, cookie: %p, buffer: %p, bufferSize: %zu, num: %"
947 B_PRIu32 "\n", volume, cookie, buffer, bufferSize, *_num);
948
949 IndexDirIterator* iterator = (IndexDirIterator*)cookie;
950
951 if (*_num == 0)
952 return B_BAD_VALUE;
953
954 IndexDirIterator previousIterator = *iterator;
955
956 // get the next index
957 Index* index = iterator->Next();
958 if (index == NULL) {
959 *_num = 0;
960 return B_OK;
961 }
962
963 // fill in the entry
964 if (!set_dirent_name(buffer, bufferSize, index->Name())) {
965 *iterator = previousIterator;
966 return B_BUFFER_OVERFLOW;
967 }
968
969 buffer->d_dev = volume->ID();
970 buffer->d_ino = 0;
971
972 *_num = 1;
973 return B_OK;
974 }
975
976
977 status_t
packagefs_rewind_index_dir(fs_volume * fsVolume,void * cookie)978 packagefs_rewind_index_dir(fs_volume* fsVolume, void* cookie)
979 {
980 Volume* volume = (Volume*)fsVolume->private_volume;
981
982 FUNCTION("volume: %p, cookie: %p\n", volume, cookie);
983
984 IndexDirIterator* iterator = (IndexDirIterator*)cookie;
985 *iterator = volume->GetIndexDirIterator();
986
987 return B_OK;
988 }
989
990
991 status_t
packagefs_create_index(fs_volume * fsVolume,const char * name,uint32 type,uint32 flags)992 packagefs_create_index(fs_volume* fsVolume, const char* name, uint32 type,
993 uint32 flags)
994 {
995 return B_NOT_SUPPORTED;
996 }
997
998
999 status_t
packagefs_remove_index(fs_volume * fsVolume,const char * name)1000 packagefs_remove_index(fs_volume* fsVolume, const char* name)
1001 {
1002 return B_NOT_SUPPORTED;
1003 }
1004
1005
1006 status_t
packagefs_read_index_stat(fs_volume * fsVolume,const char * name,struct stat * stat)1007 packagefs_read_index_stat(fs_volume* fsVolume, const char* name,
1008 struct stat* stat)
1009 {
1010 Volume* volume = (Volume*)fsVolume->private_volume;
1011
1012 FUNCTION("volume: %p, name: \"%s\", stat: %p\n", volume, name, stat);
1013
1014 Index* index = volume->FindIndex(StringKey(name));
1015 if (index == NULL)
1016 return B_ENTRY_NOT_FOUND;
1017
1018 VolumeReadLocker volumeReadLocker(volume);
1019
1020 memset(stat, 0, sizeof(*stat));
1021 // TODO: st_mtime, st_crtime, st_uid, st_gid are made available to
1022 // userland, so we should make an attempt to fill in values that make
1023 // sense.
1024
1025 stat->st_type = index->Type();
1026 stat->st_size = index->CountEntries();
1027
1028 return B_OK;
1029 }
1030
1031
1032 // #pragma mark - query operations
1033
1034
1035 status_t
packagefs_open_query(fs_volume * fsVolume,const char * queryString,uint32 flags,port_id port,uint32 token,void ** _cookie)1036 packagefs_open_query(fs_volume* fsVolume, const char* queryString, uint32 flags,
1037 port_id port, uint32 token, void** _cookie)
1038 {
1039 Volume* volume = (Volume*)fsVolume->private_volume;
1040
1041 FUNCTION("volume: %p, query: \"%s\", flags: %#" B_PRIx32 ", port: %"
1042 B_PRId32 ", token: %" B_PRIu32 "\n", volume, queryString, flags, port,
1043 token);
1044
1045 VolumeWriteLocker volumeWriteLocker(volume);
1046
1047 Query* query;
1048 status_t error = Query::Create(volume, queryString, flags, port, token,
1049 query);
1050 if (error != B_OK)
1051 return error;
1052
1053 *_cookie = query;
1054 return B_OK;
1055 }
1056
1057
1058 status_t
packagefs_close_query(fs_volume * fsVolume,void * cookie)1059 packagefs_close_query(fs_volume* fsVolume, void* cookie)
1060 {
1061 FUNCTION_START();
1062 return B_OK;
1063 }
1064
1065
1066 status_t
packagefs_free_query_cookie(fs_volume * fsVolume,void * cookie)1067 packagefs_free_query_cookie(fs_volume* fsVolume, void* cookie)
1068 {
1069 Volume* volume = (Volume*)fsVolume->private_volume;
1070 Query* query = (Query*)cookie;
1071
1072 FUNCTION("volume: %p, query: %p\n", volume, query);
1073
1074 VolumeWriteLocker volumeWriteLocker(volume);
1075
1076 delete query;
1077
1078 return B_OK;
1079 }
1080
1081
1082 status_t
packagefs_read_query(fs_volume * fsVolume,void * cookie,struct dirent * buffer,size_t bufferSize,uint32 * _num)1083 packagefs_read_query(fs_volume* fsVolume, void* cookie, struct dirent* buffer,
1084 size_t bufferSize, uint32* _num)
1085 {
1086 Volume* volume = (Volume*)fsVolume->private_volume;
1087 Query* query = (Query*)cookie;
1088
1089 FUNCTION("volume: %p, query: %p\n", volume, query);
1090
1091 VolumeWriteLocker volumeWriteLocker(volume);
1092
1093 status_t error = query->GetNextEntry(buffer, bufferSize);
1094 if (error == B_OK)
1095 *_num = 1;
1096 else if (error == B_ENTRY_NOT_FOUND)
1097 *_num = 0;
1098 else
1099 return error;
1100
1101 return B_OK;
1102 }
1103
1104
1105 status_t
packagefs_rewind_query(fs_volume * fsVolume,void * cookie)1106 packagefs_rewind_query(fs_volume* fsVolume, void* cookie)
1107 {
1108 Volume* volume = (Volume*)fsVolume->private_volume;
1109 Query* query = (Query*)cookie;
1110
1111 FUNCTION("volume: %p, query: %p\n", volume, query);
1112
1113 VolumeWriteLocker volumeWriteLocker(volume);
1114
1115 return query->Rewind();
1116 }
1117
1118
1119 // #pragma mark - Module Interface
1120
1121
1122 static status_t
packagefs_std_ops(int32 op,...)1123 packagefs_std_ops(int32 op, ...)
1124 {
1125 using BPackageKit::BHPKG::BPrivate::PackageFileHeapAccessorBase;
1126
1127 switch (op) {
1128 case B_MODULE_INIT:
1129 {
1130 init_debugging();
1131 PRINT("package_std_ops(): B_MODULE_INIT\n");
1132
1133 status_t error = StringPool::Init();
1134 if (error != B_OK) {
1135 ERROR("Failed to init StringPool\n");
1136 exit_debugging();
1137 return error;
1138 }
1139
1140 if (!StringConstants::Init()) {
1141 ERROR("Failed to init string constants\n");
1142 StringPool::Cleanup();
1143 exit_debugging();
1144 return error;
1145 }
1146
1147 PackageFileHeapAccessorBase::sChunkCache =
1148 create_object_cache_etc("pkgfs heap buffers",
1149 PackageFileHeapAccessorBase::kChunkSize, sizeof(void*),
1150 0, /* magazine capacity, count */ 2, 1,
1151 0, NULL, NULL, NULL, NULL);
1152 TwoKeyAVLTreeNode<void*>::sNodeCache =
1153 create_object_cache_etc("pkgfs TKAVLTreeNodes",
1154 sizeof(TwoKeyAVLTreeNode<void*>), 8,
1155 0, 0, 0, CACHE_NO_DEPOT, NULL, NULL, NULL, NULL);
1156
1157 error = PackageFSRoot::GlobalInit();
1158 if (error != B_OK) {
1159 ERROR("Failed to init PackageFSRoot\n");
1160 StringConstants::Cleanup();
1161 StringPool::Cleanup();
1162 exit_debugging();
1163 return error;
1164 }
1165
1166 return B_OK;
1167 }
1168
1169 case B_MODULE_UNINIT:
1170 {
1171 PRINT("package_std_ops(): B_MODULE_UNINIT\n");
1172 PackageFSRoot::GlobalUninit();
1173 delete_object_cache(TwoKeyAVLTreeNode<void*>::sNodeCache);
1174 delete_object_cache((object_cache*)
1175 PackageFileHeapAccessorBase::sChunkCache);
1176 StringConstants::Cleanup();
1177 StringPool::Cleanup();
1178 exit_debugging();
1179 return B_OK;
1180 }
1181
1182 default:
1183 return B_ERROR;
1184 }
1185 }
1186
1187
1188 static file_system_module_info sPackageFSModuleInfo = {
1189 {
1190 "file_systems/packagefs" B_CURRENT_FS_API_VERSION,
1191 0,
1192 packagefs_std_ops,
1193 },
1194
1195 "packagefs", // short_name
1196 "Package File System", // pretty_name
1197 0, // DDM flags
1198
1199
1200 // scanning
1201 NULL, // identify_partition,
1202 NULL, // scan_partition,
1203 NULL, // free_identify_partition_cookie,
1204 NULL, // free_partition_content_cookie()
1205
1206 &packagefs_mount
1207 };
1208
1209
1210 fs_volume_ops gPackageFSVolumeOps = {
1211 &packagefs_unmount,
1212 &packagefs_read_fs_info,
1213 NULL, // write_fs_info,
1214 NULL, // sync,
1215
1216 &packagefs_get_vnode,
1217
1218 // index directory
1219 &packagefs_open_index_dir,
1220 &packagefs_close_index_dir,
1221 &packagefs_free_index_dir_cookie,
1222 &packagefs_read_index_dir,
1223 &packagefs_rewind_index_dir,
1224
1225 &packagefs_create_index,
1226 &packagefs_remove_index,
1227 &packagefs_read_index_stat,
1228
1229 // query operations
1230 &packagefs_open_query,
1231 &packagefs_close_query,
1232 &packagefs_free_query_cookie,
1233 &packagefs_read_query,
1234 &packagefs_rewind_query,
1235
1236 // TODO: FS layer operations
1237 };
1238
1239
1240 fs_vnode_ops gPackageFSVnodeOps = {
1241 // vnode operations
1242 &packagefs_lookup,
1243 &packagefs_get_vnode_name,
1244 &packagefs_put_vnode,
1245 &packagefs_put_vnode, // remove_vnode -- same as put_vnode
1246
1247 // VM file access
1248 NULL, // can_page,
1249 NULL, // read_pages,
1250 NULL, // write_pages,
1251
1252 &packagefs_io,
1253 NULL, // cancel_io()
1254
1255 NULL, // get_file_map,
1256
1257 &packagefs_ioctl,
1258 NULL, // set_flags,
1259 NULL, // select,
1260 NULL, // deselect,
1261 NULL, // fsync,
1262
1263 &packagefs_read_symlink,
1264 NULL, // create_symlink,
1265
1266 NULL, // link,
1267 NULL, // unlink,
1268 NULL, // rename,
1269
1270 &packagefs_access,
1271 &packagefs_read_stat,
1272 NULL, // write_stat,
1273 NULL, // preallocate,
1274
1275 // file operations
1276 NULL, // create,
1277 &packagefs_open,
1278 &packagefs_close,
1279 &packagefs_free_cookie,
1280 &packagefs_read,
1281 NULL, // write,
1282
1283 // directory operations
1284 NULL, // create_dir,
1285 NULL, // remove_dir,
1286 &packagefs_open_dir,
1287 &packagefs_close_dir,
1288 &packagefs_free_dir_cookie,
1289 &packagefs_read_dir,
1290 &packagefs_rewind_dir,
1291
1292 // attribute directory operations
1293 &packagefs_open_attr_dir,
1294 &packagefs_close_attr_dir,
1295 &packagefs_free_attr_dir_cookie,
1296 &packagefs_read_attr_dir,
1297 &packagefs_rewind_attr_dir,
1298
1299 // attribute operations
1300 NULL, // create_attr,
1301 &packagefs_open_attr,
1302 &packagefs_close_attr,
1303 &packagefs_free_attr_cookie,
1304 &packagefs_read_attr,
1305 NULL, // write_attr,
1306
1307 &packagefs_read_attr_stat,
1308 NULL, // write_attr_stat,
1309 NULL, // rename_attr,
1310 NULL // remove_attr,
1311
1312 // TODO: FS layer operations
1313 };
1314
1315
1316 module_info *modules[] = {
1317 (module_info *)&sPackageFSModuleInfo,
1318 NULL,
1319 };
1320