Source to src/od-win32/posixemu.c


Enter a symbol's name here to quickly find it.

/* 
 * UAE - The Un*x Amiga Emulator
 *
 * Win32 interface
 *
 * Copyright 1997 Mathias Ortmann
 */

#include "sysconfig.h"
#include "sysdeps.h"

#include <windows.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ddraw.h>
#include <commctrl.h>
#include <commdlg.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <io.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <process.h>
#include "options.h"
#include "posixemu.h"
#include "filesys.h"

/* Our Win32 implementation of this function */
void gettimeofday( struct timeval *tv, void *blah )
{
    struct timeb time;
    ftime( &time );

    tv->tv_sec = time.time;
    tv->tv_usec = time.millitm * 1000;
}

/* convert time_t to/from AmigaDOS time */
#define secs_per_day ( 24 * 60 * 60 )
#define diff ( (8 * 365 + 2) * secs_per_day )

void get_time(time_t t, long* days, long* mins, long* ticks)
{
    /* time_t is secs since 1-1-1970 */
    /* days since 1-1-1978 */
    /* mins since midnight */
    /* ticks past minute @ 50Hz */

    t -= diff;
    *days = t / secs_per_day;
    t -= *days * secs_per_day;
    *mins = t / 60;
    t -= *mins * 60;
    *ticks = t * 50;
}

/* stdioemu, posixemu, mallocemu, and various file system helper routines */
static DWORD lasterror;

static int isillegal (unsigned char *str)
{
    int result = 0;
    unsigned char a = *str, b = str[1], c = str[2];

    if (a >= 'a' && a <= 'z')
	a &= ~' ';
    if (b >= 'a' && b <= 'z')
	b &= ~' ';
    if (c >= 'a' && c <= 'z')
	c &= ~' ';

    result = ( (a == 'A' && b == 'U' && c == 'X') ||
		(a == 'C' && b == 'O' && c == 'N') ||
		(a == 'P' && b == 'R' && c == 'N') ||
		(a == 'N' && b == 'U' && c == 'L') );

    return result;
}

static int checkspace (char *str, char s, char d)
{
    char *ptr = str;

    while (*ptr && *ptr == s)
	ptr++;

    if (!*ptr || *ptr == '/' || *ptr == '\\') {
	while (str < ptr)
	    *(str++) = d;
	return 0;
    }
    return 1;
}

/* This is sick and incomplete... in the meantime, I have discovered six new illegal file name formats
 * M$ sucks! */
void fname_atow (const char *src, char *dst, int size)
{
    char *lastslash = dst, *strt = dst, *posn = NULL, *temp = NULL;
    int i, j;

    temp = xmalloc( size );

    while (size-- > 0) {
	if (!(*dst = *src++))
	    break;

	if (*dst == '~' || *dst == '|' || *dst == '*' || *dst == '?') {
	    if (size > 2) {
		sprintf (dst, "~%02x", *dst);
		size -= 2;
		dst += 2;
	    }
	} else if (*dst == '/') {
	    if (checkspace (lastslash, ' ', (char)0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash)) {
		i = dst - lastslash - 3;
		dst++;
		for (j = i + 1; j--; dst--)
		    *dst = dst[-1];
		*(dst++) = (char)0xa0;
		dst += i;
		size--;
	    } else if (*lastslash == '.' && (dst - lastslash == 1 || (lastslash[1] == '.' && dst - lastslash == 2)) && size) {
		*(dst++) = (char)0xa0;
		size--;
	    }
	    *dst = '\\';
	    lastslash = dst + 1;
	}
	dst++;
    }

    if (checkspace (lastslash, ' ', (char)0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash) && size > 1) {
	i = dst - lastslash - 3;
	dst++;
	for (j = i + 1; j--; dst--)
	    *dst = dst[-1];
	*(dst++) = (char)0xa0;
    } else if (!strcmp (lastslash, ".") || !strcmp (lastslash, ".."))
	strcat (lastslash, "\xa0");

    /* Major kludge, because I can't find the problem... */
    if( ( posn = strstr( strt, "..\xA0\\" ) ) == strt && temp)
    {
	strcpy( temp, "..\\" );
	strcat( temp, strt + 4 );
	strcpy( strt, temp );
    }

    /* Another major kludge, for the MUI installation... */
    if( *strt == ' ' ) /* first char as a space is illegal in Windoze */
    {
	sprintf( temp, "~%02x%s", ' ', strt+1 );
	strcpy( strt, temp );
    }
}

