509 lines
12 KiB
C++
509 lines
12 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1996 - 1996.
|
||
|
//
|
||
|
// File: cmd.cxx
|
||
|
//
|
||
|
// Contents: Command-line operations
|
||
|
//
|
||
|
// History: 7-May-96 BruceFo Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include "headers.hxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <shlobj.h>
|
||
|
#include "cmd.hxx"
|
||
|
#include "myutil.hxx"
|
||
|
|
||
|
ULONG
|
||
|
DfscmdPrintf(
|
||
|
PWCHAR format,
|
||
|
...);
|
||
|
|
||
|
//
|
||
|
// -- create intermediate directories
|
||
|
// -- don't remove if it's the last one
|
||
|
// --
|
||
|
|
||
|
// This function determines where the server and share name are in a UNC path,
|
||
|
// and sets them to the output parameters. Note that the input parameter is
|
||
|
// munged in the process. E.g.:
|
||
|
// input: \\brucefo4\root\hello
|
||
|
// output: \\brucefo4\0root\hello
|
||
|
// ^server ^share
|
||
|
//
|
||
|
// FALSE is returned if it doesn't appear to be a UNC path. TRUE is returned
|
||
|
// if everything seems ok.
|
||
|
|
||
|
BOOL
|
||
|
GetServerShare(
|
||
|
IN OUT PWSTR pszUncPath,
|
||
|
OUT PWSTR* ppszServer,
|
||
|
OUT PWSTR* ppszShare
|
||
|
)
|
||
|
{
|
||
|
appAssert(NULL != pszUncPath);
|
||
|
|
||
|
//
|
||
|
// Do a quick check that this is a UNC path
|
||
|
//
|
||
|
|
||
|
PWSTR pT;
|
||
|
|
||
|
if ( L'\\' != pszUncPath[0]
|
||
|
|| L'\\' != pszUncPath[1]
|
||
|
|| L'\\' == pszUncPath[2] || L'\0' == pszUncPath[2]
|
||
|
|| (NULL == (pT = wcschr(&pszUncPath[3], L'\\')))
|
||
|
)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*ppszServer = &pszUncPath[2];
|
||
|
*pT++ = L'\0';
|
||
|
*ppszShare = pT;
|
||
|
|
||
|
appDebugOut((DEB_TRACE,
|
||
|
"GetServerShare: Server: %ws, share: %ws\n",
|
||
|
*ppszServer, *ppszShare));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// This function determines the appropriate Dfs name to pass to the NetDfs
|
||
|
// APIs. The input buffer is modified. E.g.:
|
||
|
// input: \\dfsname\dfsshare
|
||
|
// output: \\dfsname\0dfsshare
|
||
|
// ^dfs
|
||
|
//
|
||
|
// FALSE is returned if it doesn't appear to be a dfs name. TRUE is returned
|
||
|
// if everything seems ok.
|
||
|
|
||
|
BOOL
|
||
|
GetDfs(
|
||
|
IN OUT PWSTR pszDfsName,
|
||
|
OUT PWSTR* ppszDfs
|
||
|
)
|
||
|
{
|
||
|
appAssert(NULL != pszDfsName);
|
||
|
|
||
|
//
|
||
|
// Do a quick check that this is a Dfs name
|
||
|
//
|
||
|
|
||
|
PWSTR pT;
|
||
|
|
||
|
if ( L'\\' != pszDfsName[0]
|
||
|
|| L'\\' != pszDfsName[1]
|
||
|
|| L'\\' == pszDfsName[2] || L'\0' == pszDfsName[2]
|
||
|
|| (NULL == (pT = wcschr(&pszDfsName[3], L'\\')))
|
||
|
)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*ppszDfs = &pszDfsName[2];
|
||
|
|
||
|
//
|
||
|
// Go to next slash or end
|
||
|
//
|
||
|
pT++;
|
||
|
while (*pT != L'\\' && *pT != L'\0')
|
||
|
pT++;
|
||
|
|
||
|
*pT = L'\0';
|
||
|
|
||
|
appDebugOut((DEB_TRACE,
|
||
|
"GetDfs: Dfs: %ws\n",
|
||
|
*ppszDfs));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
CmdMap(
|
||
|
IN PWSTR pszDfsPath,
|
||
|
IN PWSTR pszUncPath,
|
||
|
IN PWSTR pszComment,
|
||
|
IN BOOLEAN fRestore
|
||
|
)
|
||
|
{
|
||
|
appDebugOut((DEB_TRACE,"CmdMap(%ws, %ws, %ws)\n",
|
||
|
pszDfsPath, pszUncPath, pszComment));
|
||
|
|
||
|
PWSTR pszServer, pszShare;
|
||
|
if (!GetServerShare(pszUncPath, &pszServer, &pszShare))
|
||
|
{
|
||
|
Usage();
|
||
|
}
|
||
|
|
||
|
|
||
|
NET_API_STATUS status = NetDfsAdd(
|
||
|
pszDfsPath,
|
||
|
pszServer,
|
||
|
pszShare,
|
||
|
pszComment,
|
||
|
(fRestore == FALSE) ?
|
||
|
DFS_ADD_VOLUME : DFS_ADD_VOLUME | DFS_RESTORE_VOLUME);
|
||
|
if (status == NERR_Success)
|
||
|
{
|
||
|
// Notify shell of change.
|
||
|
|
||
|
appDebugOut((DEB_TRACE,
|
||
|
"Notify shell about new path %ws\n",
|
||
|
pszDfsPath));
|
||
|
|
||
|
SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, pszDfsPath, NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DfsErrorMessage(status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CmdUnmap(
|
||
|
IN PWSTR pszDfsPath
|
||
|
)
|
||
|
{
|
||
|
appDebugOut((DEB_TRACE,"CmdUnmap(%ws)\n",
|
||
|
pszDfsPath));
|
||
|
|
||
|
//
|
||
|
// Delete all the replicas, and hence the volume
|
||
|
//
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
PDFS_INFO_3 pVolumeInfo = NULL;
|
||
|
NET_API_STATUS status = NetDfsGetInfo(
|
||
|
pszDfsPath,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
3,
|
||
|
(LPBYTE*)&pVolumeInfo);
|
||
|
CHECK_NET_API_STATUS(status);
|
||
|
if (NERR_Success == status)
|
||
|
{
|
||
|
// now, we have pVolumeInfo memory to delete
|
||
|
|
||
|
for (ULONG i = 0; i < pVolumeInfo->NumberOfStorages; i++)
|
||
|
{
|
||
|
appDebugOut((DEB_TRACE,
|
||
|
"Deleting replica %d of %d\n",
|
||
|
i + 1, pVolumeInfo->NumberOfStorages));
|
||
|
|
||
|
PDFS_STORAGE_INFO pDfsStorageInfo = &pVolumeInfo->Storage[i];
|
||
|
|
||
|
status = NetDfsRemove(
|
||
|
pszDfsPath,
|
||
|
pDfsStorageInfo->ServerName,
|
||
|
pDfsStorageInfo->ShareName);
|
||
|
if (status != NERR_Success)
|
||
|
{
|
||
|
DfsErrorMessage(status);
|
||
|
}
|
||
|
}
|
||
|
NetApiBufferFree(pVolumeInfo);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DfsErrorMessage(status);
|
||
|
}
|
||
|
|
||
|
// Notify shell of change.
|
||
|
|
||
|
appDebugOut((DEB_TRACE,
|
||
|
"Notify shell about deleted path %ws\n",
|
||
|
pszDfsPath));
|
||
|
|
||
|
SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, pszDfsPath, NULL);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CmdAdd(
|
||
|
IN PWSTR pszDfsPath,
|
||
|
IN PWSTR pszUncPath,
|
||
|
IN BOOLEAN fRestore
|
||
|
)
|
||
|
{
|
||
|
appDebugOut((DEB_TRACE,"CmdAdd(%ws, %ws)\n",
|
||
|
pszDfsPath, pszUncPath));
|
||
|
|
||
|
PWSTR pszServer, pszShare;
|
||
|
if (!GetServerShare(pszUncPath, &pszServer, &pszShare))
|
||
|
{
|
||
|
Usage();
|
||
|
}
|
||
|
|
||
|
NET_API_STATUS status = NetDfsAdd(
|
||
|
pszDfsPath,
|
||
|
pszServer,
|
||
|
pszShare,
|
||
|
NULL,
|
||
|
(fRestore == FALSE) ? 0 : DFS_RESTORE_VOLUME);
|
||
|
if (status != NERR_Success)
|
||
|
{
|
||
|
DfsErrorMessage(status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CmdRemove(
|
||
|
IN PWSTR pszDfsPath,
|
||
|
IN PWSTR pszUncPath
|
||
|
)
|
||
|
{
|
||
|
appDebugOut((DEB_TRACE,"CmdRemove(%ws, %ws)\n",
|
||
|
pszDfsPath, pszUncPath));
|
||
|
|
||
|
PWSTR pszServer, pszShare;
|
||
|
if (!GetServerShare(pszUncPath, &pszServer, &pszShare))
|
||
|
{
|
||
|
Usage();
|
||
|
}
|
||
|
|
||
|
NET_API_STATUS status = NetDfsRemove(
|
||
|
pszDfsPath,
|
||
|
pszServer,
|
||
|
pszShare);
|
||
|
if (status != NERR_Success)
|
||
|
{
|
||
|
DfsErrorMessage(status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CmdView(
|
||
|
IN PWSTR pszDfsName, // of form \\dfsname\dfsshare
|
||
|
IN DWORD level,
|
||
|
IN BOOLEAN fBatch,
|
||
|
IN BOOLEAN fRestore
|
||
|
)
|
||
|
{
|
||
|
appDebugOut((DEB_TRACE,"CmdView(%ws, %d)\n",
|
||
|
pszDfsName, level));
|
||
|
|
||
|
PWSTR pszDfs; // of form 'dfsname'
|
||
|
if (!GetDfs(pszDfsName, &pszDfs))
|
||
|
{
|
||
|
Usage();
|
||
|
}
|
||
|
|
||
|
DWORD entriesread;
|
||
|
LPBYTE buffer;
|
||
|
DWORD resumeHandle = 0;
|
||
|
NET_API_STATUS status = NetDfsEnum(
|
||
|
pszDfs,
|
||
|
level,
|
||
|
0xffffffff,
|
||
|
(LPBYTE*)&buffer,
|
||
|
&entriesread,
|
||
|
&resumeHandle);
|
||
|
if (status == NERR_Success)
|
||
|
{
|
||
|
PDFS_INFO_3 pDfsInfo = (PDFS_INFO_3)buffer;
|
||
|
DWORD i, j;
|
||
|
LPDFS_STORAGE_INFO pStorage;
|
||
|
|
||
|
#if DBG == 1
|
||
|
appDebugOut((DEB_TRACE,"NetDfsEnum returned %d entries\n", entriesread));
|
||
|
for (i = 0; i < entriesread; i++)
|
||
|
{
|
||
|
if (level == 1)
|
||
|
{
|
||
|
pDfsInfo = (PDFS_INFO_3)(&(((PDFS_INFO_1)buffer)[i]));
|
||
|
}
|
||
|
else if (level == 2)
|
||
|
{
|
||
|
pDfsInfo = (PDFS_INFO_3)(&(((PDFS_INFO_2)buffer)[i]));
|
||
|
}
|
||
|
else if (level == 3)
|
||
|
{
|
||
|
pDfsInfo = &(((PDFS_INFO_3)buffer)[i]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// bug!
|
||
|
break;
|
||
|
}
|
||
|
appDebugOut((DEB_TRACE,"\t%ws\n", pDfsInfo->EntryPath));
|
||
|
}
|
||
|
pDfsInfo = (PDFS_INFO_3)buffer;
|
||
|
#endif // DBG == 1
|
||
|
|
||
|
if (fBatch == FALSE)
|
||
|
{
|
||
|
for (i = 0; i < entriesread; i++)
|
||
|
{
|
||
|
DfscmdPrintf(L"%ws", pDfsInfo->EntryPath);
|
||
|
|
||
|
if (level == 1)
|
||
|
{
|
||
|
DfscmdPrintf(L"\r\n");
|
||
|
pDfsInfo = (LPDFS_INFO_3)
|
||
|
((LPBYTE) pDfsInfo + sizeof(DFS_INFO_1));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (L'\0' != *pDfsInfo->Comment)
|
||
|
{
|
||
|
// Print the comment at column 60.
|
||
|
int len = wcslen(pDfsInfo->EntryPath);
|
||
|
while (len++ < 58)
|
||
|
{
|
||
|
DfscmdPrintf(L" "); // putchar?
|
||
|
}
|
||
|
|
||
|
DfscmdPrintf(L" %ws\r\n", pDfsInfo->Comment);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DfscmdPrintf(L"\r\n");
|
||
|
}
|
||
|
|
||
|
if (level == 2)
|
||
|
{
|
||
|
pDfsInfo = (LPDFS_INFO_3)
|
||
|
((LPBYTE) pDfsInfo + sizeof(DFS_INFO_2));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
pStorage = pDfsInfo->Storage;
|
||
|
|
||
|
for (j = 0; j < pDfsInfo->NumberOfStorages; j++)
|
||
|
{
|
||
|
DfscmdPrintf(L"\t\\\\%ws\\%ws\r\n",
|
||
|
pStorage[j].ServerName,
|
||
|
pStorage[j].ShareName);
|
||
|
}
|
||
|
|
||
|
pDfsInfo = (LPDFS_INFO_3)
|
||
|
((LPBYTE) pDfsInfo + sizeof(DFS_INFO_3));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DfscmdPrintf(L"REM BATCH RESTORE SCRIPT\r\n\r\n");
|
||
|
for (i = 0; i < entriesread; i++)
|
||
|
{
|
||
|
pStorage = pDfsInfo->Storage;
|
||
|
|
||
|
for (j = 0; j < pDfsInfo->NumberOfStorages; j++)
|
||
|
{
|
||
|
|
||
|
if (pDfsInfo->Comment == NULL
|
||
|
||
|
||
|
j > 0
|
||
|
||
|
||
|
(wcslen(pDfsInfo->Comment) == 1 && pDfsInfo->Comment[0] == L' ')
|
||
|
) {
|
||
|
|
||
|
DfscmdPrintf(L"%wsdfscmd /%ws \"%ws\" \"\\\\%ws\\%ws\"%ws\r\n",
|
||
|
(i == 0) ? L"REM " : L"",
|
||
|
(j == 0) ? L"map" : L"add",
|
||
|
pDfsInfo->EntryPath,
|
||
|
pStorage[j].ServerName,
|
||
|
pStorage[j].ShareName,
|
||
|
(fRestore == TRUE) ? L" /restore" : L"");
|
||
|
|
||
|
} else {
|
||
|
|
||
|
DfscmdPrintf(L"%wsdfscmd /%ws \"%ws\" \"\\\\%ws\\%ws\" \"%ws\"%ws\r\n",
|
||
|
(i == 0) ? L"REM " : L"",
|
||
|
(j == 0) ? L"map" : L"add",
|
||
|
pDfsInfo->EntryPath,
|
||
|
pStorage[j].ServerName,
|
||
|
pStorage[j].ShareName,
|
||
|
pDfsInfo->Comment,
|
||
|
(fRestore == TRUE) ? L" /restore" : L"");
|
||
|
|
||
|
}
|
||
|
}
|
||
|
DfscmdPrintf(L"\r\n");
|
||
|
pDfsInfo = (LPDFS_INFO_3) ((LPBYTE) pDfsInfo + sizeof(DFS_INFO_3));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NetApiBufferFree( buffer );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DfsErrorMessage(status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// The following is copied from dfsutil code, which allows redirection of
|
||
|
// output to a file.
|
||
|
//
|
||
|
|
||
|
#define MAX_MESSAGE_BUF 4096
|
||
|
#define MAX_ANSI_MESSAGE_BUF (MAX_MESSAGE_BUF * 3)
|
||
|
|
||
|
WCHAR MsgBuf[MAX_MESSAGE_BUF];
|
||
|
CHAR AnsiBuf[MAX_ANSI_MESSAGE_BUF];
|
||
|
|
||
|
ULONG
|
||
|
DfscmdPrintf(
|
||
|
PWCHAR format,
|
||
|
...)
|
||
|
{
|
||
|
DWORD written;
|
||
|
va_list va;
|
||
|
|
||
|
va_start(va, format);
|
||
|
wvsprintf(MsgBuf, format, va);
|
||
|
written = WideCharToMultiByte(CP_OEMCP, 0,
|
||
|
MsgBuf, wcslen(MsgBuf),
|
||
|
AnsiBuf, MAX_ANSI_MESSAGE_BUF,
|
||
|
NULL, NULL);
|
||
|
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), AnsiBuf, written, &written, NULL);
|
||
|
|
||
|
va_end(va);
|
||
|
return written;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef MOVERENAME
|
||
|
|
||
|
VOID
|
||
|
CmdMove(
|
||
|
IN PWSTR pszDfsPath1,
|
||
|
IN PWSTR pszDfsPath2
|
||
|
)
|
||
|
{
|
||
|
appDebugOut((DEB_TRACE,"CmdMove(%ws, %ws)\n",
|
||
|
pszDfsPath1, pszDfsPath2));
|
||
|
|
||
|
NET_API_STATUS status = NetDfsMove(
|
||
|
pszDfsPath1,
|
||
|
pszDfsPath2);
|
||
|
if (status != NERR_Success)
|
||
|
{
|
||
|
DfsErrorMessage(status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CmdRename(
|
||
|
IN PWSTR pszPath,
|
||
|
IN PWSTR pszNewPath
|
||
|
)
|
||
|
{
|
||
|
appDebugOut((DEB_TRACE,"CmdRename(%ws, %ws)\n",
|
||
|
pszPath, pszNewPath));
|
||
|
|
||
|
NET_API_STATUS status = NetDfsRename(
|
||
|
pszPath,
|
||
|
pszNewPath);
|
||
|
if (status != NERR_Success)
|
||
|
{
|
||
|
DfsErrorMessage(status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|