Whamcloud - gitweb
Fix byte swapping bug in get_next_inode_full()
[tools/e2fsprogs.git] / lib / ext2fs / namei.c
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
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  */
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 *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
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