📄 ntfs-3g.c
字号:
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_fuse_update_times(ni, NTFS_UPDATE_ATIME); if (ntfs_inode_close(ni)) set_fuse_error(&err); 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; if (ntfs_inode_close(ni)) set_fuse_error(&res); } 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_inode *ni = NULL; ntfs_attr *na = NULL; char *path = NULL; ntfschar *stream_name; int stream_name_len, res; s64 total = 0; if (!size) return 0; stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; ni = ntfs_pathname_to_inode(ctx->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) { if (na->data_size < offset) goto ok; size = na->data_size - offset; } while (size > 0) { s64 ret = ntfs_attr_pread(na, offset, size, buf); if (ret != (s64)size) ntfs_log_perror("ntfs_attr_pread error reading '%s' at " "offset %lld: %lld <> %lld", org_path, (long long)offset, (long long)size, (long long)ret); if (ret <= 0 || ret > (s64)size) { res = (ret < 0) ? -errno : -EIO; goto exit; } size -= ret; offset += ret; total += ret; }ok: ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME); res = total;exit: if (na) ntfs_attr_close(na); if (ntfs_inode_close(ni)) set_fuse_error(&res); 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) ntfs_log_perror("ntfs_attr_pwrite partial write (%lld: " "%lld <> %d)", (long long)offset, (long long)size, res); if (res <= 0) { res = -errno; goto exit; } size -= res; offset += res; total += res; } res = total; if (res > 0) ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);exit: if (na) ntfs_attr_close(na); if (ntfs_inode_close(ni)) set_fuse_error(&res); 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 = NULL; 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) goto exit; na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (!na) goto exit; if (ntfs_attr_truncate(na, size)) goto exit; ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); errno = 0;exit: res = -errno; ntfs_attr_close(na); if (ntfs_inode_close(ni)) set_fuse_error(&res); 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); 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); 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) { if (ntfs_inode_close(ni)) set_fuse_error(&res); ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME); } else res = -errno;exit: free(uname); if (ntfs_inode_close(dir_ni)) set_fuse_error(&res); 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)) set_fuse_error(&res); return res;}static int ntfs_fuse_create_file(const char *org_path, mode_t mode, struct fuse_file_info *fi __attribute__((unused))){ char *path = NULL; ntfschar *stream_name; int stream_name_len; int res; 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_create(path, mode & S_IFMT, 0, NULL); else res = ntfs_fuse_create_stream(path, stream_name, stream_name_len); free(path); if (stream_name_len) free(stream_name); 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);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. */ 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); 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; } if (ntfs_link(ni, dir_ni, uname, uname_len)) { res = -errno; goto exit; } ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME);exit: /* * Must close dir_ni first otherwise ntfs_inode_sync_file_name(ni) * may fail because ni may not be in parent's index on the disk yet. */ if (ntfs_inode_close(dir_ni)) set_fuse_error(&res); if (ntfs_inode_close(ni)) set_fuse_error(&res); free(uname); 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); 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; } if (ntfs_delete(ni, dir_ni, uname, uname_len)) res = -errno; /* ntfs_delete() always closes ni and dir_ni */ ni = dir_ni = NULL;exit: if (ntfs_inode_close(dir_ni)) set_fuse_error(&res); if (ntfs_inode_close(ni)) set_fuse_error(&res); free(uname); 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)) set_fuse_error(&res); 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); 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\n"); 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); } 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\n"); 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -