1 // kernel_interface.cpp
2 //
3 // Copyright (c) 2003-2008, Axel Dörfler (axeld@pinc-software.de)
4 // Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de)
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 //
20 // You can alternatively use *this file* under the terms of the the MIT
21 // license included in this package.
22
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <sys/stat.h>
33
34 #include <fs_index.h>
35 #include <fs_info.h>
36 #include <fs_interface.h>
37 #include <fs_query.h>
38 #include <fs_volume.h>
39 #include <vfs.h>
40 #include <KernelExport.h>
41 #include <NodeMonitor.h>
42 #include <TypeConstants.h>
43
44 #include <AutoDeleter.h>
45
46 #include "AllocationInfo.h"
47 #include "AttributeIndex.h"
48 #include "AttributeIterator.h"
49 #include "DebugSupport.h"
50 #include "Directory.h"
51 #include "Entry.h"
52 #include "EntryIterator.h"
53 #include "File.h"
54 #include "Index.h"
55 #include "IndexDirectory.h"
56 #include "Locking.h"
57 #include "Misc.h"
58 #include "Node.h"
59 #include "Query.h"
60 #include "ramfs_ioctl.h"
61 #include "SymLink.h"
62 #include "Volume.h"
63
64
65 static const size_t kOptimalIOSize = 65536;
66 static const bigtime_t kNotificationInterval = 1000000LL;
67
68
69 // notify_if_stat_changed
70 void
notify_if_stat_changed(Volume * volume,Node * node)71 notify_if_stat_changed(Volume *volume, Node *node)
72 {
73 if (volume && node && node->IsModified()) {
74 uint32 statFields = node->MarkUnmodified();
75 notify_stat_changed(volume->GetID(), -1, node->GetID(), statFields);
76 }
77 }
78
79
80 // #pragma mark - FS
81
82
83 static status_t
ramfs_mount(fs_volume * _volume,const char *,uint32 flags,const char *,ino_t * _rootID)84 ramfs_mount(fs_volume* _volume, const char* /*device*/, uint32 flags,
85 const char* /*args*/, ino_t* _rootID)
86 {
87 FUNCTION_START();
88 // parameters are ignored for now
89
90 // fail, if read-only mounting is requested
91 if (flags & B_MOUNT_READ_ONLY)
92 return B_BAD_VALUE;
93
94 // allocate and init the volume
95 Volume *volume = new(std::nothrow) Volume(_volume);
96
97 if (volume == NULL)
98 return B_NO_MEMORY;
99
100 status_t status = volume->Mount(flags);
101
102 if (status != B_OK) {
103 delete volume;
104 RETURN_ERROR(status);
105 }
106
107 *_rootID = volume->GetRootDirectory()->GetID();
108 _volume->private_volume = volume;
109 _volume->ops = &gRamFSVolumeOps;
110
111 RETURN_ERROR(B_OK);
112 }
113
114
115 static status_t
ramfs_unmount(fs_volume * _volume)116 ramfs_unmount(fs_volume* _volume)
117 {
118 FUNCTION_START();
119 Volume* volume = (Volume*)_volume->private_volume;
120 status_t error = B_OK;
121 if (volume->WriteLock()) {
122 error = volume->Unmount();
123 if (error == B_OK)
124 delete volume;
125 } else
126 SET_ERROR(error, B_ERROR);
127 RETURN_ERROR(error);
128 }
129
130
131 static status_t
ramfs_read_fs_info(fs_volume * _volume,struct fs_info * info)132 ramfs_read_fs_info(fs_volume* _volume, struct fs_info *info)
133 {
134 FUNCTION_START();
135 Volume* volume = (Volume*)_volume->private_volume;
136
137 VolumeReadLocker locker(volume);
138 if (!locker.IsLocked())
139 RETURN_ERROR(B_ERROR);
140
141 info->flags = B_FS_HAS_ATTR | B_FS_HAS_MIME | B_FS_HAS_QUERY
142 | B_FS_IS_REMOVABLE;
143 info->block_size = B_PAGE_SIZE;
144 info->io_size = kOptimalIOSize;
145 info->total_blocks = volume->CountBlocks();
146 info->free_blocks = volume->CountFreeBlocks();
147 info->device_name[0] = '\0';
148 strlcpy(info->volume_name, volume->GetName(),
149 sizeof(info->volume_name));
150 strcpy(info->fsh_name, "ramfs");
151 return B_OK;
152 }
153
154
155 static status_t
ramfs_write_fs_info(fs_volume * _volume,const struct fs_info * info,uint32 mask)156 ramfs_write_fs_info(fs_volume* _volume, const struct fs_info *info, uint32 mask)
157 {
158 FUNCTION_START();
159 Volume* volume = (Volume*)_volume->private_volume;
160
161 VolumeWriteLocker locker(volume);
162 if (!locker.IsLocked())
163 RETURN_ERROR(B_ERROR);
164
165 status_t error = B_OK;
166 if (mask & FS_WRITE_FSINFO_NAME)
167 error = volume->SetName(info->volume_name);
168
169 RETURN_ERROR(error);
170 }
171
172
173 // ramfs_sync
174 static status_t
ramfs_sync(fs_volume *)175 ramfs_sync(fs_volume* /*fs*/)
176 {
177 FUNCTION_START();
178 return B_OK;
179 }
180
181
182 // #pragma mark - VNodes
183
184
185 static status_t
ramfs_lookup(fs_volume * _volume,fs_vnode * _dir,const char * entryName,ino_t * _vnodeID)186 ramfs_lookup(fs_volume* _volume, fs_vnode* _dir, const char* entryName,
187 ino_t* _vnodeID)
188 {
189 // FUNCTION_START();
190 Volume* volume = (Volume*)_volume->private_volume;
191 Directory* dir = dynamic_cast<Directory*>((Node*)_dir->private_node);
192
193 FUNCTION(("dir: (%llu), entry: `%s'\n", (dir ? dir->GetID() : -1),
194 entryName));
195
196 // check for non-directories
197 if (dir == NULL)
198 RETURN_ERROR(B_NOT_A_DIRECTORY);
199
200 VolumeReadLocker locker(volume);
201 if (!locker.IsLocked())
202 RETURN_ERROR(B_ERROR);
203
204 status_t error = B_OK;
205 Node *node = NULL;
206
207 // special entries: "." and ".."
208 if (!strcmp(entryName, ".")) {
209 *_vnodeID = dir->GetID();
210 if (volume->GetVNode(*_vnodeID, &node) != B_OK)
211 error = B_BAD_VALUE;
212 } else if (!strcmp(entryName, "..")) {
213 Directory *parent = dir->GetParent();
214 if (parent && volume->GetVNode(parent->GetID(), &node) == B_OK)
215 *_vnodeID = node->GetID();
216 else
217 error = B_BAD_VALUE;
218
219 // ordinary entries
220 } else {
221 // find the entry
222 error = dir->FindAndGetNode(entryName, &node);
223 if (error == B_OK)
224 *_vnodeID = node->GetID();
225 }
226
227 RETURN_ERROR(error);
228 }
229
230
231 static status_t
ramfs_get_vnode(fs_volume * _volume,ino_t vnid,fs_vnode * node,int * _type,uint32 * _flags,bool reenter)232 ramfs_get_vnode(fs_volume* _volume, ino_t vnid, fs_vnode* node, int* _type,
233 uint32* _flags, bool reenter)
234 {
235 FUNCTION(("node: %lld\n", vnid));
236 Volume* volume = (Volume*)_volume->private_volume;
237 Node *foundNode = NULL;
238
239 VolumeReadLocker locker(volume);
240 if (!locker.IsLocked())
241 RETURN_ERROR(B_ERROR);
242
243 status_t error = volume->FindNode(vnid, &foundNode);
244 if (error == B_OK) {
245 node->private_node = foundNode;
246 node->ops = &gRamFSVnodeOps;
247 *_type = foundNode->GetMode();
248 *_flags = 0;
249 }
250 RETURN_ERROR(error);
251 }
252
253
254 static status_t
ramfs_write_vnode(fs_volume *,fs_vnode * DARG (_node),bool)255 ramfs_write_vnode(fs_volume* /*fs*/, fs_vnode* DARG(_node), bool /*reenter*/)
256 {
257 // DANGER: If dbg_printf() is used, this thread will enter another FS and
258 // even perform a write operation. The is dangerous here, since this hook
259 // may be called out of the other FSs, since, for instance a put_vnode()
260 // called from another FS may cause the VFS layer to free vnodes and thus
261 // invoke this hook.
262 // FUNCTION_START();
263 //FUNCTION(("node: %lld\n", ((Node*)_node)->GetID()));
264 status_t error = B_OK;
265 RETURN_ERROR(error);
266 }
267
268
269 static status_t
ramfs_remove_vnode(fs_volume * _volume,fs_vnode * _node,bool)270 ramfs_remove_vnode(fs_volume* _volume, fs_vnode* _node, bool /*reenter*/)
271 {
272 FUNCTION(("node: %lld\n", ((Node*)_node)->GetID()));
273 Volume* volume = (Volume*)_volume->private_volume;
274 Node* node = (Node*)_node->private_node;
275
276 VolumeWriteLocker locker(volume);
277 if (!locker.IsLocked())
278 RETURN_ERROR(B_ERROR);
279
280 status_t error = B_OK;
281 volume->NodeRemoved(node);
282 delete node;
283 RETURN_ERROR(error);
284 }
285
286
287 // #pragma mark - Nodes
288
289
290 static status_t
ramfs_ioctl(fs_volume * _volume,fs_vnode *,void *,uint32 cmd,void * buffer,size_t)291 ramfs_ioctl(fs_volume* _volume, fs_vnode* /*node*/, void* /*cookie*/,
292 uint32 cmd, void *buffer, size_t /*length*/)
293 {
294 FUNCTION_START();
295 Volume* volume = (Volume*)_volume->private_volume;
296
297 status_t error = B_OK;
298 switch (cmd) {
299 case RAMFS_IOCTL_GET_ALLOCATION_INFO:
300 {
301 if (buffer) {
302 VolumeReadLocker locker(volume);
303 if (!locker.IsLocked()) {
304 AllocationInfo *info = (AllocationInfo*)buffer;
305 volume->GetAllocationInfo(*info);
306 } else
307 SET_ERROR(error, B_ERROR);
308 } else
309 SET_ERROR(error, B_BAD_VALUE);
310 break;
311 }
312 case RAMFS_IOCTL_DUMP_INDEX:
313 {
314 if (buffer) {
315 VolumeReadLocker locker(volume);
316 if (!locker.IsLocked()) {
317 const char *name = (const char*)buffer;
318 PRINT(" RAMFS_IOCTL_DUMP_INDEX, `%s'\n", name);
319 IndexDirectory *indexDir = volume->GetIndexDirectory();
320 if (indexDir) {
321 if (Index *index = indexDir->FindIndex(name))
322 index->Dump();
323 else
324 SET_ERROR(error, B_ENTRY_NOT_FOUND);
325 } else
326 SET_ERROR(error, B_ENTRY_NOT_FOUND);
327 } else
328 SET_ERROR(error, B_ERROR);
329 } else
330 SET_ERROR(error, B_BAD_VALUE);
331 break;
332 }
333 default:
334 error = B_DEV_INVALID_IOCTL;
335 break;
336 }
337 RETURN_ERROR(error);
338 }
339
340
341 static status_t
ramfs_set_flags(fs_volume *,fs_vnode *,void *,int)342 ramfs_set_flags(fs_volume* /*fs*/, fs_vnode* /*node*/, void* /*cookie*/,
343 int /*flags*/)
344 {
345 FUNCTION_START();
346 // TODO : ramfs_set_flags
347 return B_OK;
348 }
349
350
351 static status_t
ramfs_fsync(fs_volume *,fs_vnode *)352 ramfs_fsync(fs_volume* /*fs*/, fs_vnode* /*node*/)
353 {
354 FUNCTION_START();
355 return B_OK;
356 }
357
358
359 static status_t
ramfs_read_symlink(fs_volume * _volume,fs_vnode * _node,char * buffer,size_t * bufferSize)360 ramfs_read_symlink(fs_volume* _volume, fs_vnode* _node, char *buffer,
361 size_t *bufferSize)
362 {
363 FUNCTION_START();
364 Volume* volume = (Volume*)_volume->private_volume;
365 Node* node = (Node*)_node->private_node;
366
367 VolumeReadLocker locker(volume);
368 if (!locker.IsLocked())
369 RETURN_ERROR(B_ERROR);
370
371 status_t error = B_OK;
372 // read symlinks only
373 if (!node->IsSymLink())
374 error = B_BAD_VALUE;
375 if (error == B_OK) {
376 if (SymLink *symLink = dynamic_cast<SymLink*>(node)) {
377 // copy the link contents
378 size_t toRead = min(*bufferSize,
379 symLink->GetLinkedPathLength());
380 if (toRead > 0)
381 memcpy(buffer, symLink->GetLinkedPath(),
382 toRead);
383
384 *bufferSize = symLink->GetLinkedPathLength();
385 } else {
386 FATAL("Node %" B_PRIdINO " pretends to be a SymLink, but isn't!\n",
387 node->GetID());
388 error = B_BAD_VALUE;
389 }
390 }
391 RETURN_ERROR(error);
392 }
393
394
395 static status_t
ramfs_create_symlink(fs_volume * _volume,fs_vnode * _dir,const char * name,const char * path,int mode)396 ramfs_create_symlink(fs_volume* _volume, fs_vnode* _dir, const char *name,
397 const char *path, int mode)
398 {
399 FUNCTION(("name: `%s', path: `%s'\n", name, path));
400 Volume* volume = (Volume*)_volume->private_volume;
401 Directory* dir = dynamic_cast<Directory*>((Node*)_dir->private_node);
402
403 if (name == NULL || *name == '\0')
404 RETURN_ERROR(B_BAD_VALUE);
405 if (dir == NULL)
406 RETURN_ERROR(B_BAD_VALUE);
407
408 VolumeWriteLocker locker(volume);
409 if (!locker.IsLocked())
410 RETURN_ERROR(B_ERROR);
411
412 status_t error = B_OK;
413 NodeMTimeUpdater mTimeUpdater(dir);
414 // directory deleted?
415 bool removed;
416 if (get_vnode_removed(volume->FSVolume(), dir->GetID(), &removed)
417 != B_OK || removed) {
418 SET_ERROR(error, B_NOT_ALLOWED);
419 }
420
421 // check directory write permissions
422 error = dir->CheckPermissions(ACCESS_W);
423 Node *node = NULL;
424 if (error == B_OK) {
425 // check if entry does already exist
426 if (dir->FindNode(name, &node) == B_OK) {
427 SET_ERROR(error, B_FILE_EXISTS);
428 } else {
429 // entry doesn't exist: create a symlink
430 SymLink *symLink = NULL;
431 error = dir->CreateSymLink(name, path, &symLink);
432 if (error == B_OK) {
433 node = symLink;
434 // set permissions, owner and group
435 node->SetMode(mode);
436 node->SetUID(geteuid());
437 node->SetGID(getegid());
438 // put the node
439 volume->PutVNode(node);
440 }
441 }
442 }
443 NodeMTimeUpdater mTimeUpdater2(node);
444 // notify listeners
445 if (error == B_OK) {
446 notify_entry_created(volume->GetID(), dir->GetID(), name,
447 node->GetID());
448 }
449
450 RETURN_ERROR(error);
451 }
452
453
454 static status_t
ramfs_link(fs_volume * _volume,fs_vnode * _dir,const char * name,fs_vnode * _node)455 ramfs_link(fs_volume* _volume, fs_vnode* _dir, const char *name,
456 fs_vnode* _node)
457 {
458 FUNCTION(("name: `%s'\n", name));
459 Volume* volume = (Volume*)_volume->private_volume;
460 Directory* dir = dynamic_cast<Directory*>((Node*)_dir->private_node);
461 Node* node = (Node*)_node->private_node;
462
463 if (dir == NULL)
464 RETURN_ERROR(B_BAD_VALUE);
465
466 VolumeWriteLocker locker(volume);
467 if (!locker.IsLocked())
468 RETURN_ERROR(B_ERROR);
469
470 status_t error = B_OK;
471 NodeMTimeUpdater mTimeUpdater(dir);
472 // directory deleted?
473 bool removed;
474 if (get_vnode_removed(volume->FSVolume(), dir->GetID(), &removed)
475 != B_OK || removed) {
476 SET_ERROR(error, B_NOT_ALLOWED);
477 }
478 // check directory write permissions
479 error = dir->CheckPermissions(ACCESS_W);
480 Entry *entry = NULL;
481 if (error == B_OK) {
482 // check if entry does already exist
483 if (dir->FindEntry(name, &entry) == B_OK) {
484 SET_ERROR(error, B_FILE_EXISTS);
485 } else {
486 // entry doesn't exist: create a link
487 error = dir->CreateEntry(node, name);
488 }
489 }
490 // notify listeners
491 if (error == B_OK) {
492 notify_entry_created(volume->GetID(), dir->GetID(), name,
493 node->GetID());
494 }
495
496 RETURN_ERROR(error);
497 }
498
499
500 static status_t
ramfs_unlink(fs_volume * _volume,fs_vnode * _dir,const char * name)501 ramfs_unlink(fs_volume* _volume, fs_vnode* _dir, const char *name)
502 {
503 FUNCTION(("name: `%s'\n", name));
504 Volume* volume = (Volume*)_volume->private_volume;
505 Directory* dir = dynamic_cast<Directory*>((Node*)_dir->private_node);
506 status_t error = B_OK;
507
508 if (name == NULL || *name == '\0' || strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
509 RETURN_ERROR(B_BAD_VALUE);
510 if (dir == NULL)
511 RETURN_ERROR(B_BAD_VALUE);
512
513 VolumeWriteLocker locker(volume);
514 if (!locker.IsLocked())
515 RETURN_ERROR(B_ERROR);
516
517 NodeMTimeUpdater mTimeUpdater(dir);
518 // check directory write permissions
519 error = dir->CheckPermissions(ACCESS_W);
520 ino_t nodeID = -1;
521 if (error == B_OK) {
522 // check if entry exists
523 Node *node = NULL;
524 Entry *entry = NULL;
525 if (dir->FindAndGetNode(name, &node, &entry) == B_OK) {
526 nodeID = node->GetID();
527 // unlink the entry, if it isn't a non-empty directory
528 if (node->IsDirectory()
529 && !dynamic_cast<Directory*>(node)->IsEmpty()) {
530 SET_ERROR(error, B_DIRECTORY_NOT_EMPTY);
531 } else
532 error = dir->DeleteEntry(entry);
533 volume->PutVNode(node);
534 } else
535 SET_ERROR(error, B_ENTRY_NOT_FOUND);
536 }
537 // notify listeners
538 if (error == B_OK)
539 notify_entry_removed(volume->GetID(), dir->GetID(), name, nodeID);
540
541 RETURN_ERROR(error);
542 }
543
544
545 static status_t
ramfs_rename(fs_volume * _volume,fs_vnode * _oldDir,const char * oldName,fs_vnode * _newDir,const char * newName)546 ramfs_rename(fs_volume* _volume, fs_vnode* _oldDir, const char *oldName,
547 fs_vnode* _newDir, const char *newName)
548 {
549 Volume* volume = (Volume*)_volume->private_volume;
550
551 Directory* oldDir = dynamic_cast<Directory*>((Node*)_oldDir->private_node);
552 Directory* newDir = dynamic_cast<Directory*>((Node*)_newDir->private_node);
553
554 FUNCTION(("old dir: %lld, old name: `%s', new dir: %lld, new name: `%s'\n",
555 oldDir->GetID(), oldName, newDir->GetID(), newName));
556
557 VolumeWriteLocker locker(volume);
558 if (!locker.IsLocked())
559 RETURN_ERROR(B_ERROR);
560
561 status_t error = B_OK;
562
563 NodeMTimeUpdater mTimeUpdater1(oldDir);
564 NodeMTimeUpdater mTimeUpdater2(newDir);
565
566 // target directory deleted?
567 bool removed;
568 if (get_vnode_removed(volume->FSVolume(), newDir->GetID(), &removed)
569 != B_OK || removed) {
570 SET_ERROR(error, B_NOT_ALLOWED);
571 }
572
573 // check directory write permissions
574 if (error == B_OK)
575 error = oldDir->CheckPermissions(ACCESS_W);
576 if (error == B_OK)
577 error = newDir->CheckPermissions(ACCESS_W);
578
579 Node *node = NULL;
580 Entry *entry = NULL;
581 if (error == B_OK) {
582 // check if entry exists
583 if (oldDir->FindAndGetNode(oldName, &node, &entry) != B_OK) {
584 SET_ERROR(error, B_ENTRY_NOT_FOUND);
585 } else {
586 if (oldDir != newDir) {
587 // check whether the entry is a descendent of the target
588 // directory
589 for (Directory *parent = newDir; parent != NULL;
590 parent = parent->GetParent()) {
591 if (parent == node) {
592 error = B_BAD_VALUE;
593 break;
594 } else if (parent == oldDir)
595 break;
596 }
597 }
598 }
599
600 // check the target directory situation
601 Node *clobberNode = NULL;
602 Entry *clobberEntry = NULL;
603 if (error == B_OK) {
604 if (newDir->FindAndGetNode(newName, &clobberNode,
605 &clobberEntry) == B_OK) {
606 if (clobberNode->IsDirectory()
607 && !dynamic_cast<Directory*>(clobberNode)->IsEmpty()) {
608 SET_ERROR(error, B_NAME_IN_USE);
609 }
610 }
611 }
612
613 // do the job
614 if (error == B_OK) {
615 // temporarily acquire an additional reference to make
616 // sure the node isn't deleted when we remove the entry
617 error = node->AddReference();
618 if (error == B_OK) {
619 // delete the original entry
620 error = oldDir->DeleteEntry(entry);
621 if (error == B_OK) {
622 // create the new one/relink the target entry
623 if (clobberEntry)
624 error = clobberEntry->Link(node);
625 else
626 error = newDir->CreateEntry(node, newName);
627
628 if (error == B_OK) {
629 // send a "removed" notification for the clobbered
630 // entry
631 if (clobberEntry) {
632 notify_entry_removed(volume->GetID(),
633 newDir->GetID(), newName,
634 clobberNode->GetID());
635 }
636 } else {
637 // try to recreate the original entry, in case of
638 // failure
639 newDir->CreateEntry(node, oldName);
640 }
641 }
642 node->RemoveReference();
643 }
644 }
645
646 // release the entries
647 if (clobberEntry)
648 volume->PutVNode(clobberNode);
649 if (entry)
650 volume->PutVNode(node);
651 }
652
653 // notify listeners
654 if (error == B_OK) {
655 notify_entry_moved(volume->GetID(), oldDir->GetID(), oldName,
656 newDir->GetID(), newName, node->GetID());
657 }
658
659 RETURN_ERROR(error);
660 }
661
662
663 static status_t
ramfs_access(fs_volume * _volume,fs_vnode * _node,int mode)664 ramfs_access(fs_volume* _volume, fs_vnode* _node, int mode)
665 {
666 FUNCTION_START();
667 Volume* volume = (Volume*)_volume->private_volume;
668 Node* node = (Node*)_node->private_node;
669
670 VolumeReadLocker locker(volume);
671 if (!locker.IsLocked())
672 RETURN_ERROR(B_ERROR);
673
674 status_t error = node->CheckPermissions(mode);
675 RETURN_ERROR(error);
676 }
677
678
679 static status_t
ramfs_read_stat(fs_volume * _volume,fs_vnode * _node,struct stat * st)680 ramfs_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat *st)
681 {
682 // FUNCTION_START();
683 Volume* volume = (Volume*)_volume->private_volume;
684 Node* node = (Node*)_node->private_node;
685
686 FUNCTION(("node: %lld\n", node->GetID()));
687
688 VolumeReadLocker locker(volume);
689 if (!locker.IsLocked())
690 RETURN_ERROR(B_ERROR);
691
692 st->st_dev = volume->GetID();
693 st->st_ino = node->GetID();
694 st->st_mode = node->GetMode();
695 st->st_nlink = node->GetRefCount();
696 st->st_uid = node->GetUID();
697 st->st_gid = node->GetGID();
698 st->st_size = node->GetSize();
699 st->st_blksize = kOptimalIOSize;
700 st->st_blocks = (st->st_size + st->st_blksize - 1) / st->st_blksize;
701 st->st_atime = node->GetATime();
702 st->st_mtime = node->GetMTime();
703 st->st_ctime = node->GetCTime();
704 st->st_crtime = node->GetCrTime();
705
706 RETURN_ERROR(B_OK);
707 }
708
709
710 static status_t
ramfs_write_stat(fs_volume * _volume,fs_vnode * _node,const struct stat * st,uint32 mask)711 ramfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat *st,
712 uint32 mask)
713 {
714 FUNCTION(("mask: %lx\n", mask));
715
716 Volume* volume = (Volume*)_volume->private_volume;
717 Node* node = (Node*)_node->private_node;
718
719 VolumeWriteLocker locker(volume);
720 if (!locker.IsLocked())
721 RETURN_ERROR(B_ERROR);
722
723 status_t error = B_OK;
724 NodeMTimeUpdater mTimeUpdater(node);
725 // check permissions
726 error = node->CheckPermissions(ACCESS_W);
727 // size
728 if (error == B_OK && (mask & B_STAT_SIZE))
729 error = node->SetSize(st->st_size);
730 if (error == B_OK) {
731 // permissions
732 if (mask & B_STAT_MODE) {
733 node->SetMode((node->GetMode() & ~S_IUMSK)
734 | (st->st_mode & S_IUMSK));
735 }
736 // UID
737 if (mask & B_STAT_UID)
738 node->SetUID(st->st_uid);
739 // GID
740 if (mask & B_STAT_GID)
741 node->SetGID(st->st_gid);
742 // mtime
743 if (mask & B_STAT_MODIFICATION_TIME)
744 node->SetMTime(st->st_mtime);
745 // crtime
746 if (mask & B_STAT_CREATION_TIME)
747 node->SetCrTime(st->st_crtime);
748 }
749
750 // notify listeners
751 if (error == B_OK)
752 notify_if_stat_changed(volume, node);
753
754 RETURN_ERROR(error);
755 }
756
757
758 // #pragma mark - Files
759
760
761 class FileCookie {
762 public:
FileCookie(int openMode)763 FileCookie(int openMode) : fOpenMode(openMode), fLastNotificationTime(0) {}
764
GetOpenMode()765 inline int GetOpenMode() { return fOpenMode; }
GetLastNotificationTime()766 inline bigtime_t GetLastNotificationTime() { return fLastNotificationTime; }
767
NotificationIntervalElapsed(bool set=false)768 inline bool NotificationIntervalElapsed(bool set = false)
769 {
770 bigtime_t currentTime = system_time();
771 bool result = (currentTime
772 - fLastNotificationTime > kNotificationInterval);
773
774 if (set && result)
775 fLastNotificationTime = currentTime;
776
777 return result;
778 }
779
780 private:
781 int fOpenMode;
782 bigtime_t fLastNotificationTime;
783 };
784
785
786 static status_t
ramfs_create(fs_volume * _volume,fs_vnode * _dir,const char * name,int openMode,int mode,void ** _cookie,ino_t * vnid)787 ramfs_create(fs_volume* _volume, fs_vnode* _dir, const char *name, int openMode,
788 int mode, void** _cookie, ino_t *vnid)
789 {
790 FUNCTION(("name: `%s', open mode: %x, mode: %x\n", name, openMode, mode));
791 Volume* volume = (Volume*)_volume->private_volume;
792 Directory* dir = dynamic_cast<Directory*>((Node*)_dir->private_node);
793
794 if (name == NULL || *name == '\0')
795 RETURN_ERROR(B_BAD_VALUE);
796 if (dir == NULL)
797 RETURN_ERROR(B_BAD_VALUE);
798 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
799 RETURN_ERROR(B_FILE_EXISTS);
800
801 VolumeWriteLocker locker(volume);
802 if (!locker.IsLocked())
803 RETURN_ERROR(B_ERROR);
804
805 NodeMTimeUpdater mTimeUpdater(dir);
806 status_t error = B_OK;
807
808 // directory deleted?
809 bool removed;
810 if (get_vnode_removed(volume->FSVolume(), dir->GetID(), &removed)
811 != B_OK || removed) {
812 SET_ERROR(error, B_NOT_ALLOWED);
813 }
814 // create the file cookie
815 FileCookie *cookie = NULL;
816 if (error == B_OK) {
817 cookie = new(nothrow) FileCookie(openMode);
818 if (!cookie)
819 SET_ERROR(error, B_NO_MEMORY);
820 }
821 Node *node = NULL;
822 if (error == B_OK) {
823 // check if entry does already exist
824 if (dir->FindNode(name, &node) == B_OK) {
825 // entry does already exist
826 // fail, if we shall fail, when the file exists
827 if (openMode & O_EXCL) {
828 SET_ERROR(error, B_FILE_EXISTS);
829 // don't create a file over an existing directory or symlink
830 } else if (!node->IsFile()) {
831 SET_ERROR(error, B_NOT_ALLOWED);
832 // the user must have write permission for an existing entry
833 } else if ((error = node->CheckPermissions(ACCESS_W)) == B_OK) {
834 // truncate, if requested
835 if (openMode & O_TRUNC)
836 error = node->SetSize(0);
837 // we ignore the supplied permissions in this case
838 // get vnode
839 if (error == B_OK) {
840 *vnid = node->GetID();
841 error = volume->GetVNode(node->GetID(), &node);
842 }
843 }
844 // the user must have dir write permission to create a new entry
845 } else if ((error = dir->CheckPermissions(ACCESS_W)) == B_OK) {
846 // entry doesn't exist: create a file
847 File *file = NULL;
848 error = dir->CreateFile(name, &file);
849 if (error == B_OK) {
850 node = file;
851 *vnid = node->GetID();
852 // set permissions, owner and group
853 node->SetMode(mode);
854 node->SetUID(geteuid());
855 node->SetGID(getegid());
856
857 // set cache in vnode
858 struct vnode* vnode;
859 if (vfs_lookup_vnode(_volume->id, node->GetID(), &vnode) == B_OK) {
860 vfs_set_vnode_cache(vnode, file->GetCache(vnode));
861 }
862 }
863 }
864 // set result / cleanup on failure
865 if (error == B_OK)
866 *_cookie = cookie;
867 else if (cookie)
868 delete cookie;
869 }
870 NodeMTimeUpdater mTimeUpdater2(node);
871 // notify listeners
872 if (error == B_OK)
873 notify_entry_created(volume->GetID(), dir->GetID(), name, *vnid);
874
875 RETURN_ERROR(error);
876 }
877
878
879 static status_t
ramfs_open(fs_volume * _volume,fs_vnode * _node,int openMode,void ** _cookie)880 ramfs_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie)
881 {
882 // FUNCTION_START();
883 Volume* volume = (Volume*)_volume->private_volume;
884 Node* node = (Node*)_node->private_node;
885
886 FUNCTION(("node: %lld\n", node->GetID()));
887
888 VolumeReadLocker locker(volume);
889 if (!locker.IsLocked())
890 RETURN_ERROR(B_ERROR);
891
892 status_t error = B_OK;
893 // directory can be opened read-only
894 if (node->IsDirectory() && (openMode & O_RWMASK) != O_RDONLY)
895 error = B_IS_A_DIRECTORY;
896 if (error == B_OK && (openMode & O_DIRECTORY) != 0 && !node->IsDirectory())
897 error = B_NOT_A_DIRECTORY;
898
899 int accessMode = open_mode_to_access(openMode);
900 // truncating requires write permission
901 if (error == B_OK && (openMode & O_TRUNC))
902 accessMode |= ACCESS_W;
903 // check open mode against permissions
904 if (error == B_OK)
905 error = node->CheckPermissions(accessMode);
906 // create the cookie
907 FileCookie *cookie = NULL;
908 if (error == B_OK) {
909 cookie = new(nothrow) FileCookie(openMode);
910 if (!cookie)
911 SET_ERROR(error, B_NO_MEMORY);
912 }
913 // truncate if requested
914 if (error == B_OK && (openMode & O_TRUNC))
915 error = node->SetSize(0);
916 NodeMTimeUpdater mTimeUpdater(node);
917 // set result / cleanup on failure
918 if (error == B_OK)
919 *_cookie = cookie;
920 else if (cookie)
921 delete cookie;
922
923 RETURN_ERROR(error);
924 }
925
926
927 static status_t
ramfs_close(fs_volume * _volume,fs_vnode * _node,void *)928 ramfs_close(fs_volume* _volume, fs_vnode* _node, void* /*cookie*/)
929 {
930 // FUNCTION_START();
931 Volume* volume = (Volume*)_volume->private_volume;
932 Node* node = (Node*)_node->private_node;
933
934 FUNCTION(("node: %lld\n", node->GetID()));
935
936 VolumeReadLocker locker(volume);
937 if (!locker.IsLocked())
938 RETURN_ERROR(B_ERROR);
939
940 status_t error = B_OK;
941 // notify listeners
942 notify_if_stat_changed(volume, node);
943
944 return error;
945 }
946
947
948 static status_t
ramfs_free_cookie(fs_volume *,fs_vnode *,void * _cookie)949 ramfs_free_cookie(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
950 {
951 FUNCTION_START();
952 FileCookie *cookie = (FileCookie*)_cookie;
953 delete cookie;
954 return B_OK;
955 }
956
957
958 static status_t
ramfs_read(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,void * buffer,size_t * bufferSize)959 ramfs_read(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
960 void *buffer, size_t *bufferSize)
961 {
962 // FUNCTION_START();
963 Volume* volume = (Volume*)_volume->private_volume;
964 Node* node = (Node*)_node->private_node;
965 FileCookie *cookie = (FileCookie*)_cookie;
966
967 // FUNCTION(("((%lu, %lu), %lld, %p, %lu)\n", node->GetDirID(),
968 // node->GetObjectID(), pos, buffer, *bufferSize));
969
970 VolumeReadLocker locker(volume);
971 if (!locker.IsLocked())
972 RETURN_ERROR(B_ERROR);
973
974 status_t error = B_OK;
975 // don't read anything but files
976 if (!node->IsFile())
977 SET_ERROR(error, B_BAD_VALUE);
978
979 // check, if reading is allowed
980 int rwMode = cookie->GetOpenMode() & O_RWMASK;
981 if (error == B_OK && rwMode != O_RDONLY && rwMode != O_RDWR)
982 SET_ERROR(error, B_FILE_ERROR);
983
984 // read
985 if (error == B_OK) {
986 if (File *file = dynamic_cast<File*>(node)) {
987 error = file->ReadAt(pos, buffer, *bufferSize, bufferSize);
988 } else {
989 FATAL("Node %" B_PRIdINO " pretends to be a File, but isn't!\n",
990 node->GetID());
991 error = B_BAD_VALUE;
992 }
993 }
994
995 RETURN_ERROR(error);
996 }
997
998
999 static status_t
ramfs_write(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,const void * buffer,size_t * bufferSize)1000 ramfs_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
1001 const void *buffer, size_t *bufferSize)
1002 {
1003 // FUNCTION_START();
1004 Volume* volume = (Volume*)_volume->private_volume;
1005 Node* node = (Node*)_node->private_node;
1006
1007 FileCookie *cookie = (FileCookie*)_cookie;
1008 // FUNCTION(("((%lu, %lu), %lld, %p, %lu)\n", node->GetDirID(),
1009 // node->GetObjectID(), pos, buffer, *bufferSize));
1010
1011 VolumeWriteLocker locker(volume);
1012 if (!locker.IsLocked())
1013 RETURN_ERROR(B_ERROR);
1014
1015 status_t error = B_OK;
1016 // don't write anything but files
1017 if (!node->IsFile())
1018 SET_ERROR(error, B_BAD_VALUE);
1019 if (error == B_OK) {
1020 // check, if reading is allowed
1021 int rwMode = cookie->GetOpenMode() & O_RWMASK;
1022 if (error == B_OK && rwMode != O_WRONLY && rwMode != O_RDWR)
1023 SET_ERROR(error, B_FILE_ERROR);
1024 if (error == B_OK) {
1025 // reset the position, if opened in append mode
1026 if (cookie->GetOpenMode() & O_APPEND)
1027 pos = node->GetSize();
1028 // write
1029 if (File *file = dynamic_cast<File*>(node)) {
1030 error = file->WriteAt(pos, buffer, *bufferSize,
1031 bufferSize);
1032 } else {
1033 FATAL("Node %" B_PRIdINO " pretends to be a File, but isn't!\n",
1034 node->GetID());
1035 error = B_BAD_VALUE;
1036 }
1037 }
1038 }
1039 // notify listeners
1040 if (error == B_OK && cookie->NotificationIntervalElapsed(true))
1041 notify_if_stat_changed(volume, node);
1042 NodeMTimeUpdater mTimeUpdater(node);
1043 RETURN_ERROR(error);
1044 }
1045
1046
1047 // #pragma mark - Directories
1048
1049
1050 class DirectoryCookie {
1051 public:
DirectoryCookie(Directory * directory=NULL)1052 DirectoryCookie(Directory *directory = NULL)
1053 :
1054 fIterator(directory),
1055 fDotIndex(DOT_INDEX),
1056 // debugging
1057 fIteratorID(atomic_add(&fNextIteratorID, 1)),
1058 fGetNextCounter(0)
1059 {
1060 }
1061
Unset()1062 void Unset() { fIterator.Unset(); }
1063
1064 // EntryIterator *GetIterator() const { return &fIterator; }
1065
GetNext(ino_t * nodeID,const char ** entryName)1066 status_t GetNext(ino_t *nodeID, const char **entryName)
1067 {
1068 fGetNextCounter++;
1069 status_t error = B_OK;
1070 if (fDotIndex == DOT_INDEX) {
1071 // "."
1072 Node *entry = fIterator.GetDirectory();
1073 *nodeID = entry->GetID();
1074 *entryName = ".";
1075 fDotIndex++;
1076 } else if (fDotIndex == DOT_DOT_INDEX) {
1077 // ".."
1078 Directory *dir = fIterator.GetDirectory();
1079 if (dir->GetParent())
1080 *nodeID = dir->GetParent()->GetID();
1081 else
1082 *nodeID = dir->GetID();
1083 *entryName = "..";
1084 fDotIndex++;
1085 } else {
1086 // ordinary entries
1087 Entry *entry = NULL;
1088 error = fIterator.GetNext(&entry);
1089 if (error == B_OK) {
1090 *nodeID = entry->GetNode()->GetID();
1091 *entryName = entry->GetName();
1092 }
1093 }
1094 PRINT("EntryIterator %" B_PRId32 ", GetNext() counter: %" B_PRId32 ", entry: %p (%lld)\n",
1095 fIteratorID, fGetNextCounter, fIterator.GetCurrent(),
1096 (fIterator.GetCurrent()
1097 ? fIterator.GetCurrent()->GetNode()->GetID() : -1));
1098 return error;
1099 }
1100
Rewind()1101 status_t Rewind()
1102 {
1103 fDotIndex = DOT_INDEX;
1104 return fIterator.Rewind();
1105 }
1106
Suspend()1107 status_t Suspend() { return fIterator.Suspend(); }
Resume()1108 status_t Resume() { return fIterator.Resume(); }
1109
1110 private:
1111 enum {
1112 DOT_INDEX = 0,
1113 DOT_DOT_INDEX = 1,
1114 ENTRY_INDEX = 2,
1115 };
1116
1117 private:
1118 EntryIterator fIterator;
1119 uint32 fDotIndex;
1120
1121 // debugging
1122 int32 fIteratorID;
1123 int32 fGetNextCounter;
1124 static int32 fNextIteratorID;
1125 };
1126
1127
1128 int32 DirectoryCookie::fNextIteratorID = 0;
1129
1130
1131 static status_t
ramfs_create_dir(fs_volume * _volume,fs_vnode * _dir,const char * name,int mode)1132 ramfs_create_dir(fs_volume* _volume, fs_vnode* _dir, const char *name, int mode)
1133 {
1134 FUNCTION(("name: `%s', mode: %x\n", name, mode));
1135 Volume* volume = (Volume*)_volume->private_volume;
1136 Directory* dir = dynamic_cast<Directory*>((Node*)_dir->private_node);
1137
1138 if (name == NULL || *name == '\0')
1139 RETURN_ERROR(B_BAD_VALUE);
1140 if (dir == NULL)
1141 RETURN_ERROR(B_BAD_VALUE);
1142 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
1143 RETURN_ERROR(B_FILE_EXISTS);
1144
1145 VolumeWriteLocker locker(volume);
1146 if (!locker.IsLocked())
1147 RETURN_ERROR(B_ERROR);
1148
1149 NodeMTimeUpdater mTimeUpdater(dir);
1150 // directory deleted?
1151 bool removed;
1152 status_t error = B_OK;
1153 if (get_vnode_removed(volume->FSVolume(), dir->GetID(), &removed)
1154 != B_OK || removed) {
1155 SET_ERROR(error, B_NOT_ALLOWED);
1156 }
1157
1158 // check directory write permissions
1159 error = dir->CheckPermissions(ACCESS_W);
1160 Node *node = NULL;
1161 if (error == B_OK) {
1162 // check if entry does already exist
1163 if (dir->FindNode(name, &node) == B_OK) {
1164 SET_ERROR(error, B_FILE_EXISTS);
1165 } else {
1166 // entry doesn't exist: create a directory
1167 Directory *newDir = NULL;
1168 error = dir->CreateDirectory(name, &newDir);
1169 if (error == B_OK) {
1170 node = newDir;
1171 // set permissions, owner and group
1172 node->SetMode(mode);
1173 node->SetUID(geteuid());
1174 node->SetGID(getegid());
1175 // put the node
1176 volume->PutVNode(node);
1177 }
1178 }
1179 }
1180 NodeMTimeUpdater mTimeUpdater2(node);
1181 // notify listeners
1182 if (error == B_OK) {
1183 notify_entry_created(volume->GetID(), dir->GetID(), name,
1184 node->GetID());
1185 }
1186
1187 RETURN_ERROR(error);
1188 }
1189
1190
1191 static status_t
ramfs_remove_dir(fs_volume * _volume,fs_vnode * _dir,const char * name)1192 ramfs_remove_dir(fs_volume* _volume, fs_vnode* _dir, const char *name)
1193 {
1194 FUNCTION(("name: `%s'\n", name));
1195 Volume* volume = (Volume*)_volume->private_volume;
1196 Directory* dir = dynamic_cast<Directory*>((Node*)_dir->private_node);
1197
1198 if (name == NULL || *name == '\0' || !strcmp(name, ".") || !strcmp(name, ".."))
1199 RETURN_ERROR(B_BAD_VALUE);
1200 if (dir == NULL)
1201 RETURN_ERROR(B_BAD_VALUE);
1202
1203 VolumeWriteLocker locker(volume);
1204 if (!locker.IsLocked())
1205 RETURN_ERROR(B_ERROR);
1206
1207 NodeMTimeUpdater mTimeUpdater(dir);
1208 // check directory write permissions
1209 status_t error = dir->CheckPermissions(ACCESS_W);
1210 ino_t nodeID = -1;
1211 if (error == B_OK) {
1212 // check if entry exists
1213 Node *node = NULL;
1214 Entry *entry = NULL;
1215 if (dir->FindAndGetNode(name, &node, &entry) == B_OK) {
1216 nodeID = node->GetID();
1217 if (!node->IsDirectory()) {
1218 SET_ERROR(error, B_NOT_A_DIRECTORY);
1219 } else if (!dynamic_cast<Directory*>(node)->IsEmpty()) {
1220 SET_ERROR(error, B_DIRECTORY_NOT_EMPTY);
1221 } else
1222 error = dir->DeleteEntry(entry);
1223 volume->PutVNode(node);
1224 } else
1225 SET_ERROR(error, B_ENTRY_NOT_FOUND);
1226 }
1227 // notify listeners
1228 if (error == B_OK)
1229 notify_entry_removed(volume->GetID(), dir->GetID(), name, nodeID);
1230
1231 RETURN_ERROR(error);
1232 }
1233
1234
1235 static status_t
ramfs_open_dir(fs_volume *,fs_vnode * _node,void ** _cookie)1236 ramfs_open_dir(fs_volume* /*fs*/, fs_vnode* _node, void** _cookie)
1237 {
1238 // FUNCTION_START();
1239 // Volume *volume = (Volume*)fs;
1240 Node* node = (Node*)_node->private_node;
1241
1242 FUNCTION(("dir: (%Lu)\n", node->GetID()));
1243
1244 if (!node->IsDirectory())
1245 RETURN_ERROR(B_NOT_A_DIRECTORY);
1246
1247 // get the Directory
1248 Directory *dir = dynamic_cast<Directory*>(node);
1249 status_t error = B_OK;
1250 if (dir == NULL) {
1251 FATAL("Node %" B_PRIdINO " pretends to be a Directory, but isn't!\n",
1252 node->GetID());
1253 error = B_NOT_A_DIRECTORY;
1254 }
1255
1256 // create a DirectoryCookie
1257 if (error == B_OK) {
1258 DirectoryCookie *cookie = new(nothrow) DirectoryCookie(dir);
1259 if (cookie) {
1260 error = cookie->Suspend();
1261 if (error == B_OK)
1262 *_cookie = cookie;
1263 else
1264 delete cookie;
1265 } else
1266 SET_ERROR(error, B_NO_MEMORY);
1267 }
1268 FUNCTION_END();
1269 RETURN_ERROR(error);
1270 }
1271
1272
1273 static status_t
ramfs_close_dir(fs_volume *,fs_vnode * DARG (_node),void * _cookie)1274 ramfs_close_dir(fs_volume* /*fs*/, fs_vnode* DARG(_node), void* _cookie)
1275 {
1276 FUNCTION_START();
1277 FUNCTION(("dir: (%Lu)\n", ((Node*)_node)->GetID()));
1278 // No locking needed, since the Directory is guaranteed to live at this
1279 // time and for iterators there is a separate locking.
1280 DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1281 cookie->Unset();
1282 return B_OK;
1283 }
1284
1285
1286 static status_t
ramfs_free_dir_cookie(fs_volume *,fs_vnode *,void * _cookie)1287 ramfs_free_dir_cookie(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
1288 {
1289 FUNCTION_START();
1290 DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1291 delete cookie;
1292 return B_OK;
1293 }
1294
1295
1296 static status_t
ramfs_read_dir(fs_volume * _volume,fs_vnode * DARG (_node),void * _cookie,struct dirent * buffer,size_t bufferSize,uint32 * count)1297 ramfs_read_dir(fs_volume* _volume, fs_vnode* DARG(_node), void* _cookie,
1298 struct dirent *buffer, size_t bufferSize, uint32 *count)
1299 {
1300 FUNCTION_START();
1301 Volume* volume = (Volume*)_volume->private_volume;
1302 DARG(Node *node = (Node*)_node; )
1303
1304 FUNCTION(("dir: (%Lu)\n", node->GetID()));
1305 DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1306
1307 VolumeReadLocker locker(volume);
1308 if (!locker.IsLocked())
1309 RETURN_ERROR(B_ERROR);
1310
1311 status_t error = cookie->Resume();
1312 if (error == B_OK) {
1313 // read one entry
1314 ino_t nodeID = -1;
1315 const char *name = NULL;
1316 if (cookie->GetNext(&nodeID, &name) == B_OK) {
1317 PRINT(" entry: `%s'\n", name);
1318 size_t nameLen = strlen(name);
1319 // check, whether the entry fits into the buffer,
1320 // and fill it in
1321 size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
1322 if (length <= bufferSize) {
1323 buffer->d_dev = volume->GetID();
1324 buffer->d_ino = nodeID;
1325 memcpy(buffer->d_name, name, nameLen);
1326 buffer->d_name[nameLen] = '\0';
1327 buffer->d_reclen = length;
1328 *count = 1;
1329 } else {
1330 SET_ERROR(error, B_BUFFER_OVERFLOW);
1331 }
1332 } else
1333 *count = 0;
1334
1335 cookie->Suspend();
1336 }
1337
1338 RETURN_ERROR(error);
1339 }
1340
1341
1342 static status_t
ramfs_rewind_dir(fs_volume *,fs_vnode *,void * _cookie)1343 ramfs_rewind_dir(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
1344 {
1345 FUNCTION_START();
1346 // No locking needed, since the Directory is guaranteed to live at this
1347 // time and for iterators there is a separate locking.
1348 DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1349 // no need to Resume(), iterator remains suspended
1350 status_t error = cookie->Rewind();
1351 RETURN_ERROR(error);
1352 }
1353
1354
1355 // #pragma mark - Attribute Directories
1356
1357
1358 static status_t
ramfs_open_attr_dir(fs_volume * _volume,fs_vnode * _node,void ** _cookie)1359 ramfs_open_attr_dir(fs_volume* _volume, fs_vnode* _node, void** _cookie)
1360 {
1361 FUNCTION_START();
1362 Volume* volume = (Volume*)_volume->private_volume;
1363 Node* node = (Node*)_node->private_node;
1364
1365 VolumeReadLocker locker(volume);
1366 if (!locker.IsLocked())
1367 RETURN_ERROR(B_ERROR);
1368
1369 status_t error = B_OK;
1370 // check permissions
1371 error = node->CheckPermissions(ACCESS_R);
1372 // create iterator
1373 AttributeIterator *iterator = NULL;
1374 if (error == B_OK) {
1375 iterator = new(nothrow) AttributeIterator(node);
1376 if (iterator)
1377 error = iterator->Suspend();
1378 else
1379 SET_ERROR(error, B_NO_MEMORY);
1380 }
1381 // set result / cleanup on failure
1382 if (error == B_OK)
1383 *_cookie = iterator;
1384 else
1385 delete iterator;
1386 RETURN_ERROR(error);
1387 }
1388
1389
1390 static status_t
ramfs_close_attr_dir(fs_volume *,fs_vnode *,void * _cookie)1391 ramfs_close_attr_dir(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
1392 {
1393 FUNCTION_START();
1394 // No locking needed, since the Node is guaranteed to live at this time
1395 // and for iterators there is a separate locking.
1396 AttributeIterator *iterator = (AttributeIterator*)_cookie;
1397 iterator->Unset();
1398 return B_OK;
1399 }
1400
1401
1402 static status_t
ramfs_free_attr_dir_cookie(fs_volume *,fs_vnode *,void * _cookie)1403 ramfs_free_attr_dir_cookie(fs_volume* /*fs*/, fs_vnode* /*_node*/,
1404 void* _cookie)
1405 {
1406 FUNCTION_START();
1407 // No locking needed, since the Node is guaranteed to live at this time
1408 // and for iterators there is a separate locking.
1409 AttributeIterator *iterator = (AttributeIterator*)_cookie;
1410 delete iterator;
1411 return B_OK;
1412 }
1413
1414
1415 static status_t
ramfs_read_attr_dir(fs_volume * _volume,fs_vnode * _node,void * _cookie,struct dirent * buffer,size_t bufferSize,uint32 * count)1416 ramfs_read_attr_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie,
1417 struct dirent *buffer, size_t bufferSize, uint32 *count)
1418 {
1419 FUNCTION_START();
1420 Volume* volume = (Volume*)_volume->private_volume;
1421
1422 AttributeIterator *iterator = (AttributeIterator*)_cookie;
1423
1424 VolumeReadLocker locker(volume);
1425 if (!locker.IsLocked())
1426 RETURN_ERROR(B_ERROR);
1427
1428 status_t error = iterator->Resume();
1429 if (error == B_OK) {
1430 // get next attribute
1431 Attribute *attribute = NULL;
1432 if (iterator->GetNext(&attribute) == B_OK) {
1433 const char *name = attribute->GetName();
1434 size_t nameLen = strlen(name);
1435 // check, whether the entry fits into the buffer,
1436 // and fill it in
1437 size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
1438 if (length <= bufferSize) {
1439 buffer->d_dev = volume->GetID();
1440 buffer->d_ino = -1; // attributes don't have a node ID
1441 memcpy(buffer->d_name, name, nameLen);
1442 buffer->d_name[nameLen] = '\0';
1443 buffer->d_reclen = length;
1444 *count = 1;
1445 } else {
1446 SET_ERROR(error, B_BUFFER_OVERFLOW);
1447 }
1448 } else
1449 *count = 0;
1450
1451 iterator->Suspend();
1452 }
1453
1454 RETURN_ERROR(error);
1455 }
1456
1457
1458 static status_t
ramfs_rewind_attr_dir(fs_volume *,fs_vnode *,void * _cookie)1459 ramfs_rewind_attr_dir(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
1460 {
1461 FUNCTION_START();
1462 // No locking needed, since the Node is guaranteed to live at this time
1463 // and for iterators there is a separate locking.
1464 AttributeIterator *iterator = (AttributeIterator*)_cookie;
1465 // no need to Resume(), iterator remains suspended
1466 status_t error = iterator->Rewind();
1467 RETURN_ERROR(error);
1468 }
1469
1470
1471 // #pragma mark - Attributes
1472
1473
1474 class AttributeCookie {
1475 public:
AttributeCookie()1476 AttributeCookie() : fOpenMode(0), fLastNotificationTime(0) {}
1477
Init(const char * name,int openMode)1478 status_t Init(const char* name, int openMode)
1479 {
1480 if (!fName.SetTo(name))
1481 return B_NO_MEMORY;
1482 fOpenMode = openMode;
1483
1484 return B_OK;
1485 }
1486
GetName() const1487 inline const char* GetName() const { return fName.GetString(); }
1488
GetOpenMode() const1489 inline int GetOpenMode() const { return fOpenMode; }
1490
GetLastNotificationTime() const1491 inline bigtime_t GetLastNotificationTime() const
1492 { return fLastNotificationTime; }
1493
NotificationIntervalElapsed(bool set=false)1494 inline bool NotificationIntervalElapsed(bool set = false)
1495 {
1496 bigtime_t currentTime = system_time();
1497 bool result = (currentTime - fLastNotificationTime
1498 > kNotificationInterval);
1499 if (set && result)
1500 fLastNotificationTime = currentTime;
1501 return result;
1502 }
1503
1504 private:
1505 String fName;
1506 int fOpenMode;
1507 bigtime_t fLastNotificationTime;
1508 };
1509
1510
1511 static status_t
ramfs_create_attr(fs_volume * _volume,fs_vnode * _node,const char * name,uint32 type,int openMode,void ** _cookie)1512 ramfs_create_attr(fs_volume* _volume, fs_vnode* _node, const char *name,
1513 uint32 type, int openMode, void** _cookie)
1514 {
1515 Volume* volume = (Volume*)_volume->private_volume;
1516 Node* node = (Node*)_node->private_node;
1517
1518 VolumeWriteLocker locker(volume);
1519 if (!locker.IsLocked())
1520 RETURN_ERROR(B_ERROR);
1521
1522 // try to find the attribute
1523 Attribute *attribute = NULL;
1524 node->FindAttribute(name, &attribute);
1525
1526 // in case the attribute exists we fail if required by the openMode
1527 if (attribute && (openMode & O_EXCL))
1528 RETURN_ERROR(B_FILE_EXISTS);
1529
1530 // creating and truncating require write permission
1531 int accessMode = open_mode_to_access(openMode);
1532 if (!attribute || (openMode & O_TRUNC))
1533 accessMode |= ACCESS_W;
1534
1535 // check required permissions against node permissions
1536 status_t error = node->CheckPermissions(accessMode);
1537 if (error != B_OK)
1538 RETURN_ERROR(error);
1539
1540 // create the cookie
1541 AttributeCookie *cookie = new(nothrow) AttributeCookie();
1542 if (!cookie)
1543 return B_NO_MEMORY;
1544 ObjectDeleter<AttributeCookie> cookieDeleter(cookie);
1545
1546 // init the cookie
1547 error = cookie->Init(name, openMode);
1548 if (error != B_OK)
1549 RETURN_ERROR(error);
1550
1551 // if not existing yet, create the attribute and set its type
1552 if (!attribute) {
1553 error = node->CreateAttribute(name, &attribute);
1554 if (error != B_OK)
1555 RETURN_ERROR(error);
1556
1557 attribute->SetType(type);
1558
1559 notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
1560 B_ATTR_CREATED);
1561
1562 // else truncate if requested
1563 } else if (openMode & O_TRUNC) {
1564 error = attribute->SetSize(0);
1565 if (error != B_OK)
1566 return error;
1567
1568 notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
1569 B_ATTR_CHANGED);
1570 }
1571 NodeMTimeUpdater mTimeUpdater(node);
1572
1573 // success
1574 cookieDeleter.Detach();
1575 *_cookie = cookie;
1576
1577 return B_OK;
1578 }
1579
1580
1581 static status_t
ramfs_open_attr(fs_volume * _volume,fs_vnode * _node,const char * name,int openMode,void ** _cookie)1582 ramfs_open_attr(fs_volume* _volume, fs_vnode* _node, const char *name,
1583 int openMode, void** _cookie)
1584 {
1585 Volume* volume = (Volume*)_volume->private_volume;
1586 Node* node = (Node*)_node->private_node;
1587
1588 FUNCTION(("node: %lld\n", node->GetID()));
1589
1590 status_t error = B_OK;
1591
1592 VolumeWriteLocker locker(volume);
1593 if (!locker.IsLocked())
1594 RETURN_ERROR(B_ERROR);
1595
1596 // find the attribute
1597 Attribute *attribute = NULL;
1598 if (error == B_OK)
1599 error = node->FindAttribute(name, &attribute);
1600
1601 // truncating requires write permission
1602 int accessMode = open_mode_to_access(openMode);
1603 if (error == B_OK && (openMode & O_TRUNC))
1604 accessMode |= ACCESS_W;
1605
1606 // check open mode against permissions
1607 if (error == B_OK)
1608 error = node->CheckPermissions(accessMode);
1609
1610 // create the cookie
1611 AttributeCookie *cookie = NULL;
1612 if (error == B_OK) {
1613 cookie = new(nothrow) AttributeCookie();
1614 if (cookie) {
1615 SET_ERROR(error, cookie->Init(name, openMode));
1616 } else {
1617 SET_ERROR(error, B_NO_MEMORY);
1618 }
1619 }
1620
1621 // truncate if requested
1622 if (error == B_OK && (openMode & O_TRUNC)) {
1623 error = attribute->SetSize(0);
1624
1625 if (error == B_OK) {
1626 notify_attribute_changed(volume->GetID(), -1, node->GetID(),
1627 name, B_ATTR_CHANGED);
1628 }
1629 }
1630 NodeMTimeUpdater mTimeUpdater(node);
1631
1632 // set result / cleanup on failure
1633 if (error == B_OK)
1634 *_cookie = cookie;
1635 else if (cookie)
1636 delete cookie;
1637
1638 RETURN_ERROR(error);
1639 }
1640
1641
1642 static status_t
ramfs_close_attr(fs_volume * _volume,fs_vnode * _node,void * _cookie)1643 ramfs_close_attr(fs_volume* _volume, fs_vnode* _node, void* _cookie)
1644 {
1645 FUNCTION(("node: %lld\n", node->GetID()));
1646
1647 Volume* volume = (Volume*)_volume->private_volume;
1648 Node* node = (Node*)_node->private_node;
1649
1650 VolumeWriteLocker locker(volume);
1651 if (!locker.IsLocked())
1652 RETURN_ERROR(B_ERROR);
1653
1654 // notify listeners
1655 notify_if_stat_changed(volume, node);
1656 return B_OK;
1657 }
1658
1659
1660 static status_t
ramfs_free_attr_cookie(fs_volume *,fs_vnode *,void * _cookie)1661 ramfs_free_attr_cookie(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
1662 {
1663 FUNCTION_START();
1664 AttributeCookie *cookie = (AttributeCookie*)_cookie;
1665 delete cookie;
1666 return B_OK;
1667 }
1668
1669
1670 static status_t
ramfs_read_attr(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,void * buffer,size_t * bufferSize)1671 ramfs_read_attr(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
1672 void *buffer, size_t *bufferSize)
1673 {
1674 FUNCTION_START();
1675
1676 Volume* volume = (Volume*)_volume->private_volume;
1677 Node* node = (Node*)_node->private_node;
1678
1679 AttributeCookie *cookie = (AttributeCookie*)_cookie;
1680
1681 VolumeReadLocker locker(volume);
1682 if (!locker.IsLocked())
1683 RETURN_ERROR(B_ERROR);
1684
1685 status_t error = B_OK;
1686
1687 // find the attribute
1688 Attribute *attribute = NULL;
1689 if (error == B_OK)
1690 error = node->FindAttribute(cookie->GetName(), &attribute);
1691
1692 // check permissions
1693 int accessMode = open_mode_to_access(cookie->GetOpenMode());
1694 if (error == B_OK && !(accessMode & ACCESS_R))
1695 SET_ERROR(error, B_NOT_ALLOWED);
1696
1697 // read
1698 if (error == B_OK)
1699 error = attribute->ReadAt(pos, buffer, *bufferSize, bufferSize);
1700
1701 RETURN_ERROR(error);
1702 }
1703
1704
1705 static status_t
ramfs_write_attr(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,const void * buffer,size_t * bufferSize)1706 ramfs_write_attr(fs_volume* _volume, fs_vnode* _node, void* _cookie,
1707 off_t pos, const void *buffer, size_t *bufferSize)
1708 {
1709 FUNCTION_START();
1710
1711 Volume* volume = (Volume*)_volume->private_volume;
1712 Node* node = (Node*)_node->private_node;
1713 AttributeCookie *cookie = (AttributeCookie*)_cookie;
1714
1715 status_t error = B_OK;
1716 // Don't allow writing the reserved attributes.
1717 const char *name = cookie->GetName();
1718 if (name[0] == '\0' || !strcmp(name, "name")
1719 || !strcmp(name, "last_modified") || !strcmp(name, "size")) {
1720 // FUNCTION(("failed: node: %s, attribute: %s\n",
1721 // node->GetName(), name));
1722 RETURN_ERROR(B_NOT_ALLOWED);
1723 }
1724
1725 VolumeWriteLocker locker(volume);
1726 if (!locker.IsLocked())
1727 RETURN_ERROR(B_ERROR);
1728
1729 NodeMTimeUpdater mTimeUpdater(node);
1730
1731 // find the attribute
1732 Attribute *attribute = NULL;
1733 if (error == B_OK)
1734 error = node->FindAttribute(cookie->GetName(), &attribute);
1735
1736 // check permissions
1737 int accessMode = open_mode_to_access(cookie->GetOpenMode());
1738 if (error == B_OK && !(accessMode & ACCESS_W))
1739 SET_ERROR(error, B_NOT_ALLOWED);
1740
1741 // write the data
1742 if (error == B_OK)
1743 error = attribute->WriteAt(pos, buffer, *bufferSize, bufferSize);
1744
1745 // notify listeners
1746 if (error == B_OK) {
1747 notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
1748 B_ATTR_CHANGED);
1749 }
1750
1751 RETURN_ERROR(error);
1752 }
1753
1754
1755 static status_t
ramfs_read_attr_stat(fs_volume * _volume,fs_vnode * _node,void * _cookie,struct stat * st)1756 ramfs_read_attr_stat(fs_volume* _volume, fs_vnode* _node, void* _cookie,
1757 struct stat *st)
1758 {
1759 // FUNCTION_START();
1760
1761 Volume* volume = (Volume*)_volume->private_volume;
1762 Node* node = (Node*)_node->private_node;
1763 AttributeCookie *cookie = (AttributeCookie*)_cookie;
1764 status_t error = B_OK;
1765
1766 VolumeReadLocker locker(volume);
1767 if (!locker.IsLocked())
1768 RETURN_ERROR(B_ERROR);
1769
1770 // find the attribute
1771 Attribute *attribute = NULL;
1772 if (error == B_OK)
1773 error = node->FindAttribute(cookie->GetName(), &attribute);
1774
1775 // check permissions
1776 int accessMode = open_mode_to_access(cookie->GetOpenMode());
1777 if (error == B_OK && !(accessMode & ACCESS_R))
1778 SET_ERROR(error, B_NOT_ALLOWED);
1779
1780 // read
1781 if (error == B_OK) {
1782 st->st_type = attribute->GetType();
1783 st->st_size = attribute->GetSize();
1784 }
1785
1786 RETURN_ERROR(error);
1787 }
1788
1789
1790 static status_t
ramfs_rename_attr(fs_volume *,fs_vnode *,const char *,fs_vnode *,const char *)1791 ramfs_rename_attr(fs_volume* /*fs*/, fs_vnode* /*_fromNode*/,
1792 const char */*fromName*/, fs_vnode* /*_toNode*/, const char */*toName*/)
1793 {
1794 // TODO : ramfs_rename_attr
1795 return B_BAD_VALUE;
1796 }
1797
1798
1799 static status_t
ramfs_remove_attr(fs_volume * _volume,fs_vnode * _node,const char * name)1800 ramfs_remove_attr(fs_volume* _volume, fs_vnode* _node, const char *name)
1801 {
1802 FUNCTION_START();
1803 Volume* volume = (Volume*)_volume->private_volume;
1804 Node* node = (Node*)_node->private_node;
1805 status_t error = B_OK;
1806
1807 VolumeWriteLocker locker(volume);
1808 if (!locker.IsLocked())
1809 RETURN_ERROR(B_ERROR);
1810
1811 NodeMTimeUpdater mTimeUpdater(node);
1812
1813 // check permissions
1814 error = node->CheckPermissions(ACCESS_W);
1815
1816 // find the attribute
1817 Attribute *attribute = NULL;
1818 if (error == B_OK)
1819 error = node->FindAttribute(name, &attribute);
1820
1821 // delete it
1822 if (error == B_OK)
1823 error = node->DeleteAttribute(attribute);
1824
1825 // notify listeners
1826 if (error == B_OK) {
1827 notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
1828 B_ATTR_REMOVED);
1829 }
1830
1831 RETURN_ERROR(error);
1832 }
1833
1834
1835 // #pragma mark - Indices
1836
1837
1838 // IndexDirCookie
1839 class IndexDirCookie {
1840 public:
IndexDirCookie()1841 IndexDirCookie() : index_index(0) {}
1842
1843 int32 index_index;
1844 };
1845
1846
1847 static status_t
ramfs_open_index_dir(fs_volume * _volume,void ** _cookie)1848 ramfs_open_index_dir(fs_volume* _volume, void** _cookie)
1849 {
1850 FUNCTION_START();
1851 Volume* volume = (Volume*)_volume->private_volume;
1852
1853 VolumeReadLocker locker(volume);
1854 if (!locker.IsLocked())
1855 RETURN_ERROR(B_ERROR);
1856
1857 status_t error = B_OK;
1858 // check whether an index directory exists
1859 if (volume->GetIndexDirectory()) {
1860 IndexDirCookie *cookie = new(nothrow) IndexDirCookie;
1861 if (cookie)
1862 *_cookie = cookie;
1863 else
1864 SET_ERROR(error, B_NO_MEMORY);
1865 } else
1866 SET_ERROR(error, B_ENTRY_NOT_FOUND);
1867
1868 RETURN_ERROR(error);
1869 }
1870
1871
1872 static status_t
ramfs_close_index_dir(fs_volume *,void *)1873 ramfs_close_index_dir(fs_volume* /*fs*/, void* /*_cookie*/)
1874 {
1875 FUNCTION_START();
1876 return B_OK;
1877 }
1878
1879
1880 static status_t
ramfs_free_index_dir_cookie(fs_volume *,void * _cookie)1881 ramfs_free_index_dir_cookie(fs_volume* /*fs*/, void* _cookie)
1882 {
1883 FUNCTION_START();
1884 IndexDirCookie *cookie = (IndexDirCookie*)_cookie;
1885 delete cookie;
1886 return B_OK;
1887 }
1888
1889
1890 static status_t
ramfs_read_index_dir(fs_volume * _volume,void * _cookie,struct dirent * buffer,size_t bufferSize,uint32 * count)1891 ramfs_read_index_dir(fs_volume* _volume, void* _cookie,
1892 struct dirent *buffer, size_t bufferSize, uint32 *count)
1893 {
1894 FUNCTION_START();
1895 Volume* volume = (Volume*)_volume->private_volume;
1896 IndexDirCookie *cookie = (IndexDirCookie*)_cookie;
1897 status_t error = B_OK;
1898
1899 VolumeReadLocker locker(volume);
1900 if (!locker.IsLocked())
1901 RETURN_ERROR(B_ERROR);
1902
1903 // get the next index
1904 Index *index = volume->GetIndexDirectory()->IndexAt(
1905 cookie->index_index++);
1906 if (index) {
1907 const char *name = index->GetName();
1908 size_t nameLen = strlen(name);
1909 // check, whether the entry fits into the buffer,
1910 // and fill it in
1911 size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
1912 if (length <= bufferSize) {
1913 buffer->d_dev = volume->GetID();
1914 buffer->d_ino = -1; // indices don't have a node ID
1915 memcpy(buffer->d_name, name, nameLen);
1916 buffer->d_name[nameLen] = '\0';
1917 buffer->d_reclen = length;
1918 *count = 1;
1919 } else {
1920 SET_ERROR(error, B_BUFFER_OVERFLOW);
1921 }
1922 } else
1923 *count = 0;
1924
1925 RETURN_ERROR(error);
1926 }
1927
1928
1929 static status_t
ramfs_rewind_index_dir(fs_volume *,void * _cookie)1930 ramfs_rewind_index_dir(fs_volume* /*fs*/, void* _cookie)
1931 {
1932 FUNCTION_START();
1933 IndexDirCookie *cookie = (IndexDirCookie*)_cookie;
1934 cookie->index_index = 0;
1935 return B_OK;
1936 }
1937
1938
1939 static status_t
ramfs_create_index(fs_volume * _volume,const char * name,uint32 type,uint32)1940 ramfs_create_index(fs_volume* _volume, const char *name, uint32 type,
1941 uint32 /*flags*/)
1942 {
1943 FUNCTION_START();
1944 Volume* volume = (Volume*)_volume->private_volume;
1945 status_t error = B_OK;
1946
1947 // only root is allowed to manipulate the indices
1948 if (geteuid() != 0)
1949 RETURN_ERROR(B_NOT_ALLOWED);
1950
1951 VolumeWriteLocker locker(volume);
1952 if (!locker.IsLocked())
1953 RETURN_ERROR(B_ERROR);
1954
1955 // get the index directory
1956 if (IndexDirectory *indexDir = volume->GetIndexDirectory()) {
1957 // check whether an index with that name does already exist
1958 if (indexDir->FindIndex(name)) {
1959 SET_ERROR(error, B_FILE_EXISTS);
1960 } else {
1961 // create the index
1962 AttributeIndex *index;
1963 error = indexDir->CreateIndex(name, type, &index);
1964 }
1965 } else
1966 SET_ERROR(error, B_ENTRY_NOT_FOUND);
1967
1968 RETURN_ERROR(error);
1969 }
1970
1971
1972 static status_t
ramfs_remove_index(fs_volume * _volume,const char * name)1973 ramfs_remove_index(fs_volume* _volume, const char *name)
1974 {
1975 FUNCTION_START();
1976 Volume* volume = (Volume*)_volume->private_volume;
1977 status_t error = B_OK;
1978
1979 // only root is allowed to manipulate the indices
1980 if (geteuid() != 0)
1981 RETURN_ERROR(B_NOT_ALLOWED);
1982
1983 VolumeWriteLocker locker(volume);
1984 if (!locker.IsLocked())
1985 RETURN_ERROR(B_ERROR);
1986
1987 // get the index directory
1988 if (IndexDirectory *indexDir = volume->GetIndexDirectory()) {
1989 // check whether an index with that name does exist
1990 if (Index *index = indexDir->FindIndex(name)) {
1991 // don't delete a special index
1992 if (indexDir->IsSpecialIndex(index)) {
1993 SET_ERROR(error, B_BAD_VALUE);
1994 } else
1995 indexDir->DeleteIndex(index);
1996 } else
1997 SET_ERROR(error, B_ENTRY_NOT_FOUND);
1998 } else
1999 SET_ERROR(error, B_ENTRY_NOT_FOUND);
2000
2001 RETURN_ERROR(error);
2002 }
2003
2004
2005 static status_t
ramfs_read_index_stat(fs_volume * _volume,const char * name,struct stat * st)2006 ramfs_read_index_stat(fs_volume* _volume, const char *name, struct stat *st)
2007 {
2008 FUNCTION_START();
2009 Volume* volume = (Volume*)_volume->private_volume;
2010 status_t error = B_OK;
2011
2012 VolumeReadLocker locker(volume);
2013 if (!locker.IsLocked())
2014 RETURN_ERROR(B_ERROR);
2015
2016 // get the index directory
2017 if (IndexDirectory *indexDir = volume->GetIndexDirectory()) {
2018 // find the index
2019 if (Index *index = indexDir->FindIndex(name)) {
2020 st->st_type = index->GetType();
2021 if (index->HasFixedKeyLength())
2022 st->st_size = index->GetKeyLength();
2023 else
2024 st->st_size = kMaxIndexKeyLength;
2025 st->st_atime = 0; // TODO: index times
2026 st->st_mtime = 0; // ...
2027 st->st_ctime = 0; // ...
2028 st->st_crtime = 0; // ...
2029 st->st_uid = 0; // root owns the indices
2030 st->st_gid = 0; //
2031 } else
2032 SET_ERROR(error, B_ENTRY_NOT_FOUND);
2033 } else
2034 SET_ERROR(error, B_ENTRY_NOT_FOUND);
2035
2036 RETURN_ERROR(error);
2037 }
2038
2039
2040 // #pragma mark - Queries
2041
2042
2043 static status_t
ramfs_open_query(fs_volume * _volume,const char * queryString,uint32 flags,port_id port,uint32 token,void ** _cookie)2044 ramfs_open_query(fs_volume* _volume, const char *queryString, uint32 flags,
2045 port_id port, uint32 token, void** _cookie)
2046 {
2047 FUNCTION_START();
2048 PRINT("query = \"%s\", flags = %lu, port_id = %" B_PRId32 ", token = %" B_PRId32 "\n",
2049 queryString, flags, port, token);
2050
2051 Volume* volume = (Volume*)_volume->private_volume;
2052
2053 // lock the volume
2054 VolumeWriteLocker locker(volume);
2055 if (!locker.IsLocked())
2056 RETURN_ERROR(B_ERROR);
2057
2058 Query* query;
2059 status_t error = Query::Create(volume, queryString, flags, port, token, query);
2060 if (error != B_OK)
2061 return error;
2062 // TODO: The Query references an Index, but nothing prevents the Index
2063 // from being deleted, while the Query is in existence.
2064
2065 *_cookie = (void *)query;
2066
2067 return B_OK;
2068 }
2069
2070
2071 static status_t
ramfs_close_query(fs_volume *,void *)2072 ramfs_close_query(fs_volume* /*fs*/, void* /*cookie*/)
2073 {
2074 FUNCTION_START();
2075 return B_OK;
2076 }
2077
2078
2079 static status_t
ramfs_free_query_cookie(fs_volume * _volume,void * _cookie)2080 ramfs_free_query_cookie(fs_volume* _volume, void* _cookie)
2081 {
2082 FUNCTION_START();
2083
2084 Volume* volume = (Volume*)_volume->private_volume;
2085
2086 // lock the volume
2087 VolumeWriteLocker locker(volume);
2088 if (!locker.IsLocked())
2089 RETURN_ERROR(B_ERROR);
2090
2091 Query *query = (Query *)_cookie;
2092 delete query;
2093
2094 return B_OK;
2095 }
2096
2097
2098 static status_t
ramfs_read_query(fs_volume * _volume,void * _cookie,struct dirent * buffer,size_t bufferSize,uint32 * count)2099 ramfs_read_query(fs_volume* _volume, void* _cookie, struct dirent *buffer,
2100 size_t bufferSize, uint32 *count)
2101 {
2102 FUNCTION_START();
2103 Query *query = (Query *)_cookie;
2104 Volume* volume = (Volume*)_volume->private_volume;
2105
2106 // lock the volume
2107 VolumeReadLocker locker(volume);
2108 if (!locker.IsLocked())
2109 RETURN_ERROR(B_ERROR);
2110
2111 status_t status = query->GetNextEntry(buffer, bufferSize);
2112 if (status == B_OK)
2113 *count = 1;
2114 else if (status == B_ENTRY_NOT_FOUND)
2115 *count = 0;
2116 else
2117 return status;
2118
2119 return B_OK;
2120 }
2121
2122
2123 // TODO: status_t (*rewind_query)(fs_volume fs, void** _cookie);
2124
2125
2126 // #pragma mark - Module Interface
2127
2128
2129 static status_t
ramfs_std_ops(int32 op,...)2130 ramfs_std_ops(int32 op, ...)
2131 {
2132 switch (op) {
2133 case B_MODULE_INIT:
2134 {
2135 init_debugging();
2136 PRINT("ramfs_std_ops(): B_MODULE_INIT\n");
2137 return B_OK;
2138 }
2139
2140 case B_MODULE_UNINIT:
2141 PRINT("ramfs_std_ops(): B_MODULE_UNINIT\n");
2142 exit_debugging();
2143 return B_OK;
2144
2145 default:
2146 return B_ERROR;
2147 }
2148 }
2149
2150
2151 fs_volume_ops gRamFSVolumeOps = {
2152 &ramfs_unmount,
2153 &ramfs_read_fs_info,
2154 &ramfs_write_fs_info,
2155 &ramfs_sync,
2156 &ramfs_get_vnode,
2157
2158 /* index directory & index operations */
2159 &ramfs_open_index_dir,
2160 &ramfs_close_index_dir,
2161 &ramfs_free_index_dir_cookie,
2162 &ramfs_read_index_dir,
2163 &ramfs_rewind_index_dir,
2164
2165 &ramfs_create_index,
2166 &ramfs_remove_index,
2167 &ramfs_read_index_stat,
2168
2169 /* query operations */
2170 &ramfs_open_query,
2171 &ramfs_close_query,
2172 &ramfs_free_query_cookie,
2173 &ramfs_read_query,
2174 NULL // rewind_query
2175 };
2176
2177
2178 fs_vnode_ops gRamFSVnodeOps = {
2179 /* vnode operations */
2180 &ramfs_lookup, // lookup
2181 NULL, // get name
2182 &ramfs_write_vnode, // write
2183 &ramfs_remove_vnode, // remove
2184
2185 /* VM file access */
2186 NULL, // can_page
2187 NULL, // read pages
2188 NULL, // write pages
2189
2190 NULL, // io?
2191 NULL, // cancel io
2192
2193 NULL, // get file map
2194
2195 &ramfs_ioctl,
2196 &ramfs_set_flags,
2197 NULL, // &ramfs_select,
2198 NULL, // &ramfs_deselect,
2199 &ramfs_fsync,
2200
2201 &ramfs_read_symlink,
2202 &ramfs_create_symlink,
2203
2204 &ramfs_link,
2205 &ramfs_unlink,
2206 &ramfs_rename,
2207
2208 &ramfs_access,
2209 &ramfs_read_stat,
2210 &ramfs_write_stat,
2211 NULL, // &ramfs_preallocate,
2212
2213 /* file operations */
2214 &ramfs_create,
2215 &ramfs_open,
2216 &ramfs_close,
2217 &ramfs_free_cookie,
2218 &ramfs_read,
2219 &ramfs_write,
2220
2221 /* directory operations */
2222 &ramfs_create_dir,
2223 &ramfs_remove_dir,
2224 &ramfs_open_dir,
2225 &ramfs_close_dir,
2226 &ramfs_free_dir_cookie,
2227 &ramfs_read_dir,
2228 &ramfs_rewind_dir,
2229
2230 /* attribute directory operations */
2231 &ramfs_open_attr_dir,
2232 &ramfs_close_attr_dir,
2233 &ramfs_free_attr_dir_cookie,
2234 &ramfs_read_attr_dir,
2235 &ramfs_rewind_attr_dir,
2236
2237 /* attribute operations */
2238 &ramfs_create_attr,
2239 &ramfs_open_attr,
2240 &ramfs_close_attr,
2241 &ramfs_free_attr_cookie,
2242 &ramfs_read_attr,
2243 &ramfs_write_attr,
2244
2245 &ramfs_read_attr_stat,
2246 NULL, // &ramfs_write_attr_stat,
2247 &ramfs_rename_attr,
2248 &ramfs_remove_attr,
2249
2250 /* special nodes */
2251 NULL // create_special_node
2252 };
2253
2254 static file_system_module_info sRamFSModuleInfo = {
2255 {
2256 "file_systems/ramfs" B_CURRENT_FS_API_VERSION,
2257 0,
2258 ramfs_std_ops,
2259 },
2260
2261 "ramfs", // short_name
2262 "RAM File System", // pretty_name
2263 0 // DDM flags
2264 | B_DISK_SYSTEM_SUPPORTS_WRITING,
2265
2266 // scanning
2267 NULL, // identify_partition()
2268 NULL, // scan_partition()
2269 NULL, // free_identify_partition_cookie()
2270 NULL, // free_partition_content_cookie()
2271
2272 &ramfs_mount,
2273
2274 NULL, // TODO : &ramfs_get_supported_operations
2275
2276 NULL, // validate_resize
2277 NULL, // validate_move
2278 NULL, // validate_set_content_name
2279 NULL, // validate_set_content_parameters
2280 NULL, // validate_initialize,
2281
2282 /* shadow partition modification */
2283 NULL, // shadow_changed
2284
2285 /* writing */
2286 NULL, // defragment
2287 NULL, // repair
2288 NULL, // resize
2289 NULL, // move
2290 NULL, // set_content_name
2291 NULL, // set_content_parameters
2292 NULL // bfs_initialize
2293 };
2294
2295 module_info *modules[] = {
2296 (module_info *)&sRamFSModuleInfo,
2297 NULL,
2298 };
2299