tarsplit.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. * tarsplit [-d] [-p pfx] [-s size] - split a tar archive into independent
  3. * tar archives under some size
  4. */
  5. #include <u.h>
  6. #include <libc.h>
  7. #include <ctype.h>
  8. #include "tar.h"
  9. enum {
  10. Stdin,
  11. Endsize = 2 * Tblock, /* size of zero blocks at archive end */
  12. };
  13. /* private data */
  14. static char *filenm;
  15. static char *prefix = "ts.";
  16. static vlong size = 512*1024*1024; /* fits on a CD with room to spare */
  17. static int
  18. opennext(int out, char *prefix)
  19. {
  20. static int filenum = 0;
  21. if (out >= 0) {
  22. fprint(2, "%s: opennext called with file open\n", argv0);
  23. exits("open botch");
  24. }
  25. free(filenm);
  26. filenm = smprint("%s%.5d", prefix, filenum++);
  27. fprint(2, "%s: %s ...", filenm, thisnm);
  28. out = create(filenm, OWRITE, 0666);
  29. if (out < 0)
  30. sysfatal("%s: %r", filenm);
  31. newarch();
  32. return out;
  33. }
  34. static int
  35. split(int in, int out, char * /* inname */)
  36. {
  37. vlong len, membsz;
  38. uvlong outoff = 0;
  39. static Hblock hdr;
  40. Hblock *hp = &hdr;
  41. while (getdir(hp, in, &len)) {
  42. membsz = Tblock + ROUNDUP((uvlong)len, Tblock);
  43. if (outoff + membsz + Endsize > size) { /* won't fit? */
  44. out = closeout(out, filenm, 1);
  45. if (membsz + Endsize > size)
  46. sysfatal("archive member %s (%,lld) + overhead "
  47. "exceeds size limit %,lld", hp->name,
  48. len, size);
  49. }
  50. if (out < 0)
  51. out = opennext(out, prefix);
  52. /* write directory block */
  53. writetar(out, (char *)hp, Tblock);
  54. outoff = passtar(hp, in, out, len);
  55. }
  56. return out;
  57. }
  58. void
  59. usage(void)
  60. {
  61. fprint(2, "usage: %s [-p pfx] [-s size] [file]...\n", argv0);
  62. exits("usage");
  63. }
  64. void
  65. main(int argc, char **argv)
  66. {
  67. int out = -1;
  68. ARGBEGIN {
  69. case 'p':
  70. prefix = EARGF(usage());
  71. break;
  72. case 's':
  73. size = atoll(EARGF(usage()));
  74. if (size < Tblock + Endsize)
  75. sysfatal("implausible max size of %lld bytes", size);
  76. break;
  77. default:
  78. usage();
  79. } ARGEND
  80. if (argc <= 0)
  81. out = split(Stdin, out, "/fd/0");
  82. else
  83. for (; argc-- > 0; argv++) {
  84. int in = open(argv[0], OREAD);
  85. if (in < 0)
  86. sysfatal("%s: %r", argv[0]);
  87. out = split(in, out, argv[0]);
  88. close(in);
  89. }
  90. closeout(out, filenm, 1);
  91. exits(0);
  92. }