|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * Win32 interface
5: *
6: * Copyright 1997 Mathias Ortmann
7: */
8:
9: #ifdef __GNUC__
10: #define __int64 long long
11: #include "machdep/winstuff.h"
12: #else
13: #include <windows.h>
14: #include <ddraw.h>
15: #include <stdlib.h>
16: #include <stdarg.h>
17: #include <commctrl.h>
18: #include <commdlg.h>
19: #include <stdio.h>
20: #include <fcntl.h>
21: #include <sys/stat.h>
22: #include <io.h>
23: #endif
24:
25: #include "config.h"
26: #include "sysconfig.h"
27: #include "sysdeps.h"
28: #include "options.h"
29: #include "memory.h"
30: #include "osdep/win32.h"
31:
32: /* stdioemu, posixemu, mallocemu, and various file system helper routines */
33: static DWORD lasterror;
34:
35: static int isillegal (unsigned char *str)
36: {
37: unsigned char a = *str, b = str[1], c = str[2];
38:
39: if (a >= 'a' && a <= 'z')
40: a &= ~' ';
41: if (b >= 'a' && b <= 'z')
42: b &= ~' ';
43: if (c >= 'a' && c <= 'z')
44: c &= ~' ';
45:
46: return (a == 'A' && b == 'U' && c == 'X' ||
47: a == 'C' && b == 'O' && c == 'N' ||
48: a == 'P' && b == 'R' && c == 'N' ||
49: a == 'N' && b == 'U' && c == 'L');
50: }
51:
52: static int checkspace (char *str, char s, char d)
53: {
54: char *ptr = str;
55:
56: while (*ptr && *ptr == s)
57: ptr++;
58:
59: if (!*ptr || *ptr == '/' || *ptr == '\\') {
60: while (str < ptr)
61: *(str++) = d;
62: return 0;
63: }
64: return 1;
65: }
66:
67: /* This is sick and incomplete... in the meantime, I have discovered six new illegal file name formats
68: * M$ sucks! */
69: void fname_atow (char *src, char *dst, int size)
70: {
71: char *lastslash = dst, *strt = dst;
72: int i, j;
73:
74: while (size-- > 0) {
75: if (!(*dst = *src++))
76: break;
77:
78: if (*dst == '~' || *dst == '|' || *dst == '*' || *dst == '?') {
79: if (size > 2) {
80: sprintf (dst, "~%02x", *dst);
81: size -= 2;
82: dst += 2;
83: }
84: } else if (*dst == '/') {
85: if (checkspace (lastslash, ' ', 0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash)) {
86: i = dst - lastslash - 3;
87: dst++;
88: for (j = i + 1; j--; dst--)
89: *dst = dst[-1];
90: *(dst++) = 0xa0;
91: dst += i;
92: size--;
93: } else if (*lastslash == '.' && (dst - lastslash == 1 || lastslash[1] == '.' && dst - lastslash == 2) && size) {
94: *(dst++) = 0xa0;
95: size--;
96: }
97: *dst = '\\';
98: lastslash = dst + 1;
99: }
100: dst++;
101: }
102:
103: if (checkspace (lastslash, ' ', 0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash) && size > 1) {
104: i = dst - lastslash - 3;
105: dst++;
106: for (j = i + 1; j--; dst--)
107: *dst = dst[-1];
108: *(dst++) = 0xa0;
109: } else if (!strcmp (lastslash, ".") || !strcmp (lastslash, ".."))
110: strcat (lastslash, "\xa0");
111: }
112:
113: int getdiskfreespace (char *name, int *f_blocks, int *f_bavail, int *f_bsize)
114: {
115: char buf1[1024];
116: char buf2[1024];
117: DWORD SectorsPerCluster;
118: DWORD BytesPerSector;
119: DWORD NumberOfFreeClusters;
120: DWORD TotalNumberOfClusters;
121:
122: fname_atow (name, buf1, sizeof buf1);
123:
124: GetFullPathName (buf1, sizeof buf2, buf2, NULL);
125:
126: buf2[3] = 0;
127:
128: if (!GetDiskFreeSpace (buf2, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters)) {
129: lasterror = GetLastError ();
130: return FALSE;
131: }
132: *f_blocks = TotalNumberOfClusters;
133: *f_bavail = NumberOfFreeClusters;
134: *f_bsize = SectorsPerCluster * BytesPerSector;
135:
136: return TRUE;
137: }
138:
139: /* Translate lasterror to valid AmigaDOS error code
140: * The mapping is probably not 100% correct yet */
141: long dos_errno (void)
142: {
143: int i;
144:
145: static DWORD errtbl[][2] =
146: {
147: {ERROR_FILE_NOT_FOUND, 205}, /* 2 */
148: {ERROR_PATH_NOT_FOUND, 205}, /* 3 */
149: {ERROR_SHARING_VIOLATION, 202},
150: {ERROR_ACCESS_DENIED, 223}, /* 5 */
151: {ERROR_ARENA_TRASHED, 103}, /* 7 */
152: {ERROR_NOT_ENOUGH_MEMORY, 103}, /* 8 */
153: {ERROR_INVALID_BLOCK, 219}, /* 9 */
154: {ERROR_INVALID_DRIVE, 204}, /* 15 */
155: {ERROR_CURRENT_DIRECTORY, 214}, /* 16 */
156: {ERROR_NO_MORE_FILES, 232}, /* 18 */
157: {ERROR_LOCK_VIOLATION, 214}, /* 33 */
158: {ERROR_BAD_NETPATH, 204}, /* 53 */
159: {ERROR_NETWORK_ACCESS_DENIED, 214}, /* 65 */
160: {ERROR_BAD_NET_NAME, 204}, /* 67 */
161: {ERROR_FILE_EXISTS, 203}, /* 80 */
162: {ERROR_CANNOT_MAKE, 214}, /* 82 */
163: {ERROR_FAIL_I24, 223}, /* 83 */
164: {ERROR_DRIVE_LOCKED, 202}, /* 108 */
165: {ERROR_DISK_FULL, 221}, /* 112 */
166: {ERROR_NEGATIVE_SEEK, 219}, /* 131 */
167: {ERROR_SEEK_ON_DEVICE, 219}, /* 132 */
168: {ERROR_DIR_NOT_EMPTY, 216}, /* 145 */
169: {ERROR_ALREADY_EXISTS, 203}, /* 183 */
170: {ERROR_FILENAME_EXCED_RANGE, 205}, /* 206 */
171: {ERROR_NOT_ENOUGH_QUOTA, 221}, /* 1816 */
172: {ERROR_DIRECTORY, 212}};
173:
174: for (i = sizeof (errtbl) / sizeof (errtbl[0]); i--;) {
175: if (errtbl[i][0] == lasterror)
176: return errtbl[i][1];
177: }
178: return 236;
179: }
180:
181: static DWORD getattr (char *name, LPFILETIME lpft, size_t * size)
182: {
183: HANDLE hFind;
184: WIN32_FIND_DATA fd;
185:
186: if ((hFind = FindFirstFile (name, &fd)) == INVALID_HANDLE_VALUE) {
187: lasterror = GetLastError ();
188:
189: fd.dwFileAttributes = GetFileAttributes (name);
190:
191: return fd.dwFileAttributes;
192: }
193: FindClose (hFind);
194:
195: if (lpft)
196: *lpft = fd.ftLastWriteTime;
197: if (size)
198: *size = fd.nFileSizeLow;
199:
200: return fd.dwFileAttributes;
201: }
202:
203: int posixemu_access (char *name, int mode)
204: {
205: DWORD attr;
206: char buf[1024];
207:
208: fname_atow (name, buf, sizeof buf - 4);
209:
210: if ((attr = getattr (buf, NULL, NULL)) == ~0)
211: return -1;
212:
213: if (attr & FILE_ATTRIBUTE_READONLY && (mode & 4)) {
214: lasterror = ERROR_ACCESS_DENIED;
215: return -1;
216: } else
217: return 0;
218: }
219:
220: int posixemu_open (char *name, int oflag, int dummy)
221: {
222: DWORD fileaccess;
223: DWORD filecreate;
224: char buf[1024];
225:
226: HANDLE hFile;
227:
228: switch (oflag & (O_RDONLY | O_WRONLY | O_RDWR)) {
229: case O_RDONLY:
230: fileaccess = GENERIC_READ;
231: break;
232: case O_WRONLY:
233: fileaccess = GENERIC_WRITE;
234: break;
235: case O_RDWR:
236: fileaccess = GENERIC_READ | GENERIC_WRITE;
237: break;
238: default:
239: return -1;
240: }
241:
242: switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
243: case 0:
244: case O_EXCL:
245: filecreate = OPEN_EXISTING;
246: break;
247: case O_CREAT:
248: filecreate = OPEN_ALWAYS;
249: break;
250: case O_CREAT | O_EXCL:
251: case O_CREAT | O_TRUNC | O_EXCL:
252: filecreate = CREATE_NEW;
253: break;
254: case O_TRUNC:
255: case O_TRUNC | O_EXCL:
256: filecreate = TRUNCATE_EXISTING;
257: break;
258: case O_CREAT | O_TRUNC:
259: filecreate = CREATE_ALWAYS;
260: break;
261: }
262:
263: fname_atow (name, buf, sizeof buf);
264:
265: if ((hFile = CreateFile (buf,
266: fileaccess,
267: FILE_SHARE_READ | FILE_SHARE_WRITE,
268: NULL,
269: filecreate,
270: FILE_ATTRIBUTE_NORMAL,
271: NULL)) == INVALID_HANDLE_VALUE)
272: lasterror = GetLastError ();
273:
274: return (int) hFile;
275: }
276:
277: void posixemu_close (int hFile)
278: {
279: CloseHandle ((HANDLE) hFile);
280: }
281:
282: int w32fopendel (char *name, char *mode, int delflag)
283: {
284: HANDLE hFile;
285: hFile = CreateFile (name,
286: mode[1] == '+' ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ,
287: FILE_SHARE_READ | FILE_SHARE_WRITE,
288: NULL,
289: OPEN_EXISTING,
290: delflag ? FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE : FILE_ATTRIBUTE_NORMAL,
291: NULL);
292:
293: if (hFile == INVALID_HANDLE_VALUE) {
294: lasterror = GetLastError ();
295: hFile = 0;
296: }
297: return (int) hFile;
298: }
299:
300: int stdioemu_fclose (FILE * fd)
301: {
302: if (fd)
303: CloseHandle ((HANDLE) fd);
304: return 0;
305: }
306:
307: void *mallocemu_malloc (int size)
308: {
309: return GlobalAlloc (GPTR, size);
310: }
311:
312: void mallocemu_free (void *ptr)
313: {
314: GlobalFree (ptr);
315: }
316:
317: static int hextol (char a)
318: {
319: if (a >= '0' && a <= '9')
320: return a - '0';
321: if (a >= 'a' && a <= 'f')
322: return a - 'a' + 10;
323: if (a >= 'A' && a <= 'F')
324: return a - 'A' + 10;
325: return 2;
326: }
327:
328: /* Win32 file name restrictions suck... */
329: void fname_wtoa (unsigned char *ptr)
330: {
331: unsigned char *lastslash = ptr;
332:
333: while (*ptr) {
334: if (*ptr == '~') {
335: *ptr = hextol (ptr[1]) * 16 + hextol (ptr[2]);
336: strcpy (ptr + 1, ptr + 3);
337: } else if (*ptr == '\\') {
338: if (checkspace (lastslash, ' ', 0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash)) {
339: ptr--;
340: strcpy (lastslash + 3, lastslash + 4);
341: }
342: *ptr = '/';
343: lastslash = ptr + 1;
344: }
345: ptr++;
346: }
347:
348: if (checkspace (lastslash, ' ', 0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash))
349: strcpy (lastslash + 3, lastslash + 4);
350: }
351:
352: DIR {
353: WIN32_FIND_DATA finddata;
354: HANDLE hDir;
355: int getnext;
356: };
357:
358: DIR *opendir (char *path)
359: {
360: char buf[1024];
361: DIR *dir;
362:
363: if (!(dir = (DIR *) GlobalAlloc (GPTR, sizeof (DIR)))) {
364: lasterror = GetLastError ();
365: return 0;
366: }
367: fname_atow (path, buf, sizeof buf - 4);
368: strcat (buf, "\\*");
369:
370: if ((dir->hDir = FindFirstFile (buf, &dir->finddata)) == INVALID_HANDLE_VALUE) {
371: lasterror = GetLastError ();
372: GlobalFree (dir);
373: return 0;
374: }
375: return dir;
376: }
377:
378: struct dirent *readdir (DIR * dir)
379: {
380: if (dir->getnext) {
381: if (!FindNextFile (dir->hDir, &dir->finddata)) {
382: lasterror = GetLastError ();
383: return 0;
384: }
385: }
386: dir->getnext = TRUE;
387:
388: fname_wtoa (dir->finddata.cFileName);
389: return (struct dirent *) dir->finddata.cFileName;
390: }
391:
392: void closedir (DIR * dir)
393: {
394: FindClose (dir->hDir);
395: GlobalFree (dir);
396: }
397:
398: int setfiletime (char *name, unsigned int days, int minute, int tick)
399: {
400: FILETIME LocalFileTime, FileTime;
401: HANDLE hFile;
402: int success;
403: char buf[1024];
404:
405: fname_atow (name, buf, sizeof buf);
406:
407: if ((hFile = CreateFile (buf, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
408: lasterror = GetLastError ();
409: return 0;
410: }
411: *(__int64 *) & LocalFileTime = (((__int64) (377 * 365 + 91 + days) * (__int64) 1440 + (__int64) minute) * (__int64) (60 * 50) + (__int64) tick) * (__int64) 200000;
412:
413: if (!LocalFileTimeToFileTime (&LocalFileTime, &FileTime))
414: FileTime = LocalFileTime;
415:
416: if (!(success = SetFileTime (hFile, &FileTime, &FileTime, &FileTime)))
417: lasterror = GetLastError ();
418: CloseHandle (hFile);
419:
420: return success;
421: }
422:
423: int posixemu_read (int hFile, char *ptr, int size)
424: {
425: DWORD actual;
426:
427: if (!ReadFile ((HANDLE) hFile, ptr, size, &actual, NULL))
428: lasterror = GetLastError ();
429:
430: return actual;
431: }
432:
433: int posixemu_write (int hFile, char *ptr, int size)
434: {
435: DWORD actual;
436:
437: if (!WriteFile ((HANDLE) hFile, ptr, size, &actual, NULL))
438: lasterror = GetLastError ();
439:
440: return actual;
441: }
442:
443: int posixemu_seek (int hFile, int pos, int type)
444: {
445: int result;
446:
447: switch (type) {
448: case SEEK_SET:
449: type = FILE_BEGIN;
450: break;
451: case SEEK_CUR:
452: type = FILE_CURRENT;
453: break;
454: case SEEK_END:
455: type = FILE_END;
456: }
457:
458: if ((result = SetFilePointer ((HANDLE) hFile, pos, NULL, type)) == ~0)
459: lasterror = GetLastError ();
460:
461: return result;
462: }
463:
464: int stdioemu_fread (char *buf, int l1, int l2, FILE * hFile)
465: {
466: return posixemu_read ((int) hFile, buf, l1 * l2);
467: }
468:
469: int stdioemu_fwrite (char *buf, int l1, int l2, FILE * hFile)
470: {
471: return posixemu_write ((int) hFile, buf, l1 * l2);
472: }
473:
474: int stdioemu_fseek (FILE * hFile, int pos, int type)
475: {
476: return posixemu_seek ((int) hFile, pos, type);
477: }
478:
479: int stdioemu_ftell (FILE * hFile)
480: {
481: return SetFilePointer ((HANDLE) hFile, 0, 0, FILE_CURRENT);
482: }
483:
484: int posixemu_stat (char *name, struct stat *statbuf)
485: {
486: char buf[1024];
487: DWORD attr;
488: HANDLE hFile;
489: FILETIME ft, lft;
490:
491: fname_atow (name, buf, sizeof buf);
492:
493: if ((attr = getattr (buf, &ft, &statbuf->st_size)) == ~0) {
494: lasterror = GetLastError ();
495: return -1;
496: } else {
497: statbuf->st_mode = (attr & FILE_ATTRIBUTE_READONLY) ? 5 : 0;
498: if (attr & FILE_ATTRIBUTE_ARCHIVE)
499: statbuf->st_mode |= 0x10;
500: if (attr & FILE_ATTRIBUTE_DIRECTORY)
501: statbuf->st_mode |= 0x100;
502:
503: FileTimeToLocalFileTime (&ft, &lft);
504: statbuf->st_mtime = (*(__int64 *) & lft - ((__int64) (369 * 365 + 89) * (__int64) (24 * 60 * 60) * (__int64) 10000000)) / (__int64) 10000000;
505: }
506:
507: return 0;
508: }
509:
510: int posixemu_mkdir (char *name, int mode)
511: {
512: char buf[1024];
513:
514: fname_atow (name, buf, sizeof buf);
515:
516: if (CreateDirectory (buf, NULL))
517: return 0;
518:
519: lasterror = GetLastError ();
520:
521: return -1;
522: }
523:
524: int posixemu_unlink (char *name)
525: {
526: char buf[1024];
527:
528: fname_atow (name, buf, sizeof buf);
529: if (DeleteFile (buf))
530: return 0;
531:
532: lasterror = GetLastError ();
533:
534: return -1;
535: }
536:
537: int posixemu_rmdir (char *name)
538: {
539: char buf[1024];
540:
541: fname_atow (name, buf, sizeof buf);
542: if (RemoveDirectory (buf))
543: return 0;
544:
545: lasterror = GetLastError ();
546:
547: return -1;
548: }
549:
550: int posixemu_rename (char *name1, char *name2)
551: {
552: char buf1[1024];
553: char buf2[1024];
554:
555: fname_atow (name1, buf1, sizeof buf1);
556: fname_atow (name2, buf2, sizeof buf2);
557: if (MoveFile (name1, name2))
558: return 0;
559:
560: lasterror = GetLastError ();
561:
562: return -1;
563: }
564:
565: int posixemu_chmod (char *name, int mode)
566: {
567: char buf[1024];
568: DWORD attr = FILE_ATTRIBUTE_NORMAL;
569:
570: fname_atow (name, buf, sizeof buf);
571:
572: if (mode & 1)
573: attr |= FILE_ATTRIBUTE_READONLY;
574: if (mode & 0x10)
575: attr |= FILE_ATTRIBUTE_ARCHIVE;
576:
577: if (SetFileAttributes (buf, attr))
578: return 1;
579:
580: lasterror = GetLastError ();
581:
582: return 0;
583: }
584:
585: void posixemu_tmpnam (char *name)
586: {
587: char buf[MAX_PATH];
588:
589: GetTempPath (MAX_PATH, buf);
590: GetTempFileName (buf, "uae", 0, name);
591: }
592:
593: /* pthread Win32 emulation */
594: void sem_init (HANDLE * event, int manual_reset, int initial_state)
595: {
596: *event = CreateEvent (NULL, manual_reset, initial_state, NULL);
597: }
598:
599: void sem_wait (HANDLE * event)
600: {
601: WaitForSingleObject (*event, INFINITE);
602: }
603:
604: void sem_post (HANDLE * event)
605: {
606: SetEvent (*event);
607: }
608:
609: int sem_trywait (HANDLE * event)
610: {
611: return WaitForSingleObject (*event, 0) == WAIT_OBJECT_0;
612: }
613:
614: /* Mega-klduge to prevent problems with Watcom's habit of passing
615: * arguments in registers... */
616: static HANDLE thread_sem;
617: static void *(*thread_startfunc) (void *);
618: #ifndef __GNUC__
619: static void * __stdcall thread_starter (void *arg)
620: #else
621: static void * thread_starter( void *arg )
622: #endif
623: {
624: void *(*func) (void *) = thread_startfunc;
625: SetEvent (thread_sem);
626: return (*func) (arg);
627: }
628:
629: /* this creates high priority threads by default to speed up the file system (kludge, will be
630: * replaced by a set_penguin_priority() routine soon) */
631: int start_penguin (void *(*f) (void *), void *arg, DWORD * foo)
632: {
633: static int have_event = 0;
634: HANDLE hThread;
635:
636: if (! have_event) {
637: thread_sem = CreateEvent (NULL, 0, 0, NULL);
638: have_event = 1;
639: }
640: thread_startfunc = f;
641: hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) thread_starter, arg, 0, foo);
642: SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST);
643: WaitForSingleObject (thread_sem, INFINITE);
644: }
645:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.