You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
610 lines
17 KiB
610 lines
17 KiB
// PSeuDO CURrentDirectory module (psdocurd.c)
|
|
//
|
|
// This was swiped from cmd.exe sources to use the environment to emulate
|
|
// per process per drive current directory stuff.
|
|
//
|
|
// This uses the special '=A:=' environment strings to remember the
|
|
// current directories.
|
|
//
|
|
// Since the library is a DLL, all globals are process based.
|
|
//
|
|
#define UNICODE 1
|
|
|
|
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
#define SUCCESS FALSE
|
|
#define FAILURE TRUE
|
|
#define GD_DEFAULT 0
|
|
|
|
WCHAR CurDrvDirW[MAX_PATH] = L"";
|
|
|
|
#define DBL_BSLASH(sz) \
|
|
(*(WCHAR *)(sz) == CHAR_BSLASH) && \
|
|
(*(WCHAR *)((sz)+1) == CHAR_BSLASH)
|
|
|
|
INT
|
|
SheSetEnvVarW(
|
|
WCHAR *varname,
|
|
WCHAR *varvalue
|
|
)
|
|
{
|
|
if (!wcslen(varvalue)) {
|
|
varvalue = NULL; // null to remove from env
|
|
}
|
|
return (!SetEnvironmentVariable(varname, varvalue));
|
|
}
|
|
|
|
WCHAR *
|
|
SheGetEnvVarW(
|
|
WCHAR *varname)
|
|
{
|
|
static WCHAR GetEnvVarBuffer[ 1024 ];
|
|
|
|
if (GetEnvironmentVariableW(varname, GetEnvVarBuffer, 1024)) {
|
|
return(GetEnvVarBuffer);
|
|
} else {
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
INT
|
|
SheGetPathOffsetW(
|
|
LPWSTR lpszDir)
|
|
{
|
|
// sanity
|
|
if (!lpszDir || !*lpszDir) {
|
|
return(-1);
|
|
}
|
|
|
|
if ((*(lpszDir+1) == WCHAR_COLON) &&
|
|
((*(lpszDir+2) == WCHAR_BSLASH) ||
|
|
(*(lpszDir+2) == WCHAR_SLASH) ||
|
|
(*(lpszDir+2) == WCHAR_NULL)) ) {
|
|
|
|
return(2);
|
|
|
|
} else if (DBL_BSLASH(lpszDir)) {
|
|
|
|
// Deviceless, assume LanMan Provided UNC names (i.e. DBL_BSLASH above)
|
|
|
|
INT cchServerShareLen = -1;
|
|
DWORD dwSlashesSeen = 0;
|
|
|
|
// There are exactly 4 b-slashes from here
|
|
|
|
while (dwSlashesSeen != 4) {
|
|
cchServerShareLen++;
|
|
|
|
if (!*lpszDir) {
|
|
if (dwSlashesSeen == 3) {
|
|
return(cchServerShareLen);
|
|
} else {
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
if ((*lpszDir == CHAR_BSLASH) || (*lpszDir == CHAR_SLASH)) {
|
|
dwSlashesSeen++;
|
|
}
|
|
|
|
lpszDir++;
|
|
}
|
|
|
|
return(cchServerShareLen);
|
|
|
|
} else {
|
|
|
|
// unrecognized format
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
INT
|
|
SheGetDirW(
|
|
INT iDrive, // 0 = default, 1=A....
|
|
WCHAR *str
|
|
)
|
|
{
|
|
WCHAR denvname[ 4 ];
|
|
WCHAR *denvvalue;
|
|
WCHAR *strT = str;
|
|
|
|
if (iDrive-- == GD_DEFAULT) {
|
|
GetCurrentDirectoryW(MAX_PATH, str); // pray that str is at least MAX_PATH
|
|
return(SUCCESS);
|
|
}
|
|
|
|
denvname[ 0 ] = WCHAR_EQUAL;
|
|
denvname[ 1 ] = (WCHAR)(WCHAR_CAP_A + (WCHAR)iDrive);
|
|
denvname[ 2 ] = WCHAR_COLON;
|
|
denvname[ 3 ] = WCHAR_NULL;
|
|
|
|
denvvalue = SheGetEnvVarW( denvname );
|
|
if (!denvvalue) {
|
|
*str++ = (WCHAR)(WCHAR_CAP_A + (WCHAR)iDrive);
|
|
*str++ = WCHAR_COLON;
|
|
*str++ = WCHAR_BSLASH;
|
|
*str = WCHAR_NULL;
|
|
}
|
|
else {
|
|
|
|
if (FAILED(StringCchCopy(str, MAX_PATH, denvvalue)))
|
|
{
|
|
return FAILURE;
|
|
}
|
|
}
|
|
|
|
// there is a subtle difference between getcurrentdirectory() of DOS and the
|
|
// equivalent SheGetDir() of NT. On dos, getcurrentdirectory() accesses the
|
|
// floppy drives while in NT SheGetDir() returns the values that are set in
|
|
// the environment variables. So we hit the disk on NT too, by calling
|
|
// GetFileAttributes. We return SUCCESS or FAILURE based on the return value
|
|
// of GetFileAttributes.
|
|
|
|
if (GetFileAttributesW(strT) == (DWORD)0xffffffff)
|
|
return(FAILURE);
|
|
else
|
|
return(SUCCESS);
|
|
}
|
|
|
|
// Should be BOOL, but possible mips breakage
|
|
INT
|
|
SheGetDirA(
|
|
INT iDrive, // 0 = default, 1=A....
|
|
CHAR *szDirA)
|
|
{
|
|
WCHAR szDirW[MAX_PATH];
|
|
BOOL fDefCharUsed;
|
|
|
|
INT nRet;
|
|
|
|
if (!szDirA) {
|
|
return(FAILURE);
|
|
}
|
|
|
|
nRet = SheGetDirW(iDrive, szDirW);
|
|
if (SUCCESS == nRet)
|
|
{
|
|
WideCharToMultiByte(CP_ACP, 0, szDirW, -1, (LPSTR)szDirA,
|
|
MAX_PATH, NULL, &fDefCharUsed);
|
|
}
|
|
|
|
return(nRet);
|
|
}
|
|
|
|
INT
|
|
SheChangeDirW(
|
|
WCHAR *newdir
|
|
)
|
|
{
|
|
WCHAR denvname[ 4 ];
|
|
WCHAR newpath[ MAX_PATH ];
|
|
WCHAR denvvalue[ MAX_PATH ];
|
|
WCHAR c, *s;
|
|
DWORD attr;
|
|
|
|
GetCurrentDirectoryW( MAX_PATH, denvvalue );
|
|
c = (WCHAR)(DWORD_PTR)CharUpperW((LPTSTR)(DWORD_PTR)denvvalue[0]);
|
|
|
|
denvname[0] = WCHAR_EQUAL;
|
|
if (IsCharAlphaW(*newdir) && newdir[1] == WCHAR_COLON) {
|
|
denvname[1] = (WCHAR)(DWORD_PTR)CharUpperW((LPTSTR)(DWORD_PTR)*newdir);
|
|
newdir += 2;
|
|
} else {
|
|
denvname[ 1 ] = c;
|
|
}
|
|
denvname[ 2 ] = WCHAR_COLON;
|
|
denvname[ 3 ] = WCHAR_NULL;
|
|
|
|
if ((*newdir == WCHAR_BSLASH) || (*newdir == WCHAR_SLASH)) {
|
|
newpath[ 0 ] = denvname[ 1 ];
|
|
newpath[ 1 ] = denvname[ 2 ];
|
|
if (FAILED(StringCchCopy( &newpath[ 2 ], ARRAYSIZE(newpath) - 2, newdir)))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
} else {
|
|
if (NULL != (s = SheGetEnvVarW( denvname )))
|
|
{
|
|
if (FAILED(StringCchCopy(newpath, ARRAYSIZE(newpath), s)))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
newpath[ 0 ] = denvname[ 1 ];
|
|
newpath[ 1 ] = denvname[ 2 ];
|
|
newpath[ 2 ] = WCHAR_NULL;
|
|
}
|
|
s = newpath + wcslen( newpath );
|
|
*s++ = WCHAR_BSLASH;
|
|
if (FAILED(StringCchCopy(s, ARRAYSIZE(newpath) - (s - newpath), newdir)))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
if (!GetFullPathNameW(newpath, MAX_PATH, denvvalue, &s )) {
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
attr = GetFileAttributesW( denvvalue );
|
|
if (attr == -1 || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
if (SheSetEnvVarW(denvname,denvvalue)) {
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
SetCurrentDirectoryW( denvvalue );
|
|
|
|
// this seems wrong... SheGetDir(GD_DEFAULT, CurDrvDirW) ;
|
|
if (FAILED(StringCchCopy(CurDrvDirW, ARRAYSIZE(CurDrvDirW), denvvalue))) // this seems right to me.
|
|
{
|
|
return (ERROR_BUFFER_OVERFLOW);
|
|
}
|
|
|
|
return(SUCCESS) ;
|
|
}
|
|
|
|
INT
|
|
SheChangeDirA(
|
|
CHAR *szNewDirA
|
|
)
|
|
{
|
|
INT iRet;
|
|
WCHAR szNewDirW[MAX_PATH];
|
|
|
|
if (szNewDirA &&
|
|
MultiByteToWideChar(CP_ACP, 0, (LPSTR)szNewDirA, -1, szNewDirW, MAX_PATH))
|
|
{
|
|
iRet = SheChangeDirW(szNewDirW);
|
|
}
|
|
else
|
|
{
|
|
iRet = FAILURE;
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
INT
|
|
SheChangeDirExW(
|
|
WCHAR *newdir)
|
|
{
|
|
WCHAR wcEnvName[MAX_PATH];
|
|
WCHAR wcNewPath[MAX_PATH];
|
|
WCHAR wcEnvValue[MAX_PATH];
|
|
|
|
DWORD cchPathOffset;
|
|
|
|
WCHAR *s;
|
|
DWORD attr;
|
|
BOOL bUsedEnv = FALSE;
|
|
|
|
if (newdir && *newdir &&
|
|
((cchPathOffset = SheGetPathOffsetW(newdir)) != 0xFFFFFFFF)) {
|
|
WCHAR wc = newdir[cchPathOffset];
|
|
|
|
newdir[cchPathOffset] = WCHAR_NULL;
|
|
if (FAILED(StringCchCopy(&wcEnvName[1],
|
|
ARRAYSIZE(wcEnvName) - 1,
|
|
newdir)))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
newdir[cchPathOffset] = wc;
|
|
newdir += cchPathOffset;
|
|
|
|
} else {
|
|
|
|
GetCurrentDirectoryW(MAX_PATH, wcEnvValue);
|
|
|
|
if (FAILED(StringCchCopy(&wcEnvName[1],
|
|
ARRAYSIZE(wcEnvName) - 1,
|
|
wcEnvValue)))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
wcEnvName[0] = WCHAR_EQUAL;
|
|
if ((cchPathOffset = SheGetPathOffsetW(&wcEnvName[1])) != 0xFFFFFFFF) {
|
|
|
|
// add one since the first character is "="
|
|
wcEnvName[cchPathOffset + 1] = WCHAR_NULL;
|
|
}
|
|
|
|
//
|
|
// If return value is 2, then we are a drive letter like A:
|
|
// We need to uppercase the drive letter here, since the environ
|
|
// vars are usually set as uppercase.
|
|
//
|
|
if (cchPathOffset == 2) {
|
|
|
|
wcEnvName[1] = (WCHAR)(DWORD_PTR)CharUpper((LPWSTR)(DWORD_PTR) wcEnvName[1]);
|
|
}
|
|
|
|
if (newdir && *newdir &&
|
|
((*newdir == WCHAR_BSLASH) || (*newdir == WCHAR_SLASH))) {
|
|
|
|
if (FAILED(StringCchCopy(wcNewPath,
|
|
ARRAYSIZE(wcNewPath),
|
|
&wcEnvName[1])))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
if (FAILED(StringCchCat(wcNewPath,
|
|
ARRAYSIZE(wcNewPath),
|
|
newdir)))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
} else {
|
|
LPWSTR lpszEnvName;
|
|
|
|
if (NULL != (lpszEnvName = SheGetEnvVarW(wcEnvName))) {
|
|
|
|
if (FAILED(StringCchCopy(wcNewPath,
|
|
ARRAYSIZE(wcNewPath),
|
|
lpszEnvName)))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
bUsedEnv = TRUE;
|
|
|
|
} else {
|
|
if (FAILED(StringCchCopy(wcNewPath,
|
|
ARRAYSIZE(wcNewPath),
|
|
&wcEnvName[1])))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
if (newdir && *newdir)
|
|
{
|
|
if (!PathAppend(wcNewPath, newdir))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!GetFullPathNameW(wcNewPath, MAX_PATH, wcEnvValue, &s)) {
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
attr = GetFileAttributesW(wcEnvValue);
|
|
|
|
if ((attr == 0xFFFFFFFF ||
|
|
((attr & FILE_ATTRIBUTE_DIRECTORY) &&
|
|
!SetCurrentDirectoryW(wcEnvValue)))
|
|
&& bUsedEnv )
|
|
{
|
|
if (FAILED(StringCchCopy(wcEnvValue, ARRAYSIZE(wcEnvValue), &wcEnvName[1])) ||
|
|
FAILED(StringCchCat(wcEnvValue, ARRAYSIZE(wcEnvValue), TEXT("\\"))))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
attr = GetFileAttributesW(wcEnvValue);
|
|
|
|
}
|
|
|
|
if (attr == 0xFFFFFFFF || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
|
|
return(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
if (!SetCurrentDirectoryW(wcEnvValue)) {
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
// It's ok if this fails
|
|
SheSetEnvVarW(wcEnvName, wcEnvValue);
|
|
|
|
// this seems right to me.
|
|
if (FAILED(StringCchCopy(CurDrvDirW, ARRAYSIZE(CurDrvDirW), wcEnvValue)))
|
|
{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
return(SUCCESS) ;
|
|
}
|
|
|
|
INT
|
|
SheChangeDirExA(
|
|
CHAR *szNewDirA
|
|
)
|
|
{
|
|
INT iRet;
|
|
WCHAR szNewDirW[MAX_PATH];
|
|
|
|
if (szNewDirA &&
|
|
MultiByteToWideChar(CP_ACP, 0, (LPSTR)szNewDirA, -1, szNewDirW, MAX_PATH))
|
|
{
|
|
iRet = SheChangeDirExW(szNewDirW);
|
|
}
|
|
else
|
|
{
|
|
iRet = FAILURE;
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
INT
|
|
SheGetCurDrive()
|
|
{
|
|
if (!CurDrvDirW[0]) {
|
|
SheGetDirW(GD_DEFAULT, CurDrvDirW) ;
|
|
}
|
|
return(CurDrvDirW[0] - WCHAR_CAP_A);
|
|
}
|
|
|
|
|
|
INT
|
|
SheSetCurDrive(
|
|
INT iDrive
|
|
)
|
|
{
|
|
WCHAR chT[MAX_PATH];
|
|
|
|
if (CurDrvDirW[0] != (WCHAR)(WCHAR_CAP_A + iDrive)) {
|
|
SheGetDirW(iDrive + 1, chT);
|
|
return(SheChangeDirW(chT));
|
|
}
|
|
return(SUCCESS);
|
|
}
|
|
|
|
INT
|
|
SheFullPathA(
|
|
CHAR *fname,
|
|
DWORD sizpath,
|
|
CHAR *buf)
|
|
{
|
|
DWORD rc = SUCCESS; /* prime with good rc */
|
|
DWORD buflen; /* buffer length */
|
|
CHAR *filepart;
|
|
|
|
if (*fname == CHAR_NULL) {
|
|
SheGetDirA(GD_DEFAULT, buf);
|
|
buf += 2; /* Inc past drivespec */
|
|
buflen = strlen(buf); /* Is curdir root only? */
|
|
if (buflen >= MAX_PATH-3) { /* If too big then stop */
|
|
rc = FAILURE;
|
|
} else if (buflen != 1) { /* if not root then append */
|
|
*(buf+buflen++) = CHAR_BSLASH; /* ...a pathchar and... */
|
|
*(buf+buflen) = CHAR_NULL ; /* ...a null CHAR... */
|
|
} /* */
|
|
} else {
|
|
if ((strlen(fname) == 2) &&
|
|
(*(fname + 1) == CHAR_COLON)
|
|
// && (!is_dbcsleadchar(*fname))
|
|
) {
|
|
SheGetDirA((CHAR)(DWORD_PTR)CharUpperA((LPSTR)(DWORD_PTR)*fname) - CHAR_CAP_A, buf); /* Get curdrvdir */
|
|
if ((buflen = strlen(buf)) > 3) {
|
|
*(buf+buflen++) = CHAR_BSLASH; /* ...a pathchar and... */
|
|
*(buf+buflen) = CHAR_NULL ; /* ...a null CHAR... */
|
|
}
|
|
} else {
|
|
if (!GetFullPathNameA( fname, sizpath, buf, &filepart )) {
|
|
rc = FAILURE;
|
|
}
|
|
}
|
|
}
|
|
return(rc);
|
|
}
|
|
|
|
INT
|
|
SheFullPathW(
|
|
WCHAR *fname,
|
|
DWORD sizpath,
|
|
WCHAR *buf)
|
|
{
|
|
DWORD rc = SUCCESS; /* prime with good rc */
|
|
DWORD buflen; /* buffer length */
|
|
WCHAR *filepart;
|
|
|
|
if (*fname == WCHAR_NULL) {
|
|
SheGetDirW(GD_DEFAULT, buf);
|
|
buf += 2; /* Inc past drivespec */
|
|
buflen = wcslen(buf); /* Is curdir root only? */
|
|
if (buflen >= MAX_PATH-3) { /* If too big then stop */
|
|
rc = FAILURE;
|
|
} else if (buflen != 1) { /* if not root then append */
|
|
*(buf+buflen++) = WCHAR_BSLASH; /* ...a pathchar and... */
|
|
*(buf+buflen) = WCHAR_NULL ; /* ...a null CHAR... */
|
|
} /* */
|
|
} else {
|
|
if ((wcslen(fname) == 2) &&
|
|
(*(fname + 1) == WCHAR_COLON)
|
|
// && (!is_dbcsleadchar(*fname))
|
|
) {
|
|
SheGetDirW((WCHAR)(DWORD_PTR)CharUpperW((LPWSTR)(DWORD_PTR)*fname) - WCHAR_CAP_A, buf); /* Get curdrvdir */
|
|
if ((buflen = wcslen(buf)) > 3) {
|
|
*(buf+buflen++) = WCHAR_BSLASH; /* ...a pathchar and... */
|
|
*(buf+buflen) = WCHAR_NULL ; /* ...a null CHAR... */
|
|
}
|
|
} else {
|
|
if (!GetFullPathNameW( fname, sizpath, buf, &filepart )) {
|
|
rc = FAILURE;
|
|
}
|
|
}
|
|
}
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SheGetDirExW(
|
|
LPWSTR lpszCurDisk,
|
|
LPDWORD lpcchCurDir,
|
|
LPWSTR lpszCurDir)
|
|
{
|
|
WCHAR wcEnvName[MAX_PATH];
|
|
LPWSTR lpszEnvValue;
|
|
INT cchPathOffset;
|
|
|
|
// if lpszCurDisk NULL, do default
|
|
if (!lpszCurDisk) {
|
|
DWORD dwRet = GetCurrentDirectoryW(*lpcchCurDir, lpszCurDir);
|
|
|
|
if (dwRet) {
|
|
*lpcchCurDir = dwRet;
|
|
return(TRUE);
|
|
} else {
|
|
return(FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
cchPathOffset = SheGetPathOffsetW(lpszCurDisk);
|
|
|
|
if (cchPathOffset != 0xFFFFFFFF) {
|
|
WCHAR wc = *(lpszCurDisk + cchPathOffset);
|
|
|
|
*(lpszCurDisk + cchPathOffset) = WCHAR_NULL;
|
|
if (FAILED(StringCchCopy(&wcEnvName[1], ARRAYSIZE(wcEnvName) - 1, lpszCurDisk)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
wcEnvName[0] = WCHAR_EQUAL;
|
|
|
|
*(lpszCurDisk + cchPathOffset) = wc;
|
|
|
|
if (NULL != (lpszEnvValue = SheGetEnvVarW(wcEnvName)))
|
|
{
|
|
if (FAILED(StringCchCopy(lpszCurDir, *lpcchCurDir, lpszEnvValue)))
|
|
{
|
|
*lpcchCurDir = lstrlen(lpszEnvValue) + 1;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (FAILED(StringCchCopy(lpszCurDir, *lpcchCurDir, lpszCurDisk)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
*(lpszCurDir + cchPathOffset) = WCHAR_BSLASH;
|
|
*(lpszCurDir + cchPathOffset + 1) = WCHAR_NULL;
|
|
|
|
return(TRUE);
|
|
|
|
} else {
|
|
|
|
// parsing error
|
|
return(FALSE);
|
|
|
|
}
|
|
}
|