]>
git.proxmox.com Git - mirror_ubuntu-kernels.git/blob - fs/ntfs3/attrlist.c
1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
17 * Return: True if @le is valid.
19 static inline bool al_is_valid_le(const struct ntfs_inode
*ni
,
20 struct ATTR_LIST_ENTRY
*le
)
22 if (!le
|| !ni
->attr_list
.le
|| !ni
->attr_list
.size
)
25 return PtrOffset(ni
->attr_list
.le
, le
) + le16_to_cpu(le
->size
) <=
29 void al_destroy(struct ntfs_inode
*ni
)
31 run_close(&ni
->attr_list
.run
);
32 kfree(ni
->attr_list
.le
);
33 ni
->attr_list
.le
= NULL
;
34 ni
->attr_list
.size
= 0;
35 ni
->attr_list
.dirty
= false;
41 * This method makes sure that the ATTRIB list, if present,
42 * has been properly set up.
44 int ntfs_load_attr_list(struct ntfs_inode
*ni
, struct ATTRIB
*attr
)
50 if (ni
->attr_list
.size
)
54 lsize
= le32_to_cpu(attr
->res
.data_size
);
55 le
= kmalloc(al_aligned(lsize
), GFP_NOFS
);
60 memcpy(le
, resident_data(attr
), lsize
);
61 } else if (attr
->nres
.svcn
) {
65 u16 run_off
= le16_to_cpu(attr
->nres
.run_off
);
67 lsize
= le64_to_cpu(attr
->nres
.data_size
);
69 run_init(&ni
->attr_list
.run
);
71 err
= run_unpack_ex(&ni
->attr_list
.run
, ni
->mi
.sbi
, ni
->mi
.rno
,
72 0, le64_to_cpu(attr
->nres
.evcn
), 0,
73 Add2Ptr(attr
, run_off
),
74 le32_to_cpu(attr
->size
) - run_off
);
78 le
= kmalloc(al_aligned(lsize
), GFP_NOFS
);
84 err
= ntfs_read_run_nb(ni
->mi
.sbi
, &ni
->attr_list
.run
, 0, le
,
90 ni
->attr_list
.size
= lsize
;
91 ni
->attr_list
.le
= le
;
96 ni
->attr_list
.le
= le
;
106 * * The next list le.
107 * * If @le is NULL then return the first le.
109 struct ATTR_LIST_ENTRY
*al_enumerate(struct ntfs_inode
*ni
,
110 struct ATTR_LIST_ENTRY
*le
)
116 le
= ni
->attr_list
.le
;
118 sz
= le16_to_cpu(le
->size
);
119 if (sz
< sizeof(struct ATTR_LIST_ENTRY
)) {
120 /* Impossible 'cause we should not return such le. */
123 le
= Add2Ptr(le
, sz
);
126 /* Check boundary. */
127 off
= PtrOffset(ni
->attr_list
.le
, le
);
128 if (off
+ sizeof(struct ATTR_LIST_ENTRY
) > ni
->attr_list
.size
) {
129 /* The regular end of list. */
133 sz
= le16_to_cpu(le
->size
);
135 /* Check le for errors. */
136 if (sz
< sizeof(struct ATTR_LIST_ENTRY
) ||
137 off
+ sz
> ni
->attr_list
.size
||
138 sz
< le
->name_off
+ le
->name_len
* sizeof(short)) {
148 * Find the first le in the list which matches type, name and VCN.
150 * Return: NULL if not found.
152 struct ATTR_LIST_ENTRY
*al_find_le(struct ntfs_inode
*ni
,
153 struct ATTR_LIST_ENTRY
*le
,
154 const struct ATTRIB
*attr
)
156 CLST svcn
= attr_svcn(attr
);
158 return al_find_ex(ni
, le
, attr
->type
, attr_name(attr
), attr
->name_len
,
165 * Find the first le in the list which matches type, name and VCN.
167 * Return: NULL if not found.
169 struct ATTR_LIST_ENTRY
*al_find_ex(struct ntfs_inode
*ni
,
170 struct ATTR_LIST_ENTRY
*le
,
171 enum ATTR_TYPE type
, const __le16
*name
,
172 u8 name_len
, const CLST
*vcn
)
174 struct ATTR_LIST_ENTRY
*ret
= NULL
;
175 u32 type_in
= le32_to_cpu(type
);
177 while ((le
= al_enumerate(ni
, le
))) {
179 int diff
= le32_to_cpu(le
->type
) - type_in
;
181 /* List entries are sorted by type, name and VCN. */
188 if (le
->name_len
!= name_len
)
191 le_vcn
= le64_to_cpu(le
->vcn
);
194 * Compare entry names only for entry with vcn == 0.
196 diff
= ntfs_cmp_names(le_name(le
), name_len
, name
,
197 name_len
, ni
->mi
.sbi
->upcase
,
222 * al_find_le_to_insert
224 * Find the first list entry which matches type, name and VCN.
226 static struct ATTR_LIST_ENTRY
*al_find_le_to_insert(struct ntfs_inode
*ni
,
229 u8 name_len
, CLST vcn
)
231 struct ATTR_LIST_ENTRY
*le
= NULL
, *prev
;
232 u32 type_in
= le32_to_cpu(type
);
234 /* List entries are sorted by type, name and VCN. */
235 while ((le
= al_enumerate(ni
, prev
= le
))) {
236 int diff
= le32_to_cpu(le
->type
) - type_in
;
246 * Compare entry names only for entry with vcn == 0.
248 diff
= ntfs_cmp_names(le_name(le
), le
->name_len
, name
,
249 name_len
, ni
->mi
.sbi
->upcase
,
258 if (le64_to_cpu(le
->vcn
) >= vcn
)
262 return prev
? Add2Ptr(prev
, le16_to_cpu(prev
->size
)) : ni
->attr_list
.le
;
268 * Add an "attribute list entry" to the list.
270 int al_add_le(struct ntfs_inode
*ni
, enum ATTR_TYPE type
, const __le16
*name
,
271 u8 name_len
, CLST svcn
, __le16 id
, const struct MFT_REF
*ref
,
272 struct ATTR_LIST_ENTRY
**new_le
)
276 struct ATTR_LIST_ENTRY
*le
;
279 size_t asize
, new_asize
, old_size
;
281 typeof(ni
->attr_list
) *al
= &ni
->attr_list
;
284 * Compute the size of the new 'le'
286 sz
= le_size(name_len
);
288 new_size
= old_size
+ sz
;
289 asize
= al_aligned(old_size
);
290 new_asize
= al_aligned(new_size
);
292 /* Scan forward to the point at which the new 'le' should be inserted. */
293 le
= al_find_le_to_insert(ni
, type
, name
, name_len
, svcn
);
294 off
= PtrOffset(al
->le
, le
);
296 if (new_size
> asize
) {
297 void *ptr
= kmalloc(new_asize
, GFP_NOFS
);
302 memcpy(ptr
, al
->le
, off
);
303 memcpy(Add2Ptr(ptr
, off
+ sz
), le
, old_size
- off
);
304 le
= Add2Ptr(ptr
, off
);
308 memmove(Add2Ptr(le
, sz
), le
, old_size
- off
);
315 le
->size
= cpu_to_le16(sz
);
316 le
->name_len
= name_len
;
317 le
->name_off
= offsetof(struct ATTR_LIST_ENTRY
, name
);
318 le
->vcn
= cpu_to_le64(svcn
);
321 memcpy(le
->name
, name
, sizeof(short) * name_len
);
323 err
= attr_set_size(ni
, ATTR_LIST
, NULL
, 0, &al
->run
, new_size
,
324 &new_size
, true, &attr
);
326 /* Undo memmove above. */
327 memmove(le
, Add2Ptr(le
, sz
), old_size
- off
);
334 if (attr
&& attr
->non_res
) {
335 err
= ntfs_sb_write_run(ni
->mi
.sbi
, &al
->run
, 0, al
->le
,
346 * al_remove_le - Remove @le from attribute list.
348 bool al_remove_le(struct ntfs_inode
*ni
, struct ATTR_LIST_ENTRY
*le
)
352 typeof(ni
->attr_list
) *al
= &ni
->attr_list
;
354 if (!al_is_valid_le(ni
, le
))
357 /* Save on stack the size of 'le' */
358 size
= le16_to_cpu(le
->size
);
359 off
= PtrOffset(al
->le
, le
);
361 memmove(le
, Add2Ptr(le
, size
), al
->size
- (off
+ size
));
370 * al_delete_le - Delete first le from the list which matches its parameters.
372 bool al_delete_le(struct ntfs_inode
*ni
, enum ATTR_TYPE type
, CLST vcn
,
373 const __le16
*name
, size_t name_len
,
374 const struct MFT_REF
*ref
)
377 struct ATTR_LIST_ENTRY
*le
;
379 typeof(ni
->attr_list
) *al
= &ni
->attr_list
;
381 /* Scan forward to the first le that matches the input. */
382 le
= al_find_ex(ni
, NULL
, type
, name
, name_len
, &vcn
);
386 off
= PtrOffset(al
->le
, le
);
391 if (le
->type
!= type
)
393 if (le
->name_len
!= name_len
)
395 if (name_len
&& ntfs_cmp_names(le_name(le
), name_len
, name
, name_len
,
396 ni
->mi
.sbi
->upcase
, true))
398 if (le64_to_cpu(le
->vcn
) != vcn
)
402 * The caller specified a segment reference, so we have to
403 * scan through the matching entries until we find that segment
404 * reference or we run of matching entries.
406 if (ref
&& memcmp(ref
, &le
->ref
, sizeof(*ref
))) {
407 off
+= le16_to_cpu(le
->size
);
408 le
= Add2Ptr(al
->le
, off
);
412 /* Save on stack the size of 'le'. */
413 size
= le16_to_cpu(le
->size
);
415 memmove(le
, Add2Ptr(le
, size
), al
->size
- (off
+ size
));
423 int al_update(struct ntfs_inode
*ni
, int sync
)
427 typeof(ni
->attr_list
) *al
= &ni
->attr_list
;
429 if (!al
->dirty
|| !al
->size
)
433 * Attribute list increased on demand in al_add_le.
434 * Attribute list decreased here.
436 err
= attr_set_size(ni
, ATTR_LIST
, NULL
, 0, &al
->run
, al
->size
, NULL
,
441 if (!attr
->non_res
) {
442 memcpy(resident_data(attr
), al
->le
, al
->size
);
444 err
= ntfs_sb_write_run(ni
->mi
.sbi
, &al
->run
, 0, al
->le
,
449 attr
->nres
.valid_size
= attr
->nres
.data_size
;