📄 ntfs-3g.c
字号:
ntfs_log_error("ntfs_attr_pread returned less bytes " "than requested.\n"); if (res <= 0) { res = -errno; goto exit; } size -= res; offset += res; total += res; } res = total;exit: if (na) ntfs_attr_close(na); if (ni && ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode"); free(path); if (stream_name_len) free(stream_name); return res;}static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi __attribute__((unused))){ ntfs_volume *vol; ntfs_inode *ni = NULL; ntfs_attr *na = NULL; char *path = NULL; ntfschar *stream_name; int stream_name_len, res, total = 0; stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; vol = ctx->vol; ni = ntfs_pathname_to_inode(vol, NULL, path); if (!ni) { res = -errno; goto exit; } na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (!na) { res = -errno; goto exit; } while (size) { res = ntfs_attr_pwrite(na, offset, size, buf); if (res < (s64)size) ntfs_log_error("ntfs_attr_pwrite returned less bytes " "than requested.\n"); if (res <= 0) { res = -errno; goto exit; } size -= res; offset += res; total += res; } res = total;exit: ntfs_fuse_mark_free_space_outdated(); if (na) ntfs_attr_close(na); if (ni && ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode"); free(path); if (stream_name_len) free(stream_name); return res;}static int ntfs_fuse_truncate(const char *org_path, off_t size){ ntfs_volume *vol; ntfs_inode *ni = NULL; ntfs_attr *na; int res; char *path = NULL; ntfschar *stream_name; int stream_name_len; stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; vol = ctx->vol; ni = ntfs_pathname_to_inode(vol, NULL, path); if (!ni) { res = -errno; goto exit; } na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (!na) { res = -errno; goto exit; } res = ntfs_attr_truncate(na, size); // FIXME: check the usage and the importance of the return value if (res) res = -1; ntfs_fuse_mark_free_space_outdated(); ntfs_attr_close(na);exit: if (ni && ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode"); free(path); if (stream_name_len) free(stream_name); return res;}static int ntfs_fuse_chmod(const char *path, mode_t mode __attribute__((unused))){ if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; /* n/a for named data streams. */ if (ctx->silent) return 0; return -EOPNOTSUPP;}static int ntfs_fuse_chown(const char *path, uid_t uid, gid_t gid){ if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; /* n/a for named data streams. */ if (ctx->silent) return 0; if (uid == ctx->uid && gid == ctx->gid) return 0; return -EOPNOTSUPP;}static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev, const char *target){ char *name; ntfschar *uname = NULL, *utarget = NULL; ntfs_inode *dir_ni = NULL, *ni; char *path; int res = 0, uname_len, utarget_len; path = strdup(org_path); if (!path) return -errno; /* Generate unicode filename. */ name = strrchr(path, '/'); name++; uname_len = ntfs_mbstoucs(name, &uname, 0); if (uname_len < 0) { res = -errno; goto exit; } /* Open parent directory. */ *name = 0; dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!dir_ni) { res = -errno; goto exit; } /* Create object specified in @type. */ switch (type) { case S_IFCHR: case S_IFBLK: ni = ntfs_create_device(dir_ni, uname, uname_len, type, dev); break; case S_IFLNK: utarget_len = ntfs_mbstoucs(target, &utarget, 0); if (utarget_len < 0) { res = -errno; goto exit; } ni = ntfs_create_symlink(dir_ni, uname, uname_len, utarget, utarget_len); break; default: ni = ntfs_create(dir_ni, uname, uname_len, type); break; } if (ni) ntfs_inode_close(ni); else res = -errno;exit: free(uname); if (dir_ni) ntfs_inode_close(dir_ni); if (utarget) free(utarget); free(path); return res;}static int ntfs_fuse_create_stream(const char *path, ntfschar *stream_name, const int stream_name_len){ ntfs_inode *ni; int res = 0; ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) { res = -errno; if (res == -ENOENT) { /* * If such file does not exist, create it and try once * again to add stream to it. */ res = ntfs_fuse_create(path, S_IFREG, 0, NULL); if (!res) return ntfs_fuse_create_stream(path, stream_name, stream_name_len); else res = -errno; } return res; } if (ntfs_attr_add(ni, AT_DATA, stream_name, stream_name_len, NULL, 0)) res = -errno; if (ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode"); return res;}static int ntfs_fuse_mknod(const char *org_path, mode_t mode, dev_t dev){ char *path = NULL; ntfschar *stream_name; int stream_name_len; int res = 0; stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; if (stream_name_len && !S_ISREG(mode)) { res = -EINVAL; goto exit; } if (!stream_name_len) res = ntfs_fuse_create(path, mode & S_IFMT, dev, NULL); else res = ntfs_fuse_create_stream(path, stream_name, stream_name_len); ntfs_fuse_mark_free_space_outdated();exit: free(path); if (stream_name_len) free(stream_name); return res;}static int ntfs_fuse_symlink(const char *to, const char *from){ if (ntfs_fuse_is_named_data_stream(from)) return -EINVAL; /* n/a for named data streams. */ ntfs_fuse_mark_free_space_outdated(); return ntfs_fuse_create(from, S_IFLNK, 0, to);}static int ntfs_fuse_link(const char *old_path, const char *new_path){ char *name; ntfschar *uname = NULL; ntfs_inode *dir_ni = NULL, *ni; char *path; int res = 0, uname_len; if (ntfs_fuse_is_named_data_stream(old_path)) return -EINVAL; /* n/a for named data streams. */ if (ntfs_fuse_is_named_data_stream(new_path)) return -EINVAL; /* n/a for named data streams. */ path = strdup(new_path); if (!path) return -errno; /* Open file for which create hard link. */ ni = ntfs_pathname_to_inode(ctx->vol, NULL, old_path); if (!ni) { res = -errno; goto exit; } /* Generate unicode filename. */ name = strrchr(path, '/'); name++; uname_len = ntfs_mbstoucs(name, &uname, 0); if (uname_len < 0) { res = -errno; goto exit; } /* Open parent directory. */ *name = 0; dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!dir_ni) { res = -errno; goto exit; } ntfs_fuse_mark_free_space_outdated(); /* Create hard link. */ if (ntfs_link(ni, dir_ni, uname, uname_len)) res = -errno;exit: if (ni) ntfs_inode_close(ni); free(uname); if (dir_ni) ntfs_inode_close(dir_ni); free(path); return res;}static int ntfs_fuse_rm(const char *org_path){ char *name; ntfschar *uname = NULL; ntfs_inode *dir_ni = NULL, *ni; char *path; int res = 0, uname_len; path = strdup(org_path); if (!path) return -errno; /* Open object for delete. */ ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) { res = -errno; goto exit; } /* Generate unicode filename. */ name = strrchr(path, '/'); name++; uname_len = ntfs_mbstoucs(name, &uname, 0); if (uname_len < 0) { res = -errno; goto exit; } /* Open parent directory. */ *name = 0; dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!dir_ni) { res = -errno; goto exit; } /* Delete object. */ if (ntfs_delete(ni, dir_ni, uname, uname_len)) res = -errno; ni = NULL;exit: if (ni) ntfs_inode_close(ni); free(uname); if (dir_ni) ntfs_inode_close(dir_ni); free(path); return res;}static int ntfs_fuse_rm_stream(const char *path, ntfschar *stream_name, const int stream_name_len){ ntfs_inode *ni; ntfs_attr *na; int res = 0; ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (!na) { res = -errno; goto exit; } if (ntfs_attr_rm(na)) { res = -errno; ntfs_attr_close(na); }exit: if (ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode"); return res;}static int ntfs_fuse_unlink(const char *org_path){ char *path = NULL; ntfschar *stream_name; int stream_name_len; int res = 0; stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; if (!stream_name_len) res = ntfs_fuse_rm(path); else res = ntfs_fuse_rm_stream(path, stream_name, stream_name_len); ntfs_fuse_mark_free_space_outdated(); free(path); if (stream_name_len) free(stream_name); return res;}static int ntfs_fuse_rename(const char *old_path, const char *new_path){ int ret; if ((ret = ntfs_fuse_link(old_path, new_path))) return ret; if ((ret = ntfs_fuse_unlink(old_path))) { ntfs_fuse_unlink(new_path); return ret; } return 0;}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;}#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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -