Merge tag 'xilinx-for-v2022.07-rc1' of https://source.denx.de/u-boot/custodians/u...
[platform/kernel/u-boot.git] / fs / erofs / namei.c
1 // SPDX-License-Identifier: GPL-2.0+
2 #include "internal.h"
3
4 int 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;
119 bogusimode:
120         erofs_err("bogus i_mode (%o) @ nid %llu", vi->i_mode, vi->nid | 0ULL);
121         return -EFSCORRUPTED;
122 }
123
124 struct 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
161 struct nameidata {
162         erofs_nid_t     nid;
163         unsigned int    ftype;
164 };
165
166 int 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
212 static 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
241 int 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 }