blob: 2c372f4e27a973316db052fc61b14cd8102c47c7 [file] [log] [blame]
Mike Frysinger1fd98e02005-05-09 22:10:42 +00001/*
2 * namei.c --- ext2fs directory lookup operations
Tim Rikerc1ef7bd2006-01-25 00:08:53 +00003 *
Mike Frysinger1fd98e02005-05-09 22:10:42 +00004 * 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
23static 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
27static 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);
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000039
Mike Frysinger1fd98e02005-05-09 22:10:42 +000040#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);
Rob Landleye7c43b62006-03-01 16:39:45 +000064 ext2fs_free_mem(&buffer);
Mike Frysinger1fd98e02005-05-09 22:10:42 +000065 return retval;
66}
67
68/*
69 * This routine interprets a pathname in the context of the current
70 * directory and the root directory, and returns the inode of the
71 * containing directory, and a pointer to the filename of the file
72 * (pointing into the pathname) and the length of the filename.
73 */
74static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
75 const char *pathname, int pathlen,
76 int link_count, char *buf,
77 const char **name, int *namelen,
78 ext2_ino_t *res_inode)
79{
80 char c;
81 const char *thisname;
82 int len;
83 ext2_ino_t inode;
84 errcode_t retval;
85
86 if ((c = *pathname) == '/') {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000087 dir = root;
Mike Frysinger1fd98e02005-05-09 22:10:42 +000088 pathname++;
89 pathlen--;
90 }
91 while (1) {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000092 thisname = pathname;
Mike Frysinger1fd98e02005-05-09 22:10:42 +000093 for (len=0; --pathlen >= 0;len++) {
94 c = *(pathname++);
95 if (c == '/')
96 break;
97 }
98 if (pathlen < 0)
99 break;
100 retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode);
101 if (retval) return retval;
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000102 retval = follow_link (fs, root, dir, inode,
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000103 link_count, buf, &dir);
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000104 if (retval) return retval;
105 }
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000106 *name = thisname;
107 *namelen = len;
108 *res_inode = dir;
109 return 0;
110}
111
112static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
113 const char *pathname, size_t pathlen, int follow,
114 int link_count, char *buf, ext2_ino_t *res_inode)
115{
116 const char *basename;
117 int namelen;
118 ext2_ino_t dir, inode;
119 errcode_t retval;
120
121#ifdef NAMEI_DEBUG
122 printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n",
123 root, base, pathlen, pathname, link_count);
124#endif
125 retval = dir_namei(fs, root, base, pathname, pathlen,
126 link_count, buf, &basename, &namelen, &dir);
127 if (retval) return retval;
128 if (!namelen) { /* special case: '/usr/' etc */
129 *res_inode=dir;
130 return 0;
131 }
132 retval = ext2fs_lookup (fs, dir, basename, namelen, buf, &inode);
133 if (retval)
134 return retval;
135 if (follow) {
136 retval = follow_link(fs, root, dir, inode, link_count,
137 buf, &inode);
138 if (retval)
139 return retval;
140 }
141#ifdef NAMEI_DEBUG
142 printf("open_namei: (link_count=%d) returns %lu\n",
143 link_count, inode);
144#endif
145 *res_inode = inode;
146 return 0;
147}
148
149errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
150 const char *name, ext2_ino_t *inode)
151{
152 char *buf;
153 errcode_t retval;
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000154
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000155 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
156
157 retval = ext2fs_get_mem(fs->blocksize, &buf);
158 if (retval)
159 return retval;
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000160
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000161 retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
162 buf, inode);
163
164 ext2fs_free_mem(&buf);
165 return retval;
166}
167
168errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
169 const char *name, ext2_ino_t *inode)
170{
171 char *buf;
172 errcode_t retval;
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000173
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000174 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
175
176 retval = ext2fs_get_mem(fs->blocksize, &buf);
177 if (retval)
178 return retval;
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000179
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000180 retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
181 buf, inode);
182
183 ext2fs_free_mem(&buf);
184 return retval;
185}
186
187errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
188 ext2_ino_t inode, ext2_ino_t *res_inode)
189{
190 char *buf;
191 errcode_t retval;
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000192
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000193 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
194
195 retval = ext2fs_get_mem(fs->blocksize, &buf);
196 if (retval)
197 return retval;
198
199 retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
200
201 ext2fs_free_mem(&buf);
202 return retval;
203}
204