status_t fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, off_t pos, const void *buffer, size_t *_length) { nspace *ns = (nspace *)_vol->private_volume; vnode *node = (vnode *)_node->private_node; attrcookie *cookie = (attrcookie *)_cookie; ntfs_inode *ni = NULL; ntfs_attr *na = NULL; size_t size = *_length; char *attr_name = NULL; char *real_name = NULL; int total = 0; status_t result = B_NO_ERROR; TRACE("%s - ENTER vnode: %d\n", __FUNCTION__, node->vnid); if (ns->flags & B_FS_IS_READONLY) { return B_READ_ONLY_DEVICE; } if (pos < 0) { *_length = 0; return EINVAL; } LOCK_VOL(ns); ni = ntfs_inode_open(ns->ntvol, node->vnid); if (ni == NULL) { result = errno; goto exit; } na = ntfs_attr_open(ni, AT_DATA, cookie->uname, cookie->uname_len); if (na == NULL) { result = errno; goto exit; } pos += sizeof(uint32); // it is a named stream if (na != NULL) { if (cookie->omode & O_APPEND) pos = na->data_size; if (pos + size > na->data_size) { ntfs_mark_free_space_outdated(ns); if (ntfs_attr_truncate(na, pos + size)) size = na->data_size - pos; else notify_stat_changed(ns->id, MREF(ni->mft_no), B_STAT_SIZE); } while (size) { off_t bytesWritten = ntfs_attr_pwrite(na, pos, size, buffer); if (bytesWritten < (s64)size) ERROR("%s - ntfs_attr_pwrite returned less bytes than " "requested.\n", __FUNCTION__); if (bytesWritten <= 0) { ERROR("%s - ntfs_attr_pwrite()<=0\n", __FUNCTION__); *_length = 0; result = EINVAL; goto exit; } size -= bytesWritten; pos += bytesWritten; total += bytesWritten; } *_length = total; } else { *_length = 0; result = EINVAL; goto exit; } if (ntfs_ucstombs(na->name, na->name_len, &attr_name, 0) >= 0) { if (attr_name != NULL) { if(strncmp(attr_name, kHaikuAttrPrefix, strlen(kHaikuAttrPrefix)) !=0 ) goto exit; real_name = attr_name + strlen(kHaikuAttrPrefix); notify_attribute_changed(ns->id, MREF(ni->mft_no), real_name, B_ATTR_CHANGED); free(attr_name); } } exit: if (na != NULL) ntfs_attr_close(na); if (ni != NULL) ntfs_inode_close(ni); TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result)); UNLOCK_VOL(ns); return result; }
status_t fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie,off_t pos, const void *buffer, size_t *_length) { nspace *ns = (nspace *)_vol->private_volume; //vnode *node = (vnode *)_node->private_node; attrcookie *cookie = (attrcookie *)_cookie; ntfs_inode *ni = cookie->inode; ntfs_attr *na = cookie->stream; size_t size = *_length; int total = 0; status_t result = B_NO_ERROR; TRACE("%s - ENTER!!\n", __FUNCTION__); if (ns->flags & B_FS_IS_READONLY) { ERROR("ntfs is read-only\n"); return EROFS; } if (pos < 0) { *_length = 0; return EINVAL; } LOCK_VOL(ns); TRACE("%s - ENTER\n", __FUNCTION__); // it is a named stream if (na) { if (cookie->omode & O_APPEND) pos = na->data_size; if (pos + size > na->data_size) { ntfs_mark_free_space_outdated(ns); if (ntfs_attr_truncate(na, pos + size)) size = na->data_size - pos; else notify_stat_changed(ns->id, MREF(ni->mft_no), B_STAT_SIZE); } while (size) { off_t bytesWritten = ntfs_attr_pwrite(na, pos, size, buffer); if (bytesWritten < (s64)size) ERROR("%s - ntfs_attr_pwrite returned less bytes than " "requested.\n", __FUNCTION__); if (bytesWritten <= 0) { ERROR(("%s - ntfs_attr_pwrite()<=0\n", __FUNCTION__)); *_length = 0; result = EINVAL; goto exit; } size -= bytesWritten; pos += bytesWritten; total += bytesWritten; } *_length = total; } else { *_length = 0; return EINVAL; } if (total > 0) fs_ntfs_update_times(_vol, ni, NTFS_UPDATE_ATIME); // XXX needed ? exit: TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result)); UNLOCK_VOL(ns); return result; }
status_t fs_mount(fs_volume *_vol, const char *device, ulong flags, const char *args, ino_t *_rootID) { nspace *ns; vnode *newNode = NULL; char lockname[32]; void *handle; unsigned long mountFlags = 0; status_t result = B_NO_ERROR; ERRPRINT("fs_mount - ENTER\n"); ns = ntfs_malloc(sizeof(nspace)); if (!ns) { result = ENOMEM; goto exit; } *ns = (nspace) { .state = NF_FreeClustersOutdate | NF_FreeMFTOutdate, .show_sys_files = false, .ro = false, .flags = 0 }; strcpy(ns->devicePath,device); sprintf(lockname, "ntfs_lock %lx", ns->id); recursive_lock_init_etc(&(ns->vlock), lockname, MUTEX_FLAG_CLONE_NAME); handle = load_driver_settings("ntfs"); ns->show_sys_files = ! (strcasecmp(get_driver_parameter(handle, "hide_sys_files", "true", "true"), "true") == 0); ns->ro = strcasecmp(get_driver_parameter(handle, "read_only", "false", "false"), "false") != 0; ns->noatime = strcasecmp(get_driver_parameter(handle, "no_atime", "true", "true"), "true") == 0; unload_driver_settings(handle); if (ns->ro || (flags & B_MOUNT_READ_ONLY) != 0) { mountFlags |= MS_RDONLY; ns->flags |= B_FS_IS_READONLY; } // TODO: this does not take read-only volumes into account! ns->ntvol = utils_mount_volume(device, mountFlags, true); if (ns->ntvol != NULL) result = B_NO_ERROR; else result = errno; if (result == B_NO_ERROR) { *_rootID = FILE_root; ns->id = _vol->id; _vol->private_volume = (void *)ns; _vol->ops = &gNTFSVolumeOps; newNode = (vnode*)ntfs_calloc(sizeof(vnode)); if (newNode == NULL) result = ENOMEM; else { newNode->vnid = *_rootID; newNode->parent_vnid = -1; result = publish_vnode(_vol, *_rootID, (void*)newNode, &gNTFSVnodeOps, S_IFDIR, 0); if (result != B_NO_ERROR) { free(ns); result = EINVAL; goto exit; } else { result = B_NO_ERROR; ntfs_mark_free_space_outdated(ns); ntfs_calc_free_space(ns); } } } exit: ERRPRINT("fs_mount - EXIT, result code is %s\n", strerror(result)); return result; } status_t fs_unmount(fs_volume *_vol) { nspace *ns = (nspace*)_vol->private_volume; status_t result = B_NO_ERROR; ERRPRINT("fs_unmount - ENTER\n"); ntfs_umount(ns->ntvol, true); recursive_lock_destroy(&(ns->vlock)); free(ns); ERRPRINT("fs_unmount - EXIT, result is %s\n", strerror(result)); return result; }