Commit 36b93aed authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ntfs3_for_6.5' of https://github.com/Paragon-Software-Group/linux-ntfs3

Pull ntfs3 updates from Konstantin Komarov:
 "Updates:
   - support /proc/fs/ntfs3/<dev>/volinfo and label
   - alternative boot if primary boot is corrupted
   - small optimizations

  Fixes:
   - fix endian problems
   - fix logic errors
   - code refactoring and reformatting"

* tag 'ntfs3_for_6.5' of https://github.com/Paragon-Software-Group/linux-ntfs3:
  fs/ntfs3: Correct mode for label entry inside /proc/fs/ntfs3/
  fs/ntfs3: Add support /proc/fs/ntfs3/<dev>/volinfo and /proc/fs/ntfs3/<dev>/label
  fs/ntfs3: Fix endian problem
  fs/ntfs3: Add ability to format new mft records with bigger/smaller header
  fs/ntfs3: Code refactoring
  fs/ntfs3: Code formatting
  fs/ntfs3: Do not update primary boot in ntfs_init_from_boot()
  fs/ntfs3: Alternative boot if primary boot is corrupted
  fs/ntfs3: Mark ntfs dirty when on-disk struct is corrupted
  fs/ntfs3: Fix ntfs_atomic_open
  fs/ntfs3: Correct checking while generating attr_list
  fs/ntfs3: Use __GFP_NOWARN allocation at ntfs_load_attr_list()
  fs: ntfs3: Fix possible null-pointer dereferences in mi_read()
  fs/ntfs3: Return error for inconsistent extended attributes
  fs/ntfs3: Enhance sanity check while generating attr_list
  fs/ntfs3: Use wrapper i_blocksize() in ntfs_zero_range()
  ntfs: Fix panic about slab-out-of-bounds caused by ntfs_listxattr()
