uboot/fs/erofs/namei.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2#include "internal.h"
   3
   4int erofs_read_inode_from_disk(struct erofs_inode *vi)
   5{
   6        int ret, ifmt;
   7        char buf[sizeof(struct erofs_inode_extended)];
   8        struct erofs_inode_compact *dic;
   9        struct erofs_inode_extended *die;
  10        const erofs_off_t inode_loc = iloc(vi->nid);
  11
  12        ret = erofs_dev_read(0, buf, inode_loc, sizeof(*dic));
  13        if (ret < 0)
  14                return -EIO;
  15
  16        dic = (struct erofs_inode_compact *)buf;
  17        ifmt = le16_to_cpu(dic->i_format);
  18
  19        vi->datalayout = erofs_inode_datalayout(ifmt);
  20        if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) {
  21                erofs_err("unsupported datalayout %u of nid %llu",
  22                          vi->datalayout, vi->nid | 0ULL);
  23                return -EOPNOTSUPP;
  24        }
  25        switch (erofs_inode_version(ifmt)) {
  26        case EROFS_INODE_LAYOUT_EXTENDED:
  27                vi->inode_isize = sizeof(struct erofs_inode_extended);
  28
  29                ret = erofs_dev_read(0, buf + sizeof(*dic), inode_loc + sizeof(*dic),
  30                                     sizeof(*die) - sizeof(*dic));
  31                if (ret < 0)
  32                        return -EIO;
  33
  34                die = (struct erofs_inode_extended *)buf;
  35                vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount);
  36                vi->i_mode = le16_to_cpu(die->i_mode);
  37
  38                switch (vi->i_mode & S_IFMT) {
  39                case S_IFREG:
  40                case S_IFDIR:
  41                case S_IFLNK:
  42                        vi->u.i_blkaddr = le32_to_cpu(die->i_u.raw_blkaddr);
  43                        break;
  44                case S_IFCHR:
  45                case S_IFBLK:
  46                        vi->u.i_rdev = 0;
  47                        break;
  48                case S_IFIFO:
  49                case S_IFSOCK:
  50                        vi->u.i_rdev = 0;
  51                        break;
  52                default:
  53                        goto bogusimode;
  54                }
  55
  56                vi->i_uid = le32_to_cpu(die->i_uid);
  57                vi->i_gid = le32_to_cpu(die->i_gid);
  58                vi->i_nlink = le32_to_cpu(die->i_nlink);
  59
  60                vi->i_ctime = le64_to_cpu(die->i_ctime);
  61                vi->i_ctime_nsec = le64_to_cpu(die->i_ctime_nsec);
  62                vi->i_size = le64_to_cpu(die->i_size);
  63                if (vi->datalayout == EROFS_INODE_CHUNK_BASED)
  64                        /* fill chunked inode summary info */
  65                        vi->u.chunkformat = le16_to_cpu(die->i_u.c.format);
  66                break;
  67        case EROFS_INODE_LAYOUT_COMPACT:
  68                vi->inode_isize = sizeof(struct erofs_inode_compact);
  69                vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount);
  70                vi->i_mode = le16_to_cpu(dic->i_mode);
  71
  72                switch (vi->i_mode & S_IFMT) {
  73                case S_IFREG:
  74                case S_IFDIR:
  75                case S_IFLNK:
  76                        vi->u.i_blkaddr = le32_to_cpu(dic->i_u.raw_blkaddr);
  77                        break;
  78                case S_IFCHR:
  79                case S_IFBLK:
  80                        vi->u.i_rdev = 0;
  81                        break;
  82                case S_IFIFO:
  83                case S_IFSOCK:
  84                        vi->u.i_rdev = 0;
  85                        break;
  86                default:
  87                        goto bogusimode;
  88                }
  89
  90                vi->i_uid = le16_to_cpu(dic->i_uid);
  91                vi->i_gid = le16_to_cpu(dic->i_gid);
  92                vi->i_nlink = le16_to_cpu(dic->i_nlink);
  93
  94                vi->i_ctime = sbi.build_time;
  95                vi->i_ctime_nsec = sbi.build_time_nsec;
  96
  97                vi->i_size = le32_to_cpu(dic->i_size);
  98                if (vi->datalayout == EROFS_INODE_CHUNK_BASED)
  99                        vi->u.chunkformat = le16_to_cpu(dic->i_u.c.format);
 100                break;
 101        default:
 102                erofs_err("unsupported on-disk inode version %u of nid %llu",
 103                          erofs_inode_version(ifmt), vi->nid | 0ULL);
 104                return -EOPNOTSUPP;
 105        }
 106
 107        vi->flags = 0;
 108        if (vi->datalayout == EROFS_INODE_CHUNK_BASED) {
 109                if (vi->u.chunkformat & ~EROFS_CHUNK_FORMAT_ALL) {
 110                        erofs_err("unsupported chunk format %x of nid %llu",
 111                                  vi->u.chunkformat, vi->nid | 0ULL);
 112                        return -EOPNOTSUPP;
 113                }
 114                vi->u.chunkbits = LOG_BLOCK_SIZE +
 115                        (vi->u.chunkformat & EROFS_CHUNK_FORMAT_BLKBITS_MASK);
 116        } else if (erofs_inode_is_data_compressed(vi->datalayout))
 117                z_erofs_fill_inode(vi);
 118        return 0;
 119bogusimode:
 120        erofs_err("bogus i_mode (%o) @ nid %llu", vi->i_mode, vi->nid | 0ULL);
 121        return -EFSCORRUPTED;
 122}
 123
 124struct erofs_dirent *find_target_dirent(erofs_nid_t pnid,
 125                                        void *dentry_blk,
 126                                        const char *name, unsigned int len,
 127                                        unsigned int nameoff,
 128                                        unsigned int maxsize)
 129{
 130        struct erofs_dirent *de = dentry_blk;
 131        const struct erofs_dirent *end = dentry_blk + nameoff;
 132
 133        while (de < end) {
 134                const char *de_name;
 135                unsigned int de_namelen;
 136
 137                nameoff = le16_to_cpu(de->nameoff);
 138                de_name = (char *)dentry_blk + nameoff;
 139
 140                /* the last dirent in the block? */
 141                if (de + 1 >= end)
 142                        de_namelen = strnlen(de_name, maxsize - nameoff);
 143                else
 144                        de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
 145
 146                /* a corrupted entry is found */
 147                if (nameoff + de_namelen > maxsize ||
 148                    de_namelen > EROFS_NAME_LEN) {
 149                        erofs_err("bogus dirent @ nid %llu", pnid | 0ULL);
 150                        DBG_BUGON(1);
 151                        return ERR_PTR(-EFSCORRUPTED);
 152                }
 153
 154                if (len == de_namelen && !memcmp(de_name, name, de_namelen))
 155                        return de;
 156                ++de;
 157        }
 158        return NULL;
 159}
 160
 161struct nameidata {
 162        erofs_nid_t     nid;
 163        unsigned int    ftype;
 164};
 165
 166int erofs_namei(struct nameidata *nd,
 167                const char *name, unsigned int len)
 168{
 169        erofs_nid_t nid = nd->nid;
 170        int ret;
 171        char buf[EROFS_BLKSIZ];
 172        struct erofs_inode vi = { .nid = nid };
 173        erofs_off_t offset;
 174
 175        ret = erofs_read_inode_from_disk(&vi);
 176        if (ret)
 177                return ret;
 178
 179        offset = 0;
 180        while (offset < vi.i_size) {
 181                erofs_off_t maxsize = min_t(erofs_off_t,
 182                                            vi.i_size - offset, EROFS_BLKSIZ);
 183                struct erofs_dirent *de = (void *)buf;
 184                unsigned int nameoff;
 185
 186                ret = erofs_pread(&vi, buf, maxsize, offset);
 187                if (ret)
 188                        return ret;
 189
 190                nameoff = le16_to_cpu(de->nameoff);
 191                if (nameoff < sizeof(struct erofs_dirent) ||
 192                    nameoff >= PAGE_SIZE) {
 193                        erofs_err("invalid de[0].nameoff %u @ nid %llu",
 194                                  nameoff, nid | 0ULL);
 195                        return -EFSCORRUPTED;
 196                }
 197
 198                de = find_target_dirent(nid, buf, name, len,
 199                                        nameoff, maxsize);
 200                if (IS_ERR(de))
 201                        return PTR_ERR(de);
 202
 203                if (de) {
 204                        nd->nid = le64_to_cpu(de->nid);
 205                        return 0;
 206                }
 207                offset += maxsize;
 208        }
 209        return -ENOENT;
 210}
 211
 212static int link_path_walk(const char *name, struct nameidata *nd)
 213{
 214        nd->nid = sbi.root_nid;
 215
 216        while (*name == '/')
 217                name++;
 218
 219        /* At this point we know we have a real path component. */
 220        while (*name != '\0') {
 221                const char *p = name;
 222                int ret;
 223
 224                do {
 225                        ++p;
 226                } while (*p != '\0' && *p != '/');
 227
 228                DBG_BUGON(p <= name);
 229                ret = erofs_namei(nd, name, p - name);
 230                if (ret)
 231                        return ret;
 232
 233                name = p;
 234                /* Skip until no more slashes. */
 235                for (name = p; *name == '/'; ++name)
 236                        ;
 237        }
 238        return 0;
 239}
 240
 241int erofs_ilookup(const char *path, struct erofs_inode *vi)
 242{
 243        int ret;
 244        struct nameidata nd;
 245
 246        ret = link_path_walk(path, &nd);
 247        if (ret)
 248                return ret;
 249
 250        vi->nid = nd.nid;
 251        return erofs_read_inode_from_disk(vi);
 252}
 253