Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *
0004  * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
0005  *
0006  *  Directory handling functions for NTFS-based filesystems.
0007  *
0008  */
0009 
0010 #include <linux/fs.h>
0011 #include <linux/nls.h>
0012 
0013 #include "debug.h"
0014 #include "ntfs.h"
0015 #include "ntfs_fs.h"
0016 
0017 /* Convert little endian UTF-16 to NLS string. */
0018 int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const __le16 *name, u32 len,
0019               u8 *buf, int buf_len)
0020 {
0021     int ret, warn;
0022     u8 *op;
0023     struct nls_table *nls = sbi->options->nls;
0024 
0025     static_assert(sizeof(wchar_t) == sizeof(__le16));
0026 
0027     if (!nls) {
0028         /* UTF-16 -> UTF-8 */
0029         ret = utf16s_to_utf8s(name, len, UTF16_LITTLE_ENDIAN, buf,
0030                       buf_len);
0031         buf[ret] = '\0';
0032         return ret;
0033     }
0034 
0035     op = buf;
0036     warn = 0;
0037 
0038     while (len--) {
0039         u16 ec;
0040         int charlen;
0041         char dump[5];
0042 
0043         if (buf_len < NLS_MAX_CHARSET_SIZE) {
0044             ntfs_warn(sbi->sb,
0045                   "filename was truncated while converting.");
0046             break;
0047         }
0048 
0049         ec = le16_to_cpu(*name++);
0050         charlen = nls->uni2char(ec, op, buf_len);
0051 
0052         if (charlen > 0) {
0053             op += charlen;
0054             buf_len -= charlen;
0055             continue;
0056         }
0057 
0058         *op++ = '_';
0059         buf_len -= 1;
0060         if (warn)
0061             continue;
0062 
0063         warn = 1;
0064         hex_byte_pack(&dump[0], ec >> 8);
0065         hex_byte_pack(&dump[2], ec);
0066         dump[4] = 0;
0067 
0068         ntfs_err(sbi->sb, "failed to convert \"%s\" to %s", dump,
0069              nls->charset);
0070     }
0071 
0072     *op = '\0';
0073     return op - buf;
0074 }
0075 
0076 // clang-format off
0077 #define PLANE_SIZE  0x00010000
0078 
0079 #define SURROGATE_PAIR  0x0000d800
0080 #define SURROGATE_LOW   0x00000400
0081 #define SURROGATE_BITS  0x000003ff
0082 // clang-format on
0083 
0084 /*
0085  * put_utf16 - Modified version of put_utf16 from fs/nls/nls_base.c
0086  *
0087  * Function is sparse warnings free.
0088  */
0089 static inline void put_utf16(wchar_t *s, unsigned int c,
0090                  enum utf16_endian endian)
0091 {
0092     static_assert(sizeof(wchar_t) == sizeof(__le16));
0093     static_assert(sizeof(wchar_t) == sizeof(__be16));
0094 
0095     switch (endian) {
0096     default:
0097         *s = (wchar_t)c;
0098         break;
0099     case UTF16_LITTLE_ENDIAN:
0100         *(__le16 *)s = __cpu_to_le16(c);
0101         break;
0102     case UTF16_BIG_ENDIAN:
0103         *(__be16 *)s = __cpu_to_be16(c);
0104         break;
0105     }
0106 }
0107 
0108 /*
0109  * _utf8s_to_utf16s
0110  *
0111  * Modified version of 'utf8s_to_utf16s' allows to
0112  * detect -ENAMETOOLONG without writing out of expected maximum.
0113  */
0114 static int _utf8s_to_utf16s(const u8 *s, int inlen, enum utf16_endian endian,
0115                 wchar_t *pwcs, int maxout)
0116 {
0117     u16 *op;
0118     int size;
0119     unicode_t u;
0120 
0121     op = pwcs;
0122     while (inlen > 0 && *s) {
0123         if (*s & 0x80) {
0124             size = utf8_to_utf32(s, inlen, &u);
0125             if (size < 0)
0126                 return -EINVAL;
0127             s += size;
0128             inlen -= size;
0129 
0130             if (u >= PLANE_SIZE) {
0131                 if (maxout < 2)
0132                     return -ENAMETOOLONG;
0133 
0134                 u -= PLANE_SIZE;
0135                 put_utf16(op++,
0136                       SURROGATE_PAIR |
0137                           ((u >> 10) & SURROGATE_BITS),
0138                       endian);
0139                 put_utf16(op++,
0140                       SURROGATE_PAIR | SURROGATE_LOW |
0141                           (u & SURROGATE_BITS),
0142                       endian);
0143                 maxout -= 2;
0144             } else {
0145                 if (maxout < 1)
0146                     return -ENAMETOOLONG;
0147 
0148                 put_utf16(op++, u, endian);
0149                 maxout--;
0150             }
0151         } else {
0152             if (maxout < 1)
0153                 return -ENAMETOOLONG;
0154 
0155             put_utf16(op++, *s++, endian);
0156             inlen--;
0157             maxout--;
0158         }
0159     }
0160     return op - pwcs;
0161 }
0162 
0163 /*
0164  * ntfs_nls_to_utf16 - Convert input string to UTF-16.
0165  * @name:   Input name.
0166  * @name_len:   Input name length.
0167  * @uni:    Destination memory.
0168  * @max_ulen:   Destination memory.
0169  * @endian: Endian of target UTF-16 string.
0170  *
0171  * This function is called:
0172  * - to create NTFS name
0173  * - to create symlink
0174  *
0175  * Return: UTF-16 string length or error (if negative).
0176  */
0177 int ntfs_nls_to_utf16(struct ntfs_sb_info *sbi, const u8 *name, u32 name_len,
0178               struct cpu_str *uni, u32 max_ulen,
0179               enum utf16_endian endian)
0180 {
0181     int ret, slen;
0182     const u8 *end;
0183     struct nls_table *nls = sbi->options->nls;
0184     u16 *uname = uni->name;
0185 
0186     static_assert(sizeof(wchar_t) == sizeof(u16));
0187 
0188     if (!nls) {
0189         /* utf8 -> utf16 */
0190         ret = _utf8s_to_utf16s(name, name_len, endian, uname, max_ulen);
0191         uni->len = ret;
0192         return ret;
0193     }
0194 
0195     for (ret = 0, end = name + name_len; name < end; ret++, name += slen) {
0196         if (ret >= max_ulen)
0197             return -ENAMETOOLONG;
0198 
0199         slen = nls->char2uni(name, end - name, uname + ret);
0200         if (!slen)
0201             return -EINVAL;
0202         if (slen < 0)
0203             return slen;
0204     }
0205 
0206 #ifdef __BIG_ENDIAN
0207     if (endian == UTF16_LITTLE_ENDIAN) {
0208         int i = ret;
0209 
0210         while (i--) {
0211             __cpu_to_le16s(uname);
0212             uname++;
0213         }
0214     }
0215 #else
0216     if (endian == UTF16_BIG_ENDIAN) {
0217         int i = ret;
0218 
0219         while (i--) {
0220             __cpu_to_be16s(uname);
0221             uname++;
0222         }
0223     }
0224 #endif
0225 
0226     uni->len = ret;
0227     return ret;
0228 }
0229 
0230 /*
0231  * dir_search_u - Helper function.
0232  */
0233 struct inode *dir_search_u(struct inode *dir, const struct cpu_str *uni,
0234                struct ntfs_fnd *fnd)
0235 {
0236     int err = 0;
0237     struct super_block *sb = dir->i_sb;
0238     struct ntfs_sb_info *sbi = sb->s_fs_info;
0239     struct ntfs_inode *ni = ntfs_i(dir);
0240     struct NTFS_DE *e;
0241     int diff;
0242     struct inode *inode = NULL;
0243     struct ntfs_fnd *fnd_a = NULL;
0244 
0245     if (!fnd) {
0246         fnd_a = fnd_get();
0247         if (!fnd_a) {
0248             err = -ENOMEM;
0249             goto out;
0250         }
0251         fnd = fnd_a;
0252     }
0253 
0254     err = indx_find(&ni->dir, ni, NULL, uni, 0, sbi, &diff, &e, fnd);
0255 
0256     if (err)
0257         goto out;
0258 
0259     if (diff) {
0260         err = -ENOENT;
0261         goto out;
0262     }
0263 
0264     inode = ntfs_iget5(sb, &e->ref, uni);
0265     if (!IS_ERR(inode) && is_bad_inode(inode)) {
0266         iput(inode);
0267         err = -EINVAL;
0268     }
0269 out:
0270     fnd_put(fnd_a);
0271 
0272     return err == -ENOENT ? NULL : err ? ERR_PTR(err) : inode;
0273 }
0274 
0275 static inline int ntfs_filldir(struct ntfs_sb_info *sbi, struct ntfs_inode *ni,
0276                    const struct NTFS_DE *e, u8 *name,
0277                    struct dir_context *ctx)
0278 {
0279     const struct ATTR_FILE_NAME *fname;
0280     unsigned long ino;
0281     int name_len;
0282     u32 dt_type;
0283 
0284     fname = Add2Ptr(e, sizeof(struct NTFS_DE));
0285 
0286     if (fname->type == FILE_NAME_DOS)
0287         return 0;
0288 
0289     if (!mi_is_ref(&ni->mi, &fname->home))
0290         return 0;
0291 
0292     ino = ino_get(&e->ref);
0293 
0294     if (ino == MFT_REC_ROOT)
0295         return 0;
0296 
0297     /* Skip meta files. Unless option to show metafiles is set. */
0298     if (!sbi->options->showmeta && ntfs_is_meta_file(sbi, ino))
0299         return 0;
0300 
0301     if (sbi->options->nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN))
0302         return 0;
0303 
0304     name_len = ntfs_utf16_to_nls(sbi, fname->name, fname->name_len, name,
0305                      PATH_MAX);
0306     if (name_len <= 0) {
0307         ntfs_warn(sbi->sb, "failed to convert name for inode %lx.",
0308               ino);
0309         return 0;
0310     }
0311 
0312     dt_type = (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
0313 
0314     return !dir_emit(ctx, (s8 *)name, name_len, ino, dt_type);
0315 }
0316 
0317 /*
0318  * ntfs_read_hdr - Helper function for ntfs_readdir().
0319  */
0320 static int ntfs_read_hdr(struct ntfs_sb_info *sbi, struct ntfs_inode *ni,
0321              const struct INDEX_HDR *hdr, u64 vbo, u64 pos,
0322              u8 *name, struct dir_context *ctx)
0323 {
0324     int err;
0325     const struct NTFS_DE *e;
0326     u32 e_size;
0327     u32 end = le32_to_cpu(hdr->used);
0328     u32 off = le32_to_cpu(hdr->de_off);
0329 
0330     for (;; off += e_size) {
0331         if (off + sizeof(struct NTFS_DE) > end)
0332             return -1;
0333 
0334         e = Add2Ptr(hdr, off);
0335         e_size = le16_to_cpu(e->size);
0336         if (e_size < sizeof(struct NTFS_DE) || off + e_size > end)
0337             return -1;
0338 
0339         if (de_is_last(e))
0340             return 0;
0341 
0342         /* Skip already enumerated. */
0343         if (vbo + off < pos)
0344             continue;
0345 
0346         if (le16_to_cpu(e->key_size) < SIZEOF_ATTRIBUTE_FILENAME)
0347             return -1;
0348 
0349         ctx->pos = vbo + off;
0350 
0351         /* Submit the name to the filldir callback. */
0352         err = ntfs_filldir(sbi, ni, e, name, ctx);
0353         if (err)
0354             return err;
0355     }
0356 }
0357 
0358 /*
0359  * ntfs_readdir - file_operations::iterate_shared
0360  *
0361  * Use non sorted enumeration.
0362  * We have an example of broken volume where sorted enumeration
0363  * counts each name twice.
0364  */
0365 static int ntfs_readdir(struct file *file, struct dir_context *ctx)
0366 {
0367     const struct INDEX_ROOT *root;
0368     u64 vbo;
0369     size_t bit;
0370     loff_t eod;
0371     int err = 0;
0372     struct inode *dir = file_inode(file);
0373     struct ntfs_inode *ni = ntfs_i(dir);
0374     struct super_block *sb = dir->i_sb;
0375     struct ntfs_sb_info *sbi = sb->s_fs_info;
0376     loff_t i_size = i_size_read(dir);
0377     u32 pos = ctx->pos;
0378     u8 *name = NULL;
0379     struct indx_node *node = NULL;
0380     u8 index_bits = ni->dir.index_bits;
0381 
0382     /* Name is a buffer of PATH_MAX length. */
0383     static_assert(NTFS_NAME_LEN * 4 < PATH_MAX);
0384 
0385     eod = i_size + sbi->record_size;
0386 
0387     if (pos >= eod)
0388         return 0;
0389 
0390     if (!dir_emit_dots(file, ctx))
0391         return 0;
0392 
0393     /* Allocate PATH_MAX bytes. */
0394     name = __getname();
0395     if (!name)
0396         return -ENOMEM;
0397 
0398     if (!ni->mi_loaded && ni->attr_list.size) {
0399         /*
0400          * Directory inode is locked for read.
0401          * Load all subrecords to avoid 'write' access to 'ni' during
0402          * directory reading.
0403          */
0404         ni_lock(ni);
0405         if (!ni->mi_loaded && ni->attr_list.size) {
0406             err = ni_load_all_mi(ni);
0407             if (!err)
0408                 ni->mi_loaded = true;
0409         }
0410         ni_unlock(ni);
0411         if (err)
0412             goto out;
0413     }
0414 
0415     root = indx_get_root(&ni->dir, ni, NULL, NULL);
0416     if (!root) {
0417         err = -EINVAL;
0418         goto out;
0419     }
0420 
0421     if (pos >= sbi->record_size) {
0422         bit = (pos - sbi->record_size) >> index_bits;
0423     } else {
0424         err = ntfs_read_hdr(sbi, ni, &root->ihdr, 0, pos, name, ctx);
0425         if (err)
0426             goto out;
0427         bit = 0;
0428     }
0429 
0430     if (!i_size) {
0431         ctx->pos = eod;
0432         goto out;
0433     }
0434 
0435     for (;;) {
0436         vbo = (u64)bit << index_bits;
0437         if (vbo >= i_size) {
0438             ctx->pos = eod;
0439             goto out;
0440         }
0441 
0442         err = indx_used_bit(&ni->dir, ni, &bit);
0443         if (err)
0444             goto out;
0445 
0446         if (bit == MINUS_ONE_T) {
0447             ctx->pos = eod;
0448             goto out;
0449         }
0450 
0451         vbo = (u64)bit << index_bits;
0452         if (vbo >= i_size) {
0453             ntfs_inode_err(dir, "Looks like your dir is corrupt");
0454             err = -EINVAL;
0455             goto out;
0456         }
0457 
0458         err = indx_read(&ni->dir, ni, bit << ni->dir.idx2vbn_bits,
0459                 &node);
0460         if (err)
0461             goto out;
0462 
0463         err = ntfs_read_hdr(sbi, ni, &node->index->ihdr,
0464                     vbo + sbi->record_size, pos, name, ctx);
0465         if (err)
0466             goto out;
0467 
0468         bit += 1;
0469     }
0470 
0471 out:
0472 
0473     __putname(name);
0474     put_indx_node(node);
0475 
0476     if (err == -ENOENT) {
0477         err = 0;
0478         ctx->pos = pos;
0479     }
0480 
0481     return err;
0482 }
0483 
0484 static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
0485               size_t *files)
0486 {
0487     int err = 0;
0488     struct ntfs_inode *ni = ntfs_i(dir);
0489     struct NTFS_DE *e = NULL;
0490     struct INDEX_ROOT *root;
0491     struct INDEX_HDR *hdr;
0492     const struct ATTR_FILE_NAME *fname;
0493     u32 e_size, off, end;
0494     u64 vbo = 0;
0495     size_t drs = 0, fles = 0, bit = 0;
0496     loff_t i_size = ni->vfs_inode.i_size;
0497     struct indx_node *node = NULL;
0498     u8 index_bits = ni->dir.index_bits;
0499 
0500     if (is_empty)
0501         *is_empty = true;
0502 
0503     root = indx_get_root(&ni->dir, ni, NULL, NULL);
0504     if (!root)
0505         return -EINVAL;
0506 
0507     hdr = &root->ihdr;
0508 
0509     for (;;) {
0510         end = le32_to_cpu(hdr->used);
0511         off = le32_to_cpu(hdr->de_off);
0512 
0513         for (; off + sizeof(struct NTFS_DE) <= end; off += e_size) {
0514             e = Add2Ptr(hdr, off);
0515             e_size = le16_to_cpu(e->size);
0516             if (e_size < sizeof(struct NTFS_DE) ||
0517                 off + e_size > end)
0518                 break;
0519 
0520             if (de_is_last(e))
0521                 break;
0522 
0523             fname = de_get_fname(e);
0524             if (!fname)
0525                 continue;
0526 
0527             if (fname->type == FILE_NAME_DOS)
0528                 continue;
0529 
0530             if (is_empty) {
0531                 *is_empty = false;
0532                 if (!dirs && !files)
0533                     goto out;
0534             }
0535 
0536             if (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY)
0537                 drs += 1;
0538             else
0539                 fles += 1;
0540         }
0541 
0542         if (vbo >= i_size)
0543             goto out;
0544 
0545         err = indx_used_bit(&ni->dir, ni, &bit);
0546         if (err)
0547             goto out;
0548 
0549         if (bit == MINUS_ONE_T)
0550             goto out;
0551 
0552         vbo = (u64)bit << index_bits;
0553         if (vbo >= i_size)
0554             goto out;
0555 
0556         err = indx_read(&ni->dir, ni, bit << ni->dir.idx2vbn_bits,
0557                 &node);
0558         if (err)
0559             goto out;
0560 
0561         hdr = &node->index->ihdr;
0562         bit += 1;
0563         vbo = (u64)bit << ni->dir.idx2vbn_bits;
0564     }
0565 
0566 out:
0567     put_indx_node(node);
0568     if (dirs)
0569         *dirs = drs;
0570     if (files)
0571         *files = fles;
0572 
0573     return err;
0574 }
0575 
0576 bool dir_is_empty(struct inode *dir)
0577 {
0578     bool is_empty = false;
0579 
0580     ntfs_dir_count(dir, &is_empty, NULL, NULL);
0581 
0582     return is_empty;
0583 }
0584 
0585 // clang-format off
0586 const struct file_operations ntfs_dir_operations = {
0587     .llseek     = generic_file_llseek,
0588     .read       = generic_read_dir,
0589     .iterate_shared = ntfs_readdir,
0590     .fsync      = generic_file_fsync,
0591     .open       = ntfs_file_open,
0592 };
0593 // clang-format on