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