📄 ntfs-3g.c
字号:
return res;}static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, const ntfschar *name, const int name_len, const int name_type, const s64 pos __attribute__((unused)), const MFT_REF mref, const unsigned dt_type __attribute__((unused))){ char *filename = NULL; if (name_type == FILE_NAME_DOS) return 0; if (ntfs_ucstombs(name, name_len, &filename, 0) < 0) { ntfs_log_perror("Skipping unrepresentable filename (inode %llu)", (unsigned long long)MREF(mref)); return 0; } if (ntfs_fuse_is_named_data_stream(filename)) { ntfs_log_error("Unable to access '%s' (inode %llu) with " "current named streams access interface.\n", filename, (unsigned long long)MREF(mref)); free(filename); return 0; } if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || ctx->show_sys_files) { struct stat st = { .st_ino = MREF(mref) }; fill_ctx->filler(fill_ctx->buf, filename, &st, 0); } free(filename); return 0;}static int ntfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset __attribute__((unused)), struct fuse_file_info *fi __attribute__((unused))){ ntfs_fuse_fill_context_t fill_ctx; ntfs_volume *vol; ntfs_inode *ni; s64 pos = 0; int err = 0; vol = ctx->vol; fill_ctx.filler = filler; fill_ctx.buf = buf; ni = ntfs_pathname_to_inode(vol, NULL, path); if (!ni) return -errno; if (ntfs_readdir(ni, &pos, &fill_ctx, (ntfs_filldir_t)ntfs_fuse_filler)) err = -errno; ntfs_inode_close(ni); return err;}static int ntfs_fuse_open(const char *org_path, struct fuse_file_info *fi __attribute__((unused))){ ntfs_volume *vol; ntfs_inode *ni; ntfs_attr *na; int res = 0; 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) { na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (na) { if (NAttrEncrypted(na)) res = -EACCES; ntfs_attr_close(na); } else res = -errno; ntfs_inode_close(ni); } else res = -errno; free(path); if (stream_name_len) free(stream_name); return res;}static int ntfs_fuse_read(const char *org_path, 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; } if (offset + size > na->data_size) size = na->data_size - offset; while (size) { res = ntfs_attr_pread(na, offset, size, buf); if (res < (s64)size) 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) { res = stream_name_len; goto out; } 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 && errno != ENOSPC) ntfs_log_perror("ntfs_attr_pwrite partial write (%lld: " "%lld <> %d)", (s64)offset, (s64)size, res); 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);out: 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; int res = 0; ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; if (ntfs_attr_remove(ni, AT_DATA, stream_name, stream_name_len)) res = -errno; 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_safe_rename(const char *old_path, const char *new_path, const char *tmp){ int ret; ntfs_log_trace("Entering"); ret = ntfs_fuse_link(new_path, tmp); if (ret) return ret; ret = ntfs_fuse_unlink(new_path); if (!ret) { ret = ntfs_fuse_link(old_path, new_path); if (ret) goto restore; ret = ntfs_fuse_unlink(old_path); if (ret) { if (ntfs_fuse_unlink(new_path)) goto err; goto restore; } } goto cleanup;restore: if (ntfs_fuse_link(tmp, new_path)) {err: ntfs_log_perror("Rename failed. Existing file '%s' was renamed " "to '%s'", new_path, tmp); } else {cleanup: ntfs_fuse_unlink(tmp); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -