📄 ntfs-3g.c
字号:
*ret = 0; options = strdup(orig_opts); 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,"); ctx->silent = TRUE; s = options; while (s && *s && (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, "default_permissions")) { default_permissions = 1; } else if (!strcmp(opt, "umask")) { if (!val) { ntfs_log_error("'umask' option should have " "value.\n"); goto err_exit; } sscanf(val, "%o", &ctx->fmask); ctx->dmask = ctx->fmask; default_permissions = 1; } else if (!strcmp(opt, "fmask")) { if (!val) { ntfs_log_error("'fmask' option should have " "value.\n"); goto err_exit; } sscanf(val, "%o", &ctx->fmask); default_permissions = 1; } else if (!strcmp(opt, "dmask")) { if (!val) { ntfs_log_error("'dmask' option should have " "value.\n"); goto err_exit; } sscanf(val, "%o", &ctx->dmask); default_permissions = 1; } else if (!strcmp(opt, "uid")) { if (!val) { ntfs_log_error("'uid' option should have " "value.\n"); goto err_exit; } sscanf(val, "%i", &ctx->uid); default_permissions = 1; } else if (!strcmp(opt, "gid")) { if (!val) { ntfs_log_error("'gid' option should have " "value.\n"); goto err_exit; } sscanf(val, "%i", &ctx->gid); default_permissions = 1; } 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(locale_msg, 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 if (!strcmp(opt, "blksize")) { ntfs_log_info("WARNING: blksize option is ignored " "because ntfs-3g must calculate it.\n"); } else { /* Probably FUSE option. */ strcat(ret, opt); if (val) { strcat(ret, "="); strcat(ret, val); } strcat(ret, ","); } } if (!no_def_opts) strcat(ret, def_opts); if (default_permissions) strcat(ret, "default_permissions,"); 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 %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-2007 Szabolcs Szakacsits\n\n"); ntfs_log_info("Usage: %s device mount_point [-o options]\n\n", EXEC_NAME); ntfs_log_info("Options: ro, force, locale, uid, gid, umask, fmask, " "dmask, \n\t" " show_sys_files, no_def_opts, streams_interface.\n\t" " Please see the details in the manual.\n\n"); ntfs_log_info("%s\n", 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 (optarg[0] != '/') { if (!realpath(optarg, opts.device)) { ntfs_log_perror("Cannot mount " "'%s'", optarg); free(opts.device); opts.device = NULL; err++; break; } } else strcpy(opts.device, optarg); } else if (!opts.mnt_point) opts.mnt_point = optarg; 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 = optarg; 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);}static fuse_fstype get_fuse_fstype(void){ char buf[256]; fuse_fstype fstype = FSTYPE_NONE; FILE *f = fopen("/proc/filesystems", "r"); if (!f) { ntfs_log_perror("Failed to open /proc/filesystems"); return FSTYPE_UNKNOWN; } while (fgets(buf, sizeof(buf), f)) { if (strstr(buf, "fuseblk\n")) { fstype = FSTYPE_FUSEBLK; break; } if (strstr(buf, "fuse\n")) fstype = FSTYPE_FUSE; } fclose(f); return fstype;}static void create_dev_fuse(void){ struct stat st; if (stat("/dev/fuse", &st) && (errno == ENOENT)) { if (mknod("/dev/fuse", S_IFCHR | 0666, makedev(10, 229))) ntfs_log_perror("Failed to create /dev/fuse"); }}static fuse_fstype load_fuse_module(void){ int i; struct stat st; const char *load_fuse_cmd = "/sbin/modprobe fuse"; struct timespec req = { 0, 100000000 }; /* 100 msec */ fuse_fstype fstype; if (stat("/sbin/modprobe", &st) == -1) load_fuse_cmd = "modprobe fuse"; if (getuid() == 0) system(load_fuse_cmd); for (i = 0; i < 10; i++) { /* * We sleep first because despite the detection of the loaded * FUSE kernel module, fuse_mount() can still fail if it's not * fully functional/initialized. Note, of course this is still * unreliable but usually helps. */ nanosleep(&req, NULL); fstype = get_fuse_fstype(); if (fstype != FSTYPE_NONE) break; } return fstype;}static struct fuse_chan *try_fuse_mount(char *parsed_options){ struct fuse_chan *fc = NULL; struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); /* The fuse_mount() options get modified, so we always rebuild it */ if ((fuse_opt_add_arg(&margs, "") == -1 || fuse_opt_add_arg(&margs, "-o") == -1 || fuse_opt_add_arg(&margs, parsed_options) == -1)) { ntfs_log_error("Failed to set FUSE options.\n"); goto free_args; } fc = fuse_mount(opts.mnt_point, &margs); if (!fc) ntfs_log_error("FUSE mount point creation failed\n");free_args: fuse_opt_free_args(&margs); return fc; } static void set_fuseblk_options(char *parsed_options){ char options[64]; long pagesize; u32 blksize = ctx->vol->cluster_size; pagesize = sysconf(_SC_PAGESIZE); if (pagesize < 1) pagesize = 4096; if (blksize > (u32)pagesize) blksize = pagesize; /* parsed_options already allocated enough space. */ snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize); strcat(parsed_options, options);}int main(int argc, char *argv[]){ char *parsed_options = NULL; struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); struct fuse *fh; struct fuse_chan *fc; fuse_fstype fstype; struct stat sbuf; int use_blkdev = 0; uid_t uid, euid; int err = 10; 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; if (ntfs_fuse_init()) return 2; parsed_options = parse_mount_options(opts.options ? opts.options : ""); if (!parsed_options) goto err_out; uid = getuid(); euid = geteuid(); if (setuid(euid)) { ntfs_log_perror("Failed to set user ID to %d", euid); goto err_out; } fstype = get_fuse_fstype(); if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN) fstype = load_fuse_module(); create_dev_fuse(); if (stat(opts.device, &sbuf)) { ntfs_log_perror("Failed to access '%s'", opts.device); goto err_out; } /* Always use fuseblk for block devices unless it's surely missing. */ if (S_ISBLK(sbuf.st_mode) && (fstype != FSTYPE_FUSE)) use_blkdev = 1; if (!ntfs_open(opts.device, opts.mnt_point, use_blkdev)) goto err_out; if (use_blkdev) set_fuseblk_options(parsed_options); /* Libfuse can't always find fusermount, so let's help it. */ if (setenv("PATH", ":/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin", 0)) ntfs_log_perror("WARNING: Failed to set $PATH\n"); fc = try_fuse_mount(parsed_options); if (!fc) goto err_out; fh = (struct fuse *)1; /* Cast anything except NULL to handle errors. */ 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(fc, &margs , &ntfs_fuse_oper, sizeof(ntfs_fuse_oper), NULL); fuse_opt_free_args(&margs); if (!fh) { ntfs_log_error("fuse_new failed.\n"); fuse_unmount(opts.mnt_point, fc); goto err_out; } if (setuid(uid)) { ntfs_log_perror("Failed to set user ID to %d", uid); fuse_unmount(opts.mnt_point, fc); goto err_out; } if (S_ISBLK(sbuf.st_mode) && (fstype == FSTYPE_FUSE)) ntfs_log_info(fuse26_kmod_msg); 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); ntfs_log_info("Options: %s\n", parsed_options); fuse_loop(fh); fuse_unmount(opts.mnt_point, fc); fuse_destroy(fh); err = 0;err_out: free(parsed_options); ntfs_fuse_destroy(); return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -