⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cabinet.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 3 页
字号:
			  wcscpy( Search->Cabinet, CabinetName );
			  
			  if (DiskChangeHandler != NULL)
				{
				  DiskChangeHandler(CabinetNext, DiskNext);
				}
			  
			  Status = CabinetOpen();
			  if (Status != CAB_STATUS_SUCCESS) 
				return Status;

			}
		  else
			{
			  return CAB_STATUS_NOFILE;
			}
		  // starting new search or cabinet
		  Search->File = (PCFFILE)(FileBuffer + PCABHeader->FileTableOffset);
		  Search->Index = 0;
		  Prev = 0;
		}
	  else Search->File = (PCFFILE)(strchr( (char *)(Search->File + 1), 0 ) + 1);
	}
  DPRINT( "Found file %s\n", Search->File->FileName );
  return CAB_STATUS_SUCCESS;
}


int Validate()
{
  return (int)RtlValidateHeap(ProcessHeap, 0, 0);
}

ULONG CabinetExtractFile( PCAB_SEARCH Search )
/*
 * FUNCTION: Extracts a file from the cabinet
 * ARGUMENTS:
 *     Search = Pointer to PCAB_SEARCH structure used to locate the file
 * RETURNS
 *     Status of operation
 */
{
  ULONG Size;                // remaining file bytes to decompress
  ULONG CurrentOffset;       // current uncompressed offset within the folder
  PUCHAR CurrentBuffer;      // current pointer to compressed data in the block
  LONG RemainingBlock;       // remaining comp data in the block
  HANDLE DestFile;
  HANDLE DestFileSection;
  PVOID DestFileBuffer;      // mapped view of dest file
  PVOID CurrentDestBuffer;   // pointer to the current position in the dest view
  PCFDATA CFData;            // current data block
  ULONG Status;
  FILETIME FileTime;
  WCHAR DestName[MAX_PATH];
  NTSTATUS NtStatus;
  UNICODE_STRING UnicodeString;
  ANSI_STRING AnsiString;
  IO_STATUS_BLOCK IoStatusBlock;
  OBJECT_ATTRIBUTES ObjectAttributes;
  FILE_BASIC_INFORMATION FileBasic;
  PCFFOLDER CurrentFolder;
  LARGE_INTEGER MaxDestFileSize;
  LONG InputLength, OutputLength;
  char Junk[512];

  if( wcscmp( Search->Cabinet, CabinetName ) != 0 )
	{
	  // the file is not in the current cabinet
	  DPRINT( "File is not in this cabinet ( %S != %S )\n", Search->Cabinet, CabinetName );
	  return CAB_STATUS_NOFILE;
	}
  // look up the folder that the file specifies
  if( Search->File->FolderIndex == 0xFFFD || Search->File->FolderIndex == 0xFFFF )
	{
	  // folder is continued from previous cabinet, that shouldn't happen here
	  return CAB_STATUS_NOFILE;
	}
  else if( Search->File->FolderIndex == 0xFFFE )
	{
	  // folder is the last in this cabinet and continues into next
	  CurrentFolder = &CabinetFolders[PCABHeader->FolderCount-1];
	}
  else {
	// folder is completely contained within this cabinet
	CurrentFolder = &CabinetFolders[Search->File->FolderIndex];
  }
  switch (CurrentFolder->CompressionType & CAB_COMP_MASK)
    {
	case CAB_COMP_NONE:
	  CabinetSelectCodec(CAB_CODEC_RAW);
	  break;
	case CAB_COMP_MSZIP:
	  CabinetSelectCodec(CAB_CODEC_MSZIP);
	  break;
	default:
	  return CAB_STATUS_UNSUPPCOMP;
    }
  
  DPRINT("Extracting file at uncompressed offset (0x%X)  Size (%d bytes)).\n",
		 (UINT)Search->File->FileOffset,
		 (UINT)Search->File->FileSize);
  RtlInitAnsiString( &AnsiString, Search->File->FileName );
  wcscpy( DestName, DestPath );
  UnicodeString.MaximumLength = sizeof( DestName ) - wcslen( DestName );
  UnicodeString.Buffer = DestName + wcslen( DestName );
  UnicodeString.Length = 0;
  RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );

  /* Create destination file, fail if it already exists */
  RtlInitUnicodeString(&UnicodeString,
					   DestName);


  InitializeObjectAttributes(&ObjectAttributes,
							 &UnicodeString,
							 OBJ_CASE_INSENSITIVE,
							 NULL,
							 NULL);

  NtStatus = NtCreateFile(&DestFile,
						  GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
						  &ObjectAttributes,
						  &IoStatusBlock,
						  NULL,
						  FILE_ATTRIBUTE_NORMAL,
						  0,
						  FILE_CREATE,
						  FILE_SYNCHRONOUS_IO_NONALERT,
						  NULL,
						  0);
  if (!NT_SUCCESS(NtStatus))
    {
      DPRINT("NtCreateFile() failed (%S) (%x).\n", DestName, NtStatus);

      /* If file exists, ask to overwrite file */
      if (OverwriteHandler == NULL || OverwriteHandler(Search->File, DestName))
        {
          /* Create destination file, overwrite if it already exists */
          NtStatus = NtCreateFile(&DestFile,
								  GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
								  &ObjectAttributes,
								  &IoStatusBlock,
								  NULL,
								  FILE_ATTRIBUTE_NORMAL,
								  0,
								  FILE_OVERWRITE,
								  FILE_SYNCHRONOUS_IO_ALERT,
								  NULL,
								  0);
          if (!NT_SUCCESS(NtStatus))
            {
              DPRINT("NtCreateFile() failed 2 (%S) (%x).\n", DestName, NtStatus);
              return CAB_STATUS_CANNOT_CREATE;
            }
        }
      else
        {
          DPRINT("File (%S) exists.\n", DestName);
          return CAB_STATUS_FILE_EXISTS;
        }
    }
  MaxDestFileSize.QuadPart = Search->File->FileSize;
  NtStatus = NtCreateSection(&DestFileSection,
							 SECTION_ALL_ACCESS,
							 0,
							 &MaxDestFileSize,
							 PAGE_READWRITE,
							 SEC_COMMIT,
							 DestFile);
  if(!NT_SUCCESS(NtStatus))
	{
	  DPRINT("NtCreateSection failed: %x\n", NtStatus);
	  Status = CAB_STATUS_NOMEMORY;
	  goto CloseDestFile;
	}
  DestFileBuffer = 0;
  DestFileSize = 0;
  NtStatus = NtMapViewOfSection(DestFileSection,
								NtCurrentProcess(),
								&DestFileBuffer,
								0,
								0,
								0,
								&DestFileSize,
								ViewUnmap,
								0,
								PAGE_READWRITE);
  if(!NT_SUCCESS(NtStatus))
	{
	  DPRINT("NtMapViewOfSection failed: %x\n", NtStatus);
	  Status = CAB_STATUS_NOMEMORY;
	  goto CloseDestFileSection;
	}
  CurrentDestBuffer = DestFileBuffer;
  if (!ConvertDosDateTimeToFileTime(Search->File->FileDate, Search->File->FileTime, &FileTime))
    {
      DPRINT("DosDateTimeToFileTime() failed.\n");
      Status = CAB_STATUS_CANNOT_WRITE;
	  goto UnmapDestFile;
    }

  NtStatus = NtQueryInformationFile(DestFile,
									&IoStatusBlock,
									&FileBasic,
									sizeof(FILE_BASIC_INFORMATION),
									FileBasicInformation);
  if (!NT_SUCCESS(NtStatus))
    {
      DPRINT("NtQueryInformationFile() failed (%x).\n", NtStatus);
    }
  else
    {
      memcpy(&FileBasic.LastAccessTime, &FileTime, sizeof(FILETIME));
	  
      NtStatus = NtSetInformationFile(DestFile,
									  &IoStatusBlock,
									  &FileBasic,
									  sizeof(FILE_BASIC_INFORMATION),
									  FileBasicInformation);
      if (!NT_SUCCESS(NtStatus))
        {
          DPRINT("NtSetInformationFile() failed (%x).\n", NtStatus);
        }
    }

  SetAttributesOnFile(Search->File, DestFile);
  
  /* Call extract event handler */
  if (ExtractHandler != NULL)
    {
      ExtractHandler(Search->File, DestName);
    }
  // find the starting block of the file
  // start with the first data block of the folder
  CFData = (PCFDATA)(CabinetFolders[Search->File->FolderIndex].DataOffset + FileBuffer);
  CurrentOffset = 0;
  while( CurrentOffset + CFData->UncompSize <= Search->File->FileOffset )
	{
	  // walk the data blocks until we reach the one containing the start of the file
	  CurrentOffset += CFData->UncompSize;
	  CFData = (PCFDATA)((char *)(CFData+1) + DataReserved + CFData->CompSize);
	}
  // now decompress and discard any data in the block before the start of the file
  CurrentBuffer = ((unsigned char *)(CFData+1)) + DataReserved; // start of comp data
  RemainingBlock = CFData->CompSize;
  InputLength = RemainingBlock;
  while( CurrentOffset < Search->File->FileOffset )
	{
	  // compute remaining uncomp bytes to start of file, bounded by sizeof junk
	  OutputLength = Search->File->FileOffset - CurrentOffset;
	  if( OutputLength > (LONG)sizeof( Junk ) )
		OutputLength = sizeof( Junk );
	  OutputLength = -OutputLength;     // negate to signal NOT end of block
	  CodecUncompress( Junk,
					   CurrentBuffer,
					   &InputLength,
					   &OutputLength );
	  CurrentOffset += OutputLength;   // add the uncomp bytes extracted to current folder offset
	  CurrentBuffer += InputLength;    // add comp bytes consumed to CurrentBuffer
	  RemainingBlock -= InputLength;   // subtract bytes consumed from bytes remaining in block
	  InputLength = -RemainingBlock;   // neg for resume decompression of the same block
	}
  // now CurrentBuffer points to the first comp byte of the file, so we can begin decompressing
  
  Size = Search->File->FileSize;   // Size = remaining uncomp bytes of the file to decompress
  while(Size > 0)
    {
	  OutputLength = Size;
	  DPRINT( "Decompressing block at %x with RemainingBlock = %d, Size = %d\n", CurrentBuffer, RemainingBlock, Size );
	  Status = CodecUncompress(CurrentDestBuffer,
							   CurrentBuffer,
							   &InputLength,
							   &OutputLength);
	  if (Status != CS_SUCCESS)
		{
		  DPRINT("Cannot uncompress block.\n");
		  if(Status == CS_NOMEMORY)
			Status = CAB_STATUS_NOMEMORY;
		  Status = CAB_STATUS_INVALID_CAB;
		  goto UnmapDestFile;
		}
	  CurrentDestBuffer = (PVOID)((ULONG_PTR)CurrentDestBuffer + OutputLength);  // advance dest buffer by bytes produced
	  CurrentBuffer += InputLength;       // advance src buffer by bytes consumed
	  Size -= OutputLength;               // reduce remaining file bytes by bytes produced
	  RemainingBlock -= InputLength;      // reduce remaining block size by bytes consumed
	  if( RemainingBlock == 0 )
		{
		  // used up this block, move on to the next
		  DPRINT( "Out of block data\n" );
		  CFData = (PCFDATA)CurrentBuffer;
		  RemainingBlock = CFData->CompSize;
		  CurrentBuffer = ((unsigned char *)(CFData+1) + DataReserved);
		  InputLength = RemainingBlock;
		}
	}
  Status = CAB_STATUS_SUCCESS;
 UnmapDestFile:
  NtUnmapViewOfSection(NtCurrentProcess(), DestFileBuffer);
 CloseDestFileSection:
  NtClose(DestFileSection);
 CloseDestFile:
  NtClose(DestFile);

  return Status;
}


