blob: efcc02b7e663a4bd02c85b9128184f04351c6109 [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
Theodore Ts'od1154eb2011-09-18 17:34:37 -040012#include "config.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000013#include <stdio.h>
14#include <string.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000015#if HAVE_UNISTD_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000016#include <unistd.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000017#endif
Theodore Ts'of3db3561997-04-26 13:34:30 +000018
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000019/* #define NAMEI_DEBUG */
20
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000021#include "ext2_fs.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000022#include "ext2fs.h"
Niu Yawei08ae93a2011-11-19 23:08:03 -050023#include "ext2fsP.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000024
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000025static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
Theodore Ts'o3cb6c501997-08-11 20:29:22 +000026 const char *pathname, size_t pathlen, int follow,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000027 int link_count, char *buf, ext2_ino_t *res_inode);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000028
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000029static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
30 ext2_ino_t inode, int link_count,
31 char *buf, ext2_ino_t *res_inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000032{
33 char *pathname;
34 char *buffer = 0;
35 errcode_t retval;
36 struct ext2_inode ei;
37
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 }
Niu Yawei08ae93a2011-11-19 23:08:03 -050049 if (link_count++ >= EXT2FS_MAX_NESTED_LINKS)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000050 return EXT2_ET_SYMLINK_LOOP;
Niu Yawei08ae93a2011-11-19 23:08:03 -050051
Valerie Aurora Henson6d8b37f2010-06-13 11:00:00 -040052 /* FIXME-64: Actually, this is FIXME EXTENTS */
Theodore Ts'o795afc42004-02-21 20:54:31 -050053 if (ext2fs_inode_data_blocks(fs,&ei)) {
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -040054 retval = ext2fs_get_mem(fs->blocksize, &buffer);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000055 if (retval)
56 return retval;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000057 retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer);
58 if (retval) {
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -040059 ext2fs_free_mem(&buffer);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000060 return retval;
61 }
62 pathname = buffer;
63 } else
64 pathname = (char *)&(ei.i_block[0]);
65 retval = open_namei(fs, root, dir, pathname, ei.i_size, 1,
66 link_count, buf, res_inode);
67 if (buffer)
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -040068 ext2fs_free_mem(&buffer);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000069 return retval;
70}
71
72/*
73 * This routine interprets a pathname in the context of the current
74 * directory and the root directory, and returns the inode of the
75 * containing directory, and a pointer to the filename of the file
76 * (pointing into the pathname) and the length of the filename.
77 */
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000078static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000079 const char *pathname, int pathlen,
80 int link_count, char *buf,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000081 const char **name, int *namelen,
82 ext2_ino_t *res_inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000083{
84 char c;
85 const char *thisname;
86 int len;
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000087 ext2_ino_t inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000088 errcode_t retval;
89
90 if ((c = *pathname) == '/') {
91 dir = root;
92 pathname++;
93 pathlen--;
94 }
95 while (1) {
96 thisname = pathname;
97 for (len=0; --pathlen >= 0;len++) {
98 c = *(pathname++);
99 if (c == '/')
100 break;
101 }
102 if (pathlen < 0)
103 break;
104 retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode);
105 if (retval) return retval;
106 retval = follow_link (fs, root, dir, inode,
107 link_count, buf, &dir);
108 if (retval) return retval;
109 }
110 *name = thisname;
111 *namelen = len;
112 *res_inode = dir;
113 return 0;
114}
115
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000116static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000117 const char *pathname, size_t pathlen, int follow,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000118 int link_count, char *buf, ext2_ino_t *res_inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000119{
Theodore Ts'odec5cd12006-11-14 23:14:12 -0500120 const char *base_name;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000121 int namelen;
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000122 ext2_ino_t dir, inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000123 errcode_t retval;
124
125#ifdef NAMEI_DEBUG
126 printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n",
127 root, base, pathlen, pathname, link_count);
128#endif
129 retval = dir_namei(fs, root, base, pathname, pathlen,
Theodore Ts'odec5cd12006-11-14 23:14:12 -0500130 link_count, buf, &base_name, &namelen, &dir);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000131 if (retval) return retval;
132 if (!namelen) { /* special case: '/usr/' etc */
133 *res_inode=dir;
134 return 0;
135 }
Theodore Ts'odec5cd12006-11-14 23:14:12 -0500136 retval = ext2fs_lookup (fs, dir, base_name, namelen, buf, &inode);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000137 if (retval)
138 return retval;
139 if (follow) {
140 retval = follow_link(fs, root, dir, inode, link_count,
141 buf, &inode);
142 if (retval)
143 return retval;
144 }
145#ifdef NAMEI_DEBUG
146 printf("open_namei: (link_count=%d) returns %lu\n",
147 link_count, inode);
148#endif
149 *res_inode = inode;
150 return 0;
151}
152
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000153errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
154 const char *name, ext2_ino_t *inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000155{
156 char *buf;
157 errcode_t retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400158
Theodore Ts'of3db3561997-04-26 13:34:30 +0000159 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
160
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400161 retval = ext2fs_get_mem(fs->blocksize, &buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000162 if (retval)
163 return retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400164
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000165 retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
166 buf, inode);
167
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400168 ext2fs_free_mem(&buf);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000169 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000170}
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000171
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000172errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
173 const char *name, ext2_ino_t *inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000174{
175 char *buf;
176 errcode_t retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400177
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000178 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
179
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400180 retval = ext2fs_get_mem(fs->blocksize, &buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000181 if (retval)
182 return retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400183
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000184 retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
185 buf, inode);
186
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400187 ext2fs_free_mem(&buf);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000188 return retval;
189}
190
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000191errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
192 ext2_ino_t inode, ext2_ino_t *res_inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000193{
194 char *buf;
195 errcode_t retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400196
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000197 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
198
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400199 retval = ext2fs_get_mem(fs->blocksize, &buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000200 if (retval)
201 return retval;
202
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000203 retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
204
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400205 ext2fs_free_mem(&buf);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000206 return retval;
207}
208