namei.c revision 62f17f36031102a2a40fac338e063c556f73b94a
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 "config.h" 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#include "ext2fsP.h" 24 25static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base, 26 const char *pathname, size_t pathlen, int follow, 27 int link_count, char *buf, ext2_ino_t *res_inode); 28 29static 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) 32{ 33 char *pathname; 34 char *buffer = 0; 35 errcode_t retval; 36 struct ext2_inode ei; 37 blk64_t blk; 38 39#ifdef NAMEI_DEBUG 40 printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n", 41 root, dir, inode, link_count); 42 43#endif 44 retval = ext2fs_read_inode (fs, inode, &ei); 45 if (retval) return retval; 46 if (!LINUX_S_ISLNK (ei.i_mode)) { 47 *res_inode = inode; 48 return 0; 49 } 50 if (link_count++ >= EXT2FS_MAX_NESTED_LINKS) 51 return EXT2_ET_SYMLINK_LOOP; 52 53 if (ext2fs_inode_data_blocks(fs,&ei)) { 54 retval = ext2fs_bmap2(fs, inode, &ei, NULL, 0, 0, NULL, &blk); 55 if (retval) 56 return retval; 57 58 retval = ext2fs_get_mem(fs->blocksize, &buffer); 59 if (retval) 60 return retval; 61 62 retval = io_channel_read_blk64(fs->io, blk, 1, buffer); 63 if (retval) { 64 ext2fs_free_mem(&buffer); 65 return retval; 66 } 67 pathname = buffer; 68 } else 69 pathname = (char *)&(ei.i_block[0]); 70 retval = open_namei(fs, root, dir, pathname, ei.i_size, 1, 71 link_count, buf, res_inode); 72 if (buffer) 73 ext2fs_free_mem(&buffer); 74 return retval; 75} 76 77/* 78 * This routine interprets a pathname in the context of the current 79 * directory and the root directory, and returns the inode of the 80 * containing directory, and a pointer to the filename of the file 81 * (pointing into the pathname) and the length of the filename. 82 */ 83static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir, 84 const char *pathname, int pathlen, 85 int link_count, char *buf, 86 const char **name, int *namelen, 87 ext2_ino_t *res_inode) 88{ 89 char c; 90 const char *thisname; 91 int len; 92 ext2_ino_t inode; 93 errcode_t retval; 94 95 if ((c = *pathname) == '/') { 96 dir = root; 97 pathname++; 98 pathlen--; 99 } 100 while (1) { 101 thisname = pathname; 102 for (len=0; --pathlen >= 0;len++) { 103 c = *(pathname++); 104 if (c == '/') 105 break; 106 } 107 if (pathlen < 0) 108 break; 109 retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode); 110 if (retval) return retval; 111 retval = follow_link (fs, root, dir, inode, 112 link_count, buf, &dir); 113 if (retval) return retval; 114 } 115 *name = thisname; 116 *namelen = len; 117 *res_inode = dir; 118 return 0; 119} 120 121static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base, 122 const char *pathname, size_t pathlen, int follow, 123 int link_count, char *buf, ext2_ino_t *res_inode) 124{ 125 const char *base_name; 126 int namelen; 127 ext2_ino_t dir, inode; 128 errcode_t retval; 129 130#ifdef NAMEI_DEBUG 131 printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n", 132 root, base, pathlen, pathname, link_count); 133#endif 134 retval = dir_namei(fs, root, base, pathname, pathlen, 135 link_count, buf, &base_name, &namelen, &dir); 136 if (retval) return retval; 137 if (!namelen) { /* special case: '/usr/' etc */ 138 *res_inode=dir; 139 return 0; 140 } 141 retval = ext2fs_lookup (fs, dir, base_name, namelen, buf, &inode); 142 if (retval) 143 return retval; 144 if (follow) { 145 retval = follow_link(fs, root, dir, inode, link_count, 146 buf, &inode); 147 if (retval) 148 return retval; 149 } 150#ifdef NAMEI_DEBUG 151 printf("open_namei: (link_count=%d) returns %lu\n", 152 link_count, inode); 153#endif 154 *res_inode = inode; 155 return 0; 156} 157 158errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, 159 const char *name, ext2_ino_t *inode) 160{ 161 char *buf; 162 errcode_t retval; 163 164 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 165 166 retval = ext2fs_get_mem(fs->blocksize, &buf); 167 if (retval) 168 return retval; 169 170 retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0, 171 buf, inode); 172 173 ext2fs_free_mem(&buf); 174 return retval; 175} 176 177errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, 178 const char *name, ext2_ino_t *inode) 179{ 180 char *buf; 181 errcode_t retval; 182 183 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 184 185 retval = ext2fs_get_mem(fs->blocksize, &buf); 186 if (retval) 187 return retval; 188 189 retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0, 190 buf, inode); 191 192 ext2fs_free_mem(&buf); 193 return retval; 194} 195 196errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, 197 ext2_ino_t inode, ext2_ino_t *res_inode) 198{ 199 char *buf; 200 errcode_t retval; 201 202 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 203 204 retval = ext2fs_get_mem(fs->blocksize, &buf); 205 if (retval) 206 return retval; 207 208 retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode); 209 210 ext2fs_free_mem(&buf); 211 return retval; 212} 213 214