diff --git a/AUTHORS b/AUTHORS index 15d7f47d..242aea05 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,13 +1,21 @@ -Past and present authors of ntfs-3g in alphabetical order are: +Present authors of ntfs-3g in alphabetical order: + +Jean-Pierre Andre +Alon Bar-Lev +Dominique L Bouix +Csaba Henk +Erik Larsson +Alejandro Pulver +Szabolcs Szakacsits +Miklos Szeredi + + +Past authors in alphabetical order: Anton Altaparmakov -Jean-Pierre André -Dominique L Bouix Mario Emmenlauer -Csaba Henk Yuval Fledel Yura Pakhuchiy Richard Russon -Szabolcs Szakacsits diff --git a/include/ntfs-3g/inode.h b/include/ntfs-3g/inode.h index 1fc4d79f..f96c4482 100644 --- a/include/ntfs-3g/inode.h +++ b/include/ntfs-3g/inode.h @@ -86,16 +86,13 @@ typedef enum { #define NInoAttrListTestAndSetDirty(ni) test_and_set_nino_al_flag(ni, Dirty) #define NInoAttrListTestAndClearDirty(ni) test_and_clear_nino_al_flag(ni, Dirty) -#define NInoFileNameDirty(ni) \ - test_nino_flag(ni, FileNameDirty) -#define NInoFileNameSetDirty(ni) \ - set_nino_flag(ni, FileNameDirty) -#define NInoFileNameClearDirty(ni) \ - clear_nino_flag(ni, FileNameDirty) +#define NInoFileNameDirty(ni) test_nino_flag(ni, FileNameDirty) +#define NInoFileNameSetDirty(ni) set_nino_flag(ni, FileNameDirty) +#define NInoFileNameClearDirty(ni) clear_nino_flag(ni, FileNameDirty) #define NInoFileNameTestAndSetDirty(ni) \ - test_and_set_nino_flag(ni, FileNameDirty) + test_and_set_nino_flag(ni, FileNameDirty) #define NInoFileNameTestAndClearDirty(ni) \ - test_and_clear_nino_flag(ni, FileNameDirty) + test_and_clear_nino_flag(ni, FileNameDirty) /** * struct _ntfs_inode - The NTFS in-memory inode structure. diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h index d9538828..ae985f56 100644 --- a/include/ntfs-3g/volume.h +++ b/include/ntfs-3g/volume.h @@ -83,6 +83,21 @@ typedef enum { extern int ntfs_check_if_mounted(const char *file, unsigned long *mnt_flags); +typedef enum { + NTFS_VOLUME_OK = 0, + NTFS_VOLUME_SYNTAX_ERROR = 11, + NTFS_VOLUME_NOT_NTFS = 12, + NTFS_VOLUME_CORRUPT = 13, + NTFS_VOLUME_HIBERNATED = 14, + NTFS_VOLUME_UNCLEAN_UNMOUNT = 15, + NTFS_VOLUME_LOCKED = 16, + NTFS_VOLUME_RAID = 17, + NTFS_VOLUME_UNKNOWN_REASON = 18, + NTFS_VOLUME_NO_PRIVILEGE = 19, + NTFS_VOLUME_OUT_OF_MEMORY = 20, + NTFS_VOLUME_FUSE_ERROR = 21 +} ntfs_volume_status; + /** * enum ntfs_volume_state_bits - * @@ -243,5 +258,7 @@ extern int ntfs_logfile_reset(ntfs_volume *vol); extern int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags); +extern int ntfs_volume_error(int err); + #endif /* defined _NTFS_VOLUME_H */ diff --git a/libntfs-3g/index.c b/libntfs-3g/index.c index fc850b0c..f20f9f67 100644 --- a/libntfs-3g/index.c +++ b/libntfs-3g/index.c @@ -5,6 +5,7 @@ * Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2005-2006 Yura Pakhuchiy * Copyright (c) 2005-2006 Szabolcs Szakacsits + * Copyright (c) 2007-2008 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published diff --git a/libntfs-3g/volume.c b/libntfs-3g/volume.c index 72ecd154..e20f7630 100644 --- a/libntfs-3g/volume.c +++ b/libntfs-3g/volume.c @@ -1486,3 +1486,39 @@ err_out: return ret; } +int ntfs_volume_error(int err) +{ + int ret; + + switch (err) { + case 0: + ret = NTFS_VOLUME_OK; + break; + case EINVAL: + ret = NTFS_VOLUME_NOT_NTFS; + break; + case EIO: + ret = NTFS_VOLUME_CORRUPT; + break; + case EPERM: + ret = NTFS_VOLUME_HIBERNATED; + break; + case EOPNOTSUPP: + ret = NTFS_VOLUME_UNCLEAN_UNMOUNT; + break; + case EBUSY: + ret = NTFS_VOLUME_LOCKED; + break; + case ENXIO: + ret = NTFS_VOLUME_RAID; + break; + case EACCES: + ret = NTFS_VOLUME_NO_PRIVILEGE; + break; + default: + ret = NTFS_VOLUME_UNKNOWN_REASON; + break; + } + return ret; +} + diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 65b855f2..e07c57c8 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -1,9 +1,9 @@ /** * ntfs-3g - Third Generation NTFS Driver * - * Copyright (c) 2005-2006 Yura Pakhuchiy + * Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2005 Yuval Fledel - * Copyright (c) 2006-2007 Szabolcs Szakacsits + * Copyright (c) 2006-2008 Szabolcs Szakacsits * Copyright (c) 2007-2008 Jean-Pierre Andre * * This file is originated from the Linux-NTFS project. @@ -36,6 +36,12 @@ #error "***********************************************************" #endif +#ifdef FUSE_INTERNAL +#define FUSE_TYPE "integrated FUSE" +#else +#define FUSE_TYPE "external FUSE" +#endif + #ifdef HAVE_STDIO_H #include #endif @@ -154,21 +160,20 @@ static const char *locale_msg = static const char *usage_msg = "\n" -"%s %s - Third Generation NTFS Driver\n" +"%s %s %s %d - Third Generation NTFS Driver\n" "\n" -"Copyright (C) 2005-2006 Yura Pakhuchiy\n" -"Copyright (C) 2006-2007 Szabolcs Szakacsits\n" +"Copyright (C) 2006-2008 Szabolcs Szakacsits\n" +"Copyright (C) 2005-2007 Yura Pakhuchiy\n" "\n" "Usage: %s [-o option[,...]]\n" "\n" "Options: ro, force, locale=, uid=, gid=, umask=, fmask=, dmask=,\n" " streams_interface=. Please see details in the manual.\n" "\n" -"Example: ntfs-3g /dev/sda1 /mnt/win -o force,locale=en_EN.UTF-8\n" +"Example: ntfs-3g /dev/sda1 /mnt/win -o force\n" "\n" "%s"; - /** * ntfs_fuse_is_named_data_stream - check path to be to named data stream * @path: path to check @@ -1920,7 +1925,7 @@ static int ntfs_fuse_init(void) return 0; } -static int ntfs_open(const char *device, char *mntpoint) +static int ntfs_open(const char *device) { unsigned long flags = 0; @@ -1931,28 +1936,28 @@ static int ntfs_open(const char *device, char *mntpoint) if (ctx->force) flags |= MS_FORCE; - ctx->vol = utils_mount_volume(device, mntpoint, flags); - if (!ctx->vol) - return -1; + ctx->vol = ntfs_mount(device, flags); + if (!ctx->vol) { + ntfs_log_perror("Failed to mount '%s'", device); + goto err_out; + } ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na); if (ctx->vol->free_clusters < 0) { ntfs_log_perror("Failed to read NTFS $Bitmap"); - return -1; + goto err_out; } ctx->vol->free_mft_records = ntfs_get_nr_free_mft_records(ctx->vol); if (ctx->vol->free_mft_records < 0) { ntfs_log_perror("Failed to calculate free MFT records"); - return -1; + goto err_out; } - - return 0; -} -static void signal_handler(int arg __attribute__((unused))) -{ - fuse_exit((fuse_get_context())->fuse); + errno = 0; +err_out: + return ntfs_volume_error(errno); + } static char *parse_mount_options(const char *orig_opts) @@ -2215,7 +2220,8 @@ err_exit: static void usage(void) { - ntfs_log_info(usage_msg, EXEC_NAME, VERSION, EXEC_NAME, ntfs_home); + ntfs_log_info(usage_msg, EXEC_NAME, VERSION, FUSE_TYPE, fuse_version(), + EXEC_NAME, ntfs_home); } #ifndef HAVE_REALPATH @@ -2426,7 +2432,7 @@ static fuse_fstype load_fuse_module(void) struct timespec req = { 0, 100000000 }; /* 100 msec */ fuse_fstype fstype; - if (!stat(cmd, &st) && !getuid()) { + if (!stat(cmd, &st) && !geteuid()) { pid = fork(); if (!pid) { execl(cmd, cmd, "fuse", NULL); @@ -2511,11 +2517,35 @@ static void set_user_mount_option(char *parsed_options, uid_t uid) strcat(parsed_options, option); } +#ifndef FUSE_INTERNAL +static int set_uid(uid_t uid) +{ + if (setuid(uid)) { + ntfs_log_perror("Failed to set uid to %d", uid); + return NTFS_VOLUME_NO_PRIVILEGE; + } + return NTFS_VOLUME_OK; +} +#endif + static struct fuse *mount_fuse(char *parsed_options) { struct fuse *fh = NULL; struct fuse_args args = FUSE_ARGS_INIT(0, NULL); +#ifndef FUSE_INTERNAL + uid_t uid, euid; + /* + * We must raise privilege if possible, otherwise the user[s] fstab + * option doesn't work because mount(8) always drops privilege what + * the blkdev option requires. + */ + uid = getuid(); + euid = geteuid(); + + if (set_uid(euid)) + return NULL; +#endif /* 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"); @@ -2545,49 +2575,78 @@ static struct fuse *mount_fuse(char *parsed_options) if (!fh) goto err; - ctx->mounted = TRUE; + if (fuse_set_signal_handlers(fuse_get_session(fh))) + goto err_destory; + /* + * We can't drop privilege if internal FUSE is used because internal + * unmount needs it. Kernel 2.6.25 may include unprivileged full + * mount/unmount support. + */ +#ifndef FUSE_INTERNAL + if (set_uid(uid)) + goto err_destory; +#endif out: fuse_opt_free_args(&args); return fh; +err_destory: + fuse_destroy(fh); + fh = NULL; err: fuse_unmount(opts.mnt_point, ctx->fc); goto out; } +static void setup_logging(char *parsed_options) +{ + 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 + } + } + + ctx->seccache = (struct PERMISSIONS_CACHE*)NULL; + + ntfs_log_info("Version %s %s %d\n", VERSION, FUSE_TYPE, fuse_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("Cmdline options: %s\n", opts.options); + ntfs_log_info("Mount options: %s\n", parsed_options); +} + int main(int argc, char *argv[]) { char *parsed_options = NULL; struct fuse *fh; fuse_fstype fstype = FSTYPE_UNKNOWN; struct stat sbuf; - uid_t uid, euid; - int err = 10; + int err; utils_set_locale(); - ntfs_log_set_handler((ntfs_log_handler*)ntfs_log_handler_stderr); - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); + ntfs_log_set_handler(ntfs_log_handler_stderr); if (parse_options(argc, argv)) { usage(); - return 1; + return NTFS_VOLUME_SYNTAX_ERROR; } if (ntfs_fuse_init()) - return 2; + return NTFS_VOLUME_OUT_OF_MEMORY; 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); + if (!parsed_options) { + err = NTFS_VOLUME_SYNTAX_ERROR; goto err_out; } - + #if defined(linux) || defined(__uClinux__) fstype = get_fuse_fstype(); if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN) @@ -2598,56 +2657,37 @@ int main(int argc, char *argv[]) if (stat(opts.device, &sbuf)) { ntfs_log_perror("Failed to access '%s'", opts.device); + err = NTFS_VOLUME_NO_PRIVILEGE; goto err_out; } /* Always use fuseblk for block devices unless it's surely missing. */ if (S_ISBLK(sbuf.st_mode) && (fstype != FSTYPE_FUSE)) ctx->blkdev = TRUE; - if (ntfs_open(opts.device, opts.mnt_point)) + err = ntfs_open(opts.device); + if (err) goto err_out; if (ctx->blkdev) { /* Must do after ntfs_open() to set the right blksize. */ set_fuseblk_options(parsed_options); - set_user_mount_option(parsed_options, uid); + set_user_mount_option(parsed_options, getuid()); } fh = mount_fuse(parsed_options); - if (!fh) + if (!fh) { + err = NTFS_VOLUME_FUSE_ERROR; goto err_out; - - if (setuid(uid)) { - ntfs_log_perror("Failed to set user ID to %d", uid); - goto err_umount; } + + ctx->mounted = TRUE; #if defined(linux) || defined(__uClinux__) if (S_ISBLK(sbuf.st_mode) && (fstype == FSTYPE_FUSE)) ntfs_log_info(fuse26_kmod_msg); #endif - 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*)ntfs_log_handler_syslog); - /* Override default libntfs identify. */ - openlog(EXEC_NAME, LOG_PID, LOG_DAEMON); -#endif - } - } + setup_logging(parsed_options); - ctx->seccache = (struct PERMISSIONS_CACHE*)NULL; - - 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("Cmdline options: %s\n", opts.options); - ntfs_log_info("Mount options: %s\n", parsed_options); ctx->security.vol = ctx->vol; ctx->security.uid = ctx->uid; ctx->security.gid = ctx->gid; @@ -2667,10 +2707,11 @@ int main(int argc, char *argv[]) fuse_loop(fh); err = 0; -err_umount: + fuse_unmount(opts.mnt_point, ctx->fc); fuse_destroy(fh); err_out: + utils_mount_error(opts.device, opts.mnt_point, err); ntfs_close(); free(ctx); free(parsed_options);