3rdparty/licenseReport: Add seperate LGPL checks
[haiku.git] / src / add-ons / kernel / file_systems / reiserfs / kernel_interface.cpp
blob4152a553227fdc0a72786950bfe47f85cdee274c
1 // kernel_interface.cpp
2 //
3 // Copyright (c) 2003-2010, Ingo Weinhold (bonefish@cs.tu-berlin.de)
4 //
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.
9 //
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.
23 #include <new>
25 #include <ctype.h>
26 #include <dirent.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <sys/stat.h>
36 #include <fs_cache.h>
37 #include <fs_info.h>
38 #include <fs_interface.h>
39 #include <KernelExport.h>
41 #include "DirItem.h"
42 #include "Iterators.h"
43 #include "StatItem.h"
44 #include "Tree.h"
45 #include "VNode.h"
46 #include "Volume.h"
49 using std::nothrow;
51 static const size_t kOptimalIOSize = 65536;
53 extern fs_volume_ops gReiserFSVolumeOps;
54 extern fs_vnode_ops gReiserFSVnodeOps;
57 // #pragma mark - FS
60 // reiserfs_identify_partition
61 static float
62 reiserfs_identify_partition(int fd, partition_data *partition, void **cookie)
64 Volume* volume = new(nothrow) Volume();
65 if (volume == NULL)
66 return -1.0;
68 status_t status = volume->Identify(fd, partition);
69 if (status != B_OK) {
70 delete volume;
71 return -1.0;
74 *cookie = (void*)volume;
75 return 0.8;
79 // reiserfs_scan_partition
80 static status_t
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)
95 return B_NO_MEMORY;
97 return B_OK;
101 // reiserfs_free_identify_partition_cookie
102 static void
103 reiserfs_free_identify_partition_cookie(partition_data* partition,
104 void* _cookie)
106 delete (Volume*)_cookie;
110 // #pragma mark -
113 // reiserfs_mount
114 static status_t
115 reiserfs_mount(fs_volume *_volume, const char *device, uint32 flags,
116 const char *parameters, ino_t *rootID)
118 TOUCH(flags); TOUCH(parameters);
119 FUNCTION_START();
120 // parameters are ignored for now
121 status_t error = B_OK;
123 // allocate and init the volume
124 Volume *volume = new(nothrow) Volume;
125 if (!volume)
126 error = B_NO_MEMORY;
127 if (error == B_OK)
128 error = volume->Mount(_volume, device);
130 // set the results
131 if (error == B_OK) {
132 *rootID = volume->GetRootVNode()->GetID();
133 _volume->private_volume = volume;
134 _volume->ops = &gReiserFSVolumeOps;
137 // cleanup on failure
138 if (error != B_OK && volume)
139 delete volume;
140 RETURN_ERROR(error);
144 // reiserfs_unmount
145 static status_t
146 reiserfs_unmount(fs_volume* fs)
148 FUNCTION_START();
149 Volume *volume = (Volume*)fs->private_volume;
150 status_t error = volume->Unmount();
151 if (error == B_OK)
152 delete volume;
153 RETURN_ERROR(error);
156 // reiserfs_read_fs_info
157 static status_t
158 reiserfs_read_fs_info(fs_volume* fs, struct fs_info *info)
160 FUNCTION_START();
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));
170 return B_OK;
174 // #pragma mark - VNodes
177 // reiserfs_lookup
178 static status_t
179 reiserfs_lookup(fs_volume* fs, fs_vnode* _dir, const char *entryName,
180 ino_t *vnid)
182 // FUNCTION_START();
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
191 if (!dir->IsDir()) {
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)
198 error = B_BAD_VALUE;
199 } else if (!strcmp(entryName, "..")) {
200 *vnid = dir->GetParentID();
201 if (volume->GetVNode(*vnid, &entryNode) != B_OK)
202 error = B_BAD_VALUE;
204 // ordinary entries
205 } else {
206 // find the entry
207 VNode foundNode;
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
212 if (error == B_OK
213 && ((foundNode.IsEsoteric() && volume->GetHideEsoteric())
214 || volume->IsNegativeEntry(foundNode.GetID()))) {
215 error = B_ENTRY_NOT_FOUND;
217 if (error == B_OK) {
218 *vnid = foundNode.GetID();
219 error = volume->GetVNode(*vnid, &entryNode);
223 // add to the entry cache
224 if (error == B_OK) {
225 entry_cache_add(volume->GetID(), dir->GetID(), entryName,
226 *vnid);
229 RETURN_ERROR(error);
232 // reiserfs_read_vnode
233 static status_t
234 reiserfs_read_vnode(fs_volume *fs, ino_t vnid, fs_vnode *node, int *_type,
235 uint32 *_flags, bool reenter)
237 TOUCH(reenter);
238 // FUNCTION_START();
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;
244 if (foundNode) {
245 error = volume->FindVNode(vnid, foundNode);
246 if (error == B_OK) {
247 node->private_node = foundNode;
248 node->ops = &gReiserFSVnodeOps;
249 *_type = foundNode->GetStatData()->GetMode() & S_IFMT;
250 *_flags = 0;
251 } else
252 delete foundNode;
253 } else
254 error = B_NO_MEMORY;
255 RETURN_ERROR(error);
258 // reiserfs_write_vnode
259 static status_t
260 reiserfs_write_vnode(fs_volume *fs, fs_vnode *_node, bool reenter)
262 TOUCH(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
267 // invoke this hook.
268 // FUNCTION_START();
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())
273 delete node;
274 // RETURN_ERROR(error);
275 return error;
279 // #pragma mark - Nodes
282 // reiserfs_read_symlink
283 static status_t
284 reiserfs_read_symlink(fs_volume *fs, fs_vnode *_node, char *buffer,
285 size_t *bufferSize)
287 // FUNCTION_START();
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())
295 error = B_BAD_VALUE;
296 // read
297 if (error == B_OK)
298 error = volume->ReadLink(node, buffer, *bufferSize, bufferSize);
299 RETURN_ERROR(error);
302 // reiserfs_access
303 static status_t
304 reiserfs_access(fs_volume *fs, fs_vnode *_node, int mode)
306 TOUCH(fs);
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?
312 if (mode & W_OK)
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
323 static status_t
324 reiserfs_read_stat(fs_volume *fs, fs_vnode *_node, struct stat *st)
326 // FUNCTION_START();
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();
344 RETURN_ERROR(error);
348 // #pragma mark - Files
351 // reiserfs_open
352 static status_t
353 reiserfs_open(fs_volume *fs, fs_vnode *_node, int openMode, void **cookie)
355 // FUNCTION_START();
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
367 if (error == B_OK) {
368 StreamReader *reader = new(nothrow) StreamReader(volume->GetTree(),
369 node->GetDirID(), node->GetObjectID());
370 if (reader) {
371 error = reader->Suspend();
372 if (error == B_OK)
373 *cookie = reader;
374 else
375 delete reader;
376 } else
377 error = B_NO_MEMORY;
379 RETURN_ERROR(error);
382 // reiserfs_close
383 static status_t
384 reiserfs_close(fs_volume *fs, fs_vnode *_node, void *cookie)
386 TOUCH(fs); TOUCH(cookie);
387 // FUNCTION_START();
388 VNode *node = (VNode*)_node->private_node;
389 FUNCTION(("node: (%Ld: %lu, %lu)\n", node->GetID(), node->GetDirID(),
390 node->GetObjectID()));
391 TOUCH(node);
392 return B_OK;
395 // reiserfs_free_cookie
396 static status_t
397 reiserfs_free_cookie(fs_volume *fs, fs_vnode *_node, void *cookie)
399 TOUCH(fs);
400 // FUNCTION_START();
401 VNode *node = (VNode*)_node->private_node;
402 FUNCTION(("node: (%Ld: %lu, %lu)\n", node->GetID(), node->GetDirID(),
403 node->GetObjectID()));
404 TOUCH(node);
405 StreamReader *reader = (StreamReader*)cookie;
406 delete reader;
407 return B_OK;
410 // reiserfs_read
411 static status_t
412 reiserfs_read(fs_volume *fs, fs_vnode *_node, void *cookie, off_t pos,
413 void *buffer, size_t *bufferSize)
415 TOUCH(fs);
416 // FUNCTION_START();
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,
421 *bufferSize));
422 status_t error = B_OK;
423 // don't read anything but files
424 if (!node->IsFile()) {
425 if (node->IsDir())
426 error = B_IS_A_DIRECTORY;
427 else
428 error = B_BAD_VALUE;
431 // read
432 StreamReader *reader = (StreamReader*)cookie;
433 if (error == B_OK) {
434 error = reader->Resume();
435 if (error == B_OK) {
436 error = reader->ReadAt(pos, buffer, *bufferSize, bufferSize);
437 reader->Suspend();
440 RETURN_ERROR(error);
444 class DirectoryCookie : public DirEntryIterator {
445 public:
446 DirectoryCookie(Tree *tree, uint32 dirID, uint32 objectID,
447 uint64 startOffset = 0, bool fixedHash = false)
448 : DirEntryIterator(tree, dirID, objectID, startOffset,
449 fixedHash),
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
471 // reiserfs_open_dir
472 static status_t
473 reiserfs_open_dir(fs_volume *fs, fs_vnode *_node, void **cookie)
475 // FUNCTION_START();
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);
481 if (error == B_OK) {
482 DirectoryCookie *iterator = new(nothrow) DirectoryCookie(
483 volume->GetTree(), node->GetDirID(), node->GetObjectID());
484 if (iterator) {
485 error = iterator->Suspend();
486 if (error == B_OK)
487 *cookie = iterator;
488 else
489 delete iterator;
490 } else
491 error = B_NO_MEMORY;
493 FUNCTION_END();
494 RETURN_ERROR(error);
497 // set_dirent_name
498 static status_t
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;
507 return B_OK;
508 } else
509 RETURN_ERROR(B_BUFFER_OVERFLOW);
512 // reiserfs_close_dir
513 static status_t
514 reiserfs_close_dir(fs_volume *fs, fs_vnode *_node, void *cookie)
516 TOUCH(fs); TOUCH(cookie);
517 // FUNCTION_START();
518 VNode *node = (VNode*)_node->private_node;
519 FUNCTION(("node: (%Ld: %lu, %lu)\n", node->GetID(), node->GetDirID(),
520 node->GetObjectID()));
521 TOUCH(node);
522 return B_OK;
525 // reiserfs_free_dir_cookie
526 static status_t
527 reiserfs_free_dir_cookie(fs_volume *fs, fs_vnode *_node, void *cookie)
529 TOUCH(fs);
530 // FUNCTION_START();
531 VNode *node = (VNode*)_node->private_node;
532 FUNCTION(("node: (%Ld: %lu, %lu)\n", node->GetID(), node->GetDirID(),
533 node->GetObjectID()));
534 TOUCH(node);
535 DirectoryCookie *iterator = (DirectoryCookie*)cookie;
536 delete iterator;
537 return B_OK;
540 // reiserfs_read_dir
541 static status_t
542 reiserfs_read_dir(fs_volume *fs, fs_vnode *_node, void *cookie,
543 struct dirent *buffer, size_t bufferSize, uint32 *count)
545 // FUNCTION_START();
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();
552 if (error == B_OK) {
553 // read one entry
554 DirItem item;
555 int32 index = 0;
556 DirEntry *entry = NULL;
557 bool done = false;
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))
564 continue;
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.
567 StatData statData;
568 StatItem statItem;
569 if (volume->GetTree()->FindStatItem(dirID, objectID, &statItem)
570 != B_OK
571 || statItem.GetStatData(&statData) != B_OK
572 || (statData.IsEsoteric() && volume->GetHideEsoteric())) {
573 continue;
575 if (error == B_OK) {
576 // get the name
577 size_t nameLen = 0;
578 const char *name = item.EntryNameAt(index, &nameLen);
579 if (!name || nameLen == 0) // bad data: skip it gracefully
580 continue;
581 // fill in the entry name -- checks whether the
582 // entry fits into the buffer
583 error = set_dirent_name(buffer, bufferSize, name,
584 nameLen);
585 if (error == B_OK) {
586 // fill in the other data
587 buffer->d_dev = volume->GetID();
588 buffer->d_ino = VNode::GetIDFor(dirID, objectID);
589 *count = 1;
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,
593 buffer->d_reclen));
594 if (!strcmp("..", buffer->d_name))
595 iterator->SetEncounteredDotDot(true);
596 done = true;
600 if (error == B_ENTRY_NOT_FOUND) {
601 if (iterator->EncounteredDotDot()) {
602 error = B_OK;
603 *count = 0;
604 } else {
605 // this is necessary for the root directory
606 // it usually has no ".." entry, so we simulate one
607 // get the name
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,
613 nameLen);
614 if (error == B_OK) {
615 // fill in the other data
616 buffer->d_dev = volume->GetID();
617 buffer->d_ino = node->GetID();
618 // < That's not correct!
619 *count = 1;
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);
628 iterator->Suspend();
630 PRINT(("returning %ld entries\n", *count));
631 RETURN_ERROR(error);
634 // reiserfs_rewind_dir
635 static status_t
636 reiserfs_rewind_dir(fs_volume *fs, fs_vnode *_node, void *cookie)
638 TOUCH(fs);
639 // FUNCTION_START();
640 VNode *node = (VNode*)_node->private_node;
641 FUNCTION(("node: (%Ld: %lu, %lu)\n", node->GetID(), node->GetDirID(),
642 node->GetObjectID()));
643 TOUCH(node);
644 DirectoryCookie *iterator = (DirectoryCookie*)cookie;
645 status_t error = iterator->Rewind(); // no need to Resume()
646 if (error == B_OK)
647 error = iterator->Suspend();
648 RETURN_ERROR(error);
652 // #pragma mark - Module Interface
655 // reiserfs_std_ops
656 static status_t
657 reiserfs_std_ops(int32 op, ...)
659 switch (op) {
660 case B_MODULE_INIT:
662 init_debugging();
663 PRINT(("reiserfs_std_ops(): B_MODULE_INIT\n"));
664 return B_OK;
667 case B_MODULE_UNINIT:
668 PRINT(("reiserfs_std_ops(): B_MODULE_UNINIT\n"));
669 exit_debugging();
670 return B_OK;
672 default:
673 return B_ERROR;
680 static file_system_module_info sReiserFSModuleInfo = {
682 "file_systems/reiserfs" B_CURRENT_FS_API_VERSION,
684 reiserfs_std_ops,
687 "reiserfs", // short_name
688 "Reiser File System", // pretty_name
689 0, // DDM flags
692 // scanning
693 &reiserfs_identify_partition,
694 &reiserfs_scan_partition,
695 &reiserfs_free_identify_partition_cookie,
696 NULL, // free_partition_content_cookie()
698 &reiserfs_mount
702 fs_volume_ops gReiserFSVolumeOps = {
703 &reiserfs_unmount,
704 &reiserfs_read_fs_info,
705 NULL, // &reiserfs_write_fs_info,
706 NULL, // &reiserfs_sync,
708 &reiserfs_read_vnode
712 fs_vnode_ops gReiserFSVnodeOps = {
713 /* vnode operations */
714 &reiserfs_lookup,
715 NULL, // &reiserfs_get_vnode_name,
716 &reiserfs_write_vnode,
717 NULL, // &reiserfs_remove_vnode,
719 /* VM file access */
720 NULL, // &reiserfs_can_page,
721 NULL, // &reiserfs_read_pages,
722 NULL, // &reiserfs_write_pages,
724 NULL, // io()
725 NULL, // cancel_io()
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,
742 &reiserfs_access,
743 &reiserfs_read_stat,
744 NULL, // &reiserfs_write_stat,
745 NULL, // &reiserfs_preallocate,
747 /* file operations */
748 NULL, // &reiserfs_create,
749 &reiserfs_open,
750 &reiserfs_close,
751 &reiserfs_free_cookie,
752 &reiserfs_read,
753 NULL, // &reiserfs_write,
755 /* directory operations */
756 NULL, // &reiserfs_create_dir,
757 NULL, // &reiserfs_remove_dir,
758 &reiserfs_open_dir,
759 &reiserfs_close_dir,
760 &reiserfs_free_dir_cookie,
761 &reiserfs_read_dir,
762 &reiserfs_rewind_dir
766 module_info *modules[] = {
767 (module_info *)&sReiserFSModuleInfo,
768 NULL,