diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h index c4fb9df5..c00e5d56 100644 --- a/include/ntfs-3g/volume.h +++ b/include/ntfs-3g/volume.h @@ -78,6 +78,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 - * @@ -222,5 +237,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/volume.c b/libntfs-3g/volume.c index 699c2dd2..b90a48e6 100644 --- a/libntfs-3g/volume.c +++ b/libntfs-3g/volume.c @@ -1484,3 +1484,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 d75f3e33..a59b6612 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -1629,23 +1629,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; } + + errno = 0; +err_out: + return ntfs_volume_error(errno); - return 0; } static char *parse_mount_options(const char *orig_opts) @@ -2227,28 +2232,31 @@ int main(int argc, char *argv[]) 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_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) + if (!parsed_options) { + err = NTFS_VOLUME_SYNTAX_ERROR; goto err_out; + } uid = getuid(); euid = geteuid(); if (setuid(euid)) { ntfs_log_perror("Failed to set user ID to %d", euid); + err = NTFS_VOLUME_NO_PRIVILEGE; goto err_out; } @@ -2262,13 +2270,15 @@ 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, opts.mnt_point); + if (err) goto err_out; if (ctx->blkdev) { @@ -2278,14 +2288,19 @@ int main(int argc, char *argv[]) } 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); + ntfs_log_perror("Failed to drop privilege (uid to %d)", uid); + err = NTFS_VOLUME_NO_PRIVILEGE; 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); @@ -2317,6 +2332,7 @@ 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); diff --git a/src/utils.c b/src/utils.c index 2b14f74d..ce93a5fb 100644 --- a/src/utils.c +++ b/src/utils.c @@ -84,6 +84,10 @@ static const char *fakeraid_msg = "different device under /dev/mapper/, (e.g. /dev/mapper/nvidia_eahaabcc1)\n" "to mount NTFS. Please see the 'dmraid' documentation for help.\n"; +static const char *access_denied_msg = +"Please check the volume and the NTFS-3G binary permissions, the mounting\n" +"user and group ID, and the mount options.\n"; + static const char *forced_mount_msg = "\n" " mount -t ntfs-3g %s %s -o force\n" @@ -109,34 +113,32 @@ int utils_set_locale(void) return 0; } -ntfs_volume *utils_mount_volume(const char *volume, const char *mntpoint, - unsigned long flags) +void utils_mount_error(const char *volume, const char *mntpoint, int err) { - ntfs_volume *vol; - - vol = ntfs_mount(volume, flags); - if (!vol) { - - ntfs_log_perror("Failed to mount '%s'", volume); - - if (errno == EINVAL) + switch (err) { + case NTFS_VOLUME_NOT_NTFS: ntfs_log_error(invalid_ntfs_msg, volume); - else if (errno == EIO) + break; + case NTFS_VOLUME_CORRUPT: ntfs_log_error("%s", corrupt_volume_msg); - else if (errno == EPERM) + break; + case NTFS_VOLUME_HIBERNATED: ntfs_log_error("%s", hibernated_volume_msg); - else if (errno == EOPNOTSUPP) { + break; + case NTFS_VOLUME_UNCLEAN_UNMOUNT: ntfs_log_error(unclean_journal_msg); - ntfs_log_error(forced_mount_msg, volume, mntpoint, + ntfs_log_error(forced_mount_msg, volume, mntpoint, volume, mntpoint); - } else if (errno == EBUSY) + break; + case NTFS_VOLUME_LOCKED: ntfs_log_error("%s", opened_volume_msg); - else if (errno == ENXIO) + break; + case NTFS_VOLUME_RAID: ntfs_log_error("%s", fakeraid_msg); - - return NULL; + break; + case NTFS_VOLUME_NO_PRIVILEGE: + ntfs_log_error(access_denied_msg, volume); + break; } - - return vol; } diff --git a/src/utils.h b/src/utils.h index 400d465f..2d47ca4b 100644 --- a/src/utils.h +++ b/src/utils.h @@ -32,8 +32,6 @@ extern const char *ntfs_home; extern const char *ntfs_gpl; int utils_set_locale(void); - -ntfs_volume *utils_mount_volume(const char *device, const char *mntpoint, - unsigned long flags); +void utils_mount_error(const char *vol, const char *mntpoint, int err); #endif /* _NTFS_UTILS_H_ */