VOID
CabinetSelectCodec(ULONG Id)
/*
 * FUNCTION: Selects codec engine to use
 * ARGUMENTS:
 *     Id = Codec identifier
 */
{
  if (CodecSelected)
    {
      if (Id == CodecId)
        return;

      CodecSelected = FALSE;
    }

  switch (Id)
    {
      case CAB_CODEC_RAW:
        CodecUncompress = RawCodecUncompress;
        break;
      case CAB_CODEC_MSZIP:
        CodecUncompress = MSZipCodecUncompress;
        break;
      default:
        return;
    }

  CodecId = Id;
  CodecSelected = TRUE;
}


VOID
CabinetSetEventHandlers(PCABINET_OVERWRITE Overwrite,
  PCABINET_EXTRACT Extract,
  PCABINET_DISK_CHANGE DiskChange)
/*
 * FUNCTION: Set event handlers
 * ARGUMENTS:
 *     Overwrite = Handler called when a file is to be overwritten
 *     Extract = Handler called when a file is to be extracted
 *     DiskChange = Handler called when changing the disk
 */
{
  OverwriteHandler = Overwrite;
  ExtractHandler = Extract;
  DiskChangeHandler = DiskChange;
}


PVOID
CabinetGetCabinetReservedArea(PULONG Size)
/*
 * FUNCTION: Get pointer to cabinet reserved area. NULL if none
 */
{
  if (CabinetReservedArea != NULL)
    {
      if (Size != NULL)
        {
          *Size = CabinetReserved;
        }
      return CabinetReservedArea;
    }
  else
    {
      if (Size != NULL)
        {
          *Size = 0;
        }
      return NULL;
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -