dd.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. * dd.c -- convert and copy files. phr 22-march-85.
  3. */
  4. #include <ctype.h>
  5. #include <stdio.h>
  6. #define equal(p, q) (strcmp ((p),(q)) == 0)
  7. #define max(a, b) ((a) > (b) ? (a) : (b))
  8. #define BLOCKSIZE 512 /* Unix dd uses this so we do too */
  9. #define C_ASCII 01
  10. #define C_EBCDIC 02
  11. #define C_IBM 04
  12. #define C_BLOCK 010
  13. #define C_UNBLOCK 020
  14. #define C_LCASE 040
  15. #define C_UCASE 0100
  16. #define C_SWAB 0200
  17. #define C_NOERROR 0400
  18. #define C_SYNC 01000
  19. #define C_DEBUG 02000
  20. #define C_HARDWAY 04000 /* some conversion is needed during i/o */
  21. struct info
  22. {
  23. char *i_if; /* input filename */
  24. int i_ifd; /* input file descriptor */
  25. char *i_of; /* output filename */
  26. int i_ofd; /* output file descriptor */
  27. int i_ibs; /* input blocksize */
  28. int i_obs; /* output blocksize */
  29. int i_cbs; /* conversion buffer size */
  30. int i_skip; /* skip this many records on input */
  31. int i_files; /* skip this many files on input (TODO) */
  32. int i_seek; /* seek to this record on output */
  33. int i_count; /* copy only this many records */
  34. int i_convert; /* bit vector of conversions to apply */
  35. } info = { NULL, 0, NULL, 1, BLOCKSIZE, BLOCKSIZE, BLOCKSIZE, 0, 0, 0, -1, 0};
  36. int w_partial = 0; /* number of partial blocks written */
  37. int w_full = 0; /* numer of full blocks written */
  38. int r_partial = 0; /* number of partial blocks read */
  39. int r_full = 0; /* number of full blocks read */
  40. int r_truncate = 0; /* records truncated by conv=block */
  41. struct conversion
  42. {
  43. char *convname;
  44. int conversion;
  45. } conversions[] = {
  46. "ascii", C_ASCII | C_HARDWAY, /* ebcdic to ascii */
  47. "ebcdic", C_EBCDIC | C_HARDWAY, /* ascii to ebcdic */
  48. "ibm", C_IBM | C_HARDWAY, /* slightly different atoe */
  49. "block", C_BLOCK | C_HARDWAY, /* var to fixed len recs */
  50. "unblock", C_UNBLOCK | C_HARDWAY, /* fixed to var */
  51. "lcase", C_LCASE | C_HARDWAY, /* translate upper to lower */
  52. "ucase", C_UCASE | C_HARDWAY, /* translate lower to upper */
  53. "swab", C_SWAB | C_HARDWAY, /* swap bytes of input */
  54. "noerror", C_NOERROR, /* ignore i/o errors */
  55. "sync", C_SYNC, /* pad input recs to ibs */
  56. "debug", C_DEBUG, /* debugging output flag */
  57. NULL, 0,
  58. };
  59. char trans_table[256]; /* translation table formed by applying */
  60. /* successive transformations */
  61. char ascii_to_ebcdic[] = {
  62. 0, 01, 02, 03, 067, 055, 056, 057,
  63. 026, 05, 045, 013, 014, 015, 016, 017,
  64. 020, 021, 022, 023, 074, 075, 062, 046,
  65. 030, 031, 077, 047, 034, 035, 036, 037,
  66. 0100, 0117, 0177, 0173, 0133, 0154, 0120, 0175,
  67. 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,
  68. 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
  69. 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,
  70. 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
  71. 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,
  72. 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,
  73. 0347, 0350, 0351, 0112, 0340, 0132, 0137, 0155,
  74. 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
  75. 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,
  76. 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,
  77. 0247, 0250, 0251, 0300, 0152, 0320, 0241, 07,
  78. 040, 041, 042, 043, 044, 025, 06, 027,
  79. 050, 051, 052, 053, 054, 011, 012, 033,
  80. 060, 061, 032, 063, 064, 065, 066, 010,
  81. 070, 071, 072, 073, 04, 024, 076, 0341,
  82. 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,
  83. 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  84. 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,
  85. 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,
  86. 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,
  87. 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236,
  88. 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257,
  89. 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
  90. 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
  91. 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,
  92. 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,
  93. 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,
  94. };
  95. char ascii_to_ibm[] = {
  96. 0, 01, 02, 03, 067, 055, 056, 057,
  97. 026, 05, 045, 013, 014, 015, 016, 017,
  98. 020, 021, 022, 023, 074, 075, 062, 046,
  99. 030, 031, 077, 047, 034, 035, 036, 037,
  100. 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175,
  101. 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,
  102. 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
  103. 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,
  104. 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
  105. 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,
  106. 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,
  107. 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155,
  108. 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
  109. 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,
  110. 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,
  111. 0247, 0250, 0251, 0300, 0117, 0320, 0241, 07,
  112. 040, 041, 042, 043, 044, 025, 06, 027,
  113. 050, 051, 052, 053, 054, 011, 012, 033,
  114. 060, 061, 032, 063, 064, 065, 066, 010,
  115. 070, 071, 072, 073, 04, 024, 076, 0341,
  116. 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,
  117. 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  118. 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,
  119. 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,
  120. 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,
  121. 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236,
  122. 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257,
  123. 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
  124. 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
  125. 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,
  126. 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,
  127. 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,
  128. };
  129. char ebcdic_to_ascii[] = {
  130. 0, 01, 02, 03, 0234, 011, 0206, 0177,
  131. 0227, 0215, 0216, 013, 014, 015, 016, 017,
  132. 020, 021, 022, 023, 0235, 0205, 010, 0207,
  133. 030, 031, 0222, 0217, 034, 035, 036, 037,
  134. 0200, 0201, 0202, 0203, 0204, 012, 027, 033,
  135. 0210, 0211, 0212, 0213, 0214, 05, 06, 07,
  136. 0220, 0221, 026, 0223, 0224, 0225, 0226, 04,
  137. 0230, 0231, 0232, 0233, 024, 025, 0236, 032,
  138. 040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
  139. 0247, 0250, 0133, 056, 074, 050, 053, 041,
  140. 046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
  141. 0260, 0261, 0135, 044, 052, 051, 073, 0136,
  142. 055, 057, 0262, 0263, 0264, 0265, 0266, 0267,
  143. 0270, 0271, 0174, 054, 045, 0137, 076, 077,
  144. 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
  145. 0302, 0140, 072, 043, 0100, 047, 075, 042,
  146. 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
  147. 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
  148. 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
  149. 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,
  150. 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,
  151. 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,
  152. 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
  153. 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
  154. 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  155. 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
  156. 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
  157. 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
  158. 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
  159. 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
  160. 060, 061, 062, 063, 064, 065, 066, 067,
  161. 070, 071, 0372, 0373, 0374, 0375, 0376, 0377,
  162. };
  163. main (argc, argv)
  164. int argc;
  165. char **argv;
  166. {
  167. int i;
  168. /* initialize translation table to identity translation */
  169. for (i = 0; i < 256; i++)
  170. trans_table[i] = (char) i;
  171. /* decode arguments and fill in info structure */
  172. scanargs (argc, argv);
  173. if (info.i_if != NULL)
  174. {
  175. if ((info.i_ifd = open (info.i_if, 0)) < 0)
  176. fatal (info.i_if, 1);
  177. if (info.i_of != NULL)
  178. if ((info.i_ofd = creat (info.i_of, 0666)) < 0)
  179. fatal (info.i_of, 1);
  180. }
  181. if (info.i_convert & C_DEBUG)
  182. {
  183. printf ("Info: if=%s, of=%s, ibs=%d, obs=%d, cbs=%d, skip=%d,\n",
  184. info.i_if, info.i_of, info.i_ibs, info.i_obs, info.i_cbs,
  185. info.i_skip);
  186. printf ("files=%d, seek=%d, count=%d conv=0%o\n",
  187. info.i_files, info.i_seek, info.i_count, info.i_convert);
  188. }
  189. copy ();
  190. quit (0);
  191. }
  192. copy ()
  193. {
  194. register int i, oc = 0;
  195. int spaces = 0, col = 0;
  196. char *ibuf, *obuf, *xmalloc ();
  197. int nread, nwritten;
  198. ibuf = xmalloc (info.i_ibs);
  199. if (info.i_ibs != info.i_obs || (info.i_convert & C_HARDWAY))
  200. obuf = xmalloc (info.i_obs);
  201. else
  202. obuf = ibuf;
  203. for (i = 0; i < info.i_skip; i++)
  204. if (read (info.i_ifd, ibuf, info.i_ibs) < 0)
  205. fatal (info.i_if, 1);
  206. if (lseek (info.i_ofd, info.i_seek * info.i_obs, 0) < 0)
  207. fatal (info.i_of, 1);
  208. while ((nread = read (info.i_ifd, ibuf, info.i_ibs)) != 0)
  209. {
  210. if (info.i_count >= 0 && r_partial+r_full > info.i_count)
  211. return;
  212. if (nread < 0)
  213. {
  214. perror (info.i_if);
  215. if (info.i_convert & C_NOERROR)
  216. continue;
  217. else
  218. quit (2);
  219. }
  220. if (nread < info.i_ibs)
  221. {
  222. r_partial++;
  223. if (info.i_convert & C_SYNC)
  224. while (nread < info.i_ibs)
  225. ibuf[nread++] = '\0';
  226. }
  227. else
  228. r_full++;
  229. /* if blocksizes are the same and no conversion, just flush */
  230. if (ibuf == obuf)
  231. {
  232. if ((nwritten = write (info.i_ofd, obuf, nread)) != nread)
  233. {
  234. perror (info.i_of);
  235. w_partial++;
  236. if (!(info.i_convert & C_NOERROR))
  237. quit (1);
  238. }
  239. else if (nread == info.i_ibs)
  240. w_full++;
  241. else
  242. w_partial++;
  243. continue;
  244. }
  245. /*
  246. * copy input to output, doing conversion and flushing output
  247. * as necessary.
  248. */
  249. for (i = 0; i < nread; i++)
  250. {
  251. register int c = trans_table[ibuf[i] & 0377] & 0377;
  252. if (info.i_convert & C_BLOCK)
  253. {
  254. if (spaces-- > 0)
  255. {
  256. i--; /* push back char, get it next time */
  257. c = trans_table[' '];
  258. }
  259. else if (c == '\n')
  260. {
  261. spaces = max (0, info.i_cbs - col);
  262. col = 0;
  263. continue;
  264. }
  265. else if (col++ >= info.i_cbs)
  266. {
  267. r_truncate++;
  268. continue;
  269. }
  270. }
  271. else if (info.i_convert & C_UNBLOCK)
  272. {
  273. if (col++ >= info.i_cbs)
  274. {
  275. col = spaces = 0;
  276. c = trans_table['\n'];
  277. i--; /* get the real c next time */
  278. }
  279. else if (c == ' ')
  280. spaces++;
  281. else if (spaces > 0)
  282. {
  283. i--;
  284. spaces--;
  285. c = trans_table[' '];
  286. }
  287. }
  288. if (info.i_convert & C_SWAB)
  289. obuf[oc++ ^ 1] = c;
  290. else
  291. obuf[oc++] = c;
  292. if (oc >= info.i_obs)
  293. {
  294. if ((nwritten = write (info.i_ofd, obuf, info.i_obs)) != info.i_obs)
  295. {
  296. perror (info.i_of);
  297. w_partial++;
  298. /* maybe it would be better to try to write out the rest of the
  299. block next time instead of throwing it away */
  300. if (!(info.i_convert & C_NOERROR))
  301. quit (1);
  302. }
  303. else
  304. w_full++;
  305. oc = 0;
  306. }
  307. }
  308. }
  309. /* flush last block */
  310. if (oc > 0)
  311. {
  312. /* first, fix earlier screw if swapping bytes and n is odd */
  313. if ((info.i_convert & C_SWAB) && (oc & 1))
  314. obuf[oc-1] = obuf[oc];
  315. if ((nwritten = write (info.i_ofd, obuf, oc)) != oc)
  316. perror (info.i_of);
  317. if (nwritten > 0)
  318. w_partial++;
  319. }
  320. }
  321. scanargs (argc, argv)
  322. int argc;
  323. char **argv;
  324. {
  325. int i, n;
  326. for (i = 1; i < argc; i++)
  327. {
  328. char *name, *val, *index ();
  329. name = argv[i];
  330. if ((val = index (name, '=')) == NULL)
  331. {
  332. printf ("bad arg: %s\n", name);
  333. return -1;
  334. }
  335. *val++ = '\0';
  336. if (equal (name, "if"))
  337. info.i_if = val;
  338. else if (equal (name, "of"))
  339. info.i_of = val;
  340. else if (equal (name, "conv"))
  341. parse_conversion (val);
  342. else
  343. {
  344. n = parse_integer (val);
  345. if (equal (name, "ibs"))
  346. info.i_ibs = n;
  347. else if (equal (name, "obs"))
  348. info.i_obs = n;
  349. else if (equal (name, "bs"))
  350. info.i_obs = info.i_ibs = n;
  351. else if (equal (name, "cbs"))
  352. info.i_cbs = n;
  353. else if (equal (name, "skip"))
  354. info.i_skip = n;
  355. else if (equal (name, "seek"))
  356. info.i_seek = n;
  357. else if (equal (name, "count"))
  358. info.i_count = n;
  359. else
  360. {
  361. printf ("bad arg: %s=%s\n", name, val);
  362. exit (1);
  363. }
  364. }
  365. }
  366. }
  367. parse_integer (str)
  368. char *str;
  369. {
  370. int n = 0;
  371. char *p = str;
  372. while (isdigit (*p))
  373. {
  374. n = n * 10 + *p - '0';
  375. p++;
  376. }
  377. loop:
  378. switch (*p++)
  379. {
  380. case '\0':
  381. return n;
  382. case 'b':
  383. n *= 512;
  384. goto loop;
  385. case 'k':
  386. n *= 1024;
  387. goto loop;
  388. case 'w':
  389. n *= 2;
  390. goto loop;
  391. case 'x':
  392. n *= parse_integer (p);
  393. break;
  394. default:
  395. return 0;
  396. }
  397. return n;
  398. }
  399. parse_conversion (str)
  400. char *str;
  401. {
  402. char *new;
  403. int i, j;
  404. char *new_trans;
  405. do {
  406. if ((new = index (str, ',')) != NULL)
  407. *new++ = '\0';
  408. for (i = 0; conversions[i].convname != NULL; i++)
  409. if (equal (conversions[i].convname, str))
  410. {
  411. info.i_convert |= conversions[i].conversion;
  412. break;
  413. }
  414. if (conversions[i].convname == NULL)
  415. {
  416. printf ("%s: bad conversion.\n", str);
  417. exit (1);
  418. }
  419. #define MX(a) (bit_count (info.i_convert & (a)))
  420. if ((MX (C_ASCII | C_EBCDIC | C_IBM) > 1)
  421. || (MX (C_BLOCK | C_UNBLOCK) > 1)
  422. || (MX (C_LCASE | C_UCASE) > 1)
  423. || (MX (C_UNBLOCK | C_SYNC) > 1))
  424. {
  425. printf ("Only one conv in {ascii,ebcdic,ibm}, {lcase,ucase},\n\t%s",
  426. "{block,unblock}, {unblock,sync}\n");
  427. exit (1);
  428. }
  429. #undef MX
  430. str = new;
  431. } while (new != NULL);
  432. /* I don't know if the following restriction is stupid */
  433. /* but it's convenient */
  434. if ((info.i_convert & C_SWAB) && (info.i_ibs % 2 != 0 ||
  435. info.i_obs % 2 != 0))
  436. {
  437. printf ("Ibs and obs must both be even for swab to work.\n");
  438. exit (1);
  439. }
  440. /* fix up translation table */
  441. /* do upper and lower case if necessary */
  442. if (info.i_convert & C_UCASE)
  443. for (j = 'a'; j <= 'z'; j++)
  444. trans_table[j] = toupper (j);
  445. else if (info.i_convert & C_LCASE)
  446. for (j = 'A'; j <= 'Z'; j++)
  447. trans_table[j] = tolower (j);
  448. /* now find and apply char set translation */
  449. if (info.i_convert & C_ASCII)
  450. new_trans = ebcdic_to_ascii;
  451. else if (info.i_convert & C_EBCDIC)
  452. new_trans = ascii_to_ebcdic;
  453. else if (info.i_convert & C_IBM)
  454. new_trans = ascii_to_ibm;
  455. else
  456. return;
  457. for (i = 0; i < 256; i++)
  458. trans_table[i] = new_trans[trans_table[i]];
  459. }
  460. /* return number of 1 bits in i. */
  461. bit_count (i)
  462. register int i;
  463. {
  464. register int n;
  465. for (n = 0; i != 0; i = (i >> 1) & ~(1<<31))
  466. n += i & 1;
  467. return n;
  468. }
  469. /* print fatal error for file, then die */
  470. fatal (filename, code)
  471. char *filename;
  472. int code;
  473. {
  474. perror (filename);
  475. quit (code);
  476. }
  477. /* print statistics and exit */
  478. quit (code)
  479. {
  480. fprintf (stderr, "%d+%d records in\n", r_full, r_partial);
  481. fprintf (stderr, "%d+%d records out\n", w_full, w_partial);
  482. if (r_truncate > 0)
  483. fprintf (stderr, "%d truncated records\n", r_truncate);
  484. exit (code);
  485. }
  486. /* malloc or die */
  487. char *
  488. xmalloc (n)
  489. int n;
  490. {
  491. char *p, *malloc ();
  492. if ((p = malloc (n)) == NULL)
  493. {
  494. printf ("Malloc: not enough memory\n");
  495. exit (3);
  496. }
  497. }