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