Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

318 lines
6.4 KiB

  1. //
  2. // Stuff to deal with cpio-format files
  3. //
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <stdlib.h>
  7. #include <fcntl.h>
  8. #include <dirent.h>
  9. #include <limits.h>
  10. #include <sys/stat.h>
  11. #include <string.h>
  12. #include "cpio.h"
  13. #include "buf.h"
  14. #include "psxarc.h"
  15. #include "links.h"
  16. extern int errno;
  17. extern int fVerbose;
  18. static void cpio_dodir(PBUF pb, char *pchfile, struct stat *psb);
  19. //
  20. // Convert string pch of length len from octal and return the value.
  21. //
  22. static int
  23. cpio_atoi(char *pch, int len)
  24. {
  25. int num = 0, i;
  26. for (i = 0; i < len; ++i) {
  27. num = num * 8 + (pch[i] - '0');
  28. }
  29. return num;
  30. }
  31. void
  32. CpioList(PBUF pb)
  33. {
  34. int nbytes;
  35. int namesize, filesize;
  36. int i;
  37. static char pathname[PATH_MAX + NAME_MAX + 2];
  38. CPIO_HEAD x;
  39. for (;;) {
  40. //
  41. // read the cpio header
  42. //
  43. for (i = 0; i < sizeof(x); ++i) {
  44. ((char *)&x)[i] = bgetc(pb);
  45. }
  46. if (0 != strncmp(x.c_magic, MAGIC, strlen(MAGIC))) {
  47. fprintf(stderr,
  48. "%s: this doesn't look like a cpio archive\n",
  49. progname);
  50. exit(1);
  51. }
  52. namesize = cpio_atoi(x.c_namesize, sizeof(x.c_namesize));
  53. filesize = cpio_atoi(x.c_filesize, sizeof(x.c_filesize));
  54. for (i = 0; i < namesize; ++i) {
  55. // nb: namesize includes the null
  56. pathname[i] = bgetc(pb);
  57. }
  58. if (0 == strcmp(pathname, LASTFILENAME)) {
  59. break;
  60. }
  61. printf("%s\n", pathname);
  62. // skip the file data
  63. for (i = 0; i < filesize; ++i) {
  64. (void)bgetc(pb);
  65. }
  66. }
  67. }
  68. void
  69. CpioRead(PBUF pb)
  70. {
  71. int fdout;
  72. int mode;
  73. int i;
  74. int namesize, filesize;
  75. static CPIO_HEAD x;
  76. static char pathname[PATH_MAX + NAME_MAX + 2];
  77. for (;;) {
  78. //
  79. // read the cpio header
  80. //
  81. for (i = 0; i < sizeof(x); ++i) {
  82. ((char *)&x)[i] = bgetc(pb);
  83. }
  84. if (0 != strncmp(x.c_magic, MAGIC, strlen(MAGIC))) {
  85. fprintf(stderr,
  86. "%s: this doesn't look like a cpio archive\n",
  87. progname);
  88. exit(1);
  89. }
  90. namesize = cpio_atoi(x.c_namesize, sizeof(x.c_namesize));
  91. filesize = cpio_atoi(x.c_filesize, sizeof(x.c_filesize));
  92. for (i = 0; i < namesize; ++i) {
  93. // nb: namesize includes the null
  94. pathname[i] = bgetc(pb);
  95. }
  96. if (0 == strcmp(pathname, LASTFILENAME)) {
  97. break;
  98. }
  99. if (fVerbose) {
  100. printf("%s\n", pathname);
  101. }
  102. mode = cpio_atoi(x.c_mode, sizeof(x.c_mode));
  103. if (mode & C_ISDIR) {
  104. mkdir(pathname, 0777);
  105. } else if (mode & C_ISFIFO) {
  106. mkfifo(pathname, 0666);
  107. } else if (mode & C_ISREG) {
  108. fdout = open(pathname, O_WRONLY | O_CREAT, 0666);
  109. if (-1 == fdout) {
  110. fprintf(stderr, "%s: open: ", progname);
  111. perror(pathname);
  112. // we could continue, but we'd have to be sure
  113. // to skip this file's data.
  114. exit(1);
  115. }
  116. for (i = 0; i < filesize; ++i) {
  117. char c;
  118. c = (char)bgetc(pb);
  119. (void)write(fdout, &c, 1);
  120. --filesize;
  121. }
  122. (void)close(fdout);
  123. } else if (mode & C_ISLNK) {
  124. // XXX.mjb: symbolic link
  125. } else {
  126. fprintf(stderr, "%s: unknown mode 0%o\n", progname, mode);
  127. exit(4);
  128. }
  129. }
  130. }
  131. void
  132. cpio_itoa(int i, char *pch, int len)
  133. {
  134. int j;
  135. char buf[20];
  136. sprintf(buf, "%o", i);
  137. j = strlen(buf);
  138. if (j > len) {
  139. printf("itoa: not enough room in buf: need %d, have %d\n",
  140. j, len);
  141. exit(3);
  142. }
  143. memset(pch, '0', len);
  144. strncpy(&pch[len - j], buf, strlen(buf));
  145. }
  146. void
  147. CpioWrite(PBUF pb, char **files, int count)
  148. {
  149. CPIO_HEAD h;
  150. struct stat statbuf;
  151. int i, len;
  152. int fdin;
  153. (void)strncpy(h.c_magic, MAGIC, strlen(MAGIC));
  154. while (count > 0) {
  155. if (fVerbose) {
  156. printf("%s\n", *files);
  157. }
  158. if (-1 == (fdin = open(*files, O_RDONLY))) {
  159. fprintf(stderr, "%s: open: ");
  160. perror(*files);
  161. exit(1);
  162. }
  163. if (-1 == fstat(fdin, &statbuf)) {
  164. perror("fstat");
  165. exit(1);
  166. }
  167. cpio_itoa(strlen(*files) + 1, h.c_namesize, sizeof(h.c_namesize));
  168. cpio_itoa(statbuf.st_dev, h.c_dev, sizeof(h.c_dev));
  169. cpio_itoa(statbuf.st_ino, h.c_ino, sizeof(h.c_ino));
  170. cpio_itoa(statbuf.st_uid, h.c_uid, sizeof(h.c_uid));
  171. cpio_itoa(statbuf.st_gid, h.c_gid, sizeof(h.c_gid));
  172. cpio_itoa(statbuf.st_nlink, h.c_nlink, sizeof(h.c_nlink));
  173. cpio_itoa(statbuf.st_mtime, h.c_mtime, sizeof(h.c_mtime));
  174. if (S_ISDIR(statbuf.st_mode)) {
  175. cpio_itoa(C_ISDIR, h.c_mode, sizeof(h.c_mode));
  176. cpio_itoa(0, h.c_filesize, sizeof(h.c_filesize));
  177. // write the header
  178. for (i = 0; i < sizeof(h); ++i) {
  179. bputc(pb, ((char *)&h)[i]);
  180. }
  181. // write the directory name
  182. len = strlen(*files) + 1; // the nul, too
  183. for (i = 0; i < len; ++i) {
  184. bputc(pb, (*files)[i]);
  185. }
  186. // write the directory contents
  187. cpio_dodir(pb, *files, &statbuf);
  188. count--;
  189. files++;
  190. continue;
  191. }
  192. if (S_ISFIFO(statbuf.st_mode)) {
  193. cpio_itoa(C_ISFIFO, h.c_mode, sizeof(h.c_mode));
  194. cpio_itoa(0, h.c_filesize, sizeof(h.c_filesize));
  195. } else if (S_ISREG(statbuf.st_mode)) {
  196. cpio_itoa(C_ISREG, h.c_mode, sizeof(h.c_mode));
  197. cpio_itoa(statbuf.st_size, h.c_filesize, sizeof(h.c_filesize));
  198. } else {
  199. printf("I'm not prepared to deal with the file type "
  200. "of %s\n", *files);
  201. exit(2);
  202. }
  203. // write the cpio header
  204. for (i = 0; i < sizeof(h); ++i) {
  205. bputc(pb, ((char *)&h)[i]);
  206. }
  207. // write the filename
  208. len = strlen(*files) + 1; // the nul, too
  209. for (i = 0; i < len; ++i) {
  210. bputc(pb, (*files)[i]);
  211. }
  212. while (statbuf.st_size > 0) {
  213. char b;
  214. (void)read(fdin, &b, 1);
  215. bputc(pb, b);
  216. --statbuf.st_size;
  217. }
  218. close(fdin);
  219. count--;
  220. files++;
  221. }
  222. #if 0
  223. printf("", count); // null function call to work around
  224. // mips code generator problem
  225. #endif
  226. }
  227. static void
  228. cpio_dodir(PBUF pb, char *pchfile, struct stat *psb)
  229. {
  230. DIR *dp;
  231. struct dirent *dirent;
  232. char *pch;
  233. dp = opendir(pchfile);
  234. if (NULL == dp) {
  235. fprintf(stderr, "%s: opendir: ", progname);
  236. perror(pchfile);
  237. return;
  238. }
  239. while (NULL != (dirent = readdir(dp))) {
  240. if ('.' == dirent->d_name[0] &&
  241. ('\0' == dirent->d_name[1] ||
  242. 0 == strcmp(dirent->d_name, ".."))) {
  243. continue;
  244. }
  245. //
  246. // Recurse. We append the file name read from the directory
  247. // to the directory name we were given and call CpioWrite to
  248. // put it on the tape. It could be a directory, so we could
  249. // end up back here. This means that we must allocate the
  250. // space for the pathname dynamically. This seems like it
  251. // will be a big time-waster.
  252. //
  253. // strlen + 2: one extra for '/', one extra for nul.
  254. pch = malloc(strlen(pchfile) + strlen(dirent->d_name) + 2);
  255. if (NULL == pch) {
  256. fprintf(stderr, "%s: virtual memory exhausted\n",
  257. progname);
  258. exit(4);
  259. }
  260. strcpy(pch, pchfile);
  261. strcat(pch, "/");
  262. strcat(pch, dirent->d_name);
  263. CpioWrite(pb, &pch, 1);
  264. free(pch);
  265. }
  266. (void)closedir(dp);
  267. }