tarfn.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * Functions for extracting tar archives.
  3. * Bruce Perens, April-May 1995
  4. * Copyright (C) 1995 Bruce Perens
  5. * This is free software under the GNU General Public License.
  6. */
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <unistd.h>
  11. #include <pwd.h>
  12. #include <grp.h>
  13. #include <errno.h>
  14. #include <tarfn.h>
  15. struct TarHeader {
  16. char Name[100];
  17. char Mode[8];
  18. char UserID[8];
  19. char GroupID[8];
  20. char Size[12];
  21. char ModificationTime[12];
  22. char Checksum[8];
  23. char LinkFlag;
  24. char LinkName[100];
  25. char MagicNumber[8];
  26. char UserName[32];
  27. char GroupName[32];
  28. char MajorDevice[8];
  29. char MinorDevice[8];
  30. };
  31. typedef struct TarHeader TarHeader;
  32. static const unsigned int TarChecksumOffset
  33. = (unsigned int)&(((TarHeader *)0)->Checksum);
  34. /* Octal-ASCII-to-long */
  35. static long
  36. OtoL(const char * s, int size)
  37. {
  38. int n = 0;
  39. while ( *s == ' ' ) {
  40. s++;
  41. size--;
  42. }
  43. while ( --size >= 0 && *s >= '0' && *s <= '7' )
  44. n = (n * 010) + (*s++ - '0');
  45. return n;
  46. }
  47. static int
  48. DecodeTarHeader(char * block, TarInfo * d)
  49. {
  50. TarHeader * h = (TarHeader *)block;
  51. unsigned char * s = (unsigned char *)block;
  52. struct passwd * passwd = 0;
  53. struct group * group = 0;
  54. unsigned int i;
  55. long sum;
  56. long checksum;
  57. if ( *h->UserName )
  58. passwd = getpwnam(h->UserName);
  59. if ( *h->GroupName )
  60. group = getgrnam(h->GroupName);
  61. d->Name = h->Name;
  62. d->LinkName = h->LinkName;
  63. d->Mode = (mode_t)OtoL(h->Mode, sizeof(h->Mode));
  64. d->Size = (size_t)OtoL(h->Size, sizeof(h->Size));
  65. d->ModTime = (time_t)OtoL(h->ModificationTime
  66. ,sizeof(h->ModificationTime));
  67. d->Device = ((OtoL(h->MajorDevice, sizeof(h->MajorDevice)) & 0xff) << 8)
  68. | (OtoL(h->MinorDevice, sizeof(h->MinorDevice)) & 0xff);
  69. checksum = OtoL(h->Checksum, sizeof(h->Checksum));
  70. d->UserID = (uid_t)OtoL(h->UserID, sizeof(h->UserID));
  71. d->GroupID = (gid_t)OtoL(h->GroupID, sizeof(h->GroupID));
  72. d->Type = (TarFileType)h->LinkFlag;
  73. if ( passwd )
  74. d->UserID = passwd->pw_uid;
  75. if ( group )
  76. d->GroupID = group->gr_gid;
  77. sum = ' ' * sizeof(h->Checksum);/* Treat checksum field as all blank */
  78. for ( i = TarChecksumOffset; i > 0; i-- )
  79. sum += *s++;
  80. s += sizeof(h->Checksum); /* Skip the real checksum field */
  81. for ( i = (512 - TarChecksumOffset - sizeof(h->Checksum)); i > 0; i-- )
  82. sum += *s++;
  83. return ( sum == checksum );
  84. }
  85. extern int
  86. TarExtractor(
  87. void * userData
  88. ,const TarFunctions * functions)
  89. {
  90. int status;
  91. char buffer[512];
  92. TarInfo h;
  93. h.UserData = userData;
  94. while ( (status = functions->Read(userData, buffer, 512)) == 512 ) {
  95. int nameLength;
  96. if ( !DecodeTarHeader(buffer, &h) ) {
  97. if ( h.Name[0] == '\0' ) {
  98. return 0; /* End of tape */
  99. } else {
  100. errno = 0; /* Indicates broken tarfile */
  101. return -1; /* Header checksum error */
  102. }
  103. }
  104. if ( h.Name[0] == '\0' ) {
  105. errno = 0; /* Indicates broken tarfile */
  106. return -1; /* Bad header data */
  107. }
  108. nameLength = strlen(h.Name);
  109. switch ( h.Type ) {
  110. case NormalFile0:
  111. case NormalFile1:
  112. /* Compatibility with pre-ANSI ustar */
  113. if ( h.Name[nameLength - 1] != '/' ) {
  114. status = (*functions->ExtractFile)(&h);
  115. break;
  116. }
  117. /* Else, Fall Through */
  118. case Directory:
  119. h.Name[nameLength - 1] = '\0';
  120. status = (*functions->MakeDirectory)(&h);
  121. break;
  122. case HardLink:
  123. status = (*functions->MakeHardLink)(&h);
  124. break;
  125. case SymbolicLink:
  126. status = (*functions->MakeSymbolicLink)(&h);
  127. break;
  128. case CharacterDevice:
  129. case BlockDevice:
  130. case FIFO:
  131. status = (*functions->MakeSpecialFile)(&h);
  132. break;
  133. default:
  134. errno = 0; /* Indicates broken tarfile */
  135. return -1; /* Bad header field */
  136. }
  137. if ( status != 0 )
  138. return status; /* Pass on status from coroutine */
  139. }
  140. if ( status > 0 ) { /* Read partial header record */
  141. errno = 0; /* Indicates broken tarfile */
  142. return -1;
  143. } else {
  144. return status; /* Whatever I/O function returned */
  145. }
  146. }