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