diff options
Diffstat (limited to 'fs/ntfs')
-rw-r--r-- | fs/ntfs/ChangeLog | 2 | ||||
-rw-r--r-- | fs/ntfs/aops.c | 104 |
2 files changed, 49 insertions, 57 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index b1766642baf8..4b8666d7e7fe 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -79,6 +79,8 @@ ToDo/Notes: | |||
79 | fs/ntfs/inode.c::ntfs_read_locked_{,attr_,index_}inode(). | 79 | fs/ntfs/inode.c::ntfs_read_locked_{,attr_,index_}inode(). |
80 | - Make ntfs_write_block() not instantiate sparse blocks if they contain | 80 | - Make ntfs_write_block() not instantiate sparse blocks if they contain |
81 | only zeroes. | 81 | only zeroes. |
82 | - Fixup handling of sparse, compressed, and encrypted attributes in | ||
83 | fs/ntfs/aops.c::ntfs_writepage(). | ||
82 | 84 | ||
83 | 2.1.23 - Implement extension of resident files and make writing safe as well as | 85 | 2.1.23 - Implement extension of resident files and make writing safe as well as |
84 | many bug fixes, cleanups, and enhancements... | 86 | many bug fixes, cleanups, and enhancements... |
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index f3ad36d8b8c9..6f2954aac5a2 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c | |||
@@ -1301,38 +1301,42 @@ retry_writepage: | |||
1301 | ntfs_debug("Write outside i_size - truncated?"); | 1301 | ntfs_debug("Write outside i_size - truncated?"); |
1302 | return 0; | 1302 | return 0; |
1303 | } | 1303 | } |
1304 | /* | ||
1305 | * Only $DATA attributes can be encrypted and only unnamed $DATA | ||
1306 | * attributes can be compressed. Index root can have the flags set but | ||
1307 | * this means to create compressed/encrypted files, not that the | ||
1308 | * attribute is compressed/encrypted. | ||
1309 | */ | ||
1310 | if (ni->type != AT_INDEX_ROOT) { | ||
1311 | /* If file is encrypted, deny access, just like NT4. */ | ||
1312 | if (NInoEncrypted(ni)) { | ||
1313 | unlock_page(page); | ||
1314 | BUG_ON(ni->type != AT_DATA); | ||
1315 | ntfs_debug("Denying write access to encrypted " | ||
1316 | "file."); | ||
1317 | return -EACCES; | ||
1318 | } | ||
1319 | /* Compressed data streams are handled in compress.c. */ | ||
1320 | if (NInoNonResident(ni) && NInoCompressed(ni)) { | ||
1321 | BUG_ON(ni->type != AT_DATA); | ||
1322 | BUG_ON(ni->name_len); | ||
1323 | // TODO: Implement and replace this with | ||
1324 | // return ntfs_write_compressed_block(page); | ||
1325 | unlock_page(page); | ||
1326 | ntfs_error(vi->i_sb, "Writing to compressed files is " | ||
1327 | "not supported yet. Sorry."); | ||
1328 | return -EOPNOTSUPP; | ||
1329 | } | ||
1330 | // TODO: Implement and remove this check. | ||
1331 | if (NInoNonResident(ni) && NInoSparse(ni)) { | ||
1332 | unlock_page(page); | ||
1333 | ntfs_error(vi->i_sb, "Writing to sparse files is not " | ||
1334 | "supported yet. Sorry."); | ||
1335 | return -EOPNOTSUPP; | ||
1336 | } | ||
1337 | } | ||
1304 | /* NInoNonResident() == NInoIndexAllocPresent() */ | 1338 | /* NInoNonResident() == NInoIndexAllocPresent() */ |
1305 | if (NInoNonResident(ni)) { | 1339 | if (NInoNonResident(ni)) { |
1306 | /* | ||
1307 | * Only unnamed $DATA attributes can be compressed, encrypted, | ||
1308 | * and/or sparse. | ||
1309 | */ | ||
1310 | if (ni->type == AT_DATA && !ni->name_len) { | ||
1311 | /* If file is encrypted, deny access, just like NT4. */ | ||
1312 | if (NInoEncrypted(ni)) { | ||
1313 | unlock_page(page); | ||
1314 | ntfs_debug("Denying write access to encrypted " | ||
1315 | "file."); | ||
1316 | return -EACCES; | ||
1317 | } | ||
1318 | /* Compressed data streams are handled in compress.c. */ | ||
1319 | if (NInoCompressed(ni)) { | ||
1320 | // TODO: Implement and replace this check with | ||
1321 | // return ntfs_write_compressed_block(page); | ||
1322 | unlock_page(page); | ||
1323 | ntfs_error(vi->i_sb, "Writing to compressed " | ||
1324 | "files is not supported yet. " | ||
1325 | "Sorry."); | ||
1326 | return -EOPNOTSUPP; | ||
1327 | } | ||
1328 | // TODO: Implement and remove this check. | ||
1329 | if (NInoSparse(ni)) { | ||
1330 | unlock_page(page); | ||
1331 | ntfs_error(vi->i_sb, "Writing to sparse files " | ||
1332 | "is not supported yet. Sorry."); | ||
1333 | return -EOPNOTSUPP; | ||
1334 | } | ||
1335 | } | ||
1336 | /* We have to zero every time due to mmap-at-end-of-file. */ | 1340 | /* We have to zero every time due to mmap-at-end-of-file. */ |
1337 | if (page->index >= (i_size >> PAGE_CACHE_SHIFT)) { | 1341 | if (page->index >= (i_size >> PAGE_CACHE_SHIFT)) { |
1338 | /* The page straddles i_size. */ | 1342 | /* The page straddles i_size. */ |
@@ -1345,14 +1349,16 @@ retry_writepage: | |||
1345 | /* Handle mst protected attributes. */ | 1349 | /* Handle mst protected attributes. */ |
1346 | if (NInoMstProtected(ni)) | 1350 | if (NInoMstProtected(ni)) |
1347 | return ntfs_write_mst_block(page, wbc); | 1351 | return ntfs_write_mst_block(page, wbc); |
1348 | /* Normal data stream. */ | 1352 | /* Normal, non-resident data stream. */ |
1349 | return ntfs_write_block(page, wbc); | 1353 | return ntfs_write_block(page, wbc); |
1350 | } | 1354 | } |
1351 | /* | 1355 | /* |
1352 | * Attribute is resident, implying it is not compressed, encrypted, | 1356 | * Attribute is resident, implying it is not compressed, encrypted, or |
1353 | * sparse, or mst protected. This also means the attribute is smaller | 1357 | * mst protected. This also means the attribute is smaller than an mft |
1354 | * than an mft record and hence smaller than a page, so can simply | 1358 | * record and hence smaller than a page, so can simply return error on |
1355 | * return error on any pages with index above 0. | 1359 | * any pages with index above 0. Note the attribute can actually be |
1360 | * marked compressed but if it is resident the actual data is not | ||
1361 | * compressed so we are ok to ignore the compressed flag here. | ||
1356 | */ | 1362 | */ |
1357 | BUG_ON(page_has_buffers(page)); | 1363 | BUG_ON(page_has_buffers(page)); |
1358 | BUG_ON(!PageUptodate(page)); | 1364 | BUG_ON(!PageUptodate(page)); |
@@ -1401,30 +1407,14 @@ retry_writepage: | |||
1401 | BUG_ON(PageWriteback(page)); | 1407 | BUG_ON(PageWriteback(page)); |
1402 | set_page_writeback(page); | 1408 | set_page_writeback(page); |
1403 | unlock_page(page); | 1409 | unlock_page(page); |
1404 | |||
1405 | /* | 1410 | /* |
1406 | * Here, we don't need to zero the out of bounds area everytime because | 1411 | * Here, we do not need to zero the out of bounds area everytime |
1407 | * the below memcpy() already takes care of the mmap-at-end-of-file | 1412 | * because the below memcpy() already takes care of the |
1408 | * requirements. If the file is converted to a non-resident one, then | 1413 | * mmap-at-end-of-file requirements. If the file is converted to a |
1409 | * the code path use is switched to the non-resident one where the | 1414 | * non-resident one, then the code path use is switched to the |
1410 | * zeroing happens on each ntfs_writepage() invocation. | 1415 | * non-resident one where the zeroing happens on each ntfs_writepage() |
1411 | * | 1416 | * invocation. |
1412 | * The above also applies nicely when i_size is decreased. | ||
1413 | * | ||
1414 | * When i_size is increased, the memory between the old and new i_size | ||
1415 | * _must_ be zeroed (or overwritten with new data). Otherwise we will | ||
1416 | * expose data to userspace/disk which should never have been exposed. | ||
1417 | * | ||
1418 | * FIXME: Ensure that i_size increases do the zeroing/overwriting and | ||
1419 | * if we cannot guarantee that, then enable the zeroing below. If the | ||
1420 | * zeroing below is enabled, we MUST move the unlock_page() from above | ||
1421 | * to after the kunmap_atomic(), i.e. just before the | ||
1422 | * end_page_writeback(). | ||
1423 | * UPDATE: ntfs_prepare/commit_write() do the zeroing on i_size | ||
1424 | * increases for resident attributes so those are ok. | ||
1425 | * TODO: ntfs_truncate(), others? | ||
1426 | */ | 1417 | */ |
1427 | |||
1428 | attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); | 1418 | attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); |
1429 | i_size = i_size_read(vi); | 1419 | i_size = i_size_read(vi); |
1430 | if (unlikely(attr_len > i_size)) { | 1420 | if (unlikely(attr_len > i_size)) { |