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