xref: /openbsd/gnu/usr.bin/perl/win32/vdir.h (revision 097a140d)
1 /* vdir.h
2  *
3  * (c) 1999 Microsoft Corporation. All rights reserved.
4  * Portions (c) 1999 ActiveState Tool Corp, http://www.ActiveState.com/
5  *
6  *    You may distribute under the terms of either the GNU General Public
7  *    License or the Artistic License, as specified in the README file.
8  */
9 
10 #ifndef ___VDir_H___
11 #define ___VDir_H___
12 
13 /*
14  * Allow one slot for each possible drive letter
15  * and one additional slot for a UNC name
16  */
17 const int driveCount = ('Z'-'A')+1+1;
18 const int driveLetterCount = ('Z'-'A')+1;
19 
20 class VDir
21 {
22 public:
23     VDir(int bManageDir = 1);
24     ~VDir() {};
25 
26     void Init(VDir* pDir, VMem *pMem);
27     void SetDefaultA(char const *pDefault);
28     void SetDefaultW(WCHAR const *pDefault);
29     char* MapPathA(const char *pInName);
30     WCHAR* MapPathW(const WCHAR *pInName);
31     int SetCurrentDirectoryA(char *lpBuffer);
32     int SetCurrentDirectoryW(WCHAR *lpBuffer);
33     inline int GetDefault(void) { return nDefault; };
34 
35     inline char* GetCurrentDirectoryA(int dwBufSize, char *lpBuffer)
36     {
37 	char* ptr = dirTableA[nDefault];
38 	while (--dwBufSize)
39 	{
40 	    if ((*lpBuffer++ = *ptr++) == '\0')
41 		break;
42 	}
43         *lpBuffer = '\0';
44 	return /* unused */ NULL;
45     };
46     inline WCHAR* GetCurrentDirectoryW(int dwBufSize, WCHAR *lpBuffer)
47     {
48 	WCHAR* ptr = dirTableW[nDefault];
49 	while (--dwBufSize)
50 	{
51 	    if ((*lpBuffer++ = *ptr++) == '\0')
52 		break;
53 	}
54         *lpBuffer = '\0';
55 	return /* unused */ NULL;
56     };
57 
58     DWORD CalculateEnvironmentSpace(void);
59     LPSTR BuildEnvironmentSpace(LPSTR lpStr);
60 
61 protected:
62     int SetDirA(char const *pPath, int index);
63     int SetDirW(WCHAR const *pPath, int index);
64     void FromEnvA(char *pEnv, int index);
65     void FromEnvW(WCHAR *pEnv, int index);
66 
67     inline const char *GetDefaultDirA(void)
68     {
69 	return dirTableA[nDefault];
70     };
71     inline void SetDefaultDirA(char const *pPath, int index)
72     {
73 	SetDirA(pPath, index);
74 	nDefault = index;
75     };
76     inline const WCHAR *GetDefaultDirW(void)
77     {
78 	return dirTableW[nDefault];
79     };
80     inline void SetDefaultDirW(WCHAR const *pPath, int index)
81     {
82 	SetDirW(pPath, index);
83 	nDefault = index;
84     };
85     inline const char *GetDirA(int index)
86     {
87 	char *ptr = dirTableA[index];
88 	if (!ptr) {
89 	    /* simulate the existence of this drive */
90 	    ptr = szLocalBufferA;
91 	    ptr[0] = 'A' + index;
92 	    ptr[1] = ':';
93 	    ptr[2] = '\\';
94 	    ptr[3] = 0;
95 	}
96 	return ptr;
97     };
98     inline const WCHAR *GetDirW(int index)
99     {
100 	WCHAR *ptr = dirTableW[index];
101 	if (!ptr) {
102 	    /* simulate the existence of this drive */
103 	    ptr = szLocalBufferW;
104 	    ptr[0] = 'A' + index;
105 	    ptr[1] = ':';
106 	    ptr[2] = '\\';
107 	    ptr[3] = 0;
108 	}
109 	return ptr;
110     };
111 
112     inline int DriveIndex(char chr)
113     {
114 	if (chr == '\\' || chr == '/')
115 	    return ('Z'-'A')+1;
116 	return (chr | 0x20)-'a';
117     };
118 
119     VMem *pMem;
120     int nDefault, bManageDirectory;
121     char *dirTableA[driveCount];
122     char szLocalBufferA[MAX_PATH+1];
123     WCHAR *dirTableW[driveCount];
124     WCHAR szLocalBufferW[MAX_PATH+1];
125 };
126 
127 
128 VDir::VDir(int bManageDir /* = 1 */)
129 {
130     nDefault = 0;
131     bManageDirectory = bManageDir;
132     memset(dirTableA, 0, sizeof(dirTableA));
133     memset(dirTableW, 0, sizeof(dirTableW));
134 }
135 
136 void VDir::Init(VDir* pDir, VMem *p)
137 {
138     int index;
139 
140     pMem = p;
141     if (pDir) {
142 	for (index = 0; index < driveCount; ++index) {
143 	    SetDirW(pDir->GetDirW(index), index);
144 	}
145 	nDefault = pDir->GetDefault();
146     }
147     else {
148 	int bSave = bManageDirectory;
149 	DWORD driveBits = GetLogicalDrives();
150 
151 	bManageDirectory = 0;
152         WCHAR szBuffer[MAX_PATH*driveCount];
153         if (GetLogicalDriveStringsW(sizeof(szBuffer), szBuffer)) {
154             WCHAR* pEnv = GetEnvironmentStringsW();
155             WCHAR* ptr = szBuffer;
156             for (index = 0; index < driveCount; ++index) {
157                 if (driveBits & (1<<index)) {
158                     ptr += SetDirW(ptr, index) + 1;
159                     FromEnvW(pEnv, index);
160                 }
161             }
162             FreeEnvironmentStringsW(pEnv);
163         }
164         SetDefaultW(L".");
165 	bManageDirectory = bSave;
166   }
167 }
168 
169 int VDir::SetDirA(char const *pPath, int index)
170 {
171     char chr, *ptr;
172     int length = 0;
173     WCHAR wBuffer[MAX_PATH+1];
174     if (index < driveCount && pPath != NULL) {
175 	length = strlen(pPath);
176 	pMem->Free(dirTableA[index]);
177 	ptr = dirTableA[index] = (char*)pMem->Malloc(length+2);
178 	if (ptr != NULL) {
179 	    strcpy(ptr, pPath);
180 	    ptr += length-1;
181 	    chr = *ptr++;
182 	    if (chr != '\\' && chr != '/') {
183 		*ptr++ = '\\';
184 		*ptr = '\0';
185 	    }
186 	    MultiByteToWideChar(CP_ACP, 0, dirTableA[index], -1,
187 		    wBuffer, (sizeof(wBuffer)/sizeof(WCHAR)));
188 	    length = wcslen(wBuffer);
189 	    pMem->Free(dirTableW[index]);
190 	    dirTableW[index] = (WCHAR*)pMem->Malloc((length+1)*2);
191 	    if (dirTableW[index] != NULL) {
192 		wcscpy(dirTableW[index], wBuffer);
193 	    }
194 	}
195     }
196 
197     if(bManageDirectory)
198 	::SetCurrentDirectoryA(pPath);
199 
200     return length;
201 }
202 
203 void VDir::FromEnvA(char *pEnv, int index)
204 {   /* gets the directory for index from the environment variable. */
205     while (*pEnv != '\0') {
206 	if ((pEnv[0] == '=') && (DriveIndex(pEnv[1]) == index)
207             && pEnv[2] == ':' && pEnv[3] == '=') {
208 	    SetDirA(&pEnv[4], index);
209 	    break;
210 	}
211 	else
212 	    pEnv += strlen(pEnv)+1;
213     }
214 }
215 
216 void VDir::FromEnvW(WCHAR *pEnv, int index)
217 {   /* gets the directory for index from the environment variable. */
218     while (*pEnv != '\0') {
219 	if ((pEnv[0] == '=') && (DriveIndex((char)pEnv[1]) == index)
220             && pEnv[2] == ':' && pEnv[3] == '=') {
221 	    SetDirW(&pEnv[4], index);
222 	    break;
223 	}
224 	else
225 	    pEnv += wcslen(pEnv)+1;
226     }
227 }
228 
229 void VDir::SetDefaultA(char const *pDefault)
230 {
231     char szBuffer[MAX_PATH+1];
232     char *pPtr;
233 
234     if (GetFullPathNameA(pDefault, sizeof(szBuffer), szBuffer, &pPtr)) {
235         if (*pDefault != '.' && pPtr != NULL)
236 	    *pPtr = '\0';
237 
238 	SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0]));
239     }
240 }
241 
242 int VDir::SetDirW(WCHAR const *pPath, int index)
243 {
244     WCHAR chr, *ptr;
245     int length = 0;
246     if (index < driveCount && pPath != NULL) {
247 	length = wcslen(pPath);
248 	pMem->Free(dirTableW[index]);
249 	ptr = dirTableW[index] = (WCHAR*)pMem->Malloc((length+2)*2);
250 	if (ptr != NULL) {
251             char *ansi;
252 	    wcscpy(ptr, pPath);
253 	    ptr += length-1;
254 	    chr = *ptr++;
255 	    if (chr != '\\' && chr != '/') {
256 		*ptr++ = '\\';
257 		*ptr = '\0';
258 	    }
259             ansi = win32_ansipath(dirTableW[index]);
260 	    length = strlen(ansi);
261 	    pMem->Free(dirTableA[index]);
262 	    dirTableA[index] = (char*)pMem->Malloc(length+1);
263 	    if (dirTableA[index] != NULL) {
264 		strcpy(dirTableA[index], ansi);
265 	    }
266             win32_free(ansi);
267 	}
268     }
269 
270     if(bManageDirectory)
271 	::SetCurrentDirectoryW(pPath);
272 
273     return length;
274 }
275 
276 void VDir::SetDefaultW(WCHAR const *pDefault)
277 {
278     WCHAR szBuffer[MAX_PATH+1];
279     WCHAR *pPtr;
280 
281     if (GetFullPathNameW(pDefault, (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr)) {
282         if (*pDefault != '.' && pPtr != NULL)
283 	    *pPtr = '\0';
284 
285 	SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0]));
286     }
287 }
288 
289 inline BOOL IsPathSep(char ch)
290 {
291     return (ch == '\\' || ch == '/');
292 }
293 
294 inline void DoGetFullPathNameA(char* lpBuffer, DWORD dwSize, char* Dest)
295 {
296     char *pPtr;
297 
298     /*
299      * On WinNT GetFullPathName does not fail, (or at least always
300      * succeeds when the drive is valid) WinNT does set *Dest to NULL
301      * On Win98 GetFullPathName will set last error if it fails, but
302      * does not touch *Dest
303      */
304     *Dest = '\0';
305     GetFullPathNameA(lpBuffer, dwSize, Dest, &pPtr);
306 }
307 
308 inline bool IsSpecialFileName(const char* pName)
309 {
310     /* specical file names are devices that the system can open
311      * these include AUX, CON, NUL, PRN, COMx, LPTx, CLOCK$, CONIN$, CONOUT$
312      * (x is a single digit, and names are case-insensitive)
313      */
314     char ch = (pName[0] & ~0x20);
315     switch (ch)
316     {
317 	case 'A': /* AUX */
318 	    if (((pName[1] & ~0x20) == 'U')
319 		&& ((pName[2] & ~0x20) == 'X')
320 		&& !pName[3])
321 		    return true;
322 	    break;
323 	case 'C': /* CLOCK$, COMx,  CON, CONIN$ CONOUT$ */
324 	    ch = (pName[1] & ~0x20);
325 	    switch (ch)
326 	    {
327 		case 'L': /* CLOCK$ */
328 		    if (((pName[2] & ~0x20) == 'O')
329 			&& ((pName[3] & ~0x20) == 'C')
330 			&& ((pName[4] & ~0x20) == 'K')
331 			&& (pName[5] == '$')
332 			&& !pName[6])
333 			    return true;
334 		    break;
335 		case 'O': /* COMx,  CON, CONIN$ CONOUT$ */
336 		    if ((pName[2] & ~0x20) == 'M') {
337 			if (    inRANGE(pName[3], '1', '9')
338 			    && !pName[4])
339 			    return true;
340 		    }
341 		    else if ((pName[2] & ~0x20) == 'N') {
342 			if (!pName[3])
343 			    return true;
344 			else if ((pName[3] & ~0x20) == 'I') {
345 			    if (((pName[4] & ~0x20) == 'N')
346 				&& (pName[5] == '$')
347 				&& !pName[6])
348 			    return true;
349 			}
350 			else if ((pName[3] & ~0x20) == 'O') {
351 			    if (((pName[4] & ~0x20) == 'U')
352 				&& ((pName[5] & ~0x20) == 'T')
353 				&& (pName[6] == '$')
354 				&& !pName[7])
355 			    return true;
356 			}
357 		    }
358 		    break;
359 	    }
360 	    break;
361 	case 'L': /* LPTx */
362 	    if (((pName[1] & ~0x20) == 'U')
363 		&& ((pName[2] & ~0x20) == 'X')
364 		&&  inRANGE(pName[3], '1', '9')
365 		&& !pName[4])
366 		    return true;
367 	    break;
368 	case 'N': /* NUL */
369 	    if (((pName[1] & ~0x20) == 'U')
370 		&& ((pName[2] & ~0x20) == 'L')
371 		&& !pName[3])
372 		    return true;
373 	    break;
374 	case 'P': /* PRN */
375 	    if (((pName[1] & ~0x20) == 'R')
376 		&& ((pName[2] & ~0x20) == 'N')
377 		&& !pName[3])
378 		    return true;
379 	    break;
380     }
381     return false;
382 }
383 
384 char *VDir::MapPathA(const char *pInName)
385 {   /*
386      * possiblities -- relative path or absolute path with or without drive letter
387      * OR UNC name
388      */
389     int driveIndex;
390     char szBuffer[(MAX_PATH+1)*2];
391     char szlBuf[MAX_PATH+1];
392     int length = strlen(pInName);
393 
394     if (!length)
395 	return (char*)pInName;
396 
397     if (length > MAX_PATH) {
398 	strncpy(szlBuf, pInName, MAX_PATH);
399 	if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) {
400 	    /* absolute path - reduce length by 2 for drive specifier */
401 	    szlBuf[MAX_PATH-2] = '\0';
402 	}
403 	else
404 	    szlBuf[MAX_PATH] = '\0';
405 	pInName = szlBuf;
406     }
407     /* strlen(pInName) is now <= MAX_PATH */
408 
409     if (length > 1 && pInName[1] == ':') {
410 	/* has drive letter */
411 	if (length > 2 && IsPathSep(pInName[2])) {
412 	    /* absolute with drive letter */
413 	    DoGetFullPathNameA((char*)pInName, sizeof(szLocalBufferA), szLocalBufferA);
414 	}
415 	else {
416 	    /* relative path with drive letter */
417             driveIndex = DriveIndex(*pInName);
418             if (driveIndex < 0 || driveIndex >= driveLetterCount)
419                 return (char *)pInName;
420 	    strcpy(szBuffer, GetDirA(driveIndex));
421 	    strcat(szBuffer, &pInName[2]);
422 	    if(strlen(szBuffer) > MAX_PATH)
423 		szBuffer[MAX_PATH] = '\0';
424 
425 	    DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA);
426 	}
427     }
428     else {
429 	/* no drive letter */
430 	if (length > 1 && IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
431 	    /* UNC name */
432 	    DoGetFullPathNameA((char*)pInName, sizeof(szLocalBufferA), szLocalBufferA);
433 	}
434 	else {
435 	    strcpy(szBuffer, GetDefaultDirA());
436 	    if (IsPathSep(pInName[0])) {
437 		/* absolute path */
438 		strcpy(&szBuffer[2], pInName);
439 		DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA);
440 	    }
441 	    else {
442 		/* relative path */
443 		if (IsSpecialFileName(pInName)) {
444 		    return (char*)pInName;
445 		}
446 		else {
447 		    strcat(szBuffer, pInName);
448 		    if (strlen(szBuffer) > MAX_PATH)
449 			szBuffer[MAX_PATH] = '\0';
450 
451 		    DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA);
452 		}
453 	    }
454 	}
455     }
456 
457     return szLocalBufferA;
458 }
459 
460 int VDir::SetCurrentDirectoryA(char *lpBuffer)
461 {
462     char *pPtr;
463     int length, nRet = -1;
464 
465     pPtr = MapPathA(lpBuffer);
466     length = strlen(pPtr);
467     if(length > 3 && IsPathSep(pPtr[length-1])) {
468 	/* don't remove the trailing slash from 'x:\'  */
469 	pPtr[length-1] = '\0';
470     }
471 
472     DWORD r = GetFileAttributesA(pPtr);
473     if ((r != 0xffffffff) && (r & FILE_ATTRIBUTE_DIRECTORY))
474     {
475 	char szBuffer[(MAX_PATH+1)*2];
476 	DoGetFullPathNameA(pPtr, sizeof(szBuffer), szBuffer);
477 	SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0]));
478 	nRet = 0;
479     }
480 
481     return nRet;
482 }
483 
484 DWORD VDir::CalculateEnvironmentSpace(void)
485 {   /* the current directory environment strings are stored as '=D:=d:\path' */
486     int index;
487     DWORD dwSize = 0;
488     for (index = 0; index < driveCount; ++index) {
489 	if (dirTableA[index] != NULL) {
490 	    dwSize += strlen(dirTableA[index]) + 5;  /* add 1 for trailing NULL and 4 for '=D:=' */
491 	}
492     }
493     return dwSize;
494 }
495 
496 LPSTR VDir::BuildEnvironmentSpace(LPSTR lpStr)
497 {   /* store the current directory environment strings as '=D:=d:\path' */
498     int index, length;
499     LPSTR lpDirStr;
500     for (index = 0; index < driveCount; ++index) {
501 	lpDirStr = dirTableA[index];
502 	if (lpDirStr != NULL) {
503 	    lpStr[0] = '=';
504 	    lpStr[1] = lpDirStr[0];
505 	    lpStr[2] = '\0';
506 	    CharUpper(&lpStr[1]);
507 	    lpStr[2] = ':';
508 	    lpStr[3] = '=';
509 	    strcpy(&lpStr[4], lpDirStr);
510 	    length = strlen(lpDirStr);
511 	    lpStr += length + 5; /* add 1 for trailing NULL and 4 for '=D:=' */
512 	    if (length > 3 && IsPathSep(lpStr[-2])) {
513 		lpStr[-2] = '\0';   /* remove the trailing path separator */
514 		--lpStr;
515 	    }
516 	}
517     }
518     return lpStr;
519 }
520 
521 inline BOOL IsPathSep(WCHAR ch)
522 {
523     return (ch == '\\' || ch == '/');
524 }
525 
526 inline void DoGetFullPathNameW(WCHAR* lpBuffer, DWORD dwSize, WCHAR* Dest)
527 {
528     WCHAR *pPtr;
529 
530     /*
531      * On WinNT GetFullPathName does not fail, (or at least always
532      * succeeds when the drive is valid) WinNT does set *Dest to NULL
533      * On Win98 GetFullPathName will set last error if it fails, but
534      * does not touch *Dest
535      */
536     *Dest = '\0';
537     GetFullPathNameW(lpBuffer, dwSize, Dest, &pPtr);
538 }
539 
540 inline bool IsSpecialFileName(const WCHAR* pName)
541 {
542     /* specical file names are devices that the system can open
543      * these include AUX, CON, NUL, PRN, COMx, LPTx, CLOCK$, CONIN$, CONOUT$
544      * (x is a single digit, and names are case-insensitive)
545      */
546     WCHAR ch = (pName[0] & ~0x20);
547     switch (ch)
548     {
549 	case 'A': /* AUX */
550 	    if (((pName[1] & ~0x20) == 'U')
551 		&& ((pName[2] & ~0x20) == 'X')
552 		&& !pName[3])
553 		    return true;
554 	    break;
555 	case 'C': /* CLOCK$, COMx,  CON, CONIN$ CONOUT$ */
556 	    ch = (pName[1] & ~0x20);
557 	    switch (ch)
558 	    {
559 		case 'L': /* CLOCK$ */
560 		    if (((pName[2] & ~0x20) == 'O')
561 			&& ((pName[3] & ~0x20) == 'C')
562 			&& ((pName[4] & ~0x20) == 'K')
563 			&& (pName[5] == '$')
564 			&& !pName[6])
565 			    return true;
566 		    break;
567 		case 'O': /* COMx,  CON, CONIN$ CONOUT$ */
568 		    if ((pName[2] & ~0x20) == 'M') {
569 		        if (    inRANGE(pName[3], '1', '9')
570 			    && !pName[4])
571 			    return true;
572 		    }
573 		    else if ((pName[2] & ~0x20) == 'N') {
574 			if (!pName[3])
575 			    return true;
576 			else if ((pName[3] & ~0x20) == 'I') {
577 			    if (((pName[4] & ~0x20) == 'N')
578 				&& (pName[5] == '$')
579 				&& !pName[6])
580 			    return true;
581 			}
582 			else if ((pName[3] & ~0x20) == 'O') {
583 			    if (((pName[4] & ~0x20) == 'U')
584 				&& ((pName[5] & ~0x20) == 'T')
585 				&& (pName[6] == '$')
586 				&& !pName[7])
587 			    return true;
588 			}
589 		    }
590 		    break;
591 	    }
592 	    break;
593 	case 'L': /* LPTx */
594 	    if (((pName[1] & ~0x20) == 'U')
595 		&& ((pName[2] & ~0x20) == 'X')
596 		&&  inRANGE(pName[3], '1', '9')
597 		&& !pName[4])
598 		    return true;
599 	    break;
600 	case 'N': /* NUL */
601 	    if (((pName[1] & ~0x20) == 'U')
602 		&& ((pName[2] & ~0x20) == 'L')
603 		&& !pName[3])
604 		    return true;
605 	    break;
606 	case 'P': /* PRN */
607 	    if (((pName[1] & ~0x20) == 'R')
608 		&& ((pName[2] & ~0x20) == 'N')
609 		&& !pName[3])
610 		    return true;
611 	    break;
612     }
613     return false;
614 }
615 
616 WCHAR* VDir::MapPathW(const WCHAR *pInName)
617 {   /*
618      * possiblities -- relative path or absolute path with or without drive letter
619      * OR UNC name
620      */
621     int driveIndex;
622     WCHAR szBuffer[(MAX_PATH+1)*2];
623     WCHAR szlBuf[MAX_PATH+1];
624     int length = wcslen(pInName);
625 
626     if (!length)
627 	return (WCHAR*)pInName;
628 
629     if (length > MAX_PATH) {
630 	wcsncpy(szlBuf, pInName, MAX_PATH);
631 	if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) {
632 	    /* absolute path - reduce length by 2 for drive specifier */
633 	    szlBuf[MAX_PATH-2] = '\0';
634 	}
635 	else
636 	    szlBuf[MAX_PATH] = '\0';
637 	pInName = szlBuf;
638     }
639     /* strlen(pInName) is now <= MAX_PATH */
640 
641     if (length > 1 && pInName[1] == ':') {
642 	/* has drive letter */
643 	if (IsPathSep(pInName[2])) {
644 	    /* absolute with drive letter */
645 	    DoGetFullPathNameW((WCHAR*)pInName, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
646 	}
647 	else {
648 	    /* relative path with drive letter */
649             driveIndex = DriveIndex(*pInName);
650             if (driveIndex < 0 || driveIndex >= driveLetterCount)
651                 return (WCHAR *)pInName;
652 	    wcscpy(szBuffer, GetDirW(driveIndex));
653 	    wcscat(szBuffer, &pInName[2]);
654 	    if(wcslen(szBuffer) > MAX_PATH)
655 		szBuffer[MAX_PATH] = '\0';
656 
657 	    DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
658 	}
659     }
660     else {
661 	/* no drive letter */
662 	if (length > 1 && IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
663 	    /* UNC name */
664 	    DoGetFullPathNameW((WCHAR*)pInName, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
665 	}
666 	else {
667 	    wcscpy(szBuffer, GetDefaultDirW());
668 	    if (IsPathSep(pInName[0])) {
669 		/* absolute path */
670 		wcscpy(&szBuffer[2], pInName);
671 		DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
672 	    }
673 	    else {
674 		/* relative path */
675 		if (IsSpecialFileName(pInName)) {
676 		    return (WCHAR*)pInName;
677 		}
678 		else {
679 		    wcscat(szBuffer, pInName);
680 		    if (wcslen(szBuffer) > MAX_PATH)
681 			szBuffer[MAX_PATH] = '\0';
682 
683 		    DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
684 		}
685 	    }
686 	}
687     }
688     return szLocalBufferW;
689 }
690 
691 int VDir::SetCurrentDirectoryW(WCHAR *lpBuffer)
692 {
693     WCHAR *pPtr;
694     int length, nRet = -1;
695 
696     pPtr = MapPathW(lpBuffer);
697     length = wcslen(pPtr);
698     if(length > 3 && IsPathSep(pPtr[length-1])) {
699 	/* don't remove the trailing slash from 'x:\'  */
700 	pPtr[length-1] = '\0';
701     }
702 
703     DWORD r = GetFileAttributesW(pPtr);
704     if ((r != 0xffffffff) && (r & FILE_ATTRIBUTE_DIRECTORY))
705     {
706 	WCHAR wBuffer[(MAX_PATH+1)*2];
707 	DoGetFullPathNameW(pPtr, (sizeof(wBuffer)/sizeof(WCHAR)), wBuffer);
708 	SetDefaultDirW(wBuffer, DriveIndex((char)wBuffer[0]));
709 	nRet = 0;
710     }
711 
712     return nRet;
713 }
714 
715 #endif	/* ___VDir_H___ */
716