diff options
-rw-r--r-- | fs/ntfs/ChangeLog | 2 | ||||
-rw-r--r-- | fs/ntfs/inode.c | 215 |
2 files changed, 116 insertions, 101 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 9c5af9c8a8af..ed8d00150931 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -75,6 +75,8 @@ ToDo/Notes: | |||
75 | which leads to lock reversal. | 75 | which leads to lock reversal. |
76 | - Truncate {a,c,m}time to the ntfs supported time granularity when | 76 | - Truncate {a,c,m}time to the ntfs supported time granularity when |
77 | updating the times in the inode in ntfs_setattr(). | 77 | updating the times in the inode in ntfs_setattr(). |
78 | - Fixup handling of sparse, compressed, and encrypted attributes in | ||
79 | fs/ntfs/inode.c::ntfs_read_locked_{,attr_,index_}inode(). | ||
78 | 80 | ||
79 | 2.1.23 - Implement extension of resident files and make writing safe as well as | 81 | 2.1.23 - Implement extension of resident files and make writing safe as well as |
80 | many bug fixes, cleanups, and enhancements... | 82 | many bug fixes, cleanups, and enhancements... |
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 89d844f69244..dc4bbe3acf5c 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
@@ -1013,41 +1013,50 @@ skip_large_dir_stuff: | |||
1013 | } | 1013 | } |
1014 | a = ctx->attr; | 1014 | a = ctx->attr; |
1015 | /* Setup the state. */ | 1015 | /* Setup the state. */ |
1016 | if (a->non_resident) { | 1016 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) { |
1017 | NInoSetNonResident(ni); | 1017 | if (a->flags & ATTR_COMPRESSION_MASK) { |
1018 | if (a->flags & (ATTR_COMPRESSION_MASK | | 1018 | NInoSetCompressed(ni); |
1019 | ATTR_IS_SPARSE)) { | 1019 | if (vol->cluster_size > 4096) { |
1020 | if (a->flags & ATTR_COMPRESSION_MASK) { | 1020 | ntfs_error(vi->i_sb, "Found " |
1021 | NInoSetCompressed(ni); | ||
1022 | if (vol->cluster_size > 4096) { | ||
1023 | ntfs_error(vi->i_sb, "Found " | ||
1024 | "compressed data but " | 1021 | "compressed data but " |
1025 | "compression is " | 1022 | "compression is " |
1026 | "disabled due to " | 1023 | "disabled due to " |
1027 | "cluster size (%i) > " | 1024 | "cluster size (%i) > " |
1028 | "4kiB.", | 1025 | "4kiB.", |
1029 | vol->cluster_size); | 1026 | vol->cluster_size); |
1030 | goto unm_err_out; | 1027 | goto unm_err_out; |
1031 | } | 1028 | } |
1032 | if ((a->flags & ATTR_COMPRESSION_MASK) | 1029 | if ((a->flags & ATTR_COMPRESSION_MASK) |
1033 | != ATTR_IS_COMPRESSED) { | 1030 | != ATTR_IS_COMPRESSED) { |
1034 | ntfs_error(vi->i_sb, "Found " | 1031 | ntfs_error(vi->i_sb, "Found unknown " |
1035 | "unknown compression " | 1032 | "compression method " |
1036 | "method or corrupt " | 1033 | "or corrupt file."); |
1037 | "file."); | 1034 | goto unm_err_out; |
1038 | goto unm_err_out; | ||
1039 | } | ||
1040 | } | 1035 | } |
1041 | if (a->flags & ATTR_IS_SPARSE) | 1036 | } |
1042 | NInoSetSparse(ni); | 1037 | if (a->flags & ATTR_IS_SPARSE) |
1038 | NInoSetSparse(ni); | ||
1039 | } | ||
1040 | if (a->flags & ATTR_IS_ENCRYPTED) { | ||
1041 | if (NInoCompressed(ni)) { | ||
1042 | ntfs_error(vi->i_sb, "Found encrypted and " | ||
1043 | "compressed data."); | ||
1044 | goto unm_err_out; | ||
1045 | } | ||
1046 | NInoSetEncrypted(ni); | ||
1047 | } | ||
1048 | if (a->non_resident) { | ||
1049 | NInoSetNonResident(ni); | ||
1050 | if (NInoCompressed(ni) || NInoSparse(ni)) { | ||
1043 | if (a->data.non_resident.compression_unit != | 1051 | if (a->data.non_resident.compression_unit != |
1044 | 4) { | 1052 | 4) { |
1045 | ntfs_error(vi->i_sb, "Found " | 1053 | ntfs_error(vi->i_sb, "Found " |
1046 | "nonstandard compression unit " | 1054 | "nonstandard " |
1047 | "(%u instead of 4). Cannot " | 1055 | "compression unit (%u " |
1048 | "handle this.", | 1056 | "instead of 4). " |
1049 | a->data.non_resident. | 1057 | "Cannot handle this.", |
1050 | compression_unit); | 1058 | a->data.non_resident. |
1059 | compression_unit); | ||
1051 | err = -EOPNOTSUPP; | 1060 | err = -EOPNOTSUPP; |
1052 | goto unm_err_out; | 1061 | goto unm_err_out; |
1053 | } | 1062 | } |
@@ -1065,14 +1074,6 @@ skip_large_dir_stuff: | |||
1065 | a->data.non_resident. | 1074 | a->data.non_resident. |
1066 | compressed_size); | 1075 | compressed_size); |
1067 | } | 1076 | } |
1068 | if (a->flags & ATTR_IS_ENCRYPTED) { | ||
1069 | if (a->flags & ATTR_COMPRESSION_MASK) { | ||
1070 | ntfs_error(vi->i_sb, "Found encrypted " | ||
1071 | "and compressed data."); | ||
1072 | goto unm_err_out; | ||
1073 | } | ||
1074 | NInoSetEncrypted(ni); | ||
1075 | } | ||
1076 | if (a->data.non_resident.lowest_vcn) { | 1077 | if (a->data.non_resident.lowest_vcn) { |
1077 | ntfs_error(vi->i_sb, "First extent of $DATA " | 1078 | ntfs_error(vi->i_sb, "First extent of $DATA " |
1078 | "attribute has non zero " | 1079 | "attribute has non zero " |
@@ -1212,6 +1213,75 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1212 | if (unlikely(err)) | 1213 | if (unlikely(err)) |
1213 | goto unm_err_out; | 1214 | goto unm_err_out; |
1214 | a = ctx->attr; | 1215 | a = ctx->attr; |
1216 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) { | ||
1217 | if (a->flags & ATTR_COMPRESSION_MASK) { | ||
1218 | NInoSetCompressed(ni); | ||
1219 | if ((ni->type != AT_DATA) || (ni->type == AT_DATA && | ||
1220 | ni->name_len)) { | ||
1221 | ntfs_error(vi->i_sb, "Found compressed " | ||
1222 | "non-data or named data " | ||
1223 | "attribute. Please report " | ||
1224 | "you saw this message to " | ||
1225 | "linux-ntfs-dev@lists." | ||
1226 | "sourceforge.net"); | ||
1227 | goto unm_err_out; | ||
1228 | } | ||
1229 | if (vol->cluster_size > 4096) { | ||
1230 | ntfs_error(vi->i_sb, "Found compressed " | ||
1231 | "attribute but compression is " | ||
1232 | "disabled due to cluster size " | ||
1233 | "(%i) > 4kiB.", | ||
1234 | vol->cluster_size); | ||
1235 | goto unm_err_out; | ||
1236 | } | ||
1237 | if ((a->flags & ATTR_COMPRESSION_MASK) != | ||
1238 | ATTR_IS_COMPRESSED) { | ||
1239 | ntfs_error(vi->i_sb, "Found unknown " | ||
1240 | "compression method."); | ||
1241 | goto unm_err_out; | ||
1242 | } | ||
1243 | } | ||
1244 | /* | ||
1245 | * The encryption flag set in an index root just means to | ||
1246 | * compress all files. | ||
1247 | */ | ||
1248 | if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { | ||
1249 | ntfs_error(vi->i_sb, "Found mst protected attribute " | ||
1250 | "but the attribute is %s. Please " | ||
1251 | "report you saw this message to " | ||
1252 | "linux-ntfs-dev@lists.sourceforge.net", | ||
1253 | NInoCompressed(ni) ? "compressed" : | ||
1254 | "sparse"); | ||
1255 | goto unm_err_out; | ||
1256 | } | ||
1257 | if (a->flags & ATTR_IS_SPARSE) | ||
1258 | NInoSetSparse(ni); | ||
1259 | } | ||
1260 | if (a->flags & ATTR_IS_ENCRYPTED) { | ||
1261 | if (NInoCompressed(ni)) { | ||
1262 | ntfs_error(vi->i_sb, "Found encrypted and compressed " | ||
1263 | "data."); | ||
1264 | goto unm_err_out; | ||
1265 | } | ||
1266 | /* | ||
1267 | * The encryption flag set in an index root just means to | ||
1268 | * encrypt all files. | ||
1269 | */ | ||
1270 | if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { | ||
1271 | ntfs_error(vi->i_sb, "Found mst protected attribute " | ||
1272 | "but the attribute is encrypted. " | ||
1273 | "Please report you saw this message " | ||
1274 | "to linux-ntfs-dev@lists.sourceforge." | ||
1275 | "net"); | ||
1276 | goto unm_err_out; | ||
1277 | } | ||
1278 | if (ni->type != AT_DATA) { | ||
1279 | ntfs_error(vi->i_sb, "Found encrypted non-data " | ||
1280 | "attribute."); | ||
1281 | goto unm_err_out; | ||
1282 | } | ||
1283 | NInoSetEncrypted(ni); | ||
1284 | } | ||
1215 | if (!a->non_resident) { | 1285 | if (!a->non_resident) { |
1216 | /* Ensure the attribute name is placed before the value. */ | 1286 | /* Ensure the attribute name is placed before the value. */ |
1217 | if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= | 1287 | if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= |
@@ -1220,11 +1290,10 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1220 | "the attribute value."); | 1290 | "the attribute value."); |
1221 | goto unm_err_out; | 1291 | goto unm_err_out; |
1222 | } | 1292 | } |
1223 | if (NInoMstProtected(ni) || a->flags) { | 1293 | if (NInoMstProtected(ni)) { |
1224 | ntfs_error(vi->i_sb, "Found mst protected attribute " | 1294 | ntfs_error(vi->i_sb, "Found mst protected attribute " |
1225 | "or attribute with non-zero flags but " | 1295 | "but the attribute is resident. " |
1226 | "the attribute is resident. Please " | 1296 | "Please report you saw this message to " |
1227 | "report you saw this message to " | ||
1228 | "linux-ntfs-dev@lists.sourceforge.net"); | 1297 | "linux-ntfs-dev@lists.sourceforge.net"); |
1229 | goto unm_err_out; | 1298 | goto unm_err_out; |
1230 | } | 1299 | } |
@@ -1250,50 +1319,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1250 | "the mapping pairs array."); | 1319 | "the mapping pairs array."); |
1251 | goto unm_err_out; | 1320 | goto unm_err_out; |
1252 | } | 1321 | } |
1253 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) { | 1322 | if ((NInoCompressed(ni) || NInoSparse(ni)) && |
1254 | if (a->flags & ATTR_COMPRESSION_MASK) { | 1323 | ni->type != AT_INDEX_ROOT) { |
1255 | NInoSetCompressed(ni); | ||
1256 | if ((ni->type != AT_DATA) || (ni->type == | ||
1257 | AT_DATA && ni->name_len)) { | ||
1258 | ntfs_error(vi->i_sb, "Found compressed " | ||
1259 | "non-data or named " | ||
1260 | "data attribute. " | ||
1261 | "Please report you " | ||
1262 | "saw this message to " | ||
1263 | "linux-ntfs-dev@lists." | ||
1264 | "sourceforge.net"); | ||
1265 | goto unm_err_out; | ||
1266 | } | ||
1267 | if (vol->cluster_size > 4096) { | ||
1268 | ntfs_error(vi->i_sb, "Found compressed " | ||
1269 | "attribute but " | ||
1270 | "compression is " | ||
1271 | "disabled due to " | ||
1272 | "cluster size (%i) > " | ||
1273 | "4kiB.", | ||
1274 | vol->cluster_size); | ||
1275 | goto unm_err_out; | ||
1276 | } | ||
1277 | if ((a->flags & ATTR_COMPRESSION_MASK) != | ||
1278 | ATTR_IS_COMPRESSED) { | ||
1279 | ntfs_error(vi->i_sb, "Found unknown " | ||
1280 | "compression method."); | ||
1281 | goto unm_err_out; | ||
1282 | } | ||
1283 | } | ||
1284 | if (NInoMstProtected(ni)) { | ||
1285 | ntfs_error(vi->i_sb, "Found mst protected " | ||
1286 | "attribute but the attribute " | ||
1287 | "is %s. Please report you " | ||
1288 | "saw this message to " | ||
1289 | "linux-ntfs-dev@lists." | ||
1290 | "sourceforge.net", | ||
1291 | NInoCompressed(ni) ? | ||
1292 | "compressed" : "sparse"); | ||
1293 | goto unm_err_out; | ||
1294 | } | ||
1295 | if (a->flags & ATTR_IS_SPARSE) | ||
1296 | NInoSetSparse(ni); | ||
1297 | if (a->data.non_resident.compression_unit != 4) { | 1324 | if (a->data.non_resident.compression_unit != 4) { |
1298 | ntfs_error(vi->i_sb, "Found nonstandard " | 1325 | ntfs_error(vi->i_sb, "Found nonstandard " |
1299 | "compression unit (%u instead " | 1326 | "compression unit (%u instead " |
@@ -1313,23 +1340,6 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1313 | ni->itype.compressed.size = sle64_to_cpu( | 1340 | ni->itype.compressed.size = sle64_to_cpu( |
1314 | a->data.non_resident.compressed_size); | 1341 | a->data.non_resident.compressed_size); |
1315 | } | 1342 | } |
1316 | if (a->flags & ATTR_IS_ENCRYPTED) { | ||
1317 | if (a->flags & ATTR_COMPRESSION_MASK) { | ||
1318 | ntfs_error(vi->i_sb, "Found encrypted and " | ||
1319 | "compressed data."); | ||
1320 | goto unm_err_out; | ||
1321 | } | ||
1322 | if (NInoMstProtected(ni)) { | ||
1323 | ntfs_error(vi->i_sb, "Found mst protected " | ||
1324 | "attribute but the attribute " | ||
1325 | "is encrypted. Please report " | ||
1326 | "you saw this message to " | ||
1327 | "linux-ntfs-dev@lists." | ||
1328 | "sourceforge.net"); | ||
1329 | goto unm_err_out; | ||
1330 | } | ||
1331 | NInoSetEncrypted(ni); | ||
1332 | } | ||
1333 | if (a->data.non_resident.lowest_vcn) { | 1343 | if (a->data.non_resident.lowest_vcn) { |
1334 | ntfs_error(vi->i_sb, "First extent of attribute has " | 1344 | ntfs_error(vi->i_sb, "First extent of attribute has " |
1335 | "non-zero lowest_vcn."); | 1345 | "non-zero lowest_vcn."); |
@@ -1348,12 +1358,12 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
1348 | vi->i_mapping->a_ops = &ntfs_mst_aops; | 1358 | vi->i_mapping->a_ops = &ntfs_mst_aops; |
1349 | else | 1359 | else |
1350 | vi->i_mapping->a_ops = &ntfs_aops; | 1360 | vi->i_mapping->a_ops = &ntfs_aops; |
1351 | if (NInoCompressed(ni) || NInoSparse(ni)) | 1361 | if ((NInoCompressed(ni) || NInoSparse(ni)) && ni->type != AT_INDEX_ROOT) |
1352 | vi->i_blocks = ni->itype.compressed.size >> 9; | 1362 | vi->i_blocks = ni->itype.compressed.size >> 9; |
1353 | else | 1363 | else |
1354 | vi->i_blocks = ni->allocated_size >> 9; | 1364 | vi->i_blocks = ni->allocated_size >> 9; |
1355 | /* | 1365 | /* |
1356 | * Make sure the base inode doesn't go away and attach it to the | 1366 | * Make sure the base inode does not go away and attach it to the |
1357 | * attribute inode. | 1367 | * attribute inode. |
1358 | */ | 1368 | */ |
1359 | igrab(base_vi); | 1369 | igrab(base_vi); |
@@ -1480,7 +1490,10 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) | |||
1480 | "after the attribute value."); | 1490 | "after the attribute value."); |
1481 | goto unm_err_out; | 1491 | goto unm_err_out; |
1482 | } | 1492 | } |
1483 | /* Compressed/encrypted/sparse index root is not allowed. */ | 1493 | /* |
1494 | * Compressed/encrypted/sparse index root is not allowed, except for | ||
1495 | * directories of course but those are not dealt with here. | ||
1496 | */ | ||
1484 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED | | 1497 | if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED | |
1485 | ATTR_IS_SPARSE)) { | 1498 | ATTR_IS_SPARSE)) { |
1486 | ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index " | 1499 | ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index " |