source: trunk/src/kernel32/Fileio.cpp

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 56.5 KB
Line 
1/* $Id: Fileio.cpp,v 1.71 2003-03-03 16:39:53 sandervl Exp $ */
2
3/*
4 * Win32 File IO API functions for OS/2
5 *
6 * Copyright 1998-2000 Sander van Leeuwen
7 * Copyright 1998 Patrick Haller
8 *
9 * Some parts based on Wine code (CopyFileExA/W, FindFirstFileExW,
10 * GetShortPathNameA/W, GetLongPathNameA/W)
11 *
12 * Copyright 1993 John Burton
13 * Copyright 1993 Erik Bos
14 * Copyright 1996 Alexandre Julliard
15 *
16 *
17 * Project Odin Software License can be found in LICENSE.TXT
18 *
19 */
20
21
22/*****************************************************************************
23 * Includes *
24 *****************************************************************************/
25
26#include <odin.h>
27#include <odinwrap.h>
28#include <os2sel.h>
29
30#include <os2win.h>
31#include <stdlib.h>
32#include <string.h>
33#include "unicode.h"
34#include <heapstring.h>
35#include "handlemanager.h"
36#include "oslibdos.h"
37#include "oslibwps.h"
38
39#define DBG_LOCALLOG DBG_fileio
40#include "dbglocal.h"
41
42ODINDEBUGCHANNEL(KERNEL32-FILEIO)
43
44#include <ctype.h>
45#include "fileio.h"
46#include <win/file.h>
47
48
49/***********************************************************************
50 * DOSFS_ValidDOSName
51 *
52 * Return 1 if OS/2 file 'name' is also a valid MS-DOS name
53 * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format).
54 * File name can be terminated by '\0', '\\' or '/'.
55 */
56static int DOSFS_ValidDOSName( const char *name, int ignore_case )
57{
58 static const char invalid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS;
59 const char *p = name;
60 const char *invalid = ignore_case ? (invalid_chars + 26) : invalid_chars;
61 int len = 0;
62
63 if (*p == '.')
64 {
65 /* Check for "." and ".." */
66 p++;
67 if (*p == '.') p++;
68 /* All other names beginning with '.' are invalid */
69 return (IS_END_OF_NAME(*p));
70 }
71 while (!IS_END_OF_NAME(*p))
72 {
73 if (strchr( invalid, *p )) return 0; /* Invalid char */
74 if (*p == '.') break; /* Start of the extension */
75 if (++len > 8) return 0; /* Name too long */
76 p++;
77 }
78 if (*p != '.') return 1; /* End of name */
79 p++;
80 if (IS_END_OF_NAME(*p)) return 0; /* Empty extension not allowed */
81 len = 0;
82 while (!IS_END_OF_NAME(*p))
83 {
84 if (strchr( invalid, *p )) return 0; /* Invalid char */
85 if (*p == '.') return 0; /* Second extension not allowed */
86 if (++len > 3) return 0; /* Extension too long */
87 p++;
88 }
89 return 1;
90}
91
92/***********************************************************************
93 * DOSFS_Hash
94 *
95 * Transform an OS/2 file name into a hashed DOS name. If the name is a valid
96 * DOS name, it is converted to upper-case; otherwise it is replaced by a
97 * hashed version that fits in 8.3 format.
98 * File name can be terminated by '\0', '\\' or '/'.
99 * 'buffer' must be at least 13 characters long.
100 */
101
102static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format,
103 BOOL ignore_case )
104{
105 static const char invalid_chars[] = INVALID_DOS_CHARS "~.";
106 static const char hash_chars[33] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
107
108 const char *p, *ext;
109 char *dst;
110 unsigned short hash;
111 int i;
112
113 if (dir_format) strcpy( buffer, " " );
114
115 if (DOSFS_ValidDOSName( name, ignore_case ))
116 {
117 /* Check for '.' and '..' */
118 if (*name == '.')
119 {
120 buffer[0] = '.';
121 if (!dir_format) buffer[1] = buffer[2] = '\0';
122 if (name[1] == '.') buffer[1] = '.';
123 return;
124 }
125
126 /* Simply copy the name, converting to uppercase */
127
128 for (dst = buffer; !IS_END_OF_NAME(*name) && (*name != '.'); name++)
129 *dst++ = FILE_toupper(*name);
130 if (*name == '.')
131 {
132 if (dir_format) dst = buffer + 8;
133 else *dst++ = '.';
134 for (name++; !IS_END_OF_NAME(*name); name++)
135 *dst++ = FILE_toupper(*name);
136 }
137 if (!dir_format) *dst = '\0';
138 return;
139 }
140
141 /* Compute the hash code of the file name */
142 /* If you know something about hash functions, feel free to */
143 /* insert a better algorithm here... */
144 if (ignore_case)
145 {
146 for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
147 hash = (hash<<3) ^ (hash>>5) ^ FILE_tolower(*p) ^ (FILE_tolower(p[1]) << 8);
148 hash = (hash<<3) ^ (hash>>5) ^ FILE_tolower(*p); /* Last character*/
149 }
150 else
151 {
152 for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
153 hash = (hash << 3) ^ (hash >> 5) ^ *p ^ (p[1] << 8);
154 hash = (hash << 3) ^ (hash >> 5) ^ *p; /* Last character */
155 }
156
157 /* Find last dot for start of the extension */
158 for (p = name+1, ext = NULL; !IS_END_OF_NAME(*p); p++)
159 if (*p == '.') ext = p;
160 if (ext && IS_END_OF_NAME(ext[1]))
161 ext = NULL; /* Empty extension ignored */
162
163 /* Copy first 4 chars, replacing invalid chars with '_' */
164 for (i = 4, p = name, dst = buffer; i > 0; i--, p++)
165 {
166 if (IS_END_OF_NAME(*p) || (p == ext)) break;
167 *dst++ = strchr( invalid_chars, *p ) ? '_' : FILE_toupper(*p);
168 }
169 /* Pad to 5 chars with '~' */
170 while (i-- >= 0) *dst++ = '~';
171
172 /* Insert hash code converted to 3 ASCII chars */
173 *dst++ = hash_chars[(hash >> 10) & 0x1f];
174 *dst++ = hash_chars[(hash >> 5) & 0x1f];
175 *dst++ = hash_chars[hash & 0x1f];
176
177 /* Copy the first 3 chars of the extension (if any) */
178 if (ext)
179 {
180 if (!dir_format) *dst++ = '.';
181 for (i = 3, ext++; (i > 0) && !IS_END_OF_NAME(*ext); i--, ext++)
182 *dst++ = strchr( invalid_chars, *ext ) ? '_' : FILE_toupper(*ext);
183 }
184 if (!dir_format) *dst = '\0';
185}
186
187//******************************************************************************
188//******************************************************************************
189HANDLE WIN32API CreateFileA(LPCSTR lpszName, DWORD fdwAccess, DWORD fdwShareMode,
190 LPSECURITY_ATTRIBUTES lpsa, DWORD fdwCreate,
191 DWORD fdwAttrsAndFlags, HANDLE hTemplateFile)
192{
193 dprintf(("CreateFileA %s", lpszName));
194 return(HMCreateFile(lpszName,
195 fdwAccess,
196 fdwShareMode,
197 lpsa,
198 fdwCreate,
199 fdwAttrsAndFlags,
200 hTemplateFile));
201}
202
203//******************************************************************************
204//******************************************************************************
205HANDLE WIN32API CreateFileW(LPCWSTR lpszName, DWORD fdwAccess, DWORD fdwShareMode,
206 LPSECURITY_ATTRIBUTES lpsa, DWORD fdwCreate,
207 DWORD fdwAttrsAndFlags, HANDLE hTemplateFile)
208{
209 HANDLE rc;
210 char *astring;
211
212 astring = UnicodeToAsciiString((LPWSTR)lpszName);
213 rc = CreateFileA(astring, fdwAccess, fdwShareMode,
214 lpsa, fdwCreate, fdwAttrsAndFlags,
215 hTemplateFile);
216 FreeAsciiString(astring);
217 return(rc);
218}
219//******************************************************************************
220//******************************************************************************
221HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName, WIN32_FIND_DATAA *lpFindFileData)
222{
223 return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindFileData,
224 FindExSearchNameMatch, NULL, 0);
225}
226/*****************************************************************************
227 * Name : HANDLE WIN32API FindFirstFileExA
228 * Purpose : The FindFirstFileExA function searches a directory for a file
229 * whose name and attributes match those specified in the
230 * function call.
231 * Parameters: LPCSTR lpFileName pointer to the name of the file
232 * to search for
233 * FINDEX_INFO_LEVELS fInfoLevelId information level of the returned data
234 * LPVOID lpFindFileData pointer to the returned information
235 * FINDEX_SEARCH_OPS fSearchOp type of filtering to perform
236 * LPVOID lpSearchFilter pointer to search criteria
237 * DWORD dwAdditionalFlags additional search control flags
238 * Variables :
239 * Result : If the function succeeds, the return value is a search handle
240 * that can be used in a subsequent call to the FindNextFile or
241 * FindClose functions.
242 * If the function fails, the return value is INVALID_HANDLE_VALUE
243 * Remark :
244 * Status :
245 *
246 * Author : SvL
247 *****************************************************************************/
248HANDLE WIN32API FindFirstFileExA(LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId,
249 LPVOID lpFindFileData,
250 FINDEX_SEARCH_OPS fSearchOp,
251 LPVOID lpSearchFilter,
252 DWORD dwAdditionalFlags)
253{
254 HANDLE hFind;
255
256 if(lpFileName == NULL || lpFindFileData == NULL || lpSearchFilter != NULL)
257 {
258 dprintf(("!ERROR!: invalid parameter(s)"));
259 SetLastError(ERROR_INVALID_PARAMETER);
260 return INVALID_HANDLE_VALUE;
261 }
262
263 if(fSearchOp == FindExSearchLimitToDevices) {
264 dprintf(("!ERROR!: FindExSearchLimitToDevices not implemented"));
265 SetLastError(ERROR_NOT_SUPPORTED);
266 return INVALID_HANDLE_VALUE;
267 }
268 else
269 if(fSearchOp == FindExSearchLimitToDirectories) {
270 //NOTE: According to the SDK docs we are allowed to silently ignore this option
271 dprintf(("!WARNING!: FindExSearchLimitToDirectories IGNORED"));
272 fSearchOp = FindExSearchNameMatch;
273 }
274 if(dwAdditionalFlags != 0) {
275 dprintf(("!ERROR!: options not implemented 0x%08x 0x%08lx\n", fSearchOp, dwAdditionalFlags ));
276 SetLastError(ERROR_NOT_SUPPORTED);
277 return INVALID_HANDLE_VALUE;
278 }
279
280 dprintf(("FindFirstFileExA %s %x %x %x %x %x", lpFileName, fInfoLevelId, lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags));
281
282 switch(fInfoLevelId)
283 {
284 case FindExInfoStandard:
285 {
286 char *filename;
287 int namelen;
288
289 //Strip the backslash if 'x:\'. This function is supposed
290 //to work in that case, but fail with 'x:\directory\'
291 namelen = strlen(lpFileName);
292 if(namelen == 3 && lpFileName[1] == ':' && lpFileName[2] == '\\')
293 {
294 filename = (char *)alloca(namelen+1);
295 strcpy(filename, lpFileName);
296 filename[namelen-1] = 0;
297 }
298 else
299 filename = (char *)lpFileName;
300
301 return (HANDLE)OSLibDosFindFirst(filename, (WIN32_FIND_DATAA *)lpFindFileData);
302 }
303
304 default: //should never happen
305 dprintf(("!ERROR! unsupported fInfoLevelId"));
306 SetLastError(ERROR_INVALID_PARAMETER);
307 break;
308 }
309 return INVALID_HANDLE_VALUE;
310}
311//******************************************************************************
312//******************************************************************************
313HANDLE WINAPI FindFirstFileW(LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindFileData)
314{
315 return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindFileData,
316 FindExSearchNameMatch, NULL, 0);
317}
318/*****************************************************************************
319 * Name : HANDLE WIN32API FindFirstFileExW
320 * Purpose : The FindFirstFileExW function searches a directory for a file
321 * whose name and attributes match those specified in the
322 * function call.
323 * Parameters: LPCWSTR lpFileName pointer to the name of the file
324 * to search for
325 * FINDEX_INFO_LEVELS fInfoLevelId information level of the returned data
326 * LPVOID lpFindFileData pointer to the returned information
327 * FINDEX_SEARCH_OPS fSearchOp type of filtering to perform
328 * LPVOID lpSearchFilter pointer to search criteria
329 * DWORD dwAdditionalFlags additional search control flags
330 * Variables :
331 * Result : If the function succeeds, the return value is a search handle
332 * that can be used in a subsequent call to the FindNextFile or
333 * FindClose functions.
334 * If the function fails, the return value is INVALID_HANDLE_VALUE
335 * Remark :
336 * Status :
337 *
338 * Author : Wine
339 *****************************************************************************/
340HANDLE WIN32API FindFirstFileExW(LPCWSTR lpFileName,
341 FINDEX_INFO_LEVELS fInfoLevelId,
342 LPVOID lpFindFileData,
343 FINDEX_SEARCH_OPS fSearchOp,
344 LPVOID lpSearchFilter,
345 DWORD dwAdditionalFlags)
346{
347 HANDLE handle;
348 WIN32_FIND_DATAA dataA;
349 LPVOID _lpFindFileData;
350 LPSTR pathA;
351
352 switch(fInfoLevelId)
353 {
354 case FindExInfoStandard:
355 {
356 _lpFindFileData = &dataA;
357 }
358 break;
359 default:
360 dprintf(("!ERROR! unsupported fInfoLevelId"));
361 SetLastError(ERROR_INVALID_PARAMETER);
362 break;
363 }
364
365 pathA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
366 handle = FindFirstFileExA(pathA, fInfoLevelId, _lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags);
367 HeapFree( GetProcessHeap(), 0, pathA );
368 if (handle == INVALID_HANDLE_VALUE) return handle;
369
370 switch(fInfoLevelId)
371 {
372 case FindExInfoStandard:
373 {
374 WIN32_FIND_DATAW *dataW = (WIN32_FIND_DATAW*) lpFindFileData;
375 dataW->dwFileAttributes = dataA.dwFileAttributes;
376 dataW->ftCreationTime = dataA.ftCreationTime;
377 dataW->ftLastAccessTime = dataA.ftLastAccessTime;
378 dataW->ftLastWriteTime = dataA.ftLastWriteTime;
379 dataW->nFileSizeHigh = dataA.nFileSizeHigh;
380 dataW->nFileSizeLow = dataA.nFileSizeLow;
381 MultiByteToWideChar( CP_ACP, 0, dataA.cFileName, -1,
382 dataW->cFileName, sizeof(dataW->cFileName)/sizeof(WCHAR) );
383 MultiByteToWideChar( CP_ACP, 0, dataA.cAlternateFileName, -1,
384 dataW->cAlternateFileName,
385 sizeof(dataW->cAlternateFileName)/sizeof(WCHAR) );
386 }
387 break;
388 }
389 return handle;
390}
391//******************************************************************************
392// internal function for faster access (SHELL32)
393//******************************************************************************
394HANDLE WIN32API FindFirstFileMultiA(LPCSTR lpFileName,
395 WIN32_FIND_DATAA * lpFindFileData,
396 DWORD * count)
397{
398 dprintf(("FindFirstFileMultiA %s %x %x", lpFileName, lpFindFileData, count));
399 return (HANDLE)OSLibDosFindFirstMulti(lpFileName,lpFindFileData,count);
400}
401//******************************************************************************
402//******************************************************************************
403BOOL WIN32API FindNextFileA(HANDLE hFindFile, WIN32_FIND_DATAA * lpFindFileData)
404{
405 return OSLibDosFindNext(hFindFile,lpFindFileData);
406}
407//******************************************************************************
408// internal function for faster access (SHELL32)
409//******************************************************************************
410BOOL WIN32API FindNextFileMultiA(HANDLE hFindFile, WIN32_FIND_DATAA * lpFindFileData,
411 DWORD *count)
412{
413 dprintf(("FindNextFileMultiA %x %x %x", hFindFile, lpFindFileData, count));
414 return OSLibDosFindNextMulti(hFindFile,lpFindFileData,count);
415}
416//******************************************************************************
417//******************************************************************************
418BOOL WIN32API FindNextFileW(HANDLE hFindFile, WIN32_FIND_DATAW * lpFindFileData)
419{
420 WIN32_FIND_DATAA wfda;
421 BOOL rc;
422
423 rc = OSLibDosFindNext(hFindFile,&wfda);
424
425 if(rc == 0) {
426 memset(lpFindFileData, 0, sizeof(WIN32_FIND_DATAW));
427 }
428 else {
429 // convert back the result structure
430 memcpy(lpFindFileData,
431 &wfda,
432 sizeof(WIN32_FIND_DATAA));
433
434 lstrcpynAtoW (lpFindFileData->cFileName,
435 wfda.cFileName,
436 sizeof(wfda.cFileName));
437
438 lstrcpynAtoW (lpFindFileData->cAlternateFileName,
439 wfda.cAlternateFileName,
440 sizeof(wfda.cAlternateFileName));
441 }
442 return rc;
443}
444//******************************************************************************
445//******************************************************************************
446BOOL WIN32API FindClose(HANDLE hFindFile)
447{
448 return OSLibDosFindClose(hFindFile);
449}
450//******************************************************************************
451//******************************************************************************
452INT WIN32API CompareFileTime(FILETIME * lpft1, FILETIME * lpft2)
453{
454 if (lpft1 == NULL || lpft2 == NULL) {
455 SetLastError(ERROR_INVALID_PARAMETER);
456 return -1;
457 }
458
459 if(lpft1->dwHighDateTime > lpft2->dwHighDateTime)
460 return 1;
461
462 if(lpft1->dwHighDateTime < lpft2->dwHighDateTime)
463 return -1;
464
465 if(lpft1->dwLowDateTime > lpft2->dwLowDateTime)
466 return 1;
467
468 if(lpft1->dwLowDateTime < lpft2->dwLowDateTime)
469 return -1;
470
471 return 0; //equal
472}
473//******************************************************************************
474//******************************************************************************
475BOOL WIN32API CopyFileA(LPCSTR arg1, LPCSTR arg2, BOOL arg3)
476{
477 dprintf(("CopyFileA %s %s %d", arg1, arg2, arg3));
478 return OSLibDosCopyFile(arg1, arg2, arg3);
479}
480//******************************************************************************
481//******************************************************************************
482BOOL WIN32API CopyFileW(LPCWSTR arg1, LPCWSTR arg2, BOOL arg3)
483{
484 BOOL rc;
485 char *astring1, *astring2;
486
487 astring1 = UnicodeToAsciiString((LPWSTR)arg1);
488 astring2 = UnicodeToAsciiString((LPWSTR)arg2);
489 rc = CopyFileA(astring1, astring2, arg3);
490 FreeAsciiString(astring2);
491 FreeAsciiString(astring1);
492 return(rc);
493}
494/*****************************************************************************
495 * Name : BOOL WIN32API CopyFileExA
496 * Purpose : The CopyFileExA function copies an existing file to a new file.
497 * This function preserves extended attributes, OLE structured
498 * storage, NTFS alternate data streams, and file attributes.
499 * Security attributes for the existing file are not copied to
500 * the new file.
501 * Parameters: LPCSTR lpExistingFileName pointer to name of an existing file
502 * LPCSTR lpNewFileName pointer to filename to copy to
503 * LPPROGRESS_ROUTINE lpProgressRoutine pointer to the callback function
504 * LPVOID lpData to be passed to the callback function
505 * LPBOOL pbCancel flag that can be used to cancel the operation
506 * DWORD dwCopyFlags flags that specify how the file is copied
507 * Variables :
508 * Result : f the function succeeds, the return value is nonzero.
509 * If the function fails, the return value is zero.
510 * To get extended error information call GetLastError.
511 * Remark :
512 * Status : UNTESTED STUB
513 *
514 * Author : Markus Montkowski [Thu, 1998/05/19 11:46]
515 *****************************************************************************/
516
517BOOL WIN32API CopyFileExA( LPCSTR lpExistingFileName,
518 LPCSTR lpNewFileName,
519 LPPROGRESS_ROUTINE lpProgressRoutine,
520 LPVOID lpData,
521 LPBOOL pbCancel,
522 DWORD dwCopyFlags)
523{
524
525 dprintf(("KERNEL32: CopyFileExA(%08x,%08x,%08x,%08x,%08x,%08x) not properly implemented\n",
526 lpExistingFileName,
527 lpNewFileName,
528 lpProgressRoutine,
529 lpData,
530 pbCancel,
531 dwCopyFlags
532 ));
533
534 BOOL failIfExists = FALSE;
535
536 /*
537 * Interpret the only flag that CopyFile can interpret.
538 */
539 if((dwCopyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
540 {
541 failIfExists = TRUE;
542 }
543
544 return CopyFileA(lpExistingFileName, lpNewFileName, failIfExists);
545}
546
547
548/*****************************************************************************
549 * Name : BOOL WIN32API CopyFileExW
550 * Purpose : The CopyFileExW function copies an existing file to a new file.
551 * This function preserves extended attributes, OLE structured
552 * storage, NTFS alternate data streams, and file attributes.
553 * Security attributes for the existing file are not copied to
554 * the new file.
555 * Parameters: LPCWSTR lpExistingFileName pointer to name of an existing file
556 * LPCWSTR lpNewFileName pointer to filename to copy to
557 * LPPROGRESS_ROUTINE lpProgressRoutine pointer to the callback function
558 * LPVOID lpData to be passed to the callback function
559 * LPBOOL pbCancel flag that can be used to cancel the operation
560 * DWORD dwCopyFlags flags that specify how the file is copied
561 * Variables :
562 * Result : f the function succeeds, the return value is nonzero.
563 * If the function fails, the return value is zero.
564 * To get extended error information call GetLastError.
565 * Remark :
566 * Status : UNTESTED STUB
567 *
568 * Author : Markus Montkowski [Thu, 1998/05/19 11:46]
569 *****************************************************************************/
570
571BOOL WIN32API CopyFileExW( LPCWSTR lpExistingFileName,
572 LPCWSTR lpNewFileName,
573 LPPROGRESS_ROUTINE lpProgressRoutine,
574 LPVOID lpData,
575 LPBOOL pbCancel,
576 DWORD dwCopyFlags)
577{
578 LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpExistingFileName );
579 LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpNewFileName );
580
581 BOOL ret = CopyFileExA(sourceA,
582 destA,
583 lpProgressRoutine,
584 lpData,
585 pbCancel,
586 dwCopyFlags);
587
588 HeapFree( GetProcessHeap(), 0, sourceA );
589 HeapFree( GetProcessHeap(), 0, destA );
590
591 return ret;
592}
593//******************************************************************************
594//******************************************************************************
595BOOL WIN32API DeleteFileA(LPCSTR lpszFile)
596{
597 BOOL rc;
598
599#if 0
600 if((strstr(lpszFile, "odin32_") || strstr(lpszFile, "pe_")) && strstr(lpszFile, ".log")) {
601 return TRUE;
602 }
603#endif
604
605 if(lpszFile == NULL) {
606 SetLastError(ERROR_INVALID_PARAMETER); //??
607 return FALSE;
608 }
609 //If the app is deleting a shellink file (.lnk), then we must delete the WPS object
610 if(OSLibIsShellLink((LPSTR)lpszFile))
611 {
612 OSLibWinDeleteObject((LPSTR)lpszFile);
613 }
614
615 rc = OSLibDosDelete((LPSTR)lpszFile);
616 if(!rc) {
617 dprintf(("DeleteFileA %s returned FALSE; last error %x", lpszFile, GetLastError()));
618 if(GetLastError() == ERROR_BAD_UNIT) {
619 return TRUE;
620 }
621 }
622 else dprintf(("DeleteFileA %s", lpszFile));
623
624 return rc;
625}
626//******************************************************************************
627//******************************************************************************
628BOOL WIN32API DeleteFileW(LPCWSTR arg1)
629{
630 BOOL rc;
631 char *astring;
632
633 astring = UnicodeToAsciiString((LPWSTR)arg1);
634 rc = DeleteFileA(astring);
635 FreeAsciiString(astring);
636 return(rc);
637}
638//******************************************************************************
639//******************************************************************************
640UINT WIN32API GetTempFileNameA(LPCSTR lpPathName, LPCSTR lpPrefixString,
641 UINT uUnique, LPSTR lpTempFileName)
642{
643 dprintf(("GetTempFileNameA %s %s", lpPathName, lpPrefixString));
644 UINT rc = O32_GetTempFileName(lpPathName, lpPrefixString, uUnique, lpTempFileName);
645 dprintf(("GetTempFileNameA: returns %d (%s)\n", rc, rc > 0 && lpTempFileName ? lpTempFileName : "<nothing>"));
646 return rc;
647}
648//******************************************************************************
649//******************************************************************************
650UINT WIN32API GetTempFileNameW(LPCWSTR lpPathName, LPCWSTR lpPrefixString,
651 UINT uUnique, LPWSTR lpTempFileName)
652{
653 char *asciipath, *asciiprefix;
654 char *asciitemp = (char *)malloc(MAX_PATH+1);
655 UINT rc;
656
657 asciipath = UnicodeToAsciiString((LPWSTR)lpPathName);
658 asciiprefix = UnicodeToAsciiString((LPWSTR)lpPrefixString);
659 rc = GetTempFileNameA(asciipath, asciiprefix, uUnique, asciitemp);
660 if(rc) AsciiToUnicode(asciitemp, lpTempFileName);
661 FreeAsciiString(asciiprefix);
662 FreeAsciiString(asciipath);
663 free(asciitemp);
664 return(rc);
665}
666//******************************************************************************
667//******************************************************************************
668BOOL WIN32API ReadFile(HANDLE hFile, PVOID pBuffer, DWORD dwLength,
669 PDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
670{
671 if(lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
672 if(dwLength == 0) {
673 dprintf(("!WARNING!: Nothing to do"));
674 //TODO: should we fail here instead?? (wine doesn't)
675 return TRUE;
676 }
677 return (HMReadFile(hFile,
678 pBuffer,
679 dwLength,
680 lpNumberOfBytesRead,
681 lpOverlapped, NULL));
682}
683//******************************************************************************
684//******************************************************************************
685BOOL WIN32API ReadFileEx(HANDLE hFile,
686 LPVOID lpBuffer,
687 DWORD nNumberOfBytesToRead,
688 LPOVERLAPPED lpOverlapped,
689 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
690{
691 if(nNumberOfBytesToRead == 0) {
692 dprintf(("!WARNING!: Nothing to do"));
693 //TODO: should we fail here instead?? (wine doesn't)
694 return TRUE;
695 }
696 if(!lpOverlapped || !lpCompletionRoutine) {
697 dprintf(("!WARNING!: !lpOverlapped || !lpCompletionRoutine"));
698 SetLastError(ERROR_INVALID_PARAMETER);
699 return FALSE;
700 }
701 //SDK docs say ReadFileEx will fail if this condition is true
702 if(GetFileType(hFile) == FILE_TYPE_PIPE && (lpOverlapped->Offset || lpOverlapped->OffsetHigh)) {
703 dprintf(("!WARNING!: lpOverlapped->Offset & lpOverlapped->OffsetHigh must be ZERO for named pipes"));
704 SetLastError(ERROR_INVALID_PARAMETER);
705 return FALSE;
706 }
707 return (HMReadFile(hFile,
708 lpBuffer,
709 nNumberOfBytesToRead, NULL,
710 lpOverlapped, lpCompletionRoutine));
711}
712//******************************************************************************
713//******************************************************************************
714BOOL WIN32API WriteFile(HANDLE hFile, LPCVOID buffer, DWORD nrbytes,
715 LPDWORD nrbyteswritten, LPOVERLAPPED lpOverlapped)
716{
717 if(nrbyteswritten) *nrbyteswritten = 0;
718 if(nrbytes == 0) {
719 dprintf(("!WARNING!: Nothing to do"));
720 //TODO: should we fail here instead?? (wine doesn't)
721 return TRUE;
722 }
723
724 return (HMWriteFile(hFile,
725 buffer,
726 nrbytes,
727 nrbyteswritten,
728 lpOverlapped, NULL));
729}
730/*****************************************************************************
731 * Name : BOOL WriteFileEx
732 * Purpose : The WriteFileEx function writes data to a file. It is designed
733 * solely for asynchronous operation, unlike WriteFile, which is
734 * designed for both synchronous and asynchronous operation.
735 * WriteFileEx reports its completion status asynchronously,
736 * calling a specified completion routine when writing is completed
737 * and the calling thread is in an alertable wait state.
738 * Parameters: HANDLE hFile handle of file to write
739 * LPVOID lpBuffer address of buffer
740 * DWORD nNumberOfBytesToRead number of bytes to write
741 * LPOVERLAPPED lpOverlapped address of offset
742 * LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine address of completion routine
743 * Variables :
744 * Result : TRUE / FALSE
745 * Remark :
746 * Status : UNTESTED STUB
747 *
748 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
749 *****************************************************************************/
750
751BOOL WIN32API WriteFileEx(HANDLE hFile,
752 LPCVOID lpBuffer,
753 DWORD nNumberOfBytesToWrite,
754 LPOVERLAPPED lpOverlapped,
755 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
756{
757 if(nNumberOfBytesToWrite == 0) {
758 dprintf(("!WARNING!: Nothing to do"));
759 //TODO: should we fail here instead?? (wine doesn't)
760 return TRUE;
761 }
762 if(!lpOverlapped || !lpCompletionRoutine) {
763 dprintf(("!WARNING!: !lpOverlapped || !lpCompletionRoutine"));
764 SetLastError(ERROR_INVALID_PARAMETER);
765 return FALSE;
766 }
767 //SDK docs say WriteFileEx will fail if this condition is true
768 if(GetFileType(hFile) == FILE_TYPE_PIPE && (lpOverlapped->Offset || lpOverlapped->OffsetHigh)) {
769 dprintf(("!WARNING!: lpOverlapped->Offset & lpOverlapped->OffsetHigh must be ZERO for named pipes"));
770 SetLastError(ERROR_INVALID_PARAMETER);
771 return FALSE;
772 }
773 return (HMWriteFile(hFile,
774 (LPVOID)lpBuffer,
775 nNumberOfBytesToWrite, NULL,
776 lpOverlapped, lpCompletionRoutine));
777}
778//******************************************************************************
779//******************************************************************************
780DWORD WIN32API GetFileAttributesA(LPCSTR lpszFileName)
781{
782 DWORD rc, error;
783
784 //Disable error popus.
785 ULONG oldmode = SetErrorMode(SEM_FAILCRITICALERRORS);
786
787 rc = OSLibGetFileAttributes((LPSTR)lpszFileName);
788
789 SetErrorMode(oldmode);
790
791 //SvL: Open32 returns FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_NORMAL for
792 // directories whereas NT 4 (SP6) only returns FILE_ATTRIBUTE_DIRECTORY
793 if(rc != -1 && (rc & FILE_ATTRIBUTE_DIRECTORY)) {
794 rc = FILE_ATTRIBUTE_DIRECTORY;
795 }
796
797#if 0 // need more tests, maybe there is also a better way to hide simulated b:
798 if(rc == -1 && lpszFileName != NULL && !strnicmp(lpszFileName, "B:", 2))
799 {
800 error = GetLastError();
801 if(error = ERROR_DISK_CHANGE)
802 SetLastError(ERROR_NOT_READY);
803 else
804 SetLastError(error);
805 }
806#endif
807 dprintf(("KERNEL32: GetFileAttributes of %s returned %d\n", lpszFileName, rc));
808 return(rc);
809}
810//******************************************************************************
811//******************************************************************************
812DWORD WIN32API GetFileAttributesW(LPCWSTR arg1)
813{
814 DWORD rc;
815 char *astring;
816
817 astring = UnicodeToAsciiString((LPWSTR)arg1);
818 dprintf(("GetFileAttributesW %s", astring));
819 rc = GetFileAttributesA(astring);
820 FreeAsciiString(astring);
821 return(rc);
822}
823//******************************************************************************
824//******************************************************************************
825BOOL WIN32API SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
826{
827 dprintf(("KERNEL32: SetFileAttributes of %s", lpFileName));
828 return O32_SetFileAttributes(lpFileName, dwFileAttributes);
829}
830//******************************************************************************
831//******************************************************************************
832BOOL WIN32API SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
833{
834 char *asciifile;
835 BOOL rc;
836
837 asciifile = UnicodeToAsciiString((LPWSTR)lpFileName);
838 rc = SetFileAttributesA(asciifile, dwFileAttributes);
839 FreeAsciiString(asciifile);
840 return(rc);
841}
842//******************************************************************************
843//******************************************************************************
844DWORD WIN32API GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer,
845 LPSTR *lpFilePart)
846{
847 char *ptr, *lpszFileName;
848 DWORD rc;
849
850 dprintf(("KERNEL32: GetFullPathName(%s,%d,0x%X)", lpFileName, nBufferLength, lpBuffer));
851
852 lpszFileName = strdup(lpFileName);
853
854 while((ptr = strchr(lpszFileName, '/')) != NULL)
855 *ptr = '\\';
856
857 rc = O32_GetFullPathName(lpszFileName, nBufferLength, lpBuffer, lpFilePart);
858
859#ifdef DEBUG
860 if (rc > nBufferLength) {
861 dprintf(("KERNEL32: GetFullPathName returns %d (needs a bgger buffer)", rc));
862 } else if (rc > 0) {
863 dprintf(("KERNEL32: GetFullPathName returns %d (%s,%s)", rc, lpBuffer,
864 lpFilePart ? *lpFilePart : NULL));
865 }
866#endif
867
868 free(lpszFileName);
869
870 return rc;
871}
872//******************************************************************************
873//******************************************************************************
874DWORD WIN32API GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength,
875 LPWSTR lpBuffer, LPWSTR *lpFilePart)
876{
877 char *astring = NULL, *asciibuffer = NULL, *asciipart = NULL;
878 DWORD rc;
879
880 if(nBufferLength) {
881 asciibuffer = (char *)malloc(nBufferLength+1);
882 }
883 astring = UnicodeToAsciiString((LPWSTR)lpFileName);
884
885 rc = GetFullPathNameA(astring, nBufferLength,
886 asciibuffer, &asciipart);
887
888 if(rc>0 && rc<nBufferLength && asciibuffer)
889 AsciiToUnicode(asciibuffer,
890 lpBuffer);
891
892 if(lpFilePart) {
893 if (asciipart == NULL)
894 *lpFilePart = NULL;
895 else
896 *lpFilePart = lpBuffer + ((int)asciipart - (int)asciibuffer);
897 }
898
899 FreeAsciiString(astring);
900 if(asciibuffer) free(asciibuffer);
901 return(rc);
902}
903//******************************************************************************
904//******************************************************************************
905BOOL WIN32API MoveFileA(LPCSTR arg1, LPCSTR arg2)
906{
907 dprintf(("KERNEL32: MoveFileA %s %s", arg1, arg2));
908 return OSLibDosMoveFile(arg1, arg2);
909}
910//******************************************************************************
911//******************************************************************************
912
913
914/*****************************************************************************
915 * Name : MoveFileExA
916 * Purpose : Move or delete a file
917 * Parameters: LPCSTR lpExistingFileName
918 * LPCSTR lpNewFileName
919 * DWORD dwFlags
920 * Variables :
921 * Result :
922 * Remark : "delete on system-reboot" feature is not supported!
923 * Status :
924 *
925 * Author : Patrick Haller [2001-08-30]
926 *****************************************************************************/
927
928BOOL WIN32API MoveFileExA(LPCSTR lpszOldFilename,
929 LPCSTR lpszNewFilename,
930 DWORD fdwFlags)
931{
932 dprintf(("KERNEL32: MoveFileExA %s to %s %x, not complete!\n",
933 lpszOldFilename,
934 lpszNewFilename,
935 fdwFlags));
936
937 // this parameter combination is illegal
938 if ( (fdwFlags & MOVEFILE_DELAY_UNTIL_REBOOT) &&
939 (fdwFlags & MOVEFILE_COPY_ALLOWED) )
940 {
941 // Note: error code not verified
942 SetLastError(ERROR_INVALID_PARAMETER);
943 return FALSE;
944 }
945
946 // first, we take care about the special cases
947 if (fdwFlags && MOVEFILE_DELAY_UNTIL_REBOOT)
948 {
949 // We cannot really support this in any other way than
950 // to call the IBMCSFLK driver. As the first place I've encountered
951 // this call is Microsoft ACMSETUP wanting to replace OLEPRO32.DLL
952 // in the ODIN system directory, we are better skipping the call.
953
954 // Anyway, this is only supported under Windows NT
955 fdwFlags &= ~MOVEFILE_DELAY_UNTIL_REBOOT;
956
957 // Until we support this, we have to intercept
958 // lpszNewFilename == NULL
959 if (NULL == lpszNewFilename)
960 {
961 // try to delete the filename
962 dprintf(("KERNEL32-MoveFileExA: trying to delete file [%s], skipped.",
963 lpszOldFilename));
964
965 SetLastError( NO_ERROR );
966 return TRUE;
967 }
968 }
969
970 if (fdwFlags && MOVEFILE_COPY_ALLOWED)
971 {
972 // if lpszOldFilename and lpszNewFilename refer to different
973 // volumes, this flag controls if a copy operation is allowed.
974 }
975
976 if (fdwFlags && MOVEFILE_REPLACE_EXISTING)
977 {
978 // We can only attempt to
979 // 1 move away the current file if existing,
980 // 2 do the current move operation
981 // 3 if succesful, delete the backup
982 // otherwise restore the original file
983 }
984
985 return OSLibDosMoveFile(lpszOldFilename,
986 lpszNewFilename);
987}
988//******************************************************************************
989//******************************************************************************
990BOOL WIN32API MoveFileW(LPCWSTR lpSrc, LPCWSTR lpDest)
991{
992 char *asciisrc, *asciidest;
993 BOOL rc;
994
995 asciisrc = UnicodeToAsciiString((LPWSTR)lpSrc);
996 asciidest = UnicodeToAsciiString((LPWSTR)lpDest);
997 rc = MoveFileA(asciisrc, asciidest);
998 FreeAsciiString(asciisrc);
999 FreeAsciiString(asciidest);
1000 return(rc);
1001}
1002//******************************************************************************
1003//******************************************************************************
1004BOOL WIN32API MoveFileExW(LPCWSTR lpSrc, LPCWSTR lpDest, DWORD fdwFlags)
1005{
1006 dprintf(("KERNEL32: MoveFileExW %ls to %ls %x",
1007 lpSrc,
1008 lpDest,
1009 fdwFlags));
1010
1011 char *asciisrc,
1012 *asciidest;
1013 BOOL rc;
1014
1015 asciisrc = UnicodeToAsciiString((LPWSTR)lpSrc);
1016 if (NULL != lpDest)
1017 asciidest = UnicodeToAsciiString((LPWSTR)lpDest);
1018 else
1019 asciidest = NULL;
1020
1021 rc = MoveFileExA(asciisrc,
1022 asciidest,
1023 fdwFlags);
1024
1025 if (NULL != asciidest)
1026 FreeAsciiString(asciidest);
1027
1028 FreeAsciiString(asciisrc);
1029
1030 return(rc);
1031}
1032//******************************************************************************
1033//Behaviour in NT 4, SP6:
1034//- converts long filename to 8.3 short filname (TODO: not yet done here!)
1035//- fails on volume that doesn't support 8.3 filenames
1036//- if lpszShortPath 0 or cchBuffer too small -> return required length
1037// (INCLUDING 0 terminator)
1038//- if lpszLongPath == NULL -> ERROR_INVALID_PARAMETER (return 0)
1039//- if lpszLongPath empty -> proceed as if nothing is wrong
1040//- does NOT clear the last error if successful!
1041//- if successful -> return length of string (excluding 0 terminator)
1042//******************************************************************************
1043DWORD WIN32API GetShortPathNameA(LPCTSTR lpszLongPath,
1044 LPTSTR lpszShortPath,
1045 DWORD cchBuffer)
1046{
1047 char short_name[MAX_PATHNAME_LEN]; /* Long pathname in Unix format */
1048 int length, marker = 0;
1049 LPSTR tmpshortpath,tmplongpath;
1050 DWORD attr, sp = 0, lp = 0;
1051 int tmplen, drive;
1052
1053 dprintf(("KERNEL32: GetShortPathNameA %s", lpszLongPath));
1054
1055 if(!lpszLongPath) {
1056 SetLastError(ERROR_INVALID_PARAMETER);
1057 return 0;
1058 }
1059 if (!lpszLongPath[0]) {
1060 SetLastError(ERROR_BAD_PATHNAME);
1061 return 0;
1062 }
1063
1064 if ( ( tmpshortpath = (char*) HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) {
1065 SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
1066 return 0;
1067 }
1068
1069 if ( ( tmplongpath = (char*) HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) {
1070 SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
1071 return 0;
1072 }
1073
1074 lstrcpyA(tmplongpath,lpszLongPath);
1075
1076 /* check for drive letter */
1077 if ( lpszLongPath[1] == ':' ) {
1078 tmpshortpath[0] = lpszLongPath[0];
1079 tmpshortpath[1] = ':';
1080 sp = 2;
1081 lp = 2;
1082 }
1083
1084 //todo: check drive validity!
1085
1086 while ( lpszLongPath[lp] ) {
1087 marker = 0;
1088 /* check for path delimiters and reproduce them */
1089 if ( lpszLongPath[lp] == '\\' || lpszLongPath[lp] == '/' ) {
1090 if (!sp || tmpshortpath[sp-1]!= '\\')
1091 {
1092 /* strip double "\\" */
1093 tmpshortpath[sp] = '\\';
1094 sp++;
1095 }
1096 tmpshortpath[sp]=0;/*terminate string*/
1097 lp++;
1098 continue;
1099 }
1100
1101 tmplen = strcspn ( lpszLongPath + lp, "\\/" );
1102 lstrcpynA ( tmpshortpath+sp, lpszLongPath + lp, tmplen+1 );
1103
1104 /* Check, if the current element is a valid dos name */
1105 if ( DOSFS_ValidDOSName ( lpszLongPath + lp, TRUE ) ) {
1106 sp += tmplen;
1107 lp += tmplen;
1108 continue;
1109 }
1110
1111 if (tmplongpath[lp + tmplen] == '\\')
1112 {
1113 tmplongpath[lp + tmplen] = 0;
1114 marker = 1;
1115 }
1116
1117 attr = GetFileAttributesA(tmplongpath);
1118
1119 if (attr == -1)
1120 {
1121 SetLastError ( ERROR_FILE_NOT_FOUND );
1122 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1123 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1124 return 0;
1125 }
1126
1127 DOSFS_Hash(tmpshortpath+sp, short_name, FALSE, TRUE );
1128
1129 strcpy( tmpshortpath+sp, short_name);
1130 sp += strlen ( tmpshortpath+sp );
1131 if (marker)
1132 tmplongpath[lp + tmplen] = '\\';
1133 lp += tmplen;
1134
1135 }
1136
1137 tmpshortpath[sp] = 0;
1138
1139 lstrcpynA ( lpszShortPath, tmpshortpath, cchBuffer );
1140 dprintf(("returning %s\n", lpszShortPath));
1141 tmplen = strlen ( lpszShortPath );
1142
1143 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1144 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1145
1146 return tmplen;
1147}
1148//******************************************************************************
1149//******************************************************************************
1150DWORD WIN32API GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath,
1151 DWORD cchBuffer)
1152{
1153 LPSTR longpathA, shortpathA;
1154 DWORD ret = 0;
1155
1156 longpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszLongPath );
1157 shortpathA = (LPSTR) HeapAlloc ( GetProcessHeap(), 0, cchBuffer );
1158
1159 ret = GetShortPathNameA ( longpathA, shortpathA, cchBuffer );
1160 if (cchBuffer > 0 && !MultiByteToWideChar( CP_ACP, 0, shortpathA, -1, lpszShortPath, cchBuffer ))
1161 lpszShortPath[cchBuffer-1] = 0;
1162 HeapFree( GetProcessHeap(), 0, longpathA );
1163 HeapFree( GetProcessHeap(), 0, shortpathA );
1164
1165 return ret;
1166}
1167//******************************************************************************
1168//Behaviour in NT 4, SP6: (presumably the same as GetShortPathNameA; TODO check)
1169//- converts short filename to long filenames (TODO: not yet done here!)
1170//- if lpszShortPath 0 or cchBuffer too small -> return required length
1171// (INCLUDING 0 terminator)
1172//- if lpszLongPath == NULL -> ERROR_INVALID_PARAMETER (return 0)
1173//- if lpszLongPath empty -> proceed as if nothing is wrong
1174//- does NOT clear the last error if successful!
1175//- if successful -> return length of string (excluding 0 terminator)
1176//******************************************************************************
1177DWORD WINAPI GetLongPathNameA( LPCSTR lpszShortPath, LPSTR lpszLongPath,
1178 DWORD cchBuffer )
1179{
1180 int tmplen;
1181 char short_name[MAX_PATHNAME_LEN]; /* Long pathname in Unix format */
1182 WIN32_FIND_DATAA FindFileData;
1183 HANDLE hFind;
1184 DWORD sp = 0, lp = 0,attr;
1185 LPSTR tmpshortpath,tmplongpath;
1186 LPCSTR lpszShortPath1;
1187 LPSTR lpszLongPath1;
1188
1189 dprintf(("GetLongPathNameA %s %x %d", lpszShortPath, lpszLongPath, cchBuffer));
1190
1191 if(!lpszShortPath) {
1192 SetLastError(ERROR_INVALID_PARAMETER);
1193 return 0;
1194 }
1195
1196 if ( ( tmpshortpath = (char*) HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) {
1197 SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
1198 return 0;
1199 }
1200
1201 if ( ( tmplongpath = (char*) HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) {
1202 SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
1203 return 0;
1204 }
1205
1206 lpszShortPath1 = ODINHelperStripUNC(lpszShortPath);
1207 lpszLongPath1 = ODINHelperStripUNC(lpszLongPath);
1208
1209 lstrcpyA(tmpshortpath,lpszShortPath1);
1210
1211 /* check for drive letter */
1212 if ( lpszShortPath1[1] == ':' ) {
1213 tmplongpath[0] = lpszShortPath1[0];
1214
1215 tmplongpath[1] = ':';
1216 sp = 2;
1217 lp = 2;
1218 }
1219
1220 //todo: check drive validity!
1221
1222 while ( lpszShortPath1[lp] ) {
1223
1224 /* check for path delimiters and reproduce them */
1225 if ( lpszShortPath1[lp] == '\\' || lpszShortPath1[lp] == '/' ) {
1226 if (!sp || tmplongpath[sp-1]!= '\\')
1227 {
1228 /* strip double "\\" */
1229 tmplongpath[sp] = '\\';
1230 sp++;
1231 }
1232 tmplongpath[sp]=0;/*terminate string*/
1233 lp++;
1234 continue;
1235 }
1236
1237 tmplen = strcspn ( lpszShortPath1 + lp, "\\/" );
1238 lstrcpynA ( tmplongpath+sp, lpszShortPath1 + lp, tmplen+1 );
1239
1240 attr = GetFileAttributesA(tmplongpath);
1241 if (attr != -1)
1242 {
1243 sp += tmplen;
1244 lp += tmplen;
1245 continue;
1246 }
1247 else
1248 // it may be hashed name or name with weird characters!
1249 if ((tmplongpath+sp)[4] == '~')
1250 {
1251 //hashed entry Wine does linear dir search.. incredible.. we will be
1252 //better ;)
1253 if (strchr(tmplongpath+sp,'_'))
1254 {
1255 (tmplongpath+sp)[0] = '*';
1256 (tmplongpath+sp)[1] = 0;
1257 }
1258 else
1259 {
1260 (tmplongpath+sp)[4] = '*';
1261 (tmplongpath+sp)[5] = 0;
1262 }
1263 hFind = FindFirstFileExA(tmplongpath, FindExInfoStandard, &FindFileData,
1264 FindExSearchNameMatch, NULL, 0 );
1265
1266 if (hFind == INVALID_HANDLE_VALUE)
1267 {
1268 //no possible variants!
1269 SetLastError ( ERROR_FILE_NOT_FOUND );
1270 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1271 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1272 return 0;
1273 }
1274 else
1275 do
1276 {
1277 DOSFS_Hash(FindFileData.cFileName, short_name, FALSE, TRUE );
1278 //this happens on files like [hello world]
1279 if (!lstrncmpA(short_name, lpszShortPath1+lp, (lpszShortPath1+lp+tmplen)[-1] == '.' ? tmplen-1 : tmplen ))
1280 {
1281 strcpy( tmplongpath+sp, FindFileData.cFileName);
1282 sp += strlen ( tmplongpath+sp );
1283 lp += tmplen;
1284 break;
1285 }
1286 }
1287 while (FindNextFileA(hFind, &FindFileData));
1288
1289 // no FindClose() here or else GetLastError() will not give its error
1290 if (GetLastError() == ERROR_NO_MORE_FILES)
1291 {
1292 FindClose(hFind);
1293 SetLastError ( ERROR_FILE_NOT_FOUND );
1294 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1295 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1296 return 0;
1297 }
1298 FindClose(hFind);
1299 }
1300 else
1301 {
1302 // if this file can't be found in common or hashed files
1303 // it does not exist
1304 SetLastError ( ERROR_FILE_NOT_FOUND );
1305 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1306 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1307 return 0;
1308 }
1309 }
1310 tmplongpath[sp] = 0;
1311
1312 lstrcpynA ( lpszLongPath1, tmplongpath, cchBuffer );
1313 dprintf(("returning %s\n", lpszLongPath));
1314 tmplen = strlen ( lpszLongPath );
1315
1316 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1317 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1318
1319 return tmplen;
1320}
1321//******************************************************************************
1322//******************************************************************************
1323DWORD WINAPI GetLongPathNameW( LPCWSTR lpszShortPath, LPWSTR lpszLongPath,
1324 DWORD cchBuffer )
1325{
1326 int length;
1327
1328 dprintf(("GetLongPathNameW %x %ls %d", lpszShortPath, lpszLongPath, cchBuffer));
1329 dprintf(("WARNING: WIN98 ONLY!!"));
1330
1331 if(!lpszShortPath) {
1332 SetLastError(ERROR_INVALID_PARAMETER);
1333 return 0;
1334 }
1335
1336 length = lstrlenW(lpszShortPath) + 1;
1337 if(length > cchBuffer) {
1338 if(lpszLongPath) {
1339 *lpszLongPath = 0;
1340 }
1341 return(length); //return length required (including 0 terminator)
1342 }
1343 lstrcpyW(lpszLongPath, lpszShortPath);
1344 return(length-1);
1345}
1346//******************************************************************************
1347//******************************************************************************
1348void WIN32API SetFileApisToANSI()
1349{
1350 dprintf(("!WARNING! SetFileApisToANSI() stub\n"));
1351}
1352
1353/*****************************************************************************
1354 * Name : DWORD GetCompressedFileSizeA
1355 * Purpose : The GetCompressedFileSizeA function obtains the compressed
1356 * size, in bytes, of a specified file.
1357 * Parameters: LPCTSTR lpFileName, // pointer to name of file
1358 * LPDWORD lpFileSizeHigh // pointer to DWORD to receive
1359 * high-order doubleword of file size
1360 * Variables :
1361 * Result : size of compressed file
1362 * Remark :
1363 * Status : UNTESTED
1364 *
1365 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
1366 *****************************************************************************/
1367
1368DWORD WIN32API GetCompressedFileSizeA(LPCTSTR lpFileName, LPDWORD lpFileSizeHigh)
1369{
1370 dprintf(("KERNEL32: GetCompressedFileSizeA (%s, %08xh) not implemented.\n",
1371 lpFileName,
1372 lpFileSizeHigh));
1373
1374 /* @@@PH: simply return the standard filesize */
1375 return 0;
1376}
1377
1378
1379/*****************************************************************************
1380 * Name : DWORD GetCompressedFileSizeW
1381 * Purpose : The GetCompressedFileSizeE function obtains the compressed
1382 * size, in bytes, of a specified file.
1383 * Parameters: LPCWSTR lpFileName, // pointer to name of file
1384 * LPDWORD lpFileSizeHigh // pointer to DWORD to receive
1385 * high-order doubleword of file size
1386 * Variables :
1387 * Result : size of compressed file
1388 * Remark :
1389 * Status : UNTESTED
1390 *
1391 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
1392 *****************************************************************************/
1393
1394DWORD WIN32API GetCompressedFileSizeW(LPCWSTR lpFileName, LPDWORD lpFileSizeHigh)
1395{
1396 LPCTSTR lpAsciiFileName; /* converted filename */
1397 DWORD rc; /* function result */
1398
1399 dprintf(("KERNEL32: GetCompressedFileSizeW (%s, %08xh)\n",
1400 lpFileName,
1401 lpFileSizeHigh));
1402
1403 lpAsciiFileName = UnicodeToAsciiString( (LPWSTR) lpFileName);
1404
1405 rc = GetCompressedFileSizeA(lpAsciiFileName,
1406 lpFileSizeHigh);
1407
1408 FreeAsciiString( (char *) lpAsciiFileName);
1409
1410 return (rc); /* return result */
1411}
1412
1413
1414/*****************************************************************************
1415 * Name : BOOL GetFileAttributesExA
1416 * Purpose :
1417 * Parameters:
1418 * Variables :
1419 * Result :
1420 * Remark : KERNEL32.874
1421 * Status : UNTESTED
1422 *
1423 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
1424 *****************************************************************************/
1425
1426BOOL WIN32API GetFileAttributesExA(LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
1427 LPVOID lpFileInformation)
1428{
1429 BOOL rc;
1430
1431 dprintf(("KERNEL32: GetFileAttributesExA(%s,%08xh,%08xh) mostly implemented.\n",
1432 lpFileName,
1433 fInfoLevelId,
1434 lpFileInformation));
1435
1436 if (lpFileName == NULL) return FALSE;
1437 if (lpFileInformation == NULL) return FALSE;
1438
1439 if (fInfoLevelId == GetFileExInfoStandard)
1440 {
1441 LPWIN32_FILE_ATTRIBUTE_DATA lpFad = (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
1442
1443 rc = OSLibDosGetFileAttributesEx((LPSTR)lpFileName,
1444 fInfoLevelId,
1445 lpFileInformation);
1446 return (rc);
1447 }
1448 else
1449 {
1450 dprintf(("KERNEL32: GetFileAttributesExA - invalid info level %d!\n",
1451 fInfoLevelId));
1452 return FALSE;
1453 }
1454}
1455
1456
1457/*****************************************************************************
1458 * Name : BOOL GetFileAttributesExW
1459 * Purpose :
1460 * Parameters:
1461 * Variables :
1462 * Result :
1463 * Remark : KERNEL32.875
1464 * Status : UNTESTED
1465 *
1466 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
1467 *****************************************************************************/
1468
1469BOOL WIN32API GetFileAttributesExW(LPCWSTR lpFileName,
1470 GET_FILEEX_INFO_LEVELS fInfoLevelId,
1471 LPVOID lpFileInformation)
1472{
1473 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
1474 BOOL res = GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
1475 HeapFree( GetProcessHeap(), 0, nameA );
1476 return res;
1477}
1478
1479//******************************************************************************
1480//******************************************************************************
1481HANDLE WIN32API FindFirstChangeNotificationA(LPCSTR lpPathName,
1482 BOOL bWatchSubtree,
1483 DWORD dwNotifyFilter)
1484{
1485 dprintf(("KERNEL32: FindFirstChangeNotificationA %s, Not implemented (faked)", lpPathName));
1486 return -1;
1487}
1488//******************************************************************************
1489//******************************************************************************
1490BOOL WIN32API FindNextChangeNotification(HANDLE hChange)
1491{
1492 dprintf(("KERNEL32: FindNextChangeNotification (%08xh), Not implemented\n",
1493 hChange));
1494
1495 return FALSE;
1496}
1497//******************************************************************************
1498//******************************************************************************
1499BOOL WIN32API FindCloseChangeNotification(HANDLE hChange)
1500{
1501 dprintf(("KERNEL32: OS2FindNextChangeNotification, Not implemented\n"));
1502
1503 return(TRUE);
1504}
1505/*****************************************************************************
1506 * Name : HANDLE WIN32API FindFirstChangeNotificationW
1507 * Purpose : The FindFirstChangeNotification function creates a change
1508 * notification handle and sets up initial change notification
1509 * filter conditions. A wait on a notification handle succeeds when
1510 * a change matching the filter conditions occurs in the specified
1511 * directory or subtree.
1512 * Parameters: LPCWSTR lpPathName pointer to name of directory to watch
1513 * BOOL bWatchSubtree flag for monitoring directory or
1514 * directory tree
1515 * DWORD dwNotifyFilter filter conditions to watch for
1516 * Variables :
1517 * Result : If the function succeeds, the return value is a handle to a find
1518 * change notification object.
1519 * If the function fails, the return value is INVALID_HANDLE_VALUE
1520 * Remark :
1521 * Status : UNTESTED STUB
1522 *
1523 * Author : Markus Montkowski [Tha, 1998/05/21 20:57]
1524 *****************************************************************************/
1525HANDLE WIN32API FindFirstChangeNotificationW(LPCWSTR lpPathName,
1526 BOOL bWatchSubtree,
1527 DWORD dwNotifyFilter)
1528{
1529 LPSTR lpAsciiPath;
1530 HANDLE hChange;
1531
1532 lpAsciiPath = UnicodeToAsciiString( (LPWSTR) lpPathName);
1533 hChange = FindFirstChangeNotificationA(lpAsciiPath, bWatchSubtree,
1534 dwNotifyFilter );
1535 if (lpAsciiPath) FreeAsciiString(lpAsciiPath);
1536 return hChange;
1537}
1538/*****************************************************************************
1539 * Name : BOOL GetOverlappedResult
1540 * Purpose : forward call to Open32
1541 * Parameters:
1542 * Variables :
1543 * Result :
1544 * Remark : handle translation is done in GetOverlappedResult
1545 * Status :
1546 *
1547 * Author : Patrick Haller [Fri, 1999/06/18 03:44]
1548 *****************************************************************************/
1549
1550BOOL WIN32API GetOverlappedResult(HANDLE hFile, /* [in] handle of file to check on */
1551 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1552 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1553 BOOL bWait) /* [in] wait for the transfer to complete ? */
1554{
1555 //NOTE: According to the SDK docs lpOverlapped->hEvent can be 0. This function
1556 // is supposed to wait on the file handle in that case. We don't support
1557 // this, so we just fail.
1558 if(lpOverlapped == NULL || lpOverlapped->hEvent == 0) {
1559 dprintf(("!ERROR!: lpOverlapped == NULL || lpOverlapped->hEvent == 0"));
1560 SetLastError(ERROR_INVALID_PARAMETER);
1561 return FALSE;
1562 }
1563
1564 return HMGetOverlappedResult(hFile,
1565 lpOverlapped,
1566 lpTransferred,
1567 bWait);
1568}
1569//******************************************************************************
1570//******************************************************************************
Note: See TracBrowser for help on using the repository browser.