1 /*
2  * UAE - The Un*x Amiga Emulator
3  *
4  * Win32 interface
5  *
6  * Copyright 1997 Mathias Ortmann
7  */
8 
9 #include "sysconfig.h"
10 #include "sysdeps.h"
11 
12 #include <windows.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <ddraw.h>
16 #include <commctrl.h>
17 #include <commdlg.h>
18 #include <stdio.h>
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <io.h>
22 #include <sys/types.h>
23 #include <sys/timeb.h>
24 #include <process.h>
25 #include "options.h"
26 #include "posixemu.h"
27 #include "filesys.h"
28 
29 /* Our Win32 implementation of this function */
gettimeofday(struct timeval * tv,void * blah)30 void gettimeofday( struct timeval *tv, void *blah )
31 {
32     struct timeb time;
33     ftime( &time );
34 
35     tv->tv_sec = time.time;
36     tv->tv_usec = time.millitm * 1000;
37 }
38 
39 /* convert time_t to/from AmigaDOS time */
40 #define secs_per_day ( 24 * 60 * 60 )
41 #define diff ( (8 * 365 + 2) * secs_per_day )
42 
get_time(time_t t,long * days,long * mins,long * ticks)43 void get_time(time_t t, long* days, long* mins, long* ticks)
44 {
45     /* time_t is secs since 1-1-1970 */
46     /* days since 1-1-1978 */
47     /* mins since midnight */
48     /* ticks past minute @ 50Hz */
49 
50     t -= diff;
51     *days = t / secs_per_day;
52     t -= *days * secs_per_day;
53     *mins = t / 60;
54     t -= *mins * 60;
55     *ticks = t * 50;
56 }
57 
58 /* stdioemu, posixemu, mallocemu, and various file system helper routines */
59 static DWORD lasterror;
60 
isillegal(unsigned char * str)61 static int isillegal (unsigned char *str)
62 {
63     int result = 0;
64     unsigned char a = *str, b = str[1], c = str[2];
65 
66     if (a >= 'a' && a <= 'z')
67 	a &= ~' ';
68     if (b >= 'a' && b <= 'z')
69 	b &= ~' ';
70     if (c >= 'a' && c <= 'z')
71 	c &= ~' ';
72 
73     result = ( (a == 'A' && b == 'U' && c == 'X') ||
74 		(a == 'C' && b == 'O' && c == 'N') ||
75 		(a == 'P' && b == 'R' && c == 'N') ||
76 		(a == 'N' && b == 'U' && c == 'L') );
77 
78     return result;
79 }
80 
checkspace(char * str,char s,char d)81 static int checkspace (char *str, char s, char d)
82 {
83     char *ptr = str;
84 
85     while (*ptr && *ptr == s)
86 	ptr++;
87 
88     if (!*ptr || *ptr == '/' || *ptr == '\\') {
89 	while (str < ptr)
90 	    *(str++) = d;
91 	return 0;
92     }
93     return 1;
94 }
95 
96 /* This is sick and incomplete... in the meantime, I have discovered six new illegal file name formats
97  * M$ sucks! */
fname_atow(const char * src,char * dst,int size)98 void fname_atow (const char *src, char *dst, int size)
99 {
100     char *lastslash = dst, *strt = dst, *posn = NULL, *temp = NULL;
101     int i, j;
102 
103     temp = xmalloc( size );
104 
105     while (size-- > 0) {
106 	if (!(*dst = *src++))
107 	    break;
108 
109 	if (*dst == '~' || *dst == '|' || *dst == '*' || *dst == '?') {
110 	    if (size > 2) {
111 		sprintf (dst, "~%02x", *dst);
112 		size -= 2;
113 		dst += 2;
114 	    }
115 	} else if (*dst == '/') {
116 	    if (checkspace (lastslash, ' ', (char)0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash)) {
117 		i = dst - lastslash - 3;
118 		dst++;
119 		for (j = i + 1; j--; dst--)
120 		    *dst = dst[-1];
121 		*(dst++) = (char)0xa0;
122 		dst += i;
123 		size--;
124 	    } else if (*lastslash == '.' && (dst - lastslash == 1 || (lastslash[1] == '.' && dst - lastslash == 2)) && size) {
125 		*(dst++) = (char)0xa0;
126 		size--;
127 	    }
128 	    *dst = '\\';
129 	    lastslash = dst + 1;
130 	}
131 	dst++;
132     }
133 
134     if (checkspace (lastslash, ' ', (char)0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash) && size > 1) {
135 	i = dst - lastslash - 3;
136 	dst++;
137 	for (j = i + 1; j--; dst--)
138 	    *dst = dst[-1];
139 	*(dst++) = (char)0xa0;
140     } else if (!strcmp (lastslash, ".") || !strcmp (lastslash, ".."))
141 	strcat (lastslash, "\xa0");
142 
143     /* Major kludge, because I can't find the problem... */
144     if( ( posn = strstr( strt, "..\xA0\\" ) ) == strt && temp)
145     {
146 	strcpy( temp, "..\\" );
147 	strcat( temp, strt + 4 );
148 	strcpy( strt, temp );
149     }
150 
151     /* Another major kludge, for the MUI installation... */
152     if( *strt == ' ' ) /* first char as a space is illegal in Windoze */
153     {
154 	sprintf( temp, "~%02x%s", ' ', strt+1 );
155 	strcpy( strt, temp );
156     }
157 }
158 
hextol(char a)159 static int hextol (char a)
160 {
161     if (a >= '0' && a <= '9')
162 	return a - '0';
163     if (a >= 'a' && a <= 'f')
164 	return a - 'a' + 10;
165     if (a >= 'A' && a <= 'F')
166 	return a - 'A' + 10;
167     return 2;
168 }
169 
170 /* Win32 file name restrictions suck... */
fname_wtoa(unsigned char * ptr)171 void fname_wtoa (unsigned char *ptr)
172 {
173     unsigned char *lastslash = ptr;
174 
175     while (*ptr) {
176 	if (*ptr == '~') {
177 	    *ptr = hextol (ptr[1]) * 16 + hextol (ptr[2]);
178 	    strcpy (ptr + 1, ptr + 3);
179 	} else if (*ptr == '\\') {
180 	    if (checkspace (lastslash, ' ', (char)0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash)) {
181 		ptr--;
182 		strcpy (lastslash + 3, lastslash + 4);
183 	    }
184 	    *ptr = '/';
185 	    lastslash = ptr + 1;
186 	}
187 	ptr++;
188     }
189 
190     if (checkspace (lastslash, ' ', (char)0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash))
191 	strcpy (lastslash + 3, lastslash + 4);
192 }
193 
194 #ifndef HAVE_TRUNCATE
truncate(const char * name,long int len)195 int truncate (const char *name, long int len)
196 {
197     HANDLE hFile;
198     BOOL bResult = FALSE;
199     int result = -1;
200 
201 #if 0
202     char buf[1024];
203 
204     fname_atow(name,buf,sizeof buf);
205 
206     if( ( hFile = CreateFile( buf, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
207 			      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ) != INVALID_HANDLE_VALUE )
208     {
209 	if( SetFilePointer( hFile, len, NULL, FILE_BEGIN ) == (DWORD)len )
210 	{
211 	    if( SetEndOfFile( hFile ) == TRUE )
212 		result = 0;
213 	}
214 	else
215 	{
216 	    write_log ( "SetFilePointer() failure for %s to posn %d\n", buf, len );
217 	}
218 	CloseHandle( hFile );
219     }
220     else
221     {
222 	write_log ( "CreateFile() failed to open %s\n", buf );
223     }
224 #else
225     if( ( hFile = CreateFile( name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
226 			      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ) != INVALID_HANDLE_VALUE )
227     {
228 	if( SetFilePointer( hFile, len, NULL, FILE_BEGIN ) == (DWORD)len )
229 	{
230 	    if( SetEndOfFile( hFile ) == TRUE )
231 		result = 0;
232 	}
233 	else
234 	{
235 	    write_log ( "SetFilePointer() failure for %s to posn %d\n", name, len );
236 	}
237 	CloseHandle( hFile );
238     }
239     else
240     {
241 	write_log ( "CreateFile() failed to open %s\n", name );
242     }
243 #endif
244     if( result == -1 )
245 	lasterror = GetLastError();
246     return result;
247 }
248 #endif
249 
250 #if 0
251 
252 DIR {
253     WIN32_FIND_DATA finddata;
254     HANDLE hDir;
255     int getnext;
256 };
257 
258 DIR *posixemu_opendir(const char *path)
259 {
260     char buf[1024];
261     DIR *dir;
262 
263     if (!(dir = (DIR *)GlobalAlloc(GPTR,sizeof(DIR))))
264     {
265 	    lasterror = GetLastError();
266 	    return 0;
267     }
268 #if 0
269     fname_atow(path,buf,sizeof buf-4);
270 #else
271     strcpy( buf, path );
272 #endif
273     strcat(buf,"\\*");
274 
275     if ((dir->hDir = FindFirstFile(buf,&dir->finddata)) == INVALID_HANDLE_VALUE)
276     {
277 	    lasterror = GetLastError();
278 	    GlobalFree(dir);
279 	    return 0;
280     }
281 
282     return dir;
283 }
284 
285 struct dirent *posixemu_readdir(DIR *dir)
286 {
287     if (dir->getnext)
288     {
289 	if (!FindNextFile(dir->hDir,&dir->finddata))
290 	{
291 	    lasterror = GetLastError();
292 	    return 0;
293 	}
294     }
295     dir->getnext = TRUE;
296 
297     fname_wtoa(dir->finddata.cFileName);
298     return (struct dirent *)dir->finddata.cFileName;
299 }
300 
301 void posixemu_closedir(DIR *dir)
302 {
303     FindClose(dir->hDir);
304     GlobalFree(dir);
305 }
306 #endif
307 
w32fopendel(char * name,char * mode,int delflag)308 int w32fopendel(char *name, char *mode, int delflag)
309 {
310 	HANDLE hFile;
311 
312 	if ((hFile = CreateFile(name,
313 		mode[1] == '+' ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ,	// ouch :)
314 		FILE_SHARE_READ | FILE_SHARE_WRITE,
315 		NULL,
316 		OPEN_EXISTING,
317 		delflag ? FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE : FILE_ATTRIBUTE_NORMAL,
318 		NULL)) == INVALID_HANDLE_VALUE)
319 	{
320 		lasterror = GetLastError();
321 		hFile = 0;
322 	}
323 
324 	return (int)hFile;                      /* return handle */
325 }
326 
getattr(const char * name,LPFILETIME lpft,size_t * size)327 DWORD getattr(const char *name, LPFILETIME lpft, size_t *size)
328 {
329 	HANDLE hFind;
330 	WIN32_FIND_DATA fd;
331 
332 	if ((hFind = FindFirstFile(name,&fd)) == INVALID_HANDLE_VALUE)
333 	{
334 		lasterror = GetLastError();
335 
336 		fd.dwFileAttributes = GetFileAttributes(name);
337 
338 		return fd.dwFileAttributes;
339 	}
340 
341 	FindClose(hFind);
342 
343 	if (lpft) *lpft = fd.ftLastWriteTime;
344 	if (size) *size = fd.nFileSizeLow;
345 
346 	return fd.dwFileAttributes;
347 }
348 
349 #if 0
350 int posixemu_stat(const char *name, struct stat *statbuf)
351 {
352     DWORD attr;
353     FILETIME ft, lft;
354 
355     if ((attr = getattr(name,&ft,(size_t*)&statbuf->st_size)) == (DWORD)~0)
356     {
357 	lasterror = GetLastError();
358 	return -1;
359     }
360     else
361     {
362 	statbuf->st_mode = (attr & FILE_ATTRIBUTE_READONLY) ? FILEFLAG_READ: FILEFLAG_READ | FILEFLAG_WRITE;
363 	if (attr & FILE_ATTRIBUTE_ARCHIVE) statbuf->st_mode |= FILEFLAG_ARCHIVE;
364 	if (attr & FILE_ATTRIBUTE_DIRECTORY) statbuf->st_mode |= FILEFLAG_DIR;
365 	FileTimeToLocalFileTime(&ft,&lft);
366 	statbuf->st_mtime = (*(__int64 *)&lft-((__int64)(369*365+89)*(__int64)(24*60*60)*(__int64)10000000))/(__int64)10000000;
367     }
368     return 0;
369 }
370 
371 int posixemu_chmod(const char *name, int mode)
372 {
373     DWORD attr = FILE_ATTRIBUTE_NORMAL;
374     if (mode & 0x05) attr |= FILE_ATTRIBUTE_READONLY; /* Delete (0x01) or Write (0x04) bits */
375     if (mode & 0x10) attr |= FILE_ATTRIBUTE_ARCHIVE;
376 
377     if (SetFileAttributes(name,attr)) return 1;
378     lasterror = GetLastError();
379 
380     return -1;
381 }
382 #endif
383 
tmToSystemTime(struct tm * tmtime,LPSYSTEMTIME systime)384 void tmToSystemTime( struct tm *tmtime, LPSYSTEMTIME systime )
385 {
386     if( tmtime == NULL )
387     {
388 	GetSystemTime( systime );
389     }
390     else
391     {
392 	systime->wDay       = tmtime->tm_mday;
393 	systime->wDayOfWeek = tmtime->tm_wday;
394 	systime->wMonth     = tmtime->tm_mon + 1;
395 	systime->wYear      = tmtime->tm_year + 1900;
396 	systime->wHour      = tmtime->tm_hour;
397 	systime->wMinute    = tmtime->tm_min;
398 	systime->wSecond    = tmtime->tm_sec;
399 	systime->wMilliseconds = 0;
400     }
401 }
402 
setfiletime(const char * name,unsigned int days,int minute,int tick)403 static int setfiletime(const char *name, unsigned int days, int minute, int tick)
404 {
405     FILETIME LocalFileTime, FileTime;
406     HANDLE hFile;
407     int success;
408     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)
409     {
410 	lasterror = GetLastError();
411 	return 0;
412     }
413 
414     *(__int64 *)&LocalFileTime = (((__int64)(377*365+91+days)*(__int64)1440+(__int64)minute)*(__int64)(60*50)+(__int64)tick)*(__int64)200000;
415 
416     if (!LocalFileTimeToFileTime(&LocalFileTime,&FileTime)) FileTime = LocalFileTime;
417 
418     if (!(success = SetFileTime(hFile,&FileTime,&FileTime,&FileTime))) lasterror = GetLastError();
419     CloseHandle(hFile);
420 
421     return success;
422 }
423 
posixemu_utime(const char * name,struct utimbuf * time)424 int posixemu_utime( const char *name, struct utimbuf *time )
425 {
426     int result = -1;
427     long days, mins, ticks;
428 
429     get_time( time->actime, &days, &mins, &ticks );
430 
431     if( setfiletime( name, days, mins, ticks ) )
432 	result = 0;
433 
434 	return result;
435 }
436