13fbe39e1SAugustin Cavalier /*
23fbe39e1SAugustin Cavalier * Copyright 2021, Haiku, Inc. All rights reserved.
33fbe39e1SAugustin Cavalier * Distributed under the terms of the MIT License.
43fbe39e1SAugustin Cavalier *
53fbe39e1SAugustin Cavalier * Authors:
63fbe39e1SAugustin Cavalier * Augustin Cavalier <waddlesplash>
73fbe39e1SAugustin Cavalier */
83fbe39e1SAugustin Cavalier
93fbe39e1SAugustin Cavalier #include <dirent.h>
103fbe39e1SAugustin Cavalier #include <unistd.h>
113fbe39e1SAugustin Cavalier #include <util/kernel_cpp.h>
123fbe39e1SAugustin Cavalier #include <string.h>
133fbe39e1SAugustin Cavalier
143fbe39e1SAugustin Cavalier #include <AutoDeleter.h>
153fbe39e1SAugustin Cavalier #include <fs_cache.h>
163fbe39e1SAugustin Cavalier #include <fs_info.h>
178b018d9aSAugustin Cavalier #include <vfs.h>
185070f597SAugustin Cavalier #include <NodeMonitor.h>
193fbe39e1SAugustin Cavalier #include <file_systems/DeviceOpener.h>
203c1cf7b2SAugustin Cavalier #include <file_systems/fs_ops_support.h>
213fbe39e1SAugustin Cavalier #include <util/AutoLock.h>
223fbe39e1SAugustin Cavalier
233fbe39e1SAugustin Cavalier #include "ntfs.h"
243fbe39e1SAugustin Cavalier
253fbe39e1SAugustin Cavalier extern "C" {
263fbe39e1SAugustin Cavalier #include "libntfs/bootsect.h"
273fbe39e1SAugustin Cavalier #include "libntfs/dir.h"
283fbe39e1SAugustin Cavalier #include "utils/utils.h"
293fbe39e1SAugustin Cavalier }
303fbe39e1SAugustin Cavalier
313fbe39e1SAugustin Cavalier //#define TRACE_NTFS
323fbe39e1SAugustin Cavalier #ifdef TRACE_NTFS
333fbe39e1SAugustin Cavalier # define TRACE(X...) dprintf("ntfs: " X)
343fbe39e1SAugustin Cavalier #else
353fbe39e1SAugustin Cavalier # define TRACE(X...) ;
363fbe39e1SAugustin Cavalier #endif
373fbe39e1SAugustin Cavalier #define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
383fbe39e1SAugustin Cavalier #define ERROR(X...) dprintf("ntfs: error: " X)
393fbe39e1SAugustin Cavalier
403fbe39e1SAugustin Cavalier
413fbe39e1SAugustin Cavalier struct identify_cookie {
423fbe39e1SAugustin Cavalier NTFS_BOOT_SECTOR boot;
433fbe39e1SAugustin Cavalier };
443fbe39e1SAugustin Cavalier
455070f597SAugustin Cavalier extern "C" int mkntfs_main(const char* devpath, const char* label);
465070f597SAugustin Cavalier
473fbe39e1SAugustin Cavalier typedef CObjectDeleter<ntfs_inode, int, ntfs_inode_close> NtfsInodeCloser;
485070f597SAugustin Cavalier typedef CObjectDeleter<ntfs_attr, void, ntfs_attr_close> NtfsAttrCloser;
493fbe39e1SAugustin Cavalier static status_t fs_access(fs_volume* _volume, fs_vnode* _node, int accessMode);
503fbe39e1SAugustin Cavalier
513fbe39e1SAugustin Cavalier
523fbe39e1SAugustin Cavalier // #pragma mark - Scanning
533fbe39e1SAugustin Cavalier
543fbe39e1SAugustin Cavalier
553fbe39e1SAugustin Cavalier static float
fs_identify_partition(int fd,partition_data * partition,void ** _cookie)563fbe39e1SAugustin Cavalier fs_identify_partition(int fd, partition_data* partition, void** _cookie)
573fbe39e1SAugustin Cavalier {
583fbe39e1SAugustin Cavalier CALLED();
593fbe39e1SAugustin Cavalier
603fbe39e1SAugustin Cavalier NTFS_BOOT_SECTOR boot;
613fbe39e1SAugustin Cavalier if (read_pos(fd, 0, (void*)&boot, 512) != 512) {
623fbe39e1SAugustin Cavalier ERROR("identify_partition: failed to read boot sector\n");
633fbe39e1SAugustin Cavalier return -1;
643fbe39e1SAugustin Cavalier }
653fbe39e1SAugustin Cavalier
663fbe39e1SAugustin Cavalier if (!ntfs_boot_sector_is_ntfs(&boot)) {
673fbe39e1SAugustin Cavalier ERROR("identify_partition: boot signature doesn't match\n");
683fbe39e1SAugustin Cavalier return -1;
693fbe39e1SAugustin Cavalier }
703fbe39e1SAugustin Cavalier
713fbe39e1SAugustin Cavalier identify_cookie* cookie = new identify_cookie;
723fbe39e1SAugustin Cavalier if (cookie == NULL) {
733fbe39e1SAugustin Cavalier ERROR("identify_partition: cookie allocation failed\n");
743fbe39e1SAugustin Cavalier return -1;
753fbe39e1SAugustin Cavalier }
763fbe39e1SAugustin Cavalier
773fbe39e1SAugustin Cavalier memcpy(&cookie->boot, &boot, sizeof(boot));
783fbe39e1SAugustin Cavalier *_cookie = cookie;
793fbe39e1SAugustin Cavalier
803fbe39e1SAugustin Cavalier // This value overrides the Intel partition identifier.
813fbe39e1SAugustin Cavalier return 0.82f;
823fbe39e1SAugustin Cavalier }
833fbe39e1SAugustin Cavalier
843fbe39e1SAugustin Cavalier
853fbe39e1SAugustin Cavalier static status_t
fs_scan_partition(int fd,partition_data * partition,void * _cookie)863fbe39e1SAugustin Cavalier fs_scan_partition(int fd, partition_data* partition, void* _cookie)
873fbe39e1SAugustin Cavalier {
883fbe39e1SAugustin Cavalier CALLED();
893fbe39e1SAugustin Cavalier
903fbe39e1SAugustin Cavalier identify_cookie *cookie = (identify_cookie*)_cookie;
913fbe39e1SAugustin Cavalier partition->status = B_PARTITION_VALID;
923fbe39e1SAugustin Cavalier partition->flags |= B_PARTITION_FILE_SYSTEM;
933fbe39e1SAugustin Cavalier partition->content_size = sle64_to_cpu(cookie->boot.number_of_sectors)
943fbe39e1SAugustin Cavalier * le16_to_cpu(cookie->boot.bpb.bytes_per_sector);
953fbe39e1SAugustin Cavalier partition->block_size = le16_to_cpu(cookie->boot.bpb.bytes_per_sector);
963fbe39e1SAugustin Cavalier
973fbe39e1SAugustin Cavalier // get volume name
983fbe39e1SAugustin Cavalier ntfs_volume* ntVolume;
993fbe39e1SAugustin Cavalier char path[B_PATH_NAME_LENGTH];
1003fbe39e1SAugustin Cavalier if (ioctl(fd, B_GET_PATH_FOR_DEVICE, path) != 0) {
1013fbe39e1SAugustin Cavalier ntVolume = utils_mount_volume(path, NTFS_MNT_RDONLY | NTFS_MNT_RECOVER);
102a8261652SAugustin Cavalier if (ntVolume == NULL)
103a8261652SAugustin Cavalier return errno ? errno : B_ERROR;
104a8261652SAugustin Cavalier
1053fbe39e1SAugustin Cavalier if (ntVolume->vol_name != NULL && ntVolume->vol_name[0] != '\0')
1063fbe39e1SAugustin Cavalier partition->content_name = strdup(ntVolume->vol_name);
107a8261652SAugustin Cavalier else
108a8261652SAugustin Cavalier partition->content_name = strdup("");
1093fbe39e1SAugustin Cavalier ntfs_umount(ntVolume, true);
1103fbe39e1SAugustin Cavalier }
1113fbe39e1SAugustin Cavalier
1123fbe39e1SAugustin Cavalier return partition->content_name != NULL ? B_OK : B_NO_MEMORY;
1133fbe39e1SAugustin Cavalier }
1143fbe39e1SAugustin Cavalier
1153fbe39e1SAugustin Cavalier
1163fbe39e1SAugustin Cavalier static void
fs_free_identify_partition_cookie(partition_data * partition,void * _cookie)1173fbe39e1SAugustin Cavalier fs_free_identify_partition_cookie(partition_data* partition, void* _cookie)
1183fbe39e1SAugustin Cavalier {
1193fbe39e1SAugustin Cavalier CALLED();
1203fbe39e1SAugustin Cavalier
1213fbe39e1SAugustin Cavalier delete (identify_cookie*)_cookie;
1223fbe39e1SAugustin Cavalier }
1233fbe39e1SAugustin Cavalier
1243fbe39e1SAugustin Cavalier
1253fbe39e1SAugustin Cavalier // #pragma mark -
1263fbe39e1SAugustin Cavalier
1273fbe39e1SAugustin Cavalier
1283fbe39e1SAugustin Cavalier static status_t
fs_initialize(int fd,partition_id partitionID,const char * name,const char * parameterString,off_t partitionSize,disk_job_id job)1295070f597SAugustin Cavalier fs_initialize(int fd, partition_id partitionID, const char* name,
1305070f597SAugustin Cavalier const char* parameterString, off_t partitionSize, disk_job_id job)
1315070f597SAugustin Cavalier {
1325070f597SAugustin Cavalier TRACE("fs_initialize: '%s', %s\n", name, parameterString);
1335070f597SAugustin Cavalier
1345070f597SAugustin Cavalier update_disk_device_job_progress(job, 0);
1355070f597SAugustin Cavalier
1365070f597SAugustin Cavalier char path[B_PATH_NAME_LENGTH];
1375070f597SAugustin Cavalier if (ioctl(fd, B_GET_PATH_FOR_DEVICE, path) == 0)
1385070f597SAugustin Cavalier return B_BAD_VALUE;
1395070f597SAugustin Cavalier
1405070f597SAugustin Cavalier status_t result = mkntfs_main(path, name);
1415070f597SAugustin Cavalier if (result != 0)
1425070f597SAugustin Cavalier return result;
1435070f597SAugustin Cavalier
1445070f597SAugustin Cavalier result = scan_partition(partitionID);
1455070f597SAugustin Cavalier if (result != B_OK)
1465070f597SAugustin Cavalier return result;
1475070f597SAugustin Cavalier
1485070f597SAugustin Cavalier update_disk_device_job_progress(job, 1);
1495070f597SAugustin Cavalier return B_OK;
1505070f597SAugustin Cavalier }
1515070f597SAugustin Cavalier
1525070f597SAugustin Cavalier
1535070f597SAugustin Cavalier static status_t
fs_mount(fs_volume * _volume,const char * device,uint32 flags,const char * args,ino_t * _rootID)1543fbe39e1SAugustin Cavalier fs_mount(fs_volume* _volume, const char* device, uint32 flags,
1553fbe39e1SAugustin Cavalier const char* args, ino_t* _rootID)
1563fbe39e1SAugustin Cavalier {
1573fbe39e1SAugustin Cavalier CALLED();
1583fbe39e1SAugustin Cavalier
1593fbe39e1SAugustin Cavalier volume* volume = new struct volume;
1603fbe39e1SAugustin Cavalier vnode* root = new vnode;
1613fbe39e1SAugustin Cavalier if (volume == NULL || root == NULL)
1623fbe39e1SAugustin Cavalier return B_NO_MEMORY;
1633fbe39e1SAugustin Cavalier ObjectDeleter<struct volume> volumeDeleter(volume);
1643fbe39e1SAugustin Cavalier
1653fbe39e1SAugustin Cavalier mutex_init(&volume->lock, "NTFS volume lock");
1663fbe39e1SAugustin Cavalier volume->fs_info_flags = B_FS_IS_PERSISTENT;
1673fbe39e1SAugustin Cavalier
1683fbe39e1SAugustin Cavalier unsigned long ntfsFlags = NTFS_MNT_RECOVER | NTFS_MNT_MAY_RDONLY;
1693fbe39e1SAugustin Cavalier if ((flags & B_MOUNT_READ_ONLY) != 0 || DeviceOpener(device, O_RDWR).IsReadOnly())
1703fbe39e1SAugustin Cavalier ntfsFlags |= NTFS_MNT_RDONLY;
1713fbe39e1SAugustin Cavalier
1723fbe39e1SAugustin Cavalier // mount
1733fbe39e1SAugustin Cavalier volume->ntfs = utils_mount_volume(device, ntfsFlags);
1743fbe39e1SAugustin Cavalier if (volume->ntfs == NULL)
1753fbe39e1SAugustin Cavalier return errno;
1763fbe39e1SAugustin Cavalier
1775070f597SAugustin Cavalier if (NVolReadOnly(volume->ntfs)) {
1785070f597SAugustin Cavalier if ((ntfsFlags & NTFS_MNT_RDONLY) == 0)
1795070f597SAugustin Cavalier ERROR("volume is hibernated, mounted as read-only\n");
1803fbe39e1SAugustin Cavalier volume->fs_info_flags |= B_FS_IS_READONLY;
1815070f597SAugustin Cavalier }
1823fbe39e1SAugustin Cavalier
1833fbe39e1SAugustin Cavalier if (ntfs_volume_get_free_space(volume->ntfs) != 0) {
1843fbe39e1SAugustin Cavalier ntfs_umount(volume->ntfs, true);
1853fbe39e1SAugustin Cavalier return B_ERROR;
1863fbe39e1SAugustin Cavalier }
1873fbe39e1SAugustin Cavalier
1883fbe39e1SAugustin Cavalier const bool showSystem = false, showHidden = true, hideDot = false;
1893fbe39e1SAugustin Cavalier if (ntfs_set_shown_files(volume->ntfs, showSystem, showHidden, hideDot) != 0) {
1903fbe39e1SAugustin Cavalier ntfs_umount(volume->ntfs, true);
1913fbe39e1SAugustin Cavalier return B_ERROR;
1923fbe39e1SAugustin Cavalier }
1933fbe39e1SAugustin Cavalier
1948b018d9aSAugustin Cavalier // Fetch mount path, used when reading NTFS symlinks.
1958b018d9aSAugustin Cavalier dev_t deviceID;
1968b018d9aSAugustin Cavalier ino_t nodeID;
1978b018d9aSAugustin Cavalier status_t status = vfs_get_mount_point(_volume->id, &deviceID, &nodeID);
1988b018d9aSAugustin Cavalier char* mountpoint;
1998b018d9aSAugustin Cavalier if (status == B_OK) {
2008b018d9aSAugustin Cavalier mountpoint = (char*)malloc(PATH_MAX);
2018b018d9aSAugustin Cavalier status = vfs_entry_ref_to_path(deviceID, nodeID, NULL, true,
2028b018d9aSAugustin Cavalier mountpoint, PATH_MAX);
2038b018d9aSAugustin Cavalier if (status == B_OK) {
2048b018d9aSAugustin Cavalier char* reallocated = (char*)realloc(mountpoint, strlen(mountpoint) + 1);
2058b018d9aSAugustin Cavalier if (reallocated != NULL)
2068b018d9aSAugustin Cavalier mountpoint = reallocated;
207*13b7ddecSAugustin Cavalier } else {
208*13b7ddecSAugustin Cavalier free(mountpoint);
209*13b7ddecSAugustin Cavalier mountpoint = NULL;
2108b018d9aSAugustin Cavalier }
2118b018d9aSAugustin Cavalier }
2128b018d9aSAugustin Cavalier if (status != B_OK)
2138b018d9aSAugustin Cavalier mountpoint = strdup("");
2148b018d9aSAugustin Cavalier
2153fbe39e1SAugustin Cavalier // TODO: uid/gid mapping and real permissions
2163fbe39e1SAugustin Cavalier
2173fbe39e1SAugustin Cavalier // construct lowntfs_context
2185070f597SAugustin Cavalier volume->lowntfs.haiku_fs_volume = _volume;
2195070f597SAugustin Cavalier volume->lowntfs.current_close_state_vnode = NULL;
2205070f597SAugustin Cavalier
2213fbe39e1SAugustin Cavalier volume->lowntfs.vol = volume->ntfs;
2228b018d9aSAugustin Cavalier volume->ntfs->abs_mnt_point = volume->lowntfs.abs_mnt_point = mountpoint;
2233fbe39e1SAugustin Cavalier volume->lowntfs.dmask = 0;
2243fbe39e1SAugustin Cavalier volume->lowntfs.fmask = S_IXUSR | S_IXGRP | S_IXOTH;
2255070f597SAugustin Cavalier volume->lowntfs.dmtime = 0;
2265070f597SAugustin Cavalier volume->lowntfs.special_files = NTFS_FILES_INTERIX;
2273fbe39e1SAugustin Cavalier volume->lowntfs.posix_nlink = 0;
2285070f597SAugustin Cavalier volume->lowntfs.inherit = 0;
2295070f597SAugustin Cavalier volume->lowntfs.windows_names = 1;
2305070f597SAugustin Cavalier volume->lowntfs.latest_ghost = 0;
2313fbe39e1SAugustin Cavalier
2323fbe39e1SAugustin Cavalier *_rootID = root->inode = FILE_root;
2333fbe39e1SAugustin Cavalier root->parent_inode = (u64)-1;
2343fbe39e1SAugustin Cavalier root->mode = S_IFDIR | ACCESSPERMS;
2353fbe39e1SAugustin Cavalier root->uid = root->gid = 0;
2365070f597SAugustin Cavalier root->size = 0;
2373fbe39e1SAugustin Cavalier
2388b018d9aSAugustin Cavalier status = publish_vnode(_volume, root->inode, root, &gNtfsVnodeOps, S_IFDIR, 0);
2393fbe39e1SAugustin Cavalier if (status != B_OK) {
2403fbe39e1SAugustin Cavalier ntfs_umount(volume->ntfs, true);
2413fbe39e1SAugustin Cavalier return status;
2423fbe39e1SAugustin Cavalier }
2433fbe39e1SAugustin Cavalier
2443fbe39e1SAugustin Cavalier volumeDeleter.Detach();
2453fbe39e1SAugustin Cavalier
2463fbe39e1SAugustin Cavalier _volume->private_volume = volume;
2473fbe39e1SAugustin Cavalier _volume->ops = &gNtfsVolumeOps;
2483fbe39e1SAugustin Cavalier return B_OK;
2493fbe39e1SAugustin Cavalier }
2503fbe39e1SAugustin Cavalier
2513fbe39e1SAugustin Cavalier
2523fbe39e1SAugustin Cavalier static status_t
fs_unmount(fs_volume * _volume)2533fbe39e1SAugustin Cavalier fs_unmount(fs_volume* _volume)
2543fbe39e1SAugustin Cavalier {
2553fbe39e1SAugustin Cavalier CALLED();
2563fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
2573fbe39e1SAugustin Cavalier
2583fbe39e1SAugustin Cavalier if (ntfs_umount(volume->ntfs, false) < 0)
2593fbe39e1SAugustin Cavalier return errno;
2603fbe39e1SAugustin Cavalier
2613fbe39e1SAugustin Cavalier delete volume;
2623fbe39e1SAugustin Cavalier _volume->private_volume = NULL;
2633fbe39e1SAugustin Cavalier
2643fbe39e1SAugustin Cavalier return B_OK;
2653fbe39e1SAugustin Cavalier }
2663fbe39e1SAugustin Cavalier
2673fbe39e1SAugustin Cavalier
2683fbe39e1SAugustin Cavalier static status_t
fs_read_fs_info(fs_volume * _volume,struct fs_info * info)2693fbe39e1SAugustin Cavalier fs_read_fs_info(fs_volume* _volume, struct fs_info* info)
2703fbe39e1SAugustin Cavalier {
2713fbe39e1SAugustin Cavalier CALLED();
2723fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
2733fbe39e1SAugustin Cavalier MutexLocker lock(volume->lock);
2743fbe39e1SAugustin Cavalier
2753fbe39e1SAugustin Cavalier info->flags = volume->fs_info_flags;
2763fbe39e1SAugustin Cavalier info->block_size = volume->ntfs->cluster_size;
2773fbe39e1SAugustin Cavalier info->total_blocks = volume->ntfs->nr_clusters;
2783fbe39e1SAugustin Cavalier info->free_blocks = volume->ntfs->free_clusters;
2793fbe39e1SAugustin Cavalier
2803fbe39e1SAugustin Cavalier info->io_size = 65536;
2813fbe39e1SAugustin Cavalier
2823fbe39e1SAugustin Cavalier strlcpy(info->volume_name, volume->ntfs->vol_name, sizeof(info->volume_name));
2833fbe39e1SAugustin Cavalier strlcpy(info->fsh_name, "NTFS", sizeof(info->fsh_name));
2843fbe39e1SAugustin Cavalier
2853fbe39e1SAugustin Cavalier return B_OK;
2863fbe39e1SAugustin Cavalier }
2873fbe39e1SAugustin Cavalier
2883fbe39e1SAugustin Cavalier
2895070f597SAugustin Cavalier static status_t
fs_write_fs_info(fs_volume * _volume,const struct fs_info * info,uint32 mask)2905070f597SAugustin Cavalier fs_write_fs_info(fs_volume* _volume, const struct fs_info* info, uint32 mask)
2915070f597SAugustin Cavalier {
2925070f597SAugustin Cavalier CALLED();
2935070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
2945070f597SAugustin Cavalier MutexLocker lock(volume->lock);
2955070f597SAugustin Cavalier
2965070f597SAugustin Cavalier if ((volume->fs_info_flags & B_FS_IS_READONLY) != 0)
2975070f597SAugustin Cavalier return B_READ_ONLY_DEVICE;
2985070f597SAugustin Cavalier
2995070f597SAugustin Cavalier status_t status = B_OK;
3005070f597SAugustin Cavalier
3015070f597SAugustin Cavalier if ((mask & FS_WRITE_FSINFO_NAME) != 0) {
3025070f597SAugustin Cavalier ntfschar* label = NULL;
3035070f597SAugustin Cavalier int label_len = ntfs_mbstoucs(info->volume_name, &label);
3045070f597SAugustin Cavalier if (label_len <= 0 || label == NULL)
3055070f597SAugustin Cavalier return -1;
3065070f597SAugustin Cavalier MemoryDeleter nameDeleter(label);
3075070f597SAugustin Cavalier
3085070f597SAugustin Cavalier if (ntfs_volume_rename(volume->ntfs, label, label_len) != 0)
3095070f597SAugustin Cavalier status = errno;
3105070f597SAugustin Cavalier }
3115070f597SAugustin Cavalier
3125070f597SAugustin Cavalier return status;
3135070f597SAugustin Cavalier }
3145070f597SAugustin Cavalier
3155070f597SAugustin Cavalier
3163fbe39e1SAugustin Cavalier // #pragma mark -
3173fbe39e1SAugustin Cavalier
3183fbe39e1SAugustin Cavalier
3193fbe39e1SAugustin Cavalier static status_t
fs_init_vnode(fs_volume * _volume,ino_t parent,ino_t nid,vnode ** _vnode,bool publish=false)3205070f597SAugustin Cavalier fs_init_vnode(fs_volume* _volume, ino_t parent, ino_t nid, vnode** _vnode, bool publish = false)
3213fbe39e1SAugustin Cavalier {
3223fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
3235070f597SAugustin Cavalier ASSERT_LOCKED_MUTEX(&volume->lock);
3243fbe39e1SAugustin Cavalier
3253fbe39e1SAugustin Cavalier ntfs_inode* ni = ntfs_inode_open(volume->ntfs, nid);
3263fbe39e1SAugustin Cavalier if (ni == NULL)
3273fbe39e1SAugustin Cavalier return ENOENT;
3283fbe39e1SAugustin Cavalier NtfsInodeCloser niCloser(ni);
3293fbe39e1SAugustin Cavalier
3303fbe39e1SAugustin Cavalier vnode* node = new vnode;
3313fbe39e1SAugustin Cavalier if (node == NULL)
3323fbe39e1SAugustin Cavalier return B_NO_MEMORY;
3333fbe39e1SAugustin Cavalier ObjectDeleter<vnode> vnodeDeleter(node);
3343fbe39e1SAugustin Cavalier
3353fbe39e1SAugustin Cavalier struct stat statbuf;
3363fbe39e1SAugustin Cavalier if (ntfs_fuse_getstat(&volume->lowntfs, NULL, ni, &statbuf) != 0)
3373fbe39e1SAugustin Cavalier return errno;
3383fbe39e1SAugustin Cavalier
3395070f597SAugustin Cavalier node->inode = nid;
3405070f597SAugustin Cavalier node->parent_inode = parent;
3413fbe39e1SAugustin Cavalier node->uid = statbuf.st_uid;
3423fbe39e1SAugustin Cavalier node->gid = statbuf.st_gid;
3433fbe39e1SAugustin Cavalier node->mode = statbuf.st_mode;
3445070f597SAugustin Cavalier node->size = statbuf.st_size;
3453fbe39e1SAugustin Cavalier
3463fbe39e1SAugustin Cavalier // cache the node's name
3473fbe39e1SAugustin Cavalier char path[B_FILE_NAME_LENGTH];
3483fbe39e1SAugustin Cavalier if (utils_inode_get_name(ni, path, sizeof(path)) == 0)
3495070f597SAugustin Cavalier return B_NO_MEMORY;
3503fbe39e1SAugustin Cavalier node->name = strdup(strrchr(path, '/') + 1);
3513fbe39e1SAugustin Cavalier
3525070f597SAugustin Cavalier if (publish) {
3535070f597SAugustin Cavalier status_t status = publish_vnode(_volume, node->inode, node, &gNtfsVnodeOps, node->mode, 0);
3545070f597SAugustin Cavalier if (status != B_OK)
3555070f597SAugustin Cavalier return status;
3565070f597SAugustin Cavalier }
3573fbe39e1SAugustin Cavalier
3585070f597SAugustin Cavalier if ((node->mode & S_IFDIR) == 0) {
3595070f597SAugustin Cavalier node->file_cache = file_cache_create(_volume->id, nid, node->size);
3605070f597SAugustin Cavalier if (node->file_cache == NULL)
3615070f597SAugustin Cavalier return B_NO_INIT;
3625070f597SAugustin Cavalier }
3633fbe39e1SAugustin Cavalier
3643fbe39e1SAugustin Cavalier vnodeDeleter.Detach();
3655070f597SAugustin Cavalier *_vnode = node;
3665070f597SAugustin Cavalier return B_OK;
3675070f597SAugustin Cavalier }
3685070f597SAugustin Cavalier
3695070f597SAugustin Cavalier
3705070f597SAugustin Cavalier static status_t
fs_get_vnode(fs_volume * _volume,ino_t nid,fs_vnode * _node,int * _type,uint32 * _flags,bool reenter)3715070f597SAugustin Cavalier fs_get_vnode(fs_volume* _volume, ino_t nid, fs_vnode* _node, int* _type,
3725070f597SAugustin Cavalier uint32* _flags, bool reenter)
3735070f597SAugustin Cavalier {
3745070f597SAugustin Cavalier TRACE("get_vnode %" B_PRIdINO "\n", nid);
3755070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
3765070f597SAugustin Cavalier MutexLocker lock(reenter ? NULL : &volume->lock);
3775070f597SAugustin Cavalier
3785070f597SAugustin Cavalier vnode* vnode;
3795070f597SAugustin Cavalier status_t status = fs_init_vnode(_volume, -1 /* set by fs_lookup */, nid, &vnode);
3805070f597SAugustin Cavalier if (status != B_OK)
3815070f597SAugustin Cavalier return status;
3825070f597SAugustin Cavalier
3835070f597SAugustin Cavalier _node->private_node = vnode;
3845070f597SAugustin Cavalier _node->ops = &gNtfsVnodeOps;
3855070f597SAugustin Cavalier *_type = vnode->mode;
3865070f597SAugustin Cavalier *_flags = 0;
3875070f597SAugustin Cavalier
3883fbe39e1SAugustin Cavalier return B_OK;
3893fbe39e1SAugustin Cavalier }
3903fbe39e1SAugustin Cavalier
3913fbe39e1SAugustin Cavalier
3923fbe39e1SAugustin Cavalier static status_t
fs_put_vnode(fs_volume * _volume,fs_vnode * _node,bool reenter)3933fbe39e1SAugustin Cavalier fs_put_vnode(fs_volume* _volume, fs_vnode* _node, bool reenter)
3943fbe39e1SAugustin Cavalier {
3953fbe39e1SAugustin Cavalier CALLED();
3963fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
3973fbe39e1SAugustin Cavalier MutexLocker lock(reenter ? NULL : &volume->lock);
3983fbe39e1SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
3993fbe39e1SAugustin Cavalier
4003fbe39e1SAugustin Cavalier file_cache_delete(node->file_cache);
4013fbe39e1SAugustin Cavalier delete node;
4023fbe39e1SAugustin Cavalier return B_OK;
4033fbe39e1SAugustin Cavalier }
4043fbe39e1SAugustin Cavalier
4053fbe39e1SAugustin Cavalier
4065070f597SAugustin Cavalier static status_t
fs_remove_vnode(fs_volume * _volume,fs_vnode * _node,bool reenter)4075070f597SAugustin Cavalier fs_remove_vnode(fs_volume* _volume, fs_vnode* _node, bool reenter)
4085070f597SAugustin Cavalier {
4095070f597SAugustin Cavalier CALLED();
4105070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
4115070f597SAugustin Cavalier MutexLocker lock(reenter ? NULL : &volume->lock);
4125070f597SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
4135070f597SAugustin Cavalier
4145070f597SAugustin Cavalier if (ntfs_fuse_release(&volume->lowntfs, node->parent_inode, node->inode,
4155070f597SAugustin Cavalier node->lowntfs_close_state, node->lowntfs_ghost) != 0)
4165070f597SAugustin Cavalier return errno;
4175070f597SAugustin Cavalier
4185070f597SAugustin Cavalier file_cache_delete(node->file_cache);
4195070f597SAugustin Cavalier delete node;
4205070f597SAugustin Cavalier return B_OK;
4215070f597SAugustin Cavalier }
4225070f597SAugustin Cavalier
4235070f597SAugustin Cavalier
4245070f597SAugustin Cavalier int*
ntfs_haiku_get_close_state(struct lowntfs_context * ctx,u64 ino)4255070f597SAugustin Cavalier ntfs_haiku_get_close_state(struct lowntfs_context *ctx, u64 ino)
4265070f597SAugustin Cavalier {
4275070f597SAugustin Cavalier if (ctx->current_close_state_vnode != NULL)
4285070f597SAugustin Cavalier panic("NTFS current_close_state_vnode should be NULL!");
4295070f597SAugustin Cavalier
4305070f597SAugustin Cavalier vnode* node = NULL;
4315070f597SAugustin Cavalier if (get_vnode((fs_volume*)ctx->haiku_fs_volume, ino, (void**)&node) != B_OK)
4325070f597SAugustin Cavalier return NULL;
4335070f597SAugustin Cavalier ctx->current_close_state_vnode = node;
4345070f597SAugustin Cavalier return &node->lowntfs_close_state;
4355070f597SAugustin Cavalier }
4365070f597SAugustin Cavalier
4375070f597SAugustin Cavalier
4385070f597SAugustin Cavalier void
ntfs_haiku_put_close_state(struct lowntfs_context * ctx,u64 ino,u64 ghost)4395070f597SAugustin Cavalier ntfs_haiku_put_close_state(struct lowntfs_context *ctx, u64 ino, u64 ghost)
4405070f597SAugustin Cavalier {
4415070f597SAugustin Cavalier vnode* node = (vnode*)ctx->current_close_state_vnode;
4425070f597SAugustin Cavalier if (node == NULL)
4435070f597SAugustin Cavalier return;
4445070f597SAugustin Cavalier
4455070f597SAugustin Cavalier node->lowntfs_ghost = ghost;
4465070f597SAugustin Cavalier if ((node->lowntfs_close_state & CLOSE_GHOST) != 0) {
4475070f597SAugustin Cavalier fs_volume* _volume = (fs_volume*)ctx->haiku_fs_volume;
4485070f597SAugustin Cavalier entry_cache_remove(_volume->id, node->parent_inode, node->name);
4495070f597SAugustin Cavalier notify_entry_removed(_volume->id, node->parent_inode, node->name, node->inode);
4505070f597SAugustin Cavalier remove_vnode(_volume, node->inode);
4515070f597SAugustin Cavalier }
4525070f597SAugustin Cavalier
4535070f597SAugustin Cavalier ctx->current_close_state_vnode = NULL;
4545070f597SAugustin Cavalier put_vnode((fs_volume*)ctx->haiku_fs_volume, node->inode);
4555070f597SAugustin Cavalier }
4565070f597SAugustin Cavalier
4575070f597SAugustin Cavalier
4583fbe39e1SAugustin Cavalier static bool
fs_can_page(fs_volume * _volume,fs_vnode * _node,void * _cookie)4593fbe39e1SAugustin Cavalier fs_can_page(fs_volume* _volume, fs_vnode* _node, void* _cookie)
4603fbe39e1SAugustin Cavalier {
4613fbe39e1SAugustin Cavalier return true;
4623fbe39e1SAugustin Cavalier }
4633fbe39e1SAugustin Cavalier
4643fbe39e1SAugustin Cavalier
4653fbe39e1SAugustin Cavalier 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)4663fbe39e1SAugustin Cavalier fs_read_pages(fs_volume* _volume, fs_vnode* _node, void* _cookie,
4673fbe39e1SAugustin Cavalier off_t pos, const iovec* vecs, size_t count, size_t* _numBytes)
4683fbe39e1SAugustin Cavalier {
4693fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
4703fbe39e1SAugustin Cavalier MutexLocker lock(volume->lock);
4713fbe39e1SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
4723fbe39e1SAugustin Cavalier
4733fbe39e1SAugustin Cavalier TRACE("read_pages inode: %" B_PRIdINO", pos: %" B_PRIdOFF "; vecs: %p; "
4743fbe39e1SAugustin Cavalier "count: %" B_PRIuSIZE "; numBytes: %" B_PRIuSIZE "\n", node->inode, pos,
4753fbe39e1SAugustin Cavalier vecs, count, *_numBytes);
4763fbe39e1SAugustin Cavalier
4773fbe39e1SAugustin Cavalier ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
4783fbe39e1SAugustin Cavalier if (ni == NULL)
4793fbe39e1SAugustin Cavalier return B_FILE_ERROR;
4803fbe39e1SAugustin Cavalier NtfsInodeCloser niCloser(ni);
4813fbe39e1SAugustin Cavalier
4823fbe39e1SAugustin Cavalier if (pos < 0 || pos >= ni->data_size)
4833fbe39e1SAugustin Cavalier return B_BAD_VALUE;
4843fbe39e1SAugustin Cavalier
4853fbe39e1SAugustin Cavalier size_t bytesLeft = min_c(*_numBytes, size_t(ni->data_size - pos));
4863fbe39e1SAugustin Cavalier *_numBytes = 0;
4873fbe39e1SAugustin Cavalier for (size_t i = 0; i < count && bytesLeft > 0; i++) {
4883fbe39e1SAugustin Cavalier const size_t ioSize = min_c(bytesLeft, vecs[i].iov_len);
4893fbe39e1SAugustin Cavalier const int read = ntfs_fuse_read(ni, pos, (char*)vecs[i].iov_base, ioSize);
4903fbe39e1SAugustin Cavalier if (read < 0)
4913fbe39e1SAugustin Cavalier return errno;
4923fbe39e1SAugustin Cavalier
4933fbe39e1SAugustin Cavalier pos += read;
4943fbe39e1SAugustin Cavalier *_numBytes += read;
4953fbe39e1SAugustin Cavalier bytesLeft -= read;
4963fbe39e1SAugustin Cavalier
4973fbe39e1SAugustin Cavalier if (size_t(read) != ioSize)
4983fbe39e1SAugustin Cavalier return errno;
4993fbe39e1SAugustin Cavalier }
5003fbe39e1SAugustin Cavalier
5013fbe39e1SAugustin Cavalier return B_OK;
5023fbe39e1SAugustin Cavalier }
5033fbe39e1SAugustin Cavalier
5043fbe39e1SAugustin Cavalier
5055070f597SAugustin Cavalier 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)5065070f597SAugustin Cavalier fs_write_pages(fs_volume* _volume, fs_vnode* _node, void* _cookie,
5075070f597SAugustin Cavalier off_t pos, const iovec* vecs, size_t count, size_t* _numBytes)
5085070f597SAugustin Cavalier {
5095070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
5105070f597SAugustin Cavalier MutexLocker lock(volume->lock);
5115070f597SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
5125070f597SAugustin Cavalier
5135070f597SAugustin Cavalier TRACE("write_pages inode: %" B_PRIdINO", pos: %" B_PRIdOFF "; vecs: %p; "
5145070f597SAugustin Cavalier "count: %" B_PRIuSIZE "; numBytes: %" B_PRIuSIZE "\n", node->inode, pos,
5155070f597SAugustin Cavalier vecs, count, *_numBytes);
5165070f597SAugustin Cavalier
5175070f597SAugustin Cavalier ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
5185070f597SAugustin Cavalier if (ni == NULL)
5195070f597SAugustin Cavalier return B_FILE_ERROR;
5205070f597SAugustin Cavalier NtfsInodeCloser niCloser(ni);
5215070f597SAugustin Cavalier
5225070f597SAugustin Cavalier if (pos < 0 || pos >= ni->data_size)
5235070f597SAugustin Cavalier return B_BAD_VALUE;
5245070f597SAugustin Cavalier
5255070f597SAugustin Cavalier size_t bytesLeft = min_c(*_numBytes, size_t(ni->data_size - pos));
5265070f597SAugustin Cavalier *_numBytes = 0;
5275070f597SAugustin Cavalier for (size_t i = 0; i < count && bytesLeft > 0; i++) {
5285070f597SAugustin Cavalier const size_t ioSize = min_c(bytesLeft, vecs[i].iov_len);
5295070f597SAugustin Cavalier const int written = ntfs_fuse_write(&volume->lowntfs, ni, (char*)vecs[i].iov_base, ioSize, pos);
5305070f597SAugustin Cavalier if (written < 0)
5315070f597SAugustin Cavalier return errno;
5325070f597SAugustin Cavalier
5335070f597SAugustin Cavalier pos += written;
5345070f597SAugustin Cavalier *_numBytes += written;
5355070f597SAugustin Cavalier bytesLeft -= written;
5365070f597SAugustin Cavalier
5375070f597SAugustin Cavalier if (size_t(written) != ioSize)
5385070f597SAugustin Cavalier return errno;
5395070f597SAugustin Cavalier }
5405070f597SAugustin Cavalier
5415070f597SAugustin Cavalier return B_OK;
5425070f597SAugustin Cavalier }
5435070f597SAugustin Cavalier
5445070f597SAugustin Cavalier
5453fbe39e1SAugustin Cavalier // #pragma mark -
5463fbe39e1SAugustin Cavalier
5473fbe39e1SAugustin Cavalier
5483fbe39e1SAugustin Cavalier static status_t
fs_lookup(fs_volume * _volume,fs_vnode * _directory,const char * name,ino_t * _vnodeID)5493fbe39e1SAugustin Cavalier fs_lookup(fs_volume* _volume, fs_vnode* _directory, const char* name,
5503fbe39e1SAugustin Cavalier ino_t* _vnodeID)
5513fbe39e1SAugustin Cavalier {
5523fbe39e1SAugustin Cavalier TRACE("fs_lookup: name address: %p (%s)\n", name, name);
5533fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
5543fbe39e1SAugustin Cavalier MutexLocker lock(volume->lock);
5553fbe39e1SAugustin Cavalier vnode* directory = (vnode*)_directory->private_node;
5563fbe39e1SAugustin Cavalier
5573fbe39e1SAugustin Cavalier status_t result;
5583fbe39e1SAugustin Cavalier if (strcmp(name, ".") == 0) {
5593fbe39e1SAugustin Cavalier *_vnodeID = directory->inode;
5603fbe39e1SAugustin Cavalier } else if (strcmp(name, "..") == 0) {
5613fbe39e1SAugustin Cavalier if (directory->inode == FILE_root)
5623fbe39e1SAugustin Cavalier return ENOENT;
5633fbe39e1SAugustin Cavalier *_vnodeID = directory->parent_inode;
5643fbe39e1SAugustin Cavalier } else {
5653fbe39e1SAugustin Cavalier u64 inode = ntfs_fuse_inode_lookup(&volume->lowntfs, directory->inode, name);
5663fbe39e1SAugustin Cavalier if (inode == (u64)-1)
5673fbe39e1SAugustin Cavalier return errno;
5683fbe39e1SAugustin Cavalier *_vnodeID = inode;
5693fbe39e1SAugustin Cavalier }
5703fbe39e1SAugustin Cavalier
5713fbe39e1SAugustin Cavalier result = entry_cache_add(_volume->id, directory->inode, name, *_vnodeID);
5723fbe39e1SAugustin Cavalier if (result != B_OK)
5733fbe39e1SAugustin Cavalier return result;
5743fbe39e1SAugustin Cavalier
5753fbe39e1SAugustin Cavalier vnode* node = NULL;
5763fbe39e1SAugustin Cavalier result = get_vnode(_volume, *_vnodeID, (void**)&node);
5773fbe39e1SAugustin Cavalier if (result != B_OK)
5783fbe39e1SAugustin Cavalier return result;
5793fbe39e1SAugustin Cavalier
5803fbe39e1SAugustin Cavalier if (node->parent_inode == (u64)-1)
5813fbe39e1SAugustin Cavalier node->parent_inode = directory->inode;
5823fbe39e1SAugustin Cavalier
5833fbe39e1SAugustin Cavalier TRACE("fs_lookup: ID %" B_PRIdINO "\n", *_vnodeID);
5843fbe39e1SAugustin Cavalier return B_OK;
5853fbe39e1SAugustin Cavalier }
5863fbe39e1SAugustin Cavalier
5873fbe39e1SAugustin Cavalier
5883fbe39e1SAugustin Cavalier static status_t
fs_get_vnode_name(fs_volume * _volume,fs_vnode * _node,char * buffer,size_t bufferSize)5893fbe39e1SAugustin Cavalier fs_get_vnode_name(fs_volume* _volume, fs_vnode* _node, char* buffer, size_t bufferSize)
5903fbe39e1SAugustin Cavalier {
5913fbe39e1SAugustin Cavalier // CALLED();
5923fbe39e1SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
5933fbe39e1SAugustin Cavalier
5943fbe39e1SAugustin Cavalier if (strlcpy(buffer, node->name, bufferSize) >= bufferSize)
5953fbe39e1SAugustin Cavalier return B_BUFFER_OVERFLOW;
5963fbe39e1SAugustin Cavalier return B_OK;
5973fbe39e1SAugustin Cavalier }
5983fbe39e1SAugustin Cavalier
5993fbe39e1SAugustin Cavalier
6003fbe39e1SAugustin Cavalier static status_t
fs_ioctl(fs_volume * _volume,fs_vnode * _node,void * _cookie,uint32 cmd,void * buffer,size_t bufferLength)6013fbe39e1SAugustin Cavalier fs_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd,
6023fbe39e1SAugustin Cavalier void* buffer, size_t bufferLength)
6033fbe39e1SAugustin Cavalier {
6043fbe39e1SAugustin Cavalier // TODO?
6053fbe39e1SAugustin Cavalier return B_DEV_INVALID_IOCTL;
6063fbe39e1SAugustin Cavalier }
6073fbe39e1SAugustin Cavalier
6083fbe39e1SAugustin Cavalier
6093fbe39e1SAugustin Cavalier static status_t
fs_read_stat(fs_volume * _volume,fs_vnode * _node,struct stat * stat)6103fbe39e1SAugustin Cavalier fs_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
6113fbe39e1SAugustin Cavalier {
6123fbe39e1SAugustin Cavalier CALLED();
6133fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
6143fbe39e1SAugustin Cavalier MutexLocker lock(volume->lock);
6153fbe39e1SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
6163fbe39e1SAugustin Cavalier
6173fbe39e1SAugustin Cavalier ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
6183fbe39e1SAugustin Cavalier if (ni == NULL)
6193fbe39e1SAugustin Cavalier return errno;
6203fbe39e1SAugustin Cavalier NtfsInodeCloser niCloser(ni);
6213fbe39e1SAugustin Cavalier
6223fbe39e1SAugustin Cavalier if (ntfs_fuse_getstat(&volume->lowntfs, NULL, ni, stat) != 0)
6233fbe39e1SAugustin Cavalier return errno;
6243fbe39e1SAugustin Cavalier return B_OK;
6253fbe39e1SAugustin Cavalier }
6263fbe39e1SAugustin Cavalier
6273fbe39e1SAugustin Cavalier
6285070f597SAugustin Cavalier static status_t
fs_write_stat(fs_volume * _volume,fs_vnode * _node,const struct stat * stat,uint32 mask)6295070f597SAugustin Cavalier fs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat, uint32 mask)
6305070f597SAugustin Cavalier {
6315070f597SAugustin Cavalier CALLED();
6325070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
6335070f597SAugustin Cavalier MutexLocker lock(volume->lock);
6345070f597SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
6355070f597SAugustin Cavalier
6365070f597SAugustin Cavalier if ((volume->fs_info_flags & B_FS_IS_READONLY) != 0)
6375070f597SAugustin Cavalier return B_READ_ONLY_DEVICE;
6385070f597SAugustin Cavalier
6395070f597SAugustin Cavalier ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
6405070f597SAugustin Cavalier if (ni == NULL)
6415070f597SAugustin Cavalier return B_FILE_ERROR;
6425070f597SAugustin Cavalier NtfsInodeCloser niCloser(ni);
6435070f597SAugustin Cavalier
6445070f597SAugustin Cavalier bool updateTime = false;
6455070f597SAugustin Cavalier const uid_t euid = geteuid();
6465070f597SAugustin Cavalier
6475070f597SAugustin Cavalier const bool isOwnerOrRoot = (euid == 0 || euid == (uid_t)node->uid);
6485070f597SAugustin Cavalier const bool hasWriteAccess = fs_access(_volume, _node, W_OK);
6495070f597SAugustin Cavalier
6505070f597SAugustin Cavalier if ((mask & B_STAT_SIZE) != 0 && node->size != stat->st_size) {
6515070f597SAugustin Cavalier if ((node->mode & S_IFDIR) != 0)
6525070f597SAugustin Cavalier return B_IS_A_DIRECTORY;
6535070f597SAugustin Cavalier if (!hasWriteAccess)
6545070f597SAugustin Cavalier return B_NOT_ALLOWED;
6555070f597SAugustin Cavalier
6565070f597SAugustin Cavalier ntfs_attr* na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
6575070f597SAugustin Cavalier if (na == NULL)
6585070f597SAugustin Cavalier return errno;
6595070f597SAugustin Cavalier NtfsAttrCloser naCloser(na);
6605070f597SAugustin Cavalier
6615070f597SAugustin Cavalier if (ntfs_attr_truncate(na, stat->st_size) != 0)
6625070f597SAugustin Cavalier return errno;
6635070f597SAugustin Cavalier node->size = na->data_size;
6645070f597SAugustin Cavalier file_cache_set_size(node->file_cache, node->size);
6655070f597SAugustin Cavalier
6665070f597SAugustin Cavalier updateTime = true;
6675070f597SAugustin Cavalier }
6685070f597SAugustin Cavalier
6695070f597SAugustin Cavalier if ((mask & B_STAT_UID) != 0) {
6705070f597SAugustin Cavalier // only root should be allowed
6715070f597SAugustin Cavalier if (euid != 0)
6725070f597SAugustin Cavalier return B_NOT_ALLOWED;
6735070f597SAugustin Cavalier
6745070f597SAugustin Cavalier // We don't support this (yet.)
6755070f597SAugustin Cavalier if (node->uid != stat->st_uid)
6765070f597SAugustin Cavalier return B_UNSUPPORTED;
6775070f597SAugustin Cavalier }
6785070f597SAugustin Cavalier
6795070f597SAugustin Cavalier if ((mask & B_STAT_GID) != 0) {
6805070f597SAugustin Cavalier // only the user or root can do that
6815070f597SAugustin Cavalier if (!isOwnerOrRoot)
6825070f597SAugustin Cavalier return B_NOT_ALLOWED;
6835070f597SAugustin Cavalier
6845070f597SAugustin Cavalier // We don't support this (yet.)
6855070f597SAugustin Cavalier if (node->gid != stat->st_gid)
6865070f597SAugustin Cavalier return B_UNSUPPORTED;
6875070f597SAugustin Cavalier }
6885070f597SAugustin Cavalier
6895070f597SAugustin Cavalier if ((mask & B_STAT_MODE) != 0) {
6905070f597SAugustin Cavalier // only the user or root can do that
6915070f597SAugustin Cavalier if (!isOwnerOrRoot)
6925070f597SAugustin Cavalier return B_NOT_ALLOWED;
6935070f597SAugustin Cavalier
6945070f597SAugustin Cavalier // We don't support this (yet.)
6955070f597SAugustin Cavalier if (node->mode != stat->st_mode)
6965070f597SAugustin Cavalier return B_UNSUPPORTED;
6975070f597SAugustin Cavalier }
6985070f597SAugustin Cavalier
6995070f597SAugustin Cavalier if ((mask & B_STAT_CREATION_TIME) != 0) {
7005070f597SAugustin Cavalier // the user or root can do that or any user with write access
7015070f597SAugustin Cavalier if (!isOwnerOrRoot && !hasWriteAccess)
7025070f597SAugustin Cavalier return B_NOT_ALLOWED;
7035070f597SAugustin Cavalier
7045070f597SAugustin Cavalier ni->creation_time = timespec2ntfs(stat->st_crtim);
7055070f597SAugustin Cavalier }
7065070f597SAugustin Cavalier
7075070f597SAugustin Cavalier if ((mask & B_STAT_MODIFICATION_TIME) != 0) {
7085070f597SAugustin Cavalier // the user or root can do that or any user with write access
7095070f597SAugustin Cavalier if (!isOwnerOrRoot && !hasWriteAccess)
7105070f597SAugustin Cavalier return B_NOT_ALLOWED;
7115070f597SAugustin Cavalier
7125070f597SAugustin Cavalier ni->last_data_change_time = timespec2ntfs(stat->st_mtim);
7135070f597SAugustin Cavalier }
7145070f597SAugustin Cavalier
7155070f597SAugustin Cavalier if ((mask & B_STAT_CHANGE_TIME) != 0 || updateTime) {
7165070f597SAugustin Cavalier // the user or root can do that or any user with write access
7175070f597SAugustin Cavalier if (!isOwnerOrRoot && !hasWriteAccess)
7185070f597SAugustin Cavalier return B_NOT_ALLOWED;
7195070f597SAugustin Cavalier
7205070f597SAugustin Cavalier ni->last_mft_change_time = timespec2ntfs(stat->st_ctim);
7215070f597SAugustin Cavalier }
7225070f597SAugustin Cavalier
7235070f597SAugustin Cavalier if ((mask & B_STAT_ACCESS_TIME) != 0) {
7245070f597SAugustin Cavalier // the user or root can do that or any user with write access
7255070f597SAugustin Cavalier if (!isOwnerOrRoot && !hasWriteAccess)
7265070f597SAugustin Cavalier return B_NOT_ALLOWED;
7275070f597SAugustin Cavalier
7285070f597SAugustin Cavalier ni->last_access_time = timespec2ntfs(stat->st_atim);
7295070f597SAugustin Cavalier }
7305070f597SAugustin Cavalier
7315070f597SAugustin Cavalier ntfs_inode_mark_dirty(ni);
7325070f597SAugustin Cavalier
7335070f597SAugustin Cavalier notify_stat_changed(_volume->id, node->parent_inode, node->inode, mask);
7345070f597SAugustin Cavalier return B_OK;
7355070f597SAugustin Cavalier }
7365070f597SAugustin Cavalier
7375070f597SAugustin Cavalier
7383fbe39e1SAugustin Cavalier static status_t
fs_generic_create(fs_volume * _volume,vnode * directory,const char * name,int mode,ino_t * _inode)7395070f597SAugustin Cavalier fs_generic_create(fs_volume* _volume, vnode* directory, const char* name, int mode,
7405070f597SAugustin Cavalier ino_t* _inode)
7415070f597SAugustin Cavalier {
7425070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
7435070f597SAugustin Cavalier ASSERT_LOCKED_MUTEX(&volume->lock);
7445070f597SAugustin Cavalier
7455070f597SAugustin Cavalier if ((directory->mode & S_IFDIR) == 0)
7465070f597SAugustin Cavalier return B_BAD_TYPE;
7475070f597SAugustin Cavalier
7485070f597SAugustin Cavalier ino_t inode = -1;
7495070f597SAugustin Cavalier if (ntfs_fuse_create(&volume->lowntfs, directory->inode, name, mode & (S_IFMT | 07777),
7505070f597SAugustin Cavalier 0, (char*)NULL, &inode) != 0)
7515070f597SAugustin Cavalier return errno;
7525070f597SAugustin Cavalier
7535070f597SAugustin Cavalier vnode* node;
7545070f597SAugustin Cavalier status_t status = fs_init_vnode(_volume, directory->inode, inode, &node, true);
7555070f597SAugustin Cavalier if (status != B_OK)
7565070f597SAugustin Cavalier return status;
7575070f597SAugustin Cavalier
7585070f597SAugustin Cavalier entry_cache_add(_volume->id, directory->inode, name, inode);
7595070f597SAugustin Cavalier notify_entry_created(_volume->id, directory->inode, name, inode);
7605070f597SAugustin Cavalier *_inode = inode;
7615070f597SAugustin Cavalier return B_OK;
7625070f597SAugustin Cavalier }
7635070f597SAugustin Cavalier
7645070f597SAugustin Cavalier
7655070f597SAugustin Cavalier static status_t
fs_create(fs_volume * _volume,fs_vnode * _directory,const char * name,int openMode,int mode,void ** _cookie,ino_t * _vnodeID)7665070f597SAugustin Cavalier fs_create(fs_volume* _volume, fs_vnode* _directory, const char* name,
7675070f597SAugustin Cavalier int openMode, int mode, void** _cookie, ino_t* _vnodeID)
7685070f597SAugustin Cavalier {
7695070f597SAugustin Cavalier CALLED();
7705070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
7715070f597SAugustin Cavalier MutexLocker lock(volume->lock);
7725070f597SAugustin Cavalier vnode* directory = (vnode*)_directory->private_node;
7735070f597SAugustin Cavalier
7745070f597SAugustin Cavalier if ((directory->mode & S_IFDIR) == 0)
7755070f597SAugustin Cavalier return B_NOT_A_DIRECTORY;
7765070f597SAugustin Cavalier
7775070f597SAugustin Cavalier status_t status = fs_access(_volume, _directory, W_OK);
7785070f597SAugustin Cavalier if (status != B_OK)
7795070f597SAugustin Cavalier return status;
7805070f597SAugustin Cavalier
7815070f597SAugustin Cavalier #if 1
7825070f597SAugustin Cavalier if ((openMode & O_NOCACHE) != 0)
7835070f597SAugustin Cavalier return B_UNSUPPORTED;
7845070f597SAugustin Cavalier #endif
7855070f597SAugustin Cavalier
7865070f597SAugustin Cavalier status = fs_generic_create(_volume, directory, name, S_IFREG | (mode & 07777), _vnodeID);
7875070f597SAugustin Cavalier if (status != B_OK)
7885070f597SAugustin Cavalier return status;
7895070f597SAugustin Cavalier
7905070f597SAugustin Cavalier file_cookie* cookie = new file_cookie;
7915070f597SAugustin Cavalier if (cookie == NULL)
7925070f597SAugustin Cavalier return B_NO_MEMORY;
7935070f597SAugustin Cavalier ObjectDeleter<file_cookie> cookieDeleter(cookie);
7945070f597SAugustin Cavalier
7955070f597SAugustin Cavalier cookie->open_mode = openMode;
7965070f597SAugustin Cavalier
7975070f597SAugustin Cavalier cookieDeleter.Detach();
7985070f597SAugustin Cavalier *_cookie = cookie;
7995070f597SAugustin Cavalier return B_OK;
8005070f597SAugustin Cavalier }
8015070f597SAugustin Cavalier
8025070f597SAugustin Cavalier
8035070f597SAugustin Cavalier static status_t
fs_open(fs_volume * _volume,fs_vnode * _node,int openMode,void ** _cookie)8043fbe39e1SAugustin Cavalier fs_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie)
8053fbe39e1SAugustin Cavalier {
8063fbe39e1SAugustin Cavalier CALLED();
8073fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
8083fbe39e1SAugustin Cavalier MutexLocker lock(volume->lock);
8093fbe39e1SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
8103fbe39e1SAugustin Cavalier
8113fbe39e1SAugustin Cavalier // opening a directory read-only is allowed (but no data can be read)
8123fbe39e1SAugustin Cavalier if ((node->mode & S_IFDIR) != 0 && (openMode & O_RWMASK) != 0)
8133fbe39e1SAugustin Cavalier return B_IS_A_DIRECTORY;
8143fbe39e1SAugustin Cavalier if ((openMode & O_DIRECTORY) != 0 && (node->mode & S_IFDIR) == 0)
8153fbe39e1SAugustin Cavalier return B_NOT_A_DIRECTORY;
8163fbe39e1SAugustin Cavalier
8173fbe39e1SAugustin Cavalier status_t status = fs_access(_volume, _node, open_mode_to_access(openMode));
8183fbe39e1SAugustin Cavalier if (status != B_OK)
8193fbe39e1SAugustin Cavalier return status;
8203fbe39e1SAugustin Cavalier
8213fbe39e1SAugustin Cavalier ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
8223fbe39e1SAugustin Cavalier if (ni == NULL)
8233fbe39e1SAugustin Cavalier return errno;
8243fbe39e1SAugustin Cavalier NtfsInodeCloser niCloser(ni);
8253fbe39e1SAugustin Cavalier
8263fbe39e1SAugustin Cavalier file_cookie* cookie = new file_cookie;
8273fbe39e1SAugustin Cavalier if (cookie == NULL)
8283fbe39e1SAugustin Cavalier return B_NO_MEMORY;
8293fbe39e1SAugustin Cavalier ObjectDeleter<file_cookie> cookieDeleter(cookie);
8303fbe39e1SAugustin Cavalier
8313fbe39e1SAugustin Cavalier cookie->open_mode = openMode;
8323fbe39e1SAugustin Cavalier
8333fbe39e1SAugustin Cavalier // We don't actually support uncached mode; it would require us to handle
8343fbe39e1SAugustin Cavalier // passing user buffers to libntfs, among other things.
8353fbe39e1SAugustin Cavalier #if 0
8363fbe39e1SAugustin Cavalier if ((openMode & O_NOCACHE) != 0 && node->file_cache != NULL) {
8373fbe39e1SAugustin Cavalier status_t status = file_cache_disable(node->file_cache);
8383fbe39e1SAugustin Cavalier if (status != B_OK)
8393fbe39e1SAugustin Cavalier return status;
8403fbe39e1SAugustin Cavalier }
8413fbe39e1SAugustin Cavalier #else
8423fbe39e1SAugustin Cavalier if ((openMode & O_NOCACHE) != 0)
8433fbe39e1SAugustin Cavalier return B_UNSUPPORTED;
8443fbe39e1SAugustin Cavalier #endif
8453fbe39e1SAugustin Cavalier
8465070f597SAugustin Cavalier if ((openMode & O_TRUNC) != 0) {
8475070f597SAugustin Cavalier if ((openMode & O_RWMASK) == O_RDONLY)
8485070f597SAugustin Cavalier return B_NOT_ALLOWED;
8495070f597SAugustin Cavalier
8505070f597SAugustin Cavalier ntfs_attr* na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
8515070f597SAugustin Cavalier if (na == NULL)
8525070f597SAugustin Cavalier return errno;
8535070f597SAugustin Cavalier NtfsAttrCloser naCloser(na);
8545070f597SAugustin Cavalier
8555070f597SAugustin Cavalier if (ntfs_attr_truncate(na, 0) != 0)
8565070f597SAugustin Cavalier return errno;
8575070f597SAugustin Cavalier node->size = na->data_size;
8585070f597SAugustin Cavalier file_cache_set_size(node->file_cache, node->size);
8595070f597SAugustin Cavalier }
8605070f597SAugustin Cavalier
8613fbe39e1SAugustin Cavalier cookieDeleter.Detach();
8623fbe39e1SAugustin Cavalier *_cookie = cookie;
8633fbe39e1SAugustin Cavalier return B_OK;
8643fbe39e1SAugustin Cavalier }
8653fbe39e1SAugustin Cavalier
8663fbe39e1SAugustin Cavalier
8673fbe39e1SAugustin Cavalier static status_t
fs_read(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,void * buffer,size_t * length)8683fbe39e1SAugustin Cavalier fs_read(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
8693fbe39e1SAugustin Cavalier void* buffer, size_t* length)
8703fbe39e1SAugustin Cavalier {
8713fbe39e1SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
8723fbe39e1SAugustin Cavalier file_cookie* cookie = (file_cookie*)_cookie;
8733fbe39e1SAugustin Cavalier
8743fbe39e1SAugustin Cavalier if ((node->mode & S_IFDIR) != 0)
8753fbe39e1SAugustin Cavalier return B_IS_A_DIRECTORY;
8763fbe39e1SAugustin Cavalier
8773fbe39e1SAugustin Cavalier ASSERT((cookie->open_mode & O_RWMASK) == O_RDONLY || (cookie->open_mode & O_RDWR) != 0);
8783fbe39e1SAugustin Cavalier
8793fbe39e1SAugustin Cavalier return file_cache_read(node->file_cache, cookie, pos, buffer, length);
8803fbe39e1SAugustin Cavalier }
8813fbe39e1SAugustin Cavalier
8823fbe39e1SAugustin Cavalier
8833fbe39e1SAugustin Cavalier static status_t
fs_write(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,const void * buffer,size_t * _length)8845070f597SAugustin Cavalier fs_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
8855070f597SAugustin Cavalier const void* buffer, size_t* _length)
8865070f597SAugustin Cavalier {
8875070f597SAugustin Cavalier CALLED();
8885070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
8895070f597SAugustin Cavalier MutexLocker lock(volume->lock);
8905070f597SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
8915070f597SAugustin Cavalier file_cookie* cookie = (file_cookie*)_cookie;
8925070f597SAugustin Cavalier
8935070f597SAugustin Cavalier if ((node->mode & S_IFDIR) != 0)
8945070f597SAugustin Cavalier return B_IS_A_DIRECTORY;
8955070f597SAugustin Cavalier
8965070f597SAugustin Cavalier ASSERT((cookie->open_mode & O_WRONLY) != 0 || (cookie->open_mode & O_RDWR) != 0);
8975070f597SAugustin Cavalier
8985070f597SAugustin Cavalier if (cookie->open_mode & O_APPEND)
8995070f597SAugustin Cavalier pos = node->size;
9005070f597SAugustin Cavalier if (pos < 0)
9015070f597SAugustin Cavalier return B_BAD_VALUE;
9025070f597SAugustin Cavalier
9035070f597SAugustin Cavalier if (pos + s64(*_length) > node->size) {
9045070f597SAugustin Cavalier ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
9055070f597SAugustin Cavalier if (ni == NULL)
9065070f597SAugustin Cavalier return errno;
9075070f597SAugustin Cavalier NtfsInodeCloser niCloser(ni);
9085070f597SAugustin Cavalier
9095070f597SAugustin Cavalier ntfs_attr* na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
9105070f597SAugustin Cavalier if (na == NULL)
9115070f597SAugustin Cavalier return errno;
9125070f597SAugustin Cavalier NtfsAttrCloser naCloser(na);
9135070f597SAugustin Cavalier
9145070f597SAugustin Cavalier if (ntfs_attr_truncate(na, pos + *_length) != 0)
9155070f597SAugustin Cavalier return errno;
9165070f597SAugustin Cavalier node->size = na->data_size;
9175070f597SAugustin Cavalier file_cache_set_size(node->file_cache, node->size);
9185070f597SAugustin Cavalier }
9195070f597SAugustin Cavalier
9205070f597SAugustin Cavalier lock.Unlock();
9215070f597SAugustin Cavalier
9225070f597SAugustin Cavalier status_t status = file_cache_write(node->file_cache, cookie, pos, buffer, _length);
9235070f597SAugustin Cavalier if (status != B_OK)
9245070f597SAugustin Cavalier return status;
9255070f597SAugustin Cavalier
9265070f597SAugustin Cavalier lock.Lock();
9275070f597SAugustin Cavalier
9285070f597SAugustin Cavalier // periodically notify if the file size has changed
9295070f597SAugustin Cavalier if ((node->lowntfs_close_state & CLOSE_GHOST) == 0
9305070f597SAugustin Cavalier && cookie->last_size != node->size
9315070f597SAugustin Cavalier && system_time() > cookie->last_notification + INODE_NOTIFICATION_INTERVAL) {
9325070f597SAugustin Cavalier notify_stat_changed(_volume->id, node->parent_inode, node->inode,
9335070f597SAugustin Cavalier B_STAT_MODIFICATION_TIME | B_STAT_SIZE | B_STAT_INTERIM_UPDATE);
9345070f597SAugustin Cavalier cookie->last_size = node->size;
9355070f597SAugustin Cavalier cookie->last_notification = system_time();
9365070f597SAugustin Cavalier }
9375070f597SAugustin Cavalier return status;
9385070f597SAugustin Cavalier }
9395070f597SAugustin Cavalier
9405070f597SAugustin Cavalier
9415070f597SAugustin Cavalier static status_t
fs_fsync(fs_volume * _volume,fs_vnode * _node)9425070f597SAugustin Cavalier fs_fsync(fs_volume* _volume, fs_vnode* _node)
9435070f597SAugustin Cavalier {
9445070f597SAugustin Cavalier CALLED();
9455070f597SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
9465070f597SAugustin Cavalier
9475070f597SAugustin Cavalier return file_cache_sync(node->file_cache);
9485070f597SAugustin Cavalier }
9495070f597SAugustin Cavalier
9505070f597SAugustin Cavalier
9515070f597SAugustin Cavalier static status_t
fs_close(fs_volume * _volume,fs_vnode * _node,void * _cookie)9523fbe39e1SAugustin Cavalier fs_close(fs_volume *_volume, fs_vnode *_node, void *_cookie)
9533fbe39e1SAugustin Cavalier {
9543fbe39e1SAugustin Cavalier CALLED();
9553fbe39e1SAugustin Cavalier
9563fbe39e1SAugustin Cavalier // Nothing to do.
9573fbe39e1SAugustin Cavalier return B_OK;
9583fbe39e1SAugustin Cavalier }
9593fbe39e1SAugustin Cavalier
9603fbe39e1SAugustin Cavalier
9613fbe39e1SAugustin Cavalier static status_t
fs_free_cookie(fs_volume * _volume,fs_vnode * _node,void * _cookie)9623fbe39e1SAugustin Cavalier fs_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
9633fbe39e1SAugustin Cavalier {
9643fbe39e1SAugustin Cavalier file_cookie* cookie = (file_cookie*)_cookie;
9653fbe39e1SAugustin Cavalier delete cookie;
9663fbe39e1SAugustin Cavalier return B_OK;
9673fbe39e1SAugustin Cavalier }
9683fbe39e1SAugustin Cavalier
9693fbe39e1SAugustin Cavalier
9703fbe39e1SAugustin Cavalier static status_t
fs_generic_unlink(fs_volume * _volume,fs_vnode * _directory,const char * name,RM_TYPES type)9715070f597SAugustin Cavalier fs_generic_unlink(fs_volume* _volume, fs_vnode* _directory, const char* name, RM_TYPES type)
9725070f597SAugustin Cavalier {
9735070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
9745070f597SAugustin Cavalier MutexLocker lock(volume->lock);
9755070f597SAugustin Cavalier vnode* directory = (vnode*)_directory->private_node;
9765070f597SAugustin Cavalier
9775070f597SAugustin Cavalier status_t status = fs_access(_volume, _directory, W_OK);
9785070f597SAugustin Cavalier if (status != B_OK)
9795070f597SAugustin Cavalier return status;
9805070f597SAugustin Cavalier
9815070f597SAugustin Cavalier if (ntfs_fuse_rm(&volume->lowntfs, directory->inode, name, type) != 0)
9825070f597SAugustin Cavalier return errno;
9835070f597SAugustin Cavalier
9845070f597SAugustin Cavalier // remove_vnode() et al. will be called by put_close_state.
9855070f597SAugustin Cavalier return B_OK;
9865070f597SAugustin Cavalier }
9875070f597SAugustin Cavalier
9885070f597SAugustin Cavalier
9895070f597SAugustin Cavalier static status_t
fs_unlink(fs_volume * _volume,fs_vnode * _directory,const char * name)9905070f597SAugustin Cavalier fs_unlink(fs_volume* _volume, fs_vnode* _directory, const char* name)
9915070f597SAugustin Cavalier {
9925070f597SAugustin Cavalier CALLED();
9935070f597SAugustin Cavalier return fs_generic_unlink(_volume, _directory, name, RM_LINK);
9945070f597SAugustin Cavalier }
9955070f597SAugustin Cavalier
9965070f597SAugustin Cavalier
9975070f597SAugustin Cavalier static status_t
fs_rename(fs_volume * _volume,fs_vnode * _oldDir,const char * oldName,fs_vnode * _newDir,const char * newName)9985070f597SAugustin Cavalier fs_rename(fs_volume* _volume, fs_vnode* _oldDir, const char* oldName,
9995070f597SAugustin Cavalier fs_vnode* _newDir, const char* newName)
10005070f597SAugustin Cavalier {
10015070f597SAugustin Cavalier CALLED();
10025070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
10035070f597SAugustin Cavalier MutexLocker lock(volume->lock);
10045070f597SAugustin Cavalier
10055070f597SAugustin Cavalier vnode* old_directory = (vnode*)_oldDir->private_node;
10065070f597SAugustin Cavalier vnode* new_directory = (vnode*)_newDir->private_node;
10075070f597SAugustin Cavalier
10085070f597SAugustin Cavalier if (old_directory == new_directory && strcmp(oldName, newName) == 0)
10095070f597SAugustin Cavalier return B_OK;
10105070f597SAugustin Cavalier
10115070f597SAugustin Cavalier status_t status = fs_access(_volume, _oldDir, W_OK);
10125070f597SAugustin Cavalier if (status == B_OK)
10135070f597SAugustin Cavalier status = fs_access(_volume, _newDir, W_OK);
10145070f597SAugustin Cavalier if (status != B_OK)
10155070f597SAugustin Cavalier return status;
10165070f597SAugustin Cavalier
101791337305SAugustin Cavalier // Prevent moving a directory into one of its own children.
101891337305SAugustin Cavalier if (old_directory != new_directory) {
101991337305SAugustin Cavalier u64 oldIno = ntfs_fuse_inode_lookup(&volume->lowntfs, old_directory->inode, oldName);
102091337305SAugustin Cavalier if (oldIno == (u64)-1)
102191337305SAugustin Cavalier return B_ENTRY_NOT_FOUND;
102291337305SAugustin Cavalier
102391337305SAugustin Cavalier ino_t parent = new_directory->inode;
102491337305SAugustin Cavalier const ino_t root = FILE_root;
102591337305SAugustin Cavalier
102691337305SAugustin Cavalier while (true) {
102791337305SAugustin Cavalier if (parent == oldIno)
102891337305SAugustin Cavalier return B_BAD_VALUE;
102991337305SAugustin Cavalier else if (parent == root || parent == old_directory->inode)
103091337305SAugustin Cavalier break;
103191337305SAugustin Cavalier
103291337305SAugustin Cavalier vnode* parentNode;
103391337305SAugustin Cavalier if (get_vnode(_volume, parent, (void**)&parentNode) != B_OK)
103491337305SAugustin Cavalier return B_ERROR;
103591337305SAugustin Cavalier
103691337305SAugustin Cavalier parent = parentNode->parent_inode;
103791337305SAugustin Cavalier put_vnode(_volume, parentNode->inode);
103891337305SAugustin Cavalier }
103991337305SAugustin Cavalier }
104091337305SAugustin Cavalier
10415070f597SAugustin Cavalier if (ntfs_fuse_rename(&volume->lowntfs, old_directory->inode, oldName,
10425070f597SAugustin Cavalier new_directory->inode, newName) != 0)
10435070f597SAugustin Cavalier return errno;
10445070f597SAugustin Cavalier
10455070f597SAugustin Cavalier u64 ino = ntfs_fuse_inode_lookup(&volume->lowntfs, new_directory->inode, newName);
10465070f597SAugustin Cavalier if (ino == (u64)-1)
10475070f597SAugustin Cavalier return B_ENTRY_NOT_FOUND;
10485070f597SAugustin Cavalier
10495070f597SAugustin Cavalier vnode* node;
10505070f597SAugustin Cavalier status = get_vnode(_volume, ino, (void**)&node);
10515070f597SAugustin Cavalier if (status != B_OK)
10525070f597SAugustin Cavalier return status;
10535070f597SAugustin Cavalier
10545070f597SAugustin Cavalier free(node->name);
10555070f597SAugustin Cavalier node->name = strdup(newName);
10565070f597SAugustin Cavalier node->parent_inode = new_directory->inode;
10575070f597SAugustin Cavalier
10585070f597SAugustin Cavalier if ((node->mode & S_IFDIR) != 0)
10595070f597SAugustin Cavalier entry_cache_add(_volume->id, ino, "..", new_directory->inode);
10605070f597SAugustin Cavalier
10615070f597SAugustin Cavalier put_vnode(_volume, ino);
10625070f597SAugustin Cavalier
10635070f597SAugustin Cavalier entry_cache_remove(_volume->id, old_directory->inode, oldName);
10645070f597SAugustin Cavalier entry_cache_add(_volume->id, new_directory->inode, newName, ino);
10655070f597SAugustin Cavalier notify_entry_moved(_volume->id, old_directory->inode, oldName,
10665070f597SAugustin Cavalier new_directory->inode, newName, ino);
10675070f597SAugustin Cavalier
10685070f597SAugustin Cavalier return B_OK;
10695070f597SAugustin Cavalier }
10705070f597SAugustin Cavalier
10715070f597SAugustin Cavalier
10725070f597SAugustin Cavalier static status_t
fs_access(fs_volume * _volume,fs_vnode * _node,int accessMode)10733fbe39e1SAugustin Cavalier fs_access(fs_volume* _volume, fs_vnode* _node, int accessMode)
10743fbe39e1SAugustin Cavalier {
10753fbe39e1SAugustin Cavalier // CALLED();
10763fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
10773fbe39e1SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
10783fbe39e1SAugustin Cavalier
10793fbe39e1SAugustin Cavalier if ((accessMode & W_OK) != 0 && (volume->fs_info_flags & B_FS_IS_READONLY) != 0)
10803fbe39e1SAugustin Cavalier return B_READ_ONLY_DEVICE;
10813fbe39e1SAugustin Cavalier
10823fbe39e1SAugustin Cavalier return check_access_permissions(accessMode, node->mode, node->gid, node->uid);
10833fbe39e1SAugustin Cavalier }
10843fbe39e1SAugustin Cavalier
10853fbe39e1SAugustin Cavalier
10863fbe39e1SAugustin Cavalier static status_t
fs_read_link(fs_volume * _volume,fs_vnode * _node,char * buffer,size_t * bufferSize)10873fbe39e1SAugustin Cavalier fs_read_link(fs_volume* _volume, fs_vnode* _node, char* buffer, size_t* bufferSize)
10883fbe39e1SAugustin Cavalier {
10893fbe39e1SAugustin Cavalier CALLED();
10903fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
10913fbe39e1SAugustin Cavalier MutexLocker lock(volume->lock);
10923fbe39e1SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
10933fbe39e1SAugustin Cavalier
10943fbe39e1SAugustin Cavalier if (ntfs_fuse_readlink(&volume->lowntfs, node->inode, buffer, bufferSize) != 0)
10953fbe39e1SAugustin Cavalier return errno;
10963fbe39e1SAugustin Cavalier return B_OK;
10973fbe39e1SAugustin Cavalier }
10983fbe39e1SAugustin Cavalier
10993fbe39e1SAugustin Cavalier
11003fbe39e1SAugustin Cavalier // #pragma mark - Directory functions
11013fbe39e1SAugustin Cavalier
11023fbe39e1SAugustin Cavalier
11033fbe39e1SAugustin Cavalier static status_t
fs_create_dir(fs_volume * _volume,fs_vnode * _directory,const char * name,int mode)11045070f597SAugustin Cavalier fs_create_dir(fs_volume* _volume, fs_vnode* _directory, const char* name, int mode)
11055070f597SAugustin Cavalier {
11065070f597SAugustin Cavalier CALLED();
11075070f597SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
11085070f597SAugustin Cavalier MutexLocker lock(volume->lock);
11095070f597SAugustin Cavalier vnode* directory = (vnode*)_directory->private_node;
11105070f597SAugustin Cavalier
11115070f597SAugustin Cavalier status_t status = fs_access(_volume, _directory, W_OK);
11125070f597SAugustin Cavalier if (status != B_OK)
11135070f597SAugustin Cavalier return status;
11145070f597SAugustin Cavalier
11155070f597SAugustin Cavalier ino_t inode = -1;
11165070f597SAugustin Cavalier status = fs_generic_create(_volume, directory, name, S_IFDIR | (mode & 07777), &inode);
11175070f597SAugustin Cavalier if (status != B_OK)
11185070f597SAugustin Cavalier return status;
11195070f597SAugustin Cavalier
11205070f597SAugustin Cavalier return B_OK;
11215070f597SAugustin Cavalier }
11225070f597SAugustin Cavalier
11235070f597SAugustin Cavalier
11245070f597SAugustin Cavalier static status_t
fs_remove_dir(fs_volume * _volume,fs_vnode * _directory,const char * name)11255070f597SAugustin Cavalier fs_remove_dir(fs_volume* _volume, fs_vnode* _directory, const char* name)
11265070f597SAugustin Cavalier {
11275070f597SAugustin Cavalier CALLED();
11285070f597SAugustin Cavalier ino_t directory_inode = ((vnode*)_directory->private_node)->inode;
11295070f597SAugustin Cavalier status_t status = fs_generic_unlink(_volume, _directory, name, RM_DIR);
11305070f597SAugustin Cavalier if (status != B_OK)
11315070f597SAugustin Cavalier return status;
11325070f597SAugustin Cavalier
11335070f597SAugustin Cavalier entry_cache_remove(_volume->id, directory_inode, "..");
11345070f597SAugustin Cavalier return B_OK;
11355070f597SAugustin Cavalier }
11365070f597SAugustin Cavalier
11375070f597SAugustin Cavalier
11385070f597SAugustin Cavalier static status_t
fs_open_dir(fs_volume * _volume,fs_vnode * _node,void ** _cookie)11393fbe39e1SAugustin Cavalier fs_open_dir(fs_volume* _volume, fs_vnode* _node, void** _cookie)
11403fbe39e1SAugustin Cavalier {
11413fbe39e1SAugustin Cavalier CALLED();
11423fbe39e1SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
11433fbe39e1SAugustin Cavalier
11443fbe39e1SAugustin Cavalier status_t status = fs_access(_volume, _node, R_OK);
11453fbe39e1SAugustin Cavalier if (status != B_OK)
11463fbe39e1SAugustin Cavalier return status;
11473fbe39e1SAugustin Cavalier
11483fbe39e1SAugustin Cavalier if ((node->mode & S_IFDIR) == 0)
11493fbe39e1SAugustin Cavalier return B_NOT_A_DIRECTORY;
11503fbe39e1SAugustin Cavalier
11513fbe39e1SAugustin Cavalier directory_cookie* cookie = new directory_cookie;
11523fbe39e1SAugustin Cavalier if (cookie == NULL)
11533fbe39e1SAugustin Cavalier return B_NO_MEMORY;
11543fbe39e1SAugustin Cavalier
11553fbe39e1SAugustin Cavalier cookie->first = cookie->current = NULL;
11563fbe39e1SAugustin Cavalier *_cookie = (void*)cookie;
11573fbe39e1SAugustin Cavalier return B_OK;
11583fbe39e1SAugustin Cavalier }
11593fbe39e1SAugustin Cavalier
11603fbe39e1SAugustin Cavalier
11613fbe39e1SAugustin Cavalier 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)11623fbe39e1SAugustin Cavalier _ntfs_readdir_callback(void* _cookie, const ntfschar* ntfs_name, const int ntfs_name_len,
11633fbe39e1SAugustin Cavalier const int name_type, const s64 pos, const MFT_REF mref, const unsigned dt_type)
11643fbe39e1SAugustin Cavalier {
11653fbe39e1SAugustin Cavalier if (name_type == FILE_NAME_DOS)
11663fbe39e1SAugustin Cavalier return 0;
11673fbe39e1SAugustin Cavalier
11683fbe39e1SAugustin Cavalier directory_cookie* cookie = (directory_cookie*)_cookie;
11693fbe39e1SAugustin Cavalier
11703fbe39e1SAugustin Cavalier char* name = NULL;
11713fbe39e1SAugustin Cavalier int name_len = ntfs_ucstombs(ntfs_name, ntfs_name_len, &name, 0);
11723fbe39e1SAugustin Cavalier if (name_len <= 0 || name == NULL)
11733fbe39e1SAugustin Cavalier return -1;
11743fbe39e1SAugustin Cavalier MemoryDeleter nameDeleter(name);
11753fbe39e1SAugustin Cavalier
11763fbe39e1SAugustin Cavalier directory_cookie::entry* entry =
11773fbe39e1SAugustin Cavalier (directory_cookie::entry*)malloc(sizeof(directory_cookie::entry) + name_len);
11783fbe39e1SAugustin Cavalier if (entry == NULL)
11793fbe39e1SAugustin Cavalier return -1;
11803fbe39e1SAugustin Cavalier entry->next = NULL;
11813fbe39e1SAugustin Cavalier
11823fbe39e1SAugustin Cavalier entry->inode = MREF(mref);
11833fbe39e1SAugustin Cavalier entry->name_length = name_len;
11843fbe39e1SAugustin Cavalier memcpy(entry->name, name, name_len + 1);
11853fbe39e1SAugustin Cavalier
11863fbe39e1SAugustin Cavalier if (cookie->first == NULL) {
11873fbe39e1SAugustin Cavalier cookie->first = cookie->current = entry;
11883fbe39e1SAugustin Cavalier } else {
11893fbe39e1SAugustin Cavalier cookie->current->next = entry;
11903fbe39e1SAugustin Cavalier cookie->current = entry;
11913fbe39e1SAugustin Cavalier }
11923fbe39e1SAugustin Cavalier
11933fbe39e1SAugustin Cavalier return 0;
11943fbe39e1SAugustin Cavalier }
11953fbe39e1SAugustin Cavalier
11963fbe39e1SAugustin Cavalier
11973fbe39e1SAugustin Cavalier static status_t
fs_read_dir(fs_volume * _volume,fs_vnode * _node,void * _cookie,struct dirent * dirent,size_t bufferSize,uint32 * _num)11983fbe39e1SAugustin Cavalier fs_read_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie,
11993fbe39e1SAugustin Cavalier struct dirent* dirent, size_t bufferSize, uint32* _num)
12003fbe39e1SAugustin Cavalier {
12013fbe39e1SAugustin Cavalier CALLED();
12023fbe39e1SAugustin Cavalier directory_cookie* cookie = (directory_cookie*)_cookie;
12033fbe39e1SAugustin Cavalier
12043fbe39e1SAugustin Cavalier // TODO: While lowntfs-3g seems to also read the entire directory at once into memory,
12053fbe39e1SAugustin Cavalier // we could optimize things here by storing the data in the vnode, not the inode, and
12063fbe39e1SAugustin Cavalier // only freeing it after some period of inactivity.
12073fbe39e1SAugustin Cavalier
12083fbe39e1SAugustin Cavalier // See if we need to read the directory ourselves first.
12093fbe39e1SAugustin Cavalier if (cookie->first == NULL) {
12103fbe39e1SAugustin Cavalier volume* volume = (struct volume*)_volume->private_volume;
12113fbe39e1SAugustin Cavalier MutexLocker lock(volume->lock);
12123fbe39e1SAugustin Cavalier vnode* node = (vnode*)_node->private_node;
12133fbe39e1SAugustin Cavalier
12143fbe39e1SAugustin Cavalier ntfs_inode* ni = ntfs_inode_open(volume->ntfs, node->inode);
12153fbe39e1SAugustin Cavalier if (ni == NULL)
12163fbe39e1SAugustin Cavalier return errno;
12173fbe39e1SAugustin Cavalier NtfsInodeCloser niCloser(ni);
12183fbe39e1SAugustin Cavalier
12193fbe39e1SAugustin Cavalier s64 pos = 0;
12203fbe39e1SAugustin Cavalier if (ntfs_readdir(ni, &pos, cookie, _ntfs_readdir_callback) != 0)
12213fbe39e1SAugustin Cavalier return errno;
12223fbe39e1SAugustin Cavalier cookie->current = cookie->first;
12233fbe39e1SAugustin Cavalier }
12243fbe39e1SAugustin Cavalier if (cookie->first == NULL)
12253fbe39e1SAugustin Cavalier return ENOENT;
12263fbe39e1SAugustin Cavalier if (cookie->current == NULL) {
12273fbe39e1SAugustin Cavalier *_num = 0;
12283fbe39e1SAugustin Cavalier return B_OK;
12293fbe39e1SAugustin Cavalier }
12303fbe39e1SAugustin Cavalier
12313fbe39e1SAugustin Cavalier uint32 maxCount = *_num;
12323fbe39e1SAugustin Cavalier uint32 count = 0;
12333fbe39e1SAugustin Cavalier while (count < maxCount && bufferSize > sizeof(struct dirent)) {
1234711e2dc0SAugustin Cavalier size_t length = bufferSize - offsetof(struct dirent, d_name);
123575b68ba5SAugustin Cavalier if (length < (cookie->current->name_length + 1)) {
12363fbe39e1SAugustin Cavalier // the remaining name buffer length is too small
12373fbe39e1SAugustin Cavalier if (count == 0)
12383fbe39e1SAugustin Cavalier return B_BUFFER_OVERFLOW;
12393fbe39e1SAugustin Cavalier break;
12403fbe39e1SAugustin Cavalier }
12413fbe39e1SAugustin Cavalier length = cookie->current->name_length;
12423fbe39e1SAugustin Cavalier
12433fbe39e1SAugustin Cavalier dirent->d_dev = _volume->id;
12443fbe39e1SAugustin Cavalier dirent->d_ino = cookie->current->inode;
124523888052SAugustin Cavalier strlcpy(dirent->d_name, cookie->current->name, length + 1);
12463fbe39e1SAugustin Cavalier
12473c1cf7b2SAugustin Cavalier dirent = next_dirent(dirent, length, bufferSize);
12483fbe39e1SAugustin Cavalier count++;
12493fbe39e1SAugustin Cavalier
12503fbe39e1SAugustin Cavalier cookie->current = cookie->current->next;
12513fbe39e1SAugustin Cavalier if (cookie->current == NULL)
12523fbe39e1SAugustin Cavalier break;
12533fbe39e1SAugustin Cavalier }
12543fbe39e1SAugustin Cavalier
12553fbe39e1SAugustin Cavalier *_num = count;
12563fbe39e1SAugustin Cavalier return B_OK;
12573fbe39e1SAugustin Cavalier }
12583fbe39e1SAugustin Cavalier
12593fbe39e1SAugustin Cavalier
12603fbe39e1SAugustin Cavalier static status_t
fs_rewind_dir(fs_volume *,fs_vnode *,void * _cookie)12613fbe39e1SAugustin Cavalier fs_rewind_dir(fs_volume* /*_volume*/, fs_vnode* /*node*/, void *_cookie)
12623fbe39e1SAugustin Cavalier {
12633fbe39e1SAugustin Cavalier CALLED();
12643fbe39e1SAugustin Cavalier directory_cookie* cookie = (directory_cookie*)_cookie;
12653fbe39e1SAugustin Cavalier cookie->current = cookie->first;
12663fbe39e1SAugustin Cavalier return B_OK;
12673fbe39e1SAugustin Cavalier }
12683fbe39e1SAugustin Cavalier
12693fbe39e1SAugustin Cavalier
12703fbe39e1SAugustin Cavalier static status_t
fs_close_dir(fs_volume *,fs_vnode *,void *)12713fbe39e1SAugustin Cavalier fs_close_dir(fs_volume* /*_volume*/, fs_vnode* /*node*/, void* /*_cookie*/)
12723fbe39e1SAugustin Cavalier {
12733fbe39e1SAugustin Cavalier return B_OK;
12743fbe39e1SAugustin Cavalier }
12753fbe39e1SAugustin Cavalier
12763fbe39e1SAugustin Cavalier
12773fbe39e1SAugustin Cavalier static status_t
fs_free_dir_cookie(fs_volume * _volume,fs_vnode * _node,void * _cookie)12783fbe39e1SAugustin Cavalier fs_free_dir_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
12793fbe39e1SAugustin Cavalier {
12803fbe39e1SAugustin Cavalier CALLED();
12813fbe39e1SAugustin Cavalier directory_cookie* cookie = (directory_cookie*)_cookie;
12823fbe39e1SAugustin Cavalier if (cookie == NULL)
12833fbe39e1SAugustin Cavalier return B_OK;
12843fbe39e1SAugustin Cavalier
12853fbe39e1SAugustin Cavalier // Free entries.
12863fbe39e1SAugustin Cavalier cookie->current = cookie->first;
12873fbe39e1SAugustin Cavalier while (cookie->current != NULL) {
12883fbe39e1SAugustin Cavalier directory_cookie::entry* next = cookie->current->next;
12893fbe39e1SAugustin Cavalier free(cookie->current);
12903fbe39e1SAugustin Cavalier cookie->current = next;
12913fbe39e1SAugustin Cavalier }
12923fbe39e1SAugustin Cavalier
12933fbe39e1SAugustin Cavalier delete cookie;
12943fbe39e1SAugustin Cavalier return B_OK;
12953fbe39e1SAugustin Cavalier }
12963fbe39e1SAugustin Cavalier
12973fbe39e1SAugustin Cavalier
12983fbe39e1SAugustin Cavalier fs_volume_ops gNtfsVolumeOps = {
12993fbe39e1SAugustin Cavalier &fs_unmount,
13003fbe39e1SAugustin Cavalier &fs_read_fs_info,
13015070f597SAugustin Cavalier &fs_write_fs_info,
13023fbe39e1SAugustin Cavalier NULL, // fs_sync,
13033fbe39e1SAugustin Cavalier &fs_get_vnode,
13043fbe39e1SAugustin Cavalier };
13053fbe39e1SAugustin Cavalier
13063fbe39e1SAugustin Cavalier
13073fbe39e1SAugustin Cavalier fs_vnode_ops gNtfsVnodeOps = {
13083fbe39e1SAugustin Cavalier /* vnode operations */
13093fbe39e1SAugustin Cavalier &fs_lookup,
13103fbe39e1SAugustin Cavalier &fs_get_vnode_name,
13113fbe39e1SAugustin Cavalier &fs_put_vnode,
13125070f597SAugustin Cavalier &fs_remove_vnode,
13133fbe39e1SAugustin Cavalier
13143fbe39e1SAugustin Cavalier /* VM file access */
13153fbe39e1SAugustin Cavalier &fs_can_page,
13163fbe39e1SAugustin Cavalier &fs_read_pages,
13175070f597SAugustin Cavalier &fs_write_pages,
13183fbe39e1SAugustin Cavalier
13193fbe39e1SAugustin Cavalier NULL, // io
13203fbe39e1SAugustin Cavalier NULL, // cancel_io
13213fbe39e1SAugustin Cavalier
13223fbe39e1SAugustin Cavalier NULL, // get_file_map
13233fbe39e1SAugustin Cavalier
13243fbe39e1SAugustin Cavalier &fs_ioctl,
13253fbe39e1SAugustin Cavalier NULL,
13263fbe39e1SAugustin Cavalier NULL, // fs_select
13273fbe39e1SAugustin Cavalier NULL, // fs_deselect
13285070f597SAugustin Cavalier &fs_fsync,
13293fbe39e1SAugustin Cavalier
13303fbe39e1SAugustin Cavalier &fs_read_link,
13313fbe39e1SAugustin Cavalier NULL, // fs_create_symlink
13323fbe39e1SAugustin Cavalier
13333fbe39e1SAugustin Cavalier NULL, // fs_link,
13345070f597SAugustin Cavalier &fs_unlink,
13355070f597SAugustin Cavalier &fs_rename,
13363fbe39e1SAugustin Cavalier
13373fbe39e1SAugustin Cavalier &fs_access,
13383fbe39e1SAugustin Cavalier &fs_read_stat,
13395070f597SAugustin Cavalier &fs_write_stat,
13403fbe39e1SAugustin Cavalier NULL, // fs_preallocate
13413fbe39e1SAugustin Cavalier
13423fbe39e1SAugustin Cavalier /* file operations */
13435070f597SAugustin Cavalier &fs_create,
13443fbe39e1SAugustin Cavalier &fs_open,
13453fbe39e1SAugustin Cavalier &fs_close,
13463fbe39e1SAugustin Cavalier &fs_free_cookie,
13473fbe39e1SAugustin Cavalier &fs_read,
13485070f597SAugustin Cavalier &fs_write,
13493fbe39e1SAugustin Cavalier
13503fbe39e1SAugustin Cavalier /* directory operations */
13515070f597SAugustin Cavalier &fs_create_dir,
13525070f597SAugustin Cavalier &fs_remove_dir,
13533fbe39e1SAugustin Cavalier &fs_open_dir,
13543fbe39e1SAugustin Cavalier &fs_close_dir,
13553fbe39e1SAugustin Cavalier &fs_free_dir_cookie,
13563fbe39e1SAugustin Cavalier &fs_read_dir,
13573fbe39e1SAugustin Cavalier &fs_rewind_dir,
13583fbe39e1SAugustin Cavalier
13593fbe39e1SAugustin Cavalier /* attribute directory operations */
13603fbe39e1SAugustin Cavalier NULL, // fs_open_attr_dir,
13613fbe39e1SAugustin Cavalier NULL, // fs_close_attr_dir,
13623fbe39e1SAugustin Cavalier NULL, // fs_free_attr_dir_cookie,
13633fbe39e1SAugustin Cavalier NULL, // fs_read_attr_dir,
13643fbe39e1SAugustin Cavalier NULL, // fs_rewind_attr_dir,
13653fbe39e1SAugustin Cavalier
13663fbe39e1SAugustin Cavalier /* attribute operations */
13673fbe39e1SAugustin Cavalier NULL, // fs_create_attr,
13683fbe39e1SAugustin Cavalier NULL, // fs_open_attr,
13693fbe39e1SAugustin Cavalier NULL, // fs_close_attr,
13703fbe39e1SAugustin Cavalier NULL, // fs_free_attr_cookie,
13713fbe39e1SAugustin Cavalier NULL, // fs_read_attr,
13723fbe39e1SAugustin Cavalier NULL, // fs_write_attr,
13733fbe39e1SAugustin Cavalier NULL, // fs_read_attr_stat,
13743fbe39e1SAugustin Cavalier NULL, // fs_write_attr_stat,
13753fbe39e1SAugustin Cavalier NULL, // fs_rename_attr,
13763fbe39e1SAugustin Cavalier NULL, // fs_remove_attr,
13773fbe39e1SAugustin Cavalier };
13783fbe39e1SAugustin Cavalier
13793fbe39e1SAugustin Cavalier
13803fbe39e1SAugustin Cavalier static file_system_module_info sNtfsFileSystem = {
13813fbe39e1SAugustin Cavalier {
13823fbe39e1SAugustin Cavalier "file_systems/ntfs" B_CURRENT_FS_API_VERSION,
13833fbe39e1SAugustin Cavalier 0,
13843fbe39e1SAugustin Cavalier NULL,
13853fbe39e1SAugustin Cavalier },
13863fbe39e1SAugustin Cavalier
13873fbe39e1SAugustin Cavalier "ntfs", // short_name
13883fbe39e1SAugustin Cavalier "NT File System", // pretty_name
13895070f597SAugustin Cavalier
13905070f597SAugustin Cavalier // DDM flags
13915070f597SAugustin Cavalier 0
13925070f597SAugustin Cavalier | B_DISK_SYSTEM_IS_FILE_SYSTEM
13935070f597SAugustin Cavalier | B_DISK_SYSTEM_SUPPORTS_INITIALIZING
13945070f597SAugustin Cavalier | B_DISK_SYSTEM_SUPPORTS_WRITING
13955070f597SAugustin Cavalier ,
13963fbe39e1SAugustin Cavalier
13973fbe39e1SAugustin Cavalier // scanning
13983fbe39e1SAugustin Cavalier fs_identify_partition,
13993fbe39e1SAugustin Cavalier fs_scan_partition,
14003fbe39e1SAugustin Cavalier fs_free_identify_partition_cookie,
14013fbe39e1SAugustin Cavalier NULL, // free_partition_content_cookie()
14023fbe39e1SAugustin Cavalier
14033fbe39e1SAugustin Cavalier &fs_mount,
14043fbe39e1SAugustin Cavalier
14055070f597SAugustin Cavalier // capability querying operations
14065070f597SAugustin Cavalier NULL, // get_supported_operations
14075070f597SAugustin Cavalier
14085070f597SAugustin Cavalier NULL, // validate_resize
14095070f597SAugustin Cavalier NULL, // validate_move
14105070f597SAugustin Cavalier NULL, // validate_set_content_name
14115070f597SAugustin Cavalier NULL, // validate_set_content_parameters
14125070f597SAugustin Cavalier NULL, // validate_initialize,
14135070f597SAugustin Cavalier
14145070f597SAugustin Cavalier /* shadow partition modification */
14155070f597SAugustin Cavalier NULL, // shadow_changed
14165070f597SAugustin Cavalier
14175070f597SAugustin Cavalier /* writing */
14185070f597SAugustin Cavalier NULL, // defragment
14195070f597SAugustin Cavalier NULL, // repair
14205070f597SAugustin Cavalier NULL, // resize
14215070f597SAugustin Cavalier NULL, // move
14225070f597SAugustin Cavalier NULL, // set_content_name
14235070f597SAugustin Cavalier NULL, // set_content_parameters
14245070f597SAugustin Cavalier fs_initialize,
14255070f597SAugustin Cavalier NULL // uninitialize
14263fbe39e1SAugustin Cavalier };
14273fbe39e1SAugustin Cavalier
14283fbe39e1SAugustin Cavalier
14293fbe39e1SAugustin Cavalier module_info *modules[] = {
14303fbe39e1SAugustin Cavalier (module_info *)&sNtfsFileSystem,
14313fbe39e1SAugustin Cavalier NULL,
14323fbe39e1SAugustin Cavalier };
1433