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