namei.c revision 2eb374c9401079aa56aa12f0047ca3866e69b754
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, ino_t root, ino_t base, 29 const char *pathname, size_t pathlen, int follow, 30 int link_count, char *buf, ino_t *res_inode); 31 32static errcode_t follow_link(ext2_filsys fs, ino_t root, ino_t dir, 33 ino_t inode, int link_count, 34 char *buf, 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, ino_t root, ino_t dir, 81 const char *pathname, int pathlen, 82 int link_count, char *buf, 83 const char **name, int *namelen, ino_t *res_inode) 84{ 85 char c; 86 const char *thisname; 87 int len; 88 ino_t inode; 89 errcode_t retval; 90 91 if ((c = *pathname) == '/') { 92 dir = root; 93 pathname++; 94 pathlen--; 95 } 96 while (1) { 97 thisname = pathname; 98 for (len=0; --pathlen >= 0;len++) { 99 c = *(pathname++); 100 if (c == '/') 101 break; 102 } 103 if (pathlen < 0) 104 break; 105 retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode); 106 if (retval) return retval; 107 retval = follow_link (fs, root, dir, inode, 108 link_count, buf, &dir); 109 if (retval) return retval; 110 } 111 *name = thisname; 112 *namelen = len; 113 *res_inode = dir; 114 return 0; 115} 116 117static errcode_t open_namei(ext2_filsys fs, ino_t root, ino_t base, 118 const char *pathname, size_t pathlen, int follow, 119 int link_count, char *buf, ino_t *res_inode) 120{ 121 const char *basename; 122 int namelen; 123 ino_t dir, inode; 124 errcode_t retval; 125 126#ifdef NAMEI_DEBUG 127 printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n", 128 root, base, pathlen, pathname, link_count); 129#endif 130 retval = dir_namei(fs, root, base, pathname, pathlen, 131 link_count, buf, &basename, &namelen, &dir); 132 if (retval) return retval; 133 if (!namelen) { /* special case: '/usr/' etc */ 134 *res_inode=dir; 135 return 0; 136 } 137 retval = ext2fs_lookup (fs, dir, basename, namelen, buf, &inode); 138 if (retval) 139 return retval; 140 if (follow) { 141 retval = follow_link(fs, root, dir, inode, link_count, 142 buf, &inode); 143 if (retval) 144 return retval; 145 } 146#ifdef NAMEI_DEBUG 147 printf("open_namei: (link_count=%d) returns %lu\n", 148 link_count, inode); 149#endif 150 *res_inode = inode; 151 return 0; 152} 153 154errcode_t ext2fs_namei(ext2_filsys fs, ino_t root, ino_t cwd, 155 const char *name, ino_t *inode) 156{ 157 char *buf; 158 errcode_t retval; 159 160 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 161 162 retval = ext2fs_get_mem(fs->blocksize, (void **) &buf); 163 if (retval) 164 return retval; 165 166 retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0, 167 buf, inode); 168 169 ext2fs_free_mem((void **) &buf); 170 return retval; 171} 172 173errcode_t ext2fs_namei_follow(ext2_filsys fs, ino_t root, ino_t cwd, 174 const char *name, ino_t *inode) 175{ 176 char *buf; 177 errcode_t retval; 178 179 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 180 181 retval = ext2fs_get_mem(fs->blocksize, (void **) &buf); 182 if (retval) 183 return retval; 184 185 retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0, 186 buf, inode); 187 188 ext2fs_free_mem((void **) &buf); 189 return retval; 190} 191 192errcode_t ext2fs_follow_link(ext2_filsys fs, ino_t root, ino_t cwd, 193 ino_t inode, ino_t *res_inode) 194{ 195 char *buf; 196 errcode_t retval; 197 198 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 199 200 retval = ext2fs_get_mem(fs->blocksize, (void **) &buf); 201 if (retval) 202 return retval; 203 204 retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode); 205 206 ext2fs_free_mem((void **) &buf); 207 return retval; 208} 209 210