tarfn.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. char *next_long_name, *next_long_link;
  94. char *bp;
  95. char **longp;
  96. int long_read;
  97. next_long_name = 0;
  98. next_long_link = 0;
  99. long_read = 0;
  100. h.UserData = userData;
  101. while ( (status = functions->Read(userData, buffer, 512)) == 512 ) {
  102. int nameLength;
  103. if ( !DecodeTarHeader(buffer, &h) ) {
  104. if ( h.Name[0] == '\0' ) {
  105. return 0; /* End of tape */
  106. } else {
  107. errno = 0; /* Indicates broken tarfile */
  108. return -1; /* Header checksum error */
  109. }
  110. }
  111. if (next_long_name) {
  112. h.Name = next_long_name;
  113. }
  114. if (next_long_link) {
  115. h.LinkName = next_long_link;
  116. }
  117. next_long_name = 0;
  118. next_long_link = 0;
  119. if ( h.Name[0] == '\0' ) {
  120. errno = 0; /* Indicates broken tarfile */
  121. return -1; /* Bad header data */
  122. }
  123. nameLength = strlen(h.Name);
  124. switch ( h.Type ) {
  125. case NormalFile0:
  126. case NormalFile1:
  127. /* Compatibility with pre-ANSI ustar */
  128. if ( h.Name[nameLength - 1] != '/' ) {
  129. status = (*functions->ExtractFile)(&h);
  130. break;
  131. }
  132. /* Else, Fall Through */
  133. case Directory:
  134. h.Name[nameLength - 1] = '\0';
  135. status = (*functions->MakeDirectory)(&h);
  136. break;
  137. case HardLink:
  138. status = (*functions->MakeHardLink)(&h);
  139. break;
  140. case SymbolicLink:
  141. status = (*functions->MakeSymbolicLink)(&h);
  142. break;
  143. case CharacterDevice:
  144. case BlockDevice:
  145. case FIFO:
  146. status = (*functions->MakeSpecialFile)(&h);
  147. break;
  148. case GNU_LONGLINK:
  149. case GNU_LONGNAME:
  150. // set longp to the location of the long filename or link
  151. // we're trying to deal with
  152. longp = ((h.Type == GNU_LONGNAME)
  153. ? &next_long_name
  154. : &next_long_link);
  155. if (*longp)
  156. free(*longp);
  157. if (NULL == (*longp = (char *)malloc(h.Size))) {
  158. /* malloc failed, so bail */
  159. errno = 0;
  160. return -1;
  161. }
  162. bp = *longp;
  163. // the way the GNU long{link,name} stuff works is like this:
  164. // The first header is a "dummy" header that contains the size
  165. // of the filename. The next N headers contain the filename.
  166. // After the headers with the filename comes the "real" header
  167. // with a bogus name or link.
  168. for (long_read = h.Size; long_read > 0;
  169. long_read -= 512) {
  170. int copysize;
  171. status = functions->Read(userData, buffer, 512);
  172. // if we didn't get 512 bytes read, punt
  173. if (512 != status) {
  174. if ( status > 0 ) { /* Read partial header record */
  175. errno = 0;
  176. return -1;
  177. } else {
  178. return status;
  179. }
  180. }
  181. copysize = long_read > 512 ? 512 : long_read;
  182. memcpy (bp, buffer, copysize);
  183. bp += copysize;
  184. };
  185. // This decode function expects status to be 0 after
  186. // the case statement if we successfully decoded. I
  187. // guess what we just did was successful.
  188. status = 0;
  189. break;
  190. default:
  191. errno = 0; /* Indicates broken tarfile */
  192. return -1; /* Bad header field */
  193. }
  194. if ( status != 0 )
  195. return status; /* Pass on status from coroutine */
  196. }
  197. if ( status > 0 ) { /* Read partial header record */
  198. errno = 0; /* Indicates broken tarfile */
  199. return -1;
  200. } else {
  201. return status; /* Whatever I/O function returned */
  202. }
  203. }