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

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

Make CreateFile() return HANDLE rather than HFILE to match the current Win32 API behavior.

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