~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/ntfs3/record.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  *
  4  * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
  5  *
  6  */
  7 
  8 #include <linux/fs.h>
  9 
 10 #include "debug.h"
 11 #include "ntfs.h"
 12 #include "ntfs_fs.h"
 13 
 14 static inline int compare_attr(const struct ATTRIB *left, enum ATTR_TYPE type,
 15                                const __le16 *name, u8 name_len,
 16                                const u16 *upcase)
 17 {
 18         /* First, compare the type codes. */
 19         int diff = le32_to_cpu(left->type) - le32_to_cpu(type);
 20 
 21         if (diff)
 22                 return diff;
 23 
 24         /* They have the same type code, so we have to compare the names. */
 25         return ntfs_cmp_names(attr_name(left), left->name_len, name, name_len,
 26                               upcase, true);
 27 }
 28 
 29 /*
 30  * mi_new_attt_id
 31  *
 32  * Return: Unused attribute id that is less than mrec->next_attr_id.
 33  */
 34 static __le16 mi_new_attt_id(struct mft_inode *mi)
 35 {
 36         u16 free_id, max_id, t16;
 37         struct MFT_REC *rec = mi->mrec;
 38         struct ATTRIB *attr;
 39         __le16 id;
 40 
 41         id = rec->next_attr_id;
 42         free_id = le16_to_cpu(id);
 43         if (free_id < 0x7FFF) {
 44                 rec->next_attr_id = cpu_to_le16(free_id + 1);
 45                 return id;
 46         }
 47 
 48         /* One record can store up to 1024/24 ~= 42 attributes. */
 49         free_id = 0;
 50         max_id = 0;
 51 
 52         attr = NULL;
 53 
 54         for (;;) {
 55                 attr = mi_enum_attr(mi, attr);
 56                 if (!attr) {
 57                         rec->next_attr_id = cpu_to_le16(max_id + 1);
 58                         mi->dirty = true;
 59                         return cpu_to_le16(free_id);
 60                 }
 61 
 62                 t16 = le16_to_cpu(attr->id);
 63                 if (t16 == free_id) {
 64                         free_id += 1;
 65                         attr = NULL;
 66                 } else if (max_id < t16)
 67                         max_id = t16;
 68         }
 69 }
 70 
 71 int mi_get(struct ntfs_sb_info *sbi, CLST rno, struct mft_inode **mi)
 72 {
 73         int err;
 74         struct mft_inode *m = kzalloc(sizeof(struct mft_inode), GFP_NOFS);
 75 
 76         if (!m)
 77                 return -ENOMEM;
 78 
 79         err = mi_init(m, sbi, rno);
 80         if (err) {
 81                 kfree(m);
 82                 return err;
 83         }
 84 
 85         err = mi_read(m, false);
 86         if (err) {
 87                 mi_put(m);
 88                 return err;
 89         }
 90 
 91         *mi = m;
 92         return 0;
 93 }
 94 
 95 void mi_put(struct mft_inode *mi)
 96 {
 97         mi_clear(mi);
 98         kfree(mi);
 99 }
