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