parents 986ffe60 44b4494d
...@@ -573,7 +573,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -573,7 +573,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
sbi, run, vcn, lcn, to_allocate, &pre_alloc, sbi, run, vcn, lcn, to_allocate, &pre_alloc,
is_mft ? ALLOCATE_MFT : ALLOCATE_DEF, &alen, is_mft ? ALLOCATE_MFT : ALLOCATE_DEF, &alen,
is_mft ? 0 : is_mft ? 0 :
(sbi->record_size - (sbi->record_size -
le32_to_cpu(rec->used) + 8) / le32_to_cpu(rec->used) + 8) /
3 + 3 +
1, 1,
......
...@@ -52,7 +52,7 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr) ...@@ -52,7 +52,7 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
if (!attr->non_res) { if (!attr->non_res) {
lsize = le32_to_cpu(attr->res.data_size); lsize = le32_to_cpu(attr->res.data_size);
le = kmalloc(al_aligned(lsize), GFP_NOFS); le = kmalloc(al_aligned(lsize), GFP_NOFS | __GFP_NOWARN);
if (!le) { if (!le) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
...@@ -80,7 +80,7 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr) ...@@ -80,7 +80,7 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
if (err < 0) if (err < 0)
goto out; goto out;
le = kmalloc(al_aligned(lsize), GFP_NOFS); le = kmalloc(al_aligned(lsize), GFP_NOFS | __GFP_NOWARN);
if (!le) { if (!le) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
...@@ -375,8 +375,7 @@ bool al_remove_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le) ...@@ -375,8 +375,7 @@ bool al_remove_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le)
* al_delete_le - Delete first le from the list which matches its parameters. * al_delete_le - Delete first le from the list which matches its parameters.
*/ */
bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn, bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn,
const __le16 *name, size_t name_len, const __le16 *name, u8 name_len, const struct MFT_REF *ref)
const struct MFT_REF *ref)
{ {
u16 size; u16 size;
struct ATTR_LIST_ENTRY *le; struct ATTR_LIST_ENTRY *le;
......
...@@ -287,8 +287,8 @@ static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len, ...@@ -287,8 +287,8 @@ static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len,
/* Check bits before 'bit'. */ /* Check bits before 'bit'. */
ib = wnd->zone_bit == wnd->zone_end || ib = wnd->zone_bit == wnd->zone_end ||
bit < wnd->zone_end ? bit < wnd->zone_end ?
0 : 0 :
wnd->zone_end; wnd->zone_end;
while (bit > ib && wnd_is_free_hlp(wnd, bit - 1, 1)) { while (bit > ib && wnd_is_free_hlp(wnd, bit - 1, 1)) {
bit -= 1; bit -= 1;
...@@ -298,8 +298,8 @@ static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len, ...@@ -298,8 +298,8 @@ static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len,
/* Check bits after 'end_in'. */ /* Check bits after 'end_in'. */
ib = wnd->zone_bit == wnd->zone_end || ib = wnd->zone_bit == wnd->zone_end ||
end_in > wnd->zone_bit ? end_in > wnd->zone_bit ?
wnd->nbits : wnd->nbits :
wnd->zone_bit; wnd->zone_bit;
while (end_in < ib && wnd_is_free_hlp(wnd, end_in, 1)) { while (end_in < ib && wnd_is_free_hlp(wnd, end_in, 1)) {
end_in += 1; end_in += 1;
...@@ -418,7 +418,7 @@ static void wnd_remove_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len) ...@@ -418,7 +418,7 @@ static void wnd_remove_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len)
n3 = rb_first(&wnd->count_tree); n3 = rb_first(&wnd->count_tree);
wnd->extent_max = wnd->extent_max =
n3 ? rb_entry(n3, struct e_node, count.node)->count.key : n3 ? rb_entry(n3, struct e_node, count.node)->count.key :
0; 0;
return; return;
} }
......
...@@ -179,7 +179,7 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to) ...@@ -179,7 +179,7 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to)
{ {
int err = 0; int err = 0;
struct address_space *mapping = inode->i_mapping; struct address_space *mapping = inode->i_mapping;
u32 blocksize = 1 << inode->i_blkbits; u32 blocksize = i_blocksize(inode);
pgoff_t idx = vbo >> PAGE_SHIFT; pgoff_t idx = vbo >> PAGE_SHIFT;
u32 from = vbo & (PAGE_SIZE - 1); u32 from = vbo & (PAGE_SIZE - 1);
pgoff_t idx_end = (vbo_to + PAGE_SIZE - 1) >> PAGE_SHIFT; pgoff_t idx_end = (vbo_to + PAGE_SIZE - 1) >> PAGE_SHIFT;
...@@ -192,7 +192,7 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to) ...@@ -192,7 +192,7 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to)
for (; idx < idx_end; idx += 1, from = 0) { for (; idx < idx_end; idx += 1, from = 0) {
page_off = (loff_t)idx << PAGE_SHIFT; page_off = (loff_t)idx << PAGE_SHIFT;
to = (page_off + PAGE_SIZE) > vbo_to ? (vbo_to - page_off) : to = (page_off + PAGE_SIZE) > vbo_to ? (vbo_to - page_off) :
PAGE_SIZE; PAGE_SIZE;
iblock = page_off >> inode->i_blkbits; iblock = page_off >> inode->i_blkbits;
page = find_or_create_page(mapping, idx, page = find_or_create_page(mapping, idx,
...@@ -1078,7 +1078,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -1078,7 +1078,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
goto out; goto out;
ret = is_compressed(ni) ? ntfs_compress_write(iocb, from) : ret = is_compressed(ni) ? ntfs_compress_write(iocb, from) :
__generic_file_write_iter(iocb, from); __generic_file_write_iter(iocb, from);
out: out:
inode_unlock(inode); inode_unlock(inode);
......
...@@ -77,7 +77,7 @@ struct ATTR_STD_INFO *ni_std(struct ntfs_inode *ni) ...@@ -77,7 +77,7 @@ struct ATTR_STD_INFO *ni_std(struct ntfs_inode *ni)
attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL); attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL);
return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO)) : return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO)) :
NULL; NULL;
} }
/* /*
...@@ -92,7 +92,7 @@ struct ATTR_STD_INFO5 *ni_std5(struct ntfs_inode *ni) ...@@ -92,7 +92,7 @@ struct ATTR_STD_INFO5 *ni_std5(struct ntfs_inode *ni)
attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL); attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL);
return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO5)) : return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO5)) :
NULL; NULL;
} }
/* /*
...@@ -236,6 +236,7 @@ struct ATTRIB *ni_find_attr(struct ntfs_inode *ni, struct ATTRIB *attr, ...@@ -236,6 +236,7 @@ struct ATTRIB *ni_find_attr(struct ntfs_inode *ni, struct ATTRIB *attr,
return attr; return attr;
out: out:
ntfs_inode_err(&ni->vfs_inode, "failed to parse mft record");
ntfs_set_state(ni->mi.sbi, NTFS_DIRTY_ERROR); ntfs_set_state(ni->mi.sbi, NTFS_DIRTY_ERROR);
return NULL; return NULL;
} }
...@@ -384,7 +385,7 @@ bool ni_add_subrecord(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi) ...@@ -384,7 +385,7 @@ bool ni_add_subrecord(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi)
* ni_remove_attr - Remove all attributes for the given type/name/id. * ni_remove_attr - Remove all attributes for the given type/name/id.
*/ */
int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type, int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
const __le16 *name, size_t name_len, bool base_only, const __le16 *name, u8 name_len, bool base_only,
const __le16 *id) const __le16 *id)
{ {
int err; int err;
...@@ -517,6 +518,9 @@ ni_ins_new_attr(struct ntfs_inode *ni, struct mft_inode *mi, ...@@ -517,6 +518,9 @@ ni_ins_new_attr(struct ntfs_inode *ni, struct mft_inode *mi,
*/ */
static int ni_repack(struct ntfs_inode *ni) static int ni_repack(struct ntfs_inode *ni)
{ {
#if 1
return 0;
#else
int err = 0; int err = 0;
struct ntfs_sb_info *sbi = ni->mi.sbi; struct ntfs_sb_info *sbi = ni->mi.sbi;
struct mft_inode *mi, *mi_p = NULL; struct mft_inode *mi, *mi_p = NULL;
...@@ -639,6 +643,7 @@ static int ni_repack(struct ntfs_inode *ni) ...@@ -639,6 +643,7 @@ static int ni_repack(struct ntfs_inode *ni)
run_close(&run); run_close(&run);
return err; return err;
#endif
} }
/* /*
...@@ -813,10 +818,8 @@ int ni_create_attr_list(struct ntfs_inode *ni) ...@@ -813,10 +818,8 @@ int ni_create_attr_list(struct ntfs_inode *ni)
* Looks like one record_size is always enough. * Looks like one record_size is always enough.
*/ */
le = kmalloc(al_aligned(rs), GFP_NOFS); le = kmalloc(al_aligned(rs), GFP_NOFS);
if (!le) { if (!le)
err = -ENOMEM; return -ENOMEM;
goto out;
}
mi_get_ref(&ni->mi, &le->ref); mi_get_ref(&ni->mi, &le->ref);
ni->attr_list.le = le; ni->attr_list.le = le;
...@@ -865,15 +868,16 @@ int ni_create_attr_list(struct ntfs_inode *ni) ...@@ -865,15 +868,16 @@ int ni_create_attr_list(struct ntfs_inode *ni)
if (to_free > free_b) { if (to_free > free_b) {
err = -EINVAL; err = -EINVAL;
goto out1; goto out;
} }
} }
/* Allocate child MFT. */ /* Allocate child MFT. */
err = ntfs_look_free_mft(sbi, &rno, is_mft, ni, &mi); err = ntfs_look_free_mft(sbi, &rno, is_mft, ni, &mi);
if (err) if (err)
goto out1; goto out;
err = -EINVAL;
/* Call mi_remove_attr() in reverse order to keep pointers 'arr_move' valid. */ /* Call mi_remove_attr() in reverse order to keep pointers 'arr_move' valid. */
while (to_free > 0) { while (to_free > 0) {
struct ATTRIB *b = arr_move[--nb]; struct ATTRIB *b = arr_move[--nb];
...@@ -882,7 +886,8 @@ int ni_create_attr_list(struct ntfs_inode *ni) ...@@ -882,7 +886,8 @@ int ni_create_attr_list(struct ntfs_inode *ni)
attr = mi_insert_attr(mi, b->type, Add2Ptr(b, name_off), attr = mi_insert_attr(mi, b->type, Add2Ptr(b, name_off),
b->name_len, asize, name_off); b->name_len, asize, name_off);
WARN_ON(!attr); if (!attr)
goto out;
mi_get_ref(mi, &le_b[nb]->ref); mi_get_ref(mi, &le_b[nb]->ref);
le_b[nb]->id = attr->id; le_b[nb]->id = attr->id;
...@@ -892,17 +897,20 @@ int ni_create_attr_list(struct ntfs_inode *ni) ...@@ -892,17 +897,20 @@ int ni_create_attr_list(struct ntfs_inode *ni)
attr->id = le_b[nb]->id; attr->id = le_b[nb]->id;
/* Remove from primary record. */ /* Remove from primary record. */
WARN_ON(!mi_remove_attr(NULL, &ni->mi, b)); if (!mi_remove_attr(NULL, &ni->mi, b))
goto out;
if (to_free <= asize) if (to_free <= asize)
break; break;
to_free -= asize; to_free -= asize;
WARN_ON(!nb); if (!nb)
goto out;
} }
attr = mi_insert_attr(&ni->mi, ATTR_LIST, NULL, 0, attr = mi_insert_attr(&ni->mi, ATTR_LIST, NULL, 0,
lsize + SIZEOF_RESIDENT, SIZEOF_RESIDENT); lsize + SIZEOF_RESIDENT, SIZEOF_RESIDENT);
WARN_ON(!attr); if (!attr)
goto out;
attr->non_res = 0; attr->non_res = 0;
attr->flags = 0; attr->flags = 0;
...@@ -916,14 +924,12 @@ int ni_create_attr_list(struct ntfs_inode *ni) ...@@ -916,14 +924,12 @@ int ni_create_attr_list(struct ntfs_inode *ni)
ni->attr_list.dirty = false; ni->attr_list.dirty = false;
mark_inode_dirty(&ni->vfs_inode); mark_inode_dirty(&ni->vfs_inode);
goto out; return 0;
out1: out:
kfree(ni->attr_list.le); kfree(ni->attr_list.le);
ni->attr_list.le = NULL; ni->attr_list.le = NULL;
ni->attr_list.size = 0; ni->attr_list.size = 0;
out:
return err; return err;
} }
...@@ -1638,14 +1644,13 @@ int ni_delete_all(struct ntfs_inode *ni) ...@@ -1638,14 +1644,13 @@ int ni_delete_all(struct ntfs_inode *ni)
* Return: File name attribute by its value. * Return: File name attribute by its value.
*/ */
struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni, struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
const struct cpu_str *uni, const struct le_str *uni,
const struct MFT_REF *home_dir, const struct MFT_REF *home_dir,
struct mft_inode **mi, struct mft_inode **mi,
struct ATTR_LIST_ENTRY **le) struct ATTR_LIST_ENTRY **le)
{ {
struct ATTRIB *attr = NULL; struct ATTRIB *attr = NULL;
struct ATTR_FILE_NAME *fname; struct ATTR_FILE_NAME *fname;
struct le_str *fns;
if (le) if (le)
*le = NULL; *le = NULL;
...@@ -1669,10 +1674,9 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni, ...@@ -1669,10 +1674,9 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
if (uni->len != fname->name_len) if (uni->len != fname->name_len)
goto next; goto next;
fns = (struct le_str *)&fname->name_len; if (ntfs_cmp_names(uni->name, uni->len, fname->name, uni->len, NULL,
if (ntfs_cmp_names_cpu(uni, fns, NULL, false)) false))
goto next; goto next;
return fname; return fname;
} }
...@@ -1757,8 +1761,8 @@ int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa) ...@@ -1757,8 +1761,8 @@ int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa)
/* Resize nonresident empty attribute in-place only. */ /* Resize nonresident empty attribute in-place only. */
new_asize = (new_aflags & (ATTR_FLAG_COMPRESSED | ATTR_FLAG_SPARSED)) ? new_asize = (new_aflags & (ATTR_FLAG_COMPRESSED | ATTR_FLAG_SPARSED)) ?
(SIZEOF_NONRESIDENT_EX + 8) : (SIZEOF_NONRESIDENT_EX + 8) :
(SIZEOF_NONRESIDENT + 8); (SIZEOF_NONRESIDENT + 8);
if (!mi_resize_attr(mi, attr, new_asize - le32_to_cpu(attr->size))) if (!mi_resize_attr(mi, attr, new_asize - le32_to_cpu(attr->size)))
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -2910,7 +2914,7 @@ int ni_remove_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, ...@@ -2910,7 +2914,7 @@ int ni_remove_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
/* Find name in record. */ /* Find name in record. */
mi_get_ref(&dir_ni->mi, &de_name->home); mi_get_ref(&dir_ni->mi, &de_name->home);
fname = ni_fname_name(ni, (struct cpu_str *)&de_name->name_len, fname = ni_fname_name(ni, (struct le_str *)&de_name->name_len,
&de_name->home, &mi, &le); &de_name->home, &mi, &le);
if (!fname) if (!fname)
return -ENOENT; return -ENOENT;
...@@ -3160,8 +3164,8 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup, ...@@ -3160,8 +3164,8 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
__le64 valid_le; __le64 valid_le;
dup->alloc_size = is_attr_ext(attr) ? dup->alloc_size = is_attr_ext(attr) ?
attr->nres.total_size : attr->nres.total_size :
attr->nres.alloc_size; attr->nres.alloc_size;
dup->data_size = attr->nres.data_size; dup->data_size = attr->nres.data_size;
if (new_valid > data_size) if (new_valid > data_size)
......
...@@ -828,8 +828,8 @@ static inline struct RESTART_TABLE *extend_rsttbl(struct RESTART_TABLE *tbl, ...@@ -828,8 +828,8 @@ static inline struct RESTART_TABLE *extend_rsttbl(struct RESTART_TABLE *tbl,
memcpy(rt + 1, tbl + 1, esize * used); memcpy(rt + 1, tbl + 1, esize * used);
rt->free_goal = free_goal == ~0u ? rt->free_goal = free_goal == ~0u ?
cpu_to_le32(~0u) : cpu_to_le32(~0u) :
cpu_to_le32(sizeof(struct RESTART_TABLE) + cpu_to_le32(sizeof(struct RESTART_TABLE) +
free_goal * esize); free_goal * esize);
if (tbl->first_free) { if (tbl->first_free) {
...@@ -1090,8 +1090,8 @@ static inline u64 base_lsn(struct ntfs_log *log, ...@@ -1090,8 +1090,8 @@ static inline u64 base_lsn(struct ntfs_log *log,
<< log->file_data_bits) + << log->file_data_bits) +
((((is_log_record_end(hdr) && ((((is_log_record_end(hdr) &&
h_lsn <= le64_to_cpu(hdr->record_hdr.last_end_lsn)) ? h_lsn <= le64_to_cpu(hdr->record_hdr.last_end_lsn)) ?
le16_to_cpu(hdr->record_hdr.next_record_off) : le16_to_cpu(hdr->record_hdr.next_record_off) :
log->page_size) + log->page_size) +
lsn) >> lsn) >>
3); 3);
...@@ -1299,8 +1299,8 @@ static void log_init_pg_hdr(struct ntfs_log *log, u32 sys_page_size, ...@@ -1299,8 +1299,8 @@ static void log_init_pg_hdr(struct ntfs_log *log, u32 sys_page_size,
log->clst_per_page = 1; log->clst_per_page = 1;
log->first_page = major_ver >= 2 ? log->first_page = major_ver >= 2 ?
0x22 * page_size : 0x22 * page_size :
((sys_page_size << 1) + (page_size << 1)); ((sys_page_size << 1) + (page_size << 1));
log->major_ver = major_ver; log->major_ver = major_ver;
log->minor_ver = minor_ver; log->minor_ver = minor_ver;
} }
...@@ -1513,8 +1513,8 @@ static u32 current_log_avail(struct ntfs_log *log) ...@@ -1513,8 +1513,8 @@ static u32 current_log_avail(struct ntfs_log *log)
* If there is no oldest lsn then start at the first page of the file. * If there is no oldest lsn then start at the first page of the file.
*/ */
oldest_off = (log->l_flags & NTFSLOG_NO_OLDEST_LSN) ? oldest_off = (log->l_flags & NTFSLOG_NO_OLDEST_LSN) ?
log->first_page : log->first_page :
(log->oldest_lsn_off & ~log->sys_page_mask); (log->oldest_lsn_off & ~log->sys_page_mask);
/* /*
* We will use the next log page offset to compute the next free page. * We will use the next log page offset to compute the next free page.
...@@ -1522,9 +1522,9 @@ static u32 current_log_avail(struct ntfs_log *log) ...@@ -1522,9 +1522,9 @@ static u32 current_log_avail(struct ntfs_log *log)
* If we are at the first page then use the end of the file. * If we are at the first page then use the end of the file.
*/ */
next_free_off = (log->l_flags & NTFSLOG_REUSE_TAIL) ? next_free_off = (log->l_flags & NTFSLOG_REUSE_TAIL) ?
log->next_page + log->page_size : log->next_page + log->page_size :
log->next_page == log->first_page ? log->l_size : log->next_page == log->first_page ? log->l_size :
log->next_page; log->next_page;
/* If the two offsets are the same then there is no available space. */ /* If the two offsets are the same then there is no available space. */
if (oldest_off == next_free_off) if (oldest_off == next_free_off)
...@@ -1535,8 +1535,8 @@ static u32 current_log_avail(struct ntfs_log *log) ...@@ -1535,8 +1535,8 @@ static u32 current_log_avail(struct ntfs_log *log)
*/ */
free_bytes = free_bytes =
oldest_off < next_free_off ? oldest_off < next_free_off ?
log->total_avail_pages - (next_free_off - oldest_off) : log->total_avail_pages - (next_free_off - oldest_off) :
oldest_off - next_free_off; oldest_off - next_free_off;
free_bytes >>= log->page_bits; free_bytes >>= log->page_bits;
return free_bytes * log->reserved; return free_bytes * log->reserved;
...@@ -1671,7 +1671,7 @@ static int last_log_lsn(struct ntfs_log *log) ...@@ -1671,7 +1671,7 @@ static int last_log_lsn(struct ntfs_log *log)
best_lsn1 = first_tail ? base_lsn(log, first_tail, first_file_off) : 0; best_lsn1 = first_tail ? base_lsn(log, first_tail, first_file_off) : 0;
best_lsn2 = second_tail ? base_lsn(log, second_tail, second_file_off) : best_lsn2 = second_tail ? base_lsn(log, second_tail, second_file_off) :
0; 0;
if (first_tail && second_tail) { if (first_tail && second_tail) {
if (best_lsn1 > best_lsn2) { if (best_lsn1 > best_lsn2) {
...@@ -1767,7 +1767,7 @@ static int last_log_lsn(struct ntfs_log *log) ...@@ -1767,7 +1767,7 @@ static int last_log_lsn(struct ntfs_log *log)
page_cnt = page_pos = 1; page_cnt = page_pos = 1;
curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off) : curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off) :
log->next_page; log->next_page;
wrapped_file = wrapped_file =
curpage_off == log->first_page && curpage_off == log->first_page &&
...@@ -1826,8 +1826,8 @@ static int last_log_lsn(struct ntfs_log *log) ...@@ -1826,8 +1826,8 @@ static int last_log_lsn(struct ntfs_log *log)
((lsn_cur >> log->file_data_bits) + ((lsn_cur >> log->file_data_bits) +
((curpage_off < ((curpage_off <
(lsn_to_vbo(log, lsn_cur) & ~log->page_mask)) ? (lsn_to_vbo(log, lsn_cur) & ~log->page_mask)) ?
1 : 1 :
0)) != expected_seq) { 0)) != expected_seq) {
goto check_tail; goto check_tail;
} }
...@@ -2643,8 +2643,8 @@ static inline bool check_index_root(const struct ATTRIB *attr, ...@@ -2643,8 +2643,8 @@ static inline bool check_index_root(const struct ATTRIB *attr,
const struct INDEX_ROOT *root = resident_data(attr); const struct INDEX_ROOT *root = resident_data(attr);
u8 index_bits = le32_to_cpu(root->index_block_size) >= u8 index_bits = le32_to_cpu(root->index_block_size) >=
sbi->cluster_size ? sbi->cluster_size ?
sbi->cluster_bits : sbi->cluster_bits :
SECTOR_SHIFT; SECTOR_SHIFT;
u8 block_clst = root->index_block_clst; u8 block_clst = root->index_block_clst;
if (le32_to_cpu(attr->res.data_size) < sizeof(struct INDEX_ROOT) || if (le32_to_cpu(attr->res.data_size) < sizeof(struct INDEX_ROOT) ||
...@@ -3861,9 +3861,9 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) ...@@ -3861,9 +3861,9 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
/* If we have a valid page then grab a pointer to the restart area. */ /* If we have a valid page then grab a pointer to the restart area. */
ra2 = rst_info.valid_page ? ra2 = rst_info.valid_page ?
Add2Ptr(rst_info.r_page, Add2Ptr(rst_info.r_page,
le16_to_cpu(rst_info.r_page->ra_off)) : le16_to_cpu(rst_info.r_page->ra_off)) :
NULL; NULL;
if (rst_info.chkdsk_was_run || if (rst_info.chkdsk_was_run ||
(ra2 && ra2->client_idx[1] == LFS_NO_CLIENT_LE)) { (ra2 && ra2->client_idx[1] == LFS_NO_CLIENT_LE)) {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/nls.h>
#include "debug.h" #include "debug.h"
#include "ntfs.h" #include "ntfs.h"
...@@ -173,12 +174,12 @@ int ntfs_fix_post_read(struct NTFS_RECORD_HEADER *rhdr, size_t bytes, ...@@ -173,12 +174,12 @@ int ntfs_fix_post_read(struct NTFS_RECORD_HEADER *rhdr, size_t bytes,
fo = le16_to_cpu(rhdr->fix_off); fo = le16_to_cpu(rhdr->fix_off);
fn = simple ? ((bytes >> SECTOR_SHIFT) + 1) : fn = simple ? ((bytes >> SECTOR_SHIFT) + 1) :
le16_to_cpu(rhdr->fix_num); le16_to_cpu(rhdr->fix_num);
/* Check errors. */ /* Check errors. */
if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- || if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
fn * SECTOR_SIZE > bytes) { fn * SECTOR_SIZE > bytes) {
return -EINVAL; /* Native chkntfs returns ok! */ return -E_NTFS_CORRUPT;
} }
/* Get fixup pointer. */ /* Get fixup pointer. */
...@@ -1661,7 +1662,8 @@ int ntfs_vbo_to_lbo(struct ntfs_sb_info *sbi, const struct runs_tree *run, ...@@ -1661,7 +1662,8 @@ int ntfs_vbo_to_lbo(struct ntfs_sb_info *sbi, const struct runs_tree *run,
return 0; return 0;
} }
struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST rno, bool dir) struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST rno,
enum RECORD_FLAG flag)
{ {
int err = 0; int err = 0;
struct super_block *sb = sbi->sb; struct super_block *sb = sbi->sb;
...@@ -1673,8 +1675,7 @@ struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST rno, bool dir) ...@@ -1673,8 +1675,7 @@ struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST rno, bool dir)
ni = ntfs_i(inode); ni = ntfs_i(inode);
err = mi_format_new(&ni->mi, sbi, rno, dir ? RECORD_FLAG_DIR : 0, err = mi_format_new(&ni->mi, sbi, rno, flag, false);
false);
if (err) if (err)
goto out; goto out;
...@@ -1937,7 +1938,7 @@ int ntfs_security_init(struct ntfs_sb_info *sbi) ...@@ -1937,7 +1938,7 @@ int ntfs_security_init(struct ntfs_sb_info *sbi)
break; break;
sii_e = (struct NTFS_DE_SII *)ne; sii_e = (struct NTFS_DE_SII *)ne;
if (le16_to_cpu(ne->view.data_size) < SIZEOF_SECURITY_HDR) if (le16_to_cpu(ne->view.data_size) < sizeof(sii_e->sec_hdr))
continue; continue;
next_id = le32_to_cpu(sii_e->sec_id) + 1; next_id = le32_to_cpu(sii_e->sec_id) + 1;
...@@ -1998,18 +1999,18 @@ int ntfs_get_security_by_id(struct ntfs_sb_info *sbi, __le32 security_id, ...@@ -1998,18 +1999,18 @@ int ntfs_get_security_by_id(struct ntfs_sb_info *sbi, __le32 security_id,
goto out; goto out;
t32 = le32_to_cpu(sii_e->sec_hdr.size); t32 = le32_to_cpu(sii_e->sec_hdr.size);
if (t32 < SIZEOF_SECURITY_HDR) { if (t32 < sizeof(struct SECURITY_HDR)) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
if (t32 > SIZEOF_SECURITY_HDR + 0x10000) { if (t32 > sizeof(struct SECURITY_HDR) + 0x10000) {
/* Looks like too big security. 0x10000 - is arbitrary big number. */ /* Looks like too big security. 0x10000 - is arbitrary big number. */
err = -EFBIG; err = -EFBIG;
goto out; goto out;
} }
*size = t32 - SIZEOF_SECURITY_HDR; *size = t32 - sizeof(struct SECURITY_HDR);
p = kmalloc(*size, GFP_NOFS); p = kmalloc(*size, GFP_NOFS);
if (!p) { if (!p) {
...@@ -2023,14 +2024,14 @@ int ntfs_get_security_by_id(struct ntfs_sb_info *sbi, __le32 security_id, ...@@ -2023,14 +2024,14 @@ int ntfs_get_security_by_id(struct ntfs_sb_info *sbi, __le32 security_id,
if (err) if (err)
goto out; goto out;
if (memcmp(&d_security, &sii_e->sec_hdr, SIZEOF_SECURITY_HDR)) { if (memcmp(&d_security, &sii_e->sec_hdr, sizeof(d_security))) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
err = ntfs_read_run_nb(sbi, &ni->file.run, err = ntfs_read_run_nb(sbi, &ni->file.run,
le64_to_cpu(sii_e->sec_hdr.off) + le64_to_cpu(sii_e->sec_hdr.off) +
SIZEOF_SECURITY_HDR, sizeof(struct SECURITY_HDR),
p, *size, NULL); p, *size, NULL);
if (err) if (err)
goto out; goto out;
...@@ -2069,7 +2070,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi, ...@@ -2069,7 +2070,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
struct NTFS_DE_SDH sdh_e; struct NTFS_DE_SDH sdh_e;
struct NTFS_DE_SII sii_e; struct NTFS_DE_SII sii_e;
struct SECURITY_HDR *d_security; struct SECURITY_HDR *d_security;
u32 new_sec_size = size_sd + SIZEOF_SECURITY_HDR; u32 new_sec_size = size_sd + sizeof(struct SECURITY_HDR);
u32 aligned_sec_size = ALIGN(new_sec_size, 16); u32 aligned_sec_size = ALIGN(new_sec_size, 16);
struct SECURITY_KEY hash_key; struct SECURITY_KEY hash_key;
struct ntfs_fnd *fnd_sdh = NULL; struct ntfs_fnd *fnd_sdh = NULL;
...@@ -2207,14 +2208,14 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi, ...@@ -2207,14 +2208,14 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
/* Fill SII entry. */ /* Fill SII entry. */
sii_e.de.view.data_off = sii_e.de.view.data_off =
cpu_to_le16(offsetof(struct NTFS_DE_SII, sec_hdr)); cpu_to_le16(offsetof(struct NTFS_DE_SII, sec_hdr));
sii_e.de.view.data_size = cpu_to_le16(SIZEOF_SECURITY_HDR); sii_e.de.view.data_size = cpu_to_le16(sizeof(struct SECURITY_HDR));
sii_e.de.view.res = 0; sii_e.de.view.res = 0;
sii_e.de.size = cpu_to_le16(SIZEOF_SII_DIRENTRY); sii_e.de.size = cpu_to_le16(sizeof(struct NTFS_DE_SII));
sii_e.de.key_size = cpu_to_le16(sizeof(d_security->key.sec_id)); sii_e.de.key_size = cpu_to_le16(sizeof(d_security->key.sec_id));
sii_e.de.flags = 0; sii_e.de.flags = 0;
sii_e.de.res = 0; sii_e.de.res = 0;
sii_e.sec_id = d_security->key.sec_id; sii_e.sec_id = d_security->key.sec_id;
memcpy(&sii_e.sec_hdr, d_security, SIZEOF_SECURITY_HDR); memcpy(&sii_e.sec_hdr, d_security, sizeof(struct SECURITY_HDR));
err = indx_insert_entry(indx_sii, ni, &sii_e.de, NULL, NULL, 0); err = indx_insert_entry(indx_sii, ni, &sii_e.de, NULL, NULL, 0);
if (err) if (err)
...@@ -2223,7 +2224,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi, ...@@ -2223,7 +2224,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
/* Fill SDH entry. */ /* Fill SDH entry. */
sdh_e.de.view.data_off = sdh_e.de.view.data_off =
cpu_to_le16(offsetof(struct NTFS_DE_SDH, sec_hdr)); cpu_to_le16(offsetof(struct NTFS_DE_SDH, sec_hdr));
sdh_e.de.view.data_size = cpu_to_le16(SIZEOF_SECURITY_HDR); sdh_e.de.view.data_size = cpu_to_le16(sizeof(struct SECURITY_HDR));
sdh_e.de.view.res = 0; sdh_e.de.view.res = 0;
sdh_e.de.size = cpu_to_le16(SIZEOF_SDH_DIRENTRY); sdh_e.de.size = cpu_to_le16(SIZEOF_SDH_DIRENTRY);
sdh_e.de.key_size = cpu_to_le16(sizeof(sdh_e.key)); sdh_e.de.key_size = cpu_to_le16(sizeof(sdh_e.key));
...@@ -2231,7 +2232,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi, ...@@ -2231,7 +2232,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
sdh_e.de.res = 0; sdh_e.de.res = 0;
sdh_e.key.hash = d_security->key.hash; sdh_e.key.hash = d_security->key.hash;
sdh_e.key.sec_id = d_security->key.sec_id; sdh_e.key.sec_id = d_security->key.sec_id;
memcpy(&sdh_e.sec_hdr, d_security, SIZEOF_SECURITY_HDR); memcpy(&sdh_e.sec_hdr, d_security, sizeof(struct SECURITY_HDR));
sdh_e.magic[0] = cpu_to_le16('I'); sdh_e.magic[0] = cpu_to_le16('I');
sdh_e.magic[1] = cpu_to_le16('I'); sdh_e.magic[1] = cpu_to_le16('I');
...@@ -2522,7 +2523,8 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim) ...@@ -2522,7 +2523,8 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
/* /*
* run_deallocate - Deallocate clusters. * run_deallocate - Deallocate clusters.
*/ */
int run_deallocate(struct ntfs_sb_info *sbi, struct runs_tree *run, bool trim) int run_deallocate(struct ntfs_sb_info *sbi, const struct runs_tree *run,
bool trim)
{ {
CLST lcn, len; CLST lcn, len;
size_t idx = 0; size_t idx = 0;
...@@ -2578,13 +2580,13 @@ static inline bool name_has_forbidden_chars(const struct le_str *fname) ...@@ -2578,13 +2580,13 @@ static inline bool name_has_forbidden_chars(const struct le_str *fname)
return false; return false;
} }
static inline bool is_reserved_name(struct ntfs_sb_info *sbi, static inline bool is_reserved_name(const struct ntfs_sb_info *sbi,
const struct le_str *fname) const struct le_str *fname)
{ {
int port_digit; int port_digit;
const __le16 *name = fname->name; const __le16 *name = fname->name;
int len = fname->len; int len = fname->len;
u16 *upcase = sbi->upcase; const u16 *upcase = sbi->upcase;
/* check for 3 chars reserved names (device names) */ /* check for 3 chars reserved names (device names) */
/* name by itself or with any extension is forbidden */ /* name by itself or with any extension is forbidden */
...@@ -2618,3 +2620,60 @@ bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *fname) ...@@ -2618,3 +2620,60 @@ bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *fname)
return !name_has_forbidden_chars(fname) && return !name_has_forbidden_chars(fname) &&
!is_reserved_name(sbi, fname); !is_reserved_name(sbi, fname);
} }
/*
* ntfs_set_label - updates current ntfs label.
*/
int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len)
{
int err;
struct ATTRIB *attr;
struct ntfs_inode *ni = sbi->volume.ni;
const u8 max_ulen = 0x80; /* TODO: use attrdef to get maximum length */
/* Allocate PATH_MAX bytes. */
struct cpu_str *uni = __getname();
if (!uni)
return -ENOMEM;
err = ntfs_nls_to_utf16(sbi, label, len, uni, (PATH_MAX - 2) / 2,
UTF16_LITTLE_ENDIAN);
if (err < 0)
goto out;
if (uni->len > max_ulen) {
ntfs_warn(sbi->sb, "new label is too long");
err = -EFBIG;
goto out;
}
ni_lock(ni);
/* Ignore any errors. */
ni_remove_attr(ni, ATTR_LABEL, NULL, 0, false, NULL);
err = ni_insert_resident(ni, uni->len * sizeof(u16), ATTR_LABEL, NULL,
0, &attr, NULL, NULL);
if (err < 0)
goto unlock_out;
/* write new label in on-disk struct. */
memcpy(resident_data(attr), uni->name, uni->len * sizeof(u16));
/* update cached value of current label. */
if (len >= ARRAY_SIZE(sbi->volume.label))
len = ARRAY_SIZE(sbi->volume.label) - 1;
memcpy(sbi->volume.label, label, len);
sbi->volume.label[len] = 0;
mark_inode_dirty_sync(&ni->vfs_inode);
unlock_out:
ni_unlock(ni);
if (!err)
err = _ni_write_inode(&ni->vfs_inode, 0);
out:
__putname(uni);
return err;
}
\ No newline at end of file
...@@ -432,8 +432,8 @@ static int scan_nres_bitmap(struct ntfs_inode *ni, struct ATTRIB *bitmap, ...@@ -432,8 +432,8 @@ static int scan_nres_bitmap(struct ntfs_inode *ni, struct ATTRIB *bitmap,
nbits = 8 * (data_size - vbo); nbits = 8 * (data_size - vbo);
ok = nbits > from ? ok = nbits > from ?
(*fn)((ulong *)bh->b_data, from, nbits, ret) : (*fn)((ulong *)bh->b_data, from, nbits, ret) :
false; false;
put_bh(bh); put_bh(bh);
if (ok) { if (ok) {
...@@ -1113,6 +1113,12 @@ int indx_read(struct ntfs_index *indx, struct ntfs_inode *ni, CLST vbn, ...@@ -1113,6 +1113,12 @@ int indx_read(struct ntfs_index *indx, struct ntfs_inode *ni, CLST vbn,
*node = in; *node = in;
out: out:
if (err == -E_NTFS_CORRUPT) {
ntfs_inode_err(&ni->vfs_inode, "directory corrupted");
ntfs_set_state(ni->mi.sbi, NTFS_DIRTY_ERROR);
err = -EINVAL;
}
if (ib != in->index) if (ib != in->index)
kfree(ib); kfree(ib);
...@@ -1676,8 +1682,8 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1676,8 +1682,8 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
/* Create alloc and bitmap attributes (if not). */ /* Create alloc and bitmap attributes (if not). */
err = run_is_empty(&indx->alloc_run) ? err = run_is_empty(&indx->alloc_run) ?
indx_create_allocate(indx, ni, &new_vbn) : indx_create_allocate(indx, ni, &new_vbn) :
indx_add_allocate(indx, ni, &new_vbn); indx_add_allocate(indx, ni, &new_vbn);
/* Layout of record may be changed, so rescan root. */ /* Layout of record may be changed, so rescan root. */
root = indx_get_root(indx, ni, &attr, &mi); root = indx_get_root(indx, ni, &attr, &mi);
...@@ -1868,8 +1874,8 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1868,8 +1874,8 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
(*indx->cmp)(new_de + 1, le16_to_cpu(new_de->key_size), (*indx->cmp)(new_de + 1, le16_to_cpu(new_de->key_size),
up_e + 1, le16_to_cpu(up_e->key_size), up_e + 1, le16_to_cpu(up_e->key_size),
ctx) < 0 ? ctx) < 0 ?
hdr2 : hdr2 :
hdr1, hdr1,
new_de, NULL, ctx); new_de, NULL, ctx);
indx_mark_used(indx, ni, new_vbn >> indx->idx2vbn_bits); indx_mark_used(indx, ni, new_vbn >> indx->idx2vbn_bits);
...@@ -2340,7 +2346,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -2340,7 +2346,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
re, ctx, re, ctx,
fnd->level - 1, fnd->level - 1,
fnd) : fnd) :
indx_insert_into_root(indx, ni, re, e, indx_insert_into_root(indx, ni, re, e,
ctx, fnd, 0); ctx, fnd, 0);
kfree(re); kfree(re);
......
...@@ -263,7 +263,7 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -263,7 +263,7 @@ static struct inode *ntfs_read_mft(struct inode *inode,
goto next_attr; goto next_attr;
run = ino == MFT_REC_BITMAP ? &sbi->used.bitmap.run : run = ino == MFT_REC_BITMAP ? &sbi->used.bitmap.run :
&ni->file.run; &ni->file.run;
break; break;
case ATTR_ROOT: case ATTR_ROOT:
...@@ -291,8 +291,8 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -291,8 +291,8 @@ static struct inode *ntfs_read_mft(struct inode *inode,
goto out; goto out;
mode = sb->s_root ? mode = sb->s_root ?
(S_IFDIR | (0777 & sbi->options->fs_dmask_inv)) : (S_IFDIR | (0777 & sbi->options->fs_dmask_inv)) :
(S_IFDIR | 0777); (S_IFDIR | 0777);
goto next_attr; goto next_attr;
case ATTR_ALLOC: case ATTR_ALLOC:
...@@ -450,7 +450,7 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -450,7 +450,7 @@ static struct inode *ntfs_read_mft(struct inode *inode,
inode->i_op = &ntfs_file_inode_operations; inode->i_op = &ntfs_file_inode_operations;
inode->i_fop = &ntfs_file_operations; inode->i_fop = &ntfs_file_operations;
inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr : inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr :
&ntfs_aops; &ntfs_aops;
if (ino != MFT_REC_MFT) if (ino != MFT_REC_MFT)
init_rwsem(&ni->file.run_lock); init_rwsem(&ni->file.run_lock);
} else if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode) || } else if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode) ||
...@@ -787,7 +787,7 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ...@@ -787,7 +787,7 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
ret = blockdev_direct_IO(iocb, inode, iter, ret = blockdev_direct_IO(iocb, inode, iter,
wr ? ntfs_get_block_direct_IO_W : wr ? ntfs_get_block_direct_IO_W :
ntfs_get_block_direct_IO_R); ntfs_get_block_direct_IO_R);
if (ret > 0) if (ret > 0)
end = vbo + ret; end = vbo + ret;
...@@ -1191,11 +1191,11 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname, ...@@ -1191,11 +1191,11 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
* - ntfs_symlink * - ntfs_symlink
* - ntfs_mkdir * - ntfs_mkdir
* - ntfs_atomic_open * - ntfs_atomic_open
* *
* NOTE: if fnd != NULL (ntfs_atomic_open) then @dir is locked * NOTE: if fnd != NULL (ntfs_atomic_open) then @dir is locked
*/ */
struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
struct inode *dir, struct dentry *dentry, struct dentry *dentry,
const struct cpu_str *uni, umode_t mode, const struct cpu_str *uni, umode_t mode,
dev_t dev, const char *symname, u32 size, dev_t dev, const char *symname, u32 size,
struct ntfs_fnd *fnd) struct ntfs_fnd *fnd)
...@@ -1309,7 +1309,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, ...@@ -1309,7 +1309,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
if (err) if (err)
goto out2; goto out2;
ni = ntfs_new_inode(sbi, ino, fa & FILE_ATTRIBUTE_DIRECTORY); ni = ntfs_new_inode(sbi, ino, S_ISDIR(mode) ? RECORD_FLAG_DIR : 0);
if (IS_ERR(ni)) { if (IS_ERR(ni)) {
err = PTR_ERR(ni); err = PTR_ERR(ni);
ni = NULL; ni = NULL;
...@@ -1437,8 +1437,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, ...@@ -1437,8 +1437,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
root = Add2Ptr(attr, sizeof(I30_NAME) + SIZEOF_RESIDENT); root = Add2Ptr(attr, sizeof(I30_NAME) + SIZEOF_RESIDENT);
memcpy(root, dir_root, offsetof(struct INDEX_ROOT, ihdr)); memcpy(root, dir_root, offsetof(struct INDEX_ROOT, ihdr));
root->ihdr.de_off = root->ihdr.de_off = cpu_to_le32(sizeof(struct INDEX_HDR));
cpu_to_le32(sizeof(struct INDEX_HDR)); // 0x10
root->ihdr.used = cpu_to_le32(sizeof(struct INDEX_HDR) + root->ihdr.used = cpu_to_le32(sizeof(struct INDEX_HDR) +
sizeof(struct NTFS_DE)); sizeof(struct NTFS_DE));
root->ihdr.total = root->ihdr.used; root->ihdr.total = root->ihdr.used;
...@@ -1605,7 +1604,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, ...@@ -1605,7 +1604,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
inode->i_op = &ntfs_file_inode_operations; inode->i_op = &ntfs_file_inode_operations;
inode->i_fop = &ntfs_file_operations; inode->i_fop = &ntfs_file_operations;
inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr : inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr :
&ntfs_aops; &ntfs_aops;
init_rwsem(&ni->file.run_lock); init_rwsem(&ni->file.run_lock);
} else { } else {
inode->i_op = &ntfs_special_inode_operations; inode->i_op = &ntfs_special_inode_operations;
......
...@@ -297,7 +297,7 @@ static inline ssize_t decompress_chunk(u8 *unc, u8 *unc_end, const u8 *cmpr, ...@@ -297,7 +297,7 @@ static inline ssize_t decompress_chunk(u8 *unc, u8 *unc_end, const u8 *cmpr,
struct lznt *get_lznt_ctx(int level) struct lznt *get_lznt_ctx(int level)
{ {
struct lznt *r = kzalloc(level ? offsetof(struct lznt, hash) : struct lznt *r = kzalloc(level ? offsetof(struct lznt, hash) :
sizeof(struct lznt), sizeof(struct lznt),
GFP_NOFS); GFP_NOFS);
if (r) if (r)
...@@ -393,8 +393,8 @@ ssize_t decompress_lznt(const void *cmpr, size_t cmpr_size, void *unc, ...@@ -393,8 +393,8 @@ ssize_t decompress_lznt(const void *cmpr, size_t cmpr_size, void *unc,
} else { } else {
/* This chunk does not contain compressed data. */ /* This chunk does not contain compressed data. */
unc_use = unc_chunk + LZNT_CHUNK_SIZE > unc_end ? unc_use = unc_chunk + LZNT_CHUNK_SIZE > unc_end ?
unc_end - unc_chunk : unc_end - unc_chunk :
LZNT_CHUNK_SIZE; LZNT_CHUNK_SIZE;
if (cmpr_chunk + sizeof(chunk_hdr) + unc_use > if (cmpr_chunk + sizeof(chunk_hdr) + unc_use >
cmpr_end) { cmpr_end) {
......
...@@ -109,8 +109,8 @@ static int ntfs_create(struct mnt_idmap *idmap, struct inode *dir, ...@@ -109,8 +109,8 @@ static int ntfs_create(struct mnt_idmap *idmap, struct inode *dir,
{ {
struct inode *inode; struct inode *inode;
inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFREG | mode, inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFREG | mode, 0,
0, NULL, 0, NULL); NULL, 0, NULL);
return IS_ERR(inode) ? PTR_ERR(inode) : 0; return IS_ERR(inode) ? PTR_ERR(inode) : 0;
} }
...@@ -125,8 +125,8 @@ static int ntfs_mknod(struct mnt_idmap *idmap, struct inode *dir, ...@@ -125,8 +125,8 @@ static int ntfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
{ {
struct inode *inode; struct inode *inode;
inode = ntfs_create_inode(idmap, dir, dentry, NULL, mode, rdev, inode = ntfs_create_inode(idmap, dir, dentry, NULL, mode, rdev, NULL, 0,
NULL, 0, NULL); NULL);
return IS_ERR(inode) ? PTR_ERR(inode) : 0; return IS_ERR(inode) ? PTR_ERR(inode) : 0;
} }
...@@ -199,8 +199,8 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir, ...@@ -199,8 +199,8 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
u32 size = strlen(symname); u32 size = strlen(symname);
struct inode *inode; struct inode *inode;
inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFLNK | 0777, inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFLNK | 0777, 0,
0, symname, size, NULL); symname, size, NULL);
return IS_ERR(inode) ? PTR_ERR(inode) : 0; return IS_ERR(inode) ? PTR_ERR(inode) : 0;
} }
...@@ -213,8 +213,8 @@ static int ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, ...@@ -213,8 +213,8 @@ static int ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
{ {
struct inode *inode; struct inode *inode;
inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0,
0, NULL, 0, NULL); NULL, 0, NULL);
return IS_ERR(inode) ? PTR_ERR(inode) : 0; return IS_ERR(inode) ? PTR_ERR(inode) : 0;
} }
...@@ -422,19 +422,10 @@ static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -422,19 +422,10 @@ static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry,
* fnd contains tree's path to insert to. * fnd contains tree's path to insert to.
* If fnd is not NULL then dir is locked. * If fnd is not NULL then dir is locked.
*/ */
inode = ntfs_create_inode(mnt_idmap(file->f_path.mnt), dir, dentry, uni,
/* mode, 0, NULL, 0, fnd);
* Unfortunately I don't know how to get here correct 'struct nameidata *nd'
* or 'struct mnt_idmap *idmap'.
* See atomic_open in fs/namei.c.
* This is why xfstest/633 failed.
* Looks like ntfs_atomic_open must accept 'struct mnt_idmap *idmap' as argument.
*/
inode = ntfs_create_inode(&nop_mnt_idmap, dir, dentry, uni, mode, 0,
NULL, 0, fnd);
err = IS_ERR(inode) ? PTR_ERR(inode) : err = IS_ERR(inode) ? PTR_ERR(inode) :
finish_open(file, dentry, ntfs_file_open); finish_open(file, dentry, ntfs_file_open);
dput(d); dput(d);
out2: out2:
......
...@@ -95,11 +95,10 @@ enum RECORD_NUM { ...@@ -95,11 +95,10 @@ enum RECORD_NUM {
MFT_REC_BITMAP = 6, MFT_REC_BITMAP = 6,
MFT_REC_BOOT = 7, MFT_REC_BOOT = 7,
MFT_REC_BADCLUST = 8, MFT_REC_BADCLUST = 8,
//MFT_REC_QUOTA = 9, MFT_REC_SECURE = 9,
MFT_REC_SECURE = 9, // NTFS 3.0
MFT_REC_UPCASE = 10, MFT_REC_UPCASE = 10,
MFT_REC_EXTEND = 11, // NTFS 3.0 MFT_REC_EXTEND = 11,
MFT_REC_RESERVED = 11, MFT_REC_RESERVED = 12,
MFT_REC_FREE = 16, MFT_REC_FREE = 16,
MFT_REC_USER = 24, MFT_REC_USER = 24,
}; };
...@@ -109,7 +108,6 @@ enum ATTR_TYPE { ...@@ -109,7 +108,6 @@ enum ATTR_TYPE {
ATTR_STD = cpu_to_le32(0x10), ATTR_STD = cpu_to_le32(0x10),
ATTR_LIST = cpu_to_le32(0x20), ATTR_LIST = cpu_to_le32(0x20),
ATTR_NAME = cpu_to_le32(0x30), ATTR_NAME = cpu_to_le32(0x30),
// ATTR_VOLUME_VERSION on Nt4
ATTR_ID = cpu_to_le32(0x40), ATTR_ID = cpu_to_le32(0x40),
ATTR_SECURE = cpu_to_le32(0x50), ATTR_SECURE = cpu_to_le32(0x50),
ATTR_LABEL = cpu_to_le32(0x60), ATTR_LABEL = cpu_to_le32(0x60),
...@@ -118,7 +116,6 @@ enum ATTR_TYPE { ...@@ -118,7 +116,6 @@ enum ATTR_TYPE {
ATTR_ROOT = cpu_to_le32(0x90), ATTR_ROOT = cpu_to_le32(0x90),
ATTR_ALLOC = cpu_to_le32(0xA0), ATTR_ALLOC = cpu_to_le32(0xA0),
ATTR_BITMAP = cpu_to_le32(0xB0), ATTR_BITMAP = cpu_to_le32(0xB0),
// ATTR_SYMLINK on Nt4
ATTR_REPARSE = cpu_to_le32(0xC0), ATTR_REPARSE = cpu_to_le32(0xC0),
ATTR_EA_INFO = cpu_to_le32(0xD0), ATTR_EA_INFO = cpu_to_le32(0xD0),
ATTR_EA = cpu_to_le32(0xE0), ATTR_EA = cpu_to_le32(0xE0),
...@@ -144,6 +141,7 @@ enum FILE_ATTRIBUTE { ...@@ -144,6 +141,7 @@ enum FILE_ATTRIBUTE {
FILE_ATTRIBUTE_ENCRYPTED = cpu_to_le32(0x00004000), FILE_ATTRIBUTE_ENCRYPTED = cpu_to_le32(0x00004000),
FILE_ATTRIBUTE_VALID_FLAGS = cpu_to_le32(0x00007fb7), FILE_ATTRIBUTE_VALID_FLAGS = cpu_to_le32(0x00007fb7),
FILE_ATTRIBUTE_DIRECTORY = cpu_to_le32(0x10000000), FILE_ATTRIBUTE_DIRECTORY = cpu_to_le32(0x10000000),
FILE_ATTRIBUTE_INDEX = cpu_to_le32(0x20000000)
}; };
static_assert(sizeof(enum FILE_ATTRIBUTE) == 4); static_assert(sizeof(enum FILE_ATTRIBUTE) == 4);
...@@ -266,7 +264,7 @@ enum RECORD_FLAG { ...@@ -266,7 +264,7 @@ enum RECORD_FLAG {
RECORD_FLAG_IN_USE = cpu_to_le16(0x0001), RECORD_FLAG_IN_USE = cpu_to_le16(0x0001),
RECORD_FLAG_DIR = cpu_to_le16(0x0002), RECORD_FLAG_DIR = cpu_to_le16(0x0002),
RECORD_FLAG_SYSTEM = cpu_to_le16(0x0004), RECORD_FLAG_SYSTEM = cpu_to_le16(0x0004),
RECORD_FLAG_UNKNOWN = cpu_to_le16(0x0008), RECORD_FLAG_INDEX = cpu_to_le16(0x0008),
}; };
/* MFT Record structure. */ /* MFT Record structure. */
...@@ -290,6 +288,15 @@ struct MFT_REC { ...@@ -290,6 +288,15 @@ struct MFT_REC {
#define MFTRECORD_FIXUP_OFFSET_1 offsetof(struct MFT_REC, res) #define MFTRECORD_FIXUP_OFFSET_1 offsetof(struct MFT_REC, res)
#define MFTRECORD_FIXUP_OFFSET_3 offsetof(struct MFT_REC, fixups) #define MFTRECORD_FIXUP_OFFSET_3 offsetof(struct MFT_REC, fixups)
/*
* define MFTRECORD_FIXUP_OFFSET as MFTRECORD_FIXUP_OFFSET_3 (0x30)
* to format new mft records with bigger header (as current ntfs.sys does)
*
* define MFTRECORD_FIXUP_OFFSET as MFTRECORD_FIXUP_OFFSET_1 (0x2A)
* to format new mft records with smaller header (as old ntfs.sys did)
* Both variants are valid.
*/
#define MFTRECORD_FIXUP_OFFSET MFTRECORD_FIXUP_OFFSET_1
static_assert(MFTRECORD_FIXUP_OFFSET_1 == 0x2A); static_assert(MFTRECORD_FIXUP_OFFSET_1 == 0x2A);
static_assert(MFTRECORD_FIXUP_OFFSET_3 == 0x30); static_assert(MFTRECORD_FIXUP_OFFSET_3 == 0x30);
...@@ -331,18 +338,18 @@ struct ATTR_NONRESIDENT { ...@@ -331,18 +338,18 @@ struct ATTR_NONRESIDENT {
__le64 svcn; // 0x10: Starting VCN of this segment. __le64 svcn; // 0x10: Starting VCN of this segment.
__le64 evcn; // 0x18: End VCN of this segment. __le64 evcn; // 0x18: End VCN of this segment.
__le16 run_off; // 0x20: Offset to packed runs. __le16 run_off; // 0x20: Offset to packed runs.
// Unit of Compression size for this stream, expressed // Unit of Compression size for this stream, expressed
// as a log of the cluster size. // as a log of the cluster size.
// //
// 0 means file is not compressed // 0 means file is not compressed
// 1, 2, 3, and 4 are potentially legal values if the // 1, 2, 3, and 4 are potentially legal values if the
// stream is compressed, however the implementation // stream is compressed, however the implementation
// may only choose to use 4, or possibly 3. Note // may only choose to use 4, or possibly 3.
// that 4 means cluster size time 16. If convenient // Note that 4 means cluster size time 16.
// the implementation may wish to accept a // If convenient the implementation may wish to accept a
// reasonable range of legal values here (1-5?), // reasonable range of legal values here (1-5?),
// even if the implementation only generates // even if the implementation only generates
// a smaller set of values itself. // a smaller set of values itself.
u8 c_unit; // 0x22: u8 c_unit; // 0x22:
u8 res1[5]; // 0x23: u8 res1[5]; // 0x23:
__le64 alloc_size; // 0x28: The allocated size of attribute in bytes. __le64 alloc_size; // 0x28: The allocated size of attribute in bytes.
...@@ -836,16 +843,22 @@ static_assert(sizeof(struct ATTR_DEF_ENTRY) == 0xa0); ...@@ -836,16 +843,22 @@ static_assert(sizeof(struct ATTR_DEF_ENTRY) == 0xa0);
/* Object ID (0x40) */ /* Object ID (0x40) */
struct OBJECT_ID { struct OBJECT_ID {
struct GUID ObjId; // 0x00: Unique Id assigned to file. struct GUID ObjId; // 0x00: Unique Id assigned to file.
struct GUID BirthVolumeId; // 0x10: Birth Volume Id is the Object Id of the Volume on.
// which the Object Id was allocated. It never changes. // Birth Volume Id is the Object Id of the Volume on.
struct GUID BirthObjectId; // 0x20: Birth Object Id is the first Object Id that was // which the Object Id was allocated. It never changes.
// ever assigned to this MFT Record. I.e. If the Object Id struct GUID BirthVolumeId; //0x10:
// is changed for some reason, this field will reflect the
// original value of the Object Id. // Birth Object Id is the first Object Id that was
struct GUID DomainId; // 0x30: Domain Id is currently unused but it is intended to be // ever assigned to this MFT Record. I.e. If the Object Id
// used in a network environment where the local machine is // is changed for some reason, this field will reflect the
// part of a Windows 2000 Domain. This may be used in a Windows // original value of the Object Id.
// 2000 Advanced Server managed domain. struct GUID BirthObjectId; // 0x20:
// Domain Id is currently unused but it is intended to be
// used in a network environment where the local machine is
// part of a Windows 2000 Domain. This may be used in a Windows
// 2000 Advanced Server managed domain.
struct GUID DomainId; // 0x30:
}; };
static_assert(sizeof(struct OBJECT_ID) == 0x40); static_assert(sizeof(struct OBJECT_ID) == 0x40);
...@@ -855,32 +868,35 @@ struct NTFS_DE_O { ...@@ -855,32 +868,35 @@ struct NTFS_DE_O {
struct NTFS_DE de; struct NTFS_DE de;
struct GUID ObjId; // 0x10: Unique Id assigned to file. struct GUID ObjId; // 0x10: Unique Id assigned to file.
struct MFT_REF ref; // 0x20: MFT record number with this file. struct MFT_REF ref; // 0x20: MFT record number with this file.
struct GUID BirthVolumeId; // 0x28: Birth Volume Id is the Object Id of the Volume on
// which the Object Id was allocated. It never changes. // Birth Volume Id is the Object Id of the Volume on
struct GUID BirthObjectId; // 0x38: Birth Object Id is the first Object Id that was // which the Object Id was allocated. It never changes.
// ever assigned to this MFT Record. I.e. If the Object Id struct GUID BirthVolumeId; // 0x28:
// is changed for some reason, this field will reflect the
// original value of the Object Id. // Birth Object Id is the first Object Id that was
// This field is valid if data_size == 0x48. // ever assigned to this MFT Record. I.e. If the Object Id
struct GUID BirthDomainId; // 0x48: Domain Id is currently unused but it is intended // is changed for some reason, this field will reflect the
// to be used in a network environment where the local // original value of the Object Id.
// machine is part of a Windows 2000 Domain. This may be // This field is valid if data_size == 0x48.
// used in a Windows 2000 Advanced Server managed domain. struct GUID BirthObjectId; // 0x38:
// Domain Id is currently unused but it is intended
// to be used in a network environment where the local
// machine is part of a Windows 2000 Domain. This may be
// used in a Windows 2000 Advanced Server managed domain.
struct GUID BirthDomainId; // 0x48:
}; };
static_assert(sizeof(struct NTFS_DE_O) == 0x58); static_assert(sizeof(struct NTFS_DE_O) == 0x58);
#define NTFS_OBJECT_ENTRY_DATA_SIZE1 \
0x38 // struct NTFS_DE_O.BirthDomainId is not used
#define NTFS_OBJECT_ENTRY_DATA_SIZE2 \
0x48 // struct NTFS_DE_O.BirthDomainId is used
/* Q Directory entry structure ( rule = 0x11 ) */ /* Q Directory entry structure ( rule = 0x11 ) */
struct NTFS_DE_Q { struct NTFS_DE_Q {
struct NTFS_DE de; struct NTFS_DE de;
__le32 owner_id; // 0x10: Unique Id assigned to file __le32 owner_id; // 0x10: Unique Id assigned to file
/* here is 0x30 bytes of user quota. NOTE: 4 byte aligned! */
__le32 Version; // 0x14: 0x02 __le32 Version; // 0x14: 0x02
__le32 flags2; // 0x18: Quota flags, see above __le32 Flags; // 0x18: Quota flags, see above
__le64 BytesUsed; // 0x1C: __le64 BytesUsed; // 0x1C:
__le64 ChangeTime; // 0x24: __le64 ChangeTime; // 0x24:
__le64 WarningLimit; // 0x28: __le64 WarningLimit; // 0x28:
...@@ -888,9 +904,9 @@ struct NTFS_DE_Q { ...@@ -888,9 +904,9 @@ struct NTFS_DE_Q {
__le64 ExceededTime; // 0x3C: __le64 ExceededTime; // 0x3C:
// SID is placed here // SID is placed here
}; // sizeof() = 0x44 }__packed; // sizeof() = 0x44
#define SIZEOF_NTFS_DE_Q 0x44 static_assert(sizeof(struct NTFS_DE_Q) == 0x44);
#define SecurityDescriptorsBlockSize 0x40000 // 256K #define SecurityDescriptorsBlockSize 0x40000 // 256K
#define SecurityDescriptorMaxSize 0x20000 // 128K #define SecurityDescriptorMaxSize 0x20000 // 128K
...@@ -912,7 +928,7 @@ struct SECURITY_HDR { ...@@ -912,7 +928,7 @@ struct SECURITY_HDR {
*/ */
} __packed; } __packed;
#define SIZEOF_SECURITY_HDR 0x14 static_assert(sizeof(struct SECURITY_HDR) == 0x14);
/* SII Directory entry structure */ /* SII Directory entry structure */
struct NTFS_DE_SII { struct NTFS_DE_SII {
...@@ -921,7 +937,8 @@ struct NTFS_DE_SII { ...@@ -921,7 +937,8 @@ struct NTFS_DE_SII {
struct SECURITY_HDR sec_hdr; // 0x14: struct SECURITY_HDR sec_hdr; // 0x14:
} __packed; } __packed;
#define SIZEOF_SII_DIRENTRY 0x28 static_assert(offsetof(struct NTFS_DE_SII, sec_hdr) == 0x14);
static_assert(sizeof(struct NTFS_DE_SII) == 0x28);
/* SDH Directory entry structure */ /* SDH Directory entry structure */
struct NTFS_DE_SDH { struct NTFS_DE_SDH {
...@@ -1155,7 +1172,7 @@ struct REPARSE_DATA_BUFFER { ...@@ -1155,7 +1172,7 @@ struct REPARSE_DATA_BUFFER {
#define FILE_NEED_EA 0x80 // See ntifs.h #define FILE_NEED_EA 0x80 // See ntifs.h
/* /*
*FILE_NEED_EA, indicates that the file to which the EA belongs cannot be * FILE_NEED_EA, indicates that the file to which the EA belongs cannot be
* interpreted without understanding the associated extended attributes. * interpreted without understanding the associated extended attributes.
*/ */
struct EA_INFO { struct EA_INFO {
......
...@@ -53,6 +53,8 @@ enum utf16_endian; ...@@ -53,6 +53,8 @@ enum utf16_endian;
#define E_NTFS_NONRESIDENT 556 #define E_NTFS_NONRESIDENT 556
/* NTFS specific error code about punch hole. */ /* NTFS specific error code about punch hole. */
#define E_NTFS_NOTALIGNED 557 #define E_NTFS_NOTALIGNED 557
/* NTFS specific error code when on-disk struct is corrupted. */
#define E_NTFS_CORRUPT 558
/* sbi->flags */ /* sbi->flags */
...@@ -274,7 +276,7 @@ struct ntfs_sb_info { ...@@ -274,7 +276,7 @@ struct ntfs_sb_info {
__le16 flags; // Cached current VOLUME_INFO::flags, VOLUME_FLAG_DIRTY. __le16 flags; // Cached current VOLUME_INFO::flags, VOLUME_FLAG_DIRTY.
u8 major_ver; u8 major_ver;
u8 minor_ver; u8 minor_ver;
char label[65]; char label[256];
bool real_dirty; // Real fs state. bool real_dirty; // Real fs state.
} volume; } volume;
...@@ -284,7 +286,6 @@ struct ntfs_sb_info { ...@@ -284,7 +286,6 @@ struct ntfs_sb_info {
struct ntfs_inode *ni; struct ntfs_inode *ni;
u32 next_id; u32 next_id;
u64 next_off; u64 next_off;
__le32 def_security_id; __le32 def_security_id;
} security; } security;
...@@ -312,6 +313,7 @@ struct ntfs_sb_info { ...@@ -312,6 +313,7 @@ struct ntfs_sb_info {
struct ntfs_mount_options *options; struct ntfs_mount_options *options;
struct ratelimit_state msg_ratelimit; struct ratelimit_state msg_ratelimit;
struct proc_dir_entry *procdir;
}; };
/* One MFT record(usually 1024 bytes), consists of attributes. */ /* One MFT record(usually 1024 bytes), consists of attributes. */
...@@ -465,8 +467,7 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name, ...@@ -465,8 +467,7 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
struct ATTR_LIST_ENTRY **new_le); struct ATTR_LIST_ENTRY **new_le);
bool al_remove_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le); bool al_remove_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le);
bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn, bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn,
const __le16 *name, size_t name_len, const __le16 *name, u8 name_len, const struct MFT_REF *ref);
const struct MFT_REF *ref);
int al_update(struct ntfs_inode *ni, int sync); int al_update(struct ntfs_inode *ni, int sync);
static inline size_t al_aligned(size_t size) static inline size_t al_aligned(size_t size)
{ {
...@@ -525,7 +526,7 @@ struct ATTRIB *ni_load_attr(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -525,7 +526,7 @@ struct ATTRIB *ni_load_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
int ni_load_all_mi(struct ntfs_inode *ni); int ni_load_all_mi(struct ntfs_inode *ni);
bool ni_add_subrecord(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi); bool ni_add_subrecord(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi);
int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type, int ni_remove_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
const __le16 *name, size_t name_len, bool base_only, const __le16 *name, u8 name_len, bool base_only,
const __le16 *id); const __le16 *id);
int ni_create_attr_list(struct ntfs_inode *ni); int ni_create_attr_list(struct ntfs_inode *ni);
int ni_expand_list(struct ntfs_inode *ni); int ni_expand_list(struct ntfs_inode *ni);
...@@ -542,7 +543,7 @@ void ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr, ...@@ -542,7 +543,7 @@ void ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
struct mft_inode *mi, struct ATTR_LIST_ENTRY *le); struct mft_inode *mi, struct ATTR_LIST_ENTRY *le);
int ni_delete_all(struct ntfs_inode *ni); int ni_delete_all(struct ntfs_inode *ni);
struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni, struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
const struct cpu_str *uni, const struct le_str *uni,
const struct MFT_REF *home, const struct MFT_REF *home,
struct mft_inode **mi, struct mft_inode **mi,
struct ATTR_LIST_ENTRY **entry); struct ATTR_LIST_ENTRY **entry);
...@@ -629,7 +630,7 @@ int ntfs_bio_fill_1(struct ntfs_sb_info *sbi, const struct runs_tree *run); ...@@ -629,7 +630,7 @@ int ntfs_bio_fill_1(struct ntfs_sb_info *sbi, const struct runs_tree *run);
int ntfs_vbo_to_lbo(struct ntfs_sb_info *sbi, const struct runs_tree *run, int ntfs_vbo_to_lbo(struct ntfs_sb_info *sbi, const struct runs_tree *run,
u64 vbo, u64 *lbo, u64 *bytes); u64 vbo, u64 *lbo, u64 *bytes);
struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST nRec, struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST nRec,
bool dir); enum RECORD_FLAG flag);
extern const u8 s_default_security[0x50]; extern const u8 s_default_security[0x50];
bool is_sd_valid(const struct SECURITY_DESCRIPTOR_RELATIVE *sd, u32 len); bool is_sd_valid(const struct SECURITY_DESCRIPTOR_RELATIVE *sd, u32 len);
int ntfs_security_init(struct ntfs_sb_info *sbi); int ntfs_security_init(struct ntfs_sb_info *sbi);
...@@ -647,8 +648,10 @@ int ntfs_insert_reparse(struct ntfs_sb_info *sbi, __le32 rtag, ...@@ -647,8 +648,10 @@ int ntfs_insert_reparse(struct ntfs_sb_info *sbi, __le32 rtag,
int ntfs_remove_reparse(struct ntfs_sb_info *sbi, __le32 rtag, int ntfs_remove_reparse(struct ntfs_sb_info *sbi, __le32 rtag,
const struct MFT_REF *ref); const struct MFT_REF *ref);
void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim); void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim);
int run_deallocate(struct ntfs_sb_info *sbi, struct runs_tree *run, bool trim); int run_deallocate(struct ntfs_sb_info *sbi, const struct runs_tree *run,
bool trim);
bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *name); bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *name);
int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len);
/* Globals from index.c */ /* Globals from index.c */
int indx_used_bit(struct ntfs_index *indx, struct ntfs_inode *ni, size_t *bit); int indx_used_bit(struct ntfs_index *indx, struct ntfs_inode *ni, size_t *bit);
...@@ -706,8 +709,8 @@ int ntfs_sync_inode(struct inode *inode); ...@@ -706,8 +709,8 @@ int ntfs_sync_inode(struct inode *inode);
int ntfs_flush_inodes(struct super_block *sb, struct inode *i1, int ntfs_flush_inodes(struct super_block *sb, struct inode *i1,
struct inode *i2); struct inode *i2);
int inode_write_data(struct inode *inode, const void *data, size_t bytes); int inode_write_data(struct inode *inode, const void *data, size_t bytes);
struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
struct inode *dir, struct dentry *dentry, struct dentry *dentry,
const struct cpu_str *uni, umode_t mode, const struct cpu_str *uni, umode_t mode,
dev_t dev, const char *symname, u32 size, dev_t dev, const char *symname, u32 size,
struct ntfs_fnd *fnd); struct ntfs_fnd *fnd);
...@@ -736,7 +739,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr); ...@@ -736,7 +739,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr);
// TODO: id? // TODO: id?
struct ATTRIB *mi_find_attr(struct mft_inode *mi, struct ATTRIB *attr, struct ATTRIB *mi_find_attr(struct mft_inode *mi, struct ATTRIB *attr,
enum ATTR_TYPE type, const __le16 *name, enum ATTR_TYPE type, const __le16 *name,
size_t name_len, const __le16 *id); u8 name_len, const __le16 *id);
static inline struct ATTRIB *rec_find_attr_le(struct mft_inode *rec, static inline struct ATTRIB *rec_find_attr_le(struct mft_inode *rec,
struct ATTR_LIST_ENTRY *le) struct ATTR_LIST_ENTRY *le)
{ {
...@@ -856,12 +859,12 @@ unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase, ...@@ -856,12 +859,12 @@ unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase,
/* globals from xattr.c */ /* globals from xattr.c */
#ifdef CONFIG_NTFS3_FS_POSIX_ACL #ifdef CONFIG_NTFS3_FS_POSIX_ACL
struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, struct dentry *dentry,
struct dentry *dentry, int type); int type);
int ntfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, int ntfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
struct posix_acl *acl, int type); struct posix_acl *acl, int type);
int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode, int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode,
struct inode *dir); struct inode *dir);
#else #else
#define ntfs_get_acl NULL #define ntfs_get_acl NULL
#define ntfs_set_acl NULL #define ntfs_set_acl NULL
......
...@@ -124,7 +124,7 @@ int mi_read(struct mft_inode *mi, bool is_mft) ...@@ -124,7 +124,7 @@ int mi_read(struct mft_inode *mi, bool is_mft)
struct rw_semaphore *rw_lock = NULL; struct rw_semaphore *rw_lock = NULL;
if (is_mounted(sbi)) { if (is_mounted(sbi)) {
if (!is_mft) { if (!is_mft && mft_ni) {
rw_lock = &mft_ni->file.run_lock; rw_lock = &mft_ni->file.run_lock;
down_read(rw_lock); down_read(rw_lock);
} }
...@@ -148,7 +148,7 @@ int mi_read(struct mft_inode *mi, bool is_mft) ...@@ -148,7 +148,7 @@ int mi_read(struct mft_inode *mi, bool is_mft)
ni_lock(mft_ni); ni_lock(mft_ni);
down_write(rw_lock); down_write(rw_lock);
} }
err = attr_load_runs_vcn(mft_ni, ATTR_DATA, NULL, 0, &mft_ni->file.run, err = attr_load_runs_vcn(mft_ni, ATTR_DATA, NULL, 0, run,
vbo >> sbi->cluster_bits); vbo >> sbi->cluster_bits);
if (rw_lock) { if (rw_lock) {
up_write(rw_lock); up_write(rw_lock);
...@@ -180,6 +180,12 @@ int mi_read(struct mft_inode *mi, bool is_mft) ...@@ -180,6 +180,12 @@ int mi_read(struct mft_inode *mi, bool is_mft)
return 0; return 0;
out: out:
if (err == -E_NTFS_CORRUPT) {
ntfs_err(sbi->sb, "mft corrupted");
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
err = -EINVAL;
}
return err; return err;
} }
...@@ -296,7 +302,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) ...@@ -296,7 +302,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
*/ */
struct ATTRIB *mi_find_attr(struct mft_inode *mi, struct ATTRIB *attr, struct ATTRIB *mi_find_attr(struct mft_inode *mi, struct ATTRIB *attr,
enum ATTR_TYPE type, const __le16 *name, enum ATTR_TYPE type, const __le16 *name,
size_t name_len, const __le16 *id) u8 name_len, const __le16 *id)
{ {
u32 type_in = le32_to_cpu(type); u32 type_in = le32_to_cpu(type);
u32 atype; u32 atype;
...@@ -382,6 +388,8 @@ int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno, ...@@ -382,6 +388,8 @@ int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno,
rec->seq = cpu_to_le16(seq); rec->seq = cpu_to_le16(seq);
rec->flags = RECORD_FLAG_IN_USE | flags; rec->flags = RECORD_FLAG_IN_USE | flags;
if (MFTRECORD_FIXUP_OFFSET == MFTRECORD_FIXUP_OFFSET_3)
rec->mft_record = cpu_to_le32(rno);
mi->dirty = true; mi->dirty = true;
......
...@@ -434,8 +434,8 @@ bool run_add_entry(struct runs_tree *run, CLST vcn, CLST lcn, CLST len, ...@@ -434,8 +434,8 @@ bool run_add_entry(struct runs_tree *run, CLST vcn, CLST lcn, CLST len,
if (should_add_tail) { if (should_add_tail) {
tail_lcn = r->lcn == SPARSE_LCN ? tail_lcn = r->lcn == SPARSE_LCN ?
SPARSE_LCN : SPARSE_LCN :
(r->lcn + Tovcn); (r->lcn + Tovcn);
tail_vcn = r->vcn + Tovcn; tail_vcn = r->vcn + Tovcn;
tail_len = r->len - Tovcn; tail_len = r->len - Tovcn;
} }
......
This diff is collapsed.
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
static inline size_t unpacked_ea_size(const struct EA_FULL *ea) static inline size_t unpacked_ea_size(const struct EA_FULL *ea)
{ {
return ea->size ? le32_to_cpu(ea->size) : return ea->size ? le32_to_cpu(ea->size) :
ALIGN(struct_size(ea, name, ALIGN(struct_size(ea, name,
1 + ea->name_len + 1 + ea->name_len +
le16_to_cpu(ea->elength)), le16_to_cpu(ea->elength)),
4); 4);
...@@ -141,6 +141,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea, ...@@ -141,6 +141,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
memset(Add2Ptr(ea_p, size), 0, add_bytes); memset(Add2Ptr(ea_p, size), 0, add_bytes);
err = -EINVAL;
/* Check all attributes for consistency. */ /* Check all attributes for consistency. */
for (off = 0; off < size; off += ea_size) { for (off = 0; off < size; off += ea_size) {
const struct EA_FULL *ef = Add2Ptr(ea_p, off); const struct EA_FULL *ef = Add2Ptr(ea_p, off);
...@@ -214,6 +215,9 @@ static ssize_t ntfs_list_ea(struct ntfs_inode *ni, char *buffer, ...@@ -214,6 +215,9 @@ static ssize_t ntfs_list_ea(struct ntfs_inode *ni, char *buffer,
ea = Add2Ptr(ea_all, off); ea = Add2Ptr(ea_all, off);
ea_size = unpacked_ea_size(ea); ea_size = unpacked_ea_size(ea);
if (!ea->name_len)
break;
if (buffer) { if (buffer) {
if (ret + ea->name_len + 1 > bytes_per_buffer) { if (ret + ea->name_len + 1 > bytes_per_buffer) {
err = -ERANGE; err = -ERANGE;
...@@ -524,8 +528,8 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name, ...@@ -524,8 +528,8 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
/* /*
* ntfs_get_acl - inode_operations::get_acl * ntfs_get_acl - inode_operations::get_acl
*/ */
struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, struct dentry *dentry,
struct dentry *dentry, int type) int type)
{ {
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_inode *ni = ntfs_i(inode);
...@@ -592,8 +596,7 @@ static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap, ...@@ -592,8 +596,7 @@ static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap,
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
/* Do not change i_mode if we are in init_acl */ /* Do not change i_mode if we are in init_acl */
if (acl && !init_acl) { if (acl && !init_acl) {
err = posix_acl_update_mode(idmap, inode, &mode, err = posix_acl_update_mode(idmap, inode, &mode, &acl);
&acl);
if (err) if (err)
return err; return err;
} }
...@@ -816,10 +819,9 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de, ...@@ -816,10 +819,9 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
* ntfs_setxattr - inode_operations::setxattr * ntfs_setxattr - inode_operations::setxattr
*/ */
static noinline int ntfs_setxattr(const struct xattr_handler *handler, static noinline int ntfs_setxattr(const struct xattr_handler *handler,
struct mnt_idmap *idmap, struct mnt_idmap *idmap, struct dentry *de,
struct dentry *de, struct inode *inode, struct inode *inode, const char *name,
const char *name, const void *value, const void *value, size_t size, int flags)
size_t size, int flags)
{ {
int err = -EINVAL; int err = -EINVAL;
struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_inode *ni = ntfs_i(inode);
......
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