mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
378 lines
9.1 KiB
378 lines
9.1 KiB
/*
|
|
* Copyright (c) 1993 Microsoft Corporation
|
|
*
|
|
* FORKIZE.C
|
|
*
|
|
* This tool is for use in conjunction with the Windows NT Services for
|
|
* Macintosh File Server. Given the filename of a PC file (FAT/HPFS/NTFS)
|
|
* representing the resource fork, and filename representing the data fork
|
|
* for a Macintosh style file, combine the 2 files into the format used by
|
|
* the Services for Macintosh file server in order to share the file with
|
|
* Macintosh clients in a format they can access. Optionally a Macintosh style
|
|
* type and creator can be specified to be added to the Finder Info for
|
|
* the file. If no data fork file is given, a zero length data fork is added
|
|
* to the file. If no resource fork file is given, no resource fork is added.
|
|
*
|
|
*
|
|
* Revision History:
|
|
* 07/93 Sue Adams - initial version for use with Windows NT 3.1
|
|
* Services for Macintosh AFP server
|
|
*
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
|
|
#define AFP_SERVER_SIGNATURE *(PDWORD)"AFP"
|
|
#define AFP_SERVER_VERSION 0x00010000
|
|
#define BEGINNING_OF_TIME 0x80000000
|
|
|
|
|
|
typedef ULONG DWORD, *PDWORD;
|
|
|
|
#ifndef BYTE
|
|
typedef UCHAR BYTE;
|
|
typedef BYTE *PBYTE;
|
|
typedef BYTE *LPBYTE;
|
|
#endif
|
|
|
|
|
|
// Mac Finder Information layout
|
|
|
|
// see pg. 9-37 of Inside Macintosh vol. 6
|
|
#define FINDER_FLAG_INVISIBLE 0x40 // fd_Attr1
|
|
#define FINDER_FLAG_SET 0x01 // fd_Attr1
|
|
|
|
|
|
#define FINDER_INFO_SIZE 32
|
|
typedef struct
|
|
{
|
|
BYTE fd_Type[4];
|
|
BYTE fd_Creator[4];
|
|
BYTE fd_Attr1; // Bits 8-15
|
|
BYTE fd_Attr2; // Bits 0-7
|
|
BYTE fd_Location[4];
|
|
BYTE fd_FDWindow[2];
|
|
BYTE fd_OtherStuff[16];
|
|
} FINDERINFO, *PFINDERINFO;
|
|
|
|
// Apple-II (ProDOS) information.
|
|
|
|
// default values for newly discovered items
|
|
#define PRODOS_TYPE_FILE 0x04 // corresponds to finder fdType 'TEXT'
|
|
#define PRODOS_TYPE_DIR 0x0F
|
|
#define PRODOS_AUX_DIR 0x02 // actually 0x0200
|
|
|
|
// some other finder fdType to prodos FileType mapping values
|
|
#define PRODOS_FILETYPE_PSYS 0xFF
|
|
#define PRODOS_FILETYPE_PS16 0xB3
|
|
|
|
#define PRODOS_INFO_SIZE 6
|
|
typedef struct
|
|
{
|
|
BYTE pd_FileType[2];
|
|
BYTE pd_AuxType[4];
|
|
} PRODOSINFO, *PPRODOSINFO;
|
|
|
|
// Directory Access Permissions
|
|
#define DIR_ACCESS_SEARCH 0x01 // See Folders
|
|
#define DIR_ACCESS_READ 0x02 // See Files
|
|
#define DIR_ACCESS_WRITE 0x04 // Make Changes
|
|
#define DIR_ACCESS_OWNER 0x80 // Only for user
|
|
// if he has owner rights
|
|
|
|
typedef struct _AfpInfo
|
|
{
|
|
DWORD afpi_Signature; // Signature
|
|
LONG afpi_Version; // Version
|
|
DWORD afpi_Id; // AFP File or directory Id
|
|
DWORD afpi_BackupTime; // Backup time for the file/dir
|
|
// (Volume backup time is stored
|
|
// in the AFP_IdIndex stream)
|
|
|
|
FINDERINFO afpi_FinderInfo; // Finder Info (32 bytes)
|
|
PRODOSINFO afpi_ProDosInfo; // ProDos Info (6 bytes)
|
|
|
|
USHORT afpi_Attributes; // Attributes mask (maps ReadOnly)
|
|
|
|
BYTE afpi_AccessOwner; // Access mask (SFI vs. SFO)
|
|
BYTE afpi_AccessGroup; // Directories only
|
|
BYTE afpi_AccessWorld;
|
|
} AFPINFO, *PAFPINFO;
|
|
|
|
//
|
|
// Initialize a AFPINFO structure with default values
|
|
//
|
|
// VOID
|
|
// AfpInitAfpInfo(
|
|
// IN PAFPINFO pAfpInfo,
|
|
// IN DWORD AfpId OPTIONAL, // 0 if we don't yet know the AFP Id
|
|
// IN BOOLEAN IsDir
|
|
// )
|
|
//
|
|
#define AfpInitAfpInfo(pAfpInfo,AfpId,IsDir) \
|
|
RtlZeroMemory(pAfpInfo,sizeof(AFPINFO)); \
|
|
(pAfpInfo)->afpi_Signature = AFP_SERVER_SIGNATURE; \
|
|
(pAfpInfo)->afpi_Version = AFP_SERVER_VERSION; \
|
|
(pAfpInfo)->afpi_BackupTime = BEGINNING_OF_TIME; \
|
|
(pAfpInfo)->afpi_Id = AfpId; \
|
|
(pAfpInfo)->afpi_Attributes = 0; \
|
|
if (IsDir) \
|
|
{ \
|
|
(pAfpInfo)->afpi_AccessOwner = DIR_ACCESS_READ | DIR_ACCESS_SEARCH; \
|
|
(pAfpInfo)->afpi_AccessGroup = DIR_ACCESS_READ | DIR_ACCESS_SEARCH; \
|
|
(pAfpInfo)->afpi_AccessWorld = DIR_ACCESS_READ | DIR_ACCESS_SEARCH; \
|
|
(pAfpInfo)->afpi_ProDosInfo.pd_FileType[0] = PRODOS_TYPE_DIR;\
|
|
(pAfpInfo)->afpi_ProDosInfo.pd_AuxType[1] = PRODOS_AUX_DIR;\
|
|
} \
|
|
else \
|
|
{ \
|
|
(pAfpInfo)->afpi_ProDosInfo.pd_FileType[0] = PRODOS_TYPE_FILE; \
|
|
}
|
|
|
|
BYTE Buffer[1024 * 16];
|
|
AFPINFO AfpInfo;
|
|
WCHAR wchResource[256+1], wchDataFile[256+1], wchTarget[256+1];
|
|
WCHAR wchStream[256+20];
|
|
DWORD Options = 0;
|
|
CHAR * Usage = "\n\tUsage: forkize \n\t/t <type> \n\t/c <creator> \n\t/d <data file path> \n\t/r <resource file path> \n\t/o <target file path>\n";
|
|
|
|
#define AFP_RESC_STREAM L":AFP_Resource"
|
|
#define AFP_INFO_STREAM L":AFP_AfpInfo"
|
|
|
|
|
|
#define TYPE 0x01
|
|
#define CREATOR 0x02
|
|
#define DATA 0x04
|
|
#define RESOURCE 0x08
|
|
#define TARGET 0x10
|
|
|
|
BOOLEAN IsTargetNTFS(HANDLE);
|
|
ULONG CopyStream(HANDLE, HANDLE);
|
|
|
|
int
|
|
GetOptions(
|
|
int argc,
|
|
char ** argv
|
|
)
|
|
{
|
|
int i;
|
|
|
|
AfpInitAfpInfo(&AfpInfo, 0, FALSE);
|
|
|
|
i = 1;
|
|
while (i < argc)
|
|
{
|
|
if ((_strnicmp(argv[i], "/t", 2) == 0))
|
|
{
|
|
// pad the type with spaces
|
|
memcpy(AfpInfo.afpi_FinderInfo.fd_Type, " ", 4);
|
|
memcpy(AfpInfo.afpi_FinderInfo.fd_Type, argv[i+1], strlen(argv[i+1]));
|
|
Options |= TYPE;
|
|
i += 2;
|
|
}
|
|
else if ((_strnicmp(argv[i], "/c", 2) == 0))
|
|
{
|
|
// pad the creator with spaces
|
|
memcpy(AfpInfo.afpi_FinderInfo.fd_Creator, " ", 4);
|
|
memcpy(AfpInfo.afpi_FinderInfo.fd_Creator, argv[i+1], strlen(argv[i+1]));
|
|
Options |= CREATOR;
|
|
i += 2;
|
|
}
|
|
else if ((_strnicmp(argv[i], "/r", 2) == 0))
|
|
{
|
|
mbstowcs(wchResource, argv[i+1], strlen(argv[i+1])+1);
|
|
Options |= RESOURCE;
|
|
i += 2;
|
|
}
|
|
else if ((_strnicmp(argv[i], "/d", 2) == 0))
|
|
{
|
|
mbstowcs(wchDataFile, argv[i+1], strlen(argv[i+1])+1);
|
|
Options |= DATA;
|
|
i += 2;
|
|
}
|
|
else if ((_strnicmp(argv[i], "/o", 2) == 0))
|
|
{
|
|
mbstowcs(wchTarget, argv[i+1], strlen(argv[i+1])+1);
|
|
Options |= TARGET;
|
|
i += 2;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "%s", Usage);
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if (!(Options & TARGET) ||
|
|
(!(Options & (DATA | RESOURCE))))
|
|
#endif
|
|
if (!(Options & TARGET))
|
|
{
|
|
fprintf(stderr, "%s", Usage);
|
|
exit(0);
|
|
}
|
|
|
|
#if 0
|
|
printf("\nData file: %ws\n", wchDataFile);
|
|
printf("Resource file: %ws\n", wchResource);
|
|
printf("Target file: %ws\n", wchTarget);
|
|
#endif
|
|
return (1);
|
|
}
|
|
|
|
|
|
|
|
VOID _cdecl
|
|
main(
|
|
int argc,
|
|
char ** argv
|
|
)
|
|
{
|
|
DWORD Status, bytesWritten;
|
|
HANDLE hTarget, hDataSrc, hResourceSrc;
|
|
|
|
if (!GetOptions(argc, argv))
|
|
return;
|
|
|
|
hTarget = CreateFile(wchTarget, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hTarget == INVALID_HANDLE_VALUE)
|
|
{
|
|
Status = GetLastError();
|
|
fprintf(stderr, "Could not create target file (%d)\n", Status);
|
|
exit(0);
|
|
}
|
|
|
|
if (!IsTargetNTFS(hTarget))
|
|
{
|
|
CloseHandle(hTarget);
|
|
exit(0);
|
|
}
|
|
|
|
// open the data source file if one was specified
|
|
if (Options & DATA)
|
|
{
|
|
hDataSrc = CreateFile(wchDataFile, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hDataSrc == INVALID_HANDLE_VALUE)
|
|
{
|
|
Status = GetLastError();
|
|
CloseHandle(hTarget);
|
|
fprintf(stderr, "Could not open source data file (%d)\n", Status);
|
|
exit(0);
|
|
}
|
|
|
|
// Read the source data and write it to target data stream
|
|
printf("\nData target is %ws\n", wchTarget);
|
|
Status = CopyStream(hDataSrc, hTarget);
|
|
|
|
CloseHandle(hDataSrc);
|
|
}
|
|
|
|
CloseHandle(hTarget);
|
|
|
|
// open the resource source file if one was specified
|
|
if (Options & RESOURCE)
|
|
{
|
|
hResourceSrc = CreateFile(wchResource, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hResourceSrc == INVALID_HANDLE_VALUE)
|
|
{
|
|
Status = GetLastError();
|
|
fprintf(stderr, "Could not open source resource file (%d)\n", Status);
|
|
exit(0);
|
|
}
|
|
|
|
// Open the target resource fork
|
|
wcscpy(wchStream, wchTarget);
|
|
wcscat(wchStream, AFP_RESC_STREAM);
|
|
printf("\nResource target is %ws\n", wchStream);
|
|
|
|
hTarget = CreateFile(wchStream, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hTarget == INVALID_HANDLE_VALUE)
|
|
{
|
|
Status = GetLastError();
|
|
CloseHandle(hResourceSrc);
|
|
fprintf(stderr, "Could not create target resource fork (%d)\n", Status);
|
|
exit(0);
|
|
}
|
|
// Read the source resource and write it to target resource stream
|
|
Status = CopyStream(hResourceSrc, hTarget);
|
|
|
|
CloseHandle(hResourceSrc);
|
|
CloseHandle(hTarget);
|
|
}
|
|
|
|
if (Options & (TYPE | CREATOR))
|
|
{
|
|
// Open the target AfpInfo stream
|
|
wcscpy(wchStream, wchTarget);
|
|
wcscat(wchStream, AFP_INFO_STREAM);
|
|
printf("\nFinderInfo target is %ws\n", wchStream);
|
|
|
|
hTarget = CreateFile(wchStream, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hTarget == INVALID_HANDLE_VALUE)
|
|
{
|
|
Status = GetLastError();
|
|
fprintf(stderr, "Could not create target AfpInfo stream (%d)\n", Status);
|
|
exit(0);
|
|
}
|
|
|
|
if (!WriteFile(hTarget, &AfpInfo, sizeof(AfpInfo), &bytesWritten, NULL))
|
|
{
|
|
Status = GetLastError();
|
|
fprintf(stderr, "Could not write AFP_AfpInfo stream (%d)\n", Status);
|
|
}
|
|
|
|
CloseHandle(hTarget);
|
|
}
|
|
|
|
}
|
|
|
|
DWORD CopyStream(
|
|
IN HANDLE hSrc,
|
|
IN HANDLE hDst
|
|
)
|
|
{
|
|
DWORD bytesread, byteswritten, Status = NO_ERROR;
|
|
|
|
do
|
|
{
|
|
bytesread = byteswritten = 0;
|
|
|
|
// read from src, write to dst
|
|
if (ReadFile(hSrc, Buffer, sizeof(Buffer), &bytesread, NULL))
|
|
{
|
|
if (bytesread == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = GetLastError();
|
|
break;
|
|
}
|
|
|
|
if (!WriteFile(hDst, Buffer, bytesread, &byteswritten, NULL))
|
|
{
|
|
Status = GetLastError();
|
|
break;
|
|
}
|
|
|
|
} while (TRUE);
|
|
|
|
return(Status);
|
|
}
|