WindowsXP-SP1/inetcore/wininet/ftp/ftpapiw.cxx
2020-09-30 16:53:49 +02:00

1616 lines
38 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}