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