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