xref: /haiku/src/add-ons/kernel/file_systems/reiserfs/kernel_interface.cpp (revision e711e6e42fd7ec3111ba9dc2324fa8efedd6674b)
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.
14 //
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
18 //
19 // You can alternatively use *this file* under the terms of the the MIT
20 // license included in this package.
21 
22 
23 #include <new>
24 
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>
35 
36 #include <fs_cache.h>
37 #include <fs_info.h>
38 #include <fs_interface.h>
39 #include <KernelExport.h>
40 
41 #include "DirItem.h"
42 #include "Iterators.h"
43 #include "StatItem.h"
44 #include "Tree.h"
45 #include "VNode.h"
46 #include "Volume.h"
47 
48 
49 using std::nothrow;
50 
51 static const size_t kOptimalIOSize = 65536;
52 
53 extern fs_volume_ops gReiserFSVolumeOps;
54 extern fs_vnode_ops gReiserFSVnodeOps;
55 
56 
57 // #pragma mark - FS
58 
59 
60 // reiserfs_identify_partition
61 static float
62 reiserfs_identify_partition(int fd, partition_data *partition, void **cookie)
63 {
64 	Volume* volume = new(nothrow) Volume();
65 	if (volume == NULL)
66 		return -1.0;
67 
68 	status_t status = volume->Identify(fd, partition);
69 	if (status != B_OK) {
70 		delete volume;
71 		return -1.0;
72 	}
73 
74 	*cookie = (void*)volume;
75 	return 0.8;
76 }
77 
78 
79 // reiserfs_scan_partition
80 static status_t
81 reiserfs_scan_partition(int fd, partition_data *partition, void *_cookie)
82 {
83 	Volume* volume = (Volume*)_cookie;
84 
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();
90 
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;
96 
97 	return B_OK;
98 }
99 
100 
101 // reiserfs_free_identify_partition_cookie
102 static void
103 reiserfs_free_identify_partition_cookie(partition_data* partition,
104 	void* _cookie)
105 {
106 	delete (Volume*)_cookie;
107 }
108 
109 
110 //	#pragma mark -
111 
112 
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)
117 {
118 	TOUCH(flags); TOUCH(parameters);
119 	FUNCTION_START();
120 	// parameters are ignored for now
121 	status_t error = B_OK;
122 
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);
129 
130 	// set the results
131 	if (error == B_OK) {
132 		*rootID = volume->GetRootVNode()->GetID();
133 		_volume->private_volume = volume;
134 		_volume->ops = &gReiserFSVolumeOps;
135 	}
136 
137 	// cleanup on failure
138 	if (error != B_OK && volume)
139 		delete volume;
140 	RETURN_ERROR(error);
141 }
142 
143 
144 // reiserfs_unmount
145 static status_t
146 reiserfs_unmount(fs_volume* fs)
147 {
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);
154 }
155 
156 // reiserfs_read_fs_info
157 static status_t
158 reiserfs_read_fs_info(fs_volume* fs, struct fs_info *info)
159 {
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;
171 }
172 
173 
174 // #pragma mark - VNodes
175 
176 
177 // reiserfs_lookup
178 static status_t
179 reiserfs_lookup(fs_volume* fs, fs_vnode* _dir, const char *entryName,
180 	ino_t *vnid)
181 {
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;
189 
190 	// check for non-directories
191 	if (!dir->IsDir()) {
192 		error = B_ENTRY_NOT_FOUND;
193 
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;
203 
204 	// ordinary entries
205 	} else {
206 		// find the entry
207 		VNode foundNode;
208 		error = volume->FindDirEntry(dir, entryName, &foundNode, true);
209 
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;
216 		}
217 		if (error == B_OK) {
218 			*vnid = foundNode.GetID();
219 			error = volume->GetVNode(*vnid, &entryNode);
220 		}
221 	}
222 
223 	// add to the entry cache
224 	if (error == B_OK) {
225 		entry_cache_add(volume->GetID(), dir->GetID(), entryName,
226 			*vnid);
227 	}
228 
229 	RETURN_ERROR(error);
230 }
231 
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)
236 {
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);
256 }
257 
258 // reiserfs_write_vnode
259 static status_t
260 reiserfs_write_vnode(fs_volume *fs, fs_vnode *_node, bool reenter)
261 {
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;
276 }
277 
278 
279 // #pragma mark - Nodes
280 
281 
282 // reiserfs_read_symlink
283 static status_t
284 reiserfs_read_symlink(fs_volume *fs, fs_vnode *_node, char *buffer,
285 	size_t *bufferSize)
286 {
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);
300 }
301 
302 // reiserfs_access
303 static status_t
304 reiserfs_access(fs_volume *fs, fs_vnode *_node, int mode)
305 {
306 	TOUCH(fs);
307 	VNode *node = (VNode*)_node->private_node;
308 	FUNCTION(("node: (%Ld: %lu, %lu)\n", node->GetID(), node->GetDirID(),
309 		  node->GetObjectID()));
310 
311 	// write access requested?
312 	if (mode & W_OK)
313 		return B_READ_ONLY_DEVICE;
314 
315 	// get node permissions
316 	StatData *statData = node->GetStatData();
317 
318 	return check_access_permissions(mode, statData->GetMode(),
319 		statData->GetGID(), statData->GetUID());
320 }
321 
322 // reiserfs_read_stat
323 static status_t
324 reiserfs_read_stat(fs_volume *fs, fs_vnode *_node, struct stat *st)
325 {
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);
345 }
346 
347 
348 // #pragma mark - Files
349 
350 
351 // reiserfs_open
352 static status_t
353 reiserfs_open(fs_volume *fs, fs_vnode *_node, int openMode, void **cookie)
354 {
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;
365 	}
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;
378 	}
379 	RETURN_ERROR(error);
380 }
381 
382 // reiserfs_close
383 static status_t
384 reiserfs_close(fs_volume *fs, fs_vnode *_node, void *cookie)
385 {
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;
393 }
394 
395 // reiserfs_free_cookie
396 static status_t
397 reiserfs_free_cookie(fs_volume *fs, fs_vnode *_node, void *cookie)
398 {
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;
408 }
409 
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)
414 {
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;
429 	}
430 
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();
438 		}
439 	}
440 	RETURN_ERROR(error);
441 }
442 
443 
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)
451 	{
452 	}
453 
454 	bool EncounteredDotDot() const
455 	{
456 		return fEncounteredDotDot;
457 	}
458 
459 	void SetEncounteredDotDot(bool flag)
460 	{
461 		fEncounteredDotDot = flag;
462 	}
463 
464 	bool	fEncounteredDotDot;
465 };
466 
467 
468 // #pragma mark - Directories
469 
470 
471 // reiserfs_open_dir
472 static status_t
473 reiserfs_open_dir(fs_volume *fs, fs_vnode *_node, void **cookie)
474 {
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;
492 	}
493 	FUNCTION_END();
494 	RETURN_ERROR(error);
495 }
496 
497 // set_dirent_name
498 static status_t
499 set_dirent_name(struct dirent *buffer, size_t bufferSize,
500 						 const char *name, int32 nameLen)
501 {
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);
510 }
511 
512 // reiserfs_close_dir
513 static status_t
514 reiserfs_close_dir(fs_volume *fs, fs_vnode *_node, void *cookie)
515 {
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;
523 }
524 
525 // reiserfs_free_dir_cookie
526 static status_t
527 reiserfs_free_dir_cookie(fs_volume *fs, fs_vnode *_node, void *cookie)
528 {
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;
538 }
539 
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)
544 {
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;
574 			}
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;
597 				}
598 	 		}
599  		}
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);
625 				}
626 			}
627  		}
628  		iterator->Suspend();
629 	}
630 PRINT(("returning %ld entries\n", *count));
631 	RETURN_ERROR(error);
632 }
633 
634 // reiserfs_rewind_dir
635 static status_t
636 reiserfs_rewind_dir(fs_volume *fs, fs_vnode *_node, void *cookie)
637 {
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);
649 }
650 
651 
652 // #pragma mark - Module Interface
653 
654 
655 // reiserfs_std_ops
656 static status_t
657 reiserfs_std_ops(int32 op, ...)
658 {
659 	switch (op) {
660 		case B_MODULE_INIT:
661 		{
662 			init_debugging();
663 			PRINT(("reiserfs_std_ops(): B_MODULE_INIT\n"));
664 			return B_OK;
665 		}
666 
667 		case B_MODULE_UNINIT:
668 			PRINT(("reiserfs_std_ops(): B_MODULE_UNINIT\n"));
669 			exit_debugging();
670 			return B_OK;
671 
672 		default:
673 			return B_ERROR;
674 	}
675 }
676 
677 
678 
679 
680 static file_system_module_info sReiserFSModuleInfo = {
681 	{
682 		"file_systems/reiserfs" B_CURRENT_FS_API_VERSION,
683 		0,
684 		reiserfs_std_ops,
685 	},
686 
687 	"reiserfs",					// short_name
688 	"Reiser File System",		// pretty_name
689 	0,							// DDM flags
690 
691 
692 	// scanning
693 	&reiserfs_identify_partition,
694 	&reiserfs_scan_partition,
695 	&reiserfs_free_identify_partition_cookie,
696 	NULL,	// free_partition_content_cookie()
697 
698 	&reiserfs_mount
699 };
700 
701 
702 fs_volume_ops gReiserFSVolumeOps = {
703 	&reiserfs_unmount,
704 	&reiserfs_read_fs_info,
705 	NULL,	// &reiserfs_write_fs_info,
706 	NULL,	// &reiserfs_sync,
707 
708 	&reiserfs_read_vnode
709 };
710 
711 
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,
718 
719 	/* VM file access */
720 	NULL,	// &reiserfs_can_page,
721 	NULL,	// &reiserfs_read_pages,
722 	NULL,	// &reiserfs_write_pages,
723 
724 	NULL,	// io()
725 	NULL,	// cancel_io()
726 
727 	NULL,	// &reiserfs_get_file_map,
728 
729 	NULL,	// &reiserfs_ioctl,
730 	NULL,	// &reiserfs_set_flags,
731 	NULL,	// &reiserfs_select,
732 	NULL,	// &reiserfs_deselect,
733 	NULL,	// &reiserfs_fsync,
734 
735 	&reiserfs_read_symlink,
736 	NULL,	// &reiserfs_create_symlink,
737 
738 	NULL,	// &reiserfs_link,
739 	NULL,	// &reiserfs_unlink,
740 	NULL,	// &reiserfs_rename,
741 
742 	&reiserfs_access,
743 	&reiserfs_read_stat,
744 	NULL,	// &reiserfs_write_stat,
745 	NULL,	// &reiserfs_preallocate,
746 
747 	/* file operations */
748 	NULL,	// &reiserfs_create,
749 	&reiserfs_open,
750 	&reiserfs_close,
751 	&reiserfs_free_cookie,
752 	&reiserfs_read,
753 	NULL,	// &reiserfs_write,
754 
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
763 };
764 
765 
766 module_info *modules[] = {
767 	(module_info *)&sReiserFSModuleInfo,
768 	NULL,
769 };
770