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 <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