📄 ntfs-3g.c
字号:
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; ntfs_attr *na = NULL; 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; } na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); if (!na) { res = -ENODATA; goto exit; } ntfs_fuse_mark_free_space_outdated(); if (ntfs_attr_rm(na)) res = -errno; else na = NULL;exit: if (na) ntfs_attr_close(na); free(lename); if (ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode"); return res;}#endif /* HAVE_SETXATTR */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,#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 = 0177, .dmask = 0077, .streams = NF_STREAMS_INTERFACE_NONE, }; return 0;}static int ntfs_fuse_mount(const char *device){ ntfs_volume *vol; vol = utils_mount_volume(device, ((ctx->ro) ? MS_RDONLY : 0) | ((ctx->noatime) ? MS_NOATIME : 0), ctx->force); if (!vol) { ntfs_log_error("Mount failed.\n"); return -1; } ctx->vol = vol; return 0;}static void ntfs_fuse_destroy(void){ 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); free(opts.device);}static void signal_handler(int arg __attribute__((unused))){ fuse_exit((fuse_get_context())->fuse);}static char *parse_mount_options(const char *org_options){ char *options, *s, *opt, *val, *ret; BOOL no_def_opts = FALSE; /* * +7 for "fsname=". * +1 for comma. * +1 for null-terminator. * +PATH_MAX for resolved by realpath() device name. */ ret = ntfs_malloc(strlen(def_opts) + strlen(org_options) + 9 + PATH_MAX); if (!ret) return NULL; *ret = 0; options = strdup(org_options); if (!options) { ntfs_log_perror("strdup failed"); return NULL; } /* * FIXME: Due to major performance hit and interference * issues, always use the 'noatime' options for now. */ ctx->noatime = TRUE; strcat(ret, "noatime,"); s = options; while ((val = strsep(&s, ","))) { opt = strsep(&val, "="); if (!strcmp(opt, "ro")) { /* Read-only mount. */ if (val) { ntfs_log_error("'ro' option should not have " "value.\n"); goto err_exit; } ctx->ro = TRUE; strcat(ret, "ro,"); } else if (!strcmp(opt, "noatime")) { if (val) { ntfs_log_error("'noatime' option should not " "have value.\n"); goto err_exit; } } else if (!strcmp(opt, "fake_rw")) { if (val) { ntfs_log_error("'fake_rw' option should not " "have value.\n"); goto err_exit; } ctx->ro = TRUE; } else if (!strcmp(opt, "fsname")) { /* Filesystem name. */ /* * We need this to be able to check whether filesystem * mounted or not. */ ntfs_log_error("'fsname' is unsupported option.\n"); goto err_exit; } else if (!strcmp(opt, "no_def_opts")) { if (val) { ntfs_log_error("'no_def_opts' option should " "not have value.\n"); goto err_exit; } no_def_opts = TRUE; /* Don't add default options. */ } else if (!strcmp(opt, "umask")) { if (!val) { ntfs_log_error("'umask' option should have " "value.\n"); goto err_exit; } sscanf(val, "%i", &ctx->fmask); ctx->dmask = ctx->fmask; } else if (!strcmp(opt, "fmask")) { if (!val) { ntfs_log_error("'fmask' option should have " "value.\n"); goto err_exit; } sscanf(val, "%i", &ctx->fmask); } else if (!strcmp(opt, "dmask")) { if (!val) { ntfs_log_error("'dmask' option should have " "value.\n"); goto err_exit; } sscanf(val, "%i", &ctx->dmask); } else if (!strcmp(opt, "uid")) { if (!val) { ntfs_log_error("'uid' option should have " "value.\n"); goto err_exit; } sscanf(val, "%i", &ctx->uid); } else if (!strcmp(opt, "gid")) { if (!val) { ntfs_log_error("'gid' option should have " "value.\n"); goto err_exit; } sscanf(val, "%i", &ctx->gid); } else if (!strcmp(opt, "show_sys_files")) { if (val) { ntfs_log_error("'show_sys_files' option should " "not have value.\n"); goto err_exit; } ctx->show_sys_files = TRUE; } else if (!strcmp(opt, "silent")) { if (val) { ntfs_log_error("'silent' option should " "not have value.\n"); goto err_exit; } ctx->silent = TRUE; } else if (!strcmp(opt, "force")) { if (val) { ntfs_log_error("'force' option should not " "have value.\n"); goto err_exit; } ctx->force = TRUE; } else if (!strcmp(opt, "locale")) { if (!val) { ntfs_log_error("'locale' option should have " "value.\n"); goto err_exit; } if (!setlocale(LC_ALL, val)) ntfs_log_error("Couldn't set locale to %s thus " "you may not see properly or " "at all some files.\n", val); } else if (!strcmp(opt, "streams_interface")) { if (!val) { ntfs_log_error("'streams_interface' option " "should have value.\n"); goto err_exit; } if (!strcmp(val, "none")) ctx->streams = NF_STREAMS_INTERFACE_NONE; else if (!strcmp(val, "xattr")) ctx->streams = NF_STREAMS_INTERFACE_XATTR; else if (!strcmp(val, "windows")) ctx->streams = NF_STREAMS_INTERFACE_WINDOWS; else { ntfs_log_error("Invalid named data streams " "access interface.\n"); goto err_exit; } } else if (!strcmp(opt, "noauto")) { /* Don't pass noauto option to fuse. */ } else if (!strcmp(opt, "debug")) { if (val) { ntfs_log_error("'debug' option should not have " "value.\n"); goto err_exit; } ctx->debug = TRUE; ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG); ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE); } else if (!strcmp(opt, "no_detach")) { if (val) { ntfs_log_error("'no_detach' option should not " "have value.\n"); goto err_exit; } ctx->no_detach = TRUE; } else if (!strcmp(opt, "remount")) { ntfs_log_error("Remounting is not supported at present." " You have to umount volume and then " "mount it once again.\n"); goto err_exit; } else { /* Probably FUSE option. */ strcat(ret, opt); if (val) { strcat(ret, "="); strcat(ret, val); } strcat(ret, ","); } } if (!no_def_opts) strcat(ret, def_opts); strcat(ret, "fsname="); strcat(ret, opts.device);exit: free(options); return ret;err_exit: free(ret); ret = NULL; goto exit;}static void usage(void){ ntfs_log_info("\n%s v%s - Third Generation NTFS Driver\n\n", EXEC_NAME, VERSION); ntfs_log_info("Copyright (C) 2005-2006 Yura Pakhuchiy\n"); ntfs_log_info("Copyright (C) 2006 Szabolcs Szakacsits\n\n"); ntfs_log_info("Usage: %s device mount_point [-o options]\n\n", EXEC_NAME); ntfs_log_info("Options: force, no_def_opts, umask, " "fmask, dmask, uid, gid, show_sys_files\n\t" " silent, locale, streams_interface. " "See the details in the manual.\n\n"); ntfs_log_info("%s%s", ntfs_bugs, ntfs_home);}#ifndef HAVE_REALPATH/* If there is no realpath() on the system, provide a dummy one. */static char *realpath(const char *path, char *resolved_path){ strncpy(resolved_path, path, PATH_MAX); resolved_path[PATH_MAX] = '\0'; return resolved_path;}#endif/** * parse_options - Read and validate the programs command line * * Read the command line, verify the syntax and parse the options. * This function is very long, but quite simple. * * Return: 1 Success * 0 Error, one or more problems */static int parse_options(int argc, char *argv[]){ int err = 0, help = 0; int c = -1; static const char *sopt = "-o:h?qv"; static const struct option lopt[] = { { "options", required_argument, NULL, 'o' }, { "help", no_argument, NULL, 'h' }, { "quiet", no_argument, NULL, 'q' }, { "verbose", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } }; opterr = 0; /* We'll handle the errors, thank you. */ opts.mnt_point = NULL; opts.options = NULL; opts.device = NULL; while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { switch (c) { case 1: /* A non-option argument */ if (!opts.device) { opts.device = ntfs_malloc(PATH_MAX + 1); if (!opts.device) { err++; break; } /* We don't want relative path in /etc/mtab. */ if (argv[optind - 1][0] != '/') { if (!realpath(argv[optind - 1], opts.device)) { ntfs_log_perror("realpath"); free(opts.device); opts.device = NULL; err++; break; } } else strcpy(opts.device, argv[optind - 1]); } else if (!opts.mnt_point) opts.mnt_point = argv[optind - 1]; else { ntfs_log_error("You must specify exactly one " "device and exactly one mount " "point.\n"); err++; } break; case 'o': if (!opts.options) opts.options = argv[optind - 1]; else { ntfs_log_error("You must specify exactly one " "set of options.\n"); err++; } break; case 'h': case '?': help++; break; case 'q': opts.quiet++; break; case 'v': opts.verbose++; break; default: ntfs_log_error("Unknown option '%s'.\n", argv[optind - 1]); err++; break; } } if (help) { opts.quiet = 0; } else { if (!opts.device) { ntfs_log_error("No device specified.\n"); err++; } if (opts.quiet && opts.verbose) { ntfs_log_error("You may not use --quiet and --verbose " "at the same time.\n"); err++; } } if (help || err) usage(); return (!help && !err);}int main(int argc, char *argv[]){ char *parsed_options; struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); struct fuse *fh; int ffd = 0; utils_set_locale(); ntfs_log_set_handler(ntfs_log_handler_stderr); signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); if (!parse_options(argc, argv)) return 1; ntfs_fuse_init(); /* Parse options. */ parsed_options = parse_mount_options((opts.options) ? opts.options : ""); if (!parsed_options) { ntfs_fuse_destroy(); return 3; } /* Mount volume. */ if (ntfs_fuse_mount(opts.device)) { ntfs_fuse_destroy(); return 4; } /* Libfuse can't always find fusermount, so let's help it. */ if (setenv("PATH", ":/bin:/usr/bin:/usr/local/bin", 0) == -1) ntfs_log_perror("WARNING: Failed to set $PATH\n"); /* Create filesystem. */ if ((fuse_opt_add_arg(&margs, "") == -1 || fuse_opt_add_arg(&margs, "-o") == -1 || fuse_opt_add_arg(&margs, parsed_options) == -1)) ffd = -1; if (ffd != -1) ffd = fuse_mount(opts.mnt_point, &margs); fuse_opt_free_args(&margs); if (ffd == -1) { ntfs_log_error("fuse_mount failed.\n"); ntfs_fuse_destroy(); return 5; } free(parsed_options); fh = (struct fuse *)1; /* Cast anything except NULL to handle errors. */ margs = (struct fuse_args)FUSE_ARGS_INIT(0, NULL); if (fuse_opt_add_arg(&margs, "") == -1 || fuse_opt_add_arg(&margs, "-o") == -1) fh = NULL; if (!ctx->debug && !ctx->no_detach) { if (fuse_opt_add_arg(&margs, "use_ino,kernel_cache") == -1) fh = NULL; } else { if (fuse_opt_add_arg(&margs, "use_ino,debug") == -1) fh = NULL; } if (fh) fh = fuse_new(ffd, &margs , &ntfs_fuse_oper, sizeof(ntfs_fuse_oper)); fuse_opt_free_args(&margs); if (!fh) { ntfs_log_error("fuse_new failed.\n"); close(ffd); fuse_unmount(opts.mnt_point); ntfs_fuse_destroy(); return 6; } if (!ctx->no_detach) { if (daemon(0, ctx->debug)) ntfs_log_error("Failed to daemonize.\n"); else if (!ctx->debug) {#ifndef DEBUG ntfs_log_set_handler(ntfs_log_handler_syslog); /* Override default libntfs identify. */ openlog(EXEC_NAME, LOG_PID, LOG_DAEMON);#endif } } ntfs_log_info("Version %s\n", VERSION); ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS %d.%d)\n", opts.device, (ctx->ro) ? "Read-Only" : "Read-Write", ctx->vol->vol_name, ctx->vol->major_ver, ctx->vol->minor_ver); /* Main loop. */ fuse_loop(fh); /* Destroy. */ fuse_destroy(fh); close(ffd); fuse_unmount(opts.mnt_point); ntfs_fuse_destroy(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -