Whamcloud - gitweb
libext2fs: allocate clusters to files in expand_dir.c and mkjournal.c
[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 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
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         /* FIXME-64: Actually, this is FIXME EXTENTS */
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         if (buffer)
66                 ext2fs_free_mem(&buffer);
67         return retval;
68 }
69
70 /*
71  * This routine interprets a pathname in the context of the current
72  * directory and the root directory, and returns the inode of the
73  * containing directory, and a pointer to the filename of the file
74  * (pointing into the pathname) and the length of the filename.
75  */
76 static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
77                            const char *pathname, int pathlen,
78                            int link_count, char *buf,
79                            const char **name, int *namelen,
80                            ext2_ino_t *res_inode)
81 {
82         char c;
83         const char *thisname;
84         int len;
85         ext2_ino_t inode;
86         errcode_t retval;
87
88         if ((c = *pathname) == '/') {
89                 dir = root;
90                 pathname++;
91                 pathlen--;
92         }
93         while (1) {
94                 thisname = pathname;
95                 for (len=0; --pathlen >= 0;len++) {
96                         c = *(pathname++);
97                         if (c == '/')
98                                 break;
99                 }
100                 if (pathlen < 0)
101                         break;
102                 retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode);
103                 if (retval) return retval;
104                 retval = follow_link (fs, root, dir, inode,
105                                       link_count, buf, &dir);
106                 if (retval) return retval;
107         }
108         *name = thisname;
109         *namelen = len;
110         *res_inode = dir;
111         return 0;
112 }
113
114 static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
115                             const char *pathname, size_t pathlen, int follow,
116                             int link_count, char *buf, ext2_ino_t *res_inode)
117 {
118         const char *base_name;
119         int namelen;
120         ext2_ino_t dir, inode;
121         errcode_t retval;
122
123 #ifdef NAMEI_DEBUG
124         printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n",
125                root, base, pathlen, pathname, link_count);
126 #endif
127         retval = dir_namei(fs, root, base, pathname, pathlen,
128                            link_count, buf, &base_name, &namelen, &dir);
129         if (retval) return retval;
130         if (!namelen) {                     /* special case: '/usr/' etc */
131                 *res_inode=dir;
132                 return 0;
133         }
134         retval = ext2fs_lookup (fs, dir, base_name, namelen, buf, &inode);
135         if (retval)
136                 return retval;
137         if (follow) {
138                 retval = follow_link(fs, root, dir, inode, link_count,
139                                      buf, &inode);
140                 if (retval)
141                         return retval;
142         }
143 #ifdef NAMEI_DEBUG
144         printf("open_namei: (link_count=%d) returns %lu\n",
145                link_count, inode);
146 #endif
147         *res_inode = inode;
148         return 0;
149 }
150
151 errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
152                        const char *name, ext2_ino_t *inode)
153 {
154         char *buf;
155         errcode_t retval;
156
157         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
158
159         retval = ext2fs_get_mem(fs->blocksize, &buf);
160         if (retval)
161                 return retval;
162
163         retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
164                             buf, inode);
165
166         ext2fs_free_mem(&buf);
167         return retval;
168 }
169
170 errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
171                               const char *name, ext2_ino_t *inode)
172 {
173         char *buf;
174         errcode_t retval;
175
176         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
177
178         retval = ext2fs_get_mem(fs->blocksize, &buf);
179         if (retval)
180                 return retval;
181
182         retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
183                             buf, inode);
184
185         ext2fs_free_mem(&buf);
186         return retval;
187 }
188
189 errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
190                         ext2_ino_t inode, ext2_ino_t *res_inode)
191 {
192         char *buf;
193         errcode_t retval;
194
195         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
196
197         retval = ext2fs_get_mem(fs->blocksize, &buf);
198         if (retval)
199                 return retval;
200
201         retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
202
203         ext2fs_free_mem(&buf);
204         return retval;
205 }
206