tarfn.c 3.8 KB

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