support read-write mount with the --force option if logfile is unclean
parent
108934e9fe
commit
5984592552
|
@ -63,6 +63,10 @@
|
|||
|
||||
#define MS_EXCLUSIVE 0x08000000
|
||||
|
||||
#ifndef MS_FORCE
|
||||
#define MS_FORCE 0x10000000
|
||||
#endif
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct _ntfs_volume ntfs_volume;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
42
src/utils.c
42
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;
|
||||
|
|
Loading…
Reference in New Issue