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