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