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