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