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
24 static 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
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)28 static 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 */
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)82 static 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
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)120 static 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
ext2fs_namei(ext2_filsys fs,ext2_ino_t root,ext2_ino_t cwd,const char * name,ext2_ino_t * inode)157 errcode_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
ext2fs_namei_follow(ext2_filsys fs,ext2_ino_t root,ext2_ino_t cwd,const char * name,ext2_ino_t * inode)176 errcode_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
ext2fs_follow_link(ext2_filsys fs,ext2_ino_t root,ext2_ino_t cwd,ext2_ino_t inode,ext2_ino_t * res_inode)195 errcode_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