Commit bd45fdd2 authored by Anton Altaparmakov's avatar Anton Altaparmakov

NTFS: Fixup handling of sparse, compressed, and encrypted attributes in

      fs/ntfs/aops.c::ntfs_writepage().
Signed-off-by: default avatarAnton Altaparmakov <aia21@cantab.net>
parent 8dcdebaf
...@@ -79,6 +79,8 @@ ToDo/Notes: ...@@ -79,6 +79,8 @@ ToDo/Notes:
fs/ntfs/inode.c::ntfs_read_locked_{,attr_,index_}inode(). fs/ntfs/inode.c::ntfs_read_locked_{,attr_,index_}inode().
- Make ntfs_write_block() not instantiate sparse blocks if they contain - Make ntfs_write_block() not instantiate sparse blocks if they contain
only zeroes. only zeroes.
- Fixup handling of sparse, compressed, and encrypted attributes in
fs/ntfs/aops.c::ntfs_writepage().
2.1.23 - Implement extension of resident files and make writing safe as well as 2.1.23 - Implement extension of resident files and make writing safe as well as
many bug fixes, cleanups, and enhancements... many bug fixes, cleanups, and enhancements...
......
...@@ -1301,38 +1301,42 @@ retry_writepage: ...@@ -1301,38 +1301,42 @@ retry_writepage:
ntfs_debug("Write outside i_size - truncated?"); ntfs_debug("Write outside i_size - truncated?");
return 0; return 0;
} }
/*
* Only $DATA attributes can be encrypted and only unnamed $DATA
* attributes can be compressed. Index root can have the flags set but
* this means to create compressed/encrypted files, not that the
* attribute is compressed/encrypted.
*/
if (ni->type != AT_INDEX_ROOT) {
/* If file is encrypted, deny access, just like NT4. */
if (NInoEncrypted(ni)) {
unlock_page(page);
BUG_ON(ni->type != AT_DATA);
ntfs_debug("Denying write access to encrypted "
"file.");
return -EACCES;
}
/* Compressed data streams are handled in compress.c. */
if (NInoNonResident(ni) && NInoCompressed(ni)) {
BUG_ON(ni->type != AT_DATA);
BUG_ON(ni->name_len);
// TODO: Implement and replace this with
// return ntfs_write_compressed_block(page);
unlock_page(page);
ntfs_error(vi->i_sb, "Writing to compressed files is "
"not supported yet. Sorry.");
return -EOPNOTSUPP;
}
// TODO: Implement and remove this check.
if (NInoNonResident(ni) && NInoSparse(ni)) {
unlock_page(page);
ntfs_error(vi->i_sb, "Writing to sparse files is not "
"supported yet. Sorry.");
return -EOPNOTSUPP;
}
}
/* NInoNonResident() == NInoIndexAllocPresent() */ /* NInoNonResident() == NInoIndexAllocPresent() */
if (NInoNonResident(ni)) { if (NInoNonResident(ni)) {
/*
* Only unnamed $DATA attributes can be compressed, encrypted,
* and/or sparse.
*/
if (ni->type == AT_DATA && !ni->name_len) {
/* If file is encrypted, deny access, just like NT4. */
if (NInoEncrypted(ni)) {
unlock_page(page);
ntfs_debug("Denying write access to encrypted "
"file.");
return -EACCES;
}
/* Compressed data streams are handled in compress.c. */
if (NInoCompressed(ni)) {
// TODO: Implement and replace this check with
// return ntfs_write_compressed_block(page);
unlock_page(page);
ntfs_error(vi->i_sb, "Writing to compressed "
"files is not supported yet. "
"Sorry.");
return -EOPNOTSUPP;
}
// TODO: Implement and remove this check.
if (NInoSparse(ni)) {
unlock_page(page);
ntfs_error(vi->i_sb, "Writing to sparse files "
"is not supported yet. Sorry.");
return -EOPNOTSUPP;
}
}
/* We have to zero every time due to mmap-at-end-of-file. */ /* We have to zero every time due to mmap-at-end-of-file. */
if (page->index >= (i_size >> PAGE_CACHE_SHIFT)) { if (page->index >= (i_size >> PAGE_CACHE_SHIFT)) {
/* The page straddles i_size. */ /* The page straddles i_size. */
...@@ -1345,14 +1349,16 @@ retry_writepage: ...@@ -1345,14 +1349,16 @@ retry_writepage:
/* Handle mst protected attributes. */ /* Handle mst protected attributes. */
if (NInoMstProtected(ni)) if (NInoMstProtected(ni))
return ntfs_write_mst_block(page, wbc); return ntfs_write_mst_block(page, wbc);
/* Normal data stream. */ /* Normal, non-resident data stream. */
return ntfs_write_block(page, wbc); return ntfs_write_block(page, wbc);
} }
/* /*
* Attribute is resident, implying it is not compressed, encrypted, * Attribute is resident, implying it is not compressed, encrypted, or
* sparse, or mst protected. This also means the attribute is smaller * mst protected. This also means the attribute is smaller than an mft
* than an mft record and hence smaller than a page, so can simply * record and hence smaller than a page, so can simply return error on
* return error on any pages with index above 0. * any pages with index above 0. Note the attribute can actually be
* marked compressed but if it is resident the actual data is not
* compressed so we are ok to ignore the compressed flag here.
*/ */
BUG_ON(page_has_buffers(page)); BUG_ON(page_has_buffers(page));
BUG_ON(!PageUptodate(page)); BUG_ON(!PageUptodate(page));
...@@ -1401,30 +1407,14 @@ retry_writepage: ...@@ -1401,30 +1407,14 @@ retry_writepage:
BUG_ON(PageWriteback(page)); BUG_ON(PageWriteback(page));
set_page_writeback(page); set_page_writeback(page);
unlock_page(page); unlock_page(page);
/* /*
* Here, we don't need to zero the out of bounds area everytime because * Here, we do not need to zero the out of bounds area everytime
* the below memcpy() already takes care of the mmap-at-end-of-file * because the below memcpy() already takes care of the
* requirements. If the file is converted to a non-resident one, then * mmap-at-end-of-file requirements. If the file is converted to a
* the code path use is switched to the non-resident one where the * non-resident one, then the code path use is switched to the
* zeroing happens on each ntfs_writepage() invocation. * non-resident one where the zeroing happens on each ntfs_writepage()
* * invocation.
* The above also applies nicely when i_size is decreased.
*
* When i_size is increased, the memory between the old and new i_size
* _must_ be zeroed (or overwritten with new data). Otherwise we will
* expose data to userspace/disk which should never have been exposed.
*
* FIXME: Ensure that i_size increases do the zeroing/overwriting and
* if we cannot guarantee that, then enable the zeroing below. If the
* zeroing below is enabled, we MUST move the unlock_page() from above
* to after the kunmap_atomic(), i.e. just before the
* end_page_writeback().
* UPDATE: ntfs_prepare/commit_write() do the zeroing on i_size
* increases for resident attributes so those are ok.
* TODO: ntfs_truncate(), others?
*/ */
attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
i_size = i_size_read(vi); i_size = i_size_read(vi);
if (unlikely(attr_len > i_size)) { if (unlikely(attr_len > i_size)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment