windows-nt/Source/XPSP1/NT/sdktools/windiff/server/file.c
2020-09-26 16:20:57 +08:00

252 lines
6.4 KiB
C

/*
* file.c
*
* send files on request over a named pipe.
*
* supports requests to package up a file and send it over a named pipe.
*
* Geraint Davies, August 92
*/
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "sumserve.h"
#include "errlog.h"
#include "server.h"
BOOL ss_compress(PSTR original, PSTR compressed);
ULONG ss_checksum_block(PSTR block, int size);
extern BOOL bNoCompression; /* imported from sumserve.c Read only here */
/*
* given a pathname to a file, read the file, compress it package it up
* into SSPACKETs and send these via ss_sendblock to the named pipe.
*
*
* each packet has a sequence number. if we can't read the file, we send
* a single packet with sequence -1. otherwise, we carry on until we run out
* of data, then we send a packet with 0 size.
*/
void
ss_sendfile(HANDLE hpipe, LPSTR file, LONG lVersion)
{
SSPACKET packet;
HANDLE hfile;
int size;
char szTempname[MAX_PATH];
PSSATTRIBS attribs;
BY_HANDLE_FILE_INFORMATION bhfi;
dprintf1(("getting '%s' for %8x\n", file, hpipe));
/*
* get the file attributes first
*/
hfile = CreateFile(file, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hfile == INVALID_HANDLE_VALUE) {
/* report that we could not read the file */
packet.lSequence = -1;
ss_sendblock(hpipe, (PSTR) &packet, sizeof(packet));
DeleteFile(szTempname);
return;
}
/*
* seems to be a bug in GetFileInformationByHandle if the
* file is not on local machine - so avoid it.
*/
bhfi.dwFileAttributes = GetFileAttributes(file);
GetFileTime(hfile, &bhfi.ftCreationTime,
&bhfi.ftLastAccessTime, &bhfi.ftLastWriteTime);
CloseHandle(hfile);
/* create temp filename */
GetTempPath(sizeof(szTempname), szTempname);
GetTempFileName(szTempname, "sum", 0, szTempname);
/* compress the file into this temporary file */
if (bNoCompression || (!ss_compress(file, szTempname))) {
/* try to open the original file */
hfile = CreateFile(file, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
dprintf1(("sending original file to %8x\n", hpipe));
} else {
/* open temp (compressed) file and send this */
hfile = CreateFile(szTempname, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
dprintf1(("sending compressed file to %8x\n", hpipe));
}
if (hfile == INVALID_HANDLE_VALUE) {
/* report that we could not read the file */
packet.lSequence = -1;
ss_sendblock(hpipe, (PSTR) &packet, sizeof(packet));
DeleteFile(szTempname);
return;
}
/* loop reading blocks of the file */
for (packet.lSequence = 0; ; packet.lSequence++) {
if(!ReadFile(hfile, packet.Data, sizeof(packet.Data), (LPDWORD)(&size), NULL)) {
/* error reading file. send a -1 packet to
* indicate this
*/
packet.lSequence = -1;
ss_sendblock(hpipe, (PSTR) &packet, sizeof(packet));
break;
}
packet.ulSize = size;
if (lVersion==0)
packet.ulSum = ss_checksum_block(packet.Data, size);
else
packet.ulSum = 0; /* checksum was compute-bound and overkill */
if (size == 0) {
/*
* in the last block, in the Data[] field,
* we place a SSATTRIBS struct with the file
* times and attribs
*/
attribs = (PSSATTRIBS) packet.Data;
attribs->fileattribs = bhfi.dwFileAttributes;
attribs->ft_create = bhfi.ftCreationTime;
attribs->ft_lastaccess = bhfi.ftLastAccessTime;
attribs->ft_lastwrite = bhfi.ftLastWriteTime;
}
if (!ss_sendblock(hpipe, (PSTR) &packet, sizeof(packet))) {
dprintf1(("connection to %8x lost during copy\n", hpipe));
break;
}
if (size == 0) {
/* end of file */
break;
}
}
CloseHandle(hfile);
DeleteFile(szTempname);
return;
}
/*
* compress a file. original is the pathname of the original file,
* compressed is the pathname of the output compressed file.
*
* spawns a copy of compress.exe to compress the file, and waits for
* it to complete successfully.
*/
BOOL
ss_compress(PSTR original, PSTR compressed)
{
char szCmdLine[MAX_PATH * 2];
STARTUPINFO si;
PROCESS_INFORMATION pi;
DWORD exitcode;
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = NULL;
si.lpReserved = NULL;
si.lpReserved2 = NULL;
si.cbReserved2 = 0;
si.lpTitle = "Sumserve Compression";
si.dwFlags = STARTF_FORCEOFFFEEDBACK;
sprintf(szCmdLine, "compress %s %s", original, compressed);
if (!CreateProcess(NULL,
szCmdLine,
NULL,
NULL,
FALSE,
DETACHED_PROCESS |
NORMAL_PRIORITY_CLASS, //??? Can't we silence the console?
NULL,
NULL,
&si,
&pi)) {
return(FALSE);
}
/* wait for completion. */
WaitForSingleObject(pi.hProcess, INFINITE);
if (!GetExitCodeProcess(pi.hProcess, &exitcode)) {
return(FALSE);
}
/* close process and thread handles */
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
if (exitcode != 0) {
dprintf1(("compress exit code %ld\n", exitcode));
return(FALSE);
} else {
return(TRUE);
}
} /* ss_compress */
/* produce a checksum of a block of data.
*
* This is undoubtedly a good checksum algorithm, but it's also compute bound.
* For version 1 we turn it off. If we decide in version 2 to turn it back
* on again then we will use a faster algorithm (e.g. the one used to checksum
* a whole file.
*
* Generate checksum by the formula
* checksum = SUM( rnd(i)*(1+byte[i]) )
* where byte[i] is the i-th byte in the file, counting from 1
* rnd(x) is a pseudo-random number generated from the seed x.
*
* Adding 1 to byte ensures that all null bytes contribute, rather than
* being ignored. Multiplying each such byte by a pseudo-random
* function of its position ensures that "anagrams" of each other come
* to different sums. The pseudorandom function chosen is successive
* powers of 1664525 modulo 2**32. 1664525 is a magic number taken
* from Donald Knuth's "The Art Of Computer Programming"
*/
ULONG
ss_checksum_block(PSTR block, int size)
{
unsigned long lCheckSum = 0; /* grows into the checksum */
const unsigned long lSeed = 1664525; /* seed for random Knuth */
unsigned long lRand = 1; /* seed**n */
unsigned long lIndex = 1; /* byte number in block */
unsigned Byte; /* next byte to process in buffer */
unsigned length; /* unsigned copy of size */
length = size;
for (Byte = 0; Byte < length ;++Byte, ++lIndex) {
lRand = lRand*lSeed;
lCheckSum += lIndex*(1+block[Byte])*lRand;
}
return(lCheckSum);
} /* ss_checksum_block */