namei.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * namei.c --- ext2fs directory lookup operations
  4. *
  5. * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
  6. *
  7. * %Begin-Header%
  8. * This file may be redistributed under the terms of the GNU Public
  9. * License.
  10. * %End-Header%
  11. */
  12. #include <stdio.h>
  13. #include <string.h>
  14. #if HAVE_UNISTD_H
  15. #include <unistd.h>
  16. #endif
  17. /* #define NAMEI_DEBUG */
  18. #include "ext2_fs.h"
  19. #include "ext2fs.h"
  20. static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
  21. const char *pathname, size_t pathlen, int follow,
  22. int link_count, char *buf, ext2_ino_t *res_inode);
  23. static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
  24. ext2_ino_t inode, int link_count,
  25. char *buf, ext2_ino_t *res_inode)
  26. {
  27. char *pathname;
  28. char *buffer = NULL;
  29. errcode_t retval;
  30. struct ext2_inode ei;
  31. #ifdef NAMEI_DEBUG
  32. printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
  33. root, dir, inode, link_count);
  34. #endif
  35. retval = ext2fs_read_inode (fs, inode, &ei);
  36. if (retval) return retval;
  37. if (!LINUX_S_ISLNK (ei.i_mode)) {
  38. *res_inode = inode;
  39. return 0;
  40. }
  41. if (link_count++ > 5) {
  42. return EXT2_ET_SYMLINK_LOOP;
  43. }
  44. if (ext2fs_inode_data_blocks(fs, &ei)) {
  45. retval = ext2fs_get_mem(fs->blocksize, &buffer);
  46. if (retval)
  47. return retval;
  48. retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer);
  49. if (retval) {
  50. ext2fs_free_mem(&buffer);
  51. return retval;
  52. }
  53. pathname = buffer;
  54. } else
  55. pathname = (char *)&(ei.i_block[0]);
  56. retval = open_namei(fs, root, dir, pathname, ei.i_size, 1,
  57. link_count, buf, res_inode);
  58. ext2fs_free_mem(&buffer);
  59. return retval;
  60. }
  61. /*
  62. * This routine interprets a pathname in the context of the current
  63. * directory and the root directory, and returns the inode of the
  64. * containing directory, and a pointer to the filename of the file
  65. * (pointing into the pathname) and the length of the filename.
  66. */
  67. static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
  68. const char *pathname, int pathlen,
  69. int link_count, char *buf,
  70. const char **name, int *namelen,
  71. ext2_ino_t *res_inode)
  72. {
  73. char c;
  74. const char *thisname;
  75. int len;
  76. ext2_ino_t inode;
  77. errcode_t retval;
  78. if ((c = *pathname) == '/') {
  79. dir = root;
  80. pathname++;
  81. pathlen--;
  82. }
  83. while (1) {
  84. thisname = pathname;
  85. for (len=0; --pathlen >= 0;len++) {
  86. c = *(pathname++);
  87. if (c == '/')
  88. break;
  89. }
  90. if (pathlen < 0)
  91. break;
  92. retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode);
  93. if (retval) return retval;
  94. retval = follow_link (fs, root, dir, inode,
  95. link_count, buf, &dir);
  96. if (retval) return retval;
  97. }
  98. *name = thisname;
  99. *namelen = len;
  100. *res_inode = dir;
  101. return 0;
  102. }
  103. static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
  104. const char *pathname, size_t pathlen, int follow,
  105. int link_count, char *buf, ext2_ino_t *res_inode)
  106. {
  107. const char *basename;
  108. int namelen;
  109. ext2_ino_t dir, inode;
  110. errcode_t retval;
  111. #ifdef NAMEI_DEBUG
  112. printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n",
  113. root, base, pathlen, pathname, link_count);
  114. #endif
  115. retval = dir_namei(fs, root, base, pathname, pathlen,
  116. link_count, buf, &basename, &namelen, &dir);
  117. if (retval) return retval;
  118. if (!namelen) { /* special case: '/usr/' etc */
  119. *res_inode=dir;
  120. return 0;
  121. }
  122. retval = ext2fs_lookup (fs, dir, basename, namelen, buf, &inode);
  123. if (retval)
  124. return retval;
  125. if (follow) {
  126. retval = follow_link(fs, root, dir, inode, link_count,
  127. buf, &inode);
  128. if (retval)
  129. return retval;
  130. }
  131. #ifdef NAMEI_DEBUG
  132. printf("open_namei: (link_count=%d) returns %lu\n",
  133. link_count, inode);
  134. #endif
  135. *res_inode = inode;
  136. return 0;
  137. }
  138. errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
  139. const char *name, ext2_ino_t *inode)
  140. {
  141. char *buf;
  142. errcode_t retval;
  143. EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
  144. retval = ext2fs_get_mem(fs->blocksize, &buf);
  145. if (retval)
  146. return retval;
  147. retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
  148. buf, inode);
  149. ext2fs_free_mem(&buf);
  150. return retval;
  151. }
  152. errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
  153. const char *name, ext2_ino_t *inode)
  154. {
  155. char *buf;
  156. errcode_t retval;
  157. EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
  158. retval = ext2fs_get_mem(fs->blocksize, &buf);
  159. if (retval)
  160. return retval;
  161. retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
  162. buf, inode);
  163. ext2fs_free_mem(&buf);
  164. return retval;
  165. }
  166. errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
  167. ext2_ino_t inode, ext2_ino_t *res_inode)
  168. {
  169. char *buf;
  170. errcode_t retval;
  171. EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
  172. retval = ext2fs_get_mem(fs->blocksize, &buf);
  173. if (retval)
  174. return retval;
  175. retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
  176. ext2fs_free_mem(&buf);
  177. return retval;
  178. }