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