dmsynth: Dump data passed to Download method.
[wine] / dlls / kernel32 / tests / path.c
1 /*
2  * Unit test suite for various Path and Directory Functions
3  *
4  * Copyright 2002 Geoffrey Hausheer
5  * Copyright 2006 Detlef Riekenberg
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include "wine/test.h"
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "winnls.h"
30
31 #define HAS_TRAIL_SLASH_A(string) (string[lstrlenA(string)-1]=='\\')
32
33 #define LONGFILE "Long File test.path"
34 #define SHORTFILE "pathtest.pth"
35 #define SHORTDIR "shortdir"
36 #define LONGDIR "Long Directory"
37 #define NONFILE_SHORT "noexist.pth"
38 #define NONFILE_LONG "NonExistent File"
39 #define NONDIR_SHORT "notadir"
40 #define NONDIR_LONG "NonExistent Directory"
41
42 #define NOT_A_VALID_DRIVE '@'
43
44 /* the following characters don't work well with GetFullPathNameA
45    in Win98.  I don't know if this is a FAT thing, or if it is an OS thing
46    but I don't test these characters now.
47    NOTE: Win2k allows GetFullPathNameA to work with them though
48       |<>"
49 */
50 static const CHAR funny_chars[]="!@#$%^&*()=+{}[],?'`";
51 static const CHAR is_char_ok[] ="11111110111111111011";
52
53 static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR,LPSTR,DWORD);
54 static DWORD (WINAPI *pGetLongPathNameW)(LPWSTR,LPWSTR,DWORD);
55
56 /* Present in Win2003+ */
57 static BOOL  (WINAPI *pNeedCurrentDirectoryForExePathA)(LPCSTR);
58 static BOOL  (WINAPI *pNeedCurrentDirectoryForExePathW)(LPCWSTR);
59
60 static DWORD (WINAPI *pSearchPathA)(LPCSTR,LPCSTR,LPCSTR,DWORD,LPSTR,LPSTR*);
61 static DWORD (WINAPI *pSearchPathW)(LPCWSTR,LPCWSTR,LPCWSTR,DWORD,LPWSTR,LPWSTR*);
62
63 /* a structure to deal with wine todos somewhat cleanly */
64 typedef struct {
65   DWORD shortlen;
66   DWORD shorterror;
67   DWORD s2llen;
68   DWORD s2lerror;
69   DWORD longlen;
70   DWORD longerror;
71 } SLpassfail;
72
73 /* function that tests GetFullPathNameA, GetShortPathNameA,GetLongPathNameA */
74 /* NOTE: the passfail structure is used to allow customizable todo checking
75          for wine.  It is not very pretty, but it sure beats duplicating this
76          function lots of times
77 */
78 static void test_ValidPathA(const CHAR *curdir, const CHAR *subdir, const CHAR *filename,
79                          CHAR *shortstr, SLpassfail *passfail, const CHAR *errstr)
80 {
81   CHAR tmpstr[MAX_PATH],
82        fullpath[MAX_PATH],      /*full path to the file (not short/long) */
83        subpath[MAX_PATH],       /*relative path to the file */
84        fullpathshort[MAX_PATH], /*absolute path to the file (short format) */
85        fullpathlong[MAX_PATH],  /*absolute path to the file (long format) */
86        curdirshort[MAX_PATH],   /*absolute path to the current dir (short) */
87        curdirlong[MAX_PATH];    /*absolute path to the current dir (long) */
88   LPSTR strptr;                 /*ptr to the filename portion of the path */
89   DWORD len;
90 /* if passfail is NULL, we can perform all checks within this function,
91    otherwise, we will return the relevant data in the passfail struct, so
92    we must initialize it first
93 */
94   if(passfail!=NULL) {
95     passfail->shortlen=-1;passfail->s2llen=-1;passfail->longlen=-1;
96     passfail->shorterror=0;passfail->s2lerror=0;passfail->longerror=0;
97   }
98 /* GetLongPathNameA is only supported on Win2k+ and Win98+ */
99   if(pGetLongPathNameA) {
100     ok((len=pGetLongPathNameA(curdir,curdirlong,MAX_PATH)),
101        "%s: GetLongPathNameA failed\n",errstr);
102 /*GetLongPathNameA can return a trailing '\\' but shouldn't do so here */
103     ok(! HAS_TRAIL_SLASH_A(curdirlong),
104        "%s: GetLongPathNameA should not have a trailing \\\n",errstr);
105   }
106   ok((len=GetShortPathNameA(curdir,curdirshort,MAX_PATH)),
107      "%s: GetShortPathNameA failed\n",errstr);
108 /*GetShortPathNameA can return a trailing '\\' but shouldn't do so here */
109   ok(! HAS_TRAIL_SLASH_A(curdirshort),
110      "%s: GetShortPathNameA should not have a trailing \\\n",errstr);
111 /* build relative and absolute paths from inputs */
112   if(lstrlenA(subdir)) {
113     sprintf(subpath,"%s\\%s",subdir,filename);
114   } else {
115     lstrcpyA(subpath,filename);
116   }
117   sprintf(fullpath,"%s\\%s",curdir,subpath);
118   sprintf(fullpathshort,"%s\\%s",curdirshort,subpath);
119   sprintf(fullpathlong,"%s\\%s",curdirlong,subpath);
120 /* Test GetFullPathNameA functionality */
121   len=GetFullPathNameA(subpath,MAX_PATH,tmpstr,&strptr);
122   ok(len, "GetFullPathNameA failed for: '%s'\n",subpath);
123   if(HAS_TRAIL_SLASH_A(subpath)) {
124     ok(strptr==NULL,
125        "%s: GetFullPathNameA should not return a filename ptr\n",errstr);
126     ok(lstrcmpiA(fullpath,tmpstr)==0,
127        "%s: GetFullPathNameA returned '%s' instead of '%s'\n",
128        errstr,tmpstr,fullpath);
129   } else {
130     ok(lstrcmpiA(strptr,filename)==0,
131        "%s: GetFullPathNameA returned '%s' instead of '%s'\n",
132        errstr,strptr,filename);
133     ok(lstrcmpiA(fullpath,tmpstr)==0,
134        "%s: GetFullPathNameA returned '%s' instead of '%s'\n",
135        errstr,tmpstr,fullpath);
136   }
137 /* Test GetShortPathNameA functionality */
138   SetLastError(0);
139   len=GetShortPathNameA(fullpathshort,shortstr,MAX_PATH);
140   if(passfail==NULL) {
141     ok(len, "%s: GetShortPathNameA failed\n",errstr);
142   } else {
143     passfail->shortlen=len;
144     passfail->shorterror=GetLastError();
145   }
146 /* Test GetLongPathNameA functionality
147    We test both conversion from GetFullPathNameA and from GetShortPathNameA
148 */
149   if(pGetLongPathNameA) {
150     if(len!=0) {
151       SetLastError(0);
152       len=pGetLongPathNameA(shortstr,tmpstr,MAX_PATH);
153       if(passfail==NULL) {
154         ok(len,
155           "%s: GetLongPathNameA failed during Short->Long conversion\n", errstr);
156         ok(lstrcmpiA(fullpathlong,tmpstr)==0,
157            "%s: GetLongPathNameA returned '%s' instead of '%s'\n",
158            errstr,tmpstr,fullpathlong);
159       } else {
160         passfail->s2llen=len;
161         passfail->s2lerror=GetLastError();
162       }
163     }
164     SetLastError(0);
165     len=pGetLongPathNameA(fullpath,tmpstr,MAX_PATH);
166     if(passfail==NULL) {
167       ok(len, "%s: GetLongPathNameA failed\n",errstr);
168       if(HAS_TRAIL_SLASH_A(fullpath)) {
169         ok(lstrcmpiA(fullpathlong,tmpstr)==0,
170            "%s: GetLongPathNameA returned '%s' instead of '%s'\n",
171            errstr,tmpstr,fullpathlong);
172       } else {
173         ok(lstrcmpiA(fullpathlong,tmpstr)==0,
174           "%s: GetLongPathNameA returned '%s' instead of '%s'\n",
175           errstr,tmpstr,fullpathlong);
176       }
177     } else {
178       passfail->longlen=len;
179       passfail->longerror=GetLastError();
180     }
181   }
182 }
183
184 /* split path into leading directory, and 8.3 filename */
185 static void test_SplitShortPathA(CHAR *path,CHAR *dir,CHAR *eight,CHAR *three) {
186   int done,error;
187   int ext,fil;
188   int len,i;
189   len=lstrlenA(path);
190   ext=len; fil=len; done=0; error=0;
191 /* walk backwards over path looking for '.' or '\\' separators */
192   for(i=len-1;(i>=0) && (!done);i--) {
193     if(path[i]=='.')
194       if(ext!=len) error=1; else ext=i;
195     else if(path[i]=='\\') {
196       if(i==len-1) {
197         error=1;
198       } else {
199         fil=i;
200         done=1;
201       }
202     }
203   }
204 /* Check that we didn't find a trailing '\\' or multiple '.' */
205   ok(!error,"Illegal file found in 8.3 path '%s'\n",path);
206 /* Separate dir, root, and extension */
207   if(ext!=len) lstrcpyA(three,path+ext+1); else lstrcpyA(three,"");
208   if(fil!=len) {
209     lstrcpynA(eight,path+fil+1,ext-fil);
210     lstrcpynA(dir,path,fil+1);
211   } else {
212     lstrcpynA(eight,path,ext+1);
213     lstrcpyA(dir,"");
214   }
215 /* Validate that root and extension really are 8.3 */
216   ok(lstrlenA(eight)<=8 && lstrlenA(three)<=3,
217      "GetShortPathNAmeA did not return an 8.3 path\n");
218 }
219
220 /* Check that GetShortPathNameA returns a valid 8.3 path */
221 static void test_LongtoShortA(CHAR *teststr,const CHAR *goodstr,
222                               const CHAR *ext,const CHAR *errstr) {
223   CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
224
225   test_SplitShortPathA(teststr,dir,eight,three);
226   ok(lstrcmpiA(dir,goodstr)==0,
227      "GetShortPathNameA returned '%s' instead of '%s'\n",dir,goodstr);
228   ok(lstrcmpiA(three,ext)==0,
229      "GetShortPathNameA returned '%s' with incorrect extension\n",three);
230 }
231
232 /* Test that Get(Short|Long|Full)PathNameA work correctly with interesting
233    characters in the filename.
234      'valid' indicates whether this would be an allowed filename
235      'todo' indicates that wine doesn't get this right yet.
236    NOTE: We always call this routine with a nonexistent filename, so
237          Get(Short|Long)PathNameA should never pass, but GetFullPathNameA
238          should.
239 */
240 static void test_FunnyChars(CHAR *curdir,CHAR *curdir_short,CHAR *filename, INT valid,CHAR *errstr)
241 {
242   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
243   SLpassfail passfail;
244
245   test_ValidPathA(curdir,"",filename,tmpstr,&passfail,errstr);
246   if(valid) {
247     sprintf(tmpstr1,"%s\\%s",curdir_short,filename);
248       ok((passfail.shortlen==0 &&
249           (passfail.shorterror==ERROR_FILE_NOT_FOUND || passfail.shorterror==ERROR_PATH_NOT_FOUND || !passfail.shorterror)) ||
250          (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
251          "%s: GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
252          errstr,passfail.shortlen,passfail.shorterror,tmpstr);
253   } else {
254       ok(passfail.shortlen==0 &&
255          (passfail.shorterror==ERROR_INVALID_NAME || passfail.shorterror==ERROR_FILE_NOT_FOUND || !passfail.shorterror),
256          "%s: GetShortPathA should have failed len=%d, error=%d\n",
257          errstr,passfail.shortlen,passfail.shorterror);
258   }
259   if(pGetLongPathNameA) {
260     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
261     if(valid) {
262       ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
263          "%s: GetLongPathA returned %d and not %d\n",
264          errstr,passfail.longerror,ERROR_FILE_NOT_FOUND);
265     } else {
266       ok(passfail.longerror==ERROR_INVALID_NAME ||
267          passfail.longerror==ERROR_FILE_NOT_FOUND,
268          "%s: GetLongPathA returned %d and not %d or %d'\n",
269          errstr, passfail.longerror,ERROR_INVALID_NAME,ERROR_FILE_NOT_FOUND);
270     }
271   }
272 }
273
274 /* Routine to test that SetCurrentDirectory behaves as expected. */
275 static void test_setdir(CHAR *olddir,CHAR *newdir,
276                         CHAR *cmprstr, INT pass, const CHAR *errstr)
277 {
278   CHAR tmppath[MAX_PATH], *dirptr;
279   DWORD val,len,chklen;
280
281   val=SetCurrentDirectoryA(newdir);
282   len=GetCurrentDirectoryA(MAX_PATH,tmppath);
283 /* if 'pass' then the SetDirectoryA was supposed to pass */
284   if(pass) {
285     dirptr=(cmprstr==NULL) ? newdir : cmprstr;
286     chklen=lstrlenA(dirptr);
287     ok(val,"%s: SetCurrentDirectoryA failed\n",errstr);
288     ok(len==chklen,
289        "%s: SetCurrentDirectory did not change the directory, though it passed\n",
290        errstr);
291     ok(lstrcmpiA(dirptr,tmppath)==0,
292        "%s: SetCurrentDirectory did not change the directory, though it passed\n",
293        errstr);
294     ok(SetCurrentDirectoryA(olddir),
295        "%s: Couldn't set directory to it's original value\n",errstr);
296   } else {
297 /* else thest that it fails correctly */
298     chklen=lstrlenA(olddir);
299     ok(val==0,
300        "%s: SetCurrentDirectoryA passed when it should have failed\n",errstr);
301     ok(len==chklen,
302        "%s: SetCurrentDirectory changed the directory, though it failed\n",
303        errstr);
304     ok(lstrcmpiA(olddir,tmppath)==0,
305        "%s: SetCurrentDirectory changed the directory, though it failed\n",
306        errstr);
307   }
308 }
309 static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive)
310 {
311   CHAR tmppath[MAX_PATH], /*path to TEMP */
312        tmpstr[MAX_PATH],
313        tmpstr1[MAX_PATH],
314        invalid_dir[MAX_PATH];
315
316   DWORD len,len1,drives;
317   INT id;
318   HANDLE hndl;
319   BOOL bRes;
320   UINT unique;
321
322   *curDrive = *otherDrive = NOT_A_VALID_DRIVE;
323
324 /* Get the current drive letter */
325   if( GetCurrentDirectoryA( MAX_PATH, tmpstr))
326     *curDrive = tmpstr[0];
327   else
328     trace( "Unable to discover current drive, some tests will not be conducted.\n");
329
330 /* Test GetTempPathA */
331   len=GetTempPathA(MAX_PATH,tmppath);
332   ok(len!=0 && len < MAX_PATH,"GetTempPathA failed\n");
333   ok(HAS_TRAIL_SLASH_A(tmppath),
334      "GetTempPathA returned a path that did not end in '\\'\n");
335   lstrcpyA(tmpstr,"aaaaaaaa");
336   len1=GetTempPathA(len,tmpstr);
337   ok(len1==len+1 || broken(len1 == len), /* WinME */
338      "GetTempPathA should return string length %d instead of %d\n",len+1,len1);
339
340 /* Test GetTmpFileNameA */
341   ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n");
342   sprintf(tmpstr,"pat%.4x.tmp",id & 0xffff);
343   sprintf(tmpstr1,"pat%x.tmp",id & 0xffff);
344   ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
345      lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
346      "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
347      newdir,tmpstr,tmpstr1,id);
348   ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");     
349
350   id=GetTempFileNameA(tmppath,NULL,0,newdir);
351 /* Windows 95, 98 return 0==id, while Windows 2000, XP return 0!=id */
352   if (id)
353   {
354     sprintf(tmpstr,"%.4x.tmp",id & 0xffff);
355     sprintf(tmpstr1,"%x.tmp",id & 0xffff);
356     ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
357        lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
358        "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
359        newdir,tmpstr,tmpstr1,id);
360     ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
361   }
362
363   for(unique=0;unique<3;unique++) {
364     /* Nonexistent path */
365     sprintf(invalid_dir, "%s\\%s",tmppath,"non_existent_dir_1jwj3y32nb3");
366     SetLastError(0xdeadbeef);
367     ok(!GetTempFileNameA(invalid_dir,"tfn",unique,newdir),"GetTempFileNameA should have failed\n");
368     ok(GetLastError()==ERROR_DIRECTORY || broken(GetLastError()==ERROR_PATH_NOT_FOUND)/*win98*/,
369     "got %d, expected ERROR_DIRECTORY\n", GetLastError());
370
371     /* Check return value for unique !=0 */
372     if(unique) {
373       ok((GetTempFileNameA(tmppath,"tfn",unique,newdir) == unique),"GetTempFileNameA unexpectedly failed\n");
374       /* if unique != 0, the actual temp files are not created: */
375       ok(!DeleteFileA(newdir) && GetLastError() == ERROR_FILE_NOT_FOUND,"Deleted a file that shouldn't exist!\n");
376     }
377   }
378
379 /* Find first valid drive letter that is neither newdir[0] nor curDrive */
380   drives = GetLogicalDrives() & ~(1<<(newdir[0]-'A'));
381   if( *curDrive != NOT_A_VALID_DRIVE)
382     drives &= ~(1<<(*curDrive-'A'));
383   if( drives)
384     for( *otherDrive='A'; (drives & 1) == 0; drives>>=1, (*otherDrive)++);
385   else
386     trace( "Could not find alternative drive, some tests will not be conducted.\n");
387
388 /* Do some CreateDirectoryA tests */
389 /* It would be nice to do test the SECURITY_ATTRIBUTES, but I don't
390    really understand how they work.
391    More formal tests should be done along with CreateFile tests
392 */
393   ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n");
394   ok(CreateDirectoryA(newdir,NULL)==0,
395      "CreateDirectoryA succeeded even though a file of the same name exists\n");
396   ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
397   ok(CreateDirectoryA(newdir,NULL),"CreateDirectoryA failed\n");
398 /* Create some files to test other functions.  Note, we will test CreateFileA
399    at some later point
400 */
401   sprintf(tmpstr,"%s\\%s",newdir,SHORTDIR);
402   ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
403   sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
404   ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
405   sprintf(tmpstr,"%c:", *curDrive);
406   bRes = CreateDirectoryA(tmpstr,NULL);
407   ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED  ||
408                GetLastError() == ERROR_ALREADY_EXISTS),
409      "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError());
410   sprintf(tmpstr,"%c:\\", *curDrive);
411   bRes = CreateDirectoryA(tmpstr,NULL);
412   ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED  ||
413                GetLastError() == ERROR_ALREADY_EXISTS),
414      "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError());
415   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,SHORTFILE);
416   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
417                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
418   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
419   ok(CloseHandle(hndl),"CloseHandle failed\n");
420   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,LONGFILE);
421   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
422                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
423   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
424   ok(CloseHandle(hndl),"CloseHandle failed\n");
425   sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,SHORTFILE);
426   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
427                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
428   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
429   ok(CloseHandle(hndl),"CloseHandle failed\n");
430   sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,LONGFILE);
431   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
432                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
433   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
434   ok(CloseHandle(hndl),"CloseHandle failed\n");
435 }
436
437 /* Test GetCurrentDirectory & SetCurrentDirectory */
438 static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir)
439 {
440   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
441   char *buffer;
442   DWORD len,len1;
443 /* Save the original directory, so that we can return to it at the end
444    of the test
445 */
446   len=GetCurrentDirectoryA(MAX_PATH,origdir);
447   ok(len!=0 && len < MAX_PATH,"GetCurrentDirectoryA failed\n");
448 /* Make sure that CetCurrentDirectoryA doesn't overwrite the buffer when the
449    buffer size is too small to hold the current directory
450 */
451   lstrcpyA(tmpstr,"aaaaaaa");
452   len1=GetCurrentDirectoryA(len,tmpstr);
453   ok(len1==len+1, "GetCurrentDirectoryA returned %d instead of %d\n",len1,len+1);
454   ok(lstrcmpiA(tmpstr,"aaaaaaa")==0,
455      "GetCurrentDirectoryA should not have modified the buffer\n");
456
457   buffer = HeapAlloc( GetProcessHeap(), 0, 2 * 65536 );
458   SetLastError( 0xdeadbeef );
459   strcpy( buffer, "foo" );
460   len = GetCurrentDirectoryA( 32767, buffer );
461   ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
462   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
463   SetLastError( 0xdeadbeef );
464   strcpy( buffer, "foo" );
465   len = GetCurrentDirectoryA( 32768, buffer );
466   ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
467   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
468   SetLastError( 0xdeadbeef );
469   strcpy( buffer, "foo" );
470   len = GetCurrentDirectoryA( 65535, buffer );
471   ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4, win2k, xp */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
472   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
473   SetLastError( 0xdeadbeef );
474   strcpy( buffer, "foo" );
475   len = GetCurrentDirectoryA( 65536, buffer );
476   ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4 */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
477   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
478   SetLastError( 0xdeadbeef );
479   strcpy( buffer, "foo" );
480   len = GetCurrentDirectoryA( 2 * 65536, buffer );
481   ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4 */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
482   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
483   HeapFree( GetProcessHeap(), 0, buffer );
484
485 /* Check for crash prevention on swapped args. Crashes all but Win9x.
486 */
487   if (0)
488   {
489       GetCurrentDirectoryA( 42, (LPSTR)(MAX_PATH + 42) );
490   }
491
492 /* SetCurrentDirectoryA shouldn't care whether the string has a
493    trailing '\\' or not
494 */
495   sprintf(tmpstr,"%s\\",newdir);
496   test_setdir(origdir,tmpstr,newdir,1,"check 1");
497   test_setdir(origdir,newdir,NULL,1,"check 2");
498 /* Set the directory to the working area.  We just tested that this works,
499    so why check it again.
500 */
501   SetCurrentDirectoryA(newdir);
502 /* Check that SetCurrentDirectory fails when a nonexistent dir is specified */
503   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_SHORT);
504   test_setdir(newdir,tmpstr,NULL,0,"check 3");
505 /* Check that SetCurrentDirectory fails for a nonexistent lond directory */
506   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_LONG);
507   test_setdir(newdir,tmpstr,NULL,0,"check 4");
508 /* Check that SetCurrentDirectory passes with a long directory */
509   sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
510   test_setdir(newdir,tmpstr,NULL,1,"check 5");
511 /* Check that SetCurrentDirectory passes with a short relative directory */
512   sprintf(tmpstr,"%s",SHORTDIR);
513   sprintf(tmpstr1,"%s\\%s",newdir,SHORTDIR);
514   test_setdir(newdir,tmpstr,tmpstr1,1,"check 6");
515 /* starting with a '.' */
516   sprintf(tmpstr,".\\%s",SHORTDIR);
517   test_setdir(newdir,tmpstr,tmpstr1,1,"check 7");
518 /* Check that SetCurrentDirectory passes with a short relative directory */
519   sprintf(tmpstr,"%s",LONGDIR);
520   sprintf(tmpstr1,"%s\\%s",newdir,LONGDIR);
521   test_setdir(newdir,tmpstr,tmpstr1,1,"check 8");
522 /* starting with a '.' */
523   sprintf(tmpstr,".\\%s",LONGDIR);
524   test_setdir(newdir,tmpstr,tmpstr1,1,"check 9");
525 /* change to root without a trailing backslash. The function call succeeds
526    but the directory is not changed.
527 */
528   sprintf(tmpstr, "%c:", newdir[0]);
529   test_setdir(newdir,tmpstr,newdir,1,"check 10");
530 /* works however with a trailing backslash */
531   sprintf(tmpstr, "%c:\\", newdir[0]);
532   test_setdir(newdir,tmpstr,NULL,1,"check 11");
533 }
534
535 /* Cleanup the mess we made while executing these tests */
536 static void test_CleanupPathA(CHAR *origdir, CHAR *curdir)
537 {
538   CHAR tmpstr[MAX_PATH];
539   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
540   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
541   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,LONGFILE);
542   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
543   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,SHORTFILE);
544   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
545   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
546   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
547   sprintf(tmpstr,"%s\\%s",curdir,SHORTDIR);
548   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
549   sprintf(tmpstr,"%s\\%s",curdir,LONGDIR);
550   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
551   ok(SetCurrentDirectoryA(origdir),"SetCurrentDirectoryA failed\n");
552   ok(RemoveDirectoryA(curdir),"RemoveDirectoryA failed\n");
553 }
554
555 /* test that short path name functions work regardless of case */
556 static void test_ShortPathCase(const char *tmpdir, const char *dirname,
557                                const char *filename)
558 {
559     char buf[MAX_PATH], shortbuf[MAX_PATH];
560     HANDLE hndl;
561     int i;
562
563     snprintf(buf,sizeof(buf),"%s\\%s\\%s",tmpdir,dirname,filename);
564     GetShortPathNameA(buf,shortbuf,sizeof(shortbuf));
565     hndl = CreateFileA(shortbuf,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
566     ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed (%d)\n",GetLastError());
567     CloseHandle(hndl);
568     /* Now for the real test */
569     for(i=0;i<strlen(shortbuf);i++)
570         if (i % 2)
571             shortbuf[i] = tolower(shortbuf[i]);
572     hndl = CreateFileA(shortbuf,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
573     ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed (%d)\n",GetLastError());
574     CloseHandle(hndl);
575 }
576
577 /* This routine will test Get(Full|Short|Long)PathNameA */
578 static void test_PathNameA(CHAR *curdir, CHAR curDrive, CHAR otherDrive)
579 {
580   CHAR curdir_short[MAX_PATH],
581        longdir_short[MAX_PATH];
582   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH],tmpstr2[MAX_PATH];
583   LPSTR strptr;                 /*ptr to the filename portion of the path */
584   DWORD len;
585   INT i;
586   CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
587   SLpassfail passfail;
588
589 /* Get the short form of the current directory */
590   ok((len=GetShortPathNameA(curdir,curdir_short,MAX_PATH)),
591      "GetShortPathNameA failed\n");
592   ok(!HAS_TRAIL_SLASH_A(curdir_short),
593      "GetShortPathNameA should not have a trailing \\\n");
594 /* Get the short form of the absolute-path to LONGDIR */
595   sprintf(tmpstr,"%s\\%s",curdir_short,LONGDIR);
596   ok((len=GetShortPathNameA(tmpstr,longdir_short,MAX_PATH)),
597      "GetShortPathNameA failed\n");
598   ok(lstrcmpiA(longdir_short+(len-1),"\\")!=0,
599      "GetShortPathNameA should not have a trailing \\\n");
600
601   if (pGetLongPathNameA) {
602     DWORD rc1,rc2;
603     sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
604     rc1=(*pGetLongPathNameA)(tmpstr,NULL,0);
605     rc2=(*pGetLongPathNameA)(curdir,NULL,0);
606     ok((rc1-strlen(tmpstr))==(rc2-strlen(curdir)),
607        "GetLongPathNameA: wrong return code, %d instead of %d\n",
608        rc1, lstrlenA(tmpstr)+1);
609
610     sprintf(dir,"%c:",curDrive);
611     rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr));
612     ok(strcmp(dir,tmpstr)==0,
613        "GetLongPathNameA: returned '%s' instead of '%s' (rc=%d)\n",
614        tmpstr,dir,rc1);
615   }
616
617 /* Check the cases where both file and directory exist first */
618 /* Start with a 8.3 directory, 8.3 filename */
619   test_ValidPathA(curdir,SHORTDIR,SHORTFILE,tmpstr,NULL,"test1");
620   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,SHORTFILE);
621   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
622      "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
623 /* Now try a 8.3 directory, long file name */
624   test_ValidPathA(curdir,SHORTDIR,LONGFILE,tmpstr,NULL,"test2");
625   sprintf(tmpstr1,"%s\\%s",curdir_short,SHORTDIR);
626   test_LongtoShortA(tmpstr,tmpstr1,"PAT","test2");
627 /* Next is a long directory, 8.3 file */
628   test_ValidPathA(curdir,LONGDIR,SHORTFILE,tmpstr,NULL,"test3");
629   sprintf(tmpstr1,"%s\\%s",longdir_short,SHORTFILE);
630   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
631      "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
632 /*Lastly a long directory, long file */
633   test_ValidPathA(curdir,LONGDIR,LONGFILE,tmpstr,NULL,"test4");
634   test_LongtoShortA(tmpstr,longdir_short,"PAT","test4");
635
636 /* Now check all of the invalid file w/ valid directory combinations */
637 /* Start with a 8.3 directory, 8.3 filename */
638   test_ValidPathA(curdir,SHORTDIR,NONFILE_SHORT,tmpstr,&passfail,"test5");
639   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,NONFILE_SHORT);
640   ok((passfail.shortlen==0 &&
641       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
642        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
643      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
644      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
645      passfail.shortlen,passfail.shorterror,tmpstr);
646   if(pGetLongPathNameA) {
647     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
648     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
649        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
650   }
651 /* Now try a 8.3 directory, long file name */
652   test_ValidPathA(curdir,SHORTDIR,NONFILE_LONG,tmpstr,&passfail,"test6");
653   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
654   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
655      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
656      !passfail.shorterror,
657      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
658   if(pGetLongPathNameA) {
659     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
660     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
661        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
662   }
663 /* Next is a long directory, 8.3 file */
664   test_ValidPathA(curdir,LONGDIR,NONFILE_SHORT,tmpstr,&passfail,"test7");
665   sprintf(tmpstr2,"%s\\%s",curdir_short,LONGDIR);
666   GetShortPathNameA(tmpstr2,tmpstr1,MAX_PATH);
667   strcat(tmpstr1,"\\" NONFILE_SHORT);
668   ok((passfail.shortlen==0 &&
669       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
670        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
671      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
672      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
673      passfail.shortlen,passfail.shorterror,tmpstr);
674   if(pGetLongPathNameA) {
675     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
676     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
677       "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
678   }
679 /*Lastly a long directory, long file */
680   test_ValidPathA(curdir,LONGDIR,NONFILE_LONG,tmpstr,&passfail,"test8");
681   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
682   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
683      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
684      !passfail.shorterror,
685      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
686   if(pGetLongPathNameA) {
687     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
688     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
689        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
690   }
691 /* Now try again with directories that don't exist */
692 /* 8.3 directory, 8.3 filename */
693   test_ValidPathA(curdir,NONDIR_SHORT,SHORTFILE,tmpstr,&passfail,"test9");
694   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,NONDIR_SHORT,SHORTFILE);
695   ok((passfail.shortlen==0 &&
696       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
697        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
698      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
699      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
700      passfail.shortlen,passfail.shorterror,tmpstr);
701   if(pGetLongPathNameA) {
702     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
703     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
704        passfail.longerror==ERROR_FILE_NOT_FOUND,
705        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
706        passfail.longerror);
707   }
708 /* Now try a 8.3 directory, long file name */
709   test_ValidPathA(curdir,NONDIR_SHORT,LONGFILE,tmpstr,&passfail,"test10");
710   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
711   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
712      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
713      !passfail.shorterror,
714      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
715       passfail.shorterror);
716   if(pGetLongPathNameA) {
717     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
718     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
719        passfail.longerror==ERROR_FILE_NOT_FOUND,
720        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
721        passfail.longerror);
722   }
723 /* Next is a long directory, 8.3 file */
724   test_ValidPathA(curdir,NONDIR_LONG,SHORTFILE,tmpstr,&passfail,"test11");
725   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
726   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
727      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
728      !passfail.shorterror,
729      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
730       passfail.shorterror);
731   if(pGetLongPathNameA) {
732     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
733     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
734        passfail.longerror==ERROR_FILE_NOT_FOUND,
735        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
736        passfail.longerror);
737   }
738 /*Lastly a long directory, long file */
739   test_ValidPathA(curdir,NONDIR_LONG,LONGFILE,tmpstr,&passfail,"test12");
740   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
741   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
742      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
743      !passfail.shorterror,
744      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
745       passfail.shorterror);
746   if(pGetLongPathNameA) {
747     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
748     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
749        passfail.longerror==ERROR_FILE_NOT_FOUND,
750        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
751        passfail.longerror);
752   }
753 /* Next try directories ending with '\\' */
754 /* Existing Directories */
755   sprintf(tmpstr,"%s\\",SHORTDIR);
756   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test13");
757   sprintf(tmpstr,"%s\\",LONGDIR);
758   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test14");
759 /* Nonexistent directories */
760   sprintf(tmpstr,"%s\\",NONDIR_SHORT);
761   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test15");
762   sprintf(tmpstr2,"%s\\%s",curdir_short,tmpstr);
763   ok((passfail.shortlen==0 &&
764       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
765        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
766      (passfail.shortlen==strlen(tmpstr2) && lstrcmpiA(tmpstr1,tmpstr2)==0),
767      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
768      passfail.shortlen,passfail.shorterror,tmpstr);
769   if(pGetLongPathNameA) {
770     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
771     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
772        "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
773        passfail.longerror);
774   }
775   sprintf(tmpstr,"%s\\",NONDIR_LONG);
776   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test16");
777   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
778   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
779      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
780      !passfail.shorterror,
781      "GetShortPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
782       passfail.shorterror);
783   if(pGetLongPathNameA) {
784     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
785     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
786        "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
787        passfail.longerror);
788   }
789 /* Test GetFullPathNameA with drive letters */
790   if( curDrive != NOT_A_VALID_DRIVE) {
791     sprintf(tmpstr,"%c:",curdir[0]);
792     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr2,&strptr),
793        "GetFullPathNameA(%c:) failed\n", curdir[0]);
794     GetCurrentDirectoryA(MAX_PATH,tmpstr);
795     sprintf(tmpstr1,"%s\\",tmpstr);
796     ok(lstrcmpiA(tmpstr,tmpstr2)==0 || lstrcmpiA(tmpstr1,tmpstr2)==0,
797        "GetFullPathNameA(%c:) returned '%s' instead of '%s' or '%s'\n",
798        curdir[0],tmpstr2,tmpstr,tmpstr1);
799
800     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
801     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
802     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
803        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
804     ok(lstrcmpiA(SHORTFILE,strptr)==0,
805        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
806   }
807 /* Without a leading slash, insert the current directory if on the current drive */
808   sprintf(tmpstr,"%c:%s\\%s",curdir[0],SHORTDIR,SHORTFILE);
809   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
810   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
811   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
812       "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
813   ok(lstrcmpiA(SHORTFILE,strptr)==0,
814       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
815 /* Otherwise insert the missing leading slash */
816   if( otherDrive != NOT_A_VALID_DRIVE) {
817     /* FIXME: this test assumes that current directory on other drive is root */
818     sprintf(tmpstr,"%c:%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
819     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed for %s\n", tmpstr);
820     sprintf(tmpstr,"%c:\\%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
821     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
822        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
823     ok(lstrcmpiA(SHORTFILE,strptr)==0,
824        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
825   }
826 /* Xilinx tools like to mix Unix and DOS formats, which Windows handles fine.
827    So test for them. */
828   if( curDrive != NOT_A_VALID_DRIVE) {
829     sprintf(tmpstr,"%c:/%s\\%s",curDrive,SHORTDIR,SHORTFILE);
830     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
831     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
832     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
833        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
834     ok(lstrcmpiA(SHORTFILE,strptr)==0,
835        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
836   }
837 /**/
838   sprintf(tmpstr,"%c:%s/%s",curdir[0],SHORTDIR,SHORTFILE);
839   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
840   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
841   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
842       "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
843   ok(lstrcmpiA(SHORTFILE,strptr)==0,
844       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
845 /* Windows will insert a drive letter in front of an absolute UNIX path */
846   sprintf(tmpstr,"/%s/%s",SHORTDIR,SHORTFILE);
847   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
848   sprintf(tmpstr,"%c:\\%s\\%s",*tmpstr1,SHORTDIR,SHORTFILE);
849   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
850      "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
851 /* This passes in Wine because it still contains the pointer from the previous test */
852   ok(lstrcmpiA(SHORTFILE,strptr)==0,
853       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
854
855 /* Now try some relative paths */
856   ok(GetShortPathNameA(LONGDIR,tmpstr,MAX_PATH),"GetShortPathNameA failed\n");
857   test_SplitShortPathA(tmpstr,dir,eight,three);
858   if(pGetLongPathNameA) {
859     ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
860     ok(lstrcmpiA(tmpstr1,LONGDIR)==0,
861        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,LONGDIR);
862   }
863   sprintf(tmpstr,".\\%s",LONGDIR);
864   ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed\n");
865   test_SplitShortPathA(tmpstr1,dir,eight,three);
866   ok(lstrcmpiA(dir,".")==0 || dir[0]=='\0',
867      "GetShortPathNameA did not keep relative directory [%s]\n",tmpstr1);
868   if(pGetLongPathNameA) {
869     ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetLongPathNameA failed %s\n",
870        tmpstr);
871     ok(lstrcmpiA(tmpstr1,tmpstr)==0,
872        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
873   }
874 /* Check out Get*PathNameA on some funny characters */
875   for(i=0;i<lstrlenA(funny_chars);i++) {
876     INT valid;
877     valid=(is_char_ok[i]=='0') ? 0 : 1;
878     sprintf(tmpstr1,"check%d-1",i);
879     sprintf(tmpstr,"file%c000.ext",funny_chars[i]);
880     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
881     sprintf(tmpstr1,"check%d-2",i);
882     sprintf(tmpstr,"file000.e%ct",funny_chars[i]);
883     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
884     sprintf(tmpstr1,"check%d-3",i);
885     sprintf(tmpstr,"%cfile000.ext",funny_chars[i]);
886     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
887     sprintf(tmpstr1,"check%d-4",i);
888     sprintf(tmpstr,"file000%c.ext",funny_chars[i]);
889     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
890     sprintf(tmpstr1,"check%d-5",i);
891     sprintf(tmpstr,"Long %c File",funny_chars[i]);
892     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
893     sprintf(tmpstr1,"check%d-6",i);
894     sprintf(tmpstr,"%c Long File",funny_chars[i]);
895     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
896     sprintf(tmpstr1,"check%d-7",i);
897     sprintf(tmpstr,"Long File %c",funny_chars[i]);
898     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
899   }
900   /* Now try it on mixed case short names */
901   test_ShortPathCase(curdir,SHORTDIR,LONGFILE);
902   test_ShortPathCase(curdir,LONGDIR,SHORTFILE);
903   test_ShortPathCase(curdir,LONGDIR,LONGFILE);
904 }
905
906 static void test_GetTempPathA(char* tmp_dir)
907 {
908     DWORD len, len_with_null;
909     char buf[MAX_PATH];
910
911     len_with_null = strlen(tmp_dir) + 1;
912
913     lstrcpyA(buf, "foo");
914     len = GetTempPathA(MAX_PATH, buf);
915     ok(len <= MAX_PATH, "should fit into MAX_PATH\n");
916     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
917     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
918
919     /* Some versions of Windows touch the buffer, some don't so we don't
920      * test that. Also, NT sometimes exaggerates the required buffer size
921      * so we cannot test for an exact match. Finally, the
922      * 'len_with_null - 1' case is so buggy on Windows it's not testable.
923      * For instance in some cases Win98 returns len_with_null - 1 instead
924      * of len_with_null.
925      */
926     len = GetTempPathA(1, buf);
927     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
928
929     len = GetTempPathA(0, NULL);
930     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
931
932     /* The call above gave us the buffer size that Windows thinks is needed
933      * so the next call should work
934      */
935     lstrcpyA(buf, "foo");
936     len = GetTempPathA(len, buf);
937     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
938     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
939 }
940
941 static void test_GetTempPathW(char* tmp_dir)
942 {
943     DWORD len, len_with_null;
944     WCHAR buf[MAX_PATH];
945     WCHAR tmp_dirW[MAX_PATH];
946     static const WCHAR fooW[] = {'f','o','o',0};
947
948     MultiByteToWideChar(CP_ACP,0,tmp_dir,-1,tmp_dirW,sizeof(tmp_dirW)/sizeof(*tmp_dirW));
949     len_with_null = lstrlenW(tmp_dirW) + 1;
950
951     /* This one is different from ANSI version: ANSI version doesn't
952      * touch the buffer, unicode version usually truncates the buffer
953      * to zero size. NT still exaggerates the required buffer size
954      * sometimes so we cannot test for an exact match. Finally, the
955      * 'len_with_null - 1' case is so buggy on Windows it's not testable.
956      * For instance on NT4 it will sometimes return a path without the
957      * trailing '\\' and sometimes return an error.
958      */
959
960     lstrcpyW(buf, fooW);
961     len = GetTempPathW(MAX_PATH, buf);
962     if (len == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
963     {
964         win_skip("GetTempPathW is not available\n");
965         return;
966     }
967     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
968     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
969
970     lstrcpyW(buf, fooW);
971     len = GetTempPathW(1, buf);
972     ok(buf[0] == 0, "unicode version should truncate the buffer to zero size\n");
973     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
974
975     len = GetTempPathW(0, NULL);
976     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
977
978     lstrcpyW(buf, fooW);
979     len = GetTempPathW(len, buf);
980     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
981     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
982 }
983
984 static void test_GetTempPath(void)
985 {
986     char save_TMP[MAX_PATH];
987     char windir[MAX_PATH];
988     char buf[MAX_PATH];
989
990     if (!GetEnvironmentVariableA("TMP", save_TMP, sizeof(save_TMP))) save_TMP[0] = 0;
991
992     /* test default configuration */
993     trace("TMP=%s\n", save_TMP);
994     if (save_TMP[0])
995     {
996         strcpy(buf,save_TMP);
997         if (buf[strlen(buf)-1]!='\\')
998             strcat(buf,"\\");
999         test_GetTempPathA(buf);
1000         test_GetTempPathW(buf);
1001     }
1002
1003     /* TMP=C:\WINDOWS */
1004     GetWindowsDirectoryA(windir, sizeof(windir));
1005     SetEnvironmentVariableA("TMP", windir);
1006     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
1007     trace("TMP=%s\n", buf);
1008     strcat(windir,"\\");
1009     test_GetTempPathA(windir);
1010     test_GetTempPathW(windir);
1011
1012     /* TMP=C:\ */
1013     GetWindowsDirectoryA(windir, sizeof(windir));
1014     windir[3] = 0;
1015     SetEnvironmentVariableA("TMP", windir);
1016     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
1017     trace("TMP=%s\n", buf);
1018     test_GetTempPathA(windir);
1019     test_GetTempPathW(windir);
1020
1021     /* TMP=C: i.e. use current working directory of the specified drive */
1022     GetWindowsDirectoryA(windir, sizeof(windir));
1023     SetCurrentDirectoryA(windir);
1024     windir[2] = 0;
1025     SetEnvironmentVariableA("TMP", windir);
1026     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
1027     trace("TMP=%s\n", buf);
1028     GetWindowsDirectoryA(windir, sizeof(windir));
1029     strcat(windir,"\\");
1030     test_GetTempPathA(windir);
1031     test_GetTempPathW(windir);
1032
1033     SetEnvironmentVariableA("TMP", save_TMP);
1034 }
1035
1036 static void test_GetLongPathNameA(void)
1037 {
1038     DWORD length, explength, hostsize;
1039     char tempfile[MAX_PATH];
1040     char longpath[MAX_PATH];
1041     char unc_prefix[MAX_PATH];
1042     char unc_short[MAX_PATH], unc_long[MAX_PATH];
1043     char temppath[MAX_PATH], temppath2[MAX_PATH];
1044     HANDLE file;
1045
1046     if (!pGetLongPathNameA)
1047         return;
1048
1049     GetTempPathA(MAX_PATH, tempfile);
1050     lstrcatA(tempfile, "longfilename.longext");
1051
1052     file = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1053     CloseHandle(file);
1054
1055     /* Test a normal path with a small buffer size */
1056     memset(temppath, 0, MAX_PATH);
1057     length = pGetLongPathNameA(tempfile, temppath, 4);
1058     /* We have a failure so length should be the minimum plus the terminating '0'  */
1059     ok(length >= lstrlen(tempfile) + 1, "Wrong length\n");
1060     ok(temppath[0] == 0, "Buffer should not have been touched\n");
1061
1062     /* Some UNC syntax tests */
1063
1064     memset(temppath, 0, MAX_PATH);
1065     memset(temppath2, 0, MAX_PATH);
1066     lstrcpyA(temppath2, "\\\\?\\");
1067     lstrcatA(temppath2, tempfile);
1068     explength = length + 4;
1069
1070     SetLastError(0xdeadbeef);
1071     length = pGetLongPathNameA(temppath2, NULL, 0);
1072     if (length == 0 && GetLastError() == ERROR_BAD_NET_NAME)
1073     {
1074         win_skip("UNC syntax tests don't work on Win98/WinMe\n");
1075         DeleteFileA(tempfile);
1076         return;
1077     }
1078     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1079
1080     length = pGetLongPathNameA(temppath2, NULL, MAX_PATH);
1081     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1082
1083     length = pGetLongPathNameA(temppath2, temppath, 4);
1084     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1085     ok(temppath[0] == 0, "Buffer should not have been touched\n");
1086
1087     /* Now an UNC path with the computername */
1088     lstrcpyA(unc_prefix, "\\\\");
1089     hostsize = sizeof(unc_prefix) - 2;
1090     GetComputerName(unc_prefix + 2, &hostsize);
1091     lstrcatA(unc_prefix, "\\");
1092
1093     /* Create a short syntax for the whole unc path */
1094     memset(unc_short, 0, MAX_PATH);
1095     GetShortPathNameA(tempfile, temppath, MAX_PATH);
1096     lstrcpyA(unc_short, unc_prefix);
1097     unc_short[lstrlenA(unc_short)] = temppath[0];
1098     lstrcatA(unc_short, "$\\");
1099     lstrcatA(unc_short, strchr(temppath, '\\') + 1);
1100
1101     /* Create a long syntax for reference */
1102     memset(longpath, 0, MAX_PATH);
1103     pGetLongPathNameA(tempfile, temppath, MAX_PATH);
1104     lstrcpyA(longpath, unc_prefix);
1105     longpath[lstrlenA(longpath)] = temppath[0];
1106     lstrcatA(longpath, "$\\");
1107     lstrcatA(longpath, strchr(temppath, '\\') + 1);
1108
1109     /* NULL test */
1110     SetLastError(0xdeadbeef);
1111     length = pGetLongPathNameA(unc_short, NULL, 0);
1112     if (length == 0 && GetLastError() == ERROR_BAD_NETPATH)
1113     {
1114         /* Seen on Window XP Home */
1115         win_skip("UNC with computername is not supported\n");
1116         DeleteFileA(tempfile);
1117         return;
1118     }
1119     explength = lstrlenA(longpath) + 1;
1120     todo_wine
1121     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1122
1123     length = pGetLongPathNameA(unc_short, NULL, MAX_PATH);
1124     todo_wine
1125     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1126
1127     memset(unc_long, 0, MAX_PATH);
1128     length = pGetLongPathNameA(unc_short, unc_long, lstrlenA(unc_short));
1129     /* length will include terminating '0' on failure */
1130     todo_wine
1131     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1132     ok(unc_long[0] == 0, "Buffer should not have been touched\n");
1133
1134     memset(unc_long, 0, MAX_PATH);
1135     length = pGetLongPathNameA(unc_short, unc_long, length);
1136     /* length doesn't include terminating '0' on success */
1137     explength--;
1138     todo_wine
1139     {
1140     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1141     ok(!lstrcmpiA(unc_long, longpath), "Expected (%s), got (%s)\n", longpath, unc_long);
1142     }
1143
1144     DeleteFileA(tempfile);
1145 }
1146
1147 static void test_GetLongPathNameW(void)
1148 {
1149     DWORD length, expanded;
1150     BOOL ret;
1151     HANDLE file;
1152     WCHAR empty[MAX_PATH];
1153     WCHAR tempdir[MAX_PATH], name[200];
1154     WCHAR dirpath[4 + MAX_PATH + 200]; /* To ease removal */
1155     WCHAR shortpath[4 + MAX_PATH + 200 + 1 + 200];
1156     static const WCHAR prefix[] = { '\\','\\','?','\\', 0};
1157     static const WCHAR backslash[] = { '\\', 0};
1158     static const WCHAR letterX[] = { 'X', 0};
1159
1160     if (!pGetLongPathNameW)
1161         return;
1162
1163     SetLastError(0xdeadbeef); 
1164     length = pGetLongPathNameW(NULL,NULL,0);
1165     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1166     {
1167         win_skip("GetLongPathNameW is not implemented\n");
1168         return;
1169     }
1170     ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1171     ok(GetLastError()==ERROR_INVALID_PARAMETER,"GetLastError returned %d but expected ERROR_INVALID_PARAMETER\n",GetLastError());
1172
1173     SetLastError(0xdeadbeef); 
1174     empty[0]=0;
1175     length = pGetLongPathNameW(empty,NULL,0);
1176     ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1177     ok(GetLastError()==ERROR_PATH_NOT_FOUND,"GetLastError returned %d but expected ERROR_PATH_NOT_FOUND\n",GetLastError());
1178
1179     /* Create a long path name. The path needs to exist for these tests to
1180      * succeed so we need the "\\?\" prefix when creating directories and
1181      * files.
1182      */
1183     name[0] = 0;
1184     while (lstrlenW(name) < (sizeof(name)/sizeof(WCHAR) - 1))
1185         lstrcatW(name, letterX);
1186
1187     GetTempPathW(MAX_PATH, tempdir);
1188
1189     lstrcpyW(shortpath, prefix);
1190     lstrcatW(shortpath, tempdir);
1191     lstrcatW(shortpath, name);
1192     lstrcpyW(dirpath, shortpath);
1193     ret = CreateDirectoryW(shortpath, NULL);
1194     ok(ret, "Could not create the temporary directory : %d\n", GetLastError());
1195     lstrcatW(shortpath, backslash);
1196     lstrcatW(shortpath, name);
1197
1198     /* Path does not exist yet and we know it overruns MAX_PATH */
1199
1200     /* No prefix */
1201     SetLastError(0xdeadbeef);
1202     length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1203     ok(length == 0, "Expected 0, got %d\n", length);
1204     todo_wine
1205     ok(GetLastError() == ERROR_PATH_NOT_FOUND,
1206        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1207     /* With prefix */
1208     SetLastError(0xdeadbeef);
1209     length = pGetLongPathNameW(shortpath, NULL, 0);
1210     todo_wine
1211     {
1212     ok(length == 0, "Expected 0, got %d\n", length);
1213     ok(GetLastError() == ERROR_FILE_NOT_FOUND,
1214        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1215     }
1216
1217     file = CreateFileW(shortpath, GENERIC_READ|GENERIC_WRITE, 0, NULL,
1218                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1219     ok(file != INVALID_HANDLE_VALUE,
1220        "Could not create the temporary file : %d.\n", GetLastError());
1221     CloseHandle(file);
1222
1223     /* Path exists */
1224
1225     /* No prefix */
1226     SetLastError(0xdeadbeef);
1227     length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1228     todo_wine
1229     {
1230     ok(length == 0, "Expected 0, got %d\n", length);
1231     ok(GetLastError() == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1232     }
1233     /* With prefix */
1234     expanded = 4 + (pGetLongPathNameW(tempdir, NULL, 0) - 1) + lstrlenW(name) + 1 + lstrlenW(name) + 1;
1235     SetLastError(0xdeadbeef);
1236     length = pGetLongPathNameW(shortpath, NULL, 0);
1237     ok(length == expanded, "Expected %d, got %d\n", expanded, length);
1238
1239     /* NULL buffer with length crashes on Windows */
1240     if (0)
1241         pGetLongPathNameW(shortpath, NULL, 20);
1242
1243     ok(DeleteFileW(shortpath), "Could not delete temporary file\n");
1244     ok(RemoveDirectoryW(dirpath), "Could not delete temporary directory\n");
1245 }
1246
1247 static void test_GetShortPathNameW(void)
1248 {
1249     WCHAR test_path[] = { 'L', 'o', 'n', 'g', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'N', 'a', 'm', 'e',  0 };
1250     WCHAR path[MAX_PATH];
1251     WCHAR short_path[MAX_PATH];
1252     DWORD length;
1253     HANDLE file;
1254     int ret;
1255     WCHAR name[] = { 't', 'e', 's', 't', 0 };
1256     WCHAR backSlash[] = { '\\', 0 };
1257
1258     SetLastError(0xdeadbeef);
1259     GetTempPathW( MAX_PATH, path );
1260     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1261     {
1262         win_skip("GetTempPathW is not implemented\n");
1263         return;
1264     }
1265
1266     lstrcatW( path, test_path );
1267     lstrcatW( path, backSlash );
1268     ret = CreateDirectoryW( path, NULL );
1269     ok( ret, "Directory was not created. LastError = %d\n", GetLastError() );
1270
1271     /* Starting a main part of test */
1272     length = GetShortPathNameW( path, short_path, 0 );
1273     ok( length, "GetShortPathNameW returned 0.\n" );
1274     ret = GetShortPathNameW( path, short_path, length );
1275     ok( ret, "GetShortPathNameW returned 0.\n" );
1276     lstrcatW( short_path, name );
1277     file = CreateFileW( short_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1278     ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" );
1279
1280     /* End test */
1281     CloseHandle( file );
1282     ret = DeleteFileW( short_path );
1283     ok( ret, "Cannot delete file.\n" );
1284     ret = RemoveDirectoryW( path );
1285     ok( ret, "Cannot delete directory.\n" );
1286 }
1287
1288 static void test_GetSystemDirectory(void)
1289 {
1290     CHAR    buffer[MAX_PATH + 4];
1291     DWORD   res;
1292     DWORD   total;
1293
1294     SetLastError(0xdeadbeef);
1295     res = GetSystemDirectory(NULL, 0);
1296     /* res includes the terminating Zero */
1297     ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1298
1299     total = res;
1300
1301     /* this crashes on XP */
1302     if (0)
1303         GetSystemDirectory(NULL, total);
1304
1305     SetLastError(0xdeadbeef);
1306     res = GetSystemDirectory(NULL, total-1);
1307     /* 95+NT: total (includes the terminating Zero)
1308        98+ME: 0 with ERROR_INVALID_PARAMETER */
1309     ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1310         "returned %d with %d (expected '%d' or: '0' with "
1311         "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1312
1313     if (total > MAX_PATH) return;
1314
1315     buffer[0] = '\0';
1316     SetLastError(0xdeadbeef);
1317     res = GetSystemDirectory(buffer, total);
1318     /* res does not include the terminating Zero */
1319     ok( (res == (total-1)) && (buffer[0]),
1320         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1321         res, GetLastError(), buffer, total-1);
1322
1323     buffer[0] = '\0';
1324     SetLastError(0xdeadbeef);
1325     res = GetSystemDirectory(buffer, total + 1);
1326     /* res does not include the terminating Zero */
1327     ok( (res == (total-1)) && (buffer[0]),
1328         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1329         res, GetLastError(), buffer, total-1);
1330
1331     memset(buffer, '#', total + 1);
1332     buffer[total + 2] = '\0';
1333     SetLastError(0xdeadbeef);
1334     res = GetSystemDirectory(buffer, total-1);
1335     /* res includes the terminating Zero) */
1336     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1337         res, GetLastError(), buffer, total);
1338
1339     memset(buffer, '#', total + 1);
1340     buffer[total + 2] = '\0';
1341     SetLastError(0xdeadbeef);
1342     res = GetSystemDirectory(buffer, total-2);
1343     /* res includes the terminating Zero) */
1344     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1345         res, GetLastError(), buffer, total);
1346 }
1347
1348 static void test_GetWindowsDirectory(void)
1349 {
1350     CHAR    buffer[MAX_PATH + 4];
1351     DWORD   res;
1352     DWORD   total;
1353
1354     SetLastError(0xdeadbeef);
1355     res = GetWindowsDirectory(NULL, 0);
1356     /* res includes the terminating Zero */
1357     ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1358
1359     total = res;
1360     /* this crashes on XP */
1361     if (0)
1362         GetWindowsDirectory(NULL, total);
1363
1364     SetLastError(0xdeadbeef);
1365     res = GetWindowsDirectory(NULL, total-1);
1366     /* 95+NT: total (includes the terminating Zero)
1367        98+ME: 0 with ERROR_INVALID_PARAMETER */
1368     ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1369         "returned %d with %d (expected '%d' or: '0' with "
1370         "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1371
1372     if (total > MAX_PATH) return;
1373
1374     buffer[0] = '\0';
1375     SetLastError(0xdeadbeef);
1376     res = GetWindowsDirectory(buffer, total);
1377     /* res does not include the terminating Zero */
1378     ok( (res == (total-1)) && (buffer[0]),
1379         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1380         res, GetLastError(), buffer, total-1);
1381
1382     buffer[0] = '\0';
1383     SetLastError(0xdeadbeef);
1384     res = GetWindowsDirectory(buffer, total + 1);
1385     /* res does not include the terminating Zero */
1386     ok( (res == (total-1)) && (buffer[0]),
1387         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1388         res, GetLastError(), buffer, total-1);
1389
1390     memset(buffer, '#', total + 1);
1391     buffer[total + 2] = '\0';
1392     SetLastError(0xdeadbeef);
1393     res = GetWindowsDirectory(buffer, total-1);
1394     /* res includes the terminating Zero) */
1395     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1396         res, GetLastError(), buffer, total);
1397
1398     memset(buffer, '#', total + 1);
1399     buffer[total + 2] = '\0';
1400     SetLastError(0xdeadbeef);
1401     res = GetWindowsDirectory(buffer, total-2);
1402     /* res includes the terminating Zero) */
1403     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1404         res, GetLastError(), buffer, total);
1405 }
1406
1407 static void test_NeedCurrentDirectoryForExePathA(void)
1408 {
1409     if (!pNeedCurrentDirectoryForExePathA)
1410     {
1411         win_skip("NeedCurrentDirectoryForExePathA is not available\n");
1412         return;
1413     }
1414
1415     /* Crashes in Windows */
1416     if (0)
1417         pNeedCurrentDirectoryForExePathA(NULL);
1418
1419     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1420     ok(pNeedCurrentDirectoryForExePathA("."), "returned FALSE for \".\"\n");
1421     ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1422     ok(pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned FALSE for \"cmd.exe\"\n");
1423
1424     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1425     ok(!pNeedCurrentDirectoryForExePathA("."), "returned TRUE for \".\"\n");
1426     ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1427     ok(!pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned TRUE for \"cmd.exe\"\n");
1428 }
1429
1430 static void test_NeedCurrentDirectoryForExePathW(void)
1431 {
1432     const WCHAR thispath[] = {'.', 0};
1433     const WCHAR fullpath[] = {'c', ':', '\\', 0};
1434     const WCHAR cmdname[] = {'c', 'm', 'd', '.', 'e', 'x', 'e', 0};
1435
1436     if (!pNeedCurrentDirectoryForExePathW)
1437     {
1438         win_skip("NeedCurrentDirectoryForExePathW is not available\n");
1439         return;
1440     }
1441
1442     /* Crashes in Windows */
1443     if (0)
1444         pNeedCurrentDirectoryForExePathW(NULL);
1445
1446     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1447     ok(pNeedCurrentDirectoryForExePathW(thispath), "returned FALSE for \".\"\n");
1448     ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1449     ok(pNeedCurrentDirectoryForExePathW(cmdname), "returned FALSE for \"cmd.exe\"\n");
1450
1451     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1452     ok(!pNeedCurrentDirectoryForExePathW(thispath), "returned TRUE for \".\"\n");
1453     ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1454     ok(!pNeedCurrentDirectoryForExePathW(cmdname), "returned TRUE for \"cmd.exe\"\n");
1455 }
1456
1457 /* Call various path/file name retrieving APIs and check the case of
1458  * the returned drive letter. Some apps (for instance Adobe Photoshop CS3
1459  * installer) depend on the drive letter being in upper case.
1460  */
1461 static void test_drive_letter_case(void)
1462 {
1463     UINT ret;
1464     char buf[MAX_PATH];
1465
1466 #define is_upper_case_letter(a) ((a) >= 'A' && (a) <= 'Z')
1467
1468     memset(buf, 0, sizeof(buf));
1469     SetLastError(0xdeadbeef);
1470     ret = GetWindowsDirectory(buf, sizeof(buf));
1471     ok(ret, "GetWindowsDirectory error %u\n", GetLastError());
1472     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1473     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1474     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1475
1476     /* re-use the buffer returned by GetFullPathName */
1477     buf[2] = '/';
1478     SetLastError(0xdeadbeef);
1479     ret = GetFullPathName(buf + 2, sizeof(buf), buf, NULL);
1480     ok(ret, "GetFullPathName error %u\n", GetLastError());
1481     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1482     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1483     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1484
1485     memset(buf, 0, sizeof(buf));
1486     SetLastError(0xdeadbeef);
1487     ret = GetSystemDirectory(buf, sizeof(buf));
1488     ok(ret, "GetSystemDirectory error %u\n", GetLastError());
1489     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1490     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1491     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1492
1493     memset(buf, 0, sizeof(buf));
1494     SetLastError(0xdeadbeef);
1495     ret = GetCurrentDirectory(sizeof(buf), buf);
1496     ok(ret, "GetCurrentDirectory error %u\n", GetLastError());
1497     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1498     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1499     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1500
1501     /* TEMP is an environment variable, so it can't be tested for case-sensitivity */
1502     memset(buf, 0, sizeof(buf));
1503     SetLastError(0xdeadbeef);
1504     ret = GetTempPath(sizeof(buf), buf);
1505     ok(ret, "GetTempPath error %u\n", GetLastError());
1506     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1507     if (buf[0])
1508     {
1509         ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1510         ok(buf[strlen(buf)-1] == '\\', "Temporary path (%s) doesn't end in a slash\n", buf);
1511     }
1512
1513     memset(buf, 0, sizeof(buf));
1514     SetLastError(0xdeadbeef);
1515     ret = GetFullPathName(".", sizeof(buf), buf, NULL);
1516     ok(ret, "GetFullPathName error %u\n", GetLastError());
1517     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1518     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1519     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1520
1521     /* re-use the buffer returned by GetFullPathName */
1522     SetLastError(0xdeadbeef);
1523     ret = GetShortPathName(buf, buf, sizeof(buf));
1524     ok(ret, "GetShortPathName error %u\n", GetLastError());
1525     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1526     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1527     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1528
1529     if (pGetLongPathNameA)
1530     {
1531         /* re-use the buffer returned by GetShortPathName */
1532         SetLastError(0xdeadbeef);
1533         ret = pGetLongPathNameA(buf, buf, sizeof(buf));
1534         ok(ret, "GetLongPathNameA error %u\n", GetLastError());
1535         ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1536         ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1537         ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1538     }
1539 #undef is_upper_case_letter
1540 }
1541
1542 static void test_SearchPathA(void)
1543 {
1544     CHAR pathA[MAX_PATH], fileA[] = "", buffA[MAX_PATH];
1545     CHAR *ptrA = NULL;
1546     DWORD ret;
1547
1548     if (!pSearchPathA)
1549     {
1550         win_skip("SearchPathA isn't available\n");
1551         return;
1552     }
1553
1554     GetWindowsDirectoryA(pathA, sizeof(pathA)/sizeof(CHAR));
1555
1556     /* NULL filename */
1557     SetLastError(0xdeadbeef);
1558     ret = pSearchPathA(pathA, NULL, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1559     ok(ret == 0, "Expected failure, got %d\n", ret);
1560     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1561       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1562
1563     /* empty filename */
1564     SetLastError(0xdeadbeef);
1565     ret = pSearchPathA(pathA, fileA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1566     ok(ret == 0, "Expected failure, got %d\n", ret);
1567     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1568       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1569 }
1570
1571 static void test_SearchPathW(void)
1572 {
1573     WCHAR pathW[MAX_PATH], fileW[] = { 0 }, buffW[MAX_PATH];
1574     WCHAR *ptrW = NULL;
1575     DWORD ret;
1576
1577     if (!pSearchPathW)
1578     {
1579         win_skip("SearchPathW isn't available\n");
1580         return;
1581     }
1582
1583 if (0)
1584 {
1585     /* NULL filename, crashes on nt4 */
1586     pSearchPathW(pathW, NULL, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1587 }
1588
1589     /* empty filename */
1590     SetLastError(0xdeadbeef);
1591     ret = pSearchPathW(pathW, fileW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1592     ok(ret == 0, "Expected failure, got %d\n", ret);
1593     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1594       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1595 }
1596
1597 static void test_GetFullPathNameA(void)
1598 {
1599     char output[MAX_PATH], *filepart;
1600     DWORD ret;
1601     int i;
1602
1603     const struct
1604     {
1605         LPCSTR name;
1606         DWORD len;
1607         LPSTR buffer;
1608         LPSTR *lastpart;
1609     } invalid_parameters[] =
1610     {
1611         {NULL, 0,        NULL,   NULL},
1612         {NULL, MAX_PATH, NULL,   NULL},
1613         {NULL, MAX_PATH, output, NULL},
1614         {NULL, MAX_PATH, output, &filepart},
1615         {"",   0,        NULL,   NULL},
1616         {"",   MAX_PATH, NULL,   NULL},
1617         {"",   MAX_PATH, output, NULL},
1618         {"",   MAX_PATH, output, &filepart},
1619     };
1620
1621     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
1622     {
1623         SetLastError(0xdeadbeef);
1624         strcpy(output, "deadbeef");
1625         filepart = (char *)0xdeadbeef;
1626         ret = GetFullPathNameA(invalid_parameters[i].name,
1627                                invalid_parameters[i].len,
1628                                invalid_parameters[i].buffer,
1629                                invalid_parameters[i].lastpart);
1630         ok(!ret, "[%d] Expected GetFullPathNameA to return 0, got %u\n", i, ret);
1631         ok(!strcmp(output, "deadbeef"), "[%d] Expected the output buffer to be unchanged, got \"%s\"\n", i, output);
1632         ok(filepart == (char *)0xdeadbeef, "[%d] Expected output file part pointer to be untouched, got %p\n", i, filepart);
1633         ok(GetLastError() == 0xdeadbeef ||
1634            GetLastError() == ERROR_INVALID_NAME, /* Win7 */
1635            "[%d] Expected GetLastError() to return 0xdeadbeef, got %u\n",
1636            i, GetLastError());
1637     }
1638 }
1639
1640 static void test_GetFullPathNameW(void)
1641 {
1642     static const WCHAR emptyW[] = {0};
1643     static const WCHAR deadbeefW[] = {'d','e','a','d','b','e','e','f',0};
1644
1645     WCHAR output[MAX_PATH], *filepart;
1646     DWORD ret;
1647     int i;
1648
1649     const struct
1650     {
1651         LPCWSTR name;
1652         DWORD len;
1653         LPWSTR buffer;
1654         LPWSTR *lastpart;
1655         int win7_expect;
1656     } invalid_parameters[] =
1657     {
1658         {NULL,   0,        NULL,   NULL},
1659         {NULL,   0,        NULL,   &filepart, 1},
1660         {NULL,   MAX_PATH, NULL,   NULL},
1661         {NULL,   MAX_PATH, output, NULL},
1662         {NULL,   MAX_PATH, output, &filepart, 1},
1663         {emptyW, 0,        NULL,   NULL},
1664         {emptyW, 0,        NULL,   &filepart, 1},
1665         {emptyW, MAX_PATH, NULL,   NULL},
1666         {emptyW, MAX_PATH, output, NULL},
1667         {emptyW, MAX_PATH, output, &filepart, 1},
1668     };
1669
1670     SetLastError(0xdeadbeef);
1671     ret = GetFullPathNameW(NULL, 0, NULL, NULL);
1672     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1673     {
1674         win_skip("GetFullPathNameW is not available\n");
1675         return;
1676     }
1677
1678     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
1679     {
1680         SetLastError(0xdeadbeef);
1681         lstrcpyW(output, deadbeefW);
1682         filepart = (WCHAR *)0xdeadbeef;
1683         ret = GetFullPathNameW(invalid_parameters[i].name,
1684                                invalid_parameters[i].len,
1685                                invalid_parameters[i].buffer,
1686                                invalid_parameters[i].lastpart);
1687         ok(!ret, "[%d] Expected GetFullPathNameW to return 0, got %u\n", i, ret);
1688         ok(!lstrcmpW(output, deadbeefW), "[%d] Expected the output buffer to be unchanged, got %s\n", i, wine_dbgstr_w(output));
1689         ok(filepart == (WCHAR *)0xdeadbeef ||
1690            (invalid_parameters[i].win7_expect && filepart == NULL),
1691            "[%d] Expected output file part pointer to be untouched, got %p\n", i, filepart);
1692         ok(GetLastError() == 0xdeadbeef ||
1693            GetLastError() == ERROR_INVALID_NAME, /* Win7 */
1694            "[%d] Expected GetLastError() to return 0xdeadbeef, got %u\n",
1695            i, GetLastError());
1696     }
1697 }
1698
1699 static void init_pointers(void)
1700 {
1701     HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
1702
1703 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hKernel32, #f))
1704     MAKEFUNC(GetLongPathNameA);
1705     MAKEFUNC(GetLongPathNameW);
1706     MAKEFUNC(NeedCurrentDirectoryForExePathA);
1707     MAKEFUNC(NeedCurrentDirectoryForExePathW);
1708     MAKEFUNC(SearchPathA);
1709     MAKEFUNC(SearchPathW);
1710 #undef MAKEFUNC
1711 }
1712
1713 START_TEST(path)
1714 {
1715     CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
1716
1717     init_pointers();
1718
1719     /* Report only once */
1720     if (!pGetLongPathNameA)
1721         win_skip("GetLongPathNameA is not available\n");
1722     if (!pGetLongPathNameW)
1723         win_skip("GetLongPathNameW is not available\n");
1724
1725     test_InitPathA(curdir, &curDrive, &otherDrive);
1726     test_CurrentDirectoryA(origdir,curdir);
1727     test_PathNameA(curdir, curDrive, otherDrive);
1728     test_CleanupPathA(origdir,curdir);
1729     test_GetTempPath();
1730     test_GetLongPathNameA();
1731     test_GetLongPathNameW();
1732     test_GetShortPathNameW();
1733     test_GetSystemDirectory();
1734     test_GetWindowsDirectory();
1735     test_NeedCurrentDirectoryForExePathA();
1736     test_NeedCurrentDirectoryForExePathW();
1737     test_drive_letter_case();
1738     test_SearchPathA();
1739     test_SearchPathW();
1740     test_GetFullPathNameA();
1741     test_GetFullPathNameW();
1742 }