📄 ntfs-3g.c
字号:
{ int ret, stream_name_len; char *path = NULL; ntfschar *stream_name; ntfs_inode *ni; ntfs_log_debug("rename: old: '%s' new: '%s'\n", old_path, new_path); /* * FIXME: Rename should be atomic. */ stream_name_len = ntfs_fuse_parse_path(new_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (ni) { ret = ntfs_check_empty_dir(ni); if (ret < 0) { ret = -errno; ntfs_inode_close(ni); goto out; } if (ntfs_inode_close(ni)) { set_fuse_error(&ret); goto out; } ret = ntfs_fuse_rename_existing_dest(old_path, new_path); goto out; } ret = ntfs_fuse_link(old_path, new_path); if (ret) goto out; ret = ntfs_fuse_unlink(old_path); if (ret) ntfs_fuse_unlink(new_path);out: free(path); if (stream_name_len) free(stream_name); return ret;}static int ntfs_fuse_mkdir(const char *path, mode_t mode __attribute__((unused))){ if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; /* n/a for named data streams. */ return ntfs_fuse_create(path, S_IFDIR, 0, NULL);}static int ntfs_fuse_rmdir(const char *path){ if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; /* n/a for named data streams. */ return ntfs_fuse_rm(path);}static int ntfs_fuse_utime(const char *path, struct utimbuf *buf){ ntfs_inode *ni; int res = 0; if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; /* n/a for named data streams. */ ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; if (buf) { ni->last_access_time = buf->actime; ni->last_data_change_time = buf->modtime; ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); } else ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME); if (ntfs_inode_close(ni)) set_fuse_error(&res); return res;}static int ntfs_fuse_bmap(const char *path, size_t blocksize, uint64_t *idx){ ntfs_inode *ni; ntfs_attr *na; LCN lcn; int ret = 0; int cl_per_bl = ctx->vol->cluster_size / blocksize; if (blocksize > ctx->vol->cluster_size) return -EINVAL; if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); if (!na) { ret = -errno; goto close_inode; } if (NAttrCompressed(na) || NAttrEncrypted(na) || !NAttrNonResident(na)){ ret = -EINVAL; goto close_attr; } if (ntfs_attr_map_whole_runlist(na)) { ret = -errno; goto close_attr; } lcn = ntfs_rl_vcn_to_lcn(na->rl, *idx / cl_per_bl); *idx = (lcn > 0) ? lcn * cl_per_bl + *idx % cl_per_bl : 0; close_attr: ntfs_attr_close(na);close_inode: if (ntfs_inode_close(ni)) set_fuse_error(&ret); return ret;}#ifdef HAVE_SETXATTRstatic const char nf_ns_xattr_preffix[] = "user.";static const int nf_ns_xattr_preffix_len = 5;static int ntfs_fuse_listxattr(const char *path, char *list, size_t size){ ntfs_attr_search_ctx *actx = NULL; ntfs_volume *vol; ntfs_inode *ni; char *to = list; int ret = 0; if (ctx->streams != NF_STREAMS_INTERFACE_XATTR) return -EOPNOTSUPP; vol = ctx->vol; if (!vol) return -ENODEV; ni = ntfs_pathname_to_inode(vol, NULL, path); if (!ni) return -errno; actx = ntfs_attr_get_search_ctx(ni, NULL); if (!actx) { ret = -errno; ntfs_inode_close(ni); goto exit; } while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, actx)) { char *tmp_name = NULL; int tmp_name_len; if (!actx->attr->name_length) continue; tmp_name_len = ntfs_ucstombs((ntfschar *)((u8*)actx->attr + le16_to_cpu(actx->attr->name_offset)), actx->attr->name_length, &tmp_name, 0); if (tmp_name_len < 0) { ret = -errno; goto exit; } ret += tmp_name_len + nf_ns_xattr_preffix_len + 1; if (size) { if ((size_t)ret <= size) { strcpy(to, nf_ns_xattr_preffix); to += nf_ns_xattr_preffix_len; strncpy(to, tmp_name, tmp_name_len); to += tmp_name_len; *to = 0; to++; } else { free(tmp_name); ret = -ERANGE; goto exit; } } free(tmp_name); } if (errno != ENOENT) ret = -errno;exit: if (actx) ntfs_attr_put_search_ctx(actx); if (ntfs_inode_close(ni)) set_fuse_error(&ret); return ret;}static int ntfs_fuse_getxattr_windows(const char *path, const char *name, char *value, size_t size){ ntfs_attr_search_ctx *actx = NULL; ntfs_volume *vol; ntfs_inode *ni; char *to = value; int ret = 0; if (strcmp(name, "ntfs.streams.list")) return -EOPNOTSUPP; vol = ctx->vol; if (!vol) return -ENODEV; ni = ntfs_pathname_to_inode(vol, NULL, path); if (!ni) return -errno; actx = ntfs_attr_get_search_ctx(ni, NULL); if (!actx) { ret = -errno; ntfs_inode_close(ni); goto exit; } while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, actx)) { char *tmp_name = NULL; int tmp_name_len; if (!actx->attr->name_length) continue; tmp_name_len = ntfs_ucstombs((ntfschar *)((u8*)actx->attr + le16_to_cpu(actx->attr->name_offset)), actx->attr->name_length, &tmp_name, 0); if (tmp_name_len < 0) { ret = -errno; goto exit; } if (ret) ret++; /* For space delimiter. */ ret += tmp_name_len; if (size) { if ((size_t)ret <= size) { /* Don't add space to the beginning of line. */ if (to != value) { *to = '\0'; to++; } strncpy(to, tmp_name, tmp_name_len); to += tmp_name_len; } else { free(tmp_name); ret = -ERANGE; goto exit; } } free(tmp_name); } if (errno != ENOENT) ret = -errno;exit: if (actx) ntfs_attr_put_search_ctx(actx); if (ntfs_inode_close(ni)) set_fuse_error(&ret); return ret;}static int ntfs_fuse_getxattr(const char *path, const char *name, char *value, size_t size){ ntfs_volume *vol; ntfs_inode *ni; ntfs_attr *na = NULL; ntfschar *lename = NULL; int res, lename_len; if (ctx->streams == NF_STREAMS_INTERFACE_WINDOWS) return ntfs_fuse_getxattr_windows(path, name, value, size); if (ctx->streams != NF_STREAMS_INTERFACE_XATTR) return -EOPNOTSUPP; if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) || strlen(name) == (size_t)nf_ns_xattr_preffix_len) return -ENODATA; vol = ctx->vol; if (!vol) return -ENODEV; ni = ntfs_pathname_to_inode(vol, NULL, path); if (!ni) return -errno; lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename); if (lename_len == -1) { res = -errno; goto exit; } na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); if (!na) { res = -ENODATA; goto exit; } if (size) { if (size >= na->data_size) { res = ntfs_attr_pread(na, 0, na->data_size, value); if (res != na->data_size) res = -errno; } else res = -ERANGE; } else res = na->data_size;exit: if (na) ntfs_attr_close(na); free(lename); if (ntfs_inode_close(ni)) set_fuse_error(&res); return res;}static int ntfs_fuse_setxattr(const char *path, const char *name, const char *value, size_t size, int flags){ ntfs_volume *vol; ntfs_inode *ni; ntfs_attr *na = NULL; ntfschar *lename = NULL; int res, lename_len; if (ctx->streams != NF_STREAMS_INTERFACE_XATTR) return -EOPNOTSUPP; if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) || strlen(name) == (size_t)nf_ns_xattr_preffix_len) return -EACCES; vol = ctx->vol; if (!vol) return -ENODEV; ni = ntfs_pathname_to_inode(vol, NULL, path); if (!ni) return -errno; lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename); if (lename_len == -1) { res = -errno; goto exit; } na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); if (na && flags == XATTR_CREATE) { res = -EEXIST; goto exit; } if (!na) { if (flags == XATTR_REPLACE) { res = -ENODATA; goto exit; } if (ntfs_attr_add(ni, AT_DATA, lename, lename_len, NULL, 0)) { res = -errno; goto exit; } na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); if (!na) { res = -errno; goto exit; } } res = ntfs_attr_pwrite(na, 0, size, value); if (res != (s64) size) res = -errno; else res = 0;exit: if (na) ntfs_attr_close(na); free(lename); if (ntfs_inode_close(ni)) set_fuse_error(&res); return res;}static int ntfs_fuse_removexattr(const char *path, const char *name){ ntfs_volume *vol; ntfs_inode *ni; ntfschar *lename = NULL; int res = 0, lename_len; if (ctx->streams != NF_STREAMS_INTERFACE_XATTR) return -EOPNOTSUPP; if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) || strlen(name) == (size_t)nf_ns_xattr_preffix_len) return -ENODATA; vol = ctx->vol; if (!vol) return -ENODEV; ni = ntfs_pathname_to_inode(vol, NULL, path); if (!ni) return -errno; lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename); if (lename_len == -1) { res = -errno; goto exit; } if (ntfs_attr_remove(ni, AT_DATA, lename, lename_len)) { if (errno == ENOENT) errno = ENODATA; res = -errno; } exit: free(lename); if (ntfs_inode_close(ni)) set_fuse_error(&res); return res;}#endif /* HAVE_SETXATTR */static void ntfs_close(void){ if (!ctx) return; if (!ctx->vol) return; if (ctx->mounted) ntfs_log_info("Unmounting %s (%s)\n", opts.device, ctx->vol->vol_name); if (ntfs_umount(ctx->vol, FALSE)) ntfs_log_perror("Failed to close volume %s", opts.device); ctx->vol = NULL;}static void ntfs_fuse_destroy2(void *unused __attribute__((unused))){ ntfs_close();}static struct fuse_operations ntfs_3g_ops = { .getattr = ntfs_fuse_getattr, .readlink = ntfs_fuse_readlink, .readdir = ntfs_fuse_readdir, .open = ntfs_fuse_open, .read = ntfs_fuse_read, .write = ntfs_fuse_write, .truncate = ntfs_fuse_truncate, .statfs = ntfs_fuse_statfs, .chmod = ntfs_fuse_chmod, .chown = ntfs_fuse_chown, .create = ntfs_fuse_create_file, .mknod = ntfs_fuse_mknod, .symlink = ntfs_fuse_symlink, .link = ntfs_fuse_link, .unlink = ntfs_fuse_unlink, .rename = ntfs_fuse_rename, .mkdir = ntfs_fuse_mkdir, .rmdir = ntfs_fuse_rmdir, .utime = ntfs_fuse_utime, .bmap = ntfs_fuse_bmap, .destroy = ntfs_fuse_destroy2,#ifdef HAVE_SETXATTR .getxattr = ntfs_fuse_getxattr, .setxattr = ntfs_fuse_setxattr, .removexattr = ntfs_fuse_removexattr, .listxattr = ntfs_fuse_listxattr,#endif /* HAVE_SETXATTR */};static int ntfs_fuse_init(void){ ctx = ntfs_calloc(sizeof(ntfs_fuse_context_t)); if (!ctx) return -1; *ctx = (ntfs_fuse_context_t) { .uid = getuid(), .gid = getgid(), .streams = NF_STREAMS_INTERFACE_NONE, }; return 0;}static int ntfs_open(const char *device){ unsigned long flags = 0; if (!ctx->blkdev) flags |= MS_EXCLUSIVE; if (ctx->ro) flags |= MS_RDONLY; if (ctx->force) flags |= MS_FORCE; if (ctx->hiberfile) flags |= MS_IGNORE_HIBERFILE; ctx->vol = ntfs_mount(device, flags); if (!ctx->vol) { ntfs_log_perror("Failed to mount '%s'", device); goto err_out; } ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na); if (ctx->vol->free_clusters < 0) { ntfs_log_perror("Failed to read NTFS $Bitmap"); goto err_out; } ctx->vol->free_mft_records = ntfs_get_nr_free_mft_records(ctx->vol); if (ctx->vol->free_mft_records < 0) { ntfs_log_perror("Failed to calculate free MFT records"); goto err_out; } if (ctx->hiberfile && ntfs_volume_check_hiberfile(ctx->vol, 0)) { if (errno != EPERM) goto err_out; if (ntfs_fuse_rm("/hiberfil.sys")) goto err_out; } errno = 0;err_out: return ntfs_volume_error(errno); }#define STRAPPEND_MAX_INSIZE 8192#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)static int strappend(char **dest, const char *append){ char *p; size_t size_append, size_dest = 0; if (!dest) return -1; if (!append) return 0; size_append = strlen(append); if (*dest) size_dest = strlen(*dest); if (strappend_is_large(size_dest) || strappend_is_large(size_append)) { errno = EOVERFLOW; ntfs_log_perror("%s: Too large input buffer", EXEC_NAME); return -1; } p = realloc(*dest, size_dest + size_append + 1); if (!p) { ntfs_log_perror("%s: Memory realloction failed", EXEC_NAME); return -1; } *dest = p; strcpy(*dest + size_dest, append); return 0;}static int bogus_option_value(char *val, const char *s){ if (val) { ntfs_log_error("'%s' option shouldn't have value.\n", s); return -1; } return 0;}static int missing_option_value(char *val, const char *s){ if (!val) { ntfs_log_error("'%s' option should have a value.\n", s); return -1; } return 0;}static char *parse_mount_options(const char *orig_opts){ char *options, *s, *opt, *val, *ret = NULL; BOOL no_def_opts = FALSE; int default_permissions = 0; options = strdup(orig_opts ? orig_opts : ""); if (!options) { ntfs_log_perror("%s: strdup failed", EXEC_NAME);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -