xref: /haiku/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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
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
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
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
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
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
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
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
163 ufs2_put_vnode(fs_volume *_volume, fs_vnode *_node, bool reenter)
164 {
165 	return B_NOT_SUPPORTED;
166 }
167 
168 
169 static bool
170 ufs2_can_page(fs_volume *_volume, fs_vnode *_node, void *_cookie)
171 {
172 	return false;
173 }
174 
175 
176 static status_t
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
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
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
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
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
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
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
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
305 ufs2_close(fs_volume *_volume, fs_vnode *_node, void *_cookie)
306 {
307 	return B_OK;
308 }
309 
310 
311 static status_t
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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