star.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #ifdef HAVE_CONFIG_H
  2. # include <config.h>
  3. #endif
  4. #include <tarfn.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <unistd.h>
  8. #include <sys/stat.h>
  9. #include <fcntl.h>
  10. #include <utime.h>
  11. #include <errno.h>
  12. #include <string.h>
  13. #include <time.h>
  14. static int
  15. Read(void * userData, char * buffer, int length)
  16. {
  17. /*
  18. * If the status of the read function is < 0, it will be returned to
  19. * the caller of TarExtractor().
  20. */
  21. return read((int)userData, buffer, length);
  22. }
  23. static int
  24. IOError(TarInfo * i)
  25. {
  26. int error = errno; /* fflush() could cause errno to change */
  27. fflush(stdout);
  28. fprintf(stderr, "%s: %s\n", i->Name, strerror(error));
  29. /*
  30. * The status returned by a coroutine of TarExtractor(), if it
  31. * is non-zero, will be returned to the caller of TarExtractor().
  32. */
  33. return -2;
  34. }
  35. static int
  36. ExtractFile(TarInfo * i)
  37. {
  38. /*
  39. * If you don't want to extract the file, you must advance the tape
  40. * by the file size rounded up to the next 512-byte boundary and
  41. * return 0.
  42. */
  43. int fd = open(i->Name, O_CREAT|O_TRUNC|O_WRONLY, i->Mode & ~S_IFMT);
  44. char buffer[512];
  45. size_t size = i->Size;
  46. struct utimbuf t;
  47. if ( fd < 0 )
  48. return IOError(i);
  49. printf("File: %s\n", i->Name);
  50. while ( size > 0 ) {
  51. size_t writeSize = size >= 512 ? 512 : size;
  52. if ( Read(i->UserData, buffer, 512) != 512 )
  53. return -1; /* Something wrong with archive */
  54. if ( write(fd, buffer, writeSize) != writeSize )
  55. return IOError(i); /* Write failure. */
  56. size -= writeSize;
  57. }
  58. /* fchown() and fchmod() are cheaper than chown() and chmod(). */
  59. fchown(fd, i->UserID, i->GroupID);
  60. fchmod(fd, i->Mode & ~S_IFMT);
  61. close(fd);
  62. t.actime = time(0);
  63. t.modtime = i->ModTime;
  64. utime(i->Name, &t);
  65. return 0;
  66. }
  67. static int
  68. SetModes(TarInfo * i)
  69. {
  70. struct utimbuf t;
  71. #ifdef HAVE_LCHOWN
  72. lchown(i->Name, i->UserID, i->GroupID);
  73. #else
  74. chown(i->Name, i->UserID, i->GroupID);
  75. #endif
  76. chmod(i->Name, i->Mode & ~S_IFMT);
  77. t.actime = time(0);
  78. t.modtime = i->ModTime;
  79. utime(i->Name, &t);
  80. return 0;
  81. }
  82. static int
  83. MakeDirectory(TarInfo * i)
  84. {
  85. printf("Directory: %s\n", i->Name);
  86. if ( mkdir(i->Name, i->Mode & ~S_IFMT) != 0 ) {
  87. if ( errno == EEXIST ) {
  88. struct stat s;
  89. if ( stat(i->Name, &s) != 0 || !(s.st_mode & S_IFDIR) )
  90. return IOError(i);
  91. }
  92. else
  93. return IOError(i);
  94. }
  95. SetModes(i);
  96. return 0;
  97. }
  98. static int
  99. MakeHardLink(TarInfo * i)
  100. {
  101. printf("Hard Link: %s\n", i->Name);
  102. if ( link(i->LinkName, i->Name) != 0 )
  103. return IOError(i);
  104. SetModes(i);
  105. return 0;
  106. }
  107. static int
  108. MakeSymbolicLink(TarInfo * i)
  109. {
  110. printf("Symbolic Link: %s\n", i->Name);
  111. if ( symlink(i->LinkName, i->Name) != 0 )
  112. return -2;
  113. SetModes(i);
  114. return 0;
  115. }
  116. static int
  117. MakeSpecialFile(TarInfo * i)
  118. {
  119. printf("Special File: %s\n", i->Name);
  120. if ( mknod(i->Name, i->Mode, i->Device) != 0 )
  121. return -2;
  122. SetModes(i);
  123. return 0;
  124. }
  125. static const TarFunctions functions = {
  126. Read,
  127. ExtractFile,
  128. MakeDirectory,
  129. MakeHardLink,
  130. MakeSymbolicLink,
  131. MakeSpecialFile
  132. };
  133. int
  134. main(int argc, char * * argv)
  135. {
  136. int status = TarExtractor(NULL, &functions);
  137. if ( status == -1 ) {
  138. fflush(stdout);
  139. fprintf(stderr, "Error in archive format.\n");
  140. return -1;
  141. }
  142. else
  143. return status;
  144. }