fresh git tree for public release
we regretfully had to remove our git history for licensing reasons Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
commit
0ad4db4fad
271 changed files with 71255 additions and 0 deletions
106
mount/enum.c
Normal file
106
mount/enum.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/* Copyright (c) 2010
|
||||
* The Regents of the University of Michigan
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Permission is granted to use, copy and redistribute this software
|
||||
* for noncommercial education and research purposes, so long as no
|
||||
* fee is charged, and so long as the name of the University of Michigan
|
||||
* is not used in any advertising or publicity pertaining to the use
|
||||
* or distribution of this software without specific, written prior
|
||||
* authorization. Permission to modify or otherwise create derivative
|
||||
* works of this software is not granted.
|
||||
*
|
||||
* This software is provided as is, without representation or warranty
|
||||
* of any kind either express or implied, including without limitation
|
||||
* the implied warranties of merchantability, fitness for a particular
|
||||
* purpose, or noninfringement. The Regents of the University of
|
||||
* Michigan shall not be liable for any damages, including special,
|
||||
* indirect, incidental, or consequential damages, with respect to any
|
||||
* claim arising out of or in connection with the use of the software,
|
||||
* even if it has been or is hereafter advised of the possibility of
|
||||
* such damages.
|
||||
*/
|
||||
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nfs41_driver.h" /* NFS41_PROVIDER_NAME_A */
|
||||
|
||||
|
||||
void PrintErrorMessage(
|
||||
IN DWORD dwError);
|
||||
|
||||
static __inline
|
||||
void PrintMountLine(
|
||||
LPCTSTR local,
|
||||
LPCTSTR remote)
|
||||
{
|
||||
_tprintf(TEXT("%-11s %s\n"), local, remote);
|
||||
}
|
||||
|
||||
/* ENUM_RESOURCE_BUFFER_SIZE
|
||||
* from msdn re: WNetEnumResource
|
||||
* "An application cannot set the lpBuffer parameter to NULL and
|
||||
* retrieve the required buffer size from the lpBufferSize parameter.
|
||||
* Instead, the application should allocate a buffer of a reasonable
|
||||
* size—16 kilobytes is typical—and use the value of lpBufferSize for
|
||||
* error detection." */
|
||||
#define ENUM_RESOURCE_BUFFER_SIZE (16*1024)
|
||||
|
||||
DWORD EnumMounts(
|
||||
IN LPNETRESOURCE pContainer)
|
||||
{
|
||||
DWORD result = NO_ERROR;
|
||||
LPNETRESOURCE pResources;
|
||||
DWORD i, dwCount, dwTotal = 0;
|
||||
DWORD dwBufferSize = ENUM_RESOURCE_BUFFER_SIZE;
|
||||
HANDLE hEnum;
|
||||
|
||||
pResources = (LPNETRESOURCE)GlobalAlloc(0, ENUM_RESOURCE_BUFFER_SIZE);
|
||||
if (pResources == NULL) {
|
||||
result = WN_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = WNetOpenEnum(RESOURCE_CONNECTED,
|
||||
RESOURCETYPE_DISK, 0, pContainer, &hEnum);
|
||||
if (result)
|
||||
goto out_free;
|
||||
|
||||
_tprintf(TEXT("Listing %s mounts:\n\n"), TEXT(NFS41_PROVIDER_NAME_A));
|
||||
PrintMountLine(TEXT("Volume"), TEXT("Remote path"));
|
||||
do
|
||||
{
|
||||
dwCount = (DWORD)-1;
|
||||
result = WNetEnumResource(hEnum,
|
||||
&dwCount, pResources, &dwBufferSize);
|
||||
|
||||
if (result == NO_ERROR)
|
||||
{
|
||||
for (i = 0; i < dwCount; i++)
|
||||
{
|
||||
if (_tcscmp(pResources[i].lpProvider,
|
||||
TEXT(NFS41_PROVIDER_NAME_A)) == 0)
|
||||
{
|
||||
PrintMountLine(pResources[i].lpLocalName,
|
||||
pResources[i].lpRemoteName);
|
||||
dwTotal++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (result != WN_NO_MORE_ENTRIES)
|
||||
break;
|
||||
}
|
||||
while (result != WN_NO_MORE_ENTRIES);
|
||||
|
||||
result = WNetCloseEnum(hEnum);
|
||||
|
||||
_tprintf(TEXT("\nFound %d share%s.\n"), dwTotal,
|
||||
dwTotal == 1 ? TEXT("") : TEXT("s"));
|
||||
|
||||
out_free:
|
||||
GlobalFree((HGLOBAL)pResources);
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
369
mount/mount.c
Normal file
369
mount/mount.c
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
/* Copyright (c) 2010
|
||||
* The Regents of the University of Michigan
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Permission is granted to use, copy and redistribute this software
|
||||
* for noncommercial education and research purposes, so long as no
|
||||
* fee is charged, and so long as the name of the University of Michigan
|
||||
* is not used in any advertising or publicity pertaining to the use
|
||||
* or distribution of this software without specific, written prior
|
||||
* authorization. Permission to modify or otherwise create derivative
|
||||
* works of this software is not granted.
|
||||
*
|
||||
* This software is provided as is, without representation or warranty
|
||||
* of any kind either express or implied, including without limitation
|
||||
* the implied warranties of merchantability, fitness for a particular
|
||||
* purpose, or noninfringement. The Regents of the University of
|
||||
* Michigan shall not be liable for any damages, including special,
|
||||
* indirect, incidental, or consequential damages, with respect to any
|
||||
* claim arising out of or in connection with the use of the software,
|
||||
* even if it has been or is hereafter advised of the possibility of
|
||||
* such damages.
|
||||
*/
|
||||
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
#include <strsafe.h>
|
||||
#include <Winnetwk.h> /* for WNet*Connection */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nfs41_driver.h" /* NFS41_PROVIDER_NAME_A */
|
||||
#include "options.h"
|
||||
|
||||
|
||||
DWORD EnumMounts(
|
||||
IN LPNETRESOURCE pContainer);
|
||||
|
||||
static DWORD DoMount(
|
||||
IN LPTSTR pLocalName,
|
||||
IN LPTSTR pRemoteName,
|
||||
IN PMOUNT_OPTION_LIST pOptions);
|
||||
static DWORD DoUnmount(
|
||||
IN LPTSTR pLocalName,
|
||||
IN BOOL bForce);
|
||||
|
||||
static void RecursivePrintEaInformation(
|
||||
IN PFILE_FULL_EA_INFORMATION EA);
|
||||
static BOOL ParseDriveLetter(
|
||||
IN LPTSTR pArg,
|
||||
OUT PTCH pDriveLetter);
|
||||
void PrintErrorMessage(
|
||||
IN DWORD dwError);
|
||||
|
||||
static VOID PrintUsage(LPTSTR pProcess)
|
||||
{
|
||||
_tprintf(TEXT("Usage: %s [options] <drive letter|*> <hostname>:<path>\n")
|
||||
TEXT("Options:\n")
|
||||
TEXT("\t-h\thelp\n")
|
||||
TEXT("\t-d\tunmount\n")
|
||||
TEXT("\t-f\tforce unmount if the drive is in use\n")
|
||||
TEXT("\t-o <comma-separated mount options>\n")
|
||||
TEXT("Mount options:\n")
|
||||
TEXT("\tro\tmount as read-only\n")
|
||||
TEXT("\trsize=#\tread buffer size in bytes\n")
|
||||
TEXT("\twsize=#\twrite buffer size in bytes\n"),
|
||||
pProcess, pProcess, pProcess);
|
||||
}
|
||||
|
||||
DWORD __cdecl _tmain(DWORD argc, LPTSTR argv[])
|
||||
{
|
||||
DWORD i, result = NO_ERROR;
|
||||
TCHAR szLocalName[] = TEXT("C:\0");
|
||||
LPTSTR pLocalName = NULL;
|
||||
LPTSTR pRemoteName = NULL;
|
||||
BOOL bUnmount = FALSE;
|
||||
BOOL bForceUnmount = FALSE;
|
||||
MOUNT_OPTION_LIST Options;
|
||||
|
||||
if (argc == 1) {
|
||||
/* list open nfs shares */
|
||||
result = EnumMounts(NULL);
|
||||
if (result)
|
||||
PrintErrorMessage(GetLastError());
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = InitializeMountOptions(&Options, MAX_OPTION_BUFFER_SIZE);
|
||||
if (result) {
|
||||
PrintErrorMessage(GetLastError());
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* parse command line */
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (argv[i][0] == TEXT('-'))
|
||||
{
|
||||
if (_tcscmp(argv[i], TEXT("-h")) == 0) /* help */
|
||||
{
|
||||
PrintUsage(argv[0]);
|
||||
goto out;
|
||||
}
|
||||
else if (_tcscmp(argv[i], TEXT("-d")) == 0) /* unmount */
|
||||
{
|
||||
bUnmount = TRUE;
|
||||
}
|
||||
else if (_tcscmp(argv[i], TEXT("-f")) == 0) /* force unmount */
|
||||
{
|
||||
bForceUnmount = TRUE;
|
||||
}
|
||||
else if (_tcscmp(argv[i], TEXT("-o")) == 0) /* mount option */
|
||||
{
|
||||
++i;
|
||||
if (i >= argc)
|
||||
{
|
||||
result = ERROR_BAD_ARGUMENTS;
|
||||
_ftprintf(stderr, TEXT("Mount options missing ")
|
||||
TEXT("after '-o'.\n\n"));
|
||||
PrintUsage(argv[0]);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (!ParseMountOptions(argv[i], &Options))
|
||||
{
|
||||
result = ERROR_BAD_ARGUMENTS;
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
else
|
||||
_ftprintf(stderr, TEXT("Unrecognized option ")
|
||||
TEXT("'%s', disregarding.\n"), argv[i]);
|
||||
}
|
||||
else if (pLocalName == NULL) /* drive letter */
|
||||
{
|
||||
pLocalName = argv[i];
|
||||
}
|
||||
else if (pRemoteName == NULL) /* remote path */
|
||||
{
|
||||
pRemoteName = argv[i];
|
||||
}
|
||||
else
|
||||
_ftprintf(stderr, TEXT("Unrecognized argument ")
|
||||
TEXT("'%s', disregarding.\n"), argv[i]);
|
||||
}
|
||||
|
||||
/* validate local drive letter */
|
||||
if (pLocalName == NULL)
|
||||
{
|
||||
result = ERROR_BAD_ARGUMENTS;
|
||||
_ftprintf(stderr, TEXT("Missing argument for drive letter.\n\n"));
|
||||
PrintUsage(argv[0]);
|
||||
goto out_free;
|
||||
}
|
||||
if (FALSE == ParseDriveLetter(pLocalName, szLocalName))
|
||||
{
|
||||
result = ERROR_BAD_ARGUMENTS;
|
||||
_ftprintf(stderr, TEXT("Invalid drive letter '%s'. ")
|
||||
TEXT("Expected 'C' or 'C:'.\n\n"), pLocalName);
|
||||
PrintUsage(argv[0]);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (bUnmount == TRUE) /* unmount */
|
||||
{
|
||||
result = DoUnmount(szLocalName, bForceUnmount);
|
||||
if (result)
|
||||
PrintErrorMessage(result);
|
||||
}
|
||||
else /* mount */
|
||||
{
|
||||
if (pRemoteName == NULL)
|
||||
{
|
||||
result = ERROR_BAD_NET_NAME;
|
||||
_ftprintf(stderr, TEXT("Missing argument for remote path.\n\n"));
|
||||
PrintUsage(argv[0]);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
result = DoMount(szLocalName, pRemoteName, &Options);
|
||||
if (result)
|
||||
PrintErrorMessage(result);
|
||||
}
|
||||
|
||||
out_free:
|
||||
FreeMountOptions(&Options);
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ConvertUnixSlashes(
|
||||
IN OUT LPTSTR pRemoteName)
|
||||
{
|
||||
LPTSTR pos = pRemoteName;
|
||||
for (pos = pRemoteName; *pos; pos++)
|
||||
if (*pos == TEXT('/'))
|
||||
*pos = TEXT('\\');
|
||||
}
|
||||
|
||||
static LPTSTR FindEndOfServer(
|
||||
IN LPTSTR pRemoteName)
|
||||
{
|
||||
LPTSTR pos = pRemoteName;
|
||||
while (*pos && *pos != TEXT(':'))
|
||||
pos++;
|
||||
return pos;
|
||||
}
|
||||
|
||||
static DWORD ParseRemoteName(
|
||||
IN LPTSTR pRemoteName,
|
||||
IN OUT PMOUNT_OPTION_LIST pOptions,
|
||||
OUT LPTSTR pConnectionName,
|
||||
IN size_t cchConnectionLen)
|
||||
{
|
||||
DWORD result = NO_ERROR;
|
||||
LPTSTR pEnd;
|
||||
|
||||
ConvertUnixSlashes(pRemoteName);
|
||||
pEnd = FindEndOfServer(pRemoteName);
|
||||
|
||||
/* fail if the server name doesn't end with :\ */
|
||||
if (*pEnd == 0 || pEnd[0] != TEXT(':') || pEnd[1] != TEXT('\\')) {
|
||||
_ftprintf(stderr, TEXT("Failed to parse the remote path. ")
|
||||
TEXT("Expected 'hostname:\\path'.\n"));
|
||||
result = ERROR_BAD_ARGUMENTS;
|
||||
goto out;
|
||||
}
|
||||
*pEnd = TEXT('\0');
|
||||
++pEnd;
|
||||
|
||||
if (!InsertOption(TEXT("srvname"), pRemoteName, pOptions) ||
|
||||
!InsertOption(TEXT("mntpt"), *pEnd ? pEnd : TEXT("\\"), pOptions)) {
|
||||
result = ERROR_BAD_ARGUMENTS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = StringCchCopy(pConnectionName, cchConnectionLen, TEXT("\\\\"));
|
||||
if (FAILED(result))
|
||||
goto out;
|
||||
result = StringCbCat(pConnectionName, cchConnectionLen, pRemoteName);
|
||||
if (FAILED(result))
|
||||
goto out;
|
||||
if (*pEnd)
|
||||
result = StringCchCat(pConnectionName, cchConnectionLen, pEnd);
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static DWORD DoMount(
|
||||
IN LPTSTR pLocalName,
|
||||
IN LPTSTR pRemoteName,
|
||||
IN PMOUNT_OPTION_LIST pOptions)
|
||||
{
|
||||
DWORD result = NO_ERROR;
|
||||
TCHAR szExisting[MAX_PATH];
|
||||
TCHAR szRemoteName[MAX_PATH];
|
||||
DWORD dwLength;
|
||||
|
||||
*szRemoteName = TEXT('\0');
|
||||
result = ParseRemoteName(pRemoteName, pOptions, szRemoteName, MAX_PATH);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
/* fail if the connection already exists */
|
||||
result = WNetGetConnection(pLocalName, (LPTSTR)szExisting, &dwLength);
|
||||
if (result == NO_ERROR)
|
||||
{
|
||||
result = ERROR_ALREADY_ASSIGNED;
|
||||
_ftprintf(stderr, TEXT("Mount failed, drive %s is ")
|
||||
TEXT("already assigned to '%s'.\n"),
|
||||
pLocalName, szExisting);
|
||||
}
|
||||
else
|
||||
{
|
||||
NETRESOURCE NetResource;
|
||||
TCHAR szConnection[MAX_PATH];
|
||||
DWORD ConnectSize = MAX_PATH, ConnectResult;
|
||||
|
||||
ZeroMemory(&NetResource, sizeof(NETRESOURCE));
|
||||
NetResource.dwType = RESOURCETYPE_DISK;
|
||||
/* drive letter is chosen automatically if lpLocalName == NULL */
|
||||
NetResource.lpLocalName = *pLocalName == TEXT('*') ? NULL : pLocalName;
|
||||
NetResource.lpRemoteName = szRemoteName;
|
||||
/* ignore other network providers */
|
||||
NetResource.lpProvider = TEXT(NFS41_PROVIDER_NAME_A);
|
||||
/* pass mount options via lpComment */
|
||||
if (pOptions->Buffer->Length)
|
||||
{
|
||||
if (pOptions->Current)
|
||||
pOptions->Current->NextEntryOffset = 0;
|
||||
NetResource.lpComment = (LPTSTR)pOptions->Buffer;
|
||||
}
|
||||
|
||||
result = WNetUseConnection(NULL,
|
||||
&NetResource, NULL, NULL, 0,
|
||||
szConnection, &ConnectSize, &ConnectResult);
|
||||
|
||||
if (result == NO_ERROR)
|
||||
_tprintf(TEXT("Successfully mounted %s to drive %s\n"),
|
||||
pRemoteName, szConnection);
|
||||
else
|
||||
_ftprintf(stderr, TEXT("WNetUseConnection(%s, %s) ")
|
||||
TEXT("failed with error code %u.\n"),
|
||||
pLocalName, szRemoteName, result);
|
||||
}
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static DWORD DoUnmount(
|
||||
IN LPTSTR pLocalName,
|
||||
IN BOOL bForce)
|
||||
{
|
||||
DWORD result;
|
||||
|
||||
/* disconnect the specified local drive */
|
||||
result = WNetCancelConnection2(pLocalName, 0, bForce);
|
||||
/* TODO: verify that this connection uses the nfs41 provider -cbodley */
|
||||
switch (result)
|
||||
{
|
||||
case NO_ERROR:
|
||||
_tprintf(TEXT("Drive %s unmounted successfully.\n"), pLocalName);
|
||||
break;
|
||||
case ERROR_NOT_CONNECTED:
|
||||
_ftprintf(stderr, TEXT("Drive %s is not currently ")
|
||||
TEXT("connected.\n"), pLocalName);
|
||||
break;
|
||||
default:
|
||||
_ftprintf(stderr, TEXT("WNetCancelConnection2(%s) failed ")
|
||||
TEXT("with error code %u.\n"), pLocalName, result);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL ParseDriveLetter(
|
||||
IN LPTSTR pArg,
|
||||
OUT PTCH pDriveLetter)
|
||||
{
|
||||
/* accept 'C' or 'C:' */
|
||||
switch (_tcslen(pArg))
|
||||
{
|
||||
case 2:
|
||||
if (pArg[1] != TEXT(':'))
|
||||
return FALSE;
|
||||
/* break intentionally missing */
|
||||
case 1:
|
||||
if (_istlower(*pArg))
|
||||
*pArg = (TCHAR)_totupper(*pArg);
|
||||
else if (!_istupper(*pArg) && *pArg != TEXT('*'))
|
||||
return FALSE;
|
||||
|
||||
*pDriveLetter = *pArg;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void PrintErrorMessage(
|
||||
IN DWORD dwError)
|
||||
{
|
||||
LPTSTR lpMsgBuf = NULL;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf, 0, NULL);
|
||||
_fputts(lpMsgBuf, stderr);
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
230
mount/options.c
Normal file
230
mount/options.c
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/* Copyright (c) 2010
|
||||
* The Regents of the University of Michigan
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Permission is granted to use, copy and redistribute this software
|
||||
* for noncommercial education and research purposes, so long as no
|
||||
* fee is charged, and so long as the name of the University of Michigan
|
||||
* is not used in any advertising or publicity pertaining to the use
|
||||
* or distribution of this software without specific, written prior
|
||||
* authorization. Permission to modify or otherwise create derivative
|
||||
* works of this software is not granted.
|
||||
*
|
||||
* This software is provided as is, without representation or warranty
|
||||
* of any kind either express or implied, including without limitation
|
||||
* the implied warranties of merchantability, fitness for a particular
|
||||
* purpose, or noninfringement. The Regents of the University of
|
||||
* Michigan shall not be liable for any damages, including special,
|
||||
* indirect, incidental, or consequential damages, with respect to any
|
||||
* claim arising out of or in connection with the use of the software,
|
||||
* even if it has been or is hereafter advised of the possibility of
|
||||
* such damages.
|
||||
*/
|
||||
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
#include <strsafe.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "options.h"
|
||||
|
||||
|
||||
DWORD InitializeMountOptions(
|
||||
IN OUT PMOUNT_OPTION_LIST Options,
|
||||
IN ULONG BufferSize)
|
||||
{
|
||||
Options->Current = NULL;
|
||||
Options->Remaining = BufferSize;
|
||||
Options->Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize);
|
||||
if (Options->Buffer == NULL)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Options->Buffer->Secret = MOUNT_OPTION_BUFFER_SECRET;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void FreeMountOptions(
|
||||
IN OUT PMOUNT_OPTION_LIST Options)
|
||||
{
|
||||
Options->Current = NULL;
|
||||
Options->Remaining = 0;
|
||||
if (Options->Buffer)
|
||||
{
|
||||
LocalFree(Options->Buffer);
|
||||
Options->Buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL FindOptionByName(
|
||||
IN LPCTSTR Name,
|
||||
IN PMOUNT_OPTION_LIST Options,
|
||||
OUT PFILE_FULL_EA_INFORMATION* ppOption)
|
||||
{
|
||||
PFILE_FULL_EA_INFORMATION Current =
|
||||
(PFILE_FULL_EA_INFORMATION)Options->Buffer->Buffer;
|
||||
ULONG NameLength = (ULONG)_tcslen(Name) * sizeof(TCHAR);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (Current->EaNameLength == NameLength &&
|
||||
_tcscmp((LPTSTR)Current->EaName, Name) == 0)
|
||||
{
|
||||
*ppOption = Current;
|
||||
return TRUE;
|
||||
}
|
||||
if (Current->NextEntryOffset == 0)
|
||||
break;
|
||||
Current = (PFILE_FULL_EA_INFORMATION)
|
||||
((PBYTE)Current + Current->NextEntryOffset);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static FORCEINLINE ULONG EaBufferSize(
|
||||
IN UCHAR NameSize,
|
||||
IN USHORT ValueSize)
|
||||
{
|
||||
ULONG Size = sizeof(ULONG) + 2 * sizeof(UCHAR) + sizeof(USHORT)
|
||||
+ NameSize + ValueSize + sizeof(TCHAR);
|
||||
/* extended attributes require ULONG alignment;
|
||||
* see documentation for IoCheckEaBufferValidity() */
|
||||
return ( (Size + 3) / sizeof(ULONG) ) * sizeof(ULONG);
|
||||
}
|
||||
|
||||
static FORCEINLINE ULONG EaBufferNextOffset(
|
||||
IN PFILE_FULL_EA_INFORMATION EaBuffer)
|
||||
{
|
||||
return EaBufferSize(
|
||||
EaBuffer->EaNameLength,
|
||||
EaBuffer->EaValueLength);
|
||||
}
|
||||
|
||||
BOOL InsertOption(
|
||||
IN LPCTSTR Name,
|
||||
IN LPCTSTR Value,
|
||||
IN OUT PMOUNT_OPTION_LIST Options)
|
||||
{
|
||||
PFILE_FULL_EA_INFORMATION Current;
|
||||
UCHAR NameLen = (UCHAR)_tcslen(Name) * sizeof(TCHAR);
|
||||
USHORT ValueLen = (USHORT)_tcslen(Value) * sizeof(TCHAR);
|
||||
ULONG SpaceRequired = EaBufferSize(NameLen, ValueLen);
|
||||
|
||||
/* don't allow duplicate options */
|
||||
if (FindOptionByName(Name, Options, &Current)) {
|
||||
_ftprintf(stderr, TEXT("Found a duplicate option ")
|
||||
TEXT("'%s%s%s' while parsing '%s%s%s'.\n"),
|
||||
(PTCH)Current->EaName,
|
||||
Current->EaValueLength ? TEXT("=") : TEXT(""),
|
||||
(PTCH)(Current->EaName + Current->EaNameLength + sizeof(TCHAR)),
|
||||
Name, ValueLen ? TEXT("=") : Value, Value);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* fail if we're out of space */
|
||||
if (SpaceRequired > Options->Remaining) {
|
||||
_ftprintf(stderr, TEXT("Out of space for options!\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Options->Current == NULL)
|
||||
Current = Options->Current = (PFILE_FULL_EA_INFORMATION)
|
||||
Options->Buffer->Buffer;
|
||||
else
|
||||
Current = Options->Current = (PFILE_FULL_EA_INFORMATION)
|
||||
((PBYTE)Options->Current + Options->Current->NextEntryOffset);
|
||||
|
||||
Current->EaNameLength = NameLen;
|
||||
if (NameLen) /* copy attribute name */
|
||||
StringCbCopy((LPTSTR)Current->EaName,
|
||||
NameLen + sizeof(TCHAR), Name);
|
||||
|
||||
Current->EaValueLength = ValueLen;
|
||||
if (ValueLen) /* copy attribute value */
|
||||
StringCbCopy((LPTSTR)(Current->EaName + NameLen + sizeof(TCHAR)),
|
||||
ValueLen + sizeof(TCHAR), Value);
|
||||
|
||||
Current->Flags = 0;
|
||||
Current->NextEntryOffset = EaBufferNextOffset(Options->Current);
|
||||
|
||||
Options->Buffer->Length = (ULONG)(
|
||||
(Current->EaName + NameLen + ValueLen + 2 * sizeof(TCHAR))
|
||||
- Options->Buffer->Buffer );
|
||||
Options->Remaining -= SpaceRequired;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void RecursivePrintEaInformation(
|
||||
IN PFILE_FULL_EA_INFORMATION EA)
|
||||
{
|
||||
_tprintf(
|
||||
TEXT("----------------------\n")
|
||||
TEXT("Alignment: %5lu\n")
|
||||
TEXT("NextEntryOffset: %5lu\n")
|
||||
TEXT("Flags: %5u\n")
|
||||
TEXT("EaNameLength: %5u\n")
|
||||
TEXT("EaValueLength: %5u\n")
|
||||
TEXT("EaName: %16ls\n")
|
||||
TEXT("EaValue: %16ls\n\n"),
|
||||
(ULONG_PTR)EA % sizeof(ULONG),
|
||||
EA->NextEntryOffset,
|
||||
EA->Flags,
|
||||
EA->EaNameLength,
|
||||
EA->EaValueLength,
|
||||
(LPTSTR)EA->EaName,
|
||||
(LPTSTR)(EA->EaName + EA->EaNameLength + sizeof(TCHAR)));
|
||||
|
||||
if (EA->NextEntryOffset)
|
||||
RecursivePrintEaInformation((PFILE_FULL_EA_INFORMATION)
|
||||
((PBYTE)EA + EA->NextEntryOffset));
|
||||
}
|
||||
|
||||
static const TCHAR COMMA_T = TEXT(',');
|
||||
static const TCHAR EQUAL_T = TEXT('=');
|
||||
|
||||
BOOL ParseMountOptions(
|
||||
IN LPTSTR Arg,
|
||||
IN OUT PMOUNT_OPTION_LIST Options)
|
||||
{
|
||||
PTCH pos, comma, equals;
|
||||
|
||||
pos = Arg;
|
||||
for (;;)
|
||||
{
|
||||
comma = _tcschr(pos, COMMA_T);
|
||||
if (comma)
|
||||
{
|
||||
if (comma == pos)
|
||||
goto out_empty_option;
|
||||
*comma = 0;
|
||||
}
|
||||
else if (_tcslen(pos) == 0)
|
||||
goto out_empty_option;
|
||||
|
||||
/* accept 'option=value' or 'option' */
|
||||
equals = _tcschr(pos, EQUAL_T);
|
||||
if (equals)
|
||||
{
|
||||
if (equals == pos)
|
||||
goto out_empty_option;
|
||||
*equals = 0;
|
||||
if (!InsertOption(pos, equals + 1, Options))
|
||||
return FALSE;
|
||||
}
|
||||
else if (!InsertOption(pos, TEXT(""), Options))
|
||||
return FALSE;
|
||||
|
||||
if (comma == NULL)
|
||||
break;
|
||||
|
||||
pos = comma + 1;
|
||||
}
|
||||
|
||||
/* RecursivePrintEaInformation(
|
||||
(PFILE_FULL_EA_INFORMATION)Options->Buffer->Buffer); */
|
||||
return TRUE;
|
||||
|
||||
out_empty_option:
|
||||
_ftprintf(stderr, TEXT("Found an empty option while ")
|
||||
TEXT("reading mount options at '%s'.\n"), pos);
|
||||
return FALSE;
|
||||
}
|
||||
89
mount/options.h
Normal file
89
mount/options.h
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/* Copyright (c) 2010
|
||||
* The Regents of the University of Michigan
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Permission is granted to use, copy and redistribute this software
|
||||
* for noncommercial education and research purposes, so long as no
|
||||
* fee is charged, and so long as the name of the University of Michigan
|
||||
* is not used in any advertising or publicity pertaining to the use
|
||||
* or distribution of this software without specific, written prior
|
||||
* authorization. Permission to modify or otherwise create derivative
|
||||
* works of this software is not granted.
|
||||
*
|
||||
* This software is provided as is, without representation or warranty
|
||||
* of any kind either express or implied, including without limitation
|
||||
* the implied warranties of merchantability, fitness for a particular
|
||||
* purpose, or noninfringement. The Regents of the University of
|
||||
* Michigan shall not be liable for any damages, including special,
|
||||
* indirect, incidental, or consequential damages, with respect to any
|
||||
* claim arising out of or in connection with the use of the software,
|
||||
* even if it has been or is hereafter advised of the possibility of
|
||||
* such damages.
|
||||
*/
|
||||
|
||||
#ifndef __NFS41_MOUNT_OPTIONS_H__
|
||||
#define __NFS41_MOUNT_OPTIONS_H__
|
||||
|
||||
|
||||
#define MOUNT_OPTION_BUFFER_SECRET ('n4')
|
||||
|
||||
/* MOUNT_OPTION_BUFFER
|
||||
* Buffer passed to the network provider via NETRESOURCE.lpComment.
|
||||
* To avoid interpreting a normal comment string as mount options, a
|
||||
* NULL and secret number are expected at the front. */
|
||||
typedef struct _MOUNT_OPTION_BUFFER {
|
||||
USHORT Zero; /* = 0 */
|
||||
USHORT Secret; /* = 'n4' */
|
||||
ULONG Length;
|
||||
CHAR Buffer[1];
|
||||
} MOUNT_OPTION_BUFFER, *PMOUNT_OPTION_BUFFER;
|
||||
|
||||
|
||||
#ifndef FILE_FULL_EA_INFORMATION
|
||||
/* from wdm.h
|
||||
* couldn't find a definition outside of the ddk -cbodley */
|
||||
typedef struct _FILE_FULL_EA_INFORMATION {
|
||||
ULONG NextEntryOffset;
|
||||
UCHAR Flags;
|
||||
UCHAR EaNameLength;
|
||||
USHORT EaValueLength;
|
||||
CHAR EaName[1];
|
||||
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
|
||||
#endif
|
||||
|
||||
/* MOUNT_OPTION_LIST
|
||||
* Used internally to encapsulate the formation of the
|
||||
* extended attribute buffer for mount options. */
|
||||
typedef struct _MOUNT_OPTION_LIST {
|
||||
PMOUNT_OPTION_BUFFER Buffer;
|
||||
ULONG Remaining;
|
||||
PFILE_FULL_EA_INFORMATION Current;
|
||||
} MOUNT_OPTION_LIST, *PMOUNT_OPTION_LIST;
|
||||
|
||||
/* allocate space for 8 full attributes, but limit options by
|
||||
* space rather than count. */
|
||||
#define MAX_OPTION_EA_SIZE ( 8 * \
|
||||
(sizeof(FILE_FULL_EA_INFORMATION) + MAX_PATH) )
|
||||
|
||||
#define MAX_OPTION_BUFFER_SIZE ( sizeof(MOUNT_OPTION_BUFFER) + \
|
||||
MAX_OPTION_EA_SIZE - 1 )
|
||||
|
||||
|
||||
/* options.c */
|
||||
DWORD InitializeMountOptions(
|
||||
IN OUT PMOUNT_OPTION_LIST Options,
|
||||
IN ULONG BufferSize);
|
||||
|
||||
void FreeMountOptions(
|
||||
IN OUT PMOUNT_OPTION_LIST Options);
|
||||
|
||||
BOOL ParseMountOptions(
|
||||
IN LPTSTR Arg,
|
||||
IN OUT PMOUNT_OPTION_LIST Options);
|
||||
|
||||
BOOL InsertOption(
|
||||
IN LPCTSTR Name,
|
||||
IN LPCTSTR Value,
|
||||
IN OUT PMOUNT_OPTION_LIST Options);
|
||||
|
||||
#endif /* !__NFS41_MOUNT_OPTIONS_H__ */
|
||||
17
mount/sources
Normal file
17
mount/sources
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
TARGETTYPE=PROGRAM
|
||||
TARGETNAME=nfs_mount
|
||||
SOURCES=mount.c options.c enum.c
|
||||
UMTYPE=console
|
||||
USE_MSVCRT=1
|
||||
TARGETLIBS=$(DDK_LIB_PATH)\mpr.lib
|
||||
INCLUDES=..\sys
|
||||
|
||||
UMENTRY=wmain
|
||||
UNICODE=1
|
||||
C_DEFINES=$(C_DEFINES) -DUNICODE -D_UNICODE
|
||||
|
||||
!IF 0
|
||||
/W3 is default level
|
||||
bump to /Wall, but suppress warnings generated by system includes
|
||||
!ENDIF
|
||||
MSC_WARNING_LEVEL=/Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4711
|
||||
Loading…
Add table
Add a link
Reference in a new issue