00001
00002
00003
00004
00005
00006 #include "fsFtpFile.h"
00007 #include <stdio.h>
00008 #include "common.h"
00009 #include <limits.h>
00010 #include "fsFtpConnection.h"
00011 #include "system.h"
00012
00013 fsFtpFile::fsFtpFile()
00014 {
00015 m_dwTransferType = FTP_TRANSFER_TYPE_BINARY;
00016 m_bDontUseLIST = FALSE;
00017
00018 m_sFile = m_sRcv = (UINT) -1;
00019 }
00020
00021 fsFtpFile::~fsFtpFile()
00022 {
00023 CloseHandle ();
00024 }
00025
00026 fsInternetResult fsFtpFile::Open(LPCSTR pszFilePath, UINT64 uStartPos)
00027 {
00028 return OpenEx (pszFilePath, uStartPos, _UI64_MAX);
00029 }
00030
00031 fsInternetResult fsFtpFile::Read(LPBYTE pBuffer, DWORD dwToRead, DWORD *pdwRead)
00032 {
00033 if (m_sFile == UINT (-1))
00034 return IR_NOTINITIALIZED;
00035
00036 try {*pdwRead = recv (m_sFile, (char*) pBuffer, dwToRead, 0);}
00037 catch (...){return IR_ERROR;}
00038
00039 if (*pdwRead == 0 || *pdwRead == DWORD (SOCKET_ERROR))
00040 return fsWSAErrorToIR ();
00041
00042 return IR_SUCCESS;
00043 }
00044
00045 fsInternetResult fsFtpFile::SetTransferType(fsFtpTransferType enType)
00046 {
00047 switch (enType)
00048 {
00049 case FTT_BINARY:
00050 m_dwTransferType = FTP_TRANSFER_TYPE_BINARY;
00051 break;
00052
00053 case FTT_ASCII:
00054 m_dwTransferType = FTP_TRANSFER_TYPE_ASCII;
00055 break;
00056
00057 default:
00058 return IR_INVALIDPARAM;
00059 }
00060
00061 return IR_SUCCESS;
00062 }
00063
00064 void fsFtpFile::ReceiveExtError()
00065 {
00066 DWORD dwLen = 0;
00067 DWORD dwErr;
00068
00069 SAFE_DELETE_ARRAY (m_pszLastError);
00070
00071 InternetGetLastResponseInfo (&dwErr, NULL, &dwLen);
00072
00073 if (::GetLastError () == ERROR_INSUFFICIENT_BUFFER)
00074 {
00075 dwLen++;
00076 fsnew (m_pszLastError, char, dwLen);
00077 InternetGetLastResponseInfo (&dwErr, m_pszLastError, &dwLen);
00078 }
00079 }
00080
00081 void fsFtpFile::CloseHandle()
00082 {
00083 if (m_sFile != UINT (-1))
00084 closesocket (m_sFile);
00085
00086 if (m_sRcv != UINT (-1))
00087 closesocket (m_sRcv);
00088
00089 m_sFile = m_sRcv = (UINT) -1;
00090 }
00091
00092 SHORT fsFtpFile::OpenSocket()
00093 {
00094 sockaddr_in addr;
00095 hostent *he;
00096
00097
00098
00099 static SHORT _portStart = IPPORT_RESERVED + 10;
00100
00101 if (_portStart >= IPPORT_RESERVED + 10000)
00102 _portStart = IPPORT_RESERVED + 10;
00103
00104
00105 SHORT port;
00106
00107 char szName [10000];
00108 gethostname (szName, 10000);
00109
00110
00111 he = gethostbyname (szName);
00112
00113 if (he == NULL)
00114 return 0;
00115
00116 ZeroMemory (&addr, sizeof (addr));
00117 CopyMemory (&addr.sin_addr, he->h_addr, he->h_length);
00118 addr.sin_family = he->h_addrtype;
00119
00120 m_sRcv = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
00121 if (m_sRcv == UINT (-1))
00122 return 0;
00123
00124 int bindErr;
00125
00126
00127 do
00128 {
00129 port = _portStart++;
00130 addr.sin_port = htons (port);
00131 _portStart++;
00132 bindErr = bind (m_sRcv, (sockaddr*) &addr, sizeof (addr));
00133 }
00134 while (bindErr && ::GetLastError () == WSAEADDRINUSE);
00135
00136 if (bindErr)
00137 return 0;
00138
00139 listen (m_sRcv, 1);
00140
00141 CHAR ipAddr [100];
00142 sprintf (ipAddr, "%d,%d,%d,%d,%d,%d", (int) (BYTE) he->h_addr_list [0][0], (int) (BYTE) he->h_addr_list [0][1], (int) (BYTE) he->h_addr_list [0][2], (int) (BYTE) he->h_addr_list [0][3],
00143 DWORD (port) >> 8, DWORD (port) & 0xff);
00144 m_strPORT = ipAddr;
00145
00146 return port;
00147 }
00148
00149 fsInternetResult fsFtpFile::FtpError()
00150 {
00151 fsInternetResult ir = fsWinInetErrorToIR ();
00152 if (ir == IR_EXTERROR)
00153 ReceiveExtError ();
00154 return ir;
00155 }
00156
00157 BOOL fsFtpFile::ParseSIZE()
00158 {
00159 ReceiveExtError ();
00160
00161 int len = strlen (m_pszLastError);
00162 int pos = len - 2;
00163
00164
00165
00166 while (pos > 0 && m_pszLastError [pos - 1] >= '0' && m_pszLastError [pos - 1] <= '9')
00167 pos--;
00168
00169 if (pos <= 0 || pos == len - 2)
00170 return FALSE;
00171
00172 UINT64 uSize = (UINT64) _atoi64 (m_pszLastError + pos);
00173 if (uSize > 1000ui64*1024*1024*1024)
00174 return FALSE;
00175
00176 m_uFileSize = uSize;
00177
00178 return TRUE;
00179 }
00180
00181 fsInternetResult fsFtpFile::PASV_ConnectSocket()
00182 {
00183
00184 LPCSTR pszPORT = m_pszLastError;
00185
00186
00187 do
00188 {
00189 pszPORT = strchr (pszPORT+1, ',');
00190 if (pszPORT == NULL)
00191 return IR_ERROR;
00192 }
00193 while (IsDigit (*(pszPORT - 1)) == FALSE || IsDigit (*(pszPORT + 1)) == FALSE);
00194
00195 while (IsDigit (*(--pszPORT)));
00196 pszPORT++;
00197
00198 sockaddr_in addr;
00199
00200 ZeroMemory (&addr, sizeof (addr));
00201 addr.sin_family = AF_INET;
00202
00203 BYTE aAddr [6];
00204
00205
00206 for (int i = 0; i < 6; i++)
00207 {
00208 aAddr [i] = (BYTE) atoi (pszPORT);
00209
00210
00211 while (*pszPORT >= '0' && *pszPORT <= '9')
00212 pszPORT++;
00213 while (*pszPORT && (*pszPORT < '0' || *pszPORT > '9'))
00214 pszPORT++;
00215
00216 if (*pszPORT == 0 && i != 5)
00217 return IR_ERROR;
00218 }
00219
00220
00221 addr.sin_addr.S_un.S_un_b.s_b1 = aAddr [0];
00222 addr.sin_addr.S_un.S_un_b.s_b2 = aAddr [1];
00223 addr.sin_addr.S_un.S_un_b.s_b3 = aAddr [2];
00224 addr.sin_addr.S_un.S_un_b.s_b4 = aAddr [3];
00225
00226 addr.sin_port = short ((unsigned char)aAddr [5] << 8 | (unsigned char)aAddr [4]);
00227
00228 m_sFile = socket (AF_INET, SOCK_STREAM, 0);
00229 if (m_sFile == -1)
00230 return fsWSAErrorToIR ();
00231
00232 if (connect (m_sFile, (sockaddr*)&addr, sizeof (addr)) == -1)
00233 return fsWSAErrorToIR ();
00234
00235 return IR_SUCCESS;
00236 }
00237
00238 BOOL fsFtpFile::IsDigit(char c)
00239 {
00240 return c <= '9' && c >= '0';
00241 }
00242
00243 fsInternetResult fsFtpFile::QuerySize(LPCSTR pszFilePath)
00244 {
00245
00246
00247
00248 if (!m_pServer)
00249 return IR_NOTINITIALIZED;
00250
00251 HINTERNET hServer = m_pServer->GetHandle ();
00252
00253 if (!hServer)
00254 return IR_NOTINITIALIZED;
00255
00256 m_bContentTypeValid = FALSE;
00257 m_bDateValid = FALSE;
00258
00259 CloseHandle ();
00260
00261 CHAR szCmd [10000];
00262
00263 char szFile [10000];
00264 strcpy (szFile, pszFilePath);
00265
00266
00267 char *pszFile = max (strrchr (pszFilePath, '/'), strrchr (pszFilePath, '\\'));
00268
00269 if (pszFile)
00270 {
00271 if (pszFile - pszFilePath)
00272 {
00273 szFile [pszFile - pszFilePath] = 0;
00274
00275 sprintf (szCmd, "CWD %s", szFile);
00276
00277 Dialog (IFDD_TOSERVER, szCmd);
00278
00279 if (!FtpCommand (hServer, FALSE, m_dwTransferType, szCmd, NULL, NULL))
00280 strcpy (szFile, pszFilePath);
00281 else
00282 strcpy (szFile, pszFile + 1);
00283
00284 DialogFtpResponse ();
00285 }
00286 }
00287
00288 BOOL bListOK = FALSE;
00289
00290 m_uFileSize = _UI64_MAX;
00291
00292 if (m_bDontUseLIST == FALSE)
00293 bListOK = Send_LIST (szCmd, szFile);
00294
00295 if (bListOK == FALSE)
00296 {
00297
00298 lstrcpy (szCmd, "TYPE I");
00299 Dialog (IFDD_TOSERVER, szCmd);
00300 fsInternetResult ir;
00301 if (!FtpCommand (hServer, FALSE, FTP_TRANSFER_TYPE_BINARY, szCmd, NULL, NULL))
00302 {
00303 ir = FtpError ();
00304 DialogFtpResponse ();
00305 return ir;
00306 }
00307
00308
00309 sprintf (szCmd, "SIZE %s", szFile);
00310 Dialog (IFDD_TOSERVER, szCmd);
00311 if (FtpCommand (hServer, FALSE, FTP_TRANSFER_TYPE_BINARY, szCmd, NULL, NULL))
00312 ParseSIZE ();
00313 DialogFtpResponse ();
00314
00315 if (m_uFileSize == _UI64_MAX && m_bDontUseLIST)
00316 {
00317
00318 bListOK = Send_LIST (szCmd, szFile);
00319 }
00320 }
00321
00322 return IR_SUCCESS;
00323 }
00324
00325 void fsFtpFile::SetDontUseLIST(BOOL b)
00326 {
00327 m_bDontUseLIST = b;
00328 }
00329
00330 BOOL fsFtpFile::Send_LIST(LPSTR pszCmd, LPCSTR pszFile)
00331 {
00332 sprintf (pszCmd, "LIST %s", pszFile);
00333 Dialog (IFDD_TOSERVER, pszCmd);
00334
00335 WIN32_FIND_DATA wfd;
00336
00337 HINTERNET hFind = FtpFindFirstFile (m_pServer->GetHandle (), pszFile, &wfd, INTERNET_FLAG_NO_CACHE_WRITE |
00338 INTERNET_FLAG_RELOAD, 0);
00339
00340 DialogFtpResponse ();
00341
00342 if (hFind)
00343 {
00344 InternetCloseHandle (hFind);
00345
00346
00347
00348 if (m_uFileSize == _UI64_MAX && wfd.nFileSizeLow != UINT_MAX)
00349 {
00350 UINT64 u = ((UINT64)wfd.nFileSizeHigh * ((UINT64)MAXDWORD+1)) + wfd.nFileSizeLow;
00351
00352 if (u)
00353 m_uFileSize = u;
00354 }
00355
00356 if (wfd.ftCreationTime.dwLowDateTime != 0 || wfd.ftCreationTime.dwHighDateTime != 0)
00357 m_date = wfd.ftCreationTime;
00358 else if (wfd.ftLastWriteTime.dwLowDateTime != 0 || wfd.ftLastWriteTime.dwHighDateTime != 0)
00359 m_date = wfd.ftLastWriteTime;
00360 else
00361 m_date = wfd.ftLastAccessTime;
00362
00363 m_bDateValid = TRUE;
00364 }
00365
00366
00367
00368 return FALSE;
00369 }
00370
00371 fsFtpTransferType fsFtpFile::GetTransferType()
00372 {
00373 if (m_dwTransferType & FTP_TRANSFER_TYPE_BINARY)
00374 return FTT_BINARY;
00375 else if (m_dwTransferType & FTP_TRANSFER_TYPE_ASCII)
00376 return FTT_ASCII;
00377 else
00378 return FTT_UNKNOWN;
00379 }
00380
00381 fsInternetResult fsFtpFile::OpenEx(LPCSTR pszFilePath, UINT64 uStartPos, UINT64 , UINT64 uUploadTotalSize)
00382 {
00383 if (!m_pServer)
00384 return IR_NOTINITIALIZED;
00385
00386 HINTERNET hServer = m_pServer->GetHandle ();
00387
00388 if (!hServer)
00389 return IR_NOTINITIALIZED;
00390
00391 m_bContentTypeValid = FALSE;
00392 m_bDateValid = FALSE;
00393
00394 CloseHandle ();
00395
00396 CHAR szCmd [10000];
00397
00398 char szFile [10000];
00399 strcpy (szFile, pszFilePath);
00400
00401
00402 char *pszFile = max (strrchr (pszFilePath, '/'), strrchr (pszFilePath, '\\'));
00403
00404 if (pszFile)
00405 {
00406 if (pszFile - pszFilePath)
00407 {
00408 szFile [pszFile - pszFilePath] = 0;
00409
00410 sprintf (szCmd, "CWD %s", szFile);
00411
00412 Dialog (IFDD_TOSERVER, szCmd);
00413
00414 if (!FtpCommand (hServer, FALSE, m_dwTransferType, szCmd, NULL, NULL))
00415 strcpy (szFile, pszFilePath);
00416 else
00417 strcpy (szFile, pszFile + 1);
00418
00419 DialogFtpResponse ();
00420 }
00421 }
00422
00423 BOOL bListOK = FALSE;
00424
00425 m_uFileSize = _UI64_MAX;
00426
00427 if (m_bDontUseLIST == FALSE && uStartPos == 0)
00428 bListOK = Send_LIST (szCmd, szFile);
00429
00430 if (bListOK == FALSE)
00431 {
00432
00433 lstrcpy (szCmd, "TYPE I");
00434 Dialog (IFDD_TOSERVER, szCmd);
00435 fsInternetResult ir;
00436 if (!FtpCommand (hServer, FALSE, FTP_TRANSFER_TYPE_BINARY, szCmd, NULL, NULL))
00437 {
00438 ir = FtpError ();
00439 DialogFtpResponse ();
00440 return ir;
00441 }
00442
00443
00444 sprintf (szCmd, "SIZE %s", szFile);
00445 Dialog (IFDD_TOSERVER, szCmd);
00446 if (FtpCommand (hServer, FALSE, FTP_TRANSFER_TYPE_BINARY, szCmd, NULL, NULL))
00447 ParseSIZE ();
00448 DialogFtpResponse ();
00449
00450 if (m_uFileSize == _UI64_MAX && m_bDontUseLIST)
00451 {
00452
00453
00454 bListOK = Send_LIST (szCmd, szFile);
00455 }
00456 }
00457
00458
00459 sprintf (szCmd, "TYPE %c", m_dwTransferType & FTP_TRANSFER_TYPE_ASCII ? 'A' : 'I');
00460 Dialog (IFDD_TOSERVER, szCmd);
00461
00462 fsInternetResult ir;
00463
00464 if (!FtpCommand (hServer, FALSE, m_dwTransferType, szCmd, NULL, NULL))
00465 {
00466 ir = FtpError ();
00467 DialogFtpResponse ();
00468 return ir;
00469 }
00470
00471 DialogFtpResponse ();
00472
00473
00474 BOOL bPassive = ((fsFtpConnection*) m_pServer)->IsPassiveMode ();
00475
00476 if (bPassive)
00477 {
00478 Dialog (IFDD_TOSERVER, "PASV");
00479
00480 if (!FtpCommand (hServer, FALSE, m_dwTransferType, "PASV", NULL, NULL))
00481 {
00482 return FtpError ();
00483 }
00484
00485 DialogFtpResponse ();
00486 ReceiveExtError ();
00487
00488 fsInternetResult ir = PASV_ConnectSocket ();
00489
00490 if (ir != IR_SUCCESS)
00491 return ir;
00492 }
00493 else
00494 {
00495
00496 if (0 == OpenSocket ())
00497 return IR_ERROR;
00498
00499
00500 sprintf (szCmd, "PORT %s", m_strPORT);
00501 Dialog (IFDD_TOSERVER, szCmd);
00502 if (!FtpCommand (hServer, FALSE, m_dwTransferType, szCmd, NULL, NULL))
00503 {
00504 DialogFtpResponse ();
00505 return FtpError ();
00506 }
00507 DialogFtpResponse ();
00508 }
00509
00510 if (uUploadTotalSize == _UI64_MAX)
00511 {
00512 if (uStartPos)
00513 {
00514 sprintf (szCmd, "REST %I64u", uStartPos);
00515 Dialog (IFDD_TOSERVER, szCmd);
00516
00517 if (!FtpCommand (hServer, FALSE, m_dwTransferType, szCmd, NULL, NULL))
00518 m_enRST = RST_NONE;
00519 DialogFtpResponse ();
00520
00521 if (m_enRST == RST_NONE)
00522 return IR_RANGESNOTAVAIL;
00523
00524 m_enRST = RST_PRESENT;
00525 }
00526 else
00527 {
00528 Dialog (IFDD_TOSERVER, "REST 100");
00529
00530 if (!FtpCommand (hServer, FALSE, m_dwTransferType, "REST 100", NULL, NULL))
00531 {
00532 m_enRST = RST_NONE;
00533 DialogFtpResponse ();
00534 }
00535 else
00536 {
00537 m_enRST = RST_PRESENT;
00538 DialogFtpResponse ();
00539 Dialog (IFDD_TOSERVER, "REST 0");
00540 FtpCommand (hServer, FALSE, m_dwTransferType, "REST 0", NULL, NULL);
00541 DialogFtpResponse ();
00542 }
00543 }
00544
00545 sprintf (szCmd, "RETR %s", szFile);
00546 }
00547 else
00548 {
00549
00550 if (uStartPos)
00551 sprintf (szCmd, "APPE %s", szFile);
00552 else
00553 sprintf (szCmd, "STOR %s", szFile);
00554 }
00555
00556 Dialog (IFDD_TOSERVER, szCmd);
00557 if (!FtpCommand (hServer, FALSE, m_dwTransferType, szCmd, NULL, NULL))
00558 {
00559 ir = FtpError ();
00560 DialogFtpResponse ();
00561 return ir;
00562 }
00563 DialogFtpResponse ();
00564
00565 if (bPassive == FALSE)
00566 {
00567 m_sFile = accept (m_sRcv, NULL, 0);
00568
00569 if (m_sFile == UINT (-1))
00570 return fsWSAErrorToIR ();
00571 }
00572
00573 return IR_SUCCESS;
00574 }
00575
00576 fsInternetResult fsFtpFile::Write (LPBYTE pBuffer, DWORD dwToWrite, DWORD *pdwWritten)
00577 {
00578 if (m_sFile == UINT (-1))
00579 return IR_NOTINITIALIZED;
00580
00581 try {*pdwWritten = send (m_sFile, (char*) pBuffer, dwToWrite, 0);}
00582 catch (...){return IR_ERROR;}
00583
00584 if (*pdwWritten == 0 || *pdwWritten == DWORD (SOCKET_ERROR))
00585 return fsWSAErrorToIR ();
00586
00587 return IR_SUCCESS;
00588 }
00589
00590 BOOL fsFtpFile::FtpCommand(HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags, LPCSTR pszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand)
00591 {
00592 char szCmd [1000];
00593 if (strchr (pszCommand, '%'))
00594 {
00595 int pos = 0;
00596
00597 while (*pszCommand)
00598 {
00599 if (*pszCommand == '%')
00600 {
00601 szCmd [pos++] = '%';
00602 szCmd [pos++] = '%';
00603 }
00604 else
00605 szCmd [pos++] = *pszCommand;
00606
00607 pszCommand++;
00608 }
00609
00610 szCmd [pos] = 0;
00611 pszCommand = szCmd;
00612 }
00613
00614 return ::FtpCommand (hConnect, fExpectResponse, dwFlags, pszCommand, dwContext, phFtpCommand);
00615 }