aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAnton Altaparmakov <aia21@cantab.net>2005-06-25 11:31:27 -0400
committerAnton Altaparmakov <aia21@cantab.net>2005-06-25 11:31:27 -0400
commitca8fd7a0c6aa835e8014830b290cb965e85ac88e (patch)
tree504929d2a4beacb86fbc420c85f5c102f2a27fed /fs
parent9f993fe4634b39ca4404ba278053b03f360ec08a (diff)
NTFS: Detect the case when Windows has been suspended to disk on the volume
to be mounted and if this is the case do not allow (re)mounting read-write. This is done by parsing hiberfil.sys if present. Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
Diffstat (limited to 'fs')
-rw-r--r--fs/ntfs/ChangeLog3
-rw-r--r--fs/ntfs/super.c179
2 files changed, 171 insertions, 11 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
index 59ecca4297bb..c089bf0c02ac 100644
--- a/fs/ntfs/ChangeLog
+++ b/fs/ntfs/ChangeLog
@@ -125,6 +125,9 @@ ToDo/Notes:
125 if the runlist was not mapped at all and a mapping error occured we 125 if the runlist was not mapped at all and a mapping error occured we
126 would leave the runlist locked on exit to the function so that the 126 would leave the runlist locked on exit to the function so that the
127 next access to the same file would try to take the lock and deadlock. 127 next access to the same file would try to take the lock and deadlock.
128 - Detect the case when Windows has been suspended to disk on the volume
129 to be mounted and if this is the case do not allow (re)mounting
130 read-write. This is done by parsing hiberfil.sys if present.
128 131
1292.1.22 - Many bug and race fixes and error handling improvements. 1322.1.22 - Many bug and race fixes and error handling improvements.
130 133
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 92e1d28219b3..41aa8eb6755b 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -1156,6 +1156,124 @@ static BOOL load_and_check_logfile(ntfs_volume *vol)
1156 return TRUE; 1156 return TRUE;
1157} 1157}
1158 1158
1159#define NTFS_HIBERFIL_HEADER_SIZE 4096
1160
1161/**
1162 * check_windows_hibernation_status - check if Windows is suspended on a volume
1163 * @vol: ntfs super block of device to check
1164 *
1165 * Check if Windows is hibernated on the ntfs volume @vol. This is done by
1166 * looking for the file hiberfil.sys in the root directory of the volume. If
1167 * the file is not present Windows is definitely not suspended.
1168 *
1169 * If hiberfil.sys exists and is less than 4kiB in size it means Windows is
1170 * definitely suspended (this volume is not the system volume). Caveat: on a
1171 * system with many volumes it is possible that the < 4kiB check is bogus but
1172 * for now this should do fine.
1173 *
1174 * If hiberfil.sys exists and is larger than 4kiB in size, we need to read the
1175 * hiberfil header (which is the first 4kiB). If this begins with "hibr",
1176 * Windows is definitely suspended. If it is completely full of zeroes,
1177 * Windows is definitely not hibernated. Any other case is treated as if
1178 * Windows is suspended. This caters for the above mentioned caveat of a
1179 * system with many volumes where no "hibr" magic would be present and there is
1180 * no zero header.
1181 *
1182 * Return 0 if Windows is not hibernated on the volume, >0 if Windows is
1183 * hibernated on the volume, and -errno on error.
1184 */
1185static int check_windows_hibernation_status(ntfs_volume *vol)
1186{
1187 MFT_REF mref;
1188 struct inode *vi;
1189 ntfs_inode *ni;
1190 struct page *page;
1191 u32 *kaddr, *kend;
1192 ntfs_name *name = NULL;
1193 int ret = 1;
1194 static const ntfschar hiberfil[13] = { const_cpu_to_le16('h'),
1195 const_cpu_to_le16('i'), const_cpu_to_le16('b'),
1196 const_cpu_to_le16('e'), const_cpu_to_le16('r'),
1197 const_cpu_to_le16('f'), const_cpu_to_le16('i'),
1198 const_cpu_to_le16('l'), const_cpu_to_le16('.'),
1199 const_cpu_to_le16('s'), const_cpu_to_le16('y'),
1200 const_cpu_to_le16('s'), 0 };
1201
1202 ntfs_debug("Entering.");
1203 /*
1204 * Find the inode number for the hibernation file by looking up the
1205 * filename hiberfil.sys in the root directory.
1206 */
1207 down(&vol->root_ino->i_sem);
1208 mref = ntfs_lookup_inode_by_name(NTFS_I(vol->root_ino), hiberfil, 12,
1209 &name);
1210 up(&vol->root_ino->i_sem);
1211 if (IS_ERR_MREF(mref)) {
1212 ret = MREF_ERR(mref);
1213 /* If the file does not exist, Windows is not hibernated. */
1214 if (ret == -ENOENT) {
1215 ntfs_debug("hiberfil.sys not present. Windows is not "
1216 "hibernated on the volume.");
1217 return 0;
1218 }
1219 /* A real error occured. */
1220 ntfs_error(vol->sb, "Failed to find inode number for "
1221 "hiberfil.sys.");
1222 return ret;
1223 }
1224 /* We do not care for the type of match that was found. */
1225 kfree(name);
1226 /* Get the inode. */
1227 vi = ntfs_iget(vol->sb, MREF(mref));
1228 if (IS_ERR(vi) || is_bad_inode(vi)) {
1229 if (!IS_ERR(vi))
1230 iput(vi);
1231 ntfs_error(vol->sb, "Failed to load hiberfil.sys.");
1232 return IS_ERR(vi) ? PTR_ERR(vi) : -EIO;
1233 }
1234 if (unlikely(i_size_read(vi) < NTFS_HIBERFIL_HEADER_SIZE)) {
1235 ntfs_debug("hiberfil.sys is smaller than 4kiB (0x%llx). "
1236 "Windows is hibernated on the volume. This "
1237 "is not the system volume.", i_size_read(vi));
1238 goto iput_out;
1239 }
1240 ni = NTFS_I(vi);
1241 page = ntfs_map_page(vi->i_mapping, 0);
1242 if (IS_ERR(page)) {
1243 ntfs_error(vol->sb, "Failed to read from hiberfil.sys.");
1244 ret = PTR_ERR(page);
1245 goto iput_out;
1246 }
1247 kaddr = (u32*)page_address(page);
1248 if (*(le32*)kaddr == const_cpu_to_le32(0x72626968)/*'hibr'*/) {
1249 ntfs_debug("Magic \"hibr\" found in hiberfil.sys. Windows is "
1250 "hibernated on the volume. This is the "
1251 "system volume.");
1252 goto unm_iput_out;
1253 }
1254 kend = kaddr + NTFS_HIBERFIL_HEADER_SIZE/sizeof(*kaddr);
1255 do {
1256 if (unlikely(*kaddr)) {
1257 ntfs_debug("hiberfil.sys is larger than 4kiB "
1258 "(0x%llx), does not contain the "
1259 "\"hibr\" magic, and does not have a "
1260 "zero header. Windows is hibernated "
1261 "on the volume. This is not the "
1262 "system volume.", i_size_read(vi));
1263 goto unm_iput_out;
1264 }
1265 } while (++kaddr < kend);
1266 ntfs_debug("hiberfil.sys contains a zero header. Windows is not "
1267 "hibernated on the volume. This is the system "
1268 "volume.");
1269 ret = 0;
1270unm_iput_out:
1271 ntfs_unmap_page(page);
1272iput_out:
1273 iput(vi);
1274 return ret;
1275}
1276
1159/** 1277/**
1160 * load_and_init_quota - load and setup the quota file for a volume if present 1278 * load_and_init_quota - load and setup the quota file for a volume if present
1161 * @vol: ntfs super block describing device whose quota file to load 1279 * @vol: ntfs super block describing device whose quota file to load
@@ -1570,6 +1688,9 @@ static BOOL load_system_files(ntfs_volume *vol)
1570 MFT_RECORD *m; 1688 MFT_RECORD *m;
1571 VOLUME_INFORMATION *vi; 1689 VOLUME_INFORMATION *vi;
1572 ntfs_attr_search_ctx *ctx; 1690 ntfs_attr_search_ctx *ctx;
1691#ifdef NTFS_RW
1692 int err;
1693#endif /* NTFS_RW */
1573 1694
1574 ntfs_debug("Entering."); 1695 ntfs_debug("Entering.");
1575#ifdef NTFS_RW 1696#ifdef NTFS_RW
@@ -1746,6 +1867,50 @@ get_ctx_vol_failed:
1746 /* This will prevent a read-write remount. */ 1867 /* This will prevent a read-write remount. */
1747 NVolSetErrors(vol); 1868 NVolSetErrors(vol);
1748 } 1869 }
1870#endif /* NTFS_RW */
1871 /* Get the root directory inode so we can do path lookups. */
1872 vol->root_ino = ntfs_iget(sb, FILE_root);
1873 if (IS_ERR(vol->root_ino) || is_bad_inode(vol->root_ino)) {
1874 if (!IS_ERR(vol->root_ino))
1875 iput(vol->root_ino);
1876 ntfs_error(sb, "Failed to load root directory.");
1877 goto iput_logfile_err_out;
1878 }
1879#ifdef NTFS_RW
1880 /*
1881 * Check if Windows is suspended to disk on the target volume. If it
1882 * is hibernated, we must not write *anything* to the disk so set
1883 * NVolErrors() without setting the dirty volume flag and mount
1884 * read-only. This will prevent read-write remounting and it will also
1885 * prevent all writes.
1886 */
1887 err = check_windows_hibernation_status(vol);
1888 if (unlikely(err)) {
1889 static const char *es1a = "Failed to determine if Windows is "
1890 "hibernated";
1891 static const char *es1b = "Windows is hibernated";
1892 static const char *es2 = ". Run chkdsk.";
1893 const char *es1;
1894
1895 es1 = err < 0 ? es1a : es1b;
1896 /* If a read-write mount, convert it to a read-only mount. */
1897 if (!(sb->s_flags & MS_RDONLY)) {
1898 if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
1899 ON_ERRORS_CONTINUE))) {
1900 ntfs_error(sb, "%s and neither on_errors="
1901 "continue nor on_errors="
1902 "remount-ro was specified%s",
1903 es1, es2);
1904 goto iput_root_err_out;
1905 }
1906 sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
1907 ntfs_error(sb, "%s. Mounting read-only%s", es1, es2);
1908 } else
1909 ntfs_warning(sb, "%s. Will not be able to remount "
1910 "read-write%s", es1, es2);
1911 /* This will prevent a read-write remount. */
1912 NVolSetErrors(vol);
1913 }
1749 /* If (still) a read-write mount, mark the volume dirty. */ 1914 /* If (still) a read-write mount, mark the volume dirty. */
1750 if (!(sb->s_flags & MS_RDONLY) && 1915 if (!(sb->s_flags & MS_RDONLY) &&
1751 ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) { 1916 ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) {
@@ -1759,7 +1924,7 @@ get_ctx_vol_failed:
1759 ntfs_error(sb, "%s and neither on_errors=continue nor " 1924 ntfs_error(sb, "%s and neither on_errors=continue nor "
1760 "on_errors=remount-ro was specified%s", 1925 "on_errors=remount-ro was specified%s",
1761 es1, es2); 1926 es1, es2);
1762 goto iput_logfile_err_out; 1927 goto iput_root_err_out;
1763 } 1928 }
1764 ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); 1929 ntfs_error(sb, "%s. Mounting read-only%s", es1, es2);
1765 sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; 1930 sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
@@ -1786,7 +1951,7 @@ get_ctx_vol_failed:
1786 ntfs_error(sb, "%s and neither on_errors=continue nor " 1951 ntfs_error(sb, "%s and neither on_errors=continue nor "
1787 "on_errors=remount-ro was specified%s", 1952 "on_errors=remount-ro was specified%s",
1788 es1, es2); 1953 es1, es2);
1789 goto iput_logfile_err_out; 1954 goto iput_root_err_out;
1790 } 1955 }
1791 ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); 1956 ntfs_error(sb, "%s. Mounting read-only%s", es1, es2);
1792 sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; 1957 sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
@@ -1805,21 +1970,13 @@ get_ctx_vol_failed:
1805 ntfs_error(sb, "%s and neither on_errors=continue nor " 1970 ntfs_error(sb, "%s and neither on_errors=continue nor "
1806 "on_errors=remount-ro was specified%s", 1971 "on_errors=remount-ro was specified%s",
1807 es1, es2); 1972 es1, es2);
1808 goto iput_logfile_err_out; 1973 goto iput_root_err_out;
1809 } 1974 }
1810 ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); 1975 ntfs_error(sb, "%s. Mounting read-only%s", es1, es2);
1811 sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; 1976 sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
1812 NVolSetErrors(vol); 1977 NVolSetErrors(vol);
1813 } 1978 }
1814#endif /* NTFS_RW */ 1979#endif /* NTFS_RW */
1815 /* Get the root directory inode. */
1816 vol->root_ino = ntfs_iget(sb, FILE_root);
1817 if (IS_ERR(vol->root_ino) || is_bad_inode(vol->root_ino)) {
1818 if (!IS_ERR(vol->root_ino))
1819 iput(vol->root_ino);
1820 ntfs_error(sb, "Failed to load root directory.");
1821 goto iput_logfile_err_out;
1822 }
1823 /* If on NTFS versions before 3.0, we are done. */ 1980 /* If on NTFS versions before 3.0, we are done. */
1824 if (unlikely(vol->major_ver < 3)) 1981 if (unlikely(vol->major_ver < 3))
1825 return TRUE; 1982 return TRUE;