star.c 3.0 KB

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