xref: /haiku/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
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 = DirectoryIterator::Init(directory);
209 	if (iterator == NULL)
210 		return B_BAD_VALUE;
211 
212 	status = iterator->Lookup(name, strlen(name), (xfs_ino_t*)_vnodeID);
213 	if (status != B_OK) {
214 		delete iterator;
215 		return status;
216 	}
217 
218 	TRACE("XFS_LOOKUP: ID: (%ld)\n", *_vnodeID);
219 	status = get_vnode(volume->FSVolume(), *_vnodeID, NULL);
220 	TRACE("get_vnode status: (%d)\n", status);
221 	return status;
222 }
223 
224 
225 static status_t
226 xfs_ioctl(fs_volume *_volume, fs_vnode *_node, void *_cookie, uint32 cmd,
227 	void *buffer, size_t bufferLength)
228 {
229 	return B_NOT_SUPPORTED;
230 }
231 
232 
233 static status_t
234 xfs_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat)
235 {
236 	Inode* inode = (Inode*)_node->private_node;
237 	TRACE("XFS_READ_STAT: id: (%ld)\n", inode->ID());
238 	stat->st_dev = inode->GetVolume()->ID();
239 	stat->st_ino = inode->ID();
240 	stat->st_nlink = 1;
241 	stat->st_blksize = XFS_IO_SIZE;
242 
243 	stat->st_uid = inode->UserId();
244 	stat->st_gid = inode->GroupId();
245 	stat->st_mode = inode->Mode();
246 	stat->st_type = 0;	// TODO
247 
248 	stat->st_size = inode->Size();
249 	stat->st_blocks = inode->BlockCount();
250 
251 	inode->GetAccessTime(stat->st_atim);
252 	inode->GetModificationTime(stat->st_mtim);
253 	inode->GetChangeTime(stat->st_ctim);
254 
255 	// Only version 3 Inodes has creation time
256 	if(inode->Version() == 3)
257 		inode->GetCreationTime(stat->st_crtim);
258 	else
259 		inode->GetChangeTime(stat->st_crtim);
260 
261 	return B_OK;
262 }
263 
264 
265 static status_t
266 xfs_open(fs_volume * /*_volume*/, fs_vnode *_node, int openMode,
267 	void **_cookie)
268 {
269 	TRACE("XFS_OPEN:\n");
270 	Inode* inode = (Inode*)_node->private_node;
271 
272 	// opening a directory read-only is allowed, although you can't read
273 	// any data from it.
274 	if (inode->IsDirectory() && (openMode & O_RWMASK) != 0)
275 		return B_IS_A_DIRECTORY;
276 
277 	status_t status =  inode->CheckPermissions(open_mode_to_access(openMode)
278 		| (openMode & O_TRUNC ? W_OK : 0));
279 	if (status != B_OK)
280 		return status;
281 
282 	// Prepare the cookie
283 	file_cookie* cookie = new(std::nothrow) file_cookie;
284 	if (cookie == NULL)
285 		return B_NO_MEMORY;
286 	ObjectDeleter<file_cookie> cookieDeleter(cookie);
287 
288 	cookie->open_mode = openMode & XFS_OPEN_MODE_USER_MASK;
289 	cookie->last_size = inode->Size();
290 	cookie->last_notification = system_time();
291 
292 	cookieDeleter.Detach();
293 	*_cookie = cookie;
294 
295 	return B_OK;
296 }
297 
298 
299 static status_t
300 xfs_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
301 	void *buffer, size_t *_length)
302 {
303 	TRACE("Inode::ReadAt: pos:(%ld), *length:(%ld)\n", pos, *_length);
304 	Inode* inode = (Inode*)_node->private_node;
305 
306 	if (!inode->IsFile()) {
307 		*_length = 0;
308 		return inode->IsDirectory() ? B_IS_A_DIRECTORY : B_BAD_VALUE;
309 	}
310 
311 	return inode->ReadAt(pos, (uint8*)buffer, _length);
312 }
313 
314 
315 static status_t
316 xfs_close(fs_volume *_volume, fs_vnode *_node, void *_cookie)
317 {
318 	return B_OK;
319 }
320 
321 
322 static status_t
323 xfs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
324 {
325 	TRACE("XFS_FREE_COOKIE:\n");
326 	file_cookie* cookie = (file_cookie*)_cookie;
327 	Volume* volume = (Volume*)_volume->private_volume;
328 	Inode* inode = (Inode*)_node->private_node;
329 
330 	if (inode->Size() != cookie->last_size)
331 		notify_stat_changed(volume->ID(), -1, inode->ID(), B_STAT_SIZE);
332 
333 	delete cookie;
334 	return B_OK;
335 }
336 
337 
338 static status_t
339 xfs_access(fs_volume *_volume, fs_vnode *_node, int accessMode)
340 {
341 	Inode* inode = (Inode*)_node->private_node;
342 	return inode->CheckPermissions(accessMode);
343 }
344 
345 
346 static status_t
347 xfs_read_link(fs_volume *_volume, fs_vnode *_node, char *buffer,
348 	size_t *_bufferSize)
349 {
350 	TRACE("XFS_READ_SYMLINK\n");
351 
352 	Inode* inode = (Inode*)_node->private_node;
353 
354 	if (!inode->IsSymLink())
355 		return B_BAD_VALUE;
356 
357 	Symlink symlink(inode);
358 
359 	status_t result = symlink.ReadLink(0, buffer, _bufferSize);
360 
361 	return result;
362 }
363 
364 
365 status_t
366 xfs_unlink(fs_volume *_volume, fs_vnode *_directory, const char *name)
367 {
368 	return B_NOT_SUPPORTED;
369 }
370 
371 
372 //	#pragma mark - Directory functions
373 
374 
375 static status_t
376 xfs_create_dir(fs_volume *_volume, fs_vnode *_directory, const char *name,
377 	int mode)
378 {
379 	return B_NOT_SUPPORTED;
380 }
381 
382 
383 static status_t
384 xfs_remove_dir(fs_volume *_volume, fs_vnode *_directory, const char *name)
385 {
386 	return B_NOT_SUPPORTED;
387 }
388 
389 
390 static status_t
391 xfs_open_dir(fs_volume * /*_volume*/, fs_vnode *_node, void **_cookie)
392 {
393 	Inode* inode = (Inode*)_node->private_node;
394 	TRACE("XFS_OPEN_DIR: (%ld)\n", inode->ID());
395 
396 	status_t status = inode->CheckPermissions(R_OK);
397 	if (status < B_OK)
398 		return status;
399 
400 	if (!inode->IsDirectory())
401 		return B_NOT_A_DIRECTORY;
402 
403 	DirectoryIterator* iterator = DirectoryIterator::Init(inode);
404 	if (iterator == NULL)
405 		return B_BAD_VALUE;
406 
407 	*_cookie = iterator;
408 	return status;
409 }
410 
411 
412 static status_t
413 xfs_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
414 	struct dirent *buffer, size_t bufferSize, uint32 *_num)
415 {
416 	TRACE("XFS_READ_DIR\n");
417 	DirectoryIterator* iterator = (DirectoryIterator*)_cookie;
418 	Volume* volume = (Volume*)_volume->private_volume;
419 
420 	uint32 maxCount = *_num;
421 	uint32 count = 0;
422 
423 	while (count < maxCount && (bufferSize > sizeof(struct dirent))) {
424 		size_t length = bufferSize - sizeof(struct dirent);
425 		xfs_ino_t ino;
426 
427 		status_t status = iterator->GetNext(buffer->d_name, &length, &ino);
428 		if (status == B_ENTRY_NOT_FOUND)
429 			break;
430 		if (status == B_BUFFER_OVERFLOW) {
431 			if (count == 0)
432 				return status;
433 			break;
434 		}
435 		if (status != B_OK)
436 			return status;
437 
438 		buffer->d_dev = volume->ID();
439 		buffer->d_ino = ino;
440 		buffer->d_reclen = offsetof(struct dirent, d_name) + length + 1;
441 		bufferSize -= buffer->d_reclen;
442 		buffer = (struct dirent*)((uint8*)buffer + buffer->d_reclen);
443 		count++;
444 	}
445 
446 	*_num = count;
447 	TRACE("Count: (%d)\n", count);
448 	return B_OK;
449 }
450 
451 
452 static status_t
453 xfs_rewind_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, void *_cookie)
454 {
455 	return B_NOT_SUPPORTED;
456 }
457 
458 
459 static status_t
460 xfs_close_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/,
461 	void * /*_cookie*/)
462 {
463 	return B_OK;
464 }
465 
466 
467 static status_t
468 xfs_free_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
469 {
470 	delete (DirectoryIterator*)_cookie;
471 	return B_NOT_SUPPORTED;
472 }
473 
474 
475 static status_t
476 xfs_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
477 {
478 	Inode* inode = (Inode*)_node->private_node;
479 	TRACE("%s()\n", __FUNCTION__);
480 
481 	// Attributes are only on files
482 	if (!inode->IsFile())
483 		return B_NOT_SUPPORTED;
484 
485 	Attribute* iterator = Attribute::Init(inode);
486 	if (iterator == NULL)
487 		return B_BAD_VALUE;
488 
489 	*_cookie = iterator;
490 	return B_OK;
491 }
492 
493 
494 static status_t
495 xfs_close_attr_dir(fs_volume *_volume, fs_vnode *_node, void *cookie)
496 {
497 	TRACE("%s()\n", __FUNCTION__);
498 	return B_OK;
499 }
500 
501 
502 static status_t
503 xfs_free_attr_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
504 {
505 	delete (Attribute*)_cookie;
506 	return B_OK;
507 }
508 
509 
510 static status_t
511 xfs_read_attr_dir(fs_volume *_volume, fs_vnode *_node,
512 	void *_cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num)
513 {
514 	TRACE("%s()\n", __FUNCTION__);
515 	Attribute* iterator = (Attribute*)_cookie;
516 
517 	size_t length = bufferSize;
518 	status_t status = iterator->GetNext(dirent->d_name, &length);
519 	if (status == B_ENTRY_NOT_FOUND) {
520 		*_num = 0;
521 		return B_OK;
522 	}
523 
524 	if (status != B_OK)
525 		return status;
526 
527 	Volume* volume = (Volume*)_volume->private_volume;
528 	Inode* inode = (Inode*)_node->private_node;
529 	dirent->d_dev = volume->ID();
530 	dirent->d_ino = inode->ID();
531 	dirent->d_reclen = offsetof(struct dirent, d_name) + length + 1;
532 	*_num = 1;
533 
534 	return B_OK;
535 }
536 
537 
538 static status_t
539 xfs_rewind_attr_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie)
540 {
541 	return B_NOT_SUPPORTED;
542 }
543 
544 
545 /* attribute operations */
546 static status_t
547 xfs_create_attr(fs_volume *_volume, fs_vnode *_node,
548 	const char *name, uint32 type, int openMode, void **_cookie)
549 {
550 	return B_NOT_SUPPORTED;
551 }
552 
553 
554 static status_t
555 xfs_open_attr(fs_volume *_volume, fs_vnode *_node, const char *name,
556 	int openMode, void **_cookie)
557 {
558 	TRACE("%s()\n", __FUNCTION__);
559 
560 	status_t status;
561 
562 	Inode* inode = (Inode*)_node->private_node;
563 
564 	int accessMode = open_mode_to_access(openMode) | (openMode & O_TRUNC ? W_OK : 0);
565 	status = inode->CheckPermissions(accessMode);
566 	if (status < B_OK)
567 		return status;
568 
569 	Attribute* attribute = Attribute::Init(inode);
570 
571 	if (attribute == NULL)
572 		return B_BAD_VALUE;
573 
574 	status = attribute->Open(name, openMode, (attr_cookie**)_cookie);
575 	delete attribute;
576 
577 	return status;
578 }
579 
580 
581 static status_t
582 xfs_close_attr(fs_volume *_volume, fs_vnode *_node,
583 	void *cookie)
584 {
585 	return B_OK;
586 }
587 
588 
589 static status_t
590 xfs_free_attr_cookie(fs_volume *_volume, fs_vnode *_node, void *cookie)
591 {
592 	delete (attr_cookie*)cookie;
593 	return B_OK;
594 }
595 
596 
597 static status_t
598 xfs_read_attr(fs_volume *_volume, fs_vnode *_node, void *_cookie,
599 	off_t pos, void *buffer, size_t *_length)
600 {
601 	TRACE("%s()\n", __FUNCTION__);
602 
603 	attr_cookie* cookie = (attr_cookie*)_cookie;
604 	Inode* inode = (Inode*)_node->private_node;
605 
606 	Attribute* attribute = Attribute::Init(inode);
607 
608 	if (attribute == NULL)
609 		return B_BAD_VALUE;
610 
611 	status_t status = attribute->Read(cookie, pos, (uint8*)buffer, _length);
612 	delete attribute;
613 
614 	return status;
615 }
616 
617 
618 static status_t
619 xfs_write_attr(fs_volume *_volume, fs_vnode *_node, void *cookie,
620 	off_t pos, const void *buffer, size_t *length)
621 {
622 	return B_NOT_SUPPORTED;
623 }
624 
625 
626 static status_t
627 xfs_read_attr_stat(fs_volume *_volume, fs_vnode *_node,
628 	void *_cookie, struct stat *stat)
629 {
630 	TRACE("%s()\n", __FUNCTION__);
631 
632 	attr_cookie* cookie = (attr_cookie*)_cookie;
633 	Inode* inode = (Inode*)_node->private_node;
634 
635 	Attribute* attribute = Attribute::Init(inode);
636 
637 	if (attribute == NULL)
638 		return B_BAD_VALUE;
639 
640 	status_t status = attribute->Stat(cookie, *stat);
641 	delete attribute;
642 
643 	return status;
644 }
645 
646 
647 static status_t
648 xfs_write_attr_stat(fs_volume *_volume, fs_vnode *_node,
649 	void *cookie, const struct stat *stat, int statMask)
650 {
651 	return B_NOT_SUPPORTED;
652 }
653 
654 
655 static status_t
656 xfs_rename_attr(fs_volume *_volume, fs_vnode *fromVnode,
657 	const char *fromName, fs_vnode *toVnode, const char *toName)
658 {
659 	return B_NOT_SUPPORTED;
660 }
661 
662 
663 static status_t
664 xfs_remove_attr(fs_volume *_volume, fs_vnode *vnode,
665 	const char *name)
666 {
667 	return B_NOT_SUPPORTED;
668 }
669 
670 
671 static uint32
672 xfs_get_supported_operations(partition_data *partition, uint32 mask)
673 {
674 	return B_NOT_SUPPORTED;
675 }
676 
677 
678 static status_t
679 xfs_initialize(int fd, partition_id partitionID, const char *name,
680 	const char *parameterString, off_t partitionSize, disk_job_id job)
681 {
682 	return B_NOT_SUPPORTED;
683 }
684 
685 
686 static status_t
687 xfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize,
688 	uint32 blockSize, disk_job_id job)
689 {
690 	return B_NOT_SUPPORTED;
691 }
692 
693 
694 //	#pragma mark -
695 
696 
697 static status_t
698 xfs_std_ops(int32 op, ...)
699 {
700 	switch (op)
701 	{
702 	case B_MODULE_INIT:
703 #ifdef XFS_DEBUGGER_COMMANDS
704 		// Perform nothing at the moment
705 		// add_debugger_commands();
706 #endif
707 		return B_OK;
708 	case B_MODULE_UNINIT:
709 #ifdef XFS_DEBUGGER_COMMANDS
710 		// Perform nothing at the moment
711 		// remove_debugger_commands();
712 #endif
713 		return B_OK;
714 
715 	default:
716 		return B_ERROR;
717 	}
718 }
719 
720 
721 fs_volume_ops gxfsVolumeOps = {
722 	&xfs_unmount,
723 	&xfs_read_fs_info,
724 	NULL,				// write_fs_info()
725 	NULL,				// fs_sync,
726 	&xfs_get_vnode,
727 };
728 
729 
730 fs_vnode_ops gxfsVnodeOps = {
731 	/* vnode operations */
732 	&xfs_lookup,
733 	NULL,				// xfs_get_vnode_name- optional, and we can't do better
734 						// than the fallback implementation, so leave as NULL.
735 	&xfs_put_vnode,
736 	NULL, 				// xfs_remove_vnode,
737 
738 	/* VM file access */
739 	&xfs_can_page,
740 	&xfs_read_pages,
741 	NULL,				// xfs_write_pages,
742 
743 	&xfs_io,			// io()
744 	NULL,				// cancel_io()
745 
746 	&xfs_get_file_map,
747 
748 	&xfs_ioctl,
749 	NULL,
750 	NULL,				// fs_select
751 	NULL,				// fs_deselect
752 	NULL,				// fs_fsync,
753 
754 	&xfs_read_link,
755 	NULL,				// fs_create_symlink,
756 
757 	NULL,				// fs_link,
758 	&xfs_unlink,
759 	NULL,				// fs_rename,
760 
761 	&xfs_access,
762 	&xfs_read_stat,
763 	NULL,				// fs_write_stat,
764 	NULL,				// fs_preallocate
765 
766 	/* file operations */
767 	NULL,				// fs_create,
768 	&xfs_open,
769 	&xfs_close,
770 	&xfs_free_cookie,
771 	&xfs_read,
772 	NULL,				// fs_write,
773 
774 	/* directory operations */
775 	&xfs_create_dir,
776 	&xfs_remove_dir,
777 	&xfs_open_dir,
778 	&xfs_close_dir,
779 	&xfs_free_dir_cookie,
780 	&xfs_read_dir,
781 	&xfs_rewind_dir,
782 
783 	/* attribute directory operations */
784 	&xfs_open_attr_dir,
785 	&xfs_close_attr_dir,
786 	&xfs_free_attr_dir_cookie,
787 	&xfs_read_attr_dir,
788 	&xfs_rewind_attr_dir,
789 
790 	/* attribute operations */
791 	&xfs_create_attr,
792 	&xfs_open_attr,
793 	&xfs_close_attr,
794 	&xfs_free_attr_cookie,
795 	&xfs_read_attr,
796 	&xfs_write_attr,
797 	&xfs_read_attr_stat,
798 	&xfs_write_attr_stat,
799 	&xfs_rename_attr,
800 	&xfs_remove_attr,
801 };
802 
803 
804 static
805 file_system_module_info sxfsFileSystem = {
806 	{
807 		"file_systems/xfs" B_CURRENT_FS_API_VERSION,
808 		0,
809 		xfs_std_ops,
810 	},
811 
812 	"xfs",				// short_name
813 	"XFS File System",	// pretty_name
814 
815 	// DDM flags
816 	0 |B_DISK_SYSTEM_SUPPORTS_INITIALIZING |B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
817 	//	| B_DISK_SYSTEM_SUPPORTS_WRITING
818 	,
819 
820 	// scanning
821 	xfs_identify_partition,
822 	xfs_scan_partition,
823 	xfs_free_identify_partition_cookie,
824 	NULL,				// free_partition_content_cookie()
825 
826 	&xfs_mount,
827 
828 	/* capability querying operations */
829 	&xfs_get_supported_operations,
830 
831 	NULL,				// validate_resize
832 	NULL,				// validate_move
833 	NULL,				// validate_set_content_name
834 	NULL,				// validate_set_content_parameters
835 	NULL,				// validate_initialize,
836 
837 	/* shadow partition modification */
838 	NULL,				// shadow_changed
839 
840 	/* writing */
841 	NULL,				// defragment
842 	NULL,				// repair
843 	NULL,				// resize
844 	NULL,				// move
845 	NULL,				// set_content_name
846 	NULL,				// set_content_parameters
847 	xfs_initialize,
848 	xfs_uninitialize};
849 
850 
851 module_info *modules[] = {
852 	(module_info *)&sxfsFileSystem,
853 	NULL,
854 };
855