namei.c revision 18a1444b4f1e6a0948fd38fa0de382d86cfe04de
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
24static 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
28static 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 */
82static 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
120static 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
157errcode_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
176errcode_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
195errcode_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