1616 lines
38 KiB
C++
1616 lines
38 KiB
C++
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ftpapiw.cxx
|
||
|
||
Abstract:
|
||
|
||
Wide-character versions of Windows Internet Client DLL FTP APIs and
|
||
Internet subordinate functions
|
||
|
||
Contents:
|
||
FtpFindFirstFileW
|
||
FtpGetFileW
|
||
FtpPutFileW
|
||
FtpDeleteFileW
|
||
FtpRenameFileW
|
||
FtpOpenFileW
|
||
FtpCreateDirectoryW
|
||
FtpRemoveDirectoryW
|
||
FtpSetCurrentDirectoryW
|
||
FtpGetCurrentDirectoryW
|
||
FtpCommandW
|
||
|
||
Author:
|
||
|
||
Heath Hunnicutt [t-heathh] 13-Jul-1994
|
||
|
||
Environment:
|
||
|
||
Win32(s) user-level DLL
|
||
|
||
Revision History:
|
||
|
||
09-Mar-1995 rfirth
|
||
moved from unicode.c
|
||
|
||
21-Jul-1994 t-heathh
|
||
Created
|
||
|
||
--*/
|
||
|
||
#include <wininetp.h>
|
||
#include "ftpapih.h"
|
||
#include <w95wraps.h>
|
||
|
||
#define DEFAULT_TRANSFER_BUFFER_LENGTH (4 K)
|
||
|
||
#define ALLOWED_FTP_FLAGS (INTERNET_FLAGS_MASK \
|
||
| FTP_TRANSFER_TYPE_MASK \
|
||
)
|
||
|
||
//
|
||
// functions
|
||
//
|
||
|
||
|
||
BOOL
|
||
TransformFtpFindDataToW(LPWIN32_FIND_DATAA pfdA, LPWIN32_FIND_DATAW pfdW)
|
||
{
|
||
pfdW->dwFileAttributes = pfdA->dwFileAttributes;
|
||
pfdW->ftCreationTime = pfdA->ftCreationTime;
|
||
pfdW->ftLastAccessTime = pfdA->ftLastAccessTime;
|
||
pfdW->ftLastWriteTime = pfdA->ftLastWriteTime;
|
||
pfdW->nFileSizeHigh = pfdA->nFileSizeHigh;
|
||
pfdW->nFileSizeLow = pfdA->nFileSizeLow;
|
||
pfdW->dwReserved0 = pfdA->dwReserved0;
|
||
pfdW->dwReserved1 = pfdA->dwReserved1;
|
||
MultiByteToWideChar(CP_ACP, 0, pfdA->cFileName, -1, pfdW->cFileName, MAX_PATH);
|
||
MultiByteToWideChar(CP_ACP, 0, pfdA->cAlternateFileName, -1, pfdW->cAlternateFileName, 14);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
INTERNETAPI_(HINTERNET) FtpFindFirstFileW(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCWSTR lpszSearchFile,
|
||
OUT LPWIN32_FIND_DATAW pffdOutput,
|
||
IN DWORD dwFlags,
|
||
IN DWORD_PTR dwContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
lpszSearchFile -
|
||
pffdOutput -
|
||
dwFlags -
|
||
dwContext -
|
||
|
||
Return Value:
|
||
|
||
HINTERNET
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Handle,
|
||
"FtpFindFirstFileW",
|
||
"%#x, %.80wq, %#x, %#x, %#x",
|
||
hFtpSession,
|
||
lpszSearchFile,
|
||
pffdOutput,
|
||
dwFlags,
|
||
dwContext
|
||
));
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
MEMORYPACKET mpSearchFile;
|
||
HANDLE hInternet = NULL;
|
||
WIN32_FIND_DATAA fdA;
|
||
|
||
if (!pffdOutput
|
||
|| IsBadWritePtr(pffdOutput, sizeof(*pffdOutput))
|
||
|| (lpszSearchFile && (IsBadStringPtrW(lpszSearchFile, INTERNET_MAX_PATH_LENGTH + 1))))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
if (lpszSearchFile)
|
||
{
|
||
ALLOC_MB(lpszSearchFile,0,mpSearchFile);
|
||
if (!mpSearchFile.psStr)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
UNICODE_TO_ANSI(lpszSearchFile,mpSearchFile);
|
||
}
|
||
hInternet = FtpFindFirstFileA(hFtpSession,mpSearchFile.psStr,&fdA,dwFlags,dwContext);
|
||
if (hInternet)
|
||
{
|
||
TransformFtpFindDataToW(&fdA, pffdOutput);
|
||
}
|
||
cleanup:
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(hInternet);
|
||
return hInternet;
|
||
}
|
||
|
||
|
||
INTERNETAPI_(BOOL) FtpGetFileW(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCWSTR lpszRemoteFile,
|
||
IN LPCWSTR lpszNewFile,
|
||
IN BOOL fFailIfExists,
|
||
IN DWORD dwFlagsAndAttributes,
|
||
IN DWORD dwFlags,
|
||
IN DWORD_PTR dwContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
lpszRemoteFile -
|
||
lpszNewFile -
|
||
fFailIfExists -
|
||
dwFlagsAndAttributes -
|
||
dwFlags -
|
||
dwContext -
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpGetFileW",
|
||
"%#x, %wq, %wq, %B, %#x, %#x, %#x",
|
||
hFtpSession,
|
||
lpszRemoteFile,
|
||
lpszNewFile,
|
||
fFailIfExists,
|
||
dwFlagsAndAttributes,
|
||
dwFlags,
|
||
dwContext
|
||
));
|
||
|
||
LPINTERNET_THREAD_INFO lpThreadInfo;
|
||
DWORD error;
|
||
BOOL success;
|
||
DWORD nestingLevel = 0;
|
||
HINTERNET hSessionMapped = NULL;
|
||
HINTERNET hFileMapped = NULL;
|
||
BOOL fDeref = TRUE;
|
||
|
||
if (!GlobalDataInitialized) {
|
||
error = ERROR_INTERNET_NOT_INITIALIZED;
|
||
goto done;
|
||
}
|
||
|
||
//
|
||
// we need the INTERNET_THREAD_INFO
|
||
//
|
||
|
||
lpThreadInfo = InternetGetThreadInfo();
|
||
if (lpThreadInfo == NULL) {
|
||
|
||
INET_ASSERT(FALSE);
|
||
|
||
error = ERROR_INTERNET_INTERNAL_ERROR;
|
||
goto quit;
|
||
}
|
||
|
||
_InternetIncNestingCount();
|
||
nestingLevel = 1;
|
||
|
||
//
|
||
// map the connect handle
|
||
//
|
||
|
||
error = MapHandleToAddress(hFtpSession, (LPVOID *)&hSessionMapped, FALSE);
|
||
if ((error != ERROR_SUCCESS) && (hSessionMapped == NULL)) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// set the context and handle info and clear last error variables
|
||
//
|
||
|
||
_InternetSetObjectHandle(lpThreadInfo, hFtpSession, hSessionMapped);
|
||
_InternetSetContext(lpThreadInfo, dwContext);
|
||
_InternetClearLastError(lpThreadInfo);
|
||
|
||
//
|
||
// quit now if the handle is invalid
|
||
//
|
||
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// validate the handle
|
||
//
|
||
|
||
BOOL isLocal;
|
||
BOOL isAsync;
|
||
|
||
error = RIsHandleLocal(hSessionMapped,
|
||
&isLocal,
|
||
&isAsync,
|
||
TypeFtpConnectHandle
|
||
);
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// if we're in the async thread context then we've already validated the
|
||
// parameters, so skip this stage
|
||
//
|
||
|
||
if (!lpThreadInfo->IsAsyncWorkerThread
|
||
|| (lpThreadInfo->NestedRequests > 1)) {
|
||
|
||
//
|
||
// validate parameters
|
||
//
|
||
|
||
if (IsBadStringPtrW(lpszRemoteFile, INTERNET_MAX_PATH_LENGTH + 1)
|
||
|| (*lpszRemoteFile == L'\0')
|
||
|| IsBadStringPtrW(lpszNewFile, INTERNET_MAX_PATH_LENGTH + 1)
|
||
|| (*lpszNewFile == L'\0')
|
||
|| (((dwFlags & FTP_TRANSFER_TYPE_MASK) != 0)
|
||
? (((dwFlags & FTP_TRANSFER_TYPE_MASK) != FTP_TRANSFER_TYPE_ASCII)
|
||
&& ((dwFlags & FTP_TRANSFER_TYPE_MASK) != FTP_TRANSFER_TYPE_BINARY))
|
||
: FALSE)
|
||
|| ((dwFlags & ~ALLOWED_FTP_FLAGS) != 0)) {
|
||
error = ERROR_INVALID_PARAMETER;
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// use default transfer type if so requested
|
||
//
|
||
|
||
if ((dwFlags & FTP_TRANSFER_TYPE_MASK) == 0) {
|
||
dwFlags |= FTP_TRANSFER_TYPE_BINARY;
|
||
}
|
||
|
||
//
|
||
// if we're performing async I/O AND this we are not in the context of
|
||
// an async worker thread AND the app supplied a non-zero context value
|
||
// then we can make an async request
|
||
//
|
||
|
||
if (!lpThreadInfo->IsAsyncWorkerThread
|
||
&& isAsync
|
||
&& (dwContext != INTERNET_NO_CALLBACK)) {
|
||
|
||
//
|
||
// create an asynchronous request block (ARB) and copy the parameters
|
||
//
|
||
|
||
// MakeAsyncRequest
|
||
CFsm_FtpGetFile * pFsm;
|
||
|
||
pFsm = new CFsm_FtpGetFile(hFtpSession, dwContext, lpszRemoteFile, lpszNewFile, fFailIfExists,
|
||
dwFlagsAndAttributes, dwFlags);
|
||
if (pFsm != NULL &&
|
||
pFsm->GetError() == ERROR_SUCCESS)
|
||
{
|
||
error = pFsm->QueueWorkItem();
|
||
|
||
if ( error == ERROR_IO_PENDING ) {
|
||
fDeref = FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
||
if ( pFsm )
|
||
{
|
||
error = pFsm->GetError();
|
||
delete pFsm;
|
||
pFsm = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if we're here then ERROR_SUCCESS cannot have been returned from
|
||
// the above calls
|
||
//
|
||
|
||
INET_ASSERT(error != ERROR_SUCCESS);
|
||
|
||
|
||
DEBUG_PRINT(FTP,
|
||
INFO,
|
||
("processing request asynchronously: error = %d\n",
|
||
error
|
||
));
|
||
|
||
goto quit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// initialize variables in case of early exit
|
||
//
|
||
|
||
HANDLE hLocalFile;
|
||
HINTERNET hRemoteFile;
|
||
LPBYTE transferBuffer;
|
||
|
||
hLocalFile = INVALID_HANDLE_VALUE;
|
||
hRemoteFile = NULL;
|
||
transferBuffer = NULL;
|
||
|
||
//
|
||
// first off, allocate a buffer for the transfer(s) below. The caller can
|
||
// now influence the buffer size used by setting the appropriate option
|
||
// for this handle. If we fail to get the value then revert to the default
|
||
// size of 4K. We want to reduce the number of RPC calls we make
|
||
//
|
||
|
||
DWORD optionLength;
|
||
DWORD transferBufferLength;
|
||
|
||
optionLength = sizeof(transferBufferLength);
|
||
if (!InternetQueryOption(hFtpSession,
|
||
INTERNET_OPTION_READ_BUFFER_SIZE,
|
||
(LPVOID)&transferBufferLength,
|
||
&optionLength
|
||
)) {
|
||
transferBufferLength = DEFAULT_TRANSFER_BUFFER_LENGTH;
|
||
}
|
||
transferBuffer = (LPBYTE)ALLOCATE_FIXED_MEMORY(transferBufferLength);
|
||
if (transferBuffer == NULL) {
|
||
goto last_error_exit;
|
||
}
|
||
|
||
//
|
||
// open/create local file
|
||
//
|
||
|
||
hLocalFile = CreateFileW(lpszNewFile,
|
||
GENERIC_WRITE,
|
||
0,
|
||
NULL,
|
||
fFailIfExists ? CREATE_NEW : CREATE_ALWAYS,
|
||
dwFlagsAndAttributes | FILE_FLAG_SEQUENTIAL_SCAN,
|
||
NULL // need NULL for Win95, handle to file with attributes to copy
|
||
);
|
||
|
||
if (hLocalFile == INVALID_HANDLE_VALUE) {
|
||
goto last_error_exit;
|
||
}
|
||
|
||
//
|
||
// open file at FTP server
|
||
//
|
||
|
||
hRemoteFile = FtpOpenFileW(hFtpSession,
|
||
lpszRemoteFile,
|
||
GENERIC_READ,
|
||
dwFlags,
|
||
dwContext
|
||
);
|
||
if (hRemoteFile == NULL) {
|
||
goto last_error_exit;
|
||
}
|
||
|
||
//
|
||
// since we are going under the API, map the file handle
|
||
//
|
||
|
||
error = MapHandleToAddress(hRemoteFile, (LPVOID *)&hFileMapped, FALSE);
|
||
if ((error != ERROR_SUCCESS) && (hFileMapped == NULL)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// transfer remote file to local (i.e. download it)
|
||
//
|
||
|
||
do {
|
||
|
||
DWORD bytesRead;
|
||
|
||
//
|
||
// let app invalidate out
|
||
//
|
||
|
||
if (((HANDLE_OBJECT *)hFileMapped)->IsInvalidated()
|
||
|| ((HANDLE_OBJECT *)hSessionMapped)->IsInvalidated()) {
|
||
error = ERROR_INTERNET_OPERATION_CANCELLED;
|
||
goto cleanup;
|
||
}
|
||
|
||
success = FtpReadFile(hFileMapped,
|
||
transferBuffer,
|
||
transferBufferLength,
|
||
&bytesRead
|
||
);
|
||
if (success) {
|
||
if (bytesRead != 0) {
|
||
|
||
DWORD bytesWritten;
|
||
|
||
success = WriteFile(hLocalFile,
|
||
transferBuffer,
|
||
bytesRead,
|
||
&bytesWritten,
|
||
NULL
|
||
);
|
||
} else {
|
||
|
||
//
|
||
// done
|
||
//
|
||
|
||
error = ERROR_SUCCESS;
|
||
goto cleanup;
|
||
}
|
||
}
|
||
} while (success);
|
||
|
||
last_error_exit:
|
||
|
||
error = GetLastError();
|
||
|
||
cleanup:
|
||
|
||
if (transferBuffer != NULL) {
|
||
FREE_MEMORY((HLOCAL)transferBuffer);
|
||
}
|
||
|
||
//
|
||
// close local file
|
||
//
|
||
|
||
if (hLocalFile != INVALID_HANDLE_VALUE) {
|
||
CloseHandle(hLocalFile);
|
||
|
||
//
|
||
// if we failed, but created the local file then delete it
|
||
//
|
||
|
||
if ((error != ERROR_SUCCESS) && (hLocalFile != INVALID_HANDLE_VALUE)) {
|
||
DeleteFileW(lpszNewFile);
|
||
}
|
||
}
|
||
|
||
//
|
||
// close remote file
|
||
//
|
||
|
||
if (hRemoteFile != NULL) {
|
||
_InternetCloseHandle(hRemoteFile);
|
||
}
|
||
|
||
//
|
||
// BUGBUG [arthurbi] SetContext should not be called from here,
|
||
// InternetCloseHandle should not reset the context as its
|
||
// doing right now, and this needs to be investigated more,
|
||
// as for now we're workaround this problem by calling SetContext
|
||
//
|
||
|
||
_InternetSetContext(lpThreadInfo, dwContext);
|
||
|
||
quit:
|
||
|
||
if (hFileMapped != NULL) {
|
||
INET_ASSERT(fDeref);
|
||
DereferenceObject((LPVOID)hFileMapped);
|
||
}
|
||
|
||
if (hSessionMapped != NULL && fDeref) {
|
||
DereferenceObject((LPVOID)hSessionMapped);
|
||
}
|
||
|
||
_InternetDecNestingCount(nestingLevel);;
|
||
|
||
done:
|
||
|
||
if (error != ERROR_SUCCESS) {
|
||
SetLastError(error);
|
||
success = FALSE;
|
||
|
||
DEBUG_ERROR(API, error);
|
||
|
||
} else {
|
||
success = TRUE;
|
||
}
|
||
|
||
DEBUG_LEAVE_API(success);
|
||
return success;
|
||
}
|
||
|
||
|
||
INTERNETAPI_(BOOL) FtpPutFileW(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCWSTR lpszLocalFile,
|
||
IN LPCWSTR lpszNewRemoteFile,
|
||
IN DWORD dwFlags,
|
||
IN DWORD_PTR dwContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
lpszLocalFile -
|
||
lpszNewRemoteFile -
|
||
dwFlags -
|
||
dwContext -
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpPutFileW",
|
||
"%#x, %wq, %wq, %#x, %#x",
|
||
hFtpSession,
|
||
lpszLocalFile,
|
||
lpszNewRemoteFile,
|
||
dwFlags,
|
||
dwContext
|
||
));
|
||
|
||
LPINTERNET_THREAD_INFO lpThreadInfo;
|
||
DWORD error;
|
||
BOOL success;
|
||
DWORD nestingLevel = 0;
|
||
HINTERNET hSessionMapped = NULL;
|
||
HINTERNET hFileMapped = NULL;
|
||
BOOL fDeref = TRUE;
|
||
|
||
if (!GlobalDataInitialized) {
|
||
error = ERROR_INTERNET_NOT_INITIALIZED;
|
||
goto done;
|
||
}
|
||
|
||
//
|
||
// we need the INTERNET_THREAD_INFO
|
||
//
|
||
|
||
lpThreadInfo = InternetGetThreadInfo();
|
||
if (lpThreadInfo == NULL) {
|
||
|
||
INET_ASSERT(FALSE);
|
||
|
||
error = ERROR_INTERNET_INTERNAL_ERROR;
|
||
goto quit;
|
||
}
|
||
|
||
_InternetIncNestingCount();
|
||
nestingLevel = 1;
|
||
|
||
//
|
||
// map the connect handle
|
||
//
|
||
|
||
error = MapHandleToAddress(hFtpSession, (LPVOID *)&hSessionMapped, FALSE);
|
||
if ((error != ERROR_SUCCESS) && (hSessionMapped == NULL)) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// set the context and handle info and clear last error variables
|
||
//
|
||
|
||
_InternetSetObjectHandle(lpThreadInfo, hFtpSession, hSessionMapped);
|
||
_InternetSetContext(lpThreadInfo, dwContext);
|
||
_InternetClearLastError(lpThreadInfo);
|
||
|
||
//
|
||
// quit now if the handle is invalid
|
||
//
|
||
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// validate the handle
|
||
//
|
||
|
||
BOOL isLocal;
|
||
BOOL isAsync;
|
||
|
||
error = RIsHandleLocal(hSessionMapped,
|
||
&isLocal,
|
||
&isAsync,
|
||
TypeFtpConnectHandle
|
||
);
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// if we're in the async thread context then we've already validated the
|
||
// parameters, so skip this stage
|
||
//
|
||
|
||
if (!lpThreadInfo->IsAsyncWorkerThread
|
||
|| (lpThreadInfo->NestedRequests > 1)) {
|
||
|
||
//
|
||
// validate parameters
|
||
//
|
||
|
||
if (IsBadStringPtrW(lpszNewRemoteFile, INTERNET_MAX_PATH_LENGTH + 1)
|
||
|| (*lpszNewRemoteFile == L'\0')
|
||
|| IsBadStringPtrW(lpszLocalFile, INTERNET_MAX_PATH_LENGTH + 1)
|
||
|| (*lpszLocalFile == L'\0')
|
||
|| (((dwFlags & FTP_TRANSFER_TYPE_MASK) != 0)
|
||
? (((dwFlags & FTP_TRANSFER_TYPE_MASK) != FTP_TRANSFER_TYPE_ASCII)
|
||
&& ((dwFlags & FTP_TRANSFER_TYPE_MASK) != FTP_TRANSFER_TYPE_BINARY))
|
||
: FALSE)
|
||
|| ((dwFlags & ~ALLOWED_FTP_FLAGS) != 0)) {
|
||
error = ERROR_INVALID_PARAMETER;
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// use default transfer type if so requested
|
||
//
|
||
|
||
if ((dwFlags & FTP_TRANSFER_TYPE_MASK) == 0) {
|
||
dwFlags |= FTP_TRANSFER_TYPE_BINARY;
|
||
}
|
||
|
||
// in offline mode modifications are disallowed
|
||
// someday we will do internet briefcase but not today
|
||
|
||
if ((((INTERNET_CONNECT_HANDLE_OBJECT *)hSessionMapped)->
|
||
GetInternetOpenFlags() | dwFlags) &
|
||
INTERNET_FLAG_OFFLINE) {
|
||
error = ERROR_WRITE_PROTECT;
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// if we're performing async I/O AND this we are not in the context of
|
||
// an async worker thread AND the app supplied a non-zero context value
|
||
// then we can make an async request
|
||
//
|
||
|
||
if (!lpThreadInfo->IsAsyncWorkerThread
|
||
&& isAsync
|
||
&& (dwContext != INTERNET_NO_CALLBACK)) {
|
||
|
||
// MakeAsyncRequest
|
||
CFsm_FtpPutFile * pFsm;
|
||
|
||
pFsm = new CFsm_FtpPutFile(hFtpSession, dwContext, lpszLocalFile, lpszNewRemoteFile, dwFlags);
|
||
if (pFsm != NULL &&
|
||
pFsm->GetError() == ERROR_SUCCESS)
|
||
{
|
||
error = pFsm->QueueWorkItem();
|
||
if ( error == ERROR_IO_PENDING ) {
|
||
fDeref = FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
||
if ( pFsm )
|
||
{
|
||
error = pFsm->GetError();
|
||
delete pFsm;
|
||
pFsm = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if we're here then ERROR_SUCCESS cannot have been returned from
|
||
// the above calls
|
||
//
|
||
|
||
INET_ASSERT(error != ERROR_SUCCESS);
|
||
|
||
|
||
DEBUG_PRINT(FTP,
|
||
INFO,
|
||
("processing request asynchronously: error = %d\n",
|
||
error
|
||
));
|
||
|
||
goto quit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// initialize variables in case of early exit
|
||
//
|
||
|
||
HANDLE hLocalFile;
|
||
HINTERNET hRemoteFile;
|
||
LPBYTE transferBuffer;
|
||
|
||
hLocalFile = INVALID_HANDLE_VALUE;
|
||
hRemoteFile = NULL;
|
||
transferBuffer = NULL;
|
||
|
||
//
|
||
// first off, allocate a buffer for the transfer(s) below. The caller can
|
||
// now influence the buffer size used by setting the appropriate option
|
||
// for this handle. If we fail to get the value then revert to the default
|
||
// size of 4K. We want to reduce the number of RPC calls we make
|
||
//
|
||
|
||
DWORD optionLength;
|
||
DWORD transferBufferLength;
|
||
|
||
optionLength = sizeof(transferBufferLength);
|
||
if (!InternetQueryOption(hFtpSession,
|
||
INTERNET_OPTION_WRITE_BUFFER_SIZE,
|
||
(LPVOID)&transferBufferLength,
|
||
&optionLength
|
||
)) {
|
||
transferBufferLength = DEFAULT_TRANSFER_BUFFER_LENGTH;
|
||
}
|
||
transferBuffer = (LPBYTE)ALLOCATE_FIXED_MEMORY(transferBufferLength);
|
||
if (transferBuffer == NULL) {
|
||
goto last_error_exit;
|
||
}
|
||
|
||
//
|
||
// open local file
|
||
//
|
||
|
||
hLocalFile = CreateFileW(lpszLocalFile,
|
||
GENERIC_READ,
|
||
FILE_SHARE_READ,
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
FILE_FLAG_SEQUENTIAL_SCAN,
|
||
NULL // need NULL for Win95, handle to file with attributes to copy
|
||
);
|
||
if (hLocalFile == INVALID_HANDLE_VALUE) {
|
||
goto last_error_exit;
|
||
}
|
||
|
||
//
|
||
// open file at FTP server
|
||
//
|
||
|
||
hRemoteFile = FtpOpenFileW(hFtpSession,
|
||
lpszNewRemoteFile,
|
||
GENERIC_WRITE,
|
||
dwFlags,
|
||
dwContext
|
||
);
|
||
if (hRemoteFile == NULL) {
|
||
goto last_error_exit;
|
||
}
|
||
|
||
//
|
||
// since we are going under the API, map the file handle
|
||
//
|
||
|
||
error = MapHandleToAddress(hRemoteFile, (LPVOID *)&hFileMapped, FALSE);
|
||
if ((error != ERROR_SUCCESS) && (hFileMapped == NULL)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// transfer local file to remote (i.e. upload it)
|
||
//
|
||
|
||
do {
|
||
|
||
DWORD bytesRead;
|
||
|
||
//
|
||
// let app invalidate out
|
||
//
|
||
|
||
if (((HANDLE_OBJECT *)hFileMapped)->IsInvalidated()
|
||
|| ((HANDLE_OBJECT *)hSessionMapped)->IsInvalidated()) {
|
||
error = ERROR_INTERNET_OPERATION_CANCELLED;
|
||
goto cleanup;
|
||
}
|
||
|
||
success = ReadFile(hLocalFile,
|
||
transferBuffer,
|
||
transferBufferLength,
|
||
&bytesRead,
|
||
NULL
|
||
);
|
||
if (success) {
|
||
if (bytesRead != 0) {
|
||
|
||
DWORD bytesWritten;
|
||
|
||
success = FtpWriteFile(hFileMapped,
|
||
transferBuffer,
|
||
bytesRead,
|
||
&bytesWritten
|
||
);
|
||
} else {
|
||
|
||
//
|
||
// ensure last error is really no error
|
||
//
|
||
|
||
error = ERROR_SUCCESS;
|
||
|
||
goto cleanup;
|
||
}
|
||
}
|
||
} while (success);
|
||
|
||
last_error_exit:
|
||
|
||
error = GetLastError();
|
||
|
||
cleanup:
|
||
|
||
if (transferBuffer != NULL) {
|
||
FREE_MEMORY((HLOCAL)transferBuffer);
|
||
}
|
||
|
||
//
|
||
// close local file
|
||
//
|
||
|
||
if (hLocalFile != INVALID_HANDLE_VALUE) {
|
||
CloseHandle(hLocalFile);
|
||
}
|
||
|
||
//
|
||
// close remote file
|
||
//
|
||
|
||
if (hRemoteFile != NULL) {
|
||
_InternetCloseHandle(hRemoteFile);
|
||
}
|
||
|
||
//
|
||
// BUGBUG [arthurbi] SetContext should not be called from here,
|
||
// InternetCloseHandle should not reset the context as its
|
||
// doing right now, and this needs to be investigated more,
|
||
// as for now we're workaround this problem by calling SetContext
|
||
//
|
||
|
||
_InternetSetContext(lpThreadInfo, dwContext);
|
||
|
||
quit:
|
||
SetLastError(ERROR_SUCCESS); // a-thkesa. from win CE code BUG: WinSE 23985
|
||
|
||
if (hFileMapped != NULL) {
|
||
DereferenceObject((LPVOID)hFileMapped);
|
||
}
|
||
|
||
if (hSessionMapped != NULL && fDeref) {
|
||
DereferenceObject((LPVOID)hSessionMapped);
|
||
}
|
||
|
||
_InternetDecNestingCount(nestingLevel);;
|
||
|
||
done:
|
||
|
||
// a-thkesa Becuase 23985 fix returns ERROR_INTERNET_EXTENDED_ERROR
|
||
if(ERROR_INTERNET_EXTENDED_ERROR == GetLastError()){
|
||
success = FALSE;
|
||
}
|
||
else if (error != ERROR_SUCCESS) {
|
||
SetLastError(error);
|
||
success = FALSE;
|
||
|
||
DEBUG_ERROR(API, error);
|
||
|
||
} else {
|
||
success = TRUE;
|
||
|
||
}
|
||
|
||
DEBUG_LEAVE_API(success);
|
||
|
||
return success;
|
||
}
|
||
|
||
INTERNETAPI_(BOOL) FtpGetFileEx(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCSTR lpszRemoteFile,
|
||
IN LPCWSTR lpszNewFile,
|
||
IN BOOL fFailIfExists,
|
||
IN DWORD dwFlagsAndAttributes,
|
||
IN DWORD dwFlags,
|
||
IN DWORD_PTR dwContext
|
||
)
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpGetFileEx",
|
||
"%#x, %sq, %wq, %B, %#x, %#x, %#x",
|
||
hFtpSession,
|
||
lpszRemoteFile,
|
||
lpszNewFile,
|
||
fFailIfExists,
|
||
dwFlagsAndAttributes,
|
||
dwFlags,
|
||
dwContext
|
||
));
|
||
|
||
DWORD cc, dwErr = ERROR_SUCCESS;
|
||
BOOL fResult = FALSE;
|
||
PWSTR pwszRemoteFile = NULL;
|
||
|
||
cc = MultiByteToWideChar(CP_ACP, 0, lpszRemoteFile, -1, NULL, 0);
|
||
pwszRemoteFile = (LPWSTR)ALLOCATE_FIXED_MEMORY((cc*sizeof(WCHAR)));
|
||
if (!pwszRemoteFile)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
MultiByteToWideChar(CP_ACP, 0, lpszRemoteFile, -1, pwszRemoteFile, cc);
|
||
|
||
fResult = FtpGetFileW(hFtpSession,pwszRemoteFile,lpszNewFile,fFailIfExists,
|
||
dwFlagsAndAttributes,dwFlags,dwContext);
|
||
|
||
cleanup:
|
||
if (pwszRemoteFile)
|
||
{
|
||
FREE_MEMORY(pwszRemoteFile);
|
||
}
|
||
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(fResult);
|
||
return fResult;
|
||
|
||
}
|
||
|
||
|
||
INTERNETAPI_(BOOL) FtpPutFileEx(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCWSTR lpszLocalFile,
|
||
IN LPCSTR lpszNewRemoteFile,
|
||
IN DWORD dwFlags,
|
||
IN DWORD_PTR dwContext
|
||
)
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpPutFileEx",
|
||
"%#x, %wq, %sq, %#x, %#x",
|
||
hFtpSession,
|
||
lpszLocalFile,
|
||
lpszNewRemoteFile,
|
||
dwFlags,
|
||
dwContext
|
||
));
|
||
|
||
DWORD cc, dwErr = ERROR_SUCCESS;
|
||
BOOL fResult = FALSE;
|
||
PWSTR pwszRemoteFile = NULL;
|
||
|
||
cc = MultiByteToWideChar(CP_ACP, 0, lpszNewRemoteFile, -1, NULL, 0);
|
||
pwszRemoteFile = (LPWSTR)ALLOCATE_FIXED_MEMORY((cc*sizeof(WCHAR)));
|
||
if (!pwszRemoteFile)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
MultiByteToWideChar(CP_ACP, 0, lpszNewRemoteFile, -1, pwszRemoteFile, cc);
|
||
|
||
fResult = FtpPutFileW(hFtpSession,lpszLocalFile,pwszRemoteFile,dwFlags,dwContext);
|
||
|
||
cleanup:
|
||
if (pwszRemoteFile)
|
||
{
|
||
FREE_MEMORY(pwszRemoteFile);
|
||
}
|
||
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(fResult);
|
||
return fResult;
|
||
|
||
}
|
||
|
||
|
||
INTERNETAPI_(BOOL) FtpDeleteFileW(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCWSTR lpszFileName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
lpszFileName -
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpDeleteFileW",
|
||
"%#x, %wq",
|
||
hFtpSession,
|
||
lpszFileName
|
||
));
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
BOOL fResult = FALSE;
|
||
MEMORYPACKET mpFile;
|
||
|
||
if (!lpszFileName
|
||
|| (IsBadStringPtrW(lpszFileName, INTERNET_MAX_PATH_LENGTH + 1))
|
||
|| (*lpszFileName == L'\0'))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
ALLOC_MB(lpszFileName,0,mpFile);
|
||
if (!mpFile.psStr)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
UNICODE_TO_ANSI(lpszFileName,mpFile);
|
||
fResult = FtpDeleteFileA(hFtpSession,mpFile.psStr);
|
||
|
||
cleanup:
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(fResult);
|
||
return fResult;
|
||
}
|
||
|
||
|
||
INTERNETAPI_(BOOL) FtpRenameFileW(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCWSTR lpszExisting,
|
||
IN LPCWSTR lpszNew
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
lpszExisting -
|
||
lpszNew -
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpRenameFileW",
|
||
"%#x, %wq, %wq",
|
||
hFtpSession,
|
||
lpszExisting,
|
||
lpszNew
|
||
));
|
||
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
BOOL fResult = FALSE;
|
||
MEMORYPACKET mpExisting, mpNew;
|
||
|
||
if (!(lpszExisting && lpszNew)
|
||
|| (IsBadStringPtrW(lpszExisting, INTERNET_MAX_PATH_LENGTH + 1))
|
||
|| (IsBadStringPtrW(lpszNew, INTERNET_MAX_PATH_LENGTH + 1)))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
ALLOC_MB(lpszExisting,0,mpExisting);
|
||
ALLOC_MB(lpszNew,0,mpNew);
|
||
if (!(mpExisting.psStr && mpNew.psStr))
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
UNICODE_TO_ANSI(lpszExisting,mpExisting);
|
||
UNICODE_TO_ANSI(lpszNew,mpNew);
|
||
fResult = FtpRenameFileA(hFtpSession,mpExisting.psStr,mpNew.psStr);
|
||
|
||
cleanup:
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(fResult);
|
||
return fResult;
|
||
}
|
||
|
||
|
||
INTERNETAPI_(HINTERNET) FtpOpenFileW(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCWSTR lpszFileName,
|
||
IN DWORD dwAccess,
|
||
IN DWORD dwFlags,
|
||
IN DWORD_PTR dwContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
lpszFileName -
|
||
dwAccess -
|
||
dwFlags -
|
||
dwContext -
|
||
|
||
Return Value:
|
||
|
||
HINTERNET
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Handle,
|
||
"FtpOpenFileW",
|
||
"%#x, %wq, %#x, %#x, %#x",
|
||
hFtpSession,
|
||
lpszFileName,
|
||
dwAccess,
|
||
dwFlags,
|
||
dwContext
|
||
));
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
HINTERNET hInternet = NULL;
|
||
MEMORYPACKET mpFile;
|
||
|
||
if (!lpszFileName
|
||
|| (IsBadStringPtrW(lpszFileName, INTERNET_MAX_PATH_LENGTH + 1)))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
ALLOC_MB(lpszFileName,0,mpFile);
|
||
if (!mpFile.psStr)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
UNICODE_TO_ANSI(lpszFileName,mpFile);
|
||
hInternet = FtpOpenFileA(hFtpSession,mpFile.psStr,dwAccess,dwFlags,dwContext);
|
||
|
||
cleanup:
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
|
||
}
|
||
DEBUG_LEAVE_API(hInternet);
|
||
return hInternet;
|
||
}
|
||
|
||
|
||
INTERNETAPI_(BOOL) FtpCreateDirectoryW(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCWSTR pwszDir
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
pwszDir -
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpCreateDirectoryW",
|
||
"%#x, %wq",
|
||
hFtpSession,
|
||
pwszDir
|
||
));
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
BOOL fResult = FALSE;
|
||
MEMORYPACKET mpDir;
|
||
|
||
if (!pwszDir
|
||
|| (IsBadStringPtrW(pwszDir, INTERNET_MAX_PATH_LENGTH + 1)
|
||
|| (*pwszDir == L'\0')))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
ALLOC_MB(pwszDir,0,mpDir);
|
||
if (!mpDir.psStr)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
UNICODE_TO_ANSI(pwszDir,mpDir);
|
||
fResult = FtpCreateDirectoryA(hFtpSession,mpDir.psStr);
|
||
|
||
cleanup:
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(fResult);
|
||
return fResult;
|
||
}
|
||
|
||
|
||
INTERNETAPI_(BOOL) FtpRemoveDirectoryW(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCWSTR pwszDir
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
pwszDir -
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpRemoveDirectoryW",
|
||
"%#x, %wq",
|
||
hFtpSession,
|
||
pwszDir
|
||
));
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
BOOL fResult = FALSE;
|
||
MEMORYPACKET mpDir;
|
||
|
||
if (!pwszDir
|
||
|| (IsBadStringPtrW(pwszDir, INTERNET_MAX_PATH_LENGTH + 1)))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
ALLOC_MB(pwszDir,0,mpDir);
|
||
if (!mpDir.psStr)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
UNICODE_TO_ANSI(pwszDir,mpDir);
|
||
fResult = FtpRemoveDirectoryA(hFtpSession,mpDir.psStr);
|
||
|
||
cleanup:
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(fResult);
|
||
return fResult;
|
||
}
|
||
|
||
|
||
INTERNETAPI_(BOOL) FtpSetCurrentDirectoryW(
|
||
IN HINTERNET hFtpSession,
|
||
IN LPCWSTR pwszDir
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
pwszDir -
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpSetCurrentDirectoryW",
|
||
"%#x, %wq",
|
||
hFtpSession,
|
||
pwszDir
|
||
));
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
BOOL fResult = FALSE;
|
||
MEMORYPACKET mpDir;
|
||
|
||
if (!pwszDir
|
||
|| (IsBadStringPtrW(pwszDir, INTERNET_MAX_PATH_LENGTH + 1)))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
ALLOC_MB(pwszDir,0,mpDir);
|
||
if (!mpDir.psStr)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
UNICODE_TO_ANSI(pwszDir,mpDir);
|
||
fResult = FtpSetCurrentDirectoryA(hFtpSession,mpDir.psStr);
|
||
|
||
cleanup:
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(fResult);
|
||
return fResult;
|
||
}
|
||
|
||
|
||
INTERNETAPI_(BOOL) FtpGetCurrentDirectoryW(
|
||
IN HINTERNET hFtpSession,
|
||
OUT LPWSTR lpszCurrentDirectory,
|
||
IN OUT LPDWORD lpdwCurrentDirectory
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
lpszCurrentDirectory -
|
||
lpdwCurrentDirectory -
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpGetCurrentDirectoryW",
|
||
"%#x, %#x, %#x [%d]",
|
||
hFtpSession,
|
||
lpszCurrentDirectory,
|
||
lpdwCurrentDirectory,
|
||
lpdwCurrentDirectory ? *lpdwCurrentDirectory : 0
|
||
));
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
BOOL fResult = FALSE;
|
||
MEMORYPACKET mpDir;
|
||
|
||
if (!lpdwCurrentDirectory
|
||
|| IsBadWritePtr(lpdwCurrentDirectory, sizeof(*lpdwCurrentDirectory))
|
||
|| (lpszCurrentDirectory && IsBadWritePtr(lpszCurrentDirectory, *lpdwCurrentDirectory)))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
if (lpszCurrentDirectory)
|
||
{
|
||
mpDir.dwSize = mpDir.dwAlloc = *lpdwCurrentDirectory*sizeof(CHAR);
|
||
mpDir.psStr = (LPSTR)ALLOC_BYTES(mpDir.dwAlloc);
|
||
if (!mpDir.psStr)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
*lpdwCurrentDirectory = 0;
|
||
}
|
||
|
||
fResult = FtpGetCurrentDirectoryA(hFtpSession,mpDir.psStr,&mpDir.dwSize);
|
||
if (fResult)
|
||
{
|
||
DWORD cc = MultiByteToWideChar(CP_ACP, 0, mpDir.psStr, -1, NULL, 0);
|
||
if (*lpdwCurrentDirectory>=cc)
|
||
{
|
||
*lpdwCurrentDirectory = MultiByteToWideChar(CP_ACP, 0, mpDir.psStr, -1,
|
||
lpszCurrentDirectory, *lpdwCurrentDirectory);
|
||
}
|
||
else
|
||
{
|
||
*lpdwCurrentDirectory = cc*sizeof(WCHAR);
|
||
dwErr = ERROR_INSUFFICIENT_BUFFER;
|
||
fResult = FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (GetLastError()==ERROR_INSUFFICIENT_BUFFER)
|
||
{
|
||
*lpdwCurrentDirectory = mpDir.dwSize*sizeof(WCHAR);
|
||
}
|
||
}
|
||
|
||
cleanup:
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(fResult);
|
||
return fResult;
|
||
}
|
||
|
||
|
||
INTERNETAPI_(BOOL) FtpCommandW(
|
||
IN HINTERNET hFtpSession,
|
||
IN BOOL fExpectResponse,
|
||
IN DWORD dwFlags,
|
||
IN LPCWSTR lpszCommand,
|
||
IN DWORD_PTR dwContext,
|
||
OUT HINTERNET *phFtpCommand OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
hFtpSession -
|
||
fExpectResponse -
|
||
dwFlags -
|
||
lpszCommand -
|
||
dwContext -
|
||
phFtpCommand -
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER_API((DBG_API,
|
||
Bool,
|
||
"FtpCommandW",
|
||
"%#x, %B, %#x, %wq, %#x, %x",
|
||
hFtpSession,
|
||
fExpectResponse,
|
||
dwFlags,
|
||
lpszCommand,
|
||
dwContext,
|
||
phFtpCommand
|
||
));
|
||
|
||
MEMORYPACKET mpCommand;
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
BOOL fResult = FALSE;
|
||
if (!lpszCommand
|
||
|| IsBadStringPtrW(lpszCommand, INTERNET_MAX_URL_LENGTH)
|
||
|| (phFtpCommand && IsBadWritePtr(phFtpCommand, sizeof(*phFtpCommand))))
|
||
{
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
ALLOC_MB(lpszCommand, 0, mpCommand);
|
||
if (!mpCommand.psStr)
|
||
{
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
}
|
||
UNICODE_TO_ANSI(lpszCommand, mpCommand);
|
||
|
||
fResult = FtpCommandA(hFtpSession, fExpectResponse, dwFlags, mpCommand.psStr, dwContext, phFtpCommand);
|
||
|
||
cleanup:
|
||
if (dwErr!=ERROR_SUCCESS)
|
||
{
|
||
SetLastError(dwErr);
|
||
DEBUG_ERROR(API, dwErr);
|
||
}
|
||
DEBUG_LEAVE_API(fResult);
|
||
return fResult;
|
||
}
|
||
|