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