Exemple #1
0
/* Reads in a single TAR block
 */
long readBlock(int cm, void *buffer)
{
  long len = -1;
  switch (cm)
  {
#ifdef ENABLE_BZ2
    case CM_BZ2:
	len = BZ2_bzRead(&bzerror, bzfile, buffer, BLOCKSIZE);
      break;
#endif
#ifdef ENABLE_LZMA
    case CM_LZMA:
      len = lzma_read(lzmaFile, buffer, BLOCKSIZE);
      break;
#endif
    default: /* CM_NONE, CM_GZ */
      len = gzread(infile, buffer, BLOCKSIZE);
      break;
  }

  /* check for read errors and abort */
  if (len < 0)
  {
    PrintMessage(_T("gzread: error decompressing"));
    cm_cleanup(cm);
    return -1;
  }
  /*
   * Always expect complete blocks to process
   * the tar information.
   */
  if (len != BLOCKSIZE)
  {
    PrintMessage(_T("gzread: incomplete block read"));
    cm_cleanup(cm);
    return -1;
  }

  return len; /* success */
}
Exemple #2
0
static int
cm_teardown(void **state)
{
    cm_ctx_t *ctx = *state;
    assert_non_null(ctx);

    cm_stop(ctx);
    cm_cleanup(ctx);

    sr_logger_cleanup();

    return 0;
}
Exemple #3
0
/* Tar file extraction
 * gzFile in, handle of input tarball opened with gzopen
 * int cm, compressionMethod
 * int junkPaths, nonzero indicates to ignore stored path (don't create directories)
 * enum KeepMode keep, indicates to perform if file exists
 * int iCnt, char *iList[], argv style list of files to extract, {0,NULL} for all
 * int xCnt, char *xList[], argv style list of files NOT to extract, {0,NULL} for none
 * int failOnHardLinks, if nonzero then will treat failure to create a hard link same as
 *   failure to create a regular file, 0 prints a warning if fails - note that hardlinks
 *   will always fail on Windows prior to NT 5 (Win 2000) or later and non NTFS file systems.
 *
 * returns 0 (or positive value) on success
 * returns negative value on error, where
 *   -1 means error reading from tarball
 *   -2 means error extracting file from tarball
 *   -3 means error creating hard link
 */
