xref: /haiku/src/add-ons/kernel/file_systems/ntfs/kernel_interface.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*
2  * Copyright 2021, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Augustin Cavalier <waddlesplash>
7  */
8 
9 #include <dirent.h>
10 #include <unistd.h>
11 #include <util/kernel_cpp.h>
12 #include <string.h>
13 
14 #include <AutoDeleter.h>
15 #include <fs_cache.h>
16 #include <fs_info.h>
17 #include <NodeMonitor.h>
18 #include <file_systems/DeviceOpener.h>
19 #include <util/AutoLock.h>
20 
21 #include "ntfs.h"
22 
23 extern "C" {
24 #include "libntfs/bootsect.h"
25 #include "libntfs/dir.h"
26 #include "utils/utils.h"
27 }
28 
29 //#define TRACE_NTFS
30 #ifdef TRACE_NTFS
31 #	define TRACE(X...)	dprintf("ntfs: " X)
32 #else
33 #	define TRACE(X...) ;
34 #endif
35 #define CALLED()		TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
36 #define ERROR(X...)		dprintf("ntfs: error: " X)
37 
38 
39 struct identify_cookie {
40 	NTFS_BOOT_SECTOR boot;
41 };
42 
43 extern "C" int mkntfs_main(const char* devpath, const char* label);
44 
45 typedef CObjectDeleter<ntfs_inode, int, ntfs_inode_close> NtfsInodeCloser;
46 typedef CObjectDeleter<ntfs_attr, void, ntfs_attr_close> NtfsAttrCloser;
47 static status_t fs_access(fs_volume* _volume, fs_vnode* _node, int accessMode);
48 
49 
50 //	#pragma mark - Scanning
51 
52 
53 static float
54 fs_identify_partition(int fd, partition_data* partition, void** _cookie)
55 {
56 	CALLED();
57 
58 	NTFS_BOOT_SECTOR boot;
59 	if (read_pos(fd, 0, (void*)&boot, 512) != 512) {
60 		ERROR("identify_partition: failed to read boot sector\n");
61 		return -1;
62 	}
63 
64 	if (!ntfs_boot_sector_is_ntfs(&boot)) {
65 		ERROR("identify_partition: boot signature doesn't match\n");
66 		return -1;
67 	}
68 
69 	identify_cookie* cookie = new identify_cookie;
70 	if (cookie == NULL) {
71 		ERROR("identify_partition: cookie allocation failed\n");
72 		return -1;
73 	}
74 
75 	memcpy(&cookie->boot, &boot, sizeof(boot));
76 	*_cookie = cookie;
77 
78 	// This value overrides the Intel partition identifier.
79 	return 0.82f;
80 }
81 
82 
83 static status_t
84 fs_scan_partition(int fd, partition_data* partition, void* _cookie)
85 {
86 	CALLED();
87 
88 	identify_cookie *cookie = (identify_cookie*)_cookie;
89 	partition->status = B_PARTITION_VALID;
90 	partition->flags |= B_PARTITION_FILE_SYSTEM;
91 	partition->content_size = sle64_to_cpu(cookie->boot.number_of_sectors)
92 		* le16_to_cpu(cookie->boot.bpb.bytes_per_sector);
93 	partition->block_size = le16_to_cpu(cookie->boot.bpb.bytes_per_sector);
94 
95 	// get volume name
96 	ntfs_volume* ntVolume;
97 	char path[B_PATH_NAME_LENGTH];
98 	if (ioctl(fd, B_GET_PATH_FOR_DEVICE, path) != 0) {
99 		ntVolume = utils_mount_volume(path, NTFS_MNT_RDONLY | NTFS_MNT_RECOVER);
100 		if (ntVolume == NULL)
101 			return errno ? errno : B_ERROR;
102 
103 		if (ntVolume->vol_name != NULL && ntVolume->vol_name[0] != '\0')
104 			partition->content_name = strdup(ntVolume->vol_name);
105 		else
106 			partition->content_name = strdup("");
107 		ntfs_umount(ntVolume, true);
108 	}
109 
110 	return partition->content_name != NULL ? B_OK : B_NO_MEMORY;
111 }
112 
113 
114 static void
115 fs_free_identify_partition_cookie(partition_data* partition, void* _cookie)
116 {
117 	CALLED();
118 
119 	delete (identify_cookie*)_cookie;
120 }
121 
122 
123 //	#pragma mark -
124 
125 
126 static status_t
127 fs_initialize(int fd, partition_id partitionID, const char* name,
128 	const char* parameterString, off_t partitionSize, disk_job_id job)
129 {
130 	TRACE("fs_initialize: '%s', %s\n", name, parameterString);
131 
132 	update_disk_device_job_progress(job, 0);
133 
134 	char path[B_PATH_NAME_LENGTH];
135 	if (ioctl(fd, B_GET_PATH_FOR_DEVICE, path) == 0)
136 		return B_BAD_VALUE;
137 
138 	status_t result = mkntfs_main(path, name);
139 	if (result != 0)
140 		return result;
141 
142 	result = scan_partition(partitionID);
143 	if (result != B_OK)
144 		return result;
145 
146 	update_disk_device_job_progress(job, 1);
147 	return B_OK;
148 }
149 
150 
151 static status_t
152 fs_mount(fs_volume* _volume, const char* device, uint32 flags,
153 	const char* args, ino_t* _rootID)
154 {
155 	CALLED();
156 
157 	volume* volume = new struct volume;
158 	vnode* root = new vnode;
159 	if (volume == NULL || root == NULL)
160 		return B_NO_MEMORY;
161 	ObjectDeleter<struct volume> volumeDeleter(volume);
162 
163 	mutex_init(&volume->lock, "NTFS volume lock");
164 	volume->fs_info_flags = B_FS_IS_PERSISTENT;
165 
166 	unsigned long ntfsFlags = NTFS_MNT_RECOVER | NTFS_MNT_MAY_RDONLY;
167 	if ((flags & B_MOUNT_READ_ONLY) != 0 || DeviceOpener(device, O_RDWR).IsReadOnly())
168 		ntfsFlags |= NTFS_MNT_RDONLY;
169 
170 	// mount
171 	volume->ntfs = utils_mount_volume(device, ntfsFlags);
172 	if (volume->ntfs == NULL)
173 		return errno;
174 
175 	if (NVolReadOnly(volume->ntfs)) {
176 		if ((ntfsFlags & NTFS_MNT_RDONLY) == 0)
177 			ERROR("volume is hibernated, mounted as read-only\n");
178 		volume->fs_info_flags |= B_FS_IS_READONLY;
179 	}
180 
181 	if (ntfs_volume_get_free_space(volume->ntfs) != 0) {
182 		ntfs_umount(volume->ntfs, true);
183 		return B_ERROR;
184 	}
185 
186 	const bool showSystem = false, showHidden = true, hideDot = false;
187 	if (ntfs_set_shown_files(volume->ntfs, showSystem, showHidden, hideDot) != 0) {
188 		ntfs_umount(volume->ntfs, true);
189 		return B_ERROR;
190 	}
191 
192 	// TODO: uid/gid mapping and real permissions
193 
194 	// construct lowntfs_context
195 	volume->lowntfs.haiku_fs_volume = _volume;
196 	volume->lowntfs.current_close_state_vnode = NULL;
197 
198 	volume->lowntfs.vol = volume->ntfs;
199 	volume->ntfs->abs_mnt_point = volume->lowntfs.abs_mnt_point = strdup("");
200 	volume->lowntfs.dmask = 0;
201 	volume->lowntfs.fmask = S_IXUSR | S_IXGRP | S_IXOTH;
202 	volume->lowntfs.dmtime = 0;
203 	volume->lowntfs.special_files = NTFS_FILES_INTERIX;
204 	volume->lowntfs.posix_nlink = 0;
205 	volume->lowntfs.inherit = 0;
206 	volume->lowntfs.windows_names = 1;
207 	volume->lowntfs.latest_ghost = 0;
208 
209 	*_rootID = root->inode = FILE_root;
210 	root->parent_inode = (u64)-1;
211 	root->mode = S_IFDIR | ACCESSPERMS;
212 	root->uid = root->gid = 0;
213 	root->size = 0;
214 
215 	status_t status = publish_vnode(_volume, root->inode, root, &gNtfsVnodeOps, S_IFDIR, 0);
216 	if (status != B_OK) {
217 		ntfs_umount(volume->ntfs, true);
218 		return status;
219 	}
220 
221 	volumeDeleter.Detach();
222 
223 	_volume->private_volume = volume;
224 	_volume->ops = &gNtfsVolumeOps;
225 	return B_OK;
226 }
227 
228 
229 static status_t
230 fs_unmount(fs_volume* _volume)
231 {
232 	CALLED();
233 	volume* volume = (struct volume*)_volume->private_volume;
234 
235 	if (ntfs_umount(volume->ntfs, false) < 0)
236 		return errno;
237 
238 	delete volume;
239 	_volume->private_volume = NULL;
240 
241 	return B_OK;
242 }
243 
244 
245 static status_t
246 fs_read_fs_info(fs_volume* _volume, struct fs_info* info)
247 {
248 	CALLED();
249 	volume* volume = (struct volume*)_volume->private_volume;
250 	MutexLocker lock(volume->lock);
251 
252 	info->flags = volume->fs_info_flags;
253 	info->block_size = volume->ntfs->cluster_size;
254 	info->total_blocks = volume->ntfs->nr_clusters;
255 	info->free_blocks = volume->ntfs->free_clusters;
256 
257 	info->io_size = 65536;
258 
259 	strlcpy(info->volume_name, volume->ntfs->vol_name, sizeof(info->volume_name));
260 	strlcpy(info->fsh_name, "NTFS", sizeof(info->fsh_name));
261 
262 	return B_OK;
263 }
264 
265 
266 static status_t
267 fs_write_fs_info(fs_volume* _volume, const struct fs_info* info, uint32 mask)
268 {
269 	CALLED();
270 	volume* volume = (struct volume*)_volume->private_volume;
271 	MutexLocker lock(volume->lock);
272 
273 	if ((volume->fs_info_flags & B_FS_IS_READONLY) != 0)
274 		return B_READ_ONLY_DEVICE;
275 
276 	status_t status = B_OK;
277 
278 	if ((mask & FS_WRITE_FSINFO_NAME) != 0) {
279 		ntfschar* label = NULL;
280 		int label_len = ntfs_mbstoucs(info->volume_name, &label);
281 		if (label_len <= 0 || label == NULL)
282 			return -1;
283 		MemoryDeleter nameDeleter(label);
284 
285 		if (ntfs_volume_rename(volume->ntfs, label, label_len) != 0)
286 			status = errno;
287 	}
288 
289 	return status;
290 }
291 
292 
293 //	#pragma mark -
294 
295 
296 static status_t
297 fs_init_vnode(fs_volume* _volume, ino_t parent, ino_t nid, vnode** _vnode, bool publish = false)
298 {
299 	volume* volume = (struct volume*)_volume->private_volume;
300 	ASSERT_LOCKED_MUTEX(&volume->lock);
301 
302 	ntfs_inode* ni = ntfs_inode_open(volume->ntfs, nid);
303 	if (ni == NULL)
304 		return ENOENT;
305 	NtfsInodeCloser niCloser(ni);
306 
307 	vnode* node = new vnode;
308 	if (node == NULL)
309 		return B_NO_MEMORY;
310 	ObjectDeleter<vnode> vnodeDeleter(node);
311 
312 	struct stat statbuf;
313 	if (ntfs_fuse_getstat(&volume->lowntfs, NULL, ni, &statbuf) != 0)
314 		return errno;
315 
316 	node->inode = nid;
317 	node->parent_inode = parent;
318 	node->uid = statbuf.st_uid;
319 	node->gid = statbuf.st_gid;
320 	node->mode = statbuf.st_mode;
321 	node->size = statbuf.st_size;
322 
323 	// cache the node's name
324 	char path[B_FILE_NAME_LENGTH];
325 	if (utils_inode_get_name(ni, path, sizeof(path)) == 0)
326 		return B_NO_MEMORY;
327 	node->name = strdup(strrchr(path, '/') + 1);
328 
329 	if (publish) {
330 		status_t status = publish_vnode(_volume, node->inode, node, &gNtfsVnodeOps, node->mode, 0);
331 		if (status != B_OK)
332 			return status;
333 	}
334 
335 	if ((node->mode & S_IFDIR) == 0) {
336 		node->file_cache = file_cache_create(_volume->id, nid, node->size);
337 		if (node->file_cache == NULL)
338 			return B_NO_INIT;
339 	}
340 
341 	vnodeDeleter.Detach();
342 	*_vnode = node;
343 	return B_OK;
344 }
345 
346 
347 static status_t
348 fs_get_vnode(fs_volume* _volume, ino_t nid, fs_vnode* _node, int* _type,
349 	uint32* _flags, bool reenter)
350 {
351 	TRACE("get_vnode %" B_PRIdINO "\n", nid);
352 	volume* volume = (struct volume*)_volume->private_volume;
353 	MutexLocker lock(reenter ? NULL : &volume->lock);
354 
355 	vnode* vnode;
356 	status_t status = fs_init_vnode(_volume, -1 /* set by fs_lookup */, nid, &vnode);
357 	if (status != B_OK)
358 		return status;
359 
360 	_node->private_node = vnode;
361 	_node->ops = &gNtfsVnodeOps;
362 	*_type = vnode->mode;
363 	*_flags = 0;
364 
365 	return B_OK;
366 }
367 
368 
369 static status_t
370 fs_put_vnode(fs_volume* _volume, fs_vnode* _node, bool reenter)
371 {
372 	CALLED();
373 	volume* volume = (struct volume*)_volume->private_volume;
374 	MutexLocker lock(reenter ? NULL : &volume->lock);
375 	vnode* node = (vnode*)_node->private_node;
376 
377 	file_cache_delete(node->file_cache);
378 	delete node;
379 	return B_OK;
380 }
381 
382 
383 static status_t
384 fs_remove_vnode(fs_volume* _volume, fs_vnode* _node, bool reenter)
385 {
386 	CALLED();
387 	volume* volume = (struct volume*)_volume->private_volume;
388 	MutexLocker lock(reenter ? NULL : &volume->lock);
389 	vnode* node = (vnode*)_node->private_node;
390 
391 	if (ntfs_fuse_release(&volume->lowntfs, node->parent_inode, node->inode,
392 			node->lowntfs_close_state, node->lowntfs_ghost) != 0)
393 		return errno;
394 
395 	file_cache_delete(node->file_cache);
396 	delete node;
397 	return B_OK;
398 }
399 
400 
401 int*
402 ntfs_haiku_get_close_state(struct lowntfs_context *ctx, u64 ino)
403 {
404 	if (ctx->current_close_state_vnode != NULL)
405 		panic("NTFS current_close_state_vnode should be NULL!");
406 
407 	vnode* node = NULL;
408 	if (get_vnode((fs_volume*)ctx->haiku_fs_volume, ino, (void**)&node) != B_OK)
409 		return NULL;
410 	ctx->current_close_state_vnode = node;
411 	return &node->lowntfs_close_state;
412 }
413 
414 
415 void
416 ntfs_haiku_put_close_state(struct lowntfs_context *ctx, u64 ino, u64 ghost)
417 {
418 	vnode* node = (vnode*)ctx->current_close_state_vnode;
419 	if (node == NULL)
420 		return;
421 
422 	node->lowntfs_ghost = ghost;
423 	if ((node->lowntfs_close_state & CLOSE_GHOST) != 0) {
424 		fs_volume* _volume = (fs_volume*)ctx->haiku_fs_volume;
425 		entry_cache_remove(_volume->id, node->parent_inode, node->name);
426 		notify_entry_removed(_volume->id, node->parent_inode, node->name, node->inode);
427 		remove_vnode(_volume, node->inode);
428 	}
429 
430 	ctx->current_close_state_vnode = NULL;
431 	put_vnode((fs_volume*)ctx->haiku_fs_volume, node->inode);
432 }
433 
434 
435 static bool
436 fs_can_page(fs_volume* _volume, fs_vnode* _node, void* _cookie)
437 {
438 	return true;
439 }
440 
441 
442 static status_t
443 fs_read_pages(fs_volume* _volume, fs_vnode* _node, void* _cookie,
444 	off_t pos, const iovec* vecs, size_t count, size_t* _numBytes)
445 {
446 	volume* volume = (struct volume*)_volume->private_volume;
447 	MutexLocker lock(volume->lock);
448 	vnode* node = (vnode*)_node->private_node;
449 
450 	TRACE("read_pages inode: %" B_PRIdINO", pos: %" B_PRIdOFF "; vecs: %p; "
451 		"count: %" B_PRIuSIZE "; numBytes: %" B_PRIuSIZE "\n", node->inode, pos,
452 		vecs, count, *_numBytes);
453 
454 	ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
455 	if (ni == NULL)
456 		return B_FILE_ERROR;
457 	NtfsInodeCloser niCloser(ni);
458 
459 	if (pos < 0 || pos >= ni->data_size)
460 		return B_BAD_VALUE;
461 
462 	size_t bytesLeft = min_c(*_numBytes, size_t(ni->data_size - pos));
463 	*_numBytes = 0;
464 	for (size_t i = 0; i < count && bytesLeft > 0; i++) {
465 		const size_t ioSize = min_c(bytesLeft, vecs[i].iov_len);
466 		const int read = ntfs_fuse_read(ni, pos, (char*)vecs[i].iov_base, ioSize);
467 		if (read < 0)
468 			return errno;
469 
470 		pos += read;
471 		*_numBytes += read;
472 		bytesLeft -= read;
473 
474 		if (size_t(read) != ioSize)
475 			return errno;
476 	}
477 
478 	return B_OK;
479 }
480 
481 
482 static status_t
483 fs_write_pages(fs_volume* _volume, fs_vnode* _node, void* _cookie,
484 	off_t pos, const iovec* vecs, size_t count, size_t* _numBytes)
485 {
486 	volume* volume = (struct volume*)_volume->private_volume;
487 	MutexLocker lock(volume->lock);
488 	vnode* node = (vnode*)_node->private_node;
489 
490 	TRACE("write_pages inode: %" B_PRIdINO", pos: %" B_PRIdOFF "; vecs: %p; "
491 		"count: %" B_PRIuSIZE "; numBytes: %" B_PRIuSIZE "\n", node->inode, pos,
492 		vecs, count, *_numBytes);
493 
494 	ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
495 	if (ni == NULL)
496 		return B_FILE_ERROR;
497 	NtfsInodeCloser niCloser(ni);
498 
499 	if (pos < 0 || pos >= ni->data_size)
500 		return B_BAD_VALUE;
501 
502 	size_t bytesLeft = min_c(*_numBytes, size_t(ni->data_size - pos));
503 	*_numBytes = 0;
504 	for (size_t i = 0; i < count && bytesLeft > 0; i++) {
505 		const size_t ioSize = min_c(bytesLeft, vecs[i].iov_len);
506 		const int written = ntfs_fuse_write(&volume->lowntfs, ni, (char*)vecs[i].iov_base, ioSize, pos);
507 		if (written < 0)
508 			return errno;
509 
510 		pos += written;
511 		*_numBytes += written;
512 		bytesLeft -= written;
513 
514 		if (size_t(written) != ioSize)
515 			return errno;
516 	}
517 
518 	return B_OK;
519 }
520 
521 
522 //	#pragma mark -
523 
524 
525 static status_t
526 fs_lookup(fs_volume* _volume, fs_vnode* _directory, const char* name,
527 	ino_t* _vnodeID)
528 {
529 	TRACE("fs_lookup: name address: %p (%s)\n", name, name);
530 	volume* volume = (struct volume*)_volume->private_volume;
531 	MutexLocker lock(volume->lock);
532 	vnode* directory = (vnode*)_directory->private_node;
533 
534 	status_t result;
535 	if (strcmp(name, ".") == 0) {
536 		*_vnodeID = directory->inode;
537 	} else if (strcmp(name, "..") == 0) {
538 		if (directory->inode == FILE_root)
539 			return ENOENT;
540 		*_vnodeID = directory->parent_inode;
541 	} else {
542 		u64 inode = ntfs_fuse_inode_lookup(&volume->lowntfs, directory->inode, name);
543 		if (inode == (u64)-1)
544 			return errno;
545 		*_vnodeID = inode;
546 	}
547 
548 	result = entry_cache_add(_volume->id, directory->inode, name, *_vnodeID);
549 	if (result != B_OK)
550 		return result;
551 
552 	vnode* node = NULL;
553 	result = get_vnode(_volume, *_vnodeID, (void**)&node);
554 	if (result != B_OK)
555 		return result;
556 
557 	if (node->parent_inode == (u64)-1)
558 		node->parent_inode = directory->inode;
559 
560 	TRACE("fs_lookup: ID %" B_PRIdINO "\n", *_vnodeID);
561 	return B_OK;
562 }
563 
564 
565 static status_t
566 fs_get_vnode_name(fs_volume* _volume, fs_vnode* _node, char* buffer, size_t bufferSize)
567 {
568 	// CALLED();
569 	vnode* node = (vnode*)_node->private_node;
570 
571 	if (strlcpy(buffer, node->name, bufferSize) >= bufferSize)
572 		return B_BUFFER_OVERFLOW;
573 	return B_OK;
574 }
575 
576 
577 static status_t
578 fs_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd,
579 	void* buffer, size_t bufferLength)
580 {
581 	// TODO?
582 	return B_DEV_INVALID_IOCTL;
583 }
584 
585 
586 static status_t
587 fs_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
588 {
589 	CALLED();
590 	volume* volume = (struct volume*)_volume->private_volume;
591 	MutexLocker lock(volume->lock);
592 	vnode* node = (vnode*)_node->private_node;
593 
594 	ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
595 	if (ni == NULL)
596 		return errno;
597 	NtfsInodeCloser niCloser(ni);
598 
599 	if (ntfs_fuse_getstat(&volume->lowntfs, NULL, ni, stat) != 0)
600 		return errno;
601 	return B_OK;
602 }
603 
604 
605 static status_t
606 fs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat, uint32 mask)
607 {
608 	CALLED();
609 	volume* volume = (struct volume*)_volume->private_volume;
610 	MutexLocker lock(volume->lock);
611 	vnode* node = (vnode*)_node->private_node;
612 
613 	if ((volume->fs_info_flags & B_FS_IS_READONLY) != 0)
614 		return B_READ_ONLY_DEVICE;
615 
616 	ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
617 	if (ni == NULL)
618 		return B_FILE_ERROR;
619 	NtfsInodeCloser niCloser(ni);
620 
621 	bool updateTime = false;
622 	const uid_t euid = geteuid();
623 
624 	const bool isOwnerOrRoot = (euid == 0 || euid == (uid_t)node->uid);
625 	const bool hasWriteAccess = fs_access(_volume, _node, W_OK);
626 
627 	if ((mask & B_STAT_SIZE) != 0 && node->size != stat->st_size) {
628 		if ((node->mode & S_IFDIR) != 0)
629 			return B_IS_A_DIRECTORY;
630 		if (!hasWriteAccess)
631 			return B_NOT_ALLOWED;
632 
633 		ntfs_attr* na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
634 		if (na == NULL)
635 			return errno;
636 		NtfsAttrCloser naCloser(na);
637 
638 		if (ntfs_attr_truncate(na, stat->st_size) != 0)
639 			return errno;
640 		node->size = na->data_size;
641 		file_cache_set_size(node->file_cache, node->size);
642 
643 		updateTime = true;
644 	}
645 
646 	if ((mask & B_STAT_UID) != 0) {
647 		// only root should be allowed
648 		if (euid != 0)
649 			return B_NOT_ALLOWED;
650 
651 		// We don't support this (yet.)
652 		if (node->uid != stat->st_uid)
653 			return B_UNSUPPORTED;
654 	}
655 
656 	if ((mask & B_STAT_GID) != 0) {
657 		// only the user or root can do that
658 		if (!isOwnerOrRoot)
659 			return B_NOT_ALLOWED;
660 
661 		// We don't support this (yet.)
662 		if (node->gid != stat->st_gid)
663 			return B_UNSUPPORTED;
664 	}
665 
666 	if ((mask & B_STAT_MODE) != 0) {
667 		// only the user or root can do that
668 		if (!isOwnerOrRoot)
669 			return B_NOT_ALLOWED;
670 
671 		// We don't support this (yet.)
672 		if (node->mode != stat->st_mode)
673 			return B_UNSUPPORTED;
674 	}
675 
676 	if ((mask & B_STAT_CREATION_TIME) != 0) {
677 		// the user or root can do that or any user with write access
678 		if (!isOwnerOrRoot && !hasWriteAccess)
679 			return B_NOT_ALLOWED;
680 
681 		ni->creation_time = timespec2ntfs(stat->st_crtim);
682 	}
683 
684 	if ((mask & B_STAT_MODIFICATION_TIME) != 0) {
685 		// the user or root can do that or any user with write access
686 		if (!isOwnerOrRoot && !hasWriteAccess)
687 			return B_NOT_ALLOWED;
688 
689 		ni->last_data_change_time = timespec2ntfs(stat->st_mtim);
690 	}
691 
692 	if ((mask & B_STAT_CHANGE_TIME) != 0 || updateTime) {
693 		// the user or root can do that or any user with write access
694 		if (!isOwnerOrRoot && !hasWriteAccess)
695 			return B_NOT_ALLOWED;
696 
697 		ni->last_mft_change_time = timespec2ntfs(stat->st_ctim);
698 	}
699 
700 	if ((mask & B_STAT_ACCESS_TIME) != 0) {
701 		// the user or root can do that or any user with write access
702 		if (!isOwnerOrRoot && !hasWriteAccess)
703 			return B_NOT_ALLOWED;
704 
705 		ni->last_access_time = timespec2ntfs(stat->st_atim);
706 	}
707 
708 	ntfs_inode_mark_dirty(ni);
709 
710 	notify_stat_changed(_volume->id, node->parent_inode, node->inode, mask);
711 	return B_OK;
712 }
713 
714 
715 static inline int
716 open_mode_to_access(int openMode)
717 {
718 	if ((openMode & O_RWMASK) == O_RDONLY)
719 		return R_OK;
720 	if ((openMode & O_RWMASK) == O_WRONLY)
721 		return W_OK;
722 	if ((openMode & O_RWMASK) == O_RDWR)
723 		return R_OK | W_OK;
724 	return 0;
725 }
726 
727 
728 static status_t
729 fs_generic_create(fs_volume* _volume, vnode* directory, const char* name, int mode,
730 	ino_t* _inode)
731 {
732 	volume* volume = (struct volume*)_volume->private_volume;
733 	ASSERT_LOCKED_MUTEX(&volume->lock);
734 
735 	if ((directory->mode & S_IFDIR) == 0)
736 		return B_BAD_TYPE;
737 
738 	ino_t inode = -1;
739 	if (ntfs_fuse_create(&volume->lowntfs, directory->inode, name, mode & (S_IFMT | 07777),
740 			0, (char*)NULL, &inode) != 0)
741 		return errno;
742 
743 	vnode* node;
744 	status_t status = fs_init_vnode(_volume, directory->inode, inode, &node, true);
745 	if (status != B_OK)
746 		return status;
747 
748 	entry_cache_add(_volume->id, directory->inode, name, inode);
749 	notify_entry_created(_volume->id, directory->inode, name, inode);
750 	*_inode = inode;
751 	return B_OK;
752 }
753 
754 
755 static status_t
756 fs_create(fs_volume* _volume, fs_vnode* _directory, const char* name,
757 	int openMode, int mode, void** _cookie, ino_t* _vnodeID)
758 {
759 	CALLED();
760 	volume* volume = (struct volume*)_volume->private_volume;
761 	MutexLocker lock(volume->lock);
762 	vnode* directory = (vnode*)_directory->private_node;
763 
764 	if ((directory->mode & S_IFDIR) == 0)
765 		return B_NOT_A_DIRECTORY;
766 
767 	status_t status = fs_access(_volume, _directory, W_OK);
768 	if (status != B_OK)
769 		return status;
770 
771 #if 1
772 	if ((openMode & O_NOCACHE) != 0)
773 		return B_UNSUPPORTED;
774 #endif
775 
776 	status = fs_generic_create(_volume, directory, name, S_IFREG | (mode & 07777), _vnodeID);
777 	if (status != B_OK)
778 		return status;
779 
780 	file_cookie* cookie = new file_cookie;
781 	if (cookie == NULL)
782 		return B_NO_MEMORY;
783 	ObjectDeleter<file_cookie> cookieDeleter(cookie);
784 
785 	cookie->open_mode = openMode;
786 
787 	cookieDeleter.Detach();
788 	*_cookie = cookie;
789 	return B_OK;
790 }
791 
792 
793 static status_t
794 fs_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie)
795 {
796 	CALLED();
797 	volume* volume = (struct volume*)_volume->private_volume;
798 	MutexLocker lock(volume->lock);
799 	vnode* node = (vnode*)_node->private_node;
800 
801 	// opening a directory read-only is allowed (but no data can be read)
802 	if ((node->mode & S_IFDIR) != 0 && (openMode & O_RWMASK) != 0)
803 		return B_IS_A_DIRECTORY;
804 	if ((openMode & O_DIRECTORY) != 0 && (node->mode & S_IFDIR) == 0)
805 		return B_NOT_A_DIRECTORY;
806 
807 	status_t status = fs_access(_volume, _node, open_mode_to_access(openMode));
808 	if (status != B_OK)
809 		return status;
810 
811 	ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
812 	if (ni == NULL)
813 		return errno;
814 	NtfsInodeCloser niCloser(ni);
815 
816 	file_cookie* cookie = new file_cookie;
817 	if (cookie == NULL)
818 		return B_NO_MEMORY;
819 	ObjectDeleter<file_cookie> cookieDeleter(cookie);
820 
821 	cookie->open_mode = openMode;
822 
823 	// We don't actually support uncached mode; it would require us to handle
824 	// passing user buffers to libntfs, among other things.
825 #if 0
826 	if ((openMode & O_NOCACHE) != 0 && node->file_cache != NULL) {
827 		status_t status = file_cache_disable(node->file_cache);
828 		if (status != B_OK)
829 			return status;
830 	}
831 #else
832 	if ((openMode & O_NOCACHE) != 0)
833 		return B_UNSUPPORTED;
834 #endif
835 
836 	if ((openMode & O_TRUNC) != 0) {
837 		if ((openMode & O_RWMASK) == O_RDONLY)
838 			return B_NOT_ALLOWED;
839 
840 		ntfs_attr* na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
841 		if (na == NULL)
842 			return errno;
843 		NtfsAttrCloser naCloser(na);
844 
845 		if (ntfs_attr_truncate(na, 0) != 0)
846 			return errno;
847 		node->size = na->data_size;
848 		file_cache_set_size(node->file_cache, node->size);
849 	}
850 
851 	cookieDeleter.Detach();
852 	*_cookie = cookie;
853 	return B_OK;
854 }
855 
856 
857 static status_t
858 fs_read(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
859 	void* buffer, size_t* length)
860 {
861 	vnode* node = (vnode*)_node->private_node;
862 	file_cookie* cookie = (file_cookie*)_cookie;
863 
864 	if ((node->mode & S_IFDIR) != 0)
865 		return B_IS_A_DIRECTORY;
866 
867 	ASSERT((cookie->open_mode & O_RWMASK) == O_RDONLY || (cookie->open_mode & O_RDWR) != 0);
868 
869 	return file_cache_read(node->file_cache, cookie, pos, buffer, length);
870 }
871 
872 
873 static status_t
874 fs_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
875 	const void* buffer, size_t* _length)
876 {
877 	CALLED();
878 	volume* volume = (struct volume*)_volume->private_volume;
879 	MutexLocker lock(volume->lock);
880 	vnode* node = (vnode*)_node->private_node;
881 	file_cookie* cookie = (file_cookie*)_cookie;
882 
883 	if ((node->mode & S_IFDIR) != 0)
884 		return B_IS_A_DIRECTORY;
885 
886 	ASSERT((cookie->open_mode & O_WRONLY) != 0 || (cookie->open_mode & O_RDWR) != 0);
887 
888 	if (cookie->open_mode & O_APPEND)
889 		pos = node->size;
890 	if (pos < 0)
891 		return B_BAD_VALUE;
892 
893 	if (pos + s64(*_length) > node->size) {
894 		ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
895 		if (ni == NULL)
896 			return errno;
897 		NtfsInodeCloser niCloser(ni);
898 
899 		ntfs_attr* na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
900 		if (na == NULL)
901 			return errno;
902 		NtfsAttrCloser naCloser(na);
903 
904 		if (ntfs_attr_truncate(na, pos + *_length) != 0)
905 			return errno;
906 		node->size = na->data_size;
907 		file_cache_set_size(node->file_cache, node->size);
908 	}
909 
910 	lock.Unlock();
911 
912 	status_t status = file_cache_write(node->file_cache, cookie, pos, buffer, _length);
913 	if (status != B_OK)
914 		return status;
915 
916 	lock.Lock();
917 
918 	// periodically notify if the file size has changed
919 	if ((node->lowntfs_close_state & CLOSE_GHOST) == 0
920 			&& cookie->last_size != node->size
921 			&& system_time() > cookie->last_notification + INODE_NOTIFICATION_INTERVAL) {
922 		notify_stat_changed(_volume->id, node->parent_inode, node->inode,
923 			B_STAT_MODIFICATION_TIME | B_STAT_SIZE | B_STAT_INTERIM_UPDATE);
924 		cookie->last_size = node->size;
925 		cookie->last_notification = system_time();
926 	}
927 	return status;
928 }
929 
930 
931 static status_t
932 fs_fsync(fs_volume* _volume, fs_vnode* _node)
933 {
934 	CALLED();
935 	vnode* node = (vnode*)_node->private_node;
936 
937 	return file_cache_sync(node->file_cache);
938 }
939 
940 
941 static status_t
942 fs_close(fs_volume *_volume, fs_vnode *_node, void *_cookie)
943 {
944 	CALLED();
945 
946 	// Nothing to do.
947 	return B_OK;
948 }
949 
950 
951 static status_t
952 fs_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
953 {
954 	file_cookie* cookie = (file_cookie*)_cookie;
955 	delete cookie;
956 	return B_OK;
957 }
958 
959 
960 static status_t
961 fs_generic_unlink(fs_volume* _volume, fs_vnode* _directory, const char* name, RM_TYPES type)
962 {
963 	volume* volume = (struct volume*)_volume->private_volume;
964 	MutexLocker lock(volume->lock);
965 	vnode* directory = (vnode*)_directory->private_node;
966 
967 	status_t status = fs_access(_volume, _directory, W_OK);
968 	if (status != B_OK)
969 		return status;
970 
971 	if (ntfs_fuse_rm(&volume->lowntfs, directory->inode, name, type) != 0)
972 		return errno;
973 
974 	// remove_vnode() et al. will be called by put_close_state.
975 	return B_OK;
976 }
977 
978 
979 static status_t
980 fs_unlink(fs_volume* _volume, fs_vnode* _directory, const char* name)
981 {
982 	CALLED();
983 	return fs_generic_unlink(_volume, _directory, name, RM_LINK);
984 }
985 
986 
987 static status_t
988 fs_rename(fs_volume* _volume, fs_vnode* _oldDir, const char* oldName,
989 	fs_vnode* _newDir, const char* newName)
990 {
991 	CALLED();
992 	volume* volume = (struct volume*)_volume->private_volume;
993 	MutexLocker lock(volume->lock);
994 
995 	vnode* old_directory = (vnode*)_oldDir->private_node;
996 	vnode* new_directory = (vnode*)_newDir->private_node;
997 
998 	if (old_directory == new_directory && strcmp(oldName, newName) == 0)
999 		return B_OK;
1000 
1001 	status_t status = fs_access(_volume, _oldDir, W_OK);
1002 	if (status == B_OK)
1003 		status = fs_access(_volume, _newDir, W_OK);
1004 	if (status != B_OK)
1005 		return status;
1006 
1007 	// Prevent moving a directory into one of its own children.
1008 	if (old_directory != new_directory) {
1009 		u64 oldIno = ntfs_fuse_inode_lookup(&volume->lowntfs, old_directory->inode, oldName);
1010 		if (oldIno == (u64)-1)
1011 			return B_ENTRY_NOT_FOUND;
1012 
1013 		ino_t parent = new_directory->inode;
1014 		const ino_t root = FILE_root;
1015 
1016 		while (true) {
1017 			if (parent == oldIno)
1018 				return B_BAD_VALUE;
1019 			else if (parent == root || parent == old_directory->inode)
1020 				break;
1021 
1022 			vnode* parentNode;
1023 			if (get_vnode(_volume, parent, (void**)&parentNode) != B_OK)
1024 				return B_ERROR;
1025 
1026 			parent = parentNode->parent_inode;
1027 			put_vnode(_volume, parentNode->inode);
1028 		}
1029 	}
1030 
1031 	if (ntfs_fuse_rename(&volume->lowntfs, old_directory->inode, oldName,
1032 			new_directory->inode, newName) != 0)
1033 		return errno;
1034 
1035 	u64 ino = ntfs_fuse_inode_lookup(&volume->lowntfs, new_directory->inode, newName);
1036 	if (ino == (u64)-1)
1037 		return B_ENTRY_NOT_FOUND;
1038 
1039 	vnode* node;
1040 	status = get_vnode(_volume, ino, (void**)&node);
1041 	if (status != B_OK)
1042 		return status;
1043 
1044 	free(node->name);
1045 	node->name = strdup(newName);
1046 	node->parent_inode = new_directory->inode;
1047 
1048 	if ((node->mode & S_IFDIR) != 0)
1049 		entry_cache_add(_volume->id, ino, "..", new_directory->inode);
1050 
1051 	put_vnode(_volume, ino);
1052 
1053 	entry_cache_remove(_volume->id, old_directory->inode, oldName);
1054 	entry_cache_add(_volume->id, new_directory->inode, newName, ino);
1055 	notify_entry_moved(_volume->id, old_directory->inode, oldName,
1056 		new_directory->inode, newName, ino);
1057 
1058 	return B_OK;
1059 }
1060 
1061 
1062 static status_t
1063 fs_access(fs_volume* _volume, fs_vnode* _node, int accessMode)
1064 {
1065 	// CALLED();
1066 	volume* volume = (struct volume*)_volume->private_volume;
1067 	vnode* node = (vnode*)_node->private_node;
1068 
1069 	if ((accessMode & W_OK) != 0 && (volume->fs_info_flags & B_FS_IS_READONLY) != 0)
1070 		return B_READ_ONLY_DEVICE;
1071 
1072 	return check_access_permissions(accessMode, node->mode, node->gid, node->uid);
1073 }
1074 
1075 
1076 static status_t
1077 fs_read_link(fs_volume* _volume, fs_vnode* _node, char* buffer, size_t* bufferSize)
1078 {
1079 	CALLED();
1080 	volume* volume = (struct volume*)_volume->private_volume;
1081 	MutexLocker lock(volume->lock);
1082 	vnode* node = (vnode*)_node->private_node;
1083 
1084 	if (ntfs_fuse_readlink(&volume->lowntfs, node->inode, buffer, bufferSize) != 0)
1085 		return errno;
1086 	return B_OK;
1087 }
1088 
1089 
1090 //	#pragma mark - Directory functions
1091 
1092 
1093 static status_t
1094 fs_create_dir(fs_volume* _volume, fs_vnode* _directory, const char* name, int mode)
1095 {
1096 	CALLED();
1097 	volume* volume = (struct volume*)_volume->private_volume;
1098 	MutexLocker lock(volume->lock);
1099 	vnode* directory = (vnode*)_directory->private_node;
1100 
1101 	status_t status = fs_access(_volume, _directory, W_OK);
1102 	if (status != B_OK)
1103 		return status;
1104 
1105 	ino_t inode = -1;
1106 	status = fs_generic_create(_volume, directory, name, S_IFDIR | (mode & 07777), &inode);
1107 	if (status != B_OK)
1108 		return status;
1109 
1110 	return B_OK;
1111 }
1112 
1113 
1114 static status_t
1115 fs_remove_dir(fs_volume* _volume, fs_vnode* _directory, const char* name)
1116 {
1117 	CALLED();
1118 	ino_t directory_inode = ((vnode*)_directory->private_node)->inode;
1119 	status_t status = fs_generic_unlink(_volume, _directory, name, RM_DIR);
1120 	if (status != B_OK)
1121 		return status;
1122 
1123 	entry_cache_remove(_volume->id, directory_inode, "..");
1124 	return B_OK;
1125 }
1126 
1127 
1128 static status_t
1129 fs_open_dir(fs_volume* _volume, fs_vnode* _node, void** _cookie)
1130 {
1131 	CALLED();
1132 	vnode* node = (vnode*)_node->private_node;
1133 
1134 	status_t status = fs_access(_volume, _node, R_OK);
1135 	if (status != B_OK)
1136 		return status;
1137 
1138 	if ((node->mode & S_IFDIR) == 0)
1139 		return B_NOT_A_DIRECTORY;
1140 
1141 	directory_cookie* cookie = new directory_cookie;
1142 	if (cookie == NULL)
1143 		return B_NO_MEMORY;
1144 
1145 	cookie->first = cookie->current = NULL;
1146 	*_cookie = (void*)cookie;
1147 	return B_OK;
1148 }
1149 
1150 
1151 static int
1152 _ntfs_readdir_callback(void* _cookie, const ntfschar* ntfs_name, const int ntfs_name_len,
1153 	const int name_type, const s64 pos, const MFT_REF mref, const unsigned dt_type)
1154 {
1155 	if (name_type == FILE_NAME_DOS)
1156 		return 0;
1157 
1158 	directory_cookie* cookie = (directory_cookie*)_cookie;
1159 
1160 	char* name = NULL;
1161 	int name_len = ntfs_ucstombs(ntfs_name, ntfs_name_len, &name, 0);
1162 	if (name_len <= 0 || name == NULL)
1163 		return -1;
1164 	MemoryDeleter nameDeleter(name);
1165 
1166 	directory_cookie::entry* entry =
1167 		(directory_cookie::entry*)malloc(sizeof(directory_cookie::entry) + name_len);
1168 	if (entry == NULL)
1169 		return -1;
1170 	entry->next = NULL;
1171 
1172 	entry->inode = MREF(mref);
1173 	entry->name_length = name_len;
1174 	memcpy(entry->name, name, name_len + 1);
1175 
1176 	if (cookie->first == NULL) {
1177 		cookie->first = cookie->current = entry;
1178 	} else {
1179 		cookie->current->next = entry;
1180 		cookie->current = entry;
1181 	}
1182 
1183 	return 0;
1184 }
1185 
1186 
1187 static status_t
1188 fs_read_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie,
1189 	struct dirent* dirent, size_t bufferSize, uint32* _num)
1190 {
1191 	CALLED();
1192 	directory_cookie* cookie = (directory_cookie*)_cookie;
1193 
1194 	// TODO: While lowntfs-3g seems to also read the entire directory at once into memory,
1195 	// we could optimize things here by storing the data in the vnode, not the inode, and
1196 	// only freeing it after some period of inactivity.
1197 
1198 	// See if we need to read the directory ourselves first.
1199 	if (cookie->first == NULL) {
1200 		volume* volume = (struct volume*)_volume->private_volume;
1201 		MutexLocker lock(volume->lock);
1202 		vnode* node = (vnode*)_node->private_node;
1203 
1204 		ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
1205 		if (ni == NULL)
1206 			return errno;
1207 		NtfsInodeCloser niCloser(ni);
1208 
1209 		s64 pos = 0;
1210 		if (ntfs_readdir(ni, &pos, cookie, _ntfs_readdir_callback) != 0)
1211 			return errno;
1212 		cookie->current = cookie->first;
1213 	}
1214 	if (cookie->first == NULL)
1215 		return ENOENT;
1216 	if (cookie->current == NULL) {
1217 		*_num = 0;
1218 		return B_OK;
1219 	}
1220 
1221 	uint32 maxCount = *_num;
1222 	uint32 count = 0;
1223 	while (count < maxCount && bufferSize > sizeof(struct dirent)) {
1224 		size_t length = bufferSize - offsetof(struct dirent, d_name);
1225 		if (length < cookie->current->name_length) {
1226 			// the remaining name buffer length is too small
1227 			if (count == 0)
1228 				return B_BUFFER_OVERFLOW;
1229 			break;
1230 		}
1231 		length = cookie->current->name_length;
1232 
1233 		dirent->d_dev = _volume->id;
1234 		dirent->d_ino = cookie->current->inode;
1235 		strlcpy(dirent->d_name, cookie->current->name, length + 1);
1236 		dirent->d_reclen = offsetof(struct dirent, d_name) + length + 1;
1237 
1238 		bufferSize -= dirent->d_reclen;
1239 		dirent = (struct dirent*)((uint8*)dirent + dirent->d_reclen);
1240 		count++;
1241 
1242 		cookie->current = cookie->current->next;
1243 		if (cookie->current == NULL)
1244 			break;
1245 	}
1246 
1247 	*_num = count;
1248 	return B_OK;
1249 }
1250 
1251 
1252 static status_t
1253 fs_rewind_dir(fs_volume* /*_volume*/, fs_vnode* /*node*/, void *_cookie)
1254 {
1255 	CALLED();
1256 	directory_cookie* cookie = (directory_cookie*)_cookie;
1257 	cookie->current = cookie->first;
1258 	return B_OK;
1259 }
1260 
1261 
1262 static status_t
1263 fs_close_dir(fs_volume* /*_volume*/, fs_vnode* /*node*/, void* /*_cookie*/)
1264 {
1265 	return B_OK;
1266 }
1267 
1268 
1269 static status_t
1270 fs_free_dir_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
1271 {
1272 	CALLED();
1273 	directory_cookie* cookie = (directory_cookie*)_cookie;
1274 	if (cookie == NULL)
1275 		return B_OK;
1276 
1277 	// Free entries.
1278 	cookie->current = cookie->first;
1279 	while (cookie->current != NULL) {
1280 		directory_cookie::entry* next = cookie->current->next;
1281 		free(cookie->current);
1282 		cookie->current = next;
1283 	}
1284 
1285 	delete cookie;
1286 	return B_OK;
1287 }
1288 
1289 
1290 fs_volume_ops gNtfsVolumeOps = {
1291 	&fs_unmount,
1292 	&fs_read_fs_info,
1293 	&fs_write_fs_info,
1294 	NULL,	// fs_sync,
1295 	&fs_get_vnode,
1296 };
1297 
1298 
1299 fs_vnode_ops gNtfsVnodeOps = {
1300 	/* vnode operations */
1301 	&fs_lookup,
1302 	&fs_get_vnode_name,
1303 	&fs_put_vnode,
1304 	&fs_remove_vnode,
1305 
1306 	/* VM file access */
1307 	&fs_can_page,
1308 	&fs_read_pages,
1309 	&fs_write_pages,
1310 
1311 	NULL,	// io
1312 	NULL,	// cancel_io
1313 
1314 	NULL,	// get_file_map
1315 
1316 	&fs_ioctl,
1317 	NULL,
1318 	NULL,	// fs_select
1319 	NULL,	// fs_deselect
1320 	&fs_fsync,
1321 
1322 	&fs_read_link,
1323 	NULL,	// fs_create_symlink
1324 
1325 	NULL,	// fs_link,
1326 	&fs_unlink,
1327 	&fs_rename,
1328 
1329 	&fs_access,
1330 	&fs_read_stat,
1331 	&fs_write_stat,
1332 	NULL,	// fs_preallocate
1333 
1334 	/* file operations */
1335 	&fs_create,
1336 	&fs_open,
1337 	&fs_close,
1338 	&fs_free_cookie,
1339 	&fs_read,
1340 	&fs_write,
1341 
1342 	/* directory operations */
1343 	&fs_create_dir,
1344 	&fs_remove_dir,
1345 	&fs_open_dir,
1346 	&fs_close_dir,
1347 	&fs_free_dir_cookie,
1348 	&fs_read_dir,
1349 	&fs_rewind_dir,
1350 
1351 	/* attribute directory operations */
1352 	NULL, 	// fs_open_attr_dir,
1353 	NULL,	// fs_close_attr_dir,
1354 	NULL,	// fs_free_attr_dir_cookie,
1355 	NULL,	// fs_read_attr_dir,
1356 	NULL,	// fs_rewind_attr_dir,
1357 
1358 	/* attribute operations */
1359 	NULL,	// fs_create_attr,
1360 	NULL,	// fs_open_attr,
1361 	NULL,	// fs_close_attr,
1362 	NULL,	// fs_free_attr_cookie,
1363 	NULL,	// fs_read_attr,
1364 	NULL,	// fs_write_attr,
1365 	NULL,	// fs_read_attr_stat,
1366 	NULL,	// fs_write_attr_stat,
1367 	NULL,	// fs_rename_attr,
1368 	NULL,	// fs_remove_attr,
1369 };
1370 
1371 
1372 static file_system_module_info sNtfsFileSystem = {
1373 	{
1374 		"file_systems/ntfs" B_CURRENT_FS_API_VERSION,
1375 		0,
1376 		NULL,
1377 	},
1378 
1379 	"ntfs",							// short_name
1380 	"NT File System",				// pretty_name
1381 
1382 	// DDM flags
1383 	0
1384 	| B_DISK_SYSTEM_IS_FILE_SYSTEM
1385 	| B_DISK_SYSTEM_SUPPORTS_INITIALIZING
1386 	| B_DISK_SYSTEM_SUPPORTS_WRITING
1387 	,
1388 
1389 	// scanning
1390 	fs_identify_partition,
1391 	fs_scan_partition,
1392 	fs_free_identify_partition_cookie,
1393 	NULL,	// free_partition_content_cookie()
1394 
1395 	&fs_mount,
1396 
1397 	// capability querying operations
1398 	NULL,	// get_supported_operations
1399 
1400 	NULL,	// validate_resize
1401 	NULL,	// validate_move
1402 	NULL,	// validate_set_content_name
1403 	NULL,	// validate_set_content_parameters
1404 	NULL,	// validate_initialize,
1405 
1406 	/* shadow partition modification */
1407 	NULL,	// shadow_changed
1408 
1409 	/* writing */
1410 	NULL,	// defragment
1411 	NULL,	// repair
1412 	NULL,	// resize
1413 	NULL,	// move
1414 	NULL,	// set_content_name
1415 	NULL,	// set_content_parameters
1416 	fs_initialize,
1417 	NULL	// uninitialize
1418 };
1419 
1420 
1421 module_info *modules[] = {
1422 	(module_info *)&sNtfsFileSystem,
1423 	NULL,
1424 };
1425