source: trunk/src/kernel32/Fileio.cpp@ 21549

Last change on this file since 21549 was 21549, checked in by dmik, 15 years ago

kernel32: Fixed debug output in GetFullPathName*.

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)", lpBuffer, *lpFilePart));
864 }
865#endif
866
867 free(lpszFileName);
868
869 return rc;
870}
871//******************************************************************************
872//******************************************************************************
873DWORD WIN32API GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength,
874 LPWSTR lpBuffer, LPWSTR *lpFilePart)
875{
876 char *astring = NULL, *asciibuffer = NULL, *asciipart = NULL;
877 DWORD rc;
878
879 if(nBufferLength) {
880 asciibuffer = (char *)malloc(nBufferLength+1);
881 }
882 astring = UnicodeToAsciiString((LPWSTR)lpFileName);
883
884 rc = GetFullPathNameA(astring, nBufferLength,
885 asciibuffer, &asciipart);
886
887 if(rc>0 && rc<nBufferLength && asciibuffer)
888 AsciiToUnicode(asciibuffer,
889 lpBuffer);
890
891 if(lpFilePart) {
892 if (asciipart == NULL)
893 *lpFilePart = NULL;
894 else
895 *lpFilePart = lpBuffer + ((int)asciipart - (int)asciibuffer);
896 }
897
898 FreeAsciiString(astring);
899 if(asciibuffer) free(asciibuffer);
900 return(rc);
901}
902//******************************************************************************
903//******************************************************************************
904BOOL WIN32API MoveFileA(LPCSTR arg1, LPCSTR arg2)
905{
906 dprintf(("KERNEL32: MoveFileA %s %s", arg1, arg2));
907 return OSLibDosMoveFile(arg1, arg2);
908}
909//******************************************************************************
910//******************************************************************************
911
912
913/*****************************************************************************
914 * Name : MoveFileExA
915 * Purpose : Move or delete a file
916 * Parameters: LPCSTR lpExistingFileName
917 * LPCSTR lpNewFileName
918 * DWORD dwFlags
919 * Variables :
920 * Result :
921 * Remark : "delete on system-reboot" feature is not supported!
922 * Status :
923 *
924 * Author : Patrick Haller [2001-08-30]
925 *****************************************************************************/
926
927BOOL WIN32API MoveFileExA(LPCSTR lpszOldFilename,
928 LPCSTR lpszNewFilename,
929 DWORD fdwFlags)
930{
931 dprintf(("KERNEL32: MoveFileExA %s to %s %x, not complete!\n",
932 lpszOldFilename,
933 lpszNewFilename,
934 fdwFlags));
935
936 // this parameter combination is illegal
937 if ( (fdwFlags & MOVEFILE_DELAY_UNTIL_REBOOT) &&
938 (fdwFlags & MOVEFILE_COPY_ALLOWED) )
939 {
940 // Note: error code not verified
941 SetLastError(ERROR_INVALID_PARAMETER);
942 return FALSE;
943 }
944
945 // first, we take care about the special cases
946 if (fdwFlags && MOVEFILE_DELAY_UNTIL_REBOOT)
947 {
948 // We cannot really support this in any other way than
949 // to call the IBMCSFLK driver. As the first place I've encountered
950 // this call is Microsoft ACMSETUP wanting to replace OLEPRO32.DLL
951 // in the ODIN system directory, we are better skipping the call.
952
953 // Anyway, this is only supported under Windows NT
954 fdwFlags &= ~MOVEFILE_DELAY_UNTIL_REBOOT;
955
956 // Until we support this, we have to intercept
957 // lpszNewFilename == NULL
958 if (NULL == lpszNewFilename)
959 {
960 // try to delete the filename
961 dprintf(("KERNEL32-MoveFileExA: trying to delete file [%s], skipped.",
962 lpszOldFilename));
963
964 SetLastError( NO_ERROR );
965 return TRUE;
966 }
967 }
968
969 if (fdwFlags && MOVEFILE_COPY_ALLOWED)
970 {
971 // if lpszOldFilename and lpszNewFilename refer to different
972 // volumes, this flag controls if a copy operation is allowed.
973 }
974
975 if (fdwFlags && MOVEFILE_REPLACE_EXISTING)
976 {
977 // We can only attempt to
978 // 1 move away the current file if existing,
979 // 2 do the current move operation
980 // 3 if succesful, delete the backup
981 // otherwise restore the original file
982 }
983
984 return OSLibDosMoveFile(lpszOldFilename,
985 lpszNewFilename);
986}
987//******************************************************************************
988//******************************************************************************
989BOOL WIN32API MoveFileW(LPCWSTR lpSrc, LPCWSTR lpDest)
990{
991 char *asciisrc, *asciidest;
992 BOOL rc;
993
994 asciisrc = UnicodeToAsciiString((LPWSTR)lpSrc);
995 asciidest = UnicodeToAsciiString((LPWSTR)lpDest);
996 rc = MoveFileA(asciisrc, asciidest);
997 FreeAsciiString(asciisrc);
998 FreeAsciiString(asciidest);
999 return(rc);
1000}
1001//******************************************************************************
1002//******************************************************************************
1003BOOL WIN32API MoveFileExW(LPCWSTR lpSrc, LPCWSTR lpDest, DWORD fdwFlags)
1004{
1005 dprintf(("KERNEL32: MoveFileExW %ls to %ls %x",
1006 lpSrc,
1007 lpDest,
1008 fdwFlags));
1009
1010 char *asciisrc,
1011 *asciidest;
1012 BOOL rc;
1013
1014 asciisrc = UnicodeToAsciiString((LPWSTR)lpSrc);
1015 if (NULL != lpDest)
1016 asciidest = UnicodeToAsciiString((LPWSTR)lpDest);
1017 else
1018 asciidest = NULL;
1019
1020 rc = MoveFileExA(asciisrc,
1021 asciidest,
1022 fdwFlags);
1023
1024 if (NULL != asciidest)
1025 FreeAsciiString(asciidest);
1026
1027 FreeAsciiString(asciisrc);
1028
1029 return(rc);
1030}
1031//******************************************************************************
1032//Behaviour in NT 4, SP6:
1033//- converts long filename to 8.3 short filname (TODO: not yet done here!)
1034//- fails on volume that doesn't support 8.3 filenames
1035//- if lpszShortPath 0 or cchBuffer too small -> return required length
1036// (INCLUDING 0 terminator)
1037//- if lpszLongPath == NULL -> ERROR_INVALID_PARAMETER (return 0)
1038//- if lpszLongPath empty -> proceed as if nothing is wrong
1039//- does NOT clear the last error if successful!
1040//- if successful -> return length of string (excluding 0 terminator)
1041//******************************************************************************
1042DWORD WIN32API GetShortPathNameA(LPCTSTR lpszLongPath,
1043 LPTSTR lpszShortPath,
1044 DWORD cchBuffer)
1045{
1046 char short_name[MAX_PATHNAME_LEN]; /* Long pathname in Unix format */
1047 int length, marker = 0;
1048 LPSTR tmpshortpath,tmplongpath;
1049 DWORD attr, sp = 0, lp = 0;
1050 int tmplen, drive;
1051
1052 dprintf(("KERNEL32: GetShortPathNameA %s", lpszLongPath));
1053
1054 if(!lpszLongPath) {
1055 SetLastError(ERROR_INVALID_PARAMETER);
1056 return 0;
1057 }
1058 if (!lpszLongPath[0]) {
1059 SetLastError(ERROR_BAD_PATHNAME);
1060 return 0;
1061 }
1062
1063 if ( ( tmpshortpath = (char*) HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) {
1064 SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
1065 return 0;
1066 }
1067
1068 if ( ( tmplongpath = (char*) HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) {
1069 SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
1070 return 0;
1071 }
1072
1073 lstrcpyA(tmplongpath,lpszLongPath);
1074
1075 /* check for drive letter */
1076 if ( lpszLongPath[1] == ':' ) {
1077 tmpshortpath[0] = lpszLongPath[0];
1078 tmpshortpath[1] = ':';
1079 sp = 2;
1080 lp = 2;
1081 }
1082
1083 //todo: check drive validity!
1084
1085 while ( lpszLongPath[lp] ) {
1086 marker = 0;
1087 /* check for path delimiters and reproduce them */
1088 if ( lpszLongPath[lp] == '\\' || lpszLongPath[lp] == '/' ) {
1089 if (!sp || tmpshortpath[sp-1]!= '\\')
1090 {
1091 /* strip double "\\" */
1092 tmpshortpath[sp] = '\\';
1093 sp++;
1094 }
1095 tmpshortpath[sp]=0;/*terminate string*/
1096 lp++;
1097 continue;
1098 }
1099
1100 tmplen = strcspn ( lpszLongPath + lp, "\\/" );
1101 lstrcpynA ( tmpshortpath+sp, lpszLongPath + lp, tmplen+1 );
1102
1103 /* Check, if the current element is a valid dos name */
1104 if ( DOSFS_ValidDOSName ( lpszLongPath + lp, TRUE ) ) {
1105 sp += tmplen;
1106 lp += tmplen;
1107 continue;
1108 }
1109
1110 if (tmplongpath[lp + tmplen] == '\\')
1111 {
1112 tmplongpath[lp + tmplen] = 0;
1113 marker = 1;
1114 }
1115
1116 attr = GetFileAttributesA(tmplongpath);
1117
1118 if (attr == -1)
1119 {
1120 SetLastError ( ERROR_FILE_NOT_FOUND );
1121 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1122 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1123 return 0;
1124 }
1125
1126 DOSFS_Hash(tmpshortpath+sp, short_name, FALSE, TRUE );
1127
1128 strcpy( tmpshortpath+sp, short_name);
1129 sp += strlen ( tmpshortpath+sp );
1130 if (marker)
1131 tmplongpath[lp + tmplen] = '\\';
1132 lp += tmplen;
1133
1134 }
1135
1136 tmpshortpath[sp] = 0;
1137
1138 lstrcpynA ( lpszShortPath, tmpshortpath, cchBuffer );
1139 dprintf(("returning %s\n", lpszShortPath));
1140 tmplen = strlen ( lpszShortPath );
1141
1142 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1143 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1144
1145 return tmplen;
1146}
1147//******************************************************************************
1148//******************************************************************************
1149DWORD WIN32API GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath,
1150 DWORD cchBuffer)
1151{
1152 LPSTR longpathA, shortpathA;
1153 DWORD ret = 0;
1154
1155 longpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszLongPath );
1156 shortpathA = (LPSTR) HeapAlloc ( GetProcessHeap(), 0, cchBuffer );
1157
1158 ret = GetShortPathNameA ( longpathA, shortpathA, cchBuffer );
1159 if (cchBuffer > 0 && !MultiByteToWideChar( CP_ACP, 0, shortpathA, -1, lpszShortPath, cchBuffer ))
1160 lpszShortPath[cchBuffer-1] = 0;
1161 HeapFree( GetProcessHeap(), 0, longpathA );
1162 HeapFree( GetProcessHeap(), 0, shortpathA );
1163
1164 return ret;
1165}
1166//******************************************************************************
1167//Behaviour in NT 4, SP6: (presumably the same as GetShortPathNameA; TODO check)
1168//- converts short filename to long filenames (TODO: not yet done here!)
1169//- if lpszShortPath 0 or cchBuffer too small -> return required length
1170// (INCLUDING 0 terminator)
1171//- if lpszLongPath == NULL -> ERROR_INVALID_PARAMETER (return 0)
1172//- if lpszLongPath empty -> proceed as if nothing is wrong
1173//- does NOT clear the last error if successful!
1174//- if successful -> return length of string (excluding 0 terminator)
1175//******************************************************************************
1176DWORD WINAPI GetLongPathNameA( LPCSTR lpszShortPath, LPSTR lpszLongPath,
1177 DWORD cchBuffer )
1178{
1179 int tmplen;
1180 char short_name[MAX_PATHNAME_LEN]; /* Long pathname in Unix format */
1181 WIN32_FIND_DATAA FindFileData;
1182 HANDLE hFind;
1183 DWORD sp = 0, lp = 0,attr;
1184 LPSTR tmpshortpath,tmplongpath;
1185 LPSTR lpszShortPath1, lpszLongPath1;
1186
1187 dprintf(("GetLongPathNameA %s %x %d", lpszShortPath, lpszLongPath, cchBuffer));
1188
1189 if(!lpszShortPath) {
1190 SetLastError(ERROR_INVALID_PARAMETER);
1191 return 0;
1192 }
1193
1194 if ( ( tmpshortpath = (char*) HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) {
1195 SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
1196 return 0;
1197 }
1198
1199 if ( ( tmplongpath = (char*) HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) {
1200 SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
1201 return 0;
1202 }
1203
1204 lpszShortPath1 = ODINHelperStripUNC((char*)lpszShortPath);
1205 lpszLongPath1 = ODINHelperStripUNC((char*)lpszLongPath);
1206
1207 lstrcpyA(tmpshortpath,lpszShortPath1);
1208
1209 /* check for drive letter */
1210 if ( lpszShortPath1[1] == ':' ) {
1211 tmplongpath[0] = lpszShortPath1[0];
1212
1213 tmplongpath[1] = ':';
1214 sp = 2;
1215 lp = 2;
1216 }
1217
1218 //todo: check drive validity!
1219
1220 while ( lpszShortPath1[lp] ) {
1221
1222 /* check for path delimiters and reproduce them */
1223 if ( lpszShortPath1[lp] == '\\' || lpszShortPath1[lp] == '/' ) {
1224 if (!sp || tmplongpath[sp-1]!= '\\')
1225 {
1226 /* strip double "\\" */
1227 tmplongpath[sp] = '\\';
1228 sp++;
1229 }
1230 tmplongpath[sp]=0;/*terminate string*/
1231 lp++;
1232 continue;
1233 }
1234
1235 tmplen = strcspn ( lpszShortPath1 + lp, "\\/" );
1236 lstrcpynA ( tmplongpath+sp, lpszShortPath1 + lp, tmplen+1 );
1237
1238 attr = GetFileAttributesA(tmplongpath);
1239 if (attr != -1)
1240 {
1241 sp += tmplen;
1242 lp += tmplen;
1243 continue;
1244 }
1245 else
1246 // it may be hashed name or name with weird characters!
1247 if ((tmplongpath+sp)[4] == '~')
1248 {
1249 //hashed entry Wine does linear dir search.. incredible.. we will be
1250 //better ;)
1251 if (strchr(tmplongpath+sp,'_'))
1252 {
1253 (tmplongpath+sp)[0] = '*';
1254 (tmplongpath+sp)[1] = 0;
1255 }
1256 else
1257 {
1258 (tmplongpath+sp)[4] = '*';
1259 (tmplongpath+sp)[5] = 0;
1260 }
1261 hFind = FindFirstFileExA(tmplongpath, FindExInfoStandard, &FindFileData,
1262 FindExSearchNameMatch, NULL, 0 );
1263
1264 if (hFind == INVALID_HANDLE_VALUE)
1265 {
1266 //no possible variants!
1267 SetLastError ( ERROR_FILE_NOT_FOUND );
1268 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1269 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1270 return 0;
1271 }
1272 else
1273 do
1274 {
1275 DOSFS_Hash(FindFileData.cFileName, short_name, FALSE, TRUE );
1276 //this happens on files like [hello world]
1277 if (!lstrncmpA(short_name, lpszShortPath1+lp, (lpszShortPath1+lp+tmplen)[-1] == '.' ? tmplen-1 : tmplen ))
1278 {
1279 strcpy( tmplongpath+sp, FindFileData.cFileName);
1280 sp += strlen ( tmplongpath+sp );
1281 lp += tmplen;
1282 break;
1283 }
1284 }
1285 while (FindNextFileA(hFind, &FindFileData));
1286
1287 // no FindClose() here or else GetLastError() will not give its error
1288 if (GetLastError() == ERROR_NO_MORE_FILES)
1289 {
1290 FindClose(hFind);
1291 SetLastError ( ERROR_FILE_NOT_FOUND );
1292 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1293 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1294 return 0;
1295 }
1296 FindClose(hFind);
1297 }
1298 else
1299 {
1300 // if this file can't be found in common or hashed files
1301 // it does not exist
1302 SetLastError ( ERROR_FILE_NOT_FOUND );
1303 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1304 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1305 return 0;
1306 }
1307 }
1308 tmplongpath[sp] = 0;
1309
1310 lstrcpynA ( lpszLongPath1, tmplongpath, cchBuffer );
1311 dprintf(("returning %s\n", lpszLongPath));
1312 tmplen = strlen ( lpszLongPath );
1313
1314 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
1315 HeapFree ( GetProcessHeap(), 0, tmplongpath );
1316
1317 return tmplen;
1318}
1319//******************************************************************************
1320//******************************************************************************
1321DWORD WINAPI GetLongPathNameW( LPCWSTR lpszShortPath, LPWSTR lpszLongPath,
1322 DWORD cchBuffer )
1323{
1324 int length;
1325
1326 dprintf(("GetLongPathNameW %x %ls %d", lpszShortPath, lpszLongPath, cchBuffer));
1327 dprintf(("WARNING: WIN98 ONLY!!"));
1328
1329 if(!lpszShortPath) {
1330 SetLastError(ERROR_INVALID_PARAMETER);
1331 return 0;
1332 }
1333
1334 length = lstrlenW(lpszShortPath) + 1;
1335 if(length > cchBuffer) {
1336 if(lpszLongPath) {
1337 *lpszLongPath = 0;
1338 }
1339 return(length); //return length required (including 0 terminator)
1340 }
1341 lstrcpyW(lpszLongPath, lpszShortPath);
1342 return(length-1);
1343}
1344//******************************************************************************
1345//******************************************************************************
1346void WIN32API SetFileApisToANSI()
1347{
1348 dprintf(("!WARNING! SetFileApisToANSI() stub\n"));
1349}
1350
1351/*****************************************************************************
1352 * Name : DWORD GetCompressedFileSizeA
1353 * Purpose : The GetCompressedFileSizeA function obtains the compressed
1354 * size, in bytes, of a specified file.
1355 * Parameters: LPCTSTR lpFileName, // pointer to name of file
1356 * LPDWORD lpFileSizeHigh // pointer to DWORD to receive
1357 * high-order doubleword of file size
1358 * Variables :
1359 * Result : size of compressed file
1360 * Remark :
1361 * Status : UNTESTED
1362 *
1363 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
1364 *****************************************************************************/
1365
1366DWORD WIN32API GetCompressedFileSizeA(LPCTSTR lpFileName, LPDWORD lpFileSizeHigh)
1367{
1368 dprintf(("KERNEL32: GetCompressedFileSizeA (%s, %08xh) not implemented.\n",
1369 lpFileName,
1370 lpFileSizeHigh));
1371
1372 /* @@@PH: simply return the standard filesize */
1373 return 0;
1374}
1375
1376
1377/*****************************************************************************
1378 * Name : DWORD GetCompressedFileSizeW
1379 * Purpose : The GetCompressedFileSizeE function obtains the compressed
1380 * size, in bytes, of a specified file.
1381 * Parameters: LPCWSTR lpFileName, // pointer to name of file
1382 * LPDWORD lpFileSizeHigh // pointer to DWORD to receive
1383 * high-order doubleword of file size
1384 * Variables :
1385 * Result : size of compressed file
1386 * Remark :
1387 * Status : UNTESTED
1388 *
1389 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
1390 *****************************************************************************/
1391
1392DWORD WIN32API GetCompressedFileSizeW(LPCWSTR lpFileName, LPDWORD lpFileSizeHigh)
1393{
1394 LPCTSTR lpAsciiFileName; /* converted filename */
1395 DWORD rc; /* function result */
1396
1397 dprintf(("KERNEL32: GetCompressedFileSizeW (%s, %08xh)\n",
1398 lpFileName,
1399 lpFileSizeHigh));
1400
1401 lpAsciiFileName = UnicodeToAsciiString( (LPWSTR) lpFileName);
1402
1403 rc = GetCompressedFileSizeA(lpAsciiFileName,
1404 lpFileSizeHigh);
1405
1406 FreeAsciiString( (char *) lpAsciiFileName);
1407
1408 return (rc); /* return result */
1409}
1410
1411
1412/*****************************************************************************
1413 * Name : BOOL GetFileAttributesExA
1414 * Purpose :
1415 * Parameters:
1416 * Variables :
1417 * Result :
1418 * Remark : KERNEL32.874
1419 * Status : UNTESTED
1420 *
1421 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
1422 *****************************************************************************/
1423
1424BOOL WIN32API GetFileAttributesExA(LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
1425 LPVOID lpFileInformation)
1426{
1427 BOOL rc;
1428
1429 dprintf(("KERNEL32: GetFileAttributesExA(%s,%08xh,%08xh) mostly implemented.\n",
1430 lpFileName,
1431 fInfoLevelId,
1432 lpFileInformation));
1433
1434 if (lpFileName == NULL) return FALSE;
1435 if (lpFileInformation == NULL) return FALSE;
1436
1437 if (fInfoLevelId == GetFileExInfoStandard)
1438 {
1439 LPWIN32_FILE_ATTRIBUTE_DATA lpFad = (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
1440
1441 rc = OSLibDosGetFileAttributesEx((LPSTR)lpFileName,
1442 fInfoLevelId,
1443 lpFileInformation);
1444 return (rc);
1445 }
1446 else
1447 {
1448 dprintf(("KERNEL32: GetFileAttributesExA - invalid info level %d!\n",
1449 fInfoLevelId));
1450 return FALSE;
1451 }
1452}
1453
1454
1455/*****************************************************************************
1456 * Name : BOOL GetFileAttributesExW
1457 * Purpose :
1458 * Parameters:
1459 * Variables :
1460 * Result :
1461 * Remark : KERNEL32.875
1462 * Status : UNTESTED
1463 *
1464 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
1465 *****************************************************************************/
1466
1467BOOL WIN32API GetFileAttributesExW(LPCWSTR lpFileName,
1468 GET_FILEEX_INFO_LEVELS fInfoLevelId,
1469 LPVOID lpFileInformation)
1470{
1471 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
1472 BOOL res = GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
1473 HeapFree( GetProcessHeap(), 0, nameA );
1474 return res;
1475}
1476
1477//******************************************************************************
1478//******************************************************************************
1479HANDLE WIN32API FindFirstChangeNotificationA(LPCSTR lpPathName,
1480 BOOL bWatchSubtree,
1481 DWORD dwNotifyFilter)
1482{
1483 dprintf(("KERNEL32: FindFirstChangeNotificationA %s, Not implemented (faked)", lpPathName));
1484 return -1;
1485}
1486//******************************************************************************
1487//******************************************************************************
1488BOOL WIN32API FindNextChangeNotification(HANDLE hChange)
1489{
1490 dprintf(("KERNEL32: FindNextChangeNotification (%08xh), Not implemented\n",
1491 hChange));
1492
1493 return FALSE;
1494}
1495//******************************************************************************
1496//******************************************************************************
1497BOOL WIN32API FindCloseChangeNotification(HANDLE hChange)
1498{
1499 dprintf(("KERNEL32: OS2FindNextChangeNotification, Not implemented\n"));
1500
1501 return(TRUE);
1502}
1503/*****************************************************************************
1504 * Name : HANDLE WIN32API FindFirstChangeNotificationW
1505 * Purpose : The FindFirstChangeNotification function creates a change
1506 * notification handle and sets up initial change notification
1507 * filter conditions. A wait on a notification handle succeeds when
1508 * a change matching the filter conditions occurs in the specified
1509 * directory or subtree.
1510 * Parameters: LPCWSTR lpPathName pointer to name of directory to watch
1511 * BOOL bWatchSubtree flag for monitoring directory or
1512 * directory tree
1513 * DWORD dwNotifyFilter filter conditions to watch for
1514 * Variables :
1515 * Result : If the function succeeds, the return value is a handle to a find
1516 * change notification object.
1517 * If the function fails, the return value is INVALID_HANDLE_VALUE
1518 * Remark :
1519 * Status : UNTESTED STUB
1520 *
1521 * Author : Markus Montkowski [Tha, 1998/05/21 20:57]
1522 *****************************************************************************/
1523HANDLE WIN32API FindFirstChangeNotificationW(LPCWSTR lpPathName,
1524 BOOL bWatchSubtree,
1525 DWORD dwNotifyFilter)
1526{
1527 LPSTR lpAsciiPath;
1528 HANDLE hChange;
1529
1530 lpAsciiPath = UnicodeToAsciiString( (LPWSTR) lpPathName);
1531 hChange = FindFirstChangeNotificationA(lpAsciiPath, bWatchSubtree,
1532 dwNotifyFilter );
1533 if (lpAsciiPath) FreeAsciiString(lpAsciiPath);
1534 return hChange;
1535}
1536/*****************************************************************************
1537 * Name : BOOL GetOverlappedResult
1538 * Purpose : forward call to Open32
1539 * Parameters:
1540 * Variables :
1541 * Result :
1542 * Remark : handle translation is done in GetOverlappedResult
1543 * Status :
1544 *
1545 * Author : Patrick Haller [Fri, 1999/06/18 03:44]
1546 *****************************************************************************/
1547
1548BOOL WIN32API GetOverlappedResult(HANDLE hFile, /* [in] handle of file to check on */
1549 LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */
1550 LPDWORD lpTransferred, /* [in/out] number of bytes transferred */
1551 BOOL bWait) /* [in] wait for the transfer to complete ? */
1552{
1553 //NOTE: According to the SDK docs lpOverlapped->hEvent can be 0. This function
1554 // is supposed to wait on the file handle in that case. We don't support
1555 // this, so we just fail.
1556 if(lpOverlapped == NULL || lpOverlapped->hEvent == 0) {
1557 dprintf(("!ERROR!: lpOverlapped == NULL || lpOverlapped->hEvent == 0"));
1558 SetLastError(ERROR_INVALID_PARAMETER);
1559 return FALSE;
1560 }
1561
1562 return HMGetOverlappedResult(hFile,
1563 lpOverlapped,
1564 lpTransferred,
1565 bWait);
1566}
1567//******************************************************************************
1568//******************************************************************************
Note: See TracBrowser for help on using the repository browser.