xref: /aosp_15_r20/external/erofs-utils/lib/namei.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
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