static int hextol (char a)
{
    if (a >= '0' && a <= '9')
	return a - '0';
    if (a >= 'a' && a <= 'f')
	return a - 'a' + 10;
    if (a >= 'A' && a <= 'F')
	return a - 'A' + 10;
    return 2;
}

/* Win32 file name restrictions suck... */
void fname_wtoa (unsigned char *ptr)
{
    unsigned char *lastslash = ptr;

    while (*ptr) {
	if (*ptr == '~') {
	    *ptr = hextol (ptr[1]) * 16 + hextol (ptr[2]);
	    strcpy (ptr + 1, ptr + 3);
	} else if (*ptr == '\\') {
	    if (checkspace (lastslash, ' ', (char)0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash)) {
		ptr--;
		strcpy (lastslash + 3, lastslash + 4);
	    }
	    *ptr = '/';
	    lastslash = ptr + 1;
	}
	ptr++;
    }

    if (checkspace (lastslash, ' ', (char)0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash))
	strcpy (lastslash + 3, lastslash + 4);
}

#ifndef HAVE_TRUNCATE
int truncate (const char *name, long int len)
{
    HANDLE hFile;
    BOOL bResult = FALSE;
    int result = -1;

#if 0
    char buf[1024];

    fname_atow(name,buf,sizeof buf);

    if( ( hFile = CreateFile( buf, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
			      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ) != INVALID_HANDLE_VALUE )
    {
	if( SetFilePointer( hFile, len, NULL, FILE_BEGIN ) == (DWORD)len )
	{
	    if( SetEndOfFile( hFile ) == TRUE )
		result = 0;
	}
	else
	{
	    write_log ( "SetFilePointer() failure for %s to posn %d\n", buf, len );
	}
	CloseHandle( hFile );
    }
    else
    {
	write_log ( "CreateFile() failed to open %s\n", buf );
    }
#else
    if( ( hFile = CreateFile( name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
			      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ) != INVALID_HANDLE_VALUE )
    {
	if( SetFilePointer( hFile, len, NULL, FILE_BEGIN ) == (DWORD)len )
	{
	    if( SetEndOfFile( hFile ) == TRUE )
		result = 0;
	}
	else
	{
	    write_log ( "SetFilePointer() failure for %s to posn %d\n", name, len );
	}
	CloseHandle( hFile );
    }
    else
    {
	write_log ( "CreateFile() failed to open %s\n", name );
    }
#endif
    if( result == -1 )
	lasterror = GetLastError();
    return result;
}
#endif

#if 0

DIR {
    WIN32_FIND_DATA finddata;
    HANDLE hDir;
    int getnext;
};

DIR *posixemu_opendir(const char *path)
{
    char buf[1024];
    DIR *dir;

    if (!(dir = (DIR *)GlobalAlloc(GPTR,sizeof(DIR))))
    {
	    lasterror = GetLastError();
	    return 0;
    }
#if 0
    fname_atow(path,buf,sizeof buf-4);
#else
    strcpy( buf, path );
#endif
    strcat(buf,"\\*");

    if ((dir->hDir = FindFirstFile(buf,&dir->finddata)) == INVALID_HANDLE_VALUE)
    {
	    lasterror = GetLastError();
	    GlobalFree(dir);
	    return 0;
    }

    return dir;
}

struct dirent *posixemu_readdir(DIR *dir)
{
    if (dir->getnext)
    {
	if (!FindNextFile(dir->hDir,&dir->finddata))
	{
	    lasterror = GetLastError();
	    return 0;
	}
    }
    dir->getnext = TRUE;

    fname_wtoa(dir->finddata.cFileName);
    return (struct dirent *)dir->finddata.cFileName;
}

void posixemu_closedir(DIR *dir)
{
    FindClose(dir->hDir);
    GlobalFree(dir);
}
#endif

int w32fopendel(char *name, char *mode, int delflag)
{
	HANDLE hFile;

	if ((hFile = CreateFile(name,
		mode[1] == '+' ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ,	// ouch :)
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING,
		delflag ? FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE : FILE_ATTRIBUTE_NORMAL,
		NULL)) == INVALID_HANDLE_VALUE)
	{
		lasterror = GetLastError();
		hFile = 0;
	}

	return (int)hFile;                      /* return handle */
}
	
DWORD getattr(const char *name, LPFILETIME lpft, size_t *size)
{
	HANDLE hFind;
	WIN32_FIND_DATA fd;

	if ((hFind = FindFirstFile(name,&fd)) == INVALID_HANDLE_VALUE)
	{
		lasterror = GetLastError();

		fd.dwFileAttributes = GetFileAttributes(name);

		return fd.dwFileAttributes;
	}

	FindClose(hFind);

	if (lpft) *lpft = fd.ftLastWriteTime;
	if (size) *size = fd.nFileSizeLow;

	return fd.dwFileAttributes;
}

#if 0
int posixemu_stat(const char *name, struct stat *statbuf)
{
    DWORD attr;
    FILETIME ft, lft;

    if ((attr = getattr(name,&ft,(size_t*)&statbuf->st_size)) == (DWORD)~0)
    {
	lasterror = GetLastError();
	return -1;
    }
    else
    {
	statbuf->st_mode = (attr & FILE_ATTRIBUTE_READONLY) ? FILEFLAG_READ: FILEFLAG_READ | FILEFLAG_WRITE;
	if (attr & FILE_ATTRIBUTE_ARCHIVE) statbuf->st_mode |= FILEFLAG_ARCHIVE;
	if (attr & FILE_ATTRIBUTE_DIRECTORY) statbuf->st_mode |= FILEFLAG_DIR;
	FileTimeToLocalFileTime(&ft,&lft);
	statbuf->st_mtime = (*(__int64 *)&lft-((__int64)(369*365+89)*(__int64)(24*60*60)*(__int64)10000000))/(__int64)10000000;
    }
    return 0;
}

int posixemu_chmod(const char *name, int mode)
{
    DWORD attr = FILE_ATTRIBUTE_NORMAL;
    if (mode & 0x05) attr |= FILE_ATTRIBUTE_READONLY; /* Delete (0x01) or Write (0x04) bits */
    if (mode & 0x10) attr |= FILE_ATTRIBUTE_ARCHIVE;

    if (SetFileAttributes(name,attr)) return 1;
    lasterror = GetLastError();

    return -1;
}
#endif

void tmToSystemTime( struct tm *tmtime, LPSYSTEMTIME systime )
{
    if( tmtime == NULL )
    {
	GetSystemTime( systime );
    }
    else
    {
	systime->wDay       = tmtime->tm_mday;
	systime->wDayOfWeek = tmtime->tm_wday;
	systime->wMonth     = tmtime->tm_mon + 1;
	systime->wYear      = tmtime->tm_year + 1900;
	systime->wHour      = tmtime->tm_hour;
	systime->wMinute    = tmtime->tm_min;
	systime->wSecond    = tmtime->tm_sec;
	systime->wMilliseconds = 0;
    }
}

static int setfiletime(const char *name, unsigned int days, int minute, int tick)
{
    FILETIME LocalFileTime, FileTime;
    HANDLE hFile;
    int success;
    if ((hFile = CreateFile(name, GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL)) == INVALID_HANDLE_VALUE)
    {
	lasterror = GetLastError();
	return 0;
    }

    *(__int64 *)&LocalFileTime = (((__int64)(377*365+91+days)*(__int64)1440+(__int64)minute)*(__int64)(60*50)+(__int64)tick)*(__int64)200000;
    
    if (!LocalFileTimeToFileTime(&LocalFileTime,&FileTime)) FileTime = LocalFileTime;
    
    if (!(success = SetFileTime(hFile,&FileTime,&FileTime,&FileTime))) lasterror = GetLastError();
    CloseHandle(hFile);
    
    return success;
}

int posixemu_utime( const char *name, struct utimbuf *time )
{
    int result = -1;
    long days, mins, ticks;

    get_time( time->actime, &days, &mins, &ticks );

    if( setfiletime( name, days, mins, ticks ) )
	result = 0;

	return result;
}