int tgz_extract(gzFile in, int cm, int junkPaths, enum KeepMode keep, int iCnt, TCHAR *iList[], int xCnt, TCHAR *xList[], int failOnHardLinks)
{
  int           getheader = 1;    /* assume initial input has a tar header */
  HANDLE        outfile = INVALID_HANDLE_VALUE;

  union         tar_buffer buffer;
  unsigned long remaining;
  TCHAR          fname[BLOCKSIZE]; /* must be >= BLOCKSIZE bytes */
  time_t        tartime;

  /* do any prep work for extracting from compressed TAR file */
  if (cm_init(in, cm))
  {
    PrintMessage(_T("tgz_extract: unable to initialize decompression method."));
    cm_cleanup(cm);
    return -1;
  }
  
  while (1)
  {
    if (readBlock(cm, &buffer) < 0) return -1;
      
    /*
     * If we have to get a tar header
     */
    if (getheader >= 1)
    {
      /*
       * if we met the end of the tar
       * or the end-of-tar block,
       * we are done
       */
      if (/* (len == 0)  || */ (buffer.header.name[0]== 0)) break;

      /* compute and check header checksum, support signed or unsigned */
      if (!valid_checksum(&(buffer.header)))
      {
        PrintMessage(_T("tgz_extract: bad header checksum"));
        cm_cleanup(cm);
        return -1;
      }

      /* store time, so we can set the timestamp on files */
      tartime = (time_t)getoct(buffer.header.mtime,12);

      /* copy over filename chunk from header, avoiding overruns */
      if (getheader == 1) /* use normal (short or posix long) filename from header */
      {
        /* NOTE: prepends any prefix, including separator, and ensures terminated */
        memset(fname, 0, sizeof(fname));
		getFullName(&buffer, fname);
      }
      else /* use (GNU) long filename that preceeded this header */
      {
#if 0
        /* if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0) */
        char fs[SHORTNAMESIZE];   /* force strings to same max len, then compare */
        lstrcpyn(fs, fname, SHORTNAMESIZE);
        fs[SHORTNAMESIZE-1] = '\0';
        buffer.header.name[SHORTNAMESIZE-1] = '\0';
        if (lstrcmp(fs, buffer.header.name) != 0)
        {
          PrintMessage(_T("tgz_extract: mismatched long filename"));
          cm_cleanup(cm);
          return -1;
        }
#else
		PrintMessage(_T("tgz_extract: using GNU long filename [%s]"), fname);
#endif
      }
      /* LogMessage("buffer.header.name is:");  LogMessage(fname); */


      switch (buffer.header.typeflag)
      {
        case DIRTYPE:
		  dirEntry:
          if (!junkPaths)
          {
            safetyStrip(fname);
            makedir(fname);
          }
	      break;
		case LNKTYPE:   /* hard link */ 
		case CONTTYPE:  /* contiguous file, for compatibility treat as normal */
        case REGTYPE:
        case AREGTYPE:
	      /* Note: a file ending with a / may actually be a BSD tar directory entry */
	      if (fname[strlen(fname)-1] == '/')
	        goto dirEntry;

	      remaining = getoct(buffer.header.size,12);
	      if ( /* add (remaining > 0) && to ignore 0 zero byte files */
               ( (iList == NULL) || (matchname(fname, iCnt, iList, junkPaths)) ) &&
               (!matchname(fname, xCnt, xList, junkPaths))
             )
	      {
			  if (!junkPaths) /* if we want to use paths as stored */
			  {
	              /* try creating directory */
	              TCHAR *p = tstrrchr(fname, '/');
	              if (p != NULL) 
	              {
	                *p = '\0';
	                makedir(fname);
	                *p = '/';
	              }
			  }
			  else
			  {
	              /* try ignoring directory */
	              TCHAR *p = tstrrchr(fname, '/');
	              if (p != NULL) 
	              {
	                /* be sure terminating '\0' is copied and */
	                /* use ansi memcpy equivalent that handles overlapping regions */
	                MoveMemory(fname, p+1, (strlen(p+1) + 1) * sizeof(TCHAR) );
	              }
	          }
	          if (*fname) /* if after stripping path a fname still exists */
	          {
	            /* Attempt to open the output file and report action taken to user */
	            const TCHAR szERRMsg[] = _T("Error: Could not create file "),
	                        szSUCMsg[] = _T("Writing "),
	                        szSKPMsg[] = _T("Skipping ");
	            const TCHAR * szMsg = szSUCMsg;

	            safetyStrip(fname);

				if (buffer.header.typeflag == LNKTYPE)
				{
					outfile = INVALID_HANDLE_VALUE;
					/* create a hardlink if possible, else produce just a warning unless failOnHardLinks is true */
					if (!MakeHardLink(fname, buffer.header.linkname))
					{
						PrintMessage(_T("Warning: unable to create hard link %s [%d]"), fname, GetLastError());
						if (failOnHardLinks) 
						{
							cm_cleanup(cm);
							return -3;
						}
					}
					else
					{
						outfile = CreateFile(fname,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
						goto setTimeAndCloseFile;
					}
				} else 
				{
	            /* Open the file for writing mode, creating if doesn't exist and truncating if exists and overwrite mode */
	            outfile = CreateFile(fname,GENERIC_WRITE,FILE_SHARE_READ,NULL,(keep==OVERWRITE)?CREATE_ALWAYS:CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);

	            /* failed to open file, either valid error (like open) or it already exists and in a keep mode */
	            if (outfile == INVALID_HANDLE_VALUE)
	            {
	              /* if skip existing or only update existing and failed to open becauses exists */
	              if ((keep!=OVERWRITE) && (GetLastError()==ERROR_FILE_EXISTS))
	              {
	                /* assume skipping initially (mode==SKIP or ==UPDATE with existing file newer) */
	                szMsg = szSKPMsg; /* and update output message accordingly */

					/* if in update mode, check filetimes and reopen in overwrite mode */
	                if (keep == UPDATE)
	                {
	                  FILETIME ftm_a;
                      HANDLE h;
                      WIN32_FIND_DATA ffData;
 
	                  cnv_tar2win_time(tartime, &ftm_a); /* archive file time */
	                  h = FindFirstFile(fname, &ffData); /* existing file time */

                      if (h!=INVALID_HANDLE_VALUE)
                        FindClose(h);  /* cleanup search handle */
                      else
                        goto ERR_OPENING;

                      /* compare date+times, is one in tarball newer? */
                      if (*((LONGLONG *)&ftm_a) > *((LONGLONG *)&(ffData.ftLastWriteTime)))
                      {
                        outfile = CreateFile(fname,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
                        if (outfile == INVALID_HANDLE_VALUE) goto ERR_OPENING;
                        szMsg = szSUCMsg;
                      }
	                }
	              }
	              else /* in overwrite mode or failed for some other error than exists */
	              {
                    ERR_OPENING:
	                PrintMessage(_T("%s%s [%d]"), szERRMsg, fname, GetLastError());
	                cm_cleanup(cm);
	                return -2;
	              }
	            }

 	            /* Inform user of current extraction action (writing, skipping file XYZ) */
	            PrintMessage(_T("%s%s"), szMsg, fname);
				}
	          }
	      }
	      else
	          outfile = INVALID_HANDLE_VALUE;

	      /*
	       * could have no contents, in which case we close the file and set the times
	       */
	      if (remaining > 0)
	          getheader = 0;
		  else
	      {
	          setTimeAndCloseFile:
	          getheader = 1;
	          if (outfile != INVALID_HANDLE_VALUE)
	          {
	              FILETIME ftm;
 
	              cnv_tar2win_time(tartime, &ftm);
	              SetFileTime(outfile,&ftm,NULL,&ftm);
	              CloseHandle(outfile);
	              outfile = INVALID_HANDLE_VALUE;
	          }
		  }

	      break;
		case GNUTYPE_LONGLINK:
		case GNUTYPE_LONGNAME:
		{
	      remaining = getoct(buffer.header.size,12);
	      if (readBlock(cm, fname) < 0) return -1;
	      fname[BLOCKSIZE-1] = '\0';
	      if ((remaining >= BLOCKSIZE) || ((unsigned)strlen(fname) > remaining))
	      {
	          PrintMessage(_T("tgz_extract: invalid long name"));
	          cm_cleanup(cm);
	          return -1;
	      }
	      getheader = 2;
	      break;
		}
        default:
/*
	      if (action == TGZ_LIST)
	          printf(" %s     <---> %s\n",strtime(&tartime),fname);
*/
	      break;
      }
    }
    else  /* (getheader == 0) */
    {
      unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
	  unsigned long bwritten;

      if (outfile != INVALID_HANDLE_VALUE)
      {
          WriteFile(outfile,buffer.buffer,bytes,&bwritten,NULL);
		  if (bwritten != bytes)
          {
			  PrintMessage(_T("Error: write failed for %s"), fname);
              CloseHandle(outfile);
              DeleteFile(fname);

              cm_cleanup(cm);
              return -2;
          }
      }
      remaining -= bytes;
      if (remaining == 0) goto setTimeAndCloseFile;
    }
  } /* while(1) */
  
  cm_cleanup(cm);

  return 0;
}