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