blob: 18244613c6d735f8e5650e8a4f1c995b232d7033
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * namei.c --- ext2fs directory lookup operations |
4 | * |
5 | * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o. |
6 | * |
7 | * %Begin-Header% |
8 | * This file may be redistributed under the terms of the GNU Public |
9 | * License. |
10 | * %End-Header% |
11 | */ |
12 | |
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 | |
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 | |
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 = NULL; |
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 | if (ext2fs_inode_data_blocks(fs, &ei)) { |
52 | retval = ext2fs_get_mem(fs->blocksize, &buffer); |
53 | if (retval) |
54 | return retval; |
55 | retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer); |
56 | if (retval) { |
57 | ext2fs_free_mem(&buffer); |
58 | return retval; |
59 | } |
60 | pathname = buffer; |
61 | } else |
62 | pathname = (char *)&(ei.i_block[0]); |
63 | retval = open_namei(fs, root, dir, pathname, ei.i_size, 1, |
64 | link_count, buf, res_inode); |
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 | */ |
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 | |
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 *basename; |
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, &basename, &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, basename, 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 | |
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 | |
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 | |
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 |