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