ntdll: Use the getdents64 system call on all Linux platforms.
[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     SetLastError( 0xdeadbeef );
490     len = GetCurrentDirectoryA( 42, (LPSTR)(MAX_PATH + 42) );
491     ok( len == 0 && GetLastError() == ERROR_INVALID_PARAMETER,
492         "GetCurrentDirectoryA failed to fail %u err %u\n", len, GetLastError() );
493   }
494
495 /* SetCurrentDirectoryA shouldn't care whether the string has a
496    trailing '\\' or not
497 */
498   sprintf(tmpstr,"%s\\",newdir);
499   test_setdir(origdir,tmpstr,newdir,1,"check 1");
500   test_setdir(origdir,newdir,NULL,1,"check 2");
501 /* Set the directory to the working area.  We just tested that this works,
502    so why check it again.
503 */
504   SetCurrentDirectoryA(newdir);
505 /* Check that SetCurrentDirectory fails when a nonexistent dir is specified */
506   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_SHORT);
507   test_setdir(newdir,tmpstr,NULL,0,"check 3");
508 /* Check that SetCurrentDirectory fails for a nonexistent lond directory */
509   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_LONG);
510   test_setdir(newdir,tmpstr,NULL,0,"check 4");
511 /* Check that SetCurrentDirectory passes with a long directory */
512   sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
513   test_setdir(newdir,tmpstr,NULL,1,"check 5");
514 /* Check that SetCurrentDirectory passes with a short relative directory */
515   sprintf(tmpstr,"%s",SHORTDIR);
516   sprintf(tmpstr1,"%s\\%s",newdir,SHORTDIR);
517   test_setdir(newdir,tmpstr,tmpstr1,1,"check 6");
518 /* starting with a '.' */
519   sprintf(tmpstr,".\\%s",SHORTDIR);
520   test_setdir(newdir,tmpstr,tmpstr1,1,"check 7");
521 /* Check that SetCurrentDirectory passes with a short relative directory */
522   sprintf(tmpstr,"%s",LONGDIR);
523   sprintf(tmpstr1,"%s\\%s",newdir,LONGDIR);
524   test_setdir(newdir,tmpstr,tmpstr1,1,"check 8");
525 /* starting with a '.' */
526   sprintf(tmpstr,".\\%s",LONGDIR);
527   test_setdir(newdir,tmpstr,tmpstr1,1,"check 9");
528 /* change to root without a trailing backslash. The function call succeeds
529    but the directory is not changed.
530 */
531   sprintf(tmpstr, "%c:", newdir[0]);
532   test_setdir(newdir,tmpstr,newdir,1,"check 10");
533 /* works however with a trailing backslash */
534   sprintf(tmpstr, "%c:\\", newdir[0]);
535   test_setdir(newdir,tmpstr,NULL,1,"check 11");
536 }
537
538 /* Cleanup the mess we made while executing these tests */
539 static void test_CleanupPathA(CHAR *origdir, CHAR *curdir)
540 {
541   CHAR tmpstr[MAX_PATH];
542   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
543   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
544   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,LONGFILE);
545   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
546   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,SHORTFILE);
547   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
548   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
549   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
550   sprintf(tmpstr,"%s\\%s",curdir,SHORTDIR);
551   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
552   sprintf(tmpstr,"%s\\%s",curdir,LONGDIR);
553   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
554   ok(SetCurrentDirectoryA(origdir),"SetCurrentDirectoryA failed\n");
555   ok(RemoveDirectoryA(curdir),"RemoveDirectoryA failed\n");
556 }
557
558 /* test that short path name functions work regardless of case */
559 static void test_ShortPathCase(const char *tmpdir, const char *dirname,
560                                const char *filename)
561 {
562     char buf[MAX_PATH], shortbuf[MAX_PATH];
563     HANDLE hndl;
564     int i;
565
566     snprintf(buf,sizeof(buf),"%s\\%s\\%s",tmpdir,dirname,filename);
567     GetShortPathNameA(buf,shortbuf,sizeof(shortbuf));
568     hndl = CreateFileA(shortbuf,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
569     ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed (%d)\n",GetLastError());
570     CloseHandle(hndl);
571     /* Now for the real test */
572     for(i=0;i<strlen(shortbuf);i++)
573         if (i % 2)
574             shortbuf[i] = tolower(shortbuf[i]);
575     hndl = CreateFileA(shortbuf,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
576     ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed (%d)\n",GetLastError());
577     CloseHandle(hndl);
578 }
579
580 /* This routine will test Get(Full|Short|Long)PathNameA */
581 static void test_PathNameA(CHAR *curdir, CHAR curDrive, CHAR otherDrive)
582 {
583   CHAR curdir_short[MAX_PATH],
584        longdir_short[MAX_PATH];
585   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH],tmpstr2[MAX_PATH];
586   LPSTR strptr;                 /*ptr to the filename portion of the path */
587   DWORD len;
588   INT i;
589   CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
590   SLpassfail passfail;
591
592 /* Get the short form of the current directory */
593   ok((len=GetShortPathNameA(curdir,curdir_short,MAX_PATH)),
594      "GetShortPathNameA failed\n");
595   ok(!HAS_TRAIL_SLASH_A(curdir_short),
596      "GetShortPathNameA should not have a trailing \\\n");
597 /* Get the short form of the absolute-path to LONGDIR */
598   sprintf(tmpstr,"%s\\%s",curdir_short,LONGDIR);
599   ok((len=GetShortPathNameA(tmpstr,longdir_short,MAX_PATH)),
600      "GetShortPathNameA failed\n");
601   ok(lstrcmpiA(longdir_short+(len-1),"\\")!=0,
602      "GetShortPathNameA should not have a trailing \\\n");
603
604   if (pGetLongPathNameA) {
605     DWORD rc1,rc2;
606     sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
607     rc1=(*pGetLongPathNameA)(tmpstr,NULL,0);
608     rc2=(*pGetLongPathNameA)(curdir,NULL,0);
609     ok((rc1-strlen(tmpstr))==(rc2-strlen(curdir)),
610        "GetLongPathNameA: wrong return code, %d instead of %d\n",
611        rc1, lstrlenA(tmpstr)+1);
612
613     sprintf(dir,"%c:",curDrive);
614     rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr));
615     ok(strcmp(dir,tmpstr)==0,
616        "GetLongPathNameA: returned '%s' instead of '%s' (rc=%d)\n",
617        tmpstr,dir,rc1);
618   }
619
620 /* Check the cases where both file and directory exist first */
621 /* Start with a 8.3 directory, 8.3 filename */
622   test_ValidPathA(curdir,SHORTDIR,SHORTFILE,tmpstr,NULL,"test1");
623   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,SHORTFILE);
624   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
625      "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
626 /* Now try a 8.3 directory, long file name */
627   test_ValidPathA(curdir,SHORTDIR,LONGFILE,tmpstr,NULL,"test2");
628   sprintf(tmpstr1,"%s\\%s",curdir_short,SHORTDIR);
629   test_LongtoShortA(tmpstr,tmpstr1,"PAT","test2");
630 /* Next is a long directory, 8.3 file */
631   test_ValidPathA(curdir,LONGDIR,SHORTFILE,tmpstr,NULL,"test3");
632   sprintf(tmpstr1,"%s\\%s",longdir_short,SHORTFILE);
633   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
634      "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
635 /*Lastly a long directory, long file */
636   test_ValidPathA(curdir,LONGDIR,LONGFILE,tmpstr,NULL,"test4");
637   test_LongtoShortA(tmpstr,longdir_short,"PAT","test4");
638
639 /* Now check all of the invalid file w/ valid directory combinations */
640 /* Start with a 8.3 directory, 8.3 filename */
641   test_ValidPathA(curdir,SHORTDIR,NONFILE_SHORT,tmpstr,&passfail,"test5");
642   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,NONFILE_SHORT);
643   ok((passfail.shortlen==0 &&
644       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
645        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
646      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
647      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
648      passfail.shortlen,passfail.shorterror,tmpstr);
649   if(pGetLongPathNameA) {
650     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
651     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
652        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
653   }
654 /* Now try a 8.3 directory, long file name */
655   test_ValidPathA(curdir,SHORTDIR,NONFILE_LONG,tmpstr,&passfail,"test6");
656   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
657   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
658      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
659      !passfail.shorterror,
660      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
661   if(pGetLongPathNameA) {
662     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
663     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
664        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
665   }
666 /* Next is a long directory, 8.3 file */
667   test_ValidPathA(curdir,LONGDIR,NONFILE_SHORT,tmpstr,&passfail,"test7");
668   sprintf(tmpstr2,"%s\\%s",curdir_short,LONGDIR);
669   GetShortPathNameA(tmpstr2,tmpstr1,MAX_PATH);
670   strcat(tmpstr1,"\\" NONFILE_SHORT);
671   ok((passfail.shortlen==0 &&
672       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
673        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
674      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
675      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
676      passfail.shortlen,passfail.shorterror,tmpstr);
677   if(pGetLongPathNameA) {
678     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
679     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
680       "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
681   }
682 /*Lastly a long directory, long file */
683   test_ValidPathA(curdir,LONGDIR,NONFILE_LONG,tmpstr,&passfail,"test8");
684   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
685   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
686      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
687      !passfail.shorterror,
688      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
689   if(pGetLongPathNameA) {
690     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
691     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
692        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
693   }
694 /* Now try again with directories that don't exist */
695 /* 8.3 directory, 8.3 filename */
696   test_ValidPathA(curdir,NONDIR_SHORT,SHORTFILE,tmpstr,&passfail,"test9");
697   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,NONDIR_SHORT,SHORTFILE);
698   ok((passfail.shortlen==0 &&
699       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
700        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
701      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
702      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
703      passfail.shortlen,passfail.shorterror,tmpstr);
704   if(pGetLongPathNameA) {
705     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
706     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
707        passfail.longerror==ERROR_FILE_NOT_FOUND,
708        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
709        passfail.longerror);
710   }
711 /* Now try a 8.3 directory, long file name */
712   test_ValidPathA(curdir,NONDIR_SHORT,LONGFILE,tmpstr,&passfail,"test10");
713   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
714   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
715      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
716      !passfail.shorterror,
717      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
718       passfail.shorterror);
719   if(pGetLongPathNameA) {
720     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
721     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
722        passfail.longerror==ERROR_FILE_NOT_FOUND,
723        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
724        passfail.longerror);
725   }
726 /* Next is a long directory, 8.3 file */
727   test_ValidPathA(curdir,NONDIR_LONG,SHORTFILE,tmpstr,&passfail,"test11");
728   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
729   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
730      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
731      !passfail.shorterror,
732      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
733       passfail.shorterror);
734   if(pGetLongPathNameA) {
735     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
736     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
737        passfail.longerror==ERROR_FILE_NOT_FOUND,
738        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
739        passfail.longerror);
740   }
741 /*Lastly a long directory, long file */
742   test_ValidPathA(curdir,NONDIR_LONG,LONGFILE,tmpstr,&passfail,"test12");
743   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
744   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
745      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
746      !passfail.shorterror,
747      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
748       passfail.shorterror);
749   if(pGetLongPathNameA) {
750     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
751     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
752        passfail.longerror==ERROR_FILE_NOT_FOUND,
753        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
754        passfail.longerror);
755   }
756 /* Next try directories ending with '\\' */
757 /* Existing Directories */
758   sprintf(tmpstr,"%s\\",SHORTDIR);
759   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test13");
760   sprintf(tmpstr,"%s\\",LONGDIR);
761   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test14");
762 /* Nonexistent directories */
763   sprintf(tmpstr,"%s\\",NONDIR_SHORT);
764   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test15");
765   sprintf(tmpstr2,"%s\\%s",curdir_short,tmpstr);
766   ok((passfail.shortlen==0 &&
767       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
768        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
769      (passfail.shortlen==strlen(tmpstr2) && lstrcmpiA(tmpstr1,tmpstr2)==0),
770      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
771      passfail.shortlen,passfail.shorterror,tmpstr);
772   if(pGetLongPathNameA) {
773     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
774     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
775        "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
776        passfail.longerror);
777   }
778   sprintf(tmpstr,"%s\\",NONDIR_LONG);
779   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test16");
780   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
781   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
782      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
783      !passfail.shorterror,
784      "GetShortPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
785       passfail.shorterror);
786   if(pGetLongPathNameA) {
787     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
788     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
789        "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
790        passfail.longerror);
791   }
792 /* Test GetFullPathNameA with drive letters */
793   if( curDrive != NOT_A_VALID_DRIVE) {
794     sprintf(tmpstr,"%c:",curdir[0]);
795     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr2,&strptr),
796        "GetFullPathNameA(%c:) failed\n", curdir[0]);
797     GetCurrentDirectoryA(MAX_PATH,tmpstr);
798     sprintf(tmpstr1,"%s\\",tmpstr);
799     ok(lstrcmpiA(tmpstr,tmpstr2)==0 || lstrcmpiA(tmpstr1,tmpstr2)==0,
800        "GetFullPathNameA(%c:) returned '%s' instead of '%s' or '%s'\n",
801        curdir[0],tmpstr2,tmpstr,tmpstr1);
802
803     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
804     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
805     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
806        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
807     ok(lstrcmpiA(SHORTFILE,strptr)==0,
808        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
809   }
810 /* Without a leading slash, insert the current directory if on the current drive */
811   sprintf(tmpstr,"%c:%s\\%s",curdir[0],SHORTDIR,SHORTFILE);
812   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
813   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
814   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
815       "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
816   ok(lstrcmpiA(SHORTFILE,strptr)==0,
817       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
818 /* Otherwise insert the missing leading slash */
819   if( otherDrive != NOT_A_VALID_DRIVE) {
820     /* FIXME: this test assumes that current directory on other drive is root */
821     sprintf(tmpstr,"%c:%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
822     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed for %s\n", tmpstr);
823     sprintf(tmpstr,"%c:\\%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
824     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
825        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
826     ok(lstrcmpiA(SHORTFILE,strptr)==0,
827        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
828   }
829 /* Xilinx tools like to mix Unix and DOS formats, which Windows handles fine.
830    So test for them. */
831   if( curDrive != NOT_A_VALID_DRIVE) {
832     sprintf(tmpstr,"%c:/%s\\%s",curDrive,SHORTDIR,SHORTFILE);
833     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
834     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
835     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
836        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
837     ok(lstrcmpiA(SHORTFILE,strptr)==0,
838        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
839   }
840 /**/
841   sprintf(tmpstr,"%c:%s/%s",curdir[0],SHORTDIR,SHORTFILE);
842   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
843   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
844   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
845       "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
846   ok(lstrcmpiA(SHORTFILE,strptr)==0,
847       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
848 /* Windows will insert a drive letter in front of an absolute UNIX path */
849   sprintf(tmpstr,"/%s/%s",SHORTDIR,SHORTFILE);
850   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
851   sprintf(tmpstr,"%c:\\%s\\%s",*tmpstr1,SHORTDIR,SHORTFILE);
852   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
853      "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
854 /* This passes in Wine because it still contains the pointer from the previous test */
855   ok(lstrcmpiA(SHORTFILE,strptr)==0,
856       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
857
858 /* Now try some relative paths */
859   ok(GetShortPathNameA(LONGDIR,tmpstr,MAX_PATH),"GetShortPathNameA failed\n");
860   test_SplitShortPathA(tmpstr,dir,eight,three);
861   if(pGetLongPathNameA) {
862     ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
863     ok(lstrcmpiA(tmpstr1,LONGDIR)==0,
864        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,LONGDIR);
865   }
866   sprintf(tmpstr,".\\%s",LONGDIR);
867   ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed\n");
868   test_SplitShortPathA(tmpstr1,dir,eight,three);
869   ok(lstrcmpiA(dir,".")==0 || dir[0]=='\0',
870      "GetShortPathNameA did not keep relative directory [%s]\n",tmpstr1);
871   if(pGetLongPathNameA) {
872     ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetLongPathNameA failed %s\n",
873        tmpstr);
874     ok(lstrcmpiA(tmpstr1,tmpstr)==0,
875        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
876   }
877 /* Check out Get*PathNameA on some funny characters */
878   for(i=0;i<lstrlenA(funny_chars);i++) {
879     INT valid;
880     valid=(is_char_ok[i]=='0') ? 0 : 1;
881     sprintf(tmpstr1,"check%d-1",i);
882     sprintf(tmpstr,"file%c000.ext",funny_chars[i]);
883     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
884     sprintf(tmpstr1,"check%d-2",i);
885     sprintf(tmpstr,"file000.e%ct",funny_chars[i]);
886     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
887     sprintf(tmpstr1,"check%d-3",i);
888     sprintf(tmpstr,"%cfile000.ext",funny_chars[i]);
889     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
890     sprintf(tmpstr1,"check%d-4",i);
891     sprintf(tmpstr,"file000%c.ext",funny_chars[i]);
892     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
893     sprintf(tmpstr1,"check%d-5",i);
894     sprintf(tmpstr,"Long %c File",funny_chars[i]);
895     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
896     sprintf(tmpstr1,"check%d-6",i);
897     sprintf(tmpstr,"%c Long File",funny_chars[i]);
898     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
899     sprintf(tmpstr1,"check%d-7",i);
900     sprintf(tmpstr,"Long File %c",funny_chars[i]);
901     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
902   }
903   /* Now try it on mixed case short names */
904   test_ShortPathCase(curdir,SHORTDIR,LONGFILE);
905   test_ShortPathCase(curdir,LONGDIR,SHORTFILE);
906   test_ShortPathCase(curdir,LONGDIR,LONGFILE);
907 }
908
909 static void test_GetTempPathA(char* tmp_dir)
910 {
911     DWORD len, len_with_null;
912     char buf[MAX_PATH];
913
914     len_with_null = strlen(tmp_dir) + 1;
915
916     lstrcpyA(buf, "foo");
917     len = GetTempPathA(MAX_PATH, buf);
918     ok(len <= MAX_PATH, "should fit into MAX_PATH\n");
919     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
920     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
921
922     /* Some versions of Windows touch the buffer, some don't so we don't
923      * test that. Also, NT sometimes exaggerates the required buffer size
924      * so we cannot test for an exact match. Finally, the
925      * 'len_with_null - 1' case is so buggy on Windows it's not testable.
926      * For instance in some cases Win98 returns len_with_null - 1 instead
927      * of len_with_null.
928      */
929     len = GetTempPathA(1, buf);
930     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
931
932     len = GetTempPathA(0, NULL);
933     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
934
935     /* The call above gave us the buffer size that Windows thinks is needed
936      * so the next call should work
937      */
938     lstrcpyA(buf, "foo");
939     len = GetTempPathA(len, buf);
940     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
941     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
942 }
943
944 static void test_GetTempPathW(char* tmp_dir)
945 {
946     DWORD len, len_with_null;
947     WCHAR buf[MAX_PATH];
948     WCHAR tmp_dirW[MAX_PATH];
949     static const WCHAR fooW[] = {'f','o','o',0};
950
951     MultiByteToWideChar(CP_ACP,0,tmp_dir,-1,tmp_dirW,sizeof(tmp_dirW)/sizeof(*tmp_dirW));
952     len_with_null = lstrlenW(tmp_dirW) + 1;
953
954     /* This one is different from ANSI version: ANSI version doesn't
955      * touch the buffer, unicode version usually truncates the buffer
956      * to zero size. NT still exaggerates the required buffer size
957      * sometimes so we cannot test for an exact match. Finally, the
958      * 'len_with_null - 1' case is so buggy on Windows it's not testable.
959      * For instance on NT4 it will sometimes return a path without the
960      * trailing '\\' and sometimes return an error.
961      */
962
963     lstrcpyW(buf, fooW);
964     len = GetTempPathW(MAX_PATH, buf);
965     if (len == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
966     {
967         win_skip("GetTempPathW is not available\n");
968         return;
969     }
970     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
971     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
972
973     lstrcpyW(buf, fooW);
974     len = GetTempPathW(1, buf);
975     ok(buf[0] == 0, "unicode version should truncate the buffer to zero size\n");
976     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
977
978     len = GetTempPathW(0, NULL);
979     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
980
981     lstrcpyW(buf, fooW);
982     len = GetTempPathW(len, buf);
983     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
984     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
985 }
986
987 static void test_GetTempPath(void)
988 {
989     char save_TMP[MAX_PATH];
990     char windir[MAX_PATH];
991     char buf[MAX_PATH];
992
993     if (!GetEnvironmentVariableA("TMP", save_TMP, sizeof(save_TMP))) save_TMP[0] = 0;
994
995     /* test default configuration */
996     trace("TMP=%s\n", save_TMP);
997     if (save_TMP[0])
998     {
999         strcpy(buf,save_TMP);
1000         if (buf[strlen(buf)-1]!='\\')
1001             strcat(buf,"\\");
1002         test_GetTempPathA(buf);
1003         test_GetTempPathW(buf);
1004     }
1005
1006     /* TMP=C:\WINDOWS */
1007     GetWindowsDirectoryA(windir, sizeof(windir));
1008     SetEnvironmentVariableA("TMP", windir);
1009     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
1010     trace("TMP=%s\n", buf);
1011     strcat(windir,"\\");
1012     test_GetTempPathA(windir);
1013     test_GetTempPathW(windir);
1014
1015     /* TMP=C:\ */
1016     GetWindowsDirectoryA(windir, sizeof(windir));
1017     windir[3] = 0;
1018     SetEnvironmentVariableA("TMP", windir);
1019     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
1020     trace("TMP=%s\n", buf);
1021     test_GetTempPathA(windir);
1022     test_GetTempPathW(windir);
1023
1024     /* TMP=C: i.e. use current working directory of the specified drive */
1025     GetWindowsDirectoryA(windir, sizeof(windir));
1026     SetCurrentDirectoryA(windir);
1027     windir[2] = 0;
1028     SetEnvironmentVariableA("TMP", windir);
1029     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
1030     trace("TMP=%s\n", buf);
1031     GetWindowsDirectoryA(windir, sizeof(windir));
1032     strcat(windir,"\\");
1033     test_GetTempPathA(windir);
1034     test_GetTempPathW(windir);
1035
1036     SetEnvironmentVariableA("TMP", save_TMP);
1037 }
1038
1039 static void test_GetLongPathNameA(void)
1040 {
1041     DWORD length, explength, hostsize;
1042     char tempfile[MAX_PATH];
1043     char longpath[MAX_PATH];
1044     char unc_prefix[MAX_PATH];
1045     char unc_short[MAX_PATH], unc_long[MAX_PATH];
1046     char temppath[MAX_PATH], temppath2[MAX_PATH];
1047     HANDLE file;
1048
1049     if (!pGetLongPathNameA)
1050         return;
1051
1052     GetTempPathA(MAX_PATH, tempfile);
1053     lstrcatA(tempfile, "longfilename.longext");
1054
1055     file = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1056     CloseHandle(file);
1057
1058     /* Test a normal path with a small buffer size */
1059     memset(temppath, 0, MAX_PATH);
1060     length = pGetLongPathNameA(tempfile, temppath, 4);
1061     /* We have a failure so length should be the minimum plus the terminating '0'  */
1062     ok(length >= lstrlen(tempfile) + 1, "Wrong length\n");
1063     ok(temppath[0] == 0, "Buffer should not have been touched\n");
1064
1065     /* Some UNC syntax tests */
1066
1067     memset(temppath, 0, MAX_PATH);
1068     memset(temppath2, 0, MAX_PATH);
1069     lstrcpyA(temppath2, "\\\\?\\");
1070     lstrcatA(temppath2, tempfile);
1071     explength = length + 4;
1072
1073     SetLastError(0xdeadbeef);
1074     length = pGetLongPathNameA(temppath2, NULL, 0);
1075     if (length == 0 && GetLastError() == ERROR_BAD_NET_NAME)
1076     {
1077         win_skip("UNC syntax tests don't work on Win98/WinMe\n");
1078         DeleteFileA(tempfile);
1079         return;
1080     }
1081     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1082
1083     length = pGetLongPathNameA(temppath2, NULL, MAX_PATH);
1084     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1085
1086     length = pGetLongPathNameA(temppath2, temppath, 4);
1087     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1088     ok(temppath[0] == 0, "Buffer should not have been touched\n");
1089
1090     /* Now an UNC path with the computername */
1091     lstrcpyA(unc_prefix, "\\\\");
1092     hostsize = sizeof(unc_prefix) - 2;
1093     GetComputerName(unc_prefix + 2, &hostsize);
1094     lstrcatA(unc_prefix, "\\");
1095
1096     /* Create a short syntax for the whole unc path */
1097     memset(unc_short, 0, MAX_PATH);
1098     GetShortPathNameA(tempfile, temppath, MAX_PATH);
1099     lstrcpyA(unc_short, unc_prefix);
1100     unc_short[lstrlenA(unc_short)] = temppath[0];
1101     lstrcatA(unc_short, "$\\");
1102     lstrcatA(unc_short, strchr(temppath, '\\') + 1);
1103
1104     /* Create a long syntax for reference */
1105     memset(longpath, 0, MAX_PATH);
1106     pGetLongPathNameA(tempfile, temppath, MAX_PATH);
1107     lstrcpyA(longpath, unc_prefix);
1108     longpath[lstrlenA(longpath)] = temppath[0];
1109     lstrcatA(longpath, "$\\");
1110     lstrcatA(longpath, strchr(temppath, '\\') + 1);
1111
1112     /* NULL test */
1113     SetLastError(0xdeadbeef);
1114     length = pGetLongPathNameA(unc_short, NULL, 0);
1115     if (length == 0 && GetLastError() == ERROR_BAD_NETPATH)
1116     {
1117         /* Seen on Window XP Home */
1118         win_skip("UNC with computername is not supported\n");
1119         DeleteFileA(tempfile);
1120         return;
1121     }
1122     explength = lstrlenA(longpath) + 1;
1123     todo_wine
1124     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1125
1126     length = pGetLongPathNameA(unc_short, NULL, MAX_PATH);
1127     todo_wine
1128     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1129
1130     memset(unc_long, 0, MAX_PATH);
1131     length = pGetLongPathNameA(unc_short, unc_long, lstrlenA(unc_short));
1132     /* length will include terminating '0' on failure */
1133     todo_wine
1134     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1135     ok(unc_long[0] == 0, "Buffer should not have been touched\n");
1136
1137     memset(unc_long, 0, MAX_PATH);
1138     length = pGetLongPathNameA(unc_short, unc_long, length);
1139     /* length doesn't include terminating '0' on success */
1140     explength--;
1141     todo_wine
1142     {
1143     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1144     ok(!lstrcmpiA(unc_long, longpath), "Expected (%s), got (%s)\n", longpath, unc_long);
1145     }
1146
1147     DeleteFileA(tempfile);
1148 }
1149
1150 static void test_GetLongPathNameW(void)
1151 {
1152     DWORD length, expanded;
1153     BOOL ret;
1154     HANDLE file;
1155     WCHAR empty[MAX_PATH];
1156     WCHAR tempdir[MAX_PATH], name[200];
1157     WCHAR dirpath[4 + MAX_PATH + 200]; /* To ease removal */
1158     WCHAR shortpath[4 + MAX_PATH + 200 + 1 + 200];
1159     static const WCHAR prefix[] = { '\\','\\','?','\\', 0};
1160     static const WCHAR backslash[] = { '\\', 0};
1161     static const WCHAR letterX[] = { 'X', 0};
1162
1163     if (!pGetLongPathNameW)
1164         return;
1165
1166     SetLastError(0xdeadbeef); 
1167     length = pGetLongPathNameW(NULL,NULL,0);
1168     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1169     {
1170         win_skip("GetLongPathNameW is not implemented\n");
1171         return;
1172     }
1173     ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1174     ok(GetLastError()==ERROR_INVALID_PARAMETER,"GetLastError returned %d but expected ERROR_INVALID_PARAMETER\n",GetLastError());
1175
1176     SetLastError(0xdeadbeef); 
1177     empty[0]=0;
1178     length = pGetLongPathNameW(empty,NULL,0);
1179     ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1180     ok(GetLastError()==ERROR_PATH_NOT_FOUND,"GetLastError returned %d but expected ERROR_PATH_NOT_FOUND\n",GetLastError());
1181
1182     /* Create a long path name. The path needs to exist for these tests to
1183      * succeed so we need the "\\?\" prefix when creating directories and
1184      * files.
1185      */
1186     name[0] = 0;
1187     while (lstrlenW(name) < (sizeof(name)/sizeof(WCHAR) - 1))
1188         lstrcatW(name, letterX);
1189
1190     GetTempPathW(MAX_PATH, tempdir);
1191
1192     lstrcpyW(shortpath, prefix);
1193     lstrcatW(shortpath, tempdir);
1194     lstrcatW(shortpath, name);
1195     lstrcpyW(dirpath, shortpath);
1196     ret = CreateDirectoryW(shortpath, NULL);
1197     ok(ret, "Could not create the temporary directory : %d\n", GetLastError());
1198     lstrcatW(shortpath, backslash);
1199     lstrcatW(shortpath, name);
1200
1201     /* Path does not exist yet and we know it overruns MAX_PATH */
1202
1203     /* No prefix */
1204     SetLastError(0xdeadbeef);
1205     length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1206     ok(length == 0, "Expected 0, got %d\n", length);
1207     todo_wine
1208     ok(GetLastError() == ERROR_PATH_NOT_FOUND,
1209        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1210     /* With prefix */
1211     SetLastError(0xdeadbeef);
1212     length = pGetLongPathNameW(shortpath, NULL, 0);
1213     todo_wine
1214     {
1215     ok(length == 0, "Expected 0, got %d\n", length);
1216     ok(GetLastError() == ERROR_FILE_NOT_FOUND,
1217        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1218     }
1219
1220     file = CreateFileW(shortpath, GENERIC_READ|GENERIC_WRITE, 0, NULL,
1221                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1222     ok(file != INVALID_HANDLE_VALUE,
1223        "Could not create the temporary file : %d.\n", GetLastError());
1224     CloseHandle(file);
1225
1226     /* Path exists */
1227
1228     /* No prefix */
1229     SetLastError(0xdeadbeef);
1230     length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1231     todo_wine
1232     {
1233     ok(length == 0, "Expected 0, got %d\n", length);
1234     ok(GetLastError() == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1235     }
1236     /* With prefix */
1237     expanded = 4 + (pGetLongPathNameW(tempdir, NULL, 0) - 1) + lstrlenW(name) + 1 + lstrlenW(name) + 1;
1238     SetLastError(0xdeadbeef);
1239     length = pGetLongPathNameW(shortpath, NULL, 0);
1240     ok(length == expanded, "Expected %d, got %d\n", expanded, length);
1241
1242     /* NULL buffer with length crashes on Windows */
1243     if (0)
1244     length = pGetLongPathNameW(shortpath, NULL, 20);
1245
1246     ok(DeleteFileW(shortpath), "Could not delete temporary file\n");
1247     ok(RemoveDirectoryW(dirpath), "Could not delete temporary directory\n");
1248 }
1249
1250 static void test_GetShortPathNameW(void)
1251 {
1252     WCHAR test_path[] = { 'L', 'o', 'n', 'g', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'N', 'a', 'm', 'e',  0 };
1253     WCHAR path[MAX_PATH];
1254     WCHAR short_path[MAX_PATH];
1255     DWORD length;
1256     HANDLE file;
1257     int ret;
1258     WCHAR name[] = { 't', 'e', 's', 't', 0 };
1259     WCHAR backSlash[] = { '\\', 0 };
1260
1261     SetLastError(0xdeadbeef);
1262     GetTempPathW( MAX_PATH, path );
1263     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1264     {
1265         win_skip("GetTempPathW is not implemented\n");
1266         return;
1267     }
1268
1269     lstrcatW( path, test_path );
1270     lstrcatW( path, backSlash );
1271     ret = CreateDirectoryW( path, NULL );
1272     ok( ret, "Directory was not created. LastError = %d\n", GetLastError() );
1273
1274     /* Starting a main part of test */
1275     length = GetShortPathNameW( path, short_path, 0 );
1276     ok( length, "GetShortPathNameW returned 0.\n" );
1277     ret = GetShortPathNameW( path, short_path, length );
1278     ok( ret, "GetShortPathNameW returned 0.\n" );
1279     lstrcatW( short_path, name );
1280     file = CreateFileW( short_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1281     ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" );
1282
1283     /* End test */
1284     CloseHandle( file );
1285     ret = DeleteFileW( short_path );
1286     ok( ret, "Cannot delete file.\n" );
1287     ret = RemoveDirectoryW( path );
1288     ok( ret, "Cannot delete directory.\n" );
1289 }
1290
1291 static void test_GetSystemDirectory(void)
1292 {
1293     CHAR    buffer[MAX_PATH + 4];
1294     DWORD   res;
1295     DWORD   total;
1296
1297     SetLastError(0xdeadbeef);
1298     res = GetSystemDirectory(NULL, 0);
1299     /* res includes the terminating Zero */
1300     ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1301
1302     total = res;
1303
1304     /* this crashes on XP */
1305     if (0) res = GetSystemDirectory(NULL, total);
1306
1307     SetLastError(0xdeadbeef);
1308     res = GetSystemDirectory(NULL, total-1);
1309     /* 95+NT: total (includes the terminating Zero)
1310        98+ME: 0 with ERROR_INVALID_PARAMETER */
1311     ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1312         "returned %d with %d (expected '%d' or: '0' with "
1313         "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1314
1315     if (total > MAX_PATH) return;
1316
1317     buffer[0] = '\0';
1318     SetLastError(0xdeadbeef);
1319     res = GetSystemDirectory(buffer, total);
1320     /* res does not include the terminating Zero */
1321     ok( (res == (total-1)) && (buffer[0]),
1322         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1323         res, GetLastError(), buffer, total-1);
1324
1325     buffer[0] = '\0';
1326     SetLastError(0xdeadbeef);
1327     res = GetSystemDirectory(buffer, total + 1);
1328     /* res does not include the terminating Zero */
1329     ok( (res == (total-1)) && (buffer[0]),
1330         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1331         res, GetLastError(), buffer, total-1);
1332
1333     memset(buffer, '#', total + 1);
1334     buffer[total + 2] = '\0';
1335     SetLastError(0xdeadbeef);
1336     res = GetSystemDirectory(buffer, total-1);
1337     /* res includes the terminating Zero) */
1338     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1339         res, GetLastError(), buffer, total);
1340
1341     memset(buffer, '#', total + 1);
1342     buffer[total + 2] = '\0';
1343     SetLastError(0xdeadbeef);
1344     res = GetSystemDirectory(buffer, total-2);
1345     /* res includes the terminating Zero) */
1346     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1347         res, GetLastError(), buffer, total);
1348 }
1349
1350 static void test_GetWindowsDirectory(void)
1351 {
1352     CHAR    buffer[MAX_PATH + 4];
1353     DWORD   res;
1354     DWORD   total;
1355
1356     SetLastError(0xdeadbeef);
1357     res = GetWindowsDirectory(NULL, 0);
1358     /* res includes the terminating Zero */
1359     ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1360
1361     total = res;
1362     /* this crashes on XP */
1363     if (0) res = GetWindowsDirectory(NULL, total);
1364
1365     SetLastError(0xdeadbeef);
1366     res = GetWindowsDirectory(NULL, total-1);
1367     /* 95+NT: total (includes the terminating Zero)
1368        98+ME: 0 with ERROR_INVALID_PARAMETER */
1369     ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1370         "returned %d with %d (expected '%d' or: '0' with "
1371         "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1372
1373     if (total > MAX_PATH) return;
1374
1375     buffer[0] = '\0';
1376     SetLastError(0xdeadbeef);
1377     res = GetWindowsDirectory(buffer, total);
1378     /* res does not include the terminating Zero */
1379     ok( (res == (total-1)) && (buffer[0]),
1380         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1381         res, GetLastError(), buffer, total-1);
1382
1383     buffer[0] = '\0';
1384     SetLastError(0xdeadbeef);
1385     res = GetWindowsDirectory(buffer, total + 1);
1386     /* res does not include the terminating Zero */
1387     ok( (res == (total-1)) && (buffer[0]),
1388         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1389         res, GetLastError(), buffer, total-1);
1390
1391     memset(buffer, '#', total + 1);
1392     buffer[total + 2] = '\0';
1393     SetLastError(0xdeadbeef);
1394     res = GetWindowsDirectory(buffer, total-1);
1395     /* res includes the terminating Zero) */
1396     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1397         res, GetLastError(), buffer, total);
1398
1399     memset(buffer, '#', total + 1);
1400     buffer[total + 2] = '\0';
1401     SetLastError(0xdeadbeef);
1402     res = GetWindowsDirectory(buffer, total-2);
1403     /* res includes the terminating Zero) */
1404     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1405         res, GetLastError(), buffer, total);
1406 }
1407
1408 static void test_NeedCurrentDirectoryForExePathA(void)
1409 {
1410     if (!pNeedCurrentDirectoryForExePathA)
1411     {
1412         win_skip("NeedCurrentDirectoryForExePathA is not available\n");
1413         return;
1414     }
1415
1416     /* Crashes in Windows */
1417     if (0)
1418         ok(pNeedCurrentDirectoryForExePathA(NULL), "returned FALSE for NULL\n");
1419
1420     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1421     ok(pNeedCurrentDirectoryForExePathA("."), "returned FALSE for \".\"\n");
1422     ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1423     ok(pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned FALSE for \"cmd.exe\"\n");
1424
1425     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1426     ok(!pNeedCurrentDirectoryForExePathA("."), "returned TRUE for \".\"\n");
1427     ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1428     ok(!pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned TRUE for \"cmd.exe\"\n");
1429 }
1430
1431 static void test_NeedCurrentDirectoryForExePathW(void)
1432 {
1433     const WCHAR thispath[] = {'.', 0};
1434     const WCHAR fullpath[] = {'c', ':', '\\', 0};
1435     const WCHAR cmdname[] = {'c', 'm', 'd', '.', 'e', 'x', 'e', 0};
1436
1437     if (!pNeedCurrentDirectoryForExePathW)
1438     {
1439         win_skip("NeedCurrentDirectoryForExePathW is not available\n");
1440         return;
1441     }
1442
1443     /* Crashes in Windows */
1444     if (0)
1445         ok(pNeedCurrentDirectoryForExePathW(NULL), "returned FALSE for NULL\n");
1446
1447     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1448     ok(pNeedCurrentDirectoryForExePathW(thispath), "returned FALSE for \".\"\n");
1449     ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1450     ok(pNeedCurrentDirectoryForExePathW(cmdname), "returned FALSE for \"cmd.exe\"\n");
1451
1452     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1453     ok(!pNeedCurrentDirectoryForExePathW(thispath), "returned TRUE for \".\"\n");
1454     ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1455     ok(!pNeedCurrentDirectoryForExePathW(cmdname), "returned TRUE for \"cmd.exe\"\n");
1456 }
1457
1458 /* Call various path/file name retrieving APIs and check the case of
1459  * the returned drive letter. Some apps (for instance Adobe Photoshop CS3
1460  * installer) depend on the drive letter being in upper case.
1461  */
1462 static void test_drive_letter_case(void)
1463 {
1464     UINT ret;
1465     char buf[MAX_PATH];
1466
1467 #define is_upper_case_letter(a) ((a) >= 'A' && (a) <= 'Z')
1468
1469     memset(buf, 0, sizeof(buf));
1470     SetLastError(0xdeadbeef);
1471     ret = GetWindowsDirectory(buf, sizeof(buf));
1472     ok(ret, "GetWindowsDirectory error %u\n", GetLastError());
1473     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1474     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1475     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1476
1477     /* re-use the buffer returned by GetFullPathName */
1478     buf[2] = '/';
1479     SetLastError(0xdeadbeef);
1480     ret = GetFullPathName(buf + 2, sizeof(buf), buf, NULL);
1481     ok(ret, "GetFullPathName error %u\n", GetLastError());
1482     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1483     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1484     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1485
1486     memset(buf, 0, sizeof(buf));
1487     SetLastError(0xdeadbeef);
1488     ret = GetSystemDirectory(buf, sizeof(buf));
1489     ok(ret, "GetSystemDirectory error %u\n", GetLastError());
1490     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1491     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1492     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1493
1494     memset(buf, 0, sizeof(buf));
1495     SetLastError(0xdeadbeef);
1496     ret = GetCurrentDirectory(sizeof(buf), buf);
1497     ok(ret, "GetCurrentDirectory error %u\n", GetLastError());
1498     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1499     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1500     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1501
1502     /* TEMP is an environment variable, so it can't be tested for case-sensitivity */
1503     memset(buf, 0, sizeof(buf));
1504     SetLastError(0xdeadbeef);
1505     ret = GetTempPath(sizeof(buf), buf);
1506     ok(ret, "GetTempPath error %u\n", GetLastError());
1507     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1508     if (buf[0])
1509     {
1510         ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1511         ok(buf[strlen(buf)-1] == '\\', "Temporary path (%s) doesn't end in a slash\n", buf);
1512     }
1513
1514     memset(buf, 0, sizeof(buf));
1515     SetLastError(0xdeadbeef);
1516     ret = GetFullPathName(".", sizeof(buf), buf, NULL);
1517     ok(ret, "GetFullPathName error %u\n", GetLastError());
1518     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1519     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1520     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1521
1522     /* re-use the buffer returned by GetFullPathName */
1523     SetLastError(0xdeadbeef);
1524     ret = GetShortPathName(buf, buf, sizeof(buf));
1525     ok(ret, "GetShortPathName error %u\n", GetLastError());
1526     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1527     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1528     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1529
1530     if (pGetLongPathNameA)
1531     {
1532         /* re-use the buffer returned by GetShortPathName */
1533         SetLastError(0xdeadbeef);
1534         ret = pGetLongPathNameA(buf, buf, sizeof(buf));
1535         ok(ret, "GetLongPathNameA error %u\n", GetLastError());
1536         ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1537         ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1538         ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1539     }
1540 #undef is_upper_case_letter
1541 }
1542
1543 static void test_SearchPathA(void)
1544 {
1545     CHAR pathA[MAX_PATH], fileA[] = "", buffA[MAX_PATH];
1546     CHAR *ptrA = NULL;
1547     DWORD ret;
1548
1549     if (!pSearchPathA)
1550     {
1551         win_skip("SearchPathA isn't available\n");
1552         return;
1553     }
1554
1555     GetWindowsDirectoryA(pathA, sizeof(pathA)/sizeof(CHAR));
1556
1557     /* NULL filename */
1558     SetLastError(0xdeadbeef);
1559     ret = pSearchPathA(pathA, NULL, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1560     ok(ret == 0, "Expected failure, got %d\n", ret);
1561     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1562       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1563
1564     /* empty filename */
1565     SetLastError(0xdeadbeef);
1566     ret = pSearchPathA(pathA, fileA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1567     ok(ret == 0, "Expected failure, got %d\n", ret);
1568     ok(GetLastError() == ERROR_INVALID_PARAMETER ||
1569        broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* win9x */,
1570       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1571 }
1572
1573 static void test_SearchPathW(void)
1574 {
1575     WCHAR pathW[MAX_PATH], fileW[] = { 0 }, buffW[MAX_PATH];
1576     WCHAR *ptrW = NULL;
1577     DWORD ret;
1578
1579     if (!pSearchPathW)
1580     {
1581         win_skip("SearchPathW isn't available\n");
1582         return;
1583     }
1584
1585     /* SearchPathW is a stub on win9x and doesn't return sane error,
1586        so quess if it's implemented indirectly */
1587     SetLastError(0xdeadbeef);
1588     GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
1589     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1590     {
1591         win_skip("SearchPathW not implemented\n");
1592         return;
1593     }
1594
1595 if (0)
1596 {
1597     /* NULL filename, crashes on nt4 */
1598     SetLastError(0xdeadbeef);
1599     ret = pSearchPathW(pathW, NULL, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1600     ok(ret == 0, "Expected failure, got %d\n", ret);
1601     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1602        "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1603 }
1604
1605     /* empty filename */
1606     SetLastError(0xdeadbeef);
1607     ret = pSearchPathW(pathW, fileW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1608     ok(ret == 0, "Expected failure, got %d\n", ret);
1609     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1610       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1611 }
1612
1613 static void test_GetFullPathNameA(void)
1614 {
1615     char output[MAX_PATH], *filepart;
1616     DWORD ret;
1617     int is_win9x, i;
1618
1619     const struct
1620     {
1621         LPCSTR name;
1622         DWORD len;
1623         LPSTR buffer;
1624         LPSTR *lastpart;
1625         int win9x_crash;
1626     } invalid_parameters[] =
1627     {
1628         {NULL, 0,        NULL,   NULL,      1},
1629         {NULL, MAX_PATH, NULL,   NULL,      1},
1630         {NULL, MAX_PATH, output, NULL,      1},
1631         {NULL, MAX_PATH, output, &filepart, 1},
1632         {"",   0,        NULL,   NULL},
1633         {"",   MAX_PATH, NULL,   NULL},
1634         {"",   MAX_PATH, output, NULL},
1635         {"",   MAX_PATH, output, &filepart},
1636     };
1637
1638     SetLastError(0xdeadbeef);
1639     ret = GetFullPathNameW(NULL, 0, NULL, NULL);
1640     is_win9x = !ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
1641
1642     if (is_win9x)
1643         win_skip("Skipping some tests that cause GetFullPathNameA to crash on Win9x\n");
1644
1645     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
1646     {
1647         if (is_win9x && invalid_parameters[i].win9x_crash)
1648             continue;
1649
1650         SetLastError(0xdeadbeef);
1651         strcpy(output, "deadbeef");
1652         filepart = (char *)0xdeadbeef;
1653         ret = GetFullPathNameA(invalid_parameters[i].name,
1654                                invalid_parameters[i].len,
1655                                invalid_parameters[i].buffer,
1656                                invalid_parameters[i].lastpart);
1657         ok(!ret, "[%d] Expected GetFullPathNameA to return 0, got %u\n", i, ret);
1658         ok(!strcmp(output, "deadbeef"), "[%d] Expected the output buffer to be unchanged, got \"%s\"\n", i, output);
1659         ok(filepart == (char *)0xdeadbeef, "[%d] Expected output file part pointer to be untouched, got %p\n", i, filepart);
1660         ok(GetLastError() == 0xdeadbeef ||
1661            GetLastError() == ERROR_BAD_PATHNAME || /* Win9x */
1662            GetLastError() == ERROR_INVALID_NAME, /* Win7 */
1663            "[%d] Expected GetLastError() to return 0xdeadbeef, got %u\n",
1664            i, GetLastError());
1665     }
1666 }
1667
1668 static void test_GetFullPathNameW(void)
1669 {
1670     static const WCHAR emptyW[] = {0};
1671     static const WCHAR deadbeefW[] = {'d','e','a','d','b','e','e','f',0};
1672
1673     WCHAR output[MAX_PATH], *filepart;
1674     DWORD ret;
1675     int i;
1676
1677     const struct
1678     {
1679         LPCWSTR name;
1680         DWORD len;
1681         LPWSTR buffer;
1682         LPWSTR *lastpart;
1683         int win7_expect;
1684     } invalid_parameters[] =
1685     {
1686         {NULL,   0,        NULL,   NULL},
1687         {NULL,   0,        NULL,   &filepart, 1},
1688         {NULL,   MAX_PATH, NULL,   NULL},
1689         {NULL,   MAX_PATH, output, NULL},
1690         {NULL,   MAX_PATH, output, &filepart, 1},
1691         {emptyW, 0,        NULL,   NULL},
1692         {emptyW, 0,        NULL,   &filepart, 1},
1693         {emptyW, MAX_PATH, NULL,   NULL},
1694         {emptyW, MAX_PATH, output, NULL},
1695         {emptyW, MAX_PATH, output, &filepart, 1},
1696     };
1697
1698     SetLastError(0xdeadbeef);
1699     ret = GetFullPathNameW(NULL, 0, NULL, NULL);
1700     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1701     {
1702         win_skip("GetFullPathNameW is not available\n");
1703         return;
1704     }
1705
1706     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
1707     {
1708         SetLastError(0xdeadbeef);
1709         lstrcpyW(output, deadbeefW);
1710         filepart = (WCHAR *)0xdeadbeef;
1711         ret = GetFullPathNameW(invalid_parameters[i].name,
1712                                invalid_parameters[i].len,
1713                                invalid_parameters[i].buffer,
1714                                invalid_parameters[i].lastpart);
1715         ok(!ret, "[%d] Expected GetFullPathNameW to return 0, got %u\n", i, ret);
1716         ok(!lstrcmpW(output, deadbeefW), "[%d] Expected the output buffer to be unchanged, got %s\n", i, wine_dbgstr_w(output));
1717         ok(filepart == (WCHAR *)0xdeadbeef ||
1718            (invalid_parameters[i].win7_expect && filepart == NULL),
1719            "[%d] Expected output file part pointer to be untouched, got %p\n", i, filepart);
1720         ok(GetLastError() == 0xdeadbeef ||
1721            GetLastError() == ERROR_INVALID_NAME, /* Win7 */
1722            "[%d] Expected GetLastError() to return 0xdeadbeef, got %u\n",
1723            i, GetLastError());
1724     }
1725 }
1726
1727 static void init_pointers(void)
1728 {
1729     HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
1730
1731 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hKernel32, #f))
1732     MAKEFUNC(GetLongPathNameA);
1733     MAKEFUNC(GetLongPathNameW);
1734     MAKEFUNC(NeedCurrentDirectoryForExePathA);
1735     MAKEFUNC(NeedCurrentDirectoryForExePathW);
1736     MAKEFUNC(SearchPathA);
1737     MAKEFUNC(SearchPathW);
1738 #undef MAKEFUNC
1739 }
1740
1741 START_TEST(path)
1742 {
1743     CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
1744
1745     init_pointers();
1746
1747     /* Report only once */
1748     if (!pGetLongPathNameA)
1749         win_skip("GetLongPathNameA is not available\n");
1750     if (!pGetLongPathNameW)
1751         win_skip("GetLongPathNameW is not available\n");
1752
1753     test_InitPathA(curdir, &curDrive, &otherDrive);
1754     test_CurrentDirectoryA(origdir,curdir);
1755     test_PathNameA(curdir, curDrive, otherDrive);
1756     test_CleanupPathA(origdir,curdir);
1757     test_GetTempPath();
1758     test_GetLongPathNameA();
1759     test_GetLongPathNameW();
1760     test_GetShortPathNameW();
1761     test_GetSystemDirectory();
1762     test_GetWindowsDirectory();
1763     test_NeedCurrentDirectoryForExePathA();
1764     test_NeedCurrentDirectoryForExePathW();
1765     test_drive_letter_case();
1766     test_SearchPathA();
1767     test_SearchPathW();
1768     test_GetFullPathNameA();
1769     test_GetFullPathNameW();
1770 }