xref: /haiku/src/add-ons/kernel/file_systems/reiserfs/kernel_interface.cpp (revision 64b46b706b02d969629415c9a44c394a2a5e4993)
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 			// get the name
576 			size_t nameLen = 0;
577 			const char *name = item.EntryNameAt(index, &nameLen);
578 			if (!name || nameLen == 0)	// bad data: skip it gracefully
579 				continue;
580 			// fill in the entry name -- checks whether the
581 			// entry fits into the buffer
582 			error = set_dirent_name(buffer, bufferSize, name, nameLen);
583 			if (error == B_OK) {
584 				// fill in the other data
585 				buffer->d_dev = volume->GetID();
586 				buffer->d_ino = VNode::GetIDFor(dirID, objectID);
587 				*count = 1;
588 PRINT(("Successfully read entry: dir: (%Ld: %ld, %ld), name: `%s', "
589    "id: (%Ld, %ld, %ld), reclen: %hu\n", node->GetID(), node->GetDirID(),
590    node->GetObjectID(), buffer->d_name, buffer->d_ino, dirID, objectID,
591    buffer->d_reclen));
592 				if (!strcmp("..", buffer->d_name))
593 					iterator->SetEncounteredDotDot(true);
594 				done = true;
595 			}
596  		}
597  		if (error == B_ENTRY_NOT_FOUND) {
598  			if (iterator->EncounteredDotDot()) {
599 	 			error = B_OK;
600 				*count = 0;
601 			} else {
602 				// this is necessary for the root directory
603 				// it usually has no ".." entry, so we simulate one
604 				// get the name
605 				const char *name = "..";
606 				size_t nameLen = strlen(name);
607 				// fill in the entry name -- checks whether the
608 				// entry fits into the buffer
609 				error = set_dirent_name(buffer, bufferSize, name,
610 										nameLen);
611 				if (error == B_OK) {
612 					// fill in the other data
613 					buffer->d_dev = volume->GetID();
614 					buffer->d_ino = node->GetID();
615 	// < That's not correct!
616 					*count = 1;
617 PRINT(("faking `..' entry: dir: (%Ld: %ld, %ld), name: `%s', "
618 	   "id: (%Ld, %ld, %ld), reclen: %hu\n", node->GetID(), node->GetDirID(),
619 	   node->GetObjectID(), buffer->d_name, buffer->d_ino, node->GetDirID(),
620 	   node->GetObjectID(), buffer->d_reclen));
621 					iterator->SetEncounteredDotDot(true);
622 				}
623 			}
624  		}
625  		iterator->Suspend();
626 	}
627 PRINT(("returning %ld entries\n", *count));
628 	RETURN_ERROR(error);
629 }
630 
631 // reiserfs_rewind_dir
632 static status_t
633 reiserfs_rewind_dir(fs_volume *fs, fs_vnode *_node, void *cookie)
634 {
635 	TOUCH(fs);
636 //	FUNCTION_START();
637 	VNode *node = (VNode*)_node->private_node;
638 FUNCTION(("node: (%Ld: %lu, %lu)\n", node->GetID(), node->GetDirID(),
639 		  node->GetObjectID()));
640 	TOUCH(node);
641 	DirectoryCookie *iterator = (DirectoryCookie*)cookie;
642 	status_t error = iterator->Rewind();	// no need to Resume()
643 	if (error == B_OK)
644 		error = iterator->Suspend();
645 	RETURN_ERROR(error);
646 }
647 
648 
649 // #pragma mark - Module Interface
650 
651 
652 // reiserfs_std_ops
653 static status_t
654 reiserfs_std_ops(int32 op, ...)
655 {
656 	switch (op) {
657 		case B_MODULE_INIT:
658 		{
659 			init_debugging();
660 			PRINT(("reiserfs_std_ops(): B_MODULE_INIT\n"));
661 			return B_OK;
662 		}
663 
664 		case B_MODULE_UNINIT:
665 			PRINT(("reiserfs_std_ops(): B_MODULE_UNINIT\n"));
666 			exit_debugging();
667 			return B_OK;
668 
669 		default:
670 			return B_ERROR;
671 	}
672 }
673 
674 
675 
676 
677 static file_system_module_info sReiserFSModuleInfo = {
678 	{
679 		"file_systems/reiserfs" B_CURRENT_FS_API_VERSION,
680 		0,
681 		reiserfs_std_ops,
682 	},
683 
684 	"reiserfs",					// short_name
685 	"Reiser File System",		// pretty_name
686 	0,							// DDM flags
687 
688 
689 	// scanning
690 	&reiserfs_identify_partition,
691 	&reiserfs_scan_partition,
692 	&reiserfs_free_identify_partition_cookie,
693 	NULL,	// free_partition_content_cookie()
694 
695 	&reiserfs_mount
696 };
697 
698 
699 fs_volume_ops gReiserFSVolumeOps = {
700 	&reiserfs_unmount,
701 	&reiserfs_read_fs_info,
702 	NULL,	// &reiserfs_write_fs_info,
703 	NULL,	// &reiserfs_sync,
704 
705 	&reiserfs_read_vnode
706 };
707 
708 
709 fs_vnode_ops gReiserFSVnodeOps = {
710 	/* vnode operations */
711 	&reiserfs_lookup,
712 	NULL,	// &reiserfs_get_vnode_name,
713 	&reiserfs_write_vnode,
714 	NULL,	// &reiserfs_remove_vnode,
715 
716 	/* VM file access */
717 	NULL,	// &reiserfs_can_page,
718 	NULL,	// &reiserfs_read_pages,
719 	NULL,	// &reiserfs_write_pages,
720 
721 	NULL,	// io()
722 	NULL,	// cancel_io()
723 
724 	NULL,	// &reiserfs_get_file_map,
725 
726 	NULL,	// &reiserfs_ioctl,
727 	NULL,	// &reiserfs_set_flags,
728 	NULL,	// &reiserfs_select,
729 	NULL,	// &reiserfs_deselect,
730 	NULL,	// &reiserfs_fsync,
731 
732 	&reiserfs_read_symlink,
733 	NULL,	// &reiserfs_create_symlink,
734 
735 	NULL,	// &reiserfs_link,
736 	NULL,	// &reiserfs_unlink,
737 	NULL,	// &reiserfs_rename,
738 
739 	&reiserfs_access,
740 	&reiserfs_read_stat,
741 	NULL,	// &reiserfs_write_stat,
742 	NULL,	// &reiserfs_preallocate,
743 
744 	/* file operations */
745 	NULL,	// &reiserfs_create,
746 	&reiserfs_open,
747 	&reiserfs_close,
748 	&reiserfs_free_cookie,
749 	&reiserfs_read,
750 	NULL,	// &reiserfs_write,
751 
752 	/* directory operations */
753 	NULL,	// &reiserfs_create_dir,
754 	NULL,	// &reiserfs_remove_dir,
755 	&reiserfs_open_dir,
756 	&reiserfs_close_dir,
757 	&reiserfs_free_dir_cookie,
758 	&reiserfs_read_dir,
759 	&reiserfs_rewind_dir
760 };
761 
762 
763 module_info *modules[] = {
764 	(module_info *)&sReiserFSModuleInfo,
765 	NULL,
766 };
767