macemu/BasiliskII/src/Windows/posix_emu.cpp

1160 lines
39 KiB
C++
Executable File

/*
* posix_emu.cpp -- posix and virtual desktop
*
* Basilisk II (C) 1997-2008 Christian Bauer
*
* Windows platform specific code copyright (C) Lauri Pesonen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// TODO: UNC names. Customizable "Virtual Desktop" location.
#include "sysdeps.h"
#define NO_POSIX_API_HOOK
#include "posix_emu.h"
#include "user_strings.h"
#include "util_windows.h"
#include "main.h"
#include "extfs_defs.h"
#include "prefs.h"
#include <ctype.h>
#define DEBUG_EXTFS 0
#if DEBUG_EXTFS
// This must be always on.
#define DEBUG 1
#undef OutputDebugString
#define OutputDebugString extfs_log_write
extern void extfs_log_write( char *s );
#define EXTFS_LOG_FILE_NAME "extfs.log"
#include "debug.h"
enum {
DB_EXTFS_NONE=0,
DB_EXTFS_NORMAL,
DB_EXTFS_LOUD
};
static int16 debug_extfs = DB_EXTFS_NONE;
static HANDLE extfs_log_file = INVALID_HANDLE_VALUE;
static void extfs_log_open( char *path )
{
if(debug_extfs == DB_EXTFS_NONE) return;
DeleteFile( path );
extfs_log_file = CreateFile(
path,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
// FILE_FLAG_WRITE_THROUGH|FILE_FLAG_NO_BUFFERING,
FILE_FLAG_WRITE_THROUGH,
NULL
);
if( extfs_log_file == INVALID_HANDLE_VALUE ) {
ErrorAlert( "Could not create the EXTFS log file." );
}
}
static void extfs_log_close( void )
{
if(debug_extfs == DB_EXTFS_NONE) return;
if( extfs_log_file != INVALID_HANDLE_VALUE ) {
CloseHandle( extfs_log_file );
extfs_log_file = INVALID_HANDLE_VALUE;
}
}
static void extfs_log_write( char *s )
{
DWORD bytes_written;
// should have been checked already.
if(debug_extfs == DB_EXTFS_NONE) return;
if( extfs_log_file != INVALID_HANDLE_VALUE ) {
DWORD count = strlen(s);
if (0 == WriteFile(extfs_log_file, s, count, &bytes_written, NULL) ||
(int)bytes_written != count)
{
extfs_log_close();
ErrorAlert( "extfs log file write error (out of disk space?). Log closed." );
} else {
FlushFileBuffers( extfs_log_file );
}
}
}
#else
#define DEBUG 0
#include "debug.h"
#endif // DEBUG_EXTFS
int my_errno = 0;
#define VIRTUAL_ROOT_ID ((HANDLE)0xFFFFFFFE)
static LPCTSTR desktop_name = TEXT("Virtual Desktop");
static const char *custom_icon_name = "Icon\r";
#define my_computer GetString(STR_EXTFS_VOLUME_NAME)
static TCHAR lb1[MAX_PATH_LENGTH];
static TCHAR lb2[MAX_PATH_LENGTH];
#define MRP(path) translate(path,lb1)
#define MRP2(path) translate(path,lb2)
#define DISABLE_ERRORS UINT prevmode = SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS)
#define RESTORE_ERRORS SetErrorMode(prevmode);
static TCHAR host_drive_list[512];
static TCHAR virtual_root[248]; // Not _MAX_PATH
const uint8 my_comp_icon[2670] = {
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0xD8, 0x00, 0x00, 0x08, 0xD8, 0x00, 0x00, 0x00, 0x96,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x00, 0x79, 0x79, 0x79, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xC0, 0xCC, 0xCC, 0xCC,
0xCC, 0xD7, 0x97, 0x97, 0x97, 0x97, 0x97, 0xC0, 0xC0, 0xC0, 0xC0, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0xCD, 0xDB, 0xD9, 0x79, 0x79, 0x7E, 0x79, 0x0C, 0xDD, 0xCD, 0xDD, 0xCD, 0xCD, 0xDC, 0xDD, 0xCD,
0xCC, 0xED, 0xED, 0x97, 0x97, 0x97, 0x97, 0x0C, 0xE7, 0x78, 0x77, 0x97, 0x97, 0x97, 0x97, 0x97,
0xDC, 0xED, 0xDE, 0x79, 0x79, 0x79, 0x99, 0x0C, 0xD9, 0x7E, 0x5E, 0x65, 0x5E, 0x65, 0xD9, 0x79,
0xCD, 0xDE, 0xDD, 0x97, 0xE7, 0x9E, 0x77, 0xC0, 0x97, 0x9D, 0xCD, 0xCC, 0xC7, 0xCC, 0xE7, 0x97,
0xCC, 0xED, 0xEE, 0x79, 0x79, 0x79, 0x7E, 0xCC, 0x57, 0xD5, 0xD7, 0xD5, 0xDD, 0x5D, 0xD9, 0x7E,
0xCD, 0xDE, 0xDE, 0x79, 0x97, 0x97, 0x99, 0x0C, 0x87, 0xCD, 0x75, 0xC7, 0x5C, 0x7D, 0xD9, 0x79,
0xCD, 0xDD, 0xED, 0xE7, 0x7E, 0x79, 0x77, 0xCC, 0xE7, 0xB0, 0x00, 0xC0, 0x0C, 0xCD, 0xE7, 0x97,
0xDC, 0xED, 0xEE, 0x79, 0x97, 0x86, 0x79, 0xC0, 0xE7, 0xD0, 0x2C, 0xC1, 0xC2, 0xCD, 0xD9, 0x79,
0xCD, 0xDE, 0xDD, 0x97, 0x99, 0x79, 0x97, 0x0C, 0xE7, 0xB0, 0xD0, 0xDC, 0xCC, 0xCD, 0xD6, 0x87,
0xDD, 0xDE, 0xED, 0x79, 0x77, 0xE7, 0x79, 0x0C, 0x58, 0xDC, 0x0C, 0x0C, 0xCC, 0xCD, 0xE9, 0x79,
0xCD, 0xDD, 0xD5, 0x99, 0x97, 0x99, 0x79, 0xC0, 0x87, 0xD0, 0xC0, 0xC0, 0xC0, 0xCD, 0xD7, 0xE7,
0xDD, 0xDE, 0xD7, 0x97, 0x79, 0x77, 0xE7, 0x0C, 0xE7, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x79, 0x79,
0xCD, 0xDE, 0xD9, 0x79, 0x97, 0xE9, 0x79, 0x0C, 0x97, 0x79, 0x79, 0x79, 0x79, 0x79, 0x97, 0x97,
0xDC, 0xED, 0xE7, 0x97, 0x79, 0x97, 0x97, 0x0C, 0xCD, 0xD7, 0xD7, 0xD7, 0xE7, 0xE7, 0x7E, 0x79,
0xCD, 0xDE, 0x79, 0x79, 0x97, 0x7E, 0x79, 0xC0, 0xCC, 0xCC, 0x0C, 0xCC, 0x0D, 0xCC, 0xDC, 0xDC,
0xDC, 0xED, 0x97, 0x97, 0x77, 0x99, 0x79, 0xCC, 0xCC, 0xCC, 0xDC, 0xCC, 0xDC, 0xCC, 0xCC, 0x8D,
0xCD, 0xDE, 0x79, 0x79, 0x96, 0x77, 0x97, 0x97, 0x97, 0x90, 0xCC, 0xCD, 0xCD, 0xDD, 0xDD, 0xCC,
0xDD, 0xD9, 0x76, 0x87, 0x97, 0x99, 0x7E, 0x7C, 0x0C, 0xCC, 0xDD, 0xDD, 0xED, 0xDE, 0xDD, 0xEE,
0xDE, 0xD5, 0xBD, 0xDE, 0x79, 0x79, 0x9C, 0xC0, 0xCC, 0xDD, 0xDD, 0xDD, 0xDE, 0xDD, 0xED, 0xDE,
0xDE, 0xDD, 0xDE, 0xDE, 0x79, 0x79, 0x70, 0xCD, 0xCC, 0xCC, 0xCC, 0xCC, 0xDC, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xED, 0xED, 0x97, 0x97, 0x90, 0xCC, 0x8D, 0xCC, 0xDC, 0xCD, 0xCC, 0xCC, 0xCC, 0xCC,
0xCC, 0xEE, 0xDE, 0xDE, 0x79, 0x7E, 0x70, 0xCC, 0x88, 0xDC, 0xCC, 0xCC, 0xCD, 0xDD, 0xDD, 0xDC,
0xCD, 0xDD, 0xED, 0xED, 0x97, 0x97, 0xEC, 0xCC, 0xCC, 0xCC, 0xDC, 0xCC, 0xCD, 0xDD, 0xED, 0xDD,
0xDC, 0xED, 0xED, 0xEE, 0x79, 0x79, 0xDC, 0x0D, 0xCC, 0xDC, 0xCC, 0xCD, 0xCC, 0xCC, 0xCC, 0x0C,
0xDC, 0xDE, 0xDE, 0xED, 0x97, 0xDC, 0xCC, 0xDC, 0xCD, 0xCC, 0xDC, 0xCD, 0xCC, 0xCC, 0xCD, 0xCC,
0xCC, 0xED, 0xED, 0x79, 0xDD, 0xC0, 0xCD, 0xCC, 0xDC, 0xCD, 0xCC, 0xDC, 0xCC, 0xDC, 0xDD, 0xCD,
0xCD, 0xED, 0x97, 0x97, 0xDD, 0xCC, 0xCC, 0x00, 0xC0, 0xDD, 0xCD, 0xCC, 0xCC, 0xCD, 0xD0, 0xDC,
0xDD, 0xF7, 0x99, 0x79, 0x97, 0x9D, 0xDD, 0xDD, 0xCC, 0xC0, 0xCC, 0x0C, 0xDC, 0xDC, 0xCD, 0xCD,
0xDF, 0x79, 0x77, 0x97, 0x79, 0x79, 0x79, 0x79, 0xDD, 0xDE, 0xDC, 0xCC, 0xCC, 0xC0, 0xC0, 0xDD,
0xE9, 0x79, 0x97, 0x99, 0x97, 0xE7, 0xE7, 0x97, 0x97, 0x9D, 0x79, 0xDD, 0xDD, 0xDD, 0xCD, 0xDE,
0x79, 0x79, 0x7E, 0x77, 0x00, 0x00, 0x04, 0x00, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0xF5,
0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B,
0x2B, 0x2B, 0xF9, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0xF6,
0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF7, 0xF7, 0xF7,
0xF7, 0xF8, 0x81, 0xFA, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56,
0xF7, 0xF8, 0x81, 0x81, 0x81, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xA5, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2,
0xF8, 0xF8, 0x81, 0xFA, 0xFB, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xA5, 0xC2, 0xC2, 0xFB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xFB, 0xC2, 0xC2, 0xC2,
0xF7, 0xF8, 0x81, 0x81, 0xFB, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0x2B,
0xA5, 0xC2, 0xC2, 0xFB, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x81, 0xC2, 0xC2, 0xC2,
0xF7, 0xF8, 0x81, 0x81, 0xFB, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0x2B,
0xA5, 0xC2, 0xF9, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF9, 0xFB, 0xC2, 0xC2, 0xC2,
0xF7, 0xF8, 0x81, 0x81, 0xFB, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xA5, 0xC2, 0xF9, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xF9, 0x81, 0xC2, 0xC2, 0xC2,
0xF8, 0x56, 0xFA, 0x81, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xA5, 0xC2, 0xF9, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0x2B, 0xF9, 0xFB, 0xC2, 0xC2, 0xC2,
0xF8, 0x56, 0x81, 0x81, 0xFB, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xA5, 0xC2, 0xF9, 0xF5, 0x0A, 0xF6, 0x2B, 0x0A, 0xF6, 0x0A, 0x2B, 0xF9, 0x81, 0xC2, 0xC2, 0xC2,
0xF8, 0x56, 0x81, 0x81, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xA5, 0xC2, 0xF9, 0xF5, 0xF8, 0xF6, 0x56, 0xF7, 0xF7, 0xF8, 0x2B, 0xF9, 0x81, 0xC2, 0xC2, 0xC2,
0xF8, 0x56, 0x81, 0x81, 0xFB, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xA5, 0xC2, 0xF9, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0x2B, 0x2B, 0xF9, 0xFB, 0xC2, 0xC2, 0xC2,
0xF8, 0x56, 0xFA, 0x81, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xA5, 0xC2, 0xF9, 0xF6, 0xF6, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0x2B, 0xF9, 0x81, 0xC2, 0xC2, 0xC2,
0xF8, 0x56, 0x81, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xA5, 0xC2, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xC2, 0xC2, 0xC2, 0xC2,
0xF8, 0x56, 0x81, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xA5, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2,
0xF8, 0x56, 0x81, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0xF7, 0x56, 0xF8, 0x7A, 0x7A, 0x9E, 0x9E, 0x9E, 0x9E, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2,
0xF8, 0x56, 0x81, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B,
0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF7, 0xF7, 0xF8, 0xF8,
0xF8, 0x56, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF7, 0xF7,
0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0x56, 0xB9, 0xF8,
0xF8, 0x56, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2,
0xC2, 0xC2, 0xC2, 0xF6, 0x2B, 0x2B, 0xF7, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0xF8,
0xF8, 0x56, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6,
0xF6, 0xF6, 0x2B, 0xF8, 0x56, 0xFA, 0xF9, 0x81, 0x81, 0x81, 0xFA, 0x81, 0x81, 0x81, 0xFB, 0x81,
0xFB, 0xFB, 0xFB, 0x81, 0xFA, 0xFA, 0xFA, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xF6, 0xF6,
0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFB,
0x81, 0xFB, 0xF9, 0xFA, 0xFA, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xF7,
0xF8, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF8, 0xF8, 0x56, 0x56, 0xF9, 0xF9, 0xF9, 0xFA,
0xFA, 0xFA, 0xFA, 0x81, 0x81, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xF7,
0x93, 0xA0, 0xF7, 0xF7, 0xF8, 0xF7, 0xF7, 0xF8, 0xF7, 0xF7, 0xF7, 0xF7, 0x2B, 0x2B, 0x2B, 0x2B,
0x2B, 0x2B, 0x81, 0xFB, 0x81, 0xFB, 0xFB, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xF7,
0xA0, 0xA0, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0x56, 0x56, 0xF9, 0xF9, 0xF9, 0xF8, 0xF7,
0xF7, 0xF7, 0xFB, 0xFB, 0x81, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xF7,
0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF9, 0xF9, 0xFB, 0xFB, 0xFB, 0xF8, 0xF9,
0xF9, 0xF7, 0x81, 0xFB, 0xFB, 0x81, 0xFB, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xF8, 0x2B, 0x2B, 0x56,
0x2B, 0x2B, 0xF9, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF8,
0xF8, 0xF7, 0xFB, 0xFB, 0x81, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xF8, 0xF8, 0xF6, 0xF6, 0xF9, 0xF8,
0x2B, 0xF9, 0xF8, 0x2B, 0xF9, 0x2B, 0x2B, 0xF9, 0x2B, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7,
0xF7, 0xF7, 0x81, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xF9, 0xF8, 0xF6, 0xF6, 0xF7, 0xF9, 0xF8, 0x2B,
0xF9, 0xF8, 0xF6, 0xF9, 0xF8, 0xF6, 0xF9, 0xF8, 0xF6, 0x2B, 0xF9, 0x2B, 0xF9, 0x56, 0x2B, 0xF9,
0x2B, 0xF9, 0xAC, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xFA, 0xF9, 0xF8, 0x2B, 0x2B, 0x2B, 0xF5, 0xF5,
0xF5, 0xF5, 0xF9, 0xF8, 0xF6, 0xF9, 0xF8, 0xF6, 0x2B, 0xF8, 0x2B, 0xF9, 0x56, 0x2B, 0x56, 0x2B,
0x56, 0x81, 0xAC, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xFA, 0xFA, 0xFA, 0xF9, 0xF8,
0xF8, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF5, 0x2B, 0xF9, 0xF6, 0xF9, 0xF8, 0xF7, 0xF9, 0x2B, 0xF9,
0x81, 0xAC, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2,
0xFA, 0xFA, 0xFA, 0xFA, 0xF9, 0xF8, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF5, 0xF5, 0xF5, 0x56, 0x81,
0xAC, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2,
0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xFA, 0xF9, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, 0xF8, 0x81, 0x81,
0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0x00, 0x00, 0x01, 0x00, 0x03, 0xFF, 0xFF, 0xE0,
0x02, 0x00, 0x00, 0x38, 0x02, 0xFF, 0xFF, 0x3C, 0x02, 0xFF, 0xFF, 0x3C, 0x02, 0xFF, 0xFF, 0x3C,
0x02, 0xF0, 0x0F, 0x3C, 0x02, 0xFF, 0xFF, 0x3C, 0x02, 0xFF, 0xFF, 0x7C, 0x02, 0xE0, 0x1F, 0x7C,
0x02, 0xE0, 0x1F, 0x7C, 0x02, 0xE0, 0x1F, 0x7C, 0x02, 0xE0, 0x1F, 0x7C, 0x02, 0xE0, 0x1F, 0x78,
0x02, 0xFF, 0xFF, 0x78, 0x02, 0xFF, 0xFF, 0x78, 0x02, 0x1F, 0xFF, 0x70, 0x02, 0x00, 0x00, 0x70,
0x03, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x1F, 0xFF, 0xFF,
0x02, 0x00, 0x3F, 0xFF, 0x02, 0x40, 0x00, 0x3F, 0x02, 0xC0, 0x7C, 0x3F, 0x02, 0x00, 0x7D, 0xBF,
0x0F, 0x20, 0x00, 0x3F, 0x32, 0x49, 0x00, 0x3C, 0xC4, 0x92, 0x2D, 0x70, 0xE0, 0x24, 0x1A, 0xE0,
0x1F, 0x00, 0xA5, 0xC0, 0x00, 0xFC, 0x03, 0x80, 0x00, 0x03, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xE0,
0x03, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC,
0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC,
0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xF8,
0x03, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xF0,
0x03, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF,
0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF,
0x0F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xE0,
0x1F, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x40,
0x1F, 0xFC, 0x10, 0x06, 0x10, 0x06, 0x10, 0x06, 0x10, 0x06, 0x10, 0x06, 0x10, 0x06, 0x10, 0x04,
0x1F, 0xFC, 0x0F, 0xFE, 0x0F, 0xFF, 0x18, 0x67, 0x34, 0x06, 0x69, 0x64, 0x72, 0xC8, 0x3F, 0xF0,
0x1F, 0xFC, 0x1F, 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x1F, 0xFC,
0x1F, 0xFC, 0x07, 0xFF, 0x1F, 0xFF, 0x3F, 0xFF, 0x3F, 0xFF, 0x7F, 0xFE, 0xFF, 0xFC, 0x07, 0xF8,
0x00, 0x00, 0x00, 0x80, 0x79, 0x7C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCD, 0x97, 0x97, 0x90, 0xE7, 0x97,
0x97, 0x97, 0xDD, 0xD9, 0x79, 0x7C, 0xE7, 0xD5, 0x5E, 0x58, 0xCE, 0xD7, 0x97, 0x9C, 0xDD, 0x5D,
0x7D, 0xB7, 0xDD, 0x59, 0x79, 0x7C, 0x9D, 0x10, 0x1D, 0xD9, 0xCE, 0xD7, 0x97, 0x9C, 0xDD, 0x0C,
0xCC, 0xE7, 0xDD, 0xD9, 0x79, 0x7C, 0xED, 0xDD, 0xDD, 0x79, 0xCE, 0xE7, 0xE7, 0x90, 0xE7, 0x77,
0x97, 0x97, 0xDD, 0x79, 0x79, 0x7C, 0xCC, 0xDC, 0xCD, 0xC8, 0xDD, 0x97, 0x97, 0x99, 0x7C, 0xDD,
0xDD, 0xDE, 0xDE, 0xDE, 0x7E, 0x7C, 0xCC, 0xCC, 0xCD, 0xCD, 0xDD, 0xDE, 0x99, 0x0C, 0x8C, 0xCC,
0xCC, 0xCC, 0xCD, 0xED, 0x77, 0xCC, 0xCC, 0xCD, 0xDD, 0xED, 0xCE, 0xDE, 0x9C, 0xCD, 0xCD, 0xCD,
0x0D, 0xCC, 0xCE, 0xE7, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xCC, 0xDE, 0x99, 0x97, 0x97, 0x9D, 0xDD,
0xDD, 0xDE, 0xE9, 0x77, 0x00, 0x00, 0x01, 0x00, 0xC2, 0xC2, 0xC2, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6,
0xF6, 0x2B, 0x2B, 0x2B, 0xF7, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xC2, 0xC2, 0xC2,
0xC2, 0xC2, 0xC2, 0xC2, 0xF8, 0x81, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xC2, 0x81, 0xAA,
0xAA, 0xAA, 0xFB, 0xC2, 0xF8, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xF9, 0x7F, 0x7F,
0x7F, 0x56, 0x81, 0xC2, 0xF8, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xF9, 0x0A, 0xF6,
0x0A, 0x56, 0xFB, 0xC2, 0xF8, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xF9, 0xF6, 0xF6,
0xF6, 0x56, 0x81, 0xC2, 0x56, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xF9, 0xF9, 0xF9,
0xF9, 0xF9, 0xC2, 0xC2, 0xF8, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xC2, 0xC2, 0xC2,
0xC2, 0xC2, 0xC2, 0xC2, 0x56, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0x2B, 0x2B, 0x2B, 0xF7, 0xF7,
0xF7, 0xF7, 0xF7, 0xB9, 0x56, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0x56, 0xF9,
0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0x81, 0xFA, 0x81, 0xC2, 0xC2, 0xC2, 0xF6, 0xF6, 0xF7, 0x2B, 0x2B,
0x2B, 0xF8, 0xF8, 0xF8, 0xF9, 0xFA, 0x81, 0xFB, 0xC2, 0xC2, 0xF5, 0xF7, 0x93, 0xF7, 0xF7, 0xF7,
0xF7, 0x2B, 0x2B, 0x2B, 0x2B, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xF5, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7,
0xF9, 0xFB, 0xFB, 0xF9, 0xF7, 0xFB, 0x81, 0xFB, 0xC2, 0xF6, 0xF8, 0xF9, 0x2B, 0xF9, 0x2B, 0xF9,
0xF6, 0xF8, 0x2B, 0xF8, 0xF7, 0xFB, 0xFB, 0xC2, 0xF9, 0xF7, 0xF9, 0xF7, 0xF9, 0xF7, 0xF9, 0x2B,
0xF9, 0x2B, 0xF8, 0x2B, 0x81, 0xAC, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF9, 0xF9, 0xF9,
0xF9, 0xF9, 0xF9, 0x81, 0xAC, 0xC2, 0xC2, 0xC2, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0xD8,
0x00, 0x00, 0x08, 0xD8, 0x00, 0x00, 0x00, 0x96, 0x02, 0x1C, 0xC1, 0xC4, 0x18, 0x9C, 0x00, 0x00,
0x00, 0x1C, 0x00, 0x96, 0x00, 0x05, 0x69, 0x63, 0x6C, 0x34, 0x00, 0x00, 0x00, 0x32, 0x69, 0x63,
0x6C, 0x38, 0x00, 0x00, 0x00, 0x3E, 0x49, 0x43, 0x4E, 0x23, 0x00, 0x00, 0x00, 0x4A, 0x69, 0x63,
0x73, 0x23, 0x00, 0x00, 0x00, 0x56, 0x69, 0x63, 0x73, 0x34, 0x00, 0x00, 0x00, 0x62, 0x69, 0x63,
0x73, 0x38, 0x00, 0x00, 0x00, 0x6E, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C,
0xE2, 0x10, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x04, 0x02, 0x1C, 0xE1, 0xAC, 0xBF, 0xB9,
0xFF, 0xFF, 0x00, 0x00, 0x06, 0x08, 0x02, 0x1C, 0xE1, 0xA4, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00,
0x07, 0x0C, 0x02, 0x1C, 0xE1, 0xF8, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0x50, 0x02, 0x1C,
0xE1, 0xDC, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xD4, 0x02, 0x1C, 0xE1, 0xD0
};
static bool use_streams[ 'Z'-'A'+1 ];
static bool is_ntfs_volume(LPCTSTR rootdir)
{
bool ret = false;
TCHAR tst_file[_MAX_PATH], tst_stream[_MAX_PATH];
_sntprintf( tst_file, lengthof(tst_file), TEXT("%sb2query.tmp"), rootdir );
_sntprintf( tst_stream, lengthof(tst_stream), TEXT("%s:AFP_AfpInfo"), tst_file );
if(!exists(tst_file)) {
if(create_file( tst_file, 0 )) {
if(create_file( tst_stream, 0 )) {
ret = true;
}
DeleteFile( tst_file );
}
}
return ret;
}
// !!UNC
void init_posix_emu(void)
{
if(!validate_stat_struct) {
ErrorAlert( "Invalid struct my_stat -- edit posix_emu.h" );
QuitEmulator();
}
#if DEBUG_EXTFS
debug_extfs = PrefsFindInt16("debugextfs");
debug_extfs = DB_EXTFS_LOUD;
if(debug_extfs != DB_EXTFS_NONE) {
extfs_log_open( EXTFS_LOG_FILE_NAME );
}
#endif
// We cannot use ExtFS "RootPath" because of the virtual desktop.
if(PrefsFindBool("enableextfs")) {
PrefsReplaceString("extfs", "");
} else {
PrefsRemoveItem("extfs");
D(bug("extfs disabled by user\n"));
#if DEBUG_EXTFS
extfs_log_close();
#endif
return;
}
const char *extdrives = PrefsFindString("extdrives");
// Set up drive list.
size_t outinx = 0;
for( TCHAR letter = TEXT('A'); letter <= TEXT('Z'); letter++ ) {
if(extdrives && !strchr(extdrives,letter)) continue;
TCHAR rootdir[20];
_sntprintf( rootdir, lengthof(rootdir), TEXT("%c:\\"), letter );
use_streams[ letter - 'A' ] = false;
switch(GetDriveType(rootdir)) {
case DRIVE_FIXED:
case DRIVE_REMOTE:
case DRIVE_RAMDISK:
// TODO: NTFS AFP?
// fall
case DRIVE_REMOVABLE:
case DRIVE_CDROM:
if(outinx < lengthof(host_drive_list)) {
host_drive_list[outinx] = letter;
outinx += 2;
}
}
}
// Set up virtual desktop root.
// TODO: this should be customizable.
GetModuleFileName( NULL, virtual_root, lengthof(virtual_root) );
TCHAR *p = _tcsrchr( virtual_root, TEXT('\\') );
if(p) {
_tcscpy( ++p, desktop_name );
} else {
// should never happen
_sntprintf( virtual_root, lengthof(virtual_root), TEXT("C:\\%s"), desktop_name );
}
CreateDirectory( virtual_root, 0 );
// Set up an icon looking like "My Computer"
// Can be overwritten just like any other folder custom icon.
if(my_access(custom_icon_name,0) != 0) {
int fd = my_creat( custom_icon_name, 0 );
if(fd >= 0) {
my_close(fd);
struct my_stat custom_icon_stat;
int stat_result = my_stat( custom_icon_name, &custom_icon_stat );
fd = open_rfork( custom_icon_name, O_RDWR|O_CREAT );
if(fd >= 0) {
my_write( fd, my_comp_icon, sizeof(my_comp_icon) );
my_close(fd);
// need room for the things from around the finfo that set_finfo reads
static uint8 custom_icon_hfile[ioFlXFndrInfo + SIZEOF_FXInfo];
memset(custom_icon_hfile, 0, ioFlXFndrInfo + SIZEOF_FXInfo);
static uint8 * host_finfo = custom_icon_hfile + ioFlFndrInfo;
uint32 finfo = Host2MacAddr(host_finfo);
get_finfo(custom_icon_name, finfo, 0, false);
WriteMacInt16(finfo + fdFlags, kIsInvisible);
if (stat_result == 0) {
WriteMacInt32(finfo - ioFlFndrInfo + ioFlCrDat, TimeToMacTime(custom_icon_stat.st_ctime));
WriteMacInt32(finfo - ioFlFndrInfo + ioFlMdDat, TimeToMacTime(custom_icon_stat.st_mtime));
}
set_finfo(custom_icon_name, finfo, 0, false);
get_finfo(my_computer, finfo, 0, true);
WriteMacInt16(finfo + fdFlags, ReadMacInt16(finfo + fdFlags) | kHasCustomIcon);
set_finfo(my_computer, finfo, 0, true);
} else {
my_remove(custom_icon_name);
}
}
}
}
void final_posix_emu(void)
{
#if DEBUG_EXTFS
extfs_log_close();
#endif
}
static void charset_host2mac( char *s )
{
int i, len=strlen(s), code;
for( i=len-3; i>=0; i-- ) {
if( s[i] == '%' && isxdigit(s[i+1]) && isxdigit(s[i+2]) ) {
sscanf( &s[i], "%%%02X", &code );
memmove( &s[i], &s[i+2], strlen(&s[i+2])+1 );
s[i] = code;
}
}
}
static void charset_mac2host( LPTSTR s )
{
size_t len = _tcslen(s);
D(bug(TEXT("charset_mac2host(%s)...\n"), s));
for( size_t i=len; i-->0; ) {
bool convert = false;
switch( (unsigned char)s[i] ) {
// case '\r': // handled by "default"
// case '\n':
// case '\t':
case '/':
// case '\\': // Backslash is tricky -- "s" is a full path!
// case ':':
case '*':
case '?':
case '"':
case '<':
case '>':
case '|':
case '%':
convert = true;
break;
default:
if((unsigned char)s[i] < ' ') convert = true;
break;
}
if(convert) {
TCHAR sml[10];
_sntprintf( sml, lengthof(sml), TEXT("%%%02X"), s[i] );
memmove( &s[i+2], &s[i], (_tcslen(&s[i])+1) * sizeof(TCHAR) );
memmove( &s[i], sml, 3 * sizeof(TCHAR) );
}
}
D(bug(TEXT("charset_mac2host = %s\n"), s));
}
static void make_mask(
TCHAR *mask,
LPCTSTR dir,
LPCTSTR a1,
LPCTSTR a2
)
{
_tcscpy( mask, dir );
size_t len = _tcslen(mask);
if( len && mask[len-1] != '\\' ) _tcscat( mask, TEXT("\\") );
if( a1 ) _tcscat( mask, a1 );
if( a2 ) _tcscat( mask, a2 );
}
// !!UNC
static LPTSTR translate( LPCTSTR path, TCHAR *buffer )
{
TCHAR *l = host_drive_list;
const TCHAR *p = path;
while(*l) {
if(_totupper(p[1]) == _totupper(*l)) break;
l += _tcslen(l) + 1;
}
if(p[0] == TEXT('\\') && *l && (p[2] == 0 || p[2] == TEXT(':') || p[2] == TEXT('\\'))) {
p += 2;
if(*p == TEXT(':')) p++;
if(*p == TEXT('\\')) p++;
_sntprintf( buffer, MAX_PATH_LENGTH, TEXT("%c:\\%s"), *l, p );
} else {
if(*path == TEXT('\\')) {
_sntprintf( buffer, MAX_PATH_LENGTH, TEXT("%s%s"), virtual_root, path );
} else {
int len = _tcslen(path);
if(len == 0 || path[len-1] == TEXT('\\')) {
make_mask( buffer, virtual_root, path, tstr(my_computer).get() );
} else {
make_mask( buffer, virtual_root, path, 0 );
}
}
}
charset_mac2host( buffer );
return buffer;
}
// helpers
static void strip_trailing_bs( LPTSTR path )
{
size_t len = _tcslen(path);
if(len > 0 && path[len-1] == TEXT('\\')) path[len-1] = 0;
}
#if 0 /* defined is util_windows.cpp */
static int exists( const char *p )
{
WIN32_FIND_DATA fdata;
int result = 0;
HANDLE h = FindFirstFile( p, &fdata );
if(h != INVALID_HANDLE_VALUE) {
result = 1;
FindClose( h );
}
D(bug("exists(%s) = %d\n", p, result));
return result;
}
#endif
static int is_dir( LPCTSTR p )
{
WIN32_FIND_DATA fdata;
int result = 0;
HANDLE h = FindFirstFile( p, &fdata );
if(h != INVALID_HANDLE_VALUE) {
result = (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
FindClose( h );
}
return result;
}
static int myRemoveDirectory( LPCTSTR source )
{
HANDLE fh;
WIN32_FIND_DATA FindFileData;
int ok, result = 1;
TCHAR mask[_MAX_PATH];
D(bug(TEXT("removing folder %s\n"), source));
make_mask( mask, source, TEXT("*.*"), 0 );
fh = FindFirstFile( mask, &FindFileData );
ok = fh != INVALID_HANDLE_VALUE;
while(ok) {
make_mask( mask, source, FindFileData.cFileName, 0 );
D(bug(TEXT("removing item %s\n"), mask));
int isdir = (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
if(isdir) {
// must delete ".finf", ".rsrc" but not ".", ".."
if(_tcscmp(FindFileData.cFileName,TEXT(".")) && _tcscmp(FindFileData.cFileName,TEXT(".."))) {
result = myRemoveDirectory( mask );
if(!result) break;
}
} else {
D(bug(TEXT("DeleteFile %s\n"), mask));
result = DeleteFile( mask );
if(!result) break;
}
ok = FindNextFile( fh, &FindFileData );
}
if(fh != INVALID_HANDLE_VALUE) FindClose( fh );
if(result) {
D(bug(TEXT("RemoveDirectory %s\n"), source));
result = RemoveDirectory( source );
}
return result;
}
static void make_folders( LPCTSTR path )
{
TCHAR local_path[_MAX_PATH], *p;
_tcscpy( local_path, path );
p = _tcsrchr( local_path, TEXT('\\') );
if(p) {
*p = 0;
if(_tcslen(local_path) > 3) {
make_folders(local_path);
_tmkdir(local_path);
}
}
}
// !!UNC
static bool is_same_drive( LPCTSTR p1, LPCTSTR p2 )
{
return _totupper(*p1) == _totupper(*p2);
}
// Used when the drives are known to be different.
// Can't use MoveFileEx() etc because of the Win9x limitations.
// It would simulate CopyFile*() -- DeleteFile*() anyway
static int file_move_copy( LPCTSTR src, LPCTSTR dst, bool delete_old )
{
int result = 0;
my_errno = 0;
D(bug(TEXT("file_copy %s -> %s\n"), src, dst));
// Fail if exists -- it's up to MacOS to move things to Trash
if(CopyFile(src,dst,TRUE)) {
if(delete_old && !DeleteFile(src)) {
result = -1;
my_errno = EACCES;
}
} else {
result = -1;
if(exists(src))
my_errno = EACCES;
else
my_errno = ENOENT;
}
return result;
}
static int file_move( LPCTSTR src, LPCTSTR dst )
{
return file_move_copy( src, dst, true );
}
static int file_copy( LPCTSTR src, LPCTSTR dst )
{
return file_move_copy( src, dst, false );
}
static int folder_copy( LPCTSTR folder_src, LPCTSTR folder_dst )
{
HANDLE fh;
WIN32_FIND_DATA FindFileData;
int ok, result = 0;
TCHAR mask[_MAX_PATH];
D(bug(TEXT("copying folder %s -> \n"), folder_src, folder_dst));
my_errno = 0;
if(!CreateDirectory( folder_dst, 0 )) {
my_errno = EACCES;
return -1;
}
make_mask( mask, folder_src, TEXT("*.*"), 0 );
fh = FindFirstFile( mask, &FindFileData );
ok = fh != INVALID_HANDLE_VALUE;
while(ok) {
make_mask( mask, folder_src, FindFileData.cFileName, 0 );
int isdir = (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
TCHAR target[_MAX_PATH];
make_mask( target, folder_dst, FindFileData.cFileName, 0 );
D(bug(TEXT("copying item %s -> %s\n"), mask, target));
if(isdir) {
if(_tcscmp(FindFileData.cFileName,TEXT(".")) && _tcscmp(FindFileData.cFileName,TEXT(".."))) {
result = folder_copy( mask, target );
if(result < 0) break;
}
} else {
result = file_copy( mask, target );
if(result < 0) break;
}
ok = FindNextFile( fh, &FindFileData );
}
if(fh != INVALID_HANDLE_VALUE) FindClose( fh );
return result;
}
// dir enumeration
void closedir( struct DIR *d )
{
DISABLE_ERRORS;
if(d) {
if(d->h != INVALID_HANDLE_VALUE && d->h != VIRTUAL_ROOT_ID) {
FindClose( d->h );
}
delete d;
}
RESTORE_ERRORS;
}
static int make_dentry( struct DIR *d )
{
int ok = 0;
memset( &d->de, 0, sizeof(d->de) );
if(d->h != INVALID_HANDLE_VALUE) {
if( (d->FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 &&
*d->FindFileData.cFileName == TEXT('.'))
{
ok = 0;
} else {
strlcpy( d->de.d_name, d->FindFileData.cFileName, lengthof(d->de.d_name) );
charset_host2mac( d->de.d_name );
ok = 1;
}
}
return ok;
}
struct dirent *readdir( struct DIR *d )
{
DISABLE_ERRORS;
dirent *de = 0;
if(d) {
if(d->h != INVALID_HANDLE_VALUE) {
if(d->h == VIRTUAL_ROOT_ID) {
make_dentry(d);
de = &d->de;
d->vname_list += _tcslen(d->vname_list) + 1;
if(*d->vname_list) {
_tcscpy( d->FindFileData.cFileName, d->vname_list );
d->FindFileData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
} else {
// Out of static drive entries. Continue with other stuff.
TCHAR mask[MAX_PATH_LENGTH];
make_mask( mask, virtual_root, TEXT("*.*"), 0 );
d->h = FindFirstFile( mask, &d->FindFileData );
}
} else {
int done = 0;
do {
if(make_dentry(d)) {
de = &d->de;
done = 1;
}
if(!FindNextFile( d->h, &d->FindFileData )) {
FindClose( d->h );
d->h = INVALID_HANDLE_VALUE;
done = 1;
}
} while(!done);
}
}
}
if(de) {
D(bug("readdir found %s\n", de->d_name));
}
RESTORE_ERRORS;
return de;
}
struct DIR *opendir( const char *path )
{
DISABLE_ERRORS;
auto tpath = tstr(path);
DIR *d = new DIR;
if(d) {
memset( d, 0, sizeof(DIR) );
if(*tpath.get() == 0) {
d->vname_list = host_drive_list;
if(d->vname_list) {
d->h = VIRTUAL_ROOT_ID;
_tcscpy( d->FindFileData.cFileName, d->vname_list );
d->FindFileData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
} else {
d->h = INVALID_HANDLE_VALUE;
}
} else {
TCHAR mask[MAX_PATH_LENGTH];
make_mask( mask, MRP(tpath.get()), TEXT("*.*"), 0 );
D(bug(TEXT("opendir path=%s, mask=%s\n"), tpath.get(), mask));
d->h = FindFirstFile( mask, &d->FindFileData );
if(d->h == INVALID_HANDLE_VALUE) {
delete d;
d = 0;
}
}
}
D(bug(TEXT("opendir(%s,%s) = %08x\n"), tpath.get(), MRP(tpath.get()), d));
RESTORE_ERRORS;
return d;
}
static void dump_stat( const struct my_stat *st )
{
D(bug("stat: size = %ld, mode = %ld, a = %ld, m = %ld, c = %ld\n", st->st_size, st->st_mode, st->st_atime, st->st_mtime, st->st_ctime));
}
// Exported hook functions
int my_stat( const char *path, struct my_stat *st )
{
DISABLE_ERRORS;
auto tpath = tstr(path);
int result;
if(*tpath.get() == 0) {
/// virtual root
memset( st, 0, sizeof(struct my_stat) );
st->st_mode = _S_IFDIR;
result = 0;
my_errno = 0;
} else {
result = _tstat( MRP(tpath.get()), (struct _stat *)st );
if(result < 0) {
my_errno = errno;
} else {
my_errno = 0;
}
}
D(bug(TEXT("stat(%s,%s) = %d\n"), tpath.get(), MRP(tpath.get()), result));
if(result >= 0) dump_stat( st );
RESTORE_ERRORS;
return result;
}
int my_fstat( int fd, struct my_stat *st )
{
DISABLE_ERRORS;
int result = _fstat( fd, (struct _stat *)st );
if(result < 0) {
my_errno = errno;
} else {
my_errno = 0;
}
D(bug("fstat(%d) = %d\n", fd, result));
if(result >= 0) dump_stat( st );
RESTORE_ERRORS;
return result;
}
int my_open( const char *path, int mode, ... )
{
DISABLE_ERRORS;
int result;
auto tpath = tstr(path);
LPCTSTR p = MRP(tpath.get());
// Windows "open" does not handle _O_CREAT and _O_BINARY as it should
if(mode & _O_CREAT) {
if(exists(p)) {
result = _topen( p, mode & ~_O_CREAT );
D(bug(TEXT("open-nocreat(%s,%s,%d) = %d\n"), tpath.get(), p, mode, result));
} else {
result = _tcreat( p, _S_IWRITE|_S_IREAD );
if(result < 0) {
make_folders(p);
result = _tcreat( p, _S_IWRITE|_S_IREAD );
}
D(bug(TEXT("open-creat(%s,%s,%d) = %d\n"), tpath.get(), p, mode, result));
}
} else {
result = _topen( p, mode );
D(bug(TEXT("open(%s,%s,%d) = %d\n"), tpath.get(), p, mode, result));
}
if(result < 0) {
my_errno = errno;
} else {
setmode(result, _O_BINARY);
my_errno = 0;
}
RESTORE_ERRORS;
return result;
}
int my_rename( const char *old_path, const char *new_path )
{
DISABLE_ERRORS;
int result = -1;
auto told_path = tstr(old_path);
auto tnew_path = tstr(new_path);
LPCTSTR p_old = MRP(told_path.get());
LPCTSTR p_new = MRP2(tnew_path.get());
result = my_access(old_path,0);
if(result < 0) {
// my_errno already set
} else {
if(is_same_drive(p_old,p_new)) {
result = _trename( p_old, p_new );
if(result != 0) { // by definition, rename may also return a positive value to indicate an error
my_errno = errno;
} else {
my_errno = 0;
}
} else {
if(is_dir(p_old)) {
result = folder_copy( p_old, p_new );
// my_errno already set
if(result >= 0) {
if(myRemoveDirectory( p_old )) {
my_errno = 0;
result = 0;
} else {
// there is no proper error code for this failure.
my_errno = EACCES;
result = -1;
}
}
} else {
result = file_move( p_old, p_new );
// my_errno already set
}
}
}
D(bug(TEXT("rename(%s,%s,%s,%s) = %d\n"), told_path.get(), p_old, tnew_path.get(), p_new, result));
RESTORE_ERRORS;
return result;
}
int my_access( const char *path, int mode )
{
DISABLE_ERRORS;
auto tpath = tstr(path);
LPCTSTR p = MRP(tpath.get());
WIN32_FIND_DATA fdata;
int result;
if(is_dir(p)) {
// access does not work for folders.
HANDLE h = FindFirstFile( p, &fdata );
if(h != INVALID_HANDLE_VALUE) {
FindClose( h );
if(mode == W_OK) {
if( (fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0 ) {
result = 0;
my_errno = 0;
} else {
result = -1;
my_errno = EACCES;
}
} else {
result = 0;
my_errno = 0;
}
} else {
result = -1;
my_errno = ENOENT;
}
} else {
// W_OK, F_OK are ok.
result = _taccess(p,mode);
if(result < 0) {
my_errno = errno;
} else {
my_errno = 0;
}
}
D(bug(TEXT("access(%s,%s,%d) = %d\n"), tpath.get(), p, mode, result));
RESTORE_ERRORS;
return result;
}
int my_mkdir( const char *path, int mode )
{
DISABLE_ERRORS;
auto tpath = tstr(path);
LPTSTR p = MRP(tpath.get());
strip_trailing_bs(p);
int result = _tmkdir( p );
if(result < 0) {
make_folders(p);
result = _tmkdir( p );
}
if(result < 0) {
my_errno = errno;
} else {
my_errno = 0;
}
D(bug(TEXT("mkdir(%s,%s,%d) = %d\n"), tpath.get(), p, mode, result));
RESTORE_ERRORS;
return result;
}
int my_remove( const char *path )
{
DISABLE_ERRORS;
auto tpath = tstr(path);
LPTSTR p = MRP(tpath.get());
strip_trailing_bs(p);
int result;
if(is_dir(p)) {
result = myRemoveDirectory( p );
} else {
D(bug(TEXT("DeleteFile %s\n"), p));
result = DeleteFile( p );
}
if(result) {
result = 0;
my_errno = 0;
} else {
result = -1;
if(exists(p)) {
my_errno = EACCES;
} else {
my_errno = ENOENT;
}
}
D(bug(TEXT("remove(%s,%s) = %d\n"), tpath.get(), p, result));
RESTORE_ERRORS;
return result;
}
int my_creat( const char *path, int mode )
{
DISABLE_ERRORS;
auto tpath = tstr(path);
LPCTSTR p = MRP(tpath.get());
int result = _tcreat( p, _S_IWRITE|_S_IREAD ); // note mode
if(result < 0) {
make_folders(p);
result = _tcreat( p, _S_IWRITE|_S_IREAD ); // note mode
}
if(result < 0) {
my_errno = errno;
} else {
setmode(result, _O_BINARY);
my_errno = 0;
}
D(bug(TEXT("creat(%s,%s,%d) = %d\n"), tpath.get(), p, mode,result));
RESTORE_ERRORS;
return result;
}
int my_chsize( int fd, size_t sz )
{
DISABLE_ERRORS;
int result = chsize(fd,sz);
if(result < 0) {
my_errno = errno;
} else {
my_errno = 0;
}
RESTORE_ERRORS;
return result;
}
int my_close( int fd )
{
DISABLE_ERRORS;
int result = close(fd);
if(result < 0) {
my_errno = errno;
} else {
my_errno = 0;
}
RESTORE_ERRORS;
D(bug("close(%d) = %d\n", fd, result));
return result;
}
long my_lseek( int fd, long offset, int origin )
{
DISABLE_ERRORS;
int result = lseek( fd, offset, origin );
if(result < 0) {
my_errno = errno;
} else {
my_errno = 0;
}
RESTORE_ERRORS;
return result;
}
int my_read( int fd, void *buffer, unsigned int count )
{
DISABLE_ERRORS;
int result = read( fd, buffer, count );
if(result < 0) {
my_errno = errno;
} else {
my_errno = 0;
}
RESTORE_ERRORS;
D(bug("read(%ld,%08x,%ld) = %d\n", fd, buffer, count, result));
return result;
}
int my_write( int fd, const void *buffer, unsigned int count )
{
DISABLE_ERRORS;
int result = write( fd, buffer, count );
if(result < 0) {
my_errno = errno;
} else {
my_errno = 0;
}
RESTORE_ERRORS;
D(bug("write(%ld,%08x,%ld) = %d\n", fd, buffer, count, result));
return result;
}
static FILETIME get_file_time(time_t time) {
FILETIME ft;
unsigned long long result = 11644473600LL;
result += time;
result *= 10000000LL;
ft.dwHighDateTime = (result >> 32);
ft.dwLowDateTime = (result & 0xFFFFFFFF);
return ft;
}
int my_utime( const char *path, struct my_utimbuf * my_times )
{
auto tpath = tstr(path);
LPCTSTR p = MRP(tpath.get());
HANDLE f = CreateFile(p, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (f != INVALID_HANDLE_VALUE) {
FILETIME crTime = get_file_time(my_times->actime);
FILETIME modTime = get_file_time(my_times->modtime);
SetFileTime(f, &crTime, NULL, &modTime);
CloseHandle(f);
return 0;
}
return -1;
}