100 
101 int mi_init(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno)
102 {
103         mi->sbi = sbi;
104         mi->rno = rno;
105         mi->mrec = kmalloc(sbi->record_size, GFP_NOFS);
106         if (!mi->mrec)
107                 return -ENOMEM;
108 
109         return 0;
110 }
111 
112 /*
113  * mi_read - Read MFT data.
114  */
115 int mi_read(struct mft_inode *mi, bool is_mft)
116 {
117         int err;
118         struct MFT_REC *rec = mi->mrec;
119         struct ntfs_sb_info *sbi = mi->sbi;
120         u32 bpr = sbi->record_size;
121         u64 vbo = (u64)mi->rno << sbi->record_bits;
122         struct ntfs_inode *mft_ni = sbi->mft.ni;
123         struct runs_tree *run = mft_ni ? &mft_ni->file.run : NULL;
124         struct rw_semaphore *rw_lock = NULL;
125 
126         if (is_mounted(sbi)) {
127                 if (!is_mft && mft_ni) {
128                         rw_lock = &mft_ni->file.run_lock;
129                         down_read(rw_lock);
130                 }
131         }
132 
133         err = ntfs_read_bh(sbi, run, vbo, &rec->rhdr, bpr, &mi->nb);
134         if (rw_lock)
135                 up_read(rw_lock);
136         if (!err)
137                 goto ok;
138 
139         if (err == -E_NTFS_FIXUP) {
140                 mi->dirty = true;
141                 goto ok;
142         }
143 
144         if (err != -ENOENT)
145                 goto out;
146 
147         if (rw_lock) {
148                 ni_lock(mft_ni);
149                 down_write(rw_lock);
150         }
151         err = attr_load_runs_vcn(mft_ni, ATTR_DATA, NULL, 0, run,
152                                  vbo >> sbi->cluster_bits);
153         if (rw_lock) {
154                 up_write(rw_lock);
155                 ni_unlock(mft_ni);
156         }
157         if (err)
158                 goto out;
159 
160         if (rw_lock)
161                 down_read(rw_lock);
162         err = ntfs_read_bh(sbi, run, vbo, &rec->rhdr, bpr, &mi->nb);
163         if (rw_lock)
164                 up_read(rw_lock);
165 
166         if (err == -E_NTFS_FIXUP) {
167                 mi->dirty = true;
168                 goto ok;
169         }
170         if (err)
171                 goto out;
172 
173 ok:
174         /* Check field 'total' only here. */
175         if (le32_to_cpu(rec->total) != bpr) {
176                 err = -EINVAL;
177                 goto out;
178         }
179 
180         return 0;
181 
182 out:
183         if (err == -E_NTFS_CORRUPT) {
184                 ntfs_err(sbi->sb, "mft corrupted");
185                 ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
186                 err = -EINVAL;
187         }
188 
189         return err;
190 }
191 
192 /*
193  * mi_enum_attr - start/continue attributes enumeration in record.
194  *
195  * NOTE: mi->mrec - memory of size sbi->record_size
196  * here we sure that mi->mrec->total == sbi->record_size (see mi_read)
197  */
198 struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
199 {
200         const struct MFT_REC *rec = mi->mrec;
201         u32 used = le32_to_cpu(rec->used);
202         u32 t32, off, asize, prev_type;
203         u16 t16;
204         u64 data_size, alloc_size, tot_size;
205 
206         if (!attr) {
207                 u32 total = le32_to_cpu(rec->total);
208 
209                 off = le16_to_cpu(rec->attr_off);
210 
211                 if (used > total)
212                         return NULL;
213 
214                 if (off >= used || off < MFTRECORD_FIXUP_OFFSET_1 ||
215                     !IS_ALIGNED(off, 4)) {
216                         return NULL;
217                 }
218 
219                 /* Skip non-resident records. */
220                 if (!is_rec_inuse(rec))
221                         return NULL;
222 
223                 prev_type = 0;
224                 attr = Add2Ptr(rec, off);
225         } else {
226                 /* Check if input attr inside record. */
227                 off = PtrOffset(rec, attr);
228                 if (off >= used)
229                         return NULL;
230 
231                 asize = le32_to_cpu(attr->size);
232                 if (asize < SIZEOF_RESIDENT) {
233                         /* Impossible 'cause we should not return such attribute. */
234                         return NULL;
235                 }
236 
237                 /* Overflow check. */
238                 if (off + asize < off)
239                         return NULL;
240 
241                 prev_type = le32_to_cpu(attr->type);
242                 attr = Add2Ptr(attr, asize);
243                 off += asize;
244         }
245 
246         asize = le32_to_cpu(attr->size);
247 
248         /* Can we use the first field (attr->type). */
249         if (off + 8 > used) {
250                 static_assert(ALIGN(sizeof(enum ATTR_TYPE), 8) == 8);
251                 return NULL;
252         }
253 
254         if (attr->type == ATTR_END) {
255                 /* End of enumeration. */
256                 return NULL;
257         }
258 
259         /* 0x100 is last known attribute for now. */
260         t32 = le32_to_cpu(attr->type);
261         if (!t32 || (t32 & 0xf) || (t32 > 0x100))
262                 return NULL;
263 
264         /* attributes in record must be ordered by type */
265         if (t32 < prev_type)
266                 return NULL;
267 
268         /* Check overflow and boundary. */
269         if (off + asize < off || off + asize > used)
270                 return NULL;
271 
272         /* Check size of attribute. */
273         if (!attr->non_res) {
274                 /* Check resident fields. */
275                 if (asize < SIZEOF_RESIDENT)
276                         return NULL;
277 
278                 t16 = le16_to_cpu(attr->res.data_off);
279                 if (t16 > asize)
280                         return NULL;
281 
282                 if (le32_to_cpu(attr->res.data_size) > asize - t16)
283                         return NULL;
284 
285                 t32 = sizeof(short) * attr->name_len;
286                 if (t32 && le16_to_cpu(attr->name_off) + t32 > t16)
287                         return NULL;
288 
289                 return attr;
290         }
291 
292         /* Check nonresident fields. */
293         if (attr->non_res != 1)
294                 return NULL;
295 
296         t16 = le16_to_cpu(attr->nres.run_off);
297         if (t16 > asize)
298                 return NULL;
299 
300         t32 = sizeof(short) * attr->name_len;
301         if (t32 && le16_to_cpu(attr->name_off) + t32 > t16)
302                 return NULL;
303 
304         /* Check start/end vcn. */
305         if (le64_to_cpu(attr->nres.svcn) > le64_to_cpu(attr->nres.evcn) + 1)
306                 return NULL;
307 
308         data_size = le64_to_cpu(attr->nres.data_size);
309         if (le64_to_cpu(attr->nres.valid_size) > data_size)
310                 return NULL;
311 
312         alloc_size = le64_to_cpu(attr->nres.alloc_size);
313         if (data_size > alloc_size)
314                 return NULL;
315 
316         t32 = mi->sbi->cluster_mask;
317         if (alloc_size & t32)
318                 return NULL;
319 
320         if (!attr->nres.svcn && is_attr_ext(attr)) {
321                 /* First segment of sparse/compressed attribute */
322                 if (asize + 8 < SIZEOF_NONRESIDENT_EX)
323                         return NULL;
324 
325                 tot_size = le64_to_cpu(attr->nres.total_size);
326                 if (tot_size & t32)
327                         return NULL;
328 
329                 if (tot_size > alloc_size)
330                         return NULL;
331         } else {
332                 if (asize + 8 < SIZEOF_NONRESIDENT)
333                         return NULL;
334 
335                 if (attr->nres.c_unit)
336                         return NULL;
337         }
338 
339         return attr;
340 }
341 
342 /*
343  * mi_find_attr - Find the attribute by type and name and id.
344  */
345 struct ATTRIB *mi_find_attr(struct mft_inode *mi, struct ATTRIB *attr,
346                             enum ATTR_TYPE type, const __le16 *name,
347                             u8 name_len, const __le16 *id)
348 {
349         u32 type_in = le32_to_cpu(type);
350         u32 atype;
351 
352 next_attr:
353         attr = mi_enum_attr(mi, attr);
354         if (!attr)
355                 return NULL;
356 
357         atype = le32_to_cpu(attr->type);
358         if (atype > type_in)
359                 return NULL;
360 
361         if (atype < type_in)
362                 goto next_attr;
363 
364         if (attr->name_len != name_len)
365                 goto next_attr;
366 
367         if (name_len && memcmp(attr_name(attr), name, name_len * sizeof(short)))
368                 goto next_attr;
369 
370         if (id && *id != attr->id)
371                 goto next_attr;
372 
373         return attr;
374 }
375 
376 int mi_write(struct mft_inode *mi, int wait)
377 {
378         struct MFT_REC *rec;
379         int err;
380         struct ntfs_sb_info *sbi;
381 
382         if (!mi->dirty)
383                 return 0;
384 
385         sbi = mi->sbi;
386         rec = mi->mrec;
387 
388         err = ntfs_write_bh(sbi, &rec->rhdr, &mi->nb, wait);
389         if (err)
390                 return err;
391 
392         if (mi->rno < sbi->mft.recs_mirr)
393                 sbi->flags |= NTFS_FLAGS_MFTMIRR;
394 
395         mi->dirty = false;
396 
397         return 0;
398 }
399 
400 int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno,
401                   __le16 flags, bool is_mft)
402 {
403         int err;
404         u16 seq = 1;
405         struct MFT_REC *rec;
406         u64 vbo = (u64)rno << sbi->record_bits;
407 
408         err = mi_init(mi, sbi, rno);
409         if (err)
410                 return err;
411 
412         rec = mi->mrec;
413 
414         if (rno == MFT_REC_MFT) {
415                 ;
416         } else if (rno < MFT_REC_FREE) {
417                 seq = rno;
418         } else if (rno >= sbi->mft.used) {
419                 ;
420         } else if (mi_read(mi, is_mft)) {
421                 ;
422         } else if (rec->rhdr.sign == NTFS_FILE_SIGNATURE) {
423                 /* Record is reused. Update its sequence number. */
424                 seq = le16_to_cpu(rec->seq) + 1;
425                 if (!seq)
426                         seq = 1;
427         }
428 
429         memcpy(rec, sbi->new_rec, sbi->record_size);
430 
431         rec->seq = cpu_to_le16(seq);
432         rec->flags = RECORD_FLAG_IN_USE | flags;
433         if (MFTRECORD_FIXUP_OFFSET == MFTRECORD_FIXUP_OFFSET_3)
434                 rec->mft_record = cpu_to_le32(rno);
435 
436         mi->dirty = true;
437 
438         if (!mi->nb.nbufs) {
439                 struct ntfs_inode *ni = sbi->mft.ni;
440                 bool lock = false;
441 
442                 if (is_mounted(sbi) && !is_mft) {
443                         down_read(&ni->file.run_lock);
444                         lock = true;
445                 }
446 
447                 err = ntfs_get_bh(sbi, &ni->file.run, vbo, sbi->record_size,
448                                   &mi->nb);
449                 if (lock)
450                         up_read(&ni->file.run_lock);
451         }
452 
453         return err;
454 }
455 
456 /*
457  * mi_insert_attr - Reserve space for new attribute.
458  *
459  * Return: Not full constructed attribute or NULL if not possible to create.
460  */
461 struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
462                               const __le16 *name, u8 name_len, u32 asize,
463                               u16 name_off)
464 {
465         size_t tail;
466         struct ATTRIB *attr;
467         __le16 id;
468         struct MFT_REC *rec = mi->mrec;
469         struct ntfs_sb_info *sbi = mi->sbi;
470         u32 used = le32_to_cpu(rec->used);
471         const u16 *upcase = sbi->upcase;
472 
473         /* Can we insert mi attribute? */
474         if (used + asize > sbi->record_size)
475                 return NULL;
476 
477         /*
478          * Scan through the list of attributes to find the point
479          * at which we should insert it.
480          */
481         attr = NULL;
482         while ((attr = mi_enum_attr(mi, attr))) {
483                 int diff = compare_attr(attr, type, name, name_len, upcase);
484 
485                 if (diff < 0)
486                         continue;
487 
488                 if (!diff && !is_attr_indexed(attr))
489                         return NULL;
490                 break;
491         }
492 
493         if (!attr) {
494                 /* Append. */
495                 tail = 8;
496                 attr = Add2Ptr(rec, used - 8);
497         } else {
498                 /* Insert before 'attr'. */
499                 tail = used - PtrOffset(rec, attr);
500         }
501 
502         id = mi_new_attt_id(mi);
503 
504         memmove(Add2Ptr(attr, asize), attr, tail);
505         memset(attr, 0, asize);
506 
507         attr->type = type;
508         attr->size = cpu_to_le32(asize);
509         attr->name_len = name_len;
510         attr->name_off = cpu_to_le16(name_off);
511         attr->id = id;
512 
513         memmove(Add2Ptr(attr, name_off), name, name_len * sizeof(short));
514         rec->used = cpu_to_le32(used + asize);
515 
516         mi->dirty = true;
517 
518         return attr;
519 }
520 
521 /*
522  * mi_remove_attr - Remove the attribute from record.
523  *
524  * NOTE: The source attr will point to next attribute.
525  */
526 bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi,
527                     struct ATTRIB *attr)
528 {
529         struct MFT_REC *rec = mi->mrec;
530         u32 aoff = PtrOffset(rec, attr);
531         u32 used = le32_to_cpu(rec->used);
532         u32 asize = le32_to_cpu(attr->size);
533 
534         if (aoff + asize > used)
535                 return false;
536 
537         if (ni && is_attr_indexed(attr) && attr->type == ATTR_NAME) {
538                 u16 links = le16_to_cpu(ni->mi.mrec->hard_links);
539                 if (!links) {
540                         /* minor error. Not critical. */
541                 } else {
542                         ni->mi.mrec->hard_links = cpu_to_le16(links - 1);
543                         ni->mi.dirty = true;
544                 }
545         }
546 
547         used -= asize;
548         memmove(attr, Add2Ptr(attr, asize), used - aoff);
549         rec->used = cpu_to_le32(used);
550         mi->dirty = true;
551 
552         return true;
553 }
554 
555 /* bytes = "new attribute size" - "old attribute size" */
556 bool mi_resize_attr(struct mft_inode *mi, struct ATTRIB *attr, int bytes)
557 {
558         struct MFT_REC *rec = mi->mrec;
559         u32 aoff = PtrOffset(rec, attr);
560         u32 total, used = le32_to_cpu(rec->used);
561         u32 nsize, asize = le32_to_cpu(attr->size);
562         u32 rsize = le32_to_cpu(attr->res.data_size);
563         int tail = (int)(used - aoff - asize);
564         int dsize;
565         char *next;
566 
567         if (tail < 0 || aoff >= used)
568                 return false;
569 
570         if (!bytes)
571                 return true;
572 
573         total = le32_to_cpu(rec->total);
574         next = Add2Ptr(attr, asize);
575 
576         if (bytes > 0) {
577                 dsize = ALIGN(bytes, 8);
578                 if (used + dsize > total)
579                         return false;
580                 nsize = asize + dsize;
581                 /* Move tail */
582                 memmove(next + dsize, next, tail);
583                 memset(next, 0, dsize);
584                 used += dsize;
585                 rsize += dsize;
586         } else {
587                 dsize = ALIGN(-bytes, 8);
588                 if (dsize > asize)
589                         return false;
590                 nsize = asize - dsize;
591                 memmove(next - dsize, next, tail);
592                 used -= dsize;
593                 rsize -= dsize;
594         }
595 
596         rec->used = cpu_to_le32(used);
597         attr->size = cpu_to_le32(nsize);
598         if (!attr->non_res)
599                 attr->res.data_size = cpu_to_le32(rsize);
600         mi->dirty = true;
601 
602         return true;
603 }
604 
605 /*
606  * Pack runs in MFT record.
607  * If failed record is not changed.
608  */
609 int mi_pack_runs(struct mft_inode *mi, struct ATTRIB *attr,
610                  struct runs_tree *run, CLST len)
611 {
612         int err = 0;
613         struct ntfs_sb_info *sbi = mi->sbi;
614         u32 new_run_size;
615         CLST plen;
616         struct MFT_REC *rec = mi->mrec;
617         CLST svcn = le64_to_cpu(attr->nres.svcn);
618         u32 used = le32_to_cpu(rec->used);
619         u32 aoff = PtrOffset(rec, attr);
620         u32 asize = le32_to_cpu(attr->size);
621         char *next = Add2Ptr(attr, asize);
622         u16 run_off = le16_to_cpu(attr->nres.run_off);
623         u32 run_size = asize - run_off;
624         u32 tail = used - aoff - asize;
625         u32 dsize = sbi->record_size - used;
626 
627         /* Make a maximum gap in current record. */
628         memmove(next + dsize, next, tail);
629 
630         /* Pack as much as possible. */
631         err = run_pack(run, svcn, len, Add2Ptr(attr, run_off), run_size + dsize,
632                        &plen);
633         if (err < 0) {
634                 memmove(next, next + dsize, tail);
635                 return err;
636         }
637 
638         new_run_size = ALIGN(err, 8);
639 
640         memmove(next + new_run_size - run_size, next + dsize, tail);
641 
642         attr->size = cpu_to_le32(asize + new_run_size - run_size);
643         attr->nres.evcn = cpu_to_le64(svcn + plen - 1);
644         rec->used = cpu_to_le32(used + new_run_size - run_size);
645         mi->dirty = true;
646 
647         return 0;
648 }
649 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php