xref: /haiku/src/add-ons/kernel/file_systems/reiserfs/kernel_interface.cpp (revision f91802873f53c5bc6e65030778078597c2e56300)
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
reiserfs_identify_partition(int fd,partition_data * partition,void ** cookie)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
reiserfs_scan_partition(int fd,partition_data * partition,void * _cookie)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
reiserfs_free_identify_partition_cookie(partition_data * partition,void * _cookie)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
reiserfs_mount(fs_volume * _volume,const char * device,uint32 flags,const char * parameters,ino_t * rootID)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
reiserfs_unmount(fs_volume * fs)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
reiserfs_read_fs_info(fs_volume * fs,struct fs_info * info)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
reiserfs_lookup(fs_volume * fs,fs_vnode * _dir,const char * entryName,ino_t * vnid)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: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 "), "
186 			"entry: `%s'\n",
187 		dir->GetID(), dir->GetDirID(), dir->GetObjectID(),
188 		entryName));
189 	status_t error = B_OK;
190 	VNode *entryNode = NULL;
191 
192 	// check for non-directories
193 	if (!dir->IsDir()) {
194 		error = B_ENTRY_NOT_FOUND;
195 
196 	// special entries: "." and ".."
197 	} else if (!strcmp(entryName, ".")) {
198 		*vnid = dir->GetID();
199 		if (volume->GetVNode(*vnid, &entryNode) != B_OK)
200 			error = B_BAD_VALUE;
201 	} else if (!strcmp(entryName, "..")) {
202 		*vnid = dir->GetParentID();
203 		if (volume->GetVNode(*vnid, &entryNode) != B_OK)
204 			error = B_BAD_VALUE;
205 
206 	// ordinary entries
207 	} else {
208 		// find the entry
209 		VNode foundNode;
210 		error = volume->FindDirEntry(dir, entryName, &foundNode, true);
211 
212 		// hide non-file/dir/symlink entries, if the user desires that, and
213 		// those entries explicitly set to hidden
214 		if (error == B_OK
215 			&& ((foundNode.IsEsoteric() && volume->GetHideEsoteric())
216 				|| volume->IsNegativeEntry(foundNode.GetID()))) {
217 			error = B_ENTRY_NOT_FOUND;
218 		}
219 		if (error == B_OK) {
220 			*vnid = foundNode.GetID();
221 			error = volume->GetVNode(*vnid, &entryNode);
222 		}
223 	}
224 
225 	// add to the entry cache
226 	if (error == B_OK) {
227 		entry_cache_add(volume->GetID(), dir->GetID(), entryName,
228 			*vnid);
229 	}
230 
231 	RETURN_ERROR(error);
232 }
233 
234 // reiserfs_read_vnode
235 static status_t
reiserfs_read_vnode(fs_volume * fs,ino_t vnid,fs_vnode * node,int * _type,uint32 * _flags,bool reenter)236 reiserfs_read_vnode(fs_volume *fs, ino_t vnid, fs_vnode *node, int *_type,
237 	uint32 *_flags, bool reenter)
238 {
239 	TOUCH(reenter);
240 //	FUNCTION_START();
241 	FUNCTION(("(%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
242 		vnid, VNode::GetDirIDFor(vnid), VNode::GetObjectIDFor(vnid)));
243 	Volume *volume = (Volume*)fs->private_volume;
244 	status_t error = B_OK;
245 	VNode *foundNode = new(nothrow) VNode;
246 	if (foundNode) {
247 		error = volume->FindVNode(vnid, foundNode);
248 		if (error == B_OK) {
249 			node->private_node = foundNode;
250 			node->ops = &gReiserFSVnodeOps;
251 			*_type = foundNode->GetStatData()->GetMode() & S_IFMT;
252 			*_flags = 0;
253 		} else
254 			delete foundNode;
255 	} else
256 		error = B_NO_MEMORY;
257 	RETURN_ERROR(error);
258 }
259 
260 // reiserfs_write_vnode
261 static status_t
reiserfs_write_vnode(fs_volume * fs,fs_vnode * _node,bool reenter)262 reiserfs_write_vnode(fs_volume *fs, fs_vnode *_node, bool reenter)
263 {
264 	TOUCH(reenter);
265 // DANGER: If dbg_printf() is used, this thread will enter another FS and
266 // even perform a write operation. The is dangerous here, since this hook
267 // may be called out of the other FSs, since, for instance a put_vnode()
268 // called from another FS may cause the VFS layer to free vnodes and thus
269 // invoke this hook.
270 //	FUNCTION_START();
271 	Volume *volume = (Volume*)fs->private_volume;
272 	VNode *node = (VNode*)_node->private_node;
273 	status_t error = B_OK;
274 	if (node != volume->GetRootVNode())
275 		delete node;
276 //	RETURN_ERROR(error);
277 	return error;
278 }
279 
280 
281 // #pragma mark - Nodes
282 
283 
284 // reiserfs_read_symlink
285 static status_t
reiserfs_read_symlink(fs_volume * fs,fs_vnode * _node,char * buffer,size_t * bufferSize)286 reiserfs_read_symlink(fs_volume *fs, fs_vnode *_node, char *buffer,
287 	size_t *bufferSize)
288 {
289 //	FUNCTION_START();
290 	Volume *volume = (Volume*)fs->private_volume;
291 	VNode *node = (VNode*)_node->private_node;
292 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
293 		node->GetID(), node->GetDirID(), node->GetObjectID()));
294 	status_t error = B_OK;
295 	// read symlinks only
296 	if (!node->IsSymlink())
297 		error = B_BAD_VALUE;
298 	// read
299 	if (error == B_OK)
300 		error = volume->ReadLink(node, buffer, *bufferSize, bufferSize);
301 	RETURN_ERROR(error);
302 }
303 
304 // reiserfs_access
305 static status_t
reiserfs_access(fs_volume * fs,fs_vnode * _node,int mode)306 reiserfs_access(fs_volume *fs, fs_vnode *_node, int mode)
307 {
308 	TOUCH(fs);
309 	VNode *node = (VNode*)_node->private_node;
310 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
311 		node->GetID(), node->GetDirID(), node->GetObjectID()));
312 
313 	// write access requested?
314 	if (mode & W_OK)
315 		return B_READ_ONLY_DEVICE;
316 
317 	// get node permissions
318 	StatData *statData = node->GetStatData();
319 
320 	return check_access_permissions(mode, statData->GetMode(),
321 		statData->GetGID(), statData->GetUID());
322 }
323 
324 // reiserfs_read_stat
325 static status_t
reiserfs_read_stat(fs_volume * fs,fs_vnode * _node,struct stat * st)326 reiserfs_read_stat(fs_volume *fs, fs_vnode *_node, struct stat *st)
327 {
328 //	FUNCTION_START();
329 	Volume *volume = (Volume*)fs->private_volume;
330 	VNode *node = (VNode*)_node->private_node;
331 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
332 		node->GetID(), node->GetDirID(), node->GetObjectID()));
333 	status_t error = B_OK;
334 	StatData *statData = node->GetStatData();
335 	st->st_dev = volume->GetID();
336 	st->st_ino = node->GetID();
337 	st->st_mode = statData->GetMode();
338 	st->st_nlink = statData->GetNLink();
339 	st->st_uid = statData->GetUID();
340 	st->st_gid = statData->GetGID();
341 	st->st_size = statData->GetSize();
342 	st->st_blksize = kOptimalIOSize;
343 	st->st_atime = statData->GetATime();
344 	st->st_mtime = st->st_ctime = statData->GetMTime();
345 	st->st_crtime = statData->GetCTime();
346 	RETURN_ERROR(error);
347 }
348 
349 
350 // #pragma mark - Files
351 
352 
353 // reiserfs_open
354 static status_t
reiserfs_open(fs_volume * fs,fs_vnode * _node,int openMode,void ** cookie)355 reiserfs_open(fs_volume *fs, fs_vnode *_node, int openMode, void **cookie)
356 {
357 //	FUNCTION_START();
358 	Volume *volume = (Volume*)fs->private_volume;
359 	VNode *node = (VNode*)_node->private_node;
360 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
361 		node->GetID(), node->GetDirID(), node->GetObjectID()));
362 	status_t error = B_OK;
363 	// check the open mode
364 	if ((openMode & O_RWMASK) == O_WRONLY || (openMode & O_RWMASK) == O_RDWR
365 		|| (openMode & (O_TRUNC | O_CREAT))) {
366 		error = B_READ_ONLY_DEVICE;
367 	}
368 	// create a StreamReader
369 	if (error == B_OK) {
370 		StreamReader *reader = new(nothrow) StreamReader(volume->GetTree(),
371 			node->GetDirID(), node->GetObjectID());
372 		if (reader) {
373 			error = reader->Suspend();
374 			if (error == B_OK)
375 				*cookie = reader;
376 			else
377 				delete reader;
378 		} else
379 			error = B_NO_MEMORY;
380 	}
381 	RETURN_ERROR(error);
382 }
383 
384 // reiserfs_close
385 static status_t
reiserfs_close(fs_volume * fs,fs_vnode * _node,void * cookie)386 reiserfs_close(fs_volume *fs, fs_vnode *_node, void *cookie)
387 {
388 	TOUCH(fs); TOUCH(cookie);
389 //	FUNCTION_START();
390 	VNode *node = (VNode*)_node->private_node;
391 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
392 		node->GetID(), node->GetDirID(), node->GetObjectID()));
393 	TOUCH(node);
394 	return B_OK;
395 }
396 
397 // reiserfs_free_cookie
398 static status_t
reiserfs_free_cookie(fs_volume * fs,fs_vnode * _node,void * cookie)399 reiserfs_free_cookie(fs_volume *fs, fs_vnode *_node, void *cookie)
400 {
401 	TOUCH(fs);
402 //	FUNCTION_START();
403 	VNode *node = (VNode*)_node->private_node;
404 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
405 		node->GetID(), node->GetDirID(), node->GetObjectID()));
406 	TOUCH(node);
407 	StreamReader *reader = (StreamReader*)cookie;
408 	delete reader;
409 	return B_OK;
410 }
411 
412 // reiserfs_read
413 static status_t
reiserfs_read(fs_volume * fs,fs_vnode * _node,void * cookie,off_t pos,void * buffer,size_t * bufferSize)414 reiserfs_read(fs_volume *fs, fs_vnode *_node, void *cookie, off_t pos,
415 	void *buffer, size_t *bufferSize)
416 {
417 	TOUCH(fs);
418 //	FUNCTION_START();
419 //	Volume *volume = (Volume*)fs->private_volume;
420 	VNode *node = (VNode*)_node->private_node;
421 	FUNCTION(("((%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 "), "
422 			"%" B_PRIdOFF ", %p, %lu)\n",
423 		node->GetID(), node->GetDirID(), node->GetObjectID(),
424 		pos, buffer, *bufferSize));
425 	status_t error = B_OK;
426 	// don't read anything but files
427 	if (!node->IsFile()) {
428 		if (node->IsDir())
429 			error = B_IS_A_DIRECTORY;
430 		else
431 			error = B_BAD_VALUE;
432 	}
433 
434 	// read
435 	StreamReader *reader = (StreamReader*)cookie;
436 	if (error == B_OK) {
437 		error = reader->Resume();
438 		if (error == B_OK) {
439 			error = reader->ReadAt(pos, buffer, *bufferSize, bufferSize);
440 			reader->Suspend();
441 		}
442 	}
443 	RETURN_ERROR(error);
444 }
445 
446 
447 class DirectoryCookie : public DirEntryIterator {
448 public:
DirectoryCookie(Tree * tree,uint32 dirID,uint32 objectID,uint64 startOffset=0,bool fixedHash=false)449 	DirectoryCookie(Tree *tree, uint32 dirID, uint32 objectID,
450 					uint64 startOffset = 0, bool fixedHash = false)
451 		: DirEntryIterator(tree, dirID, objectID, startOffset,
452 					fixedHash),
453 		fEncounteredDotDot(false)
454 	{
455 	}
456 
EncounteredDotDot() const457 	bool EncounteredDotDot() const
458 	{
459 		return fEncounteredDotDot;
460 	}
461 
SetEncounteredDotDot(bool flag)462 	void SetEncounteredDotDot(bool flag)
463 	{
464 		fEncounteredDotDot = flag;
465 	}
466 
467 	bool	fEncounteredDotDot;
468 };
469 
470 
471 // #pragma mark - Directories
472 
473 
474 // reiserfs_open_dir
475 static status_t
reiserfs_open_dir(fs_volume * fs,fs_vnode * _node,void ** cookie)476 reiserfs_open_dir(fs_volume *fs, fs_vnode *_node, void **cookie)
477 {
478 //	FUNCTION_START();
479 	Volume *volume = (Volume*)fs->private_volume;
480 	VNode *node = (VNode*)_node->private_node;
481 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
482 		node->GetID(), node->GetDirID(), node->GetObjectID()));
483 	status_t error = (node->IsDir() ? B_OK : B_NOT_A_DIRECTORY);
484 	if (error == B_OK) {
485 		DirectoryCookie *iterator = new(nothrow) DirectoryCookie(
486 			volume->GetTree(), node->GetDirID(), node->GetObjectID());
487 		if (iterator) {
488 			error = iterator->Suspend();
489 			if (error == B_OK)
490 				*cookie = iterator;
491 			else
492 				delete iterator;
493 		} else
494 			error = B_NO_MEMORY;
495 	}
496 	FUNCTION_END();
497 	RETURN_ERROR(error);
498 }
499 
500 // set_dirent_name
501 static status_t
set_dirent_name(struct dirent * buffer,size_t bufferSize,const char * name,int32 nameLen)502 set_dirent_name(struct dirent *buffer, size_t bufferSize,
503 						const char *name, int32 nameLen)
504 {
505 	size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
506 	if (length <= bufferSize) {
507 		memcpy(buffer->d_name, name, nameLen);
508 		buffer->d_name[nameLen] = '\0';
509 		buffer->d_reclen = length;
510 		return B_OK;
511 	} else
512 		RETURN_ERROR(B_BUFFER_OVERFLOW);
513 }
514 
515 // reiserfs_close_dir
516 static status_t
reiserfs_close_dir(fs_volume * fs,fs_vnode * _node,void * cookie)517 reiserfs_close_dir(fs_volume *fs, fs_vnode *_node, void *cookie)
518 {
519 	TOUCH(fs); TOUCH(cookie);
520 //	FUNCTION_START();
521 	VNode *node = (VNode*)_node->private_node;
522 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
523 		node->GetID(), node->GetDirID(), node->GetObjectID()));
524 	TOUCH(node);
525 	return B_OK;
526 }
527 
528 // reiserfs_free_dir_cookie
529 static status_t
reiserfs_free_dir_cookie(fs_volume * fs,fs_vnode * _node,void * cookie)530 reiserfs_free_dir_cookie(fs_volume *fs, fs_vnode *_node, void *cookie)
531 {
532 	TOUCH(fs);
533 //	FUNCTION_START();
534 	VNode *node = (VNode*)_node->private_node;
535 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
536 		node->GetID(), node->GetDirID(), node->GetObjectID()));
537 	TOUCH(node);
538 	DirectoryCookie *iterator = (DirectoryCookie*)cookie;
539 	delete iterator;
540 	return B_OK;
541 }
542 
543 // reiserfs_read_dir
544 static status_t
reiserfs_read_dir(fs_volume * fs,fs_vnode * _node,void * cookie,struct dirent * buffer,size_t bufferSize,uint32 * count)545 reiserfs_read_dir(fs_volume *fs, fs_vnode *_node, void *cookie,
546 	struct dirent *buffer, size_t bufferSize, uint32 *count)
547 {
548 //	FUNCTION_START();
549 	Volume *volume = (Volume*)fs->private_volume;
550 	VNode *node = (VNode*)_node->private_node;
551 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
552 		node->GetID(), node->GetDirID(), node->GetObjectID()));
553 	DirectoryCookie *iterator = (DirectoryCookie*)cookie;
554 	status_t error = iterator->Resume();
555 	if (error == B_OK) {
556 		// read one entry
557 		DirItem item;
558 		int32 index = 0;
559 		DirEntry *entry = NULL;
560 		bool done = false;
561 		while (error == B_OK && !done
562 				&& (error = iterator->GetNext(&item, &index, &entry)) == B_OK) {
563 			uint32 dirID = entry->GetDirID();
564 			uint32 objectID = entry->GetObjectID();
565 			// skip hidden entries and entries the user specified to be hidden
566 			if (entry->IsHidden() || volume->IsNegativeEntry(dirID, objectID))
567 				continue;
568 			// skip entry, if we can't get the stat data, or it is neither a
569 			// file, a dir nor a symlink and the user desired to hide those.
570 			StatData statData;
571 			StatItem statItem;
572 			if (volume->GetTree()->FindStatItem(dirID, objectID, &statItem)
573 					!= B_OK
574 				|| statItem.GetStatData(&statData) != B_OK
575 				|| (statData.IsEsoteric() && volume->GetHideEsoteric())) {
576 				continue;
577 			}
578 			// get the name
579 			size_t nameLen = 0;
580 			const char *name = item.EntryNameAt(index, &nameLen);
581 			if (!name || nameLen == 0)	// bad data: skip it gracefully
582 				continue;
583 			// fill in the entry name -- checks whether the
584 			// entry fits into the buffer
585 			error = set_dirent_name(buffer, bufferSize, name, nameLen);
586 			if (error == B_OK) {
587 				// fill in the other data
588 				buffer->d_dev = volume->GetID();
589 				buffer->d_ino = VNode::GetIDFor(dirID, objectID);
590 				*count = 1;
591 				PRINT(("Successfully read entry: dir: (%" B_PRIdINO ": "
592 						"%" B_PRIu32 ", %" B_PRIu32 "), name: `%s', "
593 						"id: (%" B_PRIdINO ", %" B_PRIu32 ", %" B_PRIu32 "), "
594 						"reclen: %hu\n",
595 					node->GetID(),
596 					node->GetDirID(), node->GetObjectID(), buffer->d_name,
597 					buffer->d_ino, dirID, objectID,
598 					buffer->d_reclen));
599 				if (!strcmp("..", buffer->d_name))
600 					iterator->SetEncounteredDotDot(true);
601 				done = true;
602 			}
603 		}
604 		if (error == B_ENTRY_NOT_FOUND) {
605 			if (iterator->EncounteredDotDot()) {
606 				error = B_OK;
607 				*count = 0;
608 			} else {
609 				// this is necessary for the root directory
610 				// it usually has no ".." entry, so we simulate one
611 				// get the name
612 				const char *name = "..";
613 				size_t nameLen = strlen(name);
614 				// fill in the entry name -- checks whether the
615 				// entry fits into the buffer
616 				error = set_dirent_name(buffer, bufferSize, name,
617 										nameLen);
618 				if (error == B_OK) {
619 					// fill in the other data
620 					buffer->d_dev = volume->GetID();
621 					buffer->d_ino = node->GetID();
622 	// < That's not correct!
623 					*count = 1;
624 					PRINT(("faking `..' entry: dir: (%" B_PRIdINO ": "
625 							"%" B_PRIu32 ", %" B_PRIu32 "), name: `%s', "
626 							"id: (%" B_PRIdINO ", %" B_PRIu32 ", %" B_PRIu32
627 							"), reclen: %hu\n",
628 						node->GetID(),
629 						node->GetDirID(), node->GetObjectID(), buffer->d_name,
630 						buffer->d_ino, node->GetDirID(), node->GetObjectID(),
631 						buffer->d_reclen));
632 					iterator->SetEncounteredDotDot(true);
633 				}
634 			}
635 		}
636 		iterator->Suspend();
637 	}
638 	PRINT(("returning %" B_PRIu32 " entries\n", *count));
639 	RETURN_ERROR(error);
640 }
641 
642 // reiserfs_rewind_dir
643 static status_t
reiserfs_rewind_dir(fs_volume * fs,fs_vnode * _node,void * cookie)644 reiserfs_rewind_dir(fs_volume *fs, fs_vnode *_node, void *cookie)
645 {
646 	TOUCH(fs);
647 //	FUNCTION_START();
648 	VNode *node = (VNode*)_node->private_node;
649 	FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n",
650 		node->GetID(), node->GetDirID(), node->GetObjectID()));
651 	TOUCH(node);
652 	DirectoryCookie *iterator = (DirectoryCookie*)cookie;
653 	status_t error = iterator->Rewind();	// no need to Resume()
654 	if (error == B_OK)
655 		error = iterator->Suspend();
656 	RETURN_ERROR(error);
657 }
658 
659 
660 // #pragma mark - Module Interface
661 
662 
663 // reiserfs_std_ops
664 static status_t
reiserfs_std_ops(int32 op,...)665 reiserfs_std_ops(int32 op, ...)
666 {
667 	switch (op) {
668 		case B_MODULE_INIT:
669 		{
670 			init_debugging();
671 			PRINT(("reiserfs_std_ops(): B_MODULE_INIT\n"));
672 			return B_OK;
673 		}
674 
675 		case B_MODULE_UNINIT:
676 			PRINT(("reiserfs_std_ops(): B_MODULE_UNINIT\n"));
677 			exit_debugging();
678 			return B_OK;
679 
680 		default:
681 			return B_ERROR;
682 	}
683 }
684 
685 
686 
687 
688 static file_system_module_info sReiserFSModuleInfo = {
689 	{
690 		"file_systems/reiserfs" B_CURRENT_FS_API_VERSION,
691 		0,
692 		reiserfs_std_ops,
693 	},
694 
695 	"reiserfs",					// short_name
696 	"Reiser File System",		// pretty_name
697 	0,							// DDM flags
698 
699 
700 	// scanning
701 	&reiserfs_identify_partition,
702 	&reiserfs_scan_partition,
703 	&reiserfs_free_identify_partition_cookie,
704 	NULL,	// free_partition_content_cookie()
705 
706 	&reiserfs_mount
707 };
708 
709 
710 fs_volume_ops gReiserFSVolumeOps = {
711 	&reiserfs_unmount,
712 	&reiserfs_read_fs_info,
713 	NULL,	// &reiserfs_write_fs_info,
714 	NULL,	// &reiserfs_sync,
715 
716 	&reiserfs_read_vnode
717 };
718 
719 
720 fs_vnode_ops gReiserFSVnodeOps = {
721 	/* vnode operations */
722 	&reiserfs_lookup,
723 	NULL,	// &reiserfs_get_vnode_name,
724 	&reiserfs_write_vnode,
725 	NULL,	// &reiserfs_remove_vnode,
726 
727 	/* VM file access */
728 	NULL,	// &reiserfs_can_page,
729 	NULL,	// &reiserfs_read_pages,
730 	NULL,	// &reiserfs_write_pages,
731 
732 	NULL,	// io()
733 	NULL,	// cancel_io()
734 
735 	NULL,	// &reiserfs_get_file_map,
736 
737 	NULL,	// &reiserfs_ioctl,
738 	NULL,	// &reiserfs_set_flags,
739 	NULL,	// &reiserfs_select,
740 	NULL,	// &reiserfs_deselect,
741 	NULL,	// &reiserfs_fsync,
742 
743 	&reiserfs_read_symlink,
744 	NULL,	// &reiserfs_create_symlink,
745 
746 	NULL,	// &reiserfs_link,
747 	NULL,	// &reiserfs_unlink,
748 	NULL,	// &reiserfs_rename,
749 
750 	&reiserfs_access,
751 	&reiserfs_read_stat,
752 	NULL,	// &reiserfs_write_stat,
753 	NULL,	// &reiserfs_preallocate,
754 
755 	/* file operations */
756 	NULL,	// &reiserfs_create,
757 	&reiserfs_open,
758 	&reiserfs_close,
759 	&reiserfs_free_cookie,
760 	&reiserfs_read,
761 	NULL,	// &reiserfs_write,
762 
763 	/* directory operations */
764 	NULL,	// &reiserfs_create_dir,
765 	NULL,	// &reiserfs_remove_dir,
766 	&reiserfs_open_dir,
767 	&reiserfs_close_dir,
768 	&reiserfs_free_dir_cookie,
769 	&reiserfs_read_dir,
770 	&reiserfs_rewind_dir
771 };
772 
773 
774 module_info *modules[] = {
775 	(module_info *)&sReiserFSModuleInfo,
776 	NULL,
777 };
778