1 /*
2 * Copyright 2020 Suhel Mehta, mehtasuhel@gmail.com
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6 #include <string.h>
7
8 #ifdef FS_SHELL
9 #include "fssh_api_wrapper.h"
10 #endif
11 #include <file_systems/fs_ops_support.h>
12
13 #include "DirectoryIterator.h"
14 #include "Inode.h"
15 #include "system_dependencies.h"
16 #include "ufs2.h"
17 #include "Volume.h"
18
19 #define TRACE_UFS2
20 #ifdef TRACE_UFS2
21 #define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x)
22 #else
23 #define TRACE(x...) ;
24 #endif
25 #define ERROR(x...) dprintf("\33[34mufs2:\33[0m " x)
26
27
28 struct identify_cookie
29 {
30 ufs2_super_block super_block;
31 int cookie;
32 };
33
34
35 // #pragma mark - Scanning
36 static float
ufs2_identify_partition(int fd,partition_data * partition,void ** _cookie)37 ufs2_identify_partition(int fd, partition_data *partition, void **_cookie)
38 {
39 ufs2_super_block superBlock;
40 status_t status = Volume::Identify(fd, &superBlock);
41 if (status != B_OK)
42 return -1;
43
44 identify_cookie* cookie = new identify_cookie;
45 memcpy(&cookie->super_block, &superBlock, sizeof(ufs2_super_block));
46 *_cookie = cookie;
47
48 return 0.8f;
49 }
50
51
52 static status_t
ufs2_scan_partition(int fd,partition_data * partition,void * _cookie)53 ufs2_scan_partition(int fd, partition_data *partition, void *_cookie)
54 {
55 identify_cookie* cookie = (identify_cookie*)_cookie;
56
57 partition->status = B_PARTITION_VALID;
58 partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY;
59 partition->block_size = cookie->super_block.fs_bsize;
60 partition->content_size = cookie->super_block.fs_fsize
61 * cookie->super_block.fs_size;
62 partition->content_name = strdup(cookie->super_block.fs_volname);
63 if (partition->content_name == NULL)
64 return B_NO_MEMORY;
65
66 return B_OK;
67 }
68
69
70 static void
ufs2_free_identify_partition_cookie(partition_data * partition,void * _cookie)71 ufs2_free_identify_partition_cookie(partition_data *partition, void *_cookie)
72 {
73 identify_cookie* cookie = (identify_cookie*)_cookie;
74 delete cookie;
75 return;
76 }
77
78
79 // #pragma mark -
80 static status_t
ufs2_mount(fs_volume * _volume,const char * device,uint32 flags,const char * args,ino_t * _rootID)81 ufs2_mount(fs_volume *_volume, const char *device, uint32 flags,
82 const char *args, ino_t *_rootID)
83 {
84 TRACE("Tracing mount()\n");
85 Volume* volume = new(std::nothrow) Volume(_volume);
86 if (volume == NULL)
87 return B_NO_MEMORY;
88
89 _volume->private_volume = volume;
90 _volume->ops = &gUfs2VolumeOps;
91 *_rootID = UFS2_ROOT;
92 status_t status = volume->Mount(device, flags);
93 if (status != B_OK){
94 ERROR("Failed mounting the volume. Error: %s\n", strerror(status));
95 delete volume;
96 return status;
97 }
98 return B_OK;
99 }
100
101
102 static status_t
ufs2_unmount(fs_volume * _volume)103 ufs2_unmount(fs_volume *_volume)
104 {
105 Volume* volume = (Volume *)_volume->private_volume;
106
107 status_t status = volume->Unmount();
108 delete volume;
109
110 return status;
111 }
112
113
114 static status_t
ufs2_read_fs_info(fs_volume * _volume,struct fs_info * info)115 ufs2_read_fs_info(fs_volume *_volume, struct fs_info *info)
116 {
117 Volume* volume = (Volume*)_volume->private_volume;
118
119 // File system flags
120 info->flags = B_FS_IS_PERSISTENT
121 | (volume->IsReadOnly() ? B_FS_IS_READONLY : 0);
122 info->io_size = 65536;
123 info->block_size = volume->SuperBlock().fs_fsize;
124 info->total_blocks = volume->SuperBlock().fs_size;
125 info->free_blocks = volume->SuperBlock().fs_cstotal.cs_nbfree;
126
127 strlcpy(info->volume_name, volume->Name(), sizeof(info->volume_name));
128 strlcpy(info->fsh_name, "UFS2", sizeof(info->fsh_name));
129
130 return B_OK;
131 }
132
133
134 // #pragma mark -
135
136 static status_t
ufs2_get_vnode(fs_volume * _volume,ino_t id,fs_vnode * _node,int * _type,uint32 * _flags,bool reenter)137 ufs2_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_node, int *_type,
138 uint32 *_flags, bool reenter)
139 {
140 Volume* volume = (Volume*)_volume->private_volume;
141
142 Inode* inode = new(std::nothrow) Inode(volume, id);
143 if (inode == NULL)
144 return B_NO_MEMORY;
145
146 status_t status = inode->InitCheck();
147 if (status != B_OK) {
148 delete inode;
149 ERROR("get_vnode: InitCheck() failed. Error: %s\n", strerror(status));
150 return status;
151 }
152 _node->private_node = inode;
153 _node->ops = &gufs2VnodeOps;
154 *_type = inode->Mode();
155 *_flags = 0;
156
157 return B_OK;
158
159 }
160
161
162 static status_t
ufs2_put_vnode(fs_volume * _volume,fs_vnode * _node,bool reenter)163 ufs2_put_vnode(fs_volume *_volume, fs_vnode *_node, bool reenter)
164 {
165 return B_NOT_SUPPORTED;
166 }
167
168
169 static bool
ufs2_can_page(fs_volume * _volume,fs_vnode * _node,void * _cookie)170 ufs2_can_page(fs_volume *_volume, fs_vnode *_node, void *_cookie)
171 {
172 return false;
173 }
174
175
176 static status_t
ufs2_read_pages(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,const iovec * vecs,size_t count,size_t * _numBytes)177 ufs2_read_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie,
178 off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
179 {
180 return B_NOT_SUPPORTED;
181 }
182
183
184 static status_t
ufs2_io(fs_volume * _volume,fs_vnode * _node,void * _cookie,io_request * request)185 ufs2_io(fs_volume *_volume, fs_vnode *_node, void *_cookie,
186 io_request *request)
187 {
188 return B_NOT_SUPPORTED;
189 }
190
191
192 static status_t
ufs2_get_file_map(fs_volume * _volume,fs_vnode * _node,off_t offset,size_t size,struct file_io_vec * vecs,size_t * _count)193 ufs2_get_file_map(fs_volume *_volume, fs_vnode *_node, off_t offset,
194 size_t size, struct file_io_vec *vecs, size_t *_count)
195 {
196 return B_NOT_SUPPORTED;
197 }
198
199
200 // #pragma mark -
201
202 static status_t
ufs2_lookup(fs_volume * _volume,fs_vnode * _directory,const char * name,ino_t * _vnodeID)203 ufs2_lookup(fs_volume *_volume, fs_vnode *_directory, const char *name,
204 ino_t *_vnodeID)
205 {
206 Volume* volume = (Volume*)_volume->private_volume;
207 Inode* directory = (Inode*)_directory->private_node;
208
209 // check access permissions
210 status_t status = directory->CheckPermissions(X_OK);
211 if (status < B_OK)
212 return status;
213
214 status = DirectoryIterator(directory).Lookup(name, _vnodeID);
215 if (status != B_OK)
216 return status;
217
218 status = get_vnode(volume->FSVolume(), *_vnodeID, NULL);
219 return status;
220 }
221
222
223 static status_t
ufs2_ioctl(fs_volume * _volume,fs_vnode * _node,void * _cookie,uint32 cmd,void * buffer,size_t bufferLength)224 ufs2_ioctl(fs_volume *_volume, fs_vnode *_node, void *_cookie, uint32 cmd,
225 void *buffer, size_t bufferLength)
226 {
227 return B_NOT_SUPPORTED;
228 }
229
230
231 static status_t
ufs2_read_stat(fs_volume * _volume,fs_vnode * _node,struct stat * stat)232 ufs2_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat)
233 {
234 Inode* inode = (Inode*)_node->private_node;
235 stat->st_dev = inode->GetVolume()->ID();
236 stat->st_ino = inode->ID();
237 stat->st_nlink = inode->LinkCount();
238 stat->st_blksize = 65536;
239
240 stat->st_uid = inode->UserID();
241 stat->st_gid = inode->GroupID();
242 stat->st_mode = inode->Mode();
243 stat->st_type = 0;
244
245 inode->GetAccessTime(stat->st_atim);
246 inode->GetModificationTime(stat->st_mtim);
247 inode->GetChangeTime(stat->st_ctim);
248 inode->GetCreationTime(stat->st_crtim);
249
250 stat->st_size = inode->Size();
251 stat->st_blocks = inode->NumBlocks();
252
253 return B_OK;
254 }
255
256
257 static status_t
ufs2_open(fs_volume * _volume,fs_vnode * _node,int openMode,void ** _cookie)258 ufs2_open(fs_volume * _volume, fs_vnode *_node, int openMode,
259 void **_cookie)
260 {
261 //Volume* volume = (Volume*)_volume->private_volume;
262 Inode* inode = (Inode*)_node->private_node;
263
264 // opening a directory read-only is allowed, although you can't read
265 // any data from it.
266 if (inode->IsDirectory() && (openMode & O_RWMASK) != 0)
267 return B_IS_A_DIRECTORY;
268
269 status_t status = inode->CheckPermissions(open_mode_to_access(openMode)
270 | (openMode & O_TRUNC ? W_OK : 0));
271 if (status != B_OK)
272 return status;
273
274 file_cookie* cookie = new(std::nothrow) file_cookie;
275 if (cookie == NULL)
276 return B_NO_MEMORY;
277 ObjectDeleter<file_cookie> cookieDeleter(cookie);
278
279 cookie->last_size = inode->Size();
280 cookie->last_notification = system_time();
281
282 // fileCacheEnabler.Detach();
283 cookieDeleter.Detach();
284 *_cookie = cookie;
285 return B_OK;
286 }
287
288
289 static status_t
ufs2_read(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,void * buffer,size_t * _length)290 ufs2_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
291 void *buffer, size_t *_length)
292 {
293 Inode* inode = (Inode*)_node->private_node;
294
295 if (!inode->IsFile()) {
296 *_length = 0;
297 return inode->IsDirectory() ? B_IS_A_DIRECTORY : B_BAD_VALUE;
298 }
299
300 return inode->ReadAt(pos, (uint8*)buffer, _length);
301 }
302
303
304 static status_t
ufs2_close(fs_volume * _volume,fs_vnode * _node,void * _cookie)305 ufs2_close(fs_volume *_volume, fs_vnode *_node, void *_cookie)
306 {
307 return B_OK;
308 }
309
310
311 static status_t
ufs2_free_cookie(fs_volume * _volume,fs_vnode * _node,void * _cookie)312 ufs2_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
313 {
314 file_cookie* cookie = (file_cookie*)_cookie;
315
316 delete cookie;
317 return B_OK;
318 }
319
320 static status_t
ufs2_access(fs_volume * _volume,fs_vnode * _node,int accessMode)321 ufs2_access(fs_volume *_volume, fs_vnode *_node, int accessMode)
322 {
323 Inode* inode = (Inode*)_node->private_node;
324 return inode->CheckPermissions(accessMode);
325 }
326
327
328 static status_t
ufs2_read_link(fs_volume * _volume,fs_vnode * _node,char * buffer,size_t * _bufferSize)329 ufs2_read_link(fs_volume *_volume, fs_vnode *_node, char *buffer,
330 size_t *_bufferSize)
331 {
332 Inode* inode = (Inode*)_node->private_node;
333
334 return inode->ReadLink(buffer, _bufferSize);
335 }
336
337
338 status_t
ufs2_unlink(fs_volume * _volume,fs_vnode * _directory,const char * name)339 ufs2_unlink(fs_volume *_volume, fs_vnode *_directory, const char *name)
340 {
341 return B_NOT_SUPPORTED;
342 }
343
344
345 // #pragma mark - Directory functions
346
347 static status_t
ufs2_create_dir(fs_volume * _volume,fs_vnode * _directory,const char * name,int mode)348 ufs2_create_dir(fs_volume *_volume, fs_vnode *_directory, const char *name,
349 int mode)
350 {
351 return B_NOT_SUPPORTED;
352 }
353
354
355 static status_t
ufs2_remove_dir(fs_volume * _volume,fs_vnode * _directory,const char * name)356 ufs2_remove_dir(fs_volume *_volume, fs_vnode *_directory, const char *name)
357 {
358 return B_NOT_SUPPORTED;
359 }
360
361
362 static status_t
ufs2_open_dir(fs_volume *,fs_vnode * _node,void ** _cookie)363 ufs2_open_dir(fs_volume * /*_volume*/, fs_vnode *_node, void **_cookie)
364 {
365 Inode* inode = (Inode*)_node->private_node;
366
367 status_t status = inode->CheckPermissions(R_OK);
368 if (status < B_OK)
369 return status;
370
371 if (!inode->IsDirectory())
372 return B_NOT_A_DIRECTORY;
373
374 DirectoryIterator* iterator = new(std::nothrow) DirectoryIterator(inode);
375 if (iterator == NULL)
376 return B_NO_MEMORY;
377
378 *_cookie = iterator;
379 return B_OK;
380 }
381
382
383 static status_t
ufs2_read_dir(fs_volume * _volume,fs_vnode * _node,void * _cookie,struct dirent * dirent,size_t bufferSize,uint32 * _num)384 ufs2_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
385 struct dirent *dirent, size_t bufferSize, uint32 *_num)
386 {
387 DirectoryIterator* iterator = (DirectoryIterator*)_cookie;
388 Volume* volume = (Volume*)_volume->private_volume;
389
390 uint32 maxCount = *_num;
391 uint32 count = 0;
392
393 while (count < maxCount
394 && (bufferSize >= sizeof(struct dirent) + B_FILE_NAME_LENGTH)) {
395 size_t length = bufferSize - offsetof(struct dirent, d_name);
396 ino_t iNodeNo;
397
398 status_t status = iterator->GetNext(dirent->d_name, &length, &iNodeNo);
399 if (status == B_ENTRY_NOT_FOUND)
400 break;
401 if (status == B_BUFFER_OVERFLOW) {
402 if (count == 0)
403 return status;
404 break;
405 }
406 if (status != B_OK)
407 return status;
408
409 dirent->d_dev = volume->ID();
410 dirent->d_ino = iNodeNo;
411 dirent->d_reclen = offsetof(struct dirent, d_name) + length + 1;
412 bufferSize -= dirent->d_reclen;
413 dirent = (struct dirent*)((uint8*)dirent + dirent->d_reclen);
414 count++;
415 }
416
417 *_num = count;
418 return B_OK;
419
420 }
421
422
423 static status_t
ufs2_rewind_dir(fs_volume *,fs_vnode *,void * _cookie)424 ufs2_rewind_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, void *_cookie)
425 {
426 DirectoryIterator *iterator = (DirectoryIterator *)_cookie;
427 return iterator->Rewind();
428 }
429
430
431 static status_t
ufs2_close_dir(fs_volume *,fs_vnode *,void *)432 ufs2_close_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/,
433 void * /*_cookie*/)
434 {
435 return B_OK;
436 }
437
438
439 static status_t
ufs2_free_dir_cookie(fs_volume * _volume,fs_vnode * _node,void * _cookie)440 ufs2_free_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
441 {
442 delete (DirectoryIterator*)_cookie;
443 return B_OK;
444 }
445
446
447 static status_t
ufs2_open_attr_dir(fs_volume * _volume,fs_vnode * _node,void ** _cookie)448 ufs2_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
449 {
450 return B_NOT_SUPPORTED;
451 }
452
453
454 static status_t
ufs2_close_attr_dir(fs_volume * _volume,fs_vnode * _node,void * cookie)455 ufs2_close_attr_dir(fs_volume *_volume, fs_vnode *_node, void *cookie)
456 {
457 return B_NOT_SUPPORTED;
458 }
459
460
461 static status_t
ufs2_free_attr_dir_cookie(fs_volume * _volume,fs_vnode * _node,void * _cookie)462 ufs2_free_attr_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
463 {
464 return B_NOT_SUPPORTED;
465 }
466
467
468 static status_t
ufs2_read_attr_dir(fs_volume * _volume,fs_vnode * _node,void * _cookie,struct dirent * dirent,size_t bufferSize,uint32 * _num)469 ufs2_read_attr_dir(fs_volume *_volume, fs_vnode *_node,
470 void *_cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num)
471 {
472 return B_NOT_SUPPORTED;
473 }
474
475
476 static status_t
ufs2_rewind_attr_dir(fs_volume * _volume,fs_vnode * _node,void * _cookie)477 ufs2_rewind_attr_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie)
478 {
479 return B_NOT_SUPPORTED;
480 }
481
482
483 /* attribute operations */
484 static status_t
ufs2_create_attr(fs_volume * _volume,fs_vnode * _node,const char * name,uint32 type,int openMode,void ** _cookie)485 ufs2_create_attr(fs_volume *_volume, fs_vnode *_node,
486 const char *name, uint32 type, int openMode, void **_cookie)
487 {
488 return B_NOT_SUPPORTED;
489 }
490
491
492 static status_t
ufs2_open_attr(fs_volume * _volume,fs_vnode * _node,const char * name,int openMode,void ** _cookie)493 ufs2_open_attr(fs_volume *_volume, fs_vnode *_node, const char *name,
494 int openMode, void **_cookie)
495 {
496 return B_NOT_SUPPORTED;
497 }
498
499
500 static status_t
ufs2_close_attr(fs_volume * _volume,fs_vnode * _node,void * cookie)501 ufs2_close_attr(fs_volume *_volume, fs_vnode *_node,
502 void *cookie)
503 {
504 return B_NOT_SUPPORTED;
505 }
506
507
508 static status_t
ufs2_free_attr_cookie(fs_volume * _volume,fs_vnode * _node,void * cookie)509 ufs2_free_attr_cookie(fs_volume *_volume, fs_vnode *_node,
510 void *cookie)
511 {
512 return B_NOT_SUPPORTED;
513 }
514
515
516 static status_t
ufs2_read_attr(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,void * buffer,size_t * _length)517 ufs2_read_attr(fs_volume *_volume, fs_vnode *_node, void *_cookie,
518 off_t pos, void *buffer, size_t *_length)
519 {
520 return B_NOT_SUPPORTED;
521 }
522
523
524 static status_t
ufs2_write_attr(fs_volume * _volume,fs_vnode * _node,void * cookie,off_t pos,const void * buffer,size_t * length)525 ufs2_write_attr(fs_volume *_volume, fs_vnode *_node, void *cookie,
526 off_t pos, const void *buffer, size_t *length)
527 {
528 return B_NOT_SUPPORTED;
529 }
530
531
532 static status_t
ufs2_read_attr_stat(fs_volume * _volume,fs_vnode * _node,void * _cookie,struct stat * stat)533 ufs2_read_attr_stat(fs_volume *_volume, fs_vnode *_node,
534 void *_cookie, struct stat *stat)
535 {
536 return B_NOT_SUPPORTED;
537 }
538
539
540 static status_t
ufs2_write_attr_stat(fs_volume * _volume,fs_vnode * _node,void * cookie,const struct stat * stat,int statMask)541 ufs2_write_attr_stat(fs_volume *_volume, fs_vnode *_node,
542 void *cookie, const struct stat *stat, int statMask)
543 {
544 return B_NOT_SUPPORTED;
545 }
546
547
548 static status_t
ufs2_rename_attr(fs_volume * _volume,fs_vnode * fromVnode,const char * fromName,fs_vnode * toVnode,const char * toName)549 ufs2_rename_attr(fs_volume *_volume, fs_vnode *fromVnode,
550 const char *fromName, fs_vnode *toVnode, const char *toName)
551 {
552 return B_NOT_SUPPORTED;
553 }
554
555
556 static status_t
ufs2_remove_attr(fs_volume * _volume,fs_vnode * vnode,const char * name)557 ufs2_remove_attr(fs_volume *_volume, fs_vnode *vnode,
558 const char *name)
559 {
560 return B_NOT_SUPPORTED;
561 }
562
563
564 // #pragma mark -
565
566 static status_t
ufs2_std_ops(int32 op,...)567 ufs2_std_ops(int32 op, ...)
568 {
569 switch (op)
570 {
571 case B_MODULE_INIT:
572 #ifdef ufs2_DEBUGGER_COMMANDS
573 // Perform nothing at the moment
574 // add_debugger_commands();
575 #endif
576 return B_OK;
577 case B_MODULE_UNINIT:
578 #ifdef ufs2_DEBUGGER_COMMANDS
579 // Perform nothing at the moment
580 // remove_debugger_commands();
581 #endif
582 return B_OK;
583
584 default:
585 return B_ERROR;
586 }
587 }
588
589 fs_volume_ops gUfs2VolumeOps = {
590 &ufs2_unmount,
591 &ufs2_read_fs_info,
592 NULL, //write_fs_info()
593 NULL, // fs_sync,
594 &ufs2_get_vnode,
595 };
596
597 fs_vnode_ops gufs2VnodeOps = {
598 /* vnode operations */
599 &ufs2_lookup,
600 NULL, // ufs2_get_vnode_name - optional, and we can't do better than the
601 // fallback implementation, so leave as NULL.
602 &ufs2_put_vnode,
603 NULL, // ufs2_remove_vnode,
604
605 /* VM file access */
606 &ufs2_can_page,
607 &ufs2_read_pages,
608 NULL, // ufs2_write_pages,
609
610 &ufs2_io, // io()
611 NULL, // cancel_io()
612
613 &ufs2_get_file_map,
614
615 &ufs2_ioctl,
616 NULL,
617 NULL, // fs_select
618 NULL, // fs_deselect
619 NULL, // fs_fsync,
620
621 &ufs2_read_link,
622 NULL, // fs_create_symlink,
623
624 NULL, // fs_link,
625 &ufs2_unlink,
626 NULL, // fs_rename,
627
628 &ufs2_access,
629 &ufs2_read_stat,
630 NULL, // fs_write_stat,
631 NULL, // fs_preallocate
632
633 /* file operations */
634 NULL, // fs_create,
635 &ufs2_open,
636 &ufs2_close,
637 &ufs2_free_cookie,
638 &ufs2_read,
639 NULL, // fs_write,
640
641 /* directory operations */
642 &ufs2_create_dir,
643 &ufs2_remove_dir,
644 &ufs2_open_dir,
645 &ufs2_close_dir,
646 &ufs2_free_dir_cookie,
647 &ufs2_read_dir,
648 &ufs2_rewind_dir,
649
650 /* attribute directory operations */
651 &ufs2_open_attr_dir,
652 &ufs2_close_attr_dir,
653 &ufs2_free_attr_dir_cookie,
654 &ufs2_read_attr_dir,
655 &ufs2_rewind_attr_dir,
656
657 /* attribute operations */
658 &ufs2_create_attr,
659 &ufs2_open_attr,
660 &ufs2_close_attr,
661 &ufs2_free_attr_cookie,
662 &ufs2_read_attr,
663 &ufs2_write_attr,
664 &ufs2_read_attr_stat,
665 &ufs2_write_attr_stat,
666 &ufs2_rename_attr,
667 &ufs2_remove_attr,
668 };
669
670
671 static file_system_module_info sufs2FileSystem = {
672 {
673 "file_systems/ufs2" B_CURRENT_FS_API_VERSION,
674 0,
675 ufs2_std_ops,
676 },
677
678 "ufs2", // short_name
679 "Unix Filesystem 2", // pretty_name
680
681 // DDM flags
682 B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
683 // | B_DISK_SYSTEM_SUPPORTS_WRITING
684 ,
685
686 // scanning
687 ufs2_identify_partition,
688 ufs2_scan_partition,
689 ufs2_free_identify_partition_cookie,
690 NULL, // free_partition_content_cookie()
691
692 &ufs2_mount,
693 };
694
695 module_info *modules[] = {
696 (module_info *)&sufs2FileSystem,
697 NULL,
698 };
699