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