📄 ntfs-3g.c
字号:
return ret;}static int ntfs_fuse_rename_existing_dest(const char *old_path, const char *new_path){ int ret, len; char *tmp; const char *ext = ".ntfs-3g-"; ntfs_log_trace("Entering"); len = strlen(new_path) + strlen(ext) + 10 + 1; /* wc(str(2^32)) + \0 */ tmp = ntfs_malloc(len); if (!tmp) return -errno; ret = snprintf(tmp, len, "%s%s%010d", new_path, ext, ++ntfs_sequence); if (ret != len - 1) { ntfs_log_error("snprintf failed: %d != %d\n", ret, len - 1); ret = -EOVERFLOW; } else ret = ntfs_fuse_safe_rename(old_path, new_path, tmp); free(tmp); return ret;}static int ntfs_fuse_rename(const char *old_path, const char *new_path){ 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; } ntfs_inode_close(ni); 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. */ ntfs_fuse_mark_free_space_outdated(); 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. */ ntfs_fuse_mark_free_space_outdated(); return ntfs_fuse_rm(path);}static int ntfs_fuse_utime(const char *path, struct utimbuf *buf){ ntfs_inode *ni; 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; ni->last_mft_change_time = buf->modtime; } else { time_t now; now = time(NULL); ni->last_access_time = now; ni->last_data_change_time = now; ni->last_mft_change_time = now; } NInoFileNameSetDirty(ni); NInoSetDirty(ni); if (ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode"); return 0;}static int ntfs_fuse_bmap(const char *path, size_t blocksize, uint64_t *idx){ ntfs_inode *ni; ntfs_attr *na; LCN lcn; int ret, 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; ret = 0; close_attr: ntfs_attr_close(na);close_inode: if (ntfs_inode_close(ni)) ntfs_log_perror("bmap: failed to close inode"); 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); ntfs_inode_close(ni); ntfs_log_debug("return %d\n", 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 = ' '; 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); ntfs_inode_close(ni); 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, 0); 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)) ntfs_log_perror("Failed to close inode"); 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, 0); 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; } ntfs_fuse_mark_free_space_outdated(); 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)) ntfs_log_perror("Failed to close inode"); 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, 0); 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; } ntfs_fuse_mark_free_space_outdated();exit: free(lename); if (ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode"); return res;}#endif /* HAVE_SETXATTR */static void ntfs_fuse_destroy(void){ if (!ctx) return; if (ctx->vol) { ntfs_log_info("Unmounting %s (%s)\n", opts.device, ctx->vol->vol_name); if (ntfs_umount(ctx->vol, FALSE)) ntfs_log_perror("Failed to unmount volume"); } free(ctx); ctx = NULL; free(opts.device);}static void ntfs_fuse_destroy2(void *unused __attribute__((unused))){ ntfs_fuse_destroy();}static struct fuse_operations ntfs_fuse_oper = { .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, .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_malloc(sizeof(ntfs_fuse_context_t)); if (!ctx) return -1; *ctx = (ntfs_fuse_context_t) { .state = NF_FreeClustersOutdate | NF_FreeMFTOutdate, .uid = geteuid(), .gid = getegid(), .fmask = 0, .dmask = 0, .streams = NF_STREAMS_INTERFACE_NONE, }; return 0;}static ntfs_volume *ntfs_open(const char *device, char *mntpoint, int blkdev){ unsigned long flags = 0; if (!blkdev) flags |= MS_EXCLUSIVE; if (ctx->ro) flags |= MS_RDONLY; if (ctx->noatime) flags |= MS_NOATIME; ctx->vol = utils_mount_volume(device, mntpoint, flags, ctx->force); return ctx->vol;}static void signal_handler(int arg __attribute__((unused))){ fuse_exit((fuse_get_context())->fuse);}static char *parse_mount_options(const char *orig_opts){ char *options, *s, *opt, *val, *ret; BOOL no_def_opts = FALSE; int default_permissions = 0; /* * +7 fsname= * +1 comma * +1 null-terminator * +21 ,blkdev,blksize=65536 * +20 ,default_permissions * +PATH_MAX resolved realpath() device name */ ret = ntfs_malloc(strlen(def_opts) + strlen(orig_opts) + 64 + PATH_MAX); if (!ret) return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -