xref: /haiku/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*
2  * Copyright 2001-2017, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
4  * All rights reserved. Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "system_dependencies.h"
9 #include "Directory.h"
10 #include "Inode.h"
11 #include "Utility.h"
12 #include "Volume.h"
13 
14 
15 #define XFS_IO_SIZE	65536
16 
17 struct identify_cookie
18 {
19 	/*	super_block_struct super_block;
20 	*	No structure yet implemented.
21 	*/
22 	int cookie;
23 };
24 
25 
26 //!	xfs_io() callback hook
27 static status_t
28 iterative_io_get_vecs_hook(void *cookie, io_request *request, off_t offset,
29 	size_t size, struct file_io_vec *vecs, size_t *_count)
30 {
31 	return B_NOT_SUPPORTED;
32 }
33 
34 
35 //!	xfs_io() callback hook
36 static status_t
37 iterative_io_finished_hook(void *cookie, io_request *request, status_t status,
38 	bool partialTransfer, size_t bytesTransferred)
39 {
40 	return B_NOT_SUPPORTED;
41 }
42 
43 
44 //	#pragma mark - Scanning
45 
46 
47 static float
48 xfs_identify_partition(int fd, partition_data *partition, void **_cookie)
49 {
50 	return B_NOT_SUPPORTED;
51 }
52 
53 
54 static status_t
55 xfs_scan_partition(int fd, partition_data *partition, void *_cookie)
56 {
57 	return B_NOT_SUPPORTED;
58 }
59 
60 
61 static void
62 xfs_free_identify_partition_cookie(partition_data *partition, void *_cookie)
63 {
64 	dprintf("Unsupported in XFS currently.\n");
65 	return;
66 }
67 
68 
69 //	#pragma mark -
70 
71 
72 static status_t
73 xfs_mount(fs_volume *_volume, const char *device, uint32 flags,
74 	const char *args, ino_t *_rootID)
75 {
76 	TRACE("xfs_mount(): Trying to mount\n");
77 
78 	Volume *volume = new (std::nothrow) Volume(_volume);
79 	if (volume == NULL)
80 		return B_NO_MEMORY;
81 
82 	_volume->private_volume = volume;
83 	_volume->ops = &gxfsVolumeOps;
84 
85 	status_t status = volume->Mount(device, flags);
86 	if (status != B_OK) {
87 		ERROR("Failed mounting the volume. Error: %s\n", strerror(status));
88 		delete volume;
89 		_volume->private_volume = NULL;
90 		return status;
91 	}
92 
93 	*_rootID = volume->Root();
94 	return B_OK;
95 }
96 
97 
98 static status_t
99 xfs_unmount(fs_volume *_volume)
100 {
101 	Volume* volume = (Volume*) _volume->private_volume;
102 
103 	status_t status = volume->Unmount();
104 	delete volume;
105 	TRACE("xfs_unmount(): Deleted volume");
106 	return status;
107 }
108 
109 
110 static status_t
111 xfs_read_fs_info(fs_volume *_volume, struct fs_info *info)
112 {
113 	TRACE("XFS_READ_FS_INFO:\n");
114 	Volume* volume = (Volume*)_volume->private_volume;
115 
116 	info->flags = B_FS_IS_READONLY
117 					| B_FS_HAS_ATTR | B_FS_IS_PERSISTENT;
118 
119 	info->io_size = XFS_IO_SIZE;
120 	info->block_size = volume->SuperBlock().BlockSize();
121 	info->total_blocks = volume->SuperBlock().TotalBlocks();
122 	info->free_blocks = volume->SuperBlock().FreeBlocks();
123 
124 	strlcpy(info->volume_name, volume->Name(), sizeof(info->volume_name));
125 	strlcpy(info->fsh_name, "xfs", sizeof(info->fsh_name));
126 
127 	return B_OK;
128 }
129 
130 
131 //	#pragma mark -
132 
133 
134 static status_t
135 xfs_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_node, int *_type,
136 	uint32 *_flags, bool reenter)
137 {
138 	TRACE("XFS_GET_VNODE:\n");
139 	Volume* volume = (Volume*)_volume->private_volume;
140 
141 	Inode* inode = new(std::nothrow) Inode(volume, id);
142 	if (inode == NULL)
143 		return B_NO_MEMORY;
144 
145 	status_t status = inode->Init();
146 	if (status != B_OK) {
147 		delete inode;
148 		ERROR("get_vnode: InitCheck() failed. Error: %s\n", strerror(status));
149 		return B_NO_INIT;
150 	}
151 
152 	_node->private_node = inode;
153 	_node->ops = &gxfsVnodeOps;
154 	*_type = inode->Mode();
155 	*_flags = 0;
156 	TRACE("(%ld)\n", inode->ID());
157 	return B_OK;
158 }
159 
160 
161 static status_t
162 xfs_put_vnode(fs_volume *_volume, fs_vnode *_node, bool reenter)
163 {
164 	TRACE("XFS_PUT_VNODE:\n");
165 	delete (Inode*)_node->private_node;
166 	return B_OK;
167 }
168 
169 
170 static bool
171 xfs_can_page(fs_volume *_volume, fs_vnode *_node, void *_cookie)
172 {
173 	return B_NOT_SUPPORTED;
174 }
175 
176 
177 static status_t
178 xfs_read_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie,
179 	off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
180 {
181 	return B_NOT_SUPPORTED;
182 }
183 
184 
185 static status_t
186 xfs_io(fs_volume *_volume, fs_vnode *_node, void *_cookie,
187 	io_request *request)
188 {
189 	return B_NOT_SUPPORTED;
190 }
191 
192 
193 static status_t
194 xfs_get_file_map(fs_volume *_volume, fs_vnode *_node, off_t offset,
195 	size_t size, struct file_io_vec *vecs, size_t *_count)
196 {
197 	return B_NOT_SUPPORTED;
198 }
199 
200 
201 //	#pragma mark -
202 
203 
204 static status_t
205 xfs_lookup(fs_volume *_volume, fs_vnode *_directory, const char *name,
206 	ino_t *_vnodeID)
207 {
208 	TRACE("XFS_LOOKUP: %p (%s)\n", name, name);
209 	Volume* volume = (Volume*)_volume->private_volume;
210 	Inode* directory = (Inode*)_directory->private_node;
211 
212 	if (!directory->IsDirectory())
213 		return B_NOT_A_DIRECTORY;
214 
215 	status_t status = directory->CheckPermissions(X_OK);
216 	if (status < B_OK)
217 		return status;
218 
219 	DirectoryIterator* iterator =
220 		new(std::nothrow) DirectoryIterator(directory);
221 	if (iterator == NULL)
222 		return B_NO_MEMORY;
223 
224 	status = iterator->Init();
225 	if (status != B_OK) {
226 		delete iterator;
227 		return status;
228 	}
229 
230 	status = iterator->Lookup(name, strlen(name), (xfs_ino_t*)_vnodeID);
231 	if (status != B_OK) {
232 		delete iterator;
233 		return status;
234 	}
235 
236 	TRACE("XFS_LOOKUP: ID: (%ld)\n", *_vnodeID);
237 	status = get_vnode(volume->FSVolume(), *_vnodeID, NULL);
238 	TRACE("get_vnode status: (%d)\n", status);
239 	return status;
240 }
241 
242 
243 static status_t
244 xfs_ioctl(fs_volume *_volume, fs_vnode *_node, void *_cookie, uint32 cmd,
245 	void *buffer, size_t bufferLength)
246 {
247 	return B_NOT_SUPPORTED;
248 }
249 
250 
251 static status_t
252 xfs_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat)
253 {
254 	Inode* inode = (Inode*)_node->private_node;
255 	TRACE("XFS_READ_STAT: id: (%ld)\n", inode->ID());
256 	stat->st_dev = inode->GetVolume()->ID();
257 	stat->st_ino = inode->ID();
258 	stat->st_nlink = 1;
259 	stat->st_blksize = XFS_IO_SIZE;
260 
261 	stat->st_uid = inode->UserId();
262 	stat->st_gid = inode->GroupId();
263 	stat->st_mode = inode->Mode();
264 	stat->st_type = 0;	// TODO
265 
266 	stat->st_size = inode->Size();
267 	stat->st_blocks = inode->BlockCount();
268 
269 	inode->GetAccessTime(stat->st_atim);
270 	inode->GetModificationTime(stat->st_mtim);
271 	inode->GetChangeTime(stat->st_ctim);
272 
273 	/* TODO: Can we obtain the Creation Time in v4 system? */
274 	inode->GetChangeTime(stat->st_crtim);
275 
276 	return B_OK;
277 
278 }
279 
280 
281 static status_t
282 xfs_open(fs_volume * /*_volume*/, fs_vnode *_node, int openMode,
283 	void **_cookie)
284 {
285 	TRACE("XFS_OPEN:\n");
286 	Inode* inode = (Inode*)_node->private_node;
287 
288 	// opening a directory read-only is allowed, although you can't read
289 	// any data from it.
290 	if (inode->IsDirectory() && (openMode & O_RWMASK) != 0)
291 		return B_IS_A_DIRECTORY;
292 
293 	status_t status =  inode->CheckPermissions(open_mode_to_access(openMode)
294 		| (openMode & O_TRUNC ? W_OK : 0));
295 	if (status != B_OK)
296 		return status;
297 
298 	// Prepare the cookie
299 	file_cookie* cookie = new(std::nothrow) file_cookie;
300 	if (cookie == NULL)
301 		return B_NO_MEMORY;
302 	ObjectDeleter<file_cookie> cookieDeleter(cookie);
303 
304 	cookie->open_mode = openMode & XFS_OPEN_MODE_USER_MASK;
305 	cookie->last_size = inode->Size();
306 	cookie->last_notification = system_time();
307 
308 	cookieDeleter.Detach();
309 	*_cookie = cookie;
310 
311 	return B_OK;
312 }
313 
314 
315 static status_t
316 xfs_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
317 	void *buffer, size_t *_length)
318 {
319 	TRACE("Inode::ReadAt: pos:(%ld), *length:(%ld)\n", pos, *_length);
320 	Inode* inode = (Inode*)_node->private_node;
321 
322 	if (!inode->IsFile()) {
323 		*_length = 0;
324 		return inode->IsDirectory() ? B_IS_A_DIRECTORY : B_BAD_VALUE;
325 	}
326 
327 	return inode->ReadAt(pos, (uint8*)buffer, _length);
328 }
329 
330 
331 static status_t
332 xfs_close(fs_volume *_volume, fs_vnode *_node, void *_cookie)
333 {
334 	return B_OK;
335 }
336 
337 
338 static status_t
339 xfs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
340 {
341 	TRACE("XFS_FREE_COOKIE:\n");
342 	file_cookie* cookie = (file_cookie*)_cookie;
343 	Volume* volume = (Volume*)_volume->private_volume;
344 	Inode* inode = (Inode*)_node->private_node;
345 
346 	if (inode->Size() != cookie->last_size)
347 		notify_stat_changed(volume->ID(), -1, inode->ID(), B_STAT_SIZE);
348 
349 	delete cookie;
350 	return B_OK;
351 }
352 
353 
354 static status_t
355 xfs_access(fs_volume *_volume, fs_vnode *_node, int accessMode)
356 {
357 	Inode* inode = (Inode*)_node->private_node;
358 	return inode->CheckPermissions(accessMode);
359 }
360 
361 
362 static status_t
363 xfs_read_link(fs_volume *_volume, fs_vnode *_node, char *buffer,
364 	size_t *_bufferSize)
365 {
366 	return B_NOT_SUPPORTED;
367 }
368 
369 
370 status_t
371 xfs_unlink(fs_volume *_volume, fs_vnode *_directory, const char *name)
372 {
373 	return B_NOT_SUPPORTED;
374 }
375 
376 
377 //	#pragma mark - Directory functions
378 
379 
380 static status_t
381 xfs_create_dir(fs_volume *_volume, fs_vnode *_directory, const char *name,
382 	int mode)
383 {
384 	return B_NOT_SUPPORTED;
385 }
386 
387 
388 static status_t
389 xfs_remove_dir(fs_volume *_volume, fs_vnode *_directory, const char *name)
390 {
391 	return B_NOT_SUPPORTED;
392 }
393 
394 
395 static status_t
396 xfs_open_dir(fs_volume * /*_volume*/, fs_vnode *_node, void **_cookie)
397 {
398 	Inode* inode = (Inode*)_node->private_node;
399 	TRACE("XFS_OPEN_DIR: (%ld)\n", inode->ID());
400 
401 	status_t status = inode->CheckPermissions(R_OK);
402 	if (status < B_OK)
403 		return status;
404 
405 	if (!inode->IsDirectory())
406 		return B_NOT_A_DIRECTORY;
407 
408 	DirectoryIterator* iterator = new(std::nothrow) DirectoryIterator(inode);
409 	if (iterator == NULL) {
410 		delete iterator;
411 		return B_NO_MEMORY;
412 	}
413 	status = iterator->Init();
414 	*_cookie = iterator;
415 	return status;
416 }
417 
418 
419 static status_t
420 xfs_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
421 	struct dirent *buffer, size_t bufferSize, uint32 *_num)
422 {
423 	TRACE("XFS_READ_DIR\n");
424 	DirectoryIterator* iterator = (DirectoryIterator*)_cookie;
425 	Volume* volume = (Volume*)_volume->private_volume;
426 
427 	uint32 maxCount = *_num;
428 	uint32 count = 0;
429 
430 	while (count < maxCount && (bufferSize > sizeof(struct dirent))) {
431 		size_t length = bufferSize - sizeof(struct dirent);
432 		xfs_ino_t ino;
433 
434 		status_t status = iterator->GetNext(buffer->d_name, &length, &ino);
435 		if (status == B_ENTRY_NOT_FOUND)
436 			break;
437 		if (status == B_BUFFER_OVERFLOW) {
438 			if (count == 0)
439 				return status;
440 			break;
441 		}
442 		if (status != B_OK)
443 			return status;
444 
445 		buffer->d_dev = volume->ID();
446 		buffer->d_ino = ino;
447 		buffer->d_reclen = offsetof(struct dirent, d_name) + length + 1;
448 		bufferSize -= buffer->d_reclen;
449 		buffer = (struct dirent*)((uint8*)buffer + buffer->d_reclen);
450 		count++;
451 	}
452 
453 	*_num = count;
454 	TRACE("Count: (%d)\n", count);
455 	return B_OK;
456 }
457 
458 
459 static status_t
460 xfs_rewind_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, void *_cookie)
461 {
462 	return B_NOT_SUPPORTED;
463 }
464 
465 
466 static status_t
467 xfs_close_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/,
468 	void * /*_cookie*/)
469 {
470 	return B_OK;
471 }
472 
473 
474 static status_t
475 xfs_free_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
476 {
477 	delete (DirectoryIterator*)_cookie;
478 	return B_NOT_SUPPORTED;
479 }
480 
481 
482 static status_t
483 xfs_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
484 {
485 	return B_NOT_SUPPORTED;
486 }
487 
488 
489 static status_t
490 xfs_close_attr_dir(fs_volume *_volume, fs_vnode *_node, void *cookie)
491 {
492 	return B_NOT_SUPPORTED;
493 }
494 
495 
496 static status_t
497 xfs_free_attr_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
498 {
499 	return B_NOT_SUPPORTED;
500 }
501 
502 
503 static status_t
504 xfs_read_attr_dir(fs_volume *_volume, fs_vnode *_node,
505 	void *_cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num)
506 {
507 	return B_NOT_SUPPORTED;
508 }
509 
510 
511 static status_t
512 xfs_rewind_attr_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie)
513 {
514 	return B_NOT_SUPPORTED;
515 }
516 
517 
518 /* attribute operations */
519 static status_t
520 xfs_create_attr(fs_volume *_volume, fs_vnode *_node,
521 	const char *name, uint32 type, int openMode, void **_cookie)
522 {
523 	return B_NOT_SUPPORTED;
524 }
525 
526 
527 static status_t
528 xfs_open_attr(fs_volume *_volume, fs_vnode *_node, const char *name,
529 	int openMode, void **_cookie)
530 {
531 	return B_NOT_SUPPORTED;
532 }
533 
534 
535 static status_t
536 xfs_close_attr(fs_volume *_volume, fs_vnode *_node,
537 	void *cookie)
538 {
539 	return B_NOT_SUPPORTED;
540 }
541 
542 
543 static status_t
544 xfs_free_attr_cookie(fs_volume *_volume, fs_vnode *_node, void *cookie)
545 {
546 	return B_NOT_SUPPORTED;
547 }
548 
549 
550 static status_t
551 xfs_read_attr(fs_volume *_volume, fs_vnode *_node, void *_cookie,
552 	off_t pos, void *buffer, size_t *_length)
553 {
554 	return B_NOT_SUPPORTED;
555 }
556 
557 
558 static status_t
559 xfs_write_attr(fs_volume *_volume, fs_vnode *_node, void *cookie,
560 	off_t pos, const void *buffer, size_t *length)
561 {
562 	return B_NOT_SUPPORTED;
563 }
564 
565 
566 static status_t
567 xfs_read_attr_stat(fs_volume *_volume, fs_vnode *_node,
568 	void *_cookie, struct stat *stat)
569 {
570 	return B_NOT_SUPPORTED;
571 }
572 
573 
574 static status_t
575 xfs_write_attr_stat(fs_volume *_volume, fs_vnode *_node,
576 	void *cookie, const struct stat *stat, int statMask)
577 {
578 	return B_NOT_SUPPORTED;
579 }
580 
581 
582 static status_t
583 xfs_rename_attr(fs_volume *_volume, fs_vnode *fromVnode,
584 	const char *fromName, fs_vnode *toVnode, const char *toName)
585 {
586 	return B_NOT_SUPPORTED;
587 }
588 
589 
590 static status_t
591 xfs_remove_attr(fs_volume *_volume, fs_vnode *vnode,
592 	const char *name)
593 {
594 	return B_NOT_SUPPORTED;
595 }
596 
597 
598 static uint32
599 xfs_get_supported_operations(partition_data *partition, uint32 mask)
600 {
601 	return B_NOT_SUPPORTED;
602 }
603 
604 
605 static status_t
606 xfs_initialize(int fd, partition_id partitionID, const char *name,
607 	const char *parameterString, off_t partitionSize, disk_job_id job)
608 {
609 	return B_NOT_SUPPORTED;
610 }
611 
612 
613 static status_t
614 xfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize,
615 	uint32 blockSize, disk_job_id job)
616 {
617 	return B_NOT_SUPPORTED;
618 }
619 
620 
621 //	#pragma mark -
622 
623 
624 static status_t
625 xfs_std_ops(int32 op, ...)
626 {
627 	switch (op)
628 	{
629 	case B_MODULE_INIT:
630 #ifdef XFS_DEBUGGER_COMMANDS
631 		// Perform nothing at the moment
632 		// add_debugger_commands();
633 #endif
634 		return B_OK;
635 	case B_MODULE_UNINIT:
636 #ifdef XFS_DEBUGGER_COMMANDS
637 		// Perform nothing at the moment
638 		// remove_debugger_commands();
639 #endif
640 		return B_OK;
641 
642 	default:
643 		return B_ERROR;
644 	}
645 }
646 
647 
648 fs_volume_ops gxfsVolumeOps = {
649 	&xfs_unmount,
650 	&xfs_read_fs_info,
651 	NULL,				// write_fs_info()
652 	NULL,				// fs_sync,
653 	&xfs_get_vnode,
654 };
655 
656 
657 fs_vnode_ops gxfsVnodeOps = {
658 	/* vnode operations */
659 	&xfs_lookup,
660 	NULL,				// xfs_get_vnode_name- optional, and we can't do better
661 						// than the fallback implementation, so leave as NULL.
662 	&xfs_put_vnode,
663 	NULL, 				// xfs_remove_vnode,
664 
665 	/* VM file access */
666 	&xfs_can_page,
667 	&xfs_read_pages,
668 	NULL,				// xfs_write_pages,
669 
670 	&xfs_io,			// io()
671 	NULL,				// cancel_io()
672 
673 	&xfs_get_file_map,
674 
675 	&xfs_ioctl,
676 	NULL,
677 	NULL,				// fs_select
678 	NULL,				// fs_deselect
679 	NULL,				// fs_fsync,
680 
681 	&xfs_read_link,
682 	NULL,				// fs_create_symlink,
683 
684 	NULL,				// fs_link,
685 	&xfs_unlink,
686 	NULL,				// fs_rename,
687 
688 	&xfs_access,
689 	&xfs_read_stat,
690 	NULL,				// fs_write_stat,
691 	NULL,				// fs_preallocate
692 
693 	/* file operations */
694 	NULL,				// fs_create,
695 	&xfs_open,
696 	&xfs_close,
697 	&xfs_free_cookie,
698 	&xfs_read,
699 	NULL,				// fs_write,
700 
701 	/* directory operations */
702 	&xfs_create_dir,
703 	&xfs_remove_dir,
704 	&xfs_open_dir,
705 	&xfs_close_dir,
706 	&xfs_free_dir_cookie,
707 	&xfs_read_dir,
708 	&xfs_rewind_dir,
709 
710 	/* attribute directory operations */
711 	&xfs_open_attr_dir,
712 	&xfs_close_attr_dir,
713 	&xfs_free_attr_dir_cookie,
714 	&xfs_read_attr_dir,
715 	&xfs_rewind_attr_dir,
716 
717 	/* attribute operations */
718 	&xfs_create_attr,
719 	&xfs_open_attr,
720 	&xfs_close_attr,
721 	&xfs_free_attr_cookie,
722 	&xfs_read_attr,
723 	&xfs_write_attr,
724 	&xfs_read_attr_stat,
725 	&xfs_write_attr_stat,
726 	&xfs_rename_attr,
727 	&xfs_remove_attr,
728 };
729 
730 
731 static
732 file_system_module_info sxfsFileSystem = {
733 	{
734 		"file_systems/xfs" B_CURRENT_FS_API_VERSION,
735 		0,
736 		xfs_std_ops,
737 	},
738 
739 	"xfs",				// short_name
740 	"XFS File System",	// pretty_name
741 
742 	// DDM flags
743 	0 |B_DISK_SYSTEM_SUPPORTS_INITIALIZING |B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
744 	//	| B_DISK_SYSTEM_SUPPORTS_WRITING
745 	,
746 
747 	// scanning
748 	xfs_identify_partition,
749 	xfs_scan_partition,
750 	xfs_free_identify_partition_cookie,
751 	NULL,				// free_partition_content_cookie()
752 
753 	&xfs_mount,
754 
755 	/* capability querying operations */
756 	&xfs_get_supported_operations,
757 
758 	NULL,				// validate_resize
759 	NULL,				// validate_move
760 	NULL,				// validate_set_content_name
761 	NULL,				// validate_set_content_parameters
762 	NULL,				// validate_initialize,
763 
764 	/* shadow partition modification */
765 	NULL,				// shadow_changed
766 
767 	/* writing */
768 	NULL,				// defragment
769 	NULL,				// repair
770 	NULL,				// resize
771 	NULL,				// move
772 	NULL,				// set_content_name
773 	NULL,				// set_content_parameters
774 	xfs_initialize,
775 	xfs_uninitialize};
776 
777 module_info *modules[] = {
778 	(module_info *)&sxfsFileSystem,
779 	NULL,
780 };
781