shared_tar_ext.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * Large portions of tar.c & extfs.c were nearly same. I killed this
  3. * redundancy, so code is maintainable, again.
  4. *
  5. * Actually, tar no longer uses this code :-).
  6. *
  7. * 1998 Pavel Machek
  8. *
  9. * Namespace: no pollution.
  10. */
  11. static char *get_path (char *inname, struct archive **archive, int is_dir,
  12. int do_not_open)
  13. {
  14. char *buf = strdup( inname );
  15. char *res = get_path_mangle( buf, archive, is_dir, do_not_open );
  16. char *res2 = NULL;
  17. if (res)
  18. res2 = strdup(res);
  19. free(buf);
  20. return res2;
  21. }
  22. static struct entry*
  23. __find_entry (struct entry *dir, char *name,
  24. struct loop_protect *list, int make_dirs, int make_file)
  25. {
  26. struct entry *pent, *pdir;
  27. char *p, *q, *name_end;
  28. char c;
  29. if (*name == '/') { /* Handle absolute paths */
  30. name++;
  31. dir = dir->inode->archive->root_entry;
  32. }
  33. pent = dir;
  34. p = name;
  35. name_end = name + strlen (name);
  36. q = strchr (p, '/');
  37. c = '/';
  38. if (!q)
  39. q = strchr (p, 0);
  40. for (; pent != NULL && c && *p; ){
  41. c = *q;
  42. *q = 0;
  43. if (strcmp (p, ".")){
  44. if (!strcmp (p, ".."))
  45. pent = pent->dir;
  46. else {
  47. if ((pent = __resolve_symlinks (pent, list))==NULL){
  48. *q = c;
  49. return NULL;
  50. }
  51. if (c == '/' && !S_ISDIR (pent->inode->mode)){
  52. *q = c;
  53. notadir = 1;
  54. return NULL;
  55. }
  56. pdir = pent;
  57. for (pent = pent->inode->first_in_subdir; pent; pent = pent->next_in_dir)
  58. /* Hack: I keep the original semanthic unless
  59. q+1 would break in the strchr */
  60. if (!strcmp (pent->name, p)){
  61. if (q + 1 > name_end){
  62. *q = c;
  63. notadir = !S_ISDIR (pent->inode->mode);
  64. return pent;
  65. }
  66. break;
  67. }
  68. /* When we load archive, we create automagically
  69. * non-existant directories
  70. */
  71. if (pent == NULL && make_dirs) {
  72. pent = generate_entry (dir->inode->archive, p, pdir, S_IFDIR | 0777);
  73. }
  74. if (pent == NULL && make_file) {
  75. pent = generate_entry (dir->inode->archive, p, pdir, 0777);
  76. }
  77. }
  78. }
  79. /* Next iteration */
  80. *q = c;
  81. p = q + 1;
  82. q = strchr (p, '/');
  83. if (!q)
  84. q = strchr (p, 0);
  85. }
  86. if (pent == NULL)
  87. my_errno = ENOENT;
  88. return pent;
  89. }
  90. static struct entry *find_entry (struct entry *dir, char *name, int make_dirs, int make_file)
  91. {
  92. struct entry *res;
  93. errloop = 0;
  94. notadir = 0;
  95. res = __find_entry (dir, name, NULL, make_dirs, make_file);
  96. if (res == NULL) {
  97. if (errloop)
  98. my_errno = ELOOP;
  99. else if (notadir)
  100. my_errno = ENOTDIR;
  101. }
  102. return res;
  103. }
  104. static int s_errno (vfs *me)
  105. {
  106. return my_errno;
  107. }
  108. static void * s_opendir (vfs *me, char *dirname)
  109. {
  110. struct archive *archive;
  111. char *q;
  112. struct entry *entry;
  113. struct entry **info;
  114. if ((q = get_path_mangle (dirname, &archive, 1, 0)) == NULL)
  115. return NULL;
  116. entry = find_entry (archive->root_entry, q, 0, 0);
  117. if (entry == NULL)
  118. return NULL;
  119. if ((entry = my_resolve_symlinks (entry)) == NULL)
  120. return NULL;
  121. if (!S_ISDIR (entry->inode->mode)) ERRNOR (ENOTDIR, NULL);
  122. info = (struct entry **) xmalloc (2*sizeof (struct entry *), "shared opendir");
  123. info[0] = entry->inode->first_in_subdir;
  124. info[1] = entry->inode->first_in_subdir;
  125. return info;
  126. }
  127. static void * s_readdir (void *data)
  128. {
  129. static struct {
  130. struct dirent dir;
  131. #ifdef NEED_EXTRA_DIRENT_BUFFER
  132. char extra_buffer [MC_MAXPATHLEN];
  133. #endif
  134. } dir;
  135. struct entry **info = (struct entry **) data;
  136. if (!*info)
  137. return NULL;
  138. strcpy (&(dir.dir.d_name [0]), (*info)->name);
  139. #ifndef DIRENT_LENGTH_COMPUTED
  140. dir.d_namlen = strlen (dir.dir.d_name);
  141. #endif
  142. *info = (*info)->next_in_dir;
  143. return (void *)&dir;
  144. }
  145. static int s_telldir (void *data)
  146. {
  147. struct entry **info = (struct entry **) data;
  148. struct entry *cur;
  149. int num = 0;
  150. cur = info[1];
  151. while (cur!=NULL) {
  152. if (cur == info[0]) return num;
  153. num++;
  154. cur = cur->next_in_dir;
  155. }
  156. return -1;
  157. }
  158. static void s_seekdir (void *data, int offset)
  159. {
  160. struct entry **info = (struct entry **) data;
  161. int i;
  162. info[0] = info[1];
  163. for (i=0; i<offset; i++)
  164. s_readdir( data );
  165. }
  166. static int s_closedir (void *data)
  167. {
  168. free (data);
  169. return 0;
  170. }
  171. static void stat_move( struct stat *buf, struct inode *inode )
  172. {
  173. buf->st_dev = inode->dev;
  174. buf->st_ino = inode->inode;
  175. buf->st_mode = inode->mode;
  176. buf->st_nlink = inode->nlink;
  177. buf->st_uid = inode->uid;
  178. buf->st_gid = inode->gid;
  179. #ifdef HAVE_ST_RDEV
  180. buf->st_rdev = inode->rdev;
  181. #endif
  182. buf->st_size = inode->size;
  183. #ifdef HAVE_ST_BLKSIZE
  184. buf->st_blksize = RECORDSIZE;
  185. #endif
  186. #ifdef HAVE_ST_BLOCKS
  187. buf->st_blocks = (inode->size + RECORDSIZE - 1) / RECORDSIZE;
  188. #endif
  189. buf->st_atime = inode->atime;
  190. buf->st_mtime = inode->mtime;
  191. buf->st_ctime = inode->ctime;
  192. }
  193. static int s_internal_stat (char *path, struct stat *buf, int resolve)
  194. {
  195. struct archive *archive;
  196. char *q;
  197. struct entry *entry;
  198. struct inode *inode;
  199. if ((q = get_path_mangle (path, &archive, 0, 0)) == NULL)
  200. return -1;
  201. entry = find_entry (archive->root_entry, q, 0, 0);
  202. if (entry == NULL)
  203. return -1;
  204. if (resolve && (entry = my_resolve_symlinks (entry)) == NULL)
  205. return -1;
  206. inode = entry->inode;
  207. stat_move( buf, inode );
  208. return 0;
  209. }
  210. static int s_stat (vfs *me, char *path, struct stat *buf)
  211. {
  212. return s_internal_stat (path, buf, 1);
  213. }
  214. static int s_lstat (vfs *me, char *path, struct stat *buf)
  215. {
  216. return s_internal_stat (path, buf, 0);
  217. }
  218. static int s_fstat (void *data, struct stat *buf)
  219. {
  220. struct pseudofile *file = (struct pseudofile *)data;
  221. struct inode *inode;
  222. inode = file->entry->inode;
  223. stat_move( buf, inode );
  224. return 0;
  225. }
  226. static int s_readlink (vfs *me, char *path, char *buf, int size)
  227. {
  228. struct archive *archive;
  229. char *q;
  230. int i;
  231. struct entry *entry;
  232. if ((q = get_path_mangle (path, &archive, 0, 0)) == NULL)
  233. return -1;
  234. entry = find_entry (archive->root_entry, q, 0, 0);
  235. if (entry == NULL)
  236. return -1;
  237. if (!S_ISLNK (entry->inode->mode)) ERRNOR (EINVAL, -1);
  238. if (size > (i = strlen (entry->inode->linkname))) {
  239. size = i;
  240. }
  241. strncpy (buf, entry->inode->linkname, i);
  242. return i;
  243. }