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