1 // kernel_interface.cpp
3 // Copyright (c) 2003-2010, Ingo Weinhold (bonefish@cs.tu-berlin.de)
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 // You can alternatively use *this file* under the terms of the the MIT
20 // license included in this package.
38 #include <fs_interface.h>
39 #include <KernelExport.h>
42 #include "Iterators.h"
51 static const size_t kOptimalIOSize
= 65536;
53 extern fs_volume_ops gReiserFSVolumeOps
;
54 extern fs_vnode_ops gReiserFSVnodeOps
;
60 // reiserfs_identify_partition
62 reiserfs_identify_partition(int fd
, partition_data
*partition
, void **cookie
)
64 Volume
* volume
= new(nothrow
) Volume();
68 status_t status
= volume
->Identify(fd
, partition
);
74 *cookie
= (void*)volume
;
79 // reiserfs_scan_partition
81 reiserfs_scan_partition(int fd
, partition_data
*partition
, void *_cookie
)
83 Volume
* volume
= (Volume
*)_cookie
;
85 partition
->status
= B_PARTITION_VALID
;
86 partition
->flags
|= B_PARTITION_FILE_SYSTEM
;
87 partition
->content_size
= volume
->CountBlocks()
88 * volume
->GetBlockSize();
89 partition
->block_size
= volume
->GetBlockSize();
91 volume
->UpdateName(partition
->id
);
92 // must be done after setting the content size
93 partition
->content_name
= strdup(volume
->GetName());
94 if (partition
->content_name
== NULL
)
101 // reiserfs_free_identify_partition_cookie
103 reiserfs_free_identify_partition_cookie(partition_data
* partition
,
106 delete (Volume
*)_cookie
;
115 reiserfs_mount(fs_volume
*_volume
, const char *device
, uint32 flags
,
116 const char *parameters
, ino_t
*rootID
)
118 TOUCH(flags
); TOUCH(parameters
);
120 // parameters are ignored for now
121 status_t error
= B_OK
;
123 // allocate and init the volume
124 Volume
*volume
= new(nothrow
) Volume
;
128 error
= volume
->Mount(_volume
, device
);
132 *rootID
= volume
->GetRootVNode()->GetID();
133 _volume
->private_volume
= volume
;
134 _volume
->ops
= &gReiserFSVolumeOps
;
137 // cleanup on failure
138 if (error
!= B_OK
&& volume
)
146 reiserfs_unmount(fs_volume
* fs
)
149 Volume
*volume
= (Volume
*)fs
->private_volume
;
150 status_t error
= volume
->Unmount();
156 // reiserfs_read_fs_info
158 reiserfs_read_fs_info(fs_volume
* fs
, struct fs_info
*info
)
161 Volume
*volume
= (Volume
*)fs
->private_volume
;
162 info
->flags
= B_FS_IS_PERSISTENT
| B_FS_IS_READONLY
;
163 info
->block_size
= volume
->GetBlockSize();
164 info
->io_size
= kOptimalIOSize
;
165 info
->total_blocks
= volume
->CountBlocks();
166 info
->free_blocks
= volume
->CountFreeBlocks();
167 strlcpy(info
->device_name
, volume
->GetDeviceName(),
168 sizeof(info
->device_name
));
169 strlcpy(info
->volume_name
, volume
->GetName(), sizeof(info
->volume_name
));
174 // #pragma mark - VNodes
179 reiserfs_lookup(fs_volume
* fs
, fs_vnode
* _dir
, const char *entryName
,
183 Volume
*volume
= (Volume
*)fs
->private_volume
;
184 VNode
*dir
= (VNode
*)_dir
->private_node
;
185 FUNCTION(("dir: (%Ld: %lu, %lu), entry: `%s'\n", dir
->GetID(), dir
->GetDirID(),
186 dir
->GetObjectID(), entryName
));
187 status_t error
= B_OK
;
188 VNode
*entryNode
= NULL
;
190 // check for non-directories
192 error
= B_ENTRY_NOT_FOUND
;
194 // special entries: "." and ".."
195 } else if (!strcmp(entryName
, ".")) {
196 *vnid
= dir
->GetID();
197 if (volume
->GetVNode(*vnid
, &entryNode
) != B_OK
)
199 } else if (!strcmp(entryName
, "..")) {
200 *vnid
= dir
->GetParentID();
201 if (volume
->GetVNode(*vnid
, &entryNode
) != B_OK
)
208 error
= volume
->FindDirEntry(dir
, entryName
, &foundNode
, true);
210 // hide non-file/dir/symlink entries, if the user desires that, and
211 // those entries explicitly set to hidden
213 && ((foundNode
.IsEsoteric() && volume
->GetHideEsoteric())
214 || volume
->IsNegativeEntry(foundNode
.GetID()))) {
215 error
= B_ENTRY_NOT_FOUND
;
218 *vnid
= foundNode
.GetID();
219 error
= volume
->GetVNode(*vnid
, &entryNode
);
223 // add to the entry cache
225 entry_cache_add(volume
->GetID(), dir
->GetID(), entryName
,
232 // reiserfs_read_vnode
234 reiserfs_read_vnode(fs_volume
*fs
, ino_t vnid
, fs_vnode
*node
, int *_type
,
235 uint32
*_flags
, bool reenter
)
239 FUNCTION(("(%Ld: %lu, %ld)\n", vnid
, VNode::GetDirIDFor(vnid
),
240 VNode::GetObjectIDFor(vnid
)));
241 Volume
*volume
= (Volume
*)fs
->private_volume
;
242 status_t error
= B_OK
;
243 VNode
*foundNode
= new(nothrow
) VNode
;
245 error
= volume
->FindVNode(vnid
, foundNode
);
247 node
->private_node
= foundNode
;
248 node
->ops
= &gReiserFSVnodeOps
;
249 *_type
= foundNode
->GetStatData()->GetMode() & S_IFMT
;
258 // reiserfs_write_vnode
260 reiserfs_write_vnode(fs_volume
*fs
, fs_vnode
*_node
, bool reenter
)
263 // DANGER: If dbg_printf() is used, this thread will enter another FS and
264 // even perform a write operation. The is dangerous here, since this hook
265 // may be called out of the other FSs, since, for instance a put_vnode()
266 // called from another FS may cause the VFS layer to free vnodes and thus
269 Volume
*volume
= (Volume
*)fs
->private_volume
;
270 VNode
*node
= (VNode
*)_node
->private_node
;
271 status_t error
= B_OK
;
272 if (node
!= volume
->GetRootVNode())
274 // RETURN_ERROR(error);
279 // #pragma mark - Nodes
282 // reiserfs_read_symlink
284 reiserfs_read_symlink(fs_volume
*fs
, fs_vnode
*_node
, char *buffer
,
288 Volume
*volume
= (Volume
*)fs
->private_volume
;
289 VNode
*node
= (VNode
*)_node
->private_node
;
290 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
291 node
->GetObjectID()));
292 status_t error
= B_OK
;
293 // read symlinks only
294 if (!node
->IsSymlink())
298 error
= volume
->ReadLink(node
, buffer
, *bufferSize
, bufferSize
);
304 reiserfs_access(fs_volume
*fs
, fs_vnode
*_node
, int mode
)
307 VNode
*node
= (VNode
*)_node
->private_node
;
308 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
309 node
->GetObjectID()));
311 // write access requested?
313 return B_READ_ONLY_DEVICE
;
315 // get node permissions
316 StatData
*statData
= node
->GetStatData();
318 return check_access_permissions(mode
, statData
->GetMode(),
319 statData
->GetGID(), statData
->GetUID());
322 // reiserfs_read_stat
324 reiserfs_read_stat(fs_volume
*fs
, fs_vnode
*_node
, struct stat
*st
)
327 Volume
*volume
= (Volume
*)fs
->private_volume
;
328 VNode
*node
= (VNode
*)_node
->private_node
;
329 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
330 node
->GetObjectID()));
331 status_t error
= B_OK
;
332 StatData
*statData
= node
->GetStatData();
333 st
->st_dev
= volume
->GetID();
334 st
->st_ino
= node
->GetID();
335 st
->st_mode
= statData
->GetMode();
336 st
->st_nlink
= statData
->GetNLink();
337 st
->st_uid
= statData
->GetUID();
338 st
->st_gid
= statData
->GetGID();
339 st
->st_size
= statData
->GetSize();
340 st
->st_blksize
= kOptimalIOSize
;
341 st
->st_atime
= statData
->GetATime();
342 st
->st_mtime
= st
->st_ctime
= statData
->GetMTime();
343 st
->st_crtime
= statData
->GetCTime();
348 // #pragma mark - Files
353 reiserfs_open(fs_volume
*fs
, fs_vnode
*_node
, int openMode
, void **cookie
)
356 Volume
*volume
= (Volume
*)fs
->private_volume
;
357 VNode
*node
= (VNode
*)_node
->private_node
;
358 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
359 node
->GetObjectID()));
360 status_t error
= B_OK
;
361 // check the open mode
362 if ((openMode
& O_RWMASK
) == O_WRONLY
|| (openMode
& O_RWMASK
) == O_RDWR
363 || (openMode
& (O_TRUNC
| O_CREAT
))) {
364 error
= B_READ_ONLY_DEVICE
;
366 // create a StreamReader
368 StreamReader
*reader
= new(nothrow
) StreamReader(volume
->GetTree(),
369 node
->GetDirID(), node
->GetObjectID());
371 error
= reader
->Suspend();
384 reiserfs_close(fs_volume
*fs
, fs_vnode
*_node
, void *cookie
)
386 TOUCH(fs
); TOUCH(cookie
);
388 VNode
*node
= (VNode
*)_node
->private_node
;
389 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
390 node
->GetObjectID()));
395 // reiserfs_free_cookie
397 reiserfs_free_cookie(fs_volume
*fs
, fs_vnode
*_node
, void *cookie
)
401 VNode
*node
= (VNode
*)_node
->private_node
;
402 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
403 node
->GetObjectID()));
405 StreamReader
*reader
= (StreamReader
*)cookie
;
412 reiserfs_read(fs_volume
*fs
, fs_vnode
*_node
, void *cookie
, off_t pos
,
413 void *buffer
, size_t *bufferSize
)
417 // Volume *volume = (Volume*)fs->private_volume;
418 VNode
*node
= (VNode
*)_node
->private_node
;
419 FUNCTION(("((%Ld: %lu, %lu), %Ld, %p, %lu)\n", node
->GetID(),
420 node
->GetDirID(), node
->GetObjectID(), pos
, buffer
,
422 status_t error
= B_OK
;
423 // don't read anything but files
424 if (!node
->IsFile()) {
426 error
= B_IS_A_DIRECTORY
;
432 StreamReader
*reader
= (StreamReader
*)cookie
;
434 error
= reader
->Resume();
436 error
= reader
->ReadAt(pos
, buffer
, *bufferSize
, bufferSize
);
444 class DirectoryCookie
: public DirEntryIterator
{
446 DirectoryCookie(Tree
*tree
, uint32 dirID
, uint32 objectID
,
447 uint64 startOffset
= 0, bool fixedHash
= false)
448 : DirEntryIterator(tree
, dirID
, objectID
, startOffset
,
450 fEncounteredDotDot(false)
454 bool EncounteredDotDot() const
456 return fEncounteredDotDot
;
459 void SetEncounteredDotDot(bool flag
)
461 fEncounteredDotDot
= flag
;
464 bool fEncounteredDotDot
;
468 // #pragma mark - Directories
473 reiserfs_open_dir(fs_volume
*fs
, fs_vnode
*_node
, void **cookie
)
476 Volume
*volume
= (Volume
*)fs
->private_volume
;
477 VNode
*node
= (VNode
*)_node
->private_node
;
478 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
479 node
->GetObjectID()));
480 status_t error
= (node
->IsDir() ? B_OK
: B_NOT_A_DIRECTORY
);
482 DirectoryCookie
*iterator
= new(nothrow
) DirectoryCookie(
483 volume
->GetTree(), node
->GetDirID(), node
->GetObjectID());
485 error
= iterator
->Suspend();
499 set_dirent_name(struct dirent
*buffer
, size_t bufferSize
,
500 const char *name
, int32 nameLen
)
502 size_t length
= (buffer
->d_name
+ nameLen
+ 1) - (char*)buffer
;
503 if (length
<= bufferSize
) {
504 memcpy(buffer
->d_name
, name
, nameLen
);
505 buffer
->d_name
[nameLen
] = '\0';
506 buffer
->d_reclen
= length
;
509 RETURN_ERROR(B_BUFFER_OVERFLOW
);
512 // reiserfs_close_dir
514 reiserfs_close_dir(fs_volume
*fs
, fs_vnode
*_node
, void *cookie
)
516 TOUCH(fs
); TOUCH(cookie
);
518 VNode
*node
= (VNode
*)_node
->private_node
;
519 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
520 node
->GetObjectID()));
525 // reiserfs_free_dir_cookie
527 reiserfs_free_dir_cookie(fs_volume
*fs
, fs_vnode
*_node
, void *cookie
)
531 VNode
*node
= (VNode
*)_node
->private_node
;
532 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
533 node
->GetObjectID()));
535 DirectoryCookie
*iterator
= (DirectoryCookie
*)cookie
;
542 reiserfs_read_dir(fs_volume
*fs
, fs_vnode
*_node
, void *cookie
,
543 struct dirent
*buffer
, size_t bufferSize
, uint32
*count
)
546 Volume
*volume
= (Volume
*)fs
->private_volume
;
547 VNode
*node
= (VNode
*)_node
->private_node
;
548 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
549 node
->GetObjectID()));
550 DirectoryCookie
*iterator
= (DirectoryCookie
*)cookie
;
551 status_t error
= iterator
->Resume();
556 DirEntry
*entry
= NULL
;
558 while (error
== B_OK
&& !done
559 && (error
= iterator
->GetNext(&item
, &index
, &entry
)) == B_OK
) {
560 uint32 dirID
= entry
->GetDirID();
561 uint32 objectID
= entry
->GetObjectID();
562 // skip hidden entries and entries the user specified to be hidden
563 if (entry
->IsHidden() || volume
->IsNegativeEntry(dirID
, objectID
))
565 // skip entry, if we can't get the stat data, or it is neither a
566 // file, a dir nor a symlink and the user desired to hide those.
569 if (volume
->GetTree()->FindStatItem(dirID
, objectID
, &statItem
)
571 || statItem
.GetStatData(&statData
) != B_OK
572 || (statData
.IsEsoteric() && volume
->GetHideEsoteric())) {
578 const char *name
= item
.EntryNameAt(index
, &nameLen
);
579 if (!name
|| nameLen
== 0) // bad data: skip it gracefully
581 // fill in the entry name -- checks whether the
582 // entry fits into the buffer
583 error
= set_dirent_name(buffer
, bufferSize
, name
,
586 // fill in the other data
587 buffer
->d_dev
= volume
->GetID();
588 buffer
->d_ino
= VNode::GetIDFor(dirID
, objectID
);
590 PRINT(("Successfully read entry: dir: (%Ld: %ld, %ld), name: `%s', "
591 "id: (%Ld, %ld, %ld), reclen: %hu\n", node
->GetID(), node
->GetDirID(),
592 node
->GetObjectID(), buffer
->d_name
, buffer
->d_ino
, dirID
, objectID
,
594 if (!strcmp("..", buffer
->d_name
))
595 iterator
->SetEncounteredDotDot(true);
600 if (error
== B_ENTRY_NOT_FOUND
) {
601 if (iterator
->EncounteredDotDot()) {
605 // this is necessary for the root directory
606 // it usually has no ".." entry, so we simulate one
608 const char *name
= "..";
609 size_t nameLen
= strlen(name
);
610 // fill in the entry name -- checks whether the
611 // entry fits into the buffer
612 error
= set_dirent_name(buffer
, bufferSize
, name
,
615 // fill in the other data
616 buffer
->d_dev
= volume
->GetID();
617 buffer
->d_ino
= node
->GetID();
618 // < That's not correct!
620 PRINT(("faking `..' entry: dir: (%Ld: %ld, %ld), name: `%s', "
621 "id: (%Ld, %ld, %ld), reclen: %hu\n", node
->GetID(), node
->GetDirID(),
622 node
->GetObjectID(), buffer
->d_name
, buffer
->d_ino
, node
->GetDirID(),
623 node
->GetObjectID(), buffer
->d_reclen
));
624 iterator
->SetEncounteredDotDot(true);
630 PRINT(("returning %ld entries\n", *count
));
634 // reiserfs_rewind_dir
636 reiserfs_rewind_dir(fs_volume
*fs
, fs_vnode
*_node
, void *cookie
)
640 VNode
*node
= (VNode
*)_node
->private_node
;
641 FUNCTION(("node: (%Ld: %lu, %lu)\n", node
->GetID(), node
->GetDirID(),
642 node
->GetObjectID()));
644 DirectoryCookie
*iterator
= (DirectoryCookie
*)cookie
;
645 status_t error
= iterator
->Rewind(); // no need to Resume()
647 error
= iterator
->Suspend();
652 // #pragma mark - Module Interface
657 reiserfs_std_ops(int32 op
, ...)
663 PRINT(("reiserfs_std_ops(): B_MODULE_INIT\n"));
667 case B_MODULE_UNINIT
:
668 PRINT(("reiserfs_std_ops(): B_MODULE_UNINIT\n"));
680 static file_system_module_info sReiserFSModuleInfo
= {
682 "file_systems/reiserfs" B_CURRENT_FS_API_VERSION
,
687 "reiserfs", // short_name
688 "Reiser File System", // pretty_name
693 &reiserfs_identify_partition
,
694 &reiserfs_scan_partition
,
695 &reiserfs_free_identify_partition_cookie
,
696 NULL
, // free_partition_content_cookie()
702 fs_volume_ops gReiserFSVolumeOps
= {
704 &reiserfs_read_fs_info
,
705 NULL
, // &reiserfs_write_fs_info,
706 NULL
, // &reiserfs_sync,
712 fs_vnode_ops gReiserFSVnodeOps
= {
713 /* vnode operations */
715 NULL
, // &reiserfs_get_vnode_name,
716 &reiserfs_write_vnode
,
717 NULL
, // &reiserfs_remove_vnode,
720 NULL
, // &reiserfs_can_page,
721 NULL
, // &reiserfs_read_pages,
722 NULL
, // &reiserfs_write_pages,
727 NULL
, // &reiserfs_get_file_map,
729 NULL
, // &reiserfs_ioctl,
730 NULL
, // &reiserfs_set_flags,
731 NULL
, // &reiserfs_select,
732 NULL
, // &reiserfs_deselect,
733 NULL
, // &reiserfs_fsync,
735 &reiserfs_read_symlink
,
736 NULL
, // &reiserfs_create_symlink,
738 NULL
, // &reiserfs_link,
739 NULL
, // &reiserfs_unlink,
740 NULL
, // &reiserfs_rename,
744 NULL
, // &reiserfs_write_stat,
745 NULL
, // &reiserfs_preallocate,
747 /* file operations */
748 NULL
, // &reiserfs_create,
751 &reiserfs_free_cookie
,
753 NULL
, // &reiserfs_write,
755 /* directory operations */
756 NULL
, // &reiserfs_create_dir,
757 NULL
, // &reiserfs_remove_dir,
760 &reiserfs_free_dir_cookie
,
766 module_info
*modules
[] = {
767 (module_info
*)&sReiserFSModuleInfo
,