1 /*
2  * namei.c --- ext2fs directory lookup operations
3  *
4  * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Library
8  * General Public License, version 2.
9  * %End-Header%
10  */
11 
12 #include <stdio.h>
13 #include <string.h>
14 #if HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 
18 /* #define NAMEI_DEBUG */
19 
20 #include "ext2_fs.h"
21 #include "ext2fs.h"
22 #include "ext2fsP.h"
23 
24 static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
25 			    const char *pathname, size_t pathlen, int follow,
26 			    int link_count, char *buf, ext2_ino_t *res_inode);
27 
follow_link(ext2_filsys fs,ext2_ino_t root,ext2_ino_t dir,ext2_ino_t inode,int link_count,char * buf,ext2_ino_t * res_inode)28 static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
29 			     ext2_ino_t inode, int link_count,
30 			     char *buf, ext2_ino_t *res_inode)
31 {
32 	char *pathname;
33 	char *buffer = 0;
34 	errcode_t retval;
35 	struct ext2_inode ei;
36 	blk64_t blk;
37 
38 #ifdef NAMEI_DEBUG
39 	printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
40 	       root, dir, inode, link_count);
41 
42 #endif
43 	retval = ext2fs_read_inode (fs, inode, &ei);
44 	if (retval) return retval;
45 	if (!LINUX_S_ISLNK (ei.i_mode)) {
46 		*res_inode = inode;
47 		return 0;
48 	}
49 	if (link_count++ >= EXT2FS_MAX_NESTED_LINKS)
50 		return EXT2_ET_SYMLINK_LOOP;
51 
52 	if (ext2fs_inode_data_blocks(fs,&ei)) {
53 		retval = ext2fs_bmap2(fs, inode, &ei, NULL, 0, 0, NULL, &blk);
54 		if (retval)
55 			return retval;
56 
57 		retval = ext2fs_get_mem(fs->blocksize, &buffer);
58 		if (retval)
59 			return retval;
60 
61 		retval = io_channel_read_blk64(fs->io, blk, 1, buffer);
62 		if (retval) {
63 			ext2fs_free_mem(&buffer);
64 			return retval;
65 		}
66 		pathname = buffer;
67 	} else
68 		pathname = (char *)&(ei.i_block[0]);
69 	retval = open_namei(fs, root, dir, pathname, ei.i_size, 1,
70 			    link_count, buf, res_inode);
71 	if (buffer)
72 		ext2fs_free_mem(&buffer);
73 	return retval;
74 }
75 
76 /*
77  * This routine interprets a pathname in the context of the current
78  * directory and the root directory, and returns the inode of the
79  * containing directory, and a pointer to the filename of the file
80  * (pointing into the pathname) and the length of the filename.
81  */
dir_namei(ext2_filsys fs,ext2_ino_t root,ext2_ino_t dir,const char * pathname,int pathlen,int link_count,char * buf,const char ** name,int * namelen,ext2_ino_t * res_inode)82 static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
83 			   const char *pathname, int pathlen,
84 			   int link_count, char *buf,
85 			   const char **name, int *namelen,
86 			   ext2_ino_t *res_inode)
87 {
88 	char c;
89 	const char *thisname;
90 	int len;
91 	ext2_ino_t inode;
92 	errcode_t retval;
93 
94 	if ((c = *pathname) == '/') {
95         	dir = root;
96 		pathname++;
97 		pathlen--;
98 	}
99 	while (1) {
100         	thisname = pathname;
101 		for (len=0; --pathlen >= 0;len++) {
102 			c = *(pathname++);
103 			if (c == '/')
104 				break;
105 		}
106 		if (pathlen < 0)
107 			break;
108 		retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode);
109 		if (retval) return retval;
110         	retval = follow_link (fs, root, dir, inode,
111 				      link_count, buf, &dir);
112         	if (retval) return retval;
113     	}
114 	*name = thisname;
115 	*namelen = len;
116 	*res_inode = dir;
117 	return 0;
118 }
119 
open_namei(ext2_filsys fs,ext2_ino_t root,ext2_ino_t base,const char * pathname,size_t pathlen,int follow,int link_count,char * buf,ext2_ino_t * res_inode)120 static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
121 			    const char *pathname, size_t pathlen, int follow,
122 			    int link_count, char *buf, ext2_ino_t *res_inode)
123 {
124 	const char *base_name;
125 	int namelen;
126 	ext2_ino_t dir, inode;
127 	errcode_t retval;
128 
129 #ifdef NAMEI_DEBUG
130 	printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n",
131 	       root, base, pathlen, pathname, link_count);
132 #endif
133 	retval = dir_namei(fs, root, base, pathname, pathlen,
134 			   link_count, buf, &base_name, &namelen, &dir);
135 	if (retval) return retval;
136 	if (!namelen) {                     /* special case: '/usr/' etc */
137 		*res_inode=dir;
138 		return 0;
139 	}
140 	retval = ext2fs_lookup (fs, dir, base_name, namelen, buf, &inode);
141 	if (retval)
142 		return retval;
143 	if (follow) {
144 		retval = follow_link(fs, root, dir, inode, link_count,
145 				     buf, &inode);
146 		if (retval)
147 			return retval;
148 	}
149 #ifdef NAMEI_DEBUG
150 	printf("open_namei: (link_count=%d) returns %lu\n",
151 	       link_count, inode);
152 #endif
153 	*res_inode = inode;
154 	return 0;
155 }
156 
ext2fs_namei(ext2_filsys fs,ext2_ino_t root,ext2_ino_t cwd,const char * name,ext2_ino_t * inode)157 errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
158 		       const char *name, ext2_ino_t *inode)
159 {
160 	char *buf;
161 	errcode_t retval;
162 
163 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
164 
165 	retval = ext2fs_get_mem(fs->blocksize, &buf);
166 	if (retval)
167 		return retval;
168 
169 	retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
170 			    buf, inode);
171 
172 	ext2fs_free_mem(&buf);
173 	return retval;
174 }
175 
ext2fs_namei_follow(ext2_filsys fs,ext2_ino_t root,ext2_ino_t cwd,const char * name,ext2_ino_t * inode)176 errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
177 			      const char *name, ext2_ino_t *inode)
178 {
179 	char *buf;
180 	errcode_t retval;
181 
182 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
183 
184 	retval = ext2fs_get_mem(fs->blocksize, &buf);
185 	if (retval)
186 		return retval;
187 
188 	retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
189 			    buf, inode);
190 
191 	ext2fs_free_mem(&buf);
192 	return retval;
193 }
194 
ext2fs_follow_link(ext2_filsys fs,ext2_ino_t root,ext2_ino_t cwd,ext2_ino_t inode,ext2_ino_t * res_inode)195 errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
196 			ext2_ino_t inode, ext2_ino_t *res_inode)
197 {
198 	char *buf;
199 	errcode_t retval;
200 
201 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
202 
203 	retval = ext2fs_get_mem(fs->blocksize, &buf);
204 	if (retval)
205 		return retval;
206 
207 	retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
208 
209 	ext2fs_free_mem(&buf);
210 	return retval;
211 }
212 
213