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