From 5984592552cde2b8b04e48f276abf30332069aae Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 8 Apr 2007 20:23:11 +0000 Subject: [PATCH] support read-write mount with the --force option if logfile is unclean --- include/ntfs-3g/volume.h | 4 ++++ libntfs-3g/logfile.c | 42 +++++++++------------------------------- libntfs-3g/volume.c | 34 ++++++++++++++++++++------------ src/ntfs-3g.8.in | 8 ++++---- src/ntfs-3g.c | 2 ++ src/utils.c | 42 ++++++++++++++++++++++------------------ 6 files changed, 64 insertions(+), 68 deletions(-) diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h index 3b8cde63..d0872190 100644 --- a/include/ntfs-3g/volume.h +++ b/include/ntfs-3g/volume.h @@ -63,6 +63,10 @@ #define MS_EXCLUSIVE 0x08000000 +#ifndef MS_FORCE +#define MS_FORCE 0x10000000 +#endif + /* Forward declaration */ typedef struct _ntfs_volume ntfs_volume; diff --git a/libntfs-3g/logfile.c b/libntfs-3g/logfile.c index 9b119269..3fb04f3d 100644 --- a/libntfs-3g/logfile.c +++ b/libntfs-3g/logfile.c @@ -699,55 +699,31 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp) */ int ntfs_empty_logfile(ntfs_attr *na) { - s64 len, pos, count; + s64 pos, count; char buf[NTFS_BUF_SIZE]; ntfs_log_trace("Entering.\n"); + if (NVolLogFileEmpty(na->ni->vol)) return 0; - /* The $DATA attribute of the $LogFile has to be non-resident. */ if (!NAttrNonResident(na)) { errno = EIO; - ntfs_log_perror("$LogFile $DATA attribute is resident!?!\n"); + ntfs_log_perror("Resident $LogFile $DATA attribute"); return -1; } - /* Get length of $LogFile contents. */ - len = na->data_size; - if (!len) { - ntfs_log_debug("$LogFile has zero length, no disk write " - "needed.\n"); - return 0; - } - - /* Read $LogFile until its end. We do this as a check for correct - length thus making sure we are decompressing the mapping pairs - array correctly and hence writing below is safe as well. */ - pos = 0; - while ((count = ntfs_attr_pread(na, pos, NTFS_BUF_SIZE, buf)) > 0) - pos += count; - - if (count == -1 || pos != len) { - ntfs_log_error("Amount of $LogFile data read does not " - "correspond to expected length!\n"); - if (count != -1) - errno = EIO; - return -1; - } - - /* Fill the buffer with 0xff's. */ memset(buf, -1, NTFS_BUF_SIZE); - /* Set the $DATA attribute. */ pos = 0; - while ((count = len - pos) > 0) { + while ((count = na->data_size - pos) > 0) { + if (count > NTFS_BUF_SIZE) count = NTFS_BUF_SIZE; - if ((count = ntfs_attr_pwrite(na, pos, count, buf)) <= 0) { - ntfs_log_perror("Failed to set the $LogFile attribute " - "value.\n"); + count = ntfs_attr_pwrite(na, pos, count, buf); + if (count <= 0) { + ntfs_log_perror("Failed to reset $LogFile"); if (count != -1) errno = EIO; return -1; @@ -755,7 +731,7 @@ int ntfs_empty_logfile(ntfs_attr *na) pos += count; } - /* Set the flag so we do not have to do it again on remount. */ NVolSetLogFileEmpty(na->ni->vol); + return 0; } diff --git a/libntfs-3g/volume.c b/libntfs-3g/volume.c index 893e2686..daea8f14 100644 --- a/libntfs-3g/volume.c +++ b/libntfs-3g/volume.c @@ -552,22 +552,25 @@ static int ntfs_volume_check_logfile(ntfs_volume *vol) RESTART_PAGE_HEADER *rp = NULL; int err = 0; - if ((ni = ntfs_inode_open(vol, FILE_LogFile)) == NULL) { + ni = ntfs_inode_open(vol, FILE_LogFile); + if (!ni) { ntfs_log_perror("Failed to open inode FILE_LogFile"); errno = EIO; return -1; } - if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) { + + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { ntfs_log_perror("Failed to open $FILE_LogFile/$DATA"); err = EIO; - goto exit; + goto out; } + if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp)) err = EOPNOTSUPP; free(rp); -exit: - if (na) - ntfs_attr_close(na); + ntfs_attr_close(na); +out: ntfs_inode_close(ni); if (err) { errno = err; @@ -1075,10 +1078,15 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) * We care only about read-write mounts. */ if (!(flags & MS_RDONLY)) { - if (ntfs_volume_check_logfile(vol) < 0) - goto error_exit; if (ntfs_volume_check_hiberfile(vol) < 0) goto error_exit; + if (ntfs_volume_check_logfile(vol) < 0) { + if (!(flags & MS_FORCE)) + goto error_exit; + ntfs_log_info("WARNING: Forced mount, reset $LogFile.\n"); + if (ntfs_logfile_reset(vol)) + goto error_exit; + } } return vol; @@ -1399,12 +1407,14 @@ int ntfs_logfile_reset(ntfs_volume *vol) return -1; } - if ((ni = ntfs_inode_open(vol, FILE_LogFile)) == NULL) { - ntfs_log_perror("Failed to open inode FILE_LogFile."); + ni = ntfs_inode_open(vol, FILE_LogFile); + if (!ni) { + ntfs_log_perror("Failed to open inode FILE_LogFile"); return -1; } - if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) { + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { eo = errno; ntfs_log_perror("Failed to open $FILE_LogFile/$DATA"); goto error_exit; @@ -1412,10 +1422,10 @@ int ntfs_logfile_reset(ntfs_volume *vol) if (ntfs_empty_logfile(na)) { eo = errno; - ntfs_log_perror("Failed to empty $FILE_LogFile/$DATA"); ntfs_attr_close(na); goto error_exit; } + ntfs_attr_close(na); return ntfs_inode_close(ni); diff --git a/src/ntfs-3g.8.in b/src/ntfs-3g.8.in index 54bd424c..8d039a6d 100644 --- a/src/ntfs-3g.8.in +++ b/src/ntfs-3g.8.in @@ -100,10 +100,10 @@ environment variables are not set before partitions had been mounted from /etc/fstab. .TP .B force -Force mount even if the volume is scheduled for consistency check. -Use this option with caution and preferably with the -.B ro -option. +Force mount even if the volume is scheduled for consistency check or +the logfile is unclean. The logfile will be unconditionally cleared +in the latter case. Use this option with caution and for your own +responsibility. .TP .B show_sys_files Show the system files in directory listings. diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 5772e350..155dcb1e 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -1640,6 +1640,8 @@ static ntfs_volume *ntfs_open(const char *device, char *mntpoint, int blkdev) flags |= MS_RDONLY; if (ctx->noatime) flags |= MS_NOATIME; + if (ctx->force) + flags |= MS_FORCE; ctx->vol = utils_mount_volume(device, mntpoint, flags, ctx->force); return ctx->vol; diff --git a/src/utils.c b/src/utils.c index 7ca17ab3..a8e4ae9e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -97,14 +97,14 @@ static const char *hibernated_volume_msg = "properly, so mounting could be done safely.\n"; static const char *unclean_journal_msg = -"Mount is denied because NTFS logfile is unclean. Choose one action:\n" -" Boot Windows and shutdown it cleanly, or if you have a removable\n" -" device then click the 'Safely Remove Hardware' icon in the Windows\n" -" taskbar notification area before disconnecting it.\n" -"Or\n" -" Run ntfsfix version 1.13.1 on Linux unless you have Vista.\n" -"Or\n" -" Mount the NTFS volume with the 'ro' option in read-only mode.\n"; +"Mount is denied because NTFS is marked to be in use. Choose one action:\n" +"\n" +"Choice 1: If you have Windows then disconnect the external devices by\n" +" clicking on the 'Safely Remove Hardware' icon in the Windows\n" +" taskbar then shutdown Windows cleanly.\n" +"\n" +"Choice 2: If you don't have Windows then you can use the 'force' option for\n" +" your own responsibility. For example type on the command line:\n"; static const char *opened_volume_msg = "Mount is denied because the NTFS volume is already exclusively opened.\n" @@ -118,14 +118,15 @@ static const char *fakeraid_msg = static const char *dirty_volume_msg = "Volume is scheduled for check. Please boot into Windows TWICE, or\n" -"use the 'force' mount option. For example type on the command line:\n" +"use the 'force' mount option. For example type on the command line:\n"; + +static const char *forced_mount_msg = "\n" -" mount -t ntfs-3g %s %s -o force\n" +" mount -t ntfs-3g %s %s -o force\n" "\n" -"Or add the option to the relevant row in the /etc/fstab file:\n" +" Or add the option to the relevant row in the /etc/fstab file:\n" "\n" -" %s %s ntfs-3g defaults,force 0 0\n" -"\n"; +" %s %s ntfs-3g defaults,force 0 0\n"; /** * utils_set_locale @@ -160,9 +161,11 @@ ntfs_volume *utils_mount_volume(const char *volume, const char *mntpoint, ntfs_log_error("%s", corrupt_volume_msg); else if (errno == EPERM) ntfs_log_error("%s", hibernated_volume_msg); - else if (errno == EOPNOTSUPP) - ntfs_log_error("%s", unclean_journal_msg); - else if (errno == EBUSY) + else if (errno == EOPNOTSUPP) { + ntfs_log_error(unclean_journal_msg); + ntfs_log_error(forced_mount_msg, volume, mntpoint, + volume, mntpoint); + } else if (errno == EBUSY) ntfs_log_error("%s", opened_volume_msg); else if (errno == ENXIO) ntfs_log_error("%s", fakeraid_msg); @@ -172,14 +175,15 @@ ntfs_volume *utils_mount_volume(const char *volume, const char *mntpoint, if (vol->flags & VOLUME_IS_DIRTY) { if (!force) { - ntfs_log_error(dirty_volume_msg, volume, mntpoint, + ntfs_log_error("%s", dirty_volume_msg); + ntfs_log_error(forced_mount_msg, volume, mntpoint, volume, mntpoint); ntfs_umount(vol, FALSE); return NULL; } else - ntfs_log_error("WARNING: Dirty volume mount was forced " - "by the 'force' mount option.\n"); + ntfs_log_error("WARNING: Forced mount, unclean volume " + "information is ignored.\n"); } return vol;