blob: dd710b89ba603f9b57aefd2b31c22040463d0999 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * namei.c --- ext2fs directory lookup operations
Theodore Ts'oefc6f622008-08-27 23:07:54 -04003 *
Theodore Ts'o19c78dc1997-04-29 16:17:09 +00004 * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
5 *
6 * %Begin-Header%
Theodore Ts'o543547a2010-05-17 21:31:56 -04007 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
Theodore Ts'o19c78dc1997-04-29 16:17:09 +00009 * %End-Header%
Theodore Ts'o3839e651997-04-26 13:21:57 +000010 */
11
12#include <stdio.h>
13#include <string.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000014#if HAVE_UNISTD_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000015#include <unistd.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000016#endif
Theodore Ts'of3db3561997-04-26 13:34:30 +000017
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000018/* #define NAMEI_DEBUG */
19
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000020#include "ext2_fs.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000021#include "ext2fs.h"
JP Abgralle0ed7402014-03-19 19:08:39 -070022#include "ext2fsP.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000023
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000024static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
Theodore Ts'o3cb6c501997-08-11 20:29:22 +000025 const char *pathname, size_t pathlen, int follow,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000026 int link_count, char *buf, ext2_ino_t *res_inode);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000027
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000028static 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)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000031{
32 char *pathname;
33 char *buffer = 0;
34 errcode_t retval;
35 struct ext2_inode ei;
JP Abgralle0ed7402014-03-19 19:08:39 -070036 blk64_t blk;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000037
38#ifdef NAMEI_DEBUG
39 printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
40 root, dir, inode, link_count);
Theodore Ts'oefc6f622008-08-27 23:07:54 -040041
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000042#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 }
JP Abgralle0ed7402014-03-19 19:08:39 -070049 if (link_count++ >= EXT2FS_MAX_NESTED_LINKS)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000050 return EXT2_ET_SYMLINK_LOOP;
JP Abgralle0ed7402014-03-19 19:08:39 -070051
Theodore Ts'o795afc42004-02-21 20:54:31 -050052 if (ext2fs_inode_data_blocks(fs,&ei)) {
JP Abgralle0ed7402014-03-19 19:08:39 -070053 retval = ext2fs_bmap2(fs, inode, &ei, NULL, 0, 0, NULL, &blk);
54 if (retval)
55 return retval;
56
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -040057 retval = ext2fs_get_mem(fs->blocksize, &buffer);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000058 if (retval)
59 return retval;
JP Abgralle0ed7402014-03-19 19:08:39 -070060
61 retval = io_channel_read_blk64(fs->io, blk, 1, buffer);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000062 if (retval) {
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -040063 ext2fs_free_mem(&buffer);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000064 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)
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -040072 ext2fs_free_mem(&buffer);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000073 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 */
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000082static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000083 const char *pathname, int pathlen,
84 int link_count, char *buf,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000085 const char **name, int *namelen,
86 ext2_ino_t *res_inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000087{
88 char c;
89 const char *thisname;
90 int len;
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000091 ext2_ino_t inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000092 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
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000120static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000121 const char *pathname, size_t pathlen, int follow,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000122 int link_count, char *buf, ext2_ino_t *res_inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000123{
Theodore Ts'odec5cd12006-11-14 23:14:12 -0500124 const char *base_name;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000125 int namelen;
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000126 ext2_ino_t dir, inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000127 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,
Theodore Ts'odec5cd12006-11-14 23:14:12 -0500134 link_count, buf, &base_name, &namelen, &dir);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000135 if (retval) return retval;
136 if (!namelen) { /* special case: '/usr/' etc */
137 *res_inode=dir;
138 return 0;
139 }
Theodore Ts'odec5cd12006-11-14 23:14:12 -0500140 retval = ext2fs_lookup (fs, dir, base_name, namelen, buf, &inode);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000141 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
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000157errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
158 const char *name, ext2_ino_t *inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000159{
160 char *buf;
161 errcode_t retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400162
Theodore Ts'of3db3561997-04-26 13:34:30 +0000163 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
164
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400165 retval = ext2fs_get_mem(fs->blocksize, &buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000166 if (retval)
167 return retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400168
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000169 retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
170 buf, inode);
171
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400172 ext2fs_free_mem(&buf);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000173 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000174}
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000175
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000176errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
177 const char *name, ext2_ino_t *inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000178{
179 char *buf;
180 errcode_t retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400181
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000182 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
183
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400184 retval = ext2fs_get_mem(fs->blocksize, &buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000185 if (retval)
186 return retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400187
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000188 retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
189 buf, inode);
190
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400191 ext2fs_free_mem(&buf);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000192 return retval;
193}
194
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000195errcode_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)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000197{
198 char *buf;
199 errcode_t retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400200
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000201 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
202
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400203 retval = ext2fs_get_mem(fs->blocksize, &buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000204 if (retval)
205 return retval;
206
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000207 retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
208
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400209 ext2fs_free_mem(&buf);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000210 return retval;
211}
212