support read-write mount with the --force option if logfile is unclean

master
szaka 2007-04-08 20:23:11 +00:00
parent 108934e9fe
commit 5984592552
6 changed files with 64 additions and 68 deletions

View File

@ -63,6 +63,10 @@
#define MS_EXCLUSIVE 0x08000000
#ifndef MS_FORCE
#define MS_FORCE 0x10000000
#endif
/* Forward declaration */
typedef struct _ntfs_volume ntfs_volume;

View File

@ -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;
}

View File

@ -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);

View File

@ -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.

View File

@ -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;

View File

@ -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;