Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1348 lines
32 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: xfer.cxx
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "precomp.h"
  11. #include <irmonftp.h>
  12. error_status_t
  13. MapWinsockErrorToWin32(
  14. error_status_t status
  15. );
  16. DWORD
  17. MdWork(
  18. WCHAR *arg
  19. );
  20. DWORD
  21. ReportFileError( DWORD mc,
  22. WCHAR * file,
  23. DWORD error
  24. )
  25. {
  26. DWORD dwEventStatus = 0;
  27. EVENT_LOG EventLog(WS_EVENT_SOURCE,&dwEventStatus);
  28. if (!dwEventStatus)
  29. {
  30. TCHAR ErrorDescription[ERROR_DESCRIPTION_LENGTH];
  31. if (!FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS |
  32. FORMAT_MESSAGE_FROM_SYSTEM,
  33. 0, // ignored
  34. error,
  35. 0, // try default language ids
  36. ErrorDescription,
  37. ERROR_DESCRIPTION_LENGTH,
  38. 0 // ignored
  39. ))
  40. {
  41. //
  42. // could not format the message just use the error value
  43. //
  44. StringCbPrintf(ErrorDescription, sizeof(ErrorDescription), L"0x%x", error);
  45. }
  46. WCHAR * Strings[2];
  47. Strings[0] = file;
  48. Strings[1] = ErrorDescription;
  49. dwEventStatus = EventLog.ReportError(CAT_IRXFER, mc, 2, Strings);
  50. }
  51. return dwEventStatus;
  52. }
  53. FILE_TRANSFER::FILE_TRANSFER( )
  54. {
  55. _refs = 1;
  56. _event = 0;
  57. _socket = INVALID_SOCKET;
  58. _cookie = 0;
  59. m_StopListening=FALSE;
  60. // for sock.c
  61. _fWriteable = FALSE;
  62. // for xfer.c
  63. _dataFileRecv.hFile = INVALID_HANDLE_VALUE;
  64. // for progress.c
  65. _fCancelled = FALSE;
  66. _fInUiReceiveList = FALSE;
  67. _CurrentPercentage = 0;
  68. _files = 0;
  69. _dataXferRecv.dwFileSent = 0;
  70. DbgLog2(SEV_INFO, "[0] %p: refs = %d\n", this, _refs);
  71. }
  72. FILE_TRANSFER::~FILE_TRANSFER()
  73. {
  74. if (_socket != INVALID_SOCKET) {
  75. //
  76. // Drain any remaining receive data to ensure our sent data is sent across the link.
  77. //
  78. closesocket( _socket );
  79. _socket = INVALID_SOCKET;
  80. }
  81. if (_event) {
  82. CloseHandle( _event );
  83. _event = 0;
  84. }
  85. if (_fInUiReceiveList) {
  86. _ReceiveFinished( rpcBinding, _cookie, 0 );
  87. }
  88. delete [] _files;
  89. DeleteCriticalSection(&m_Lock);
  90. }
  91. unsigned long __stdcall
  92. SendFilesWrapper( PVOID arg )
  93. {
  94. PFILE_TRANSFER(arg)->Send();
  95. return 0;
  96. }
  97. void
  98. FILE_TRANSFER::BeginSend(
  99. DWORD DeviceId,
  100. OBEX_DEVICE_TYPE DeviceType,
  101. error_status_t * pStatus,
  102. FAILURE_LOCATION * pLocation
  103. )
  104. {
  105. DWORD status;
  106. DWORD dwFiles = 0L;
  107. DWORD dwFolders = 0L;
  108. __int64 dwTotalSize = 0L;
  109. status = _GetObjListStats( _files, &dwFiles, &dwFolders, &dwTotalSize );
  110. if (status) {
  111. *pLocation = locFileOpen;
  112. goto lExit;
  113. }
  114. if (( 0 == dwFiles) && (0 == dwFolders )) {
  115. goto lExit; // nothing to send
  116. }
  117. status = Sock_EstablishConnection( DeviceId,DeviceType );
  118. if ( status ) {
  119. *pLocation = locConnect;
  120. goto lExit;
  121. }
  122. _dataXferRecv.dwTotalSize = (DWORD) dwTotalSize;
  123. DWORD ThreadId;
  124. HANDLE ThreadHandle;
  125. ThreadHandle = CreateThread( 0,
  126. 0,
  127. SendFilesWrapper,
  128. this,
  129. 0,
  130. &ThreadId
  131. );
  132. if (!ThreadHandle) {
  133. *pLocation = locStartup;
  134. status = GetLastError();
  135. goto lExit;
  136. }
  137. CloseHandle( ThreadHandle );
  138. lExit:
  139. if (status) {
  140. DecrementRefCount();
  141. }
  142. *pStatus = status;
  143. }
  144. void
  145. FILE_TRANSFER::Send()
  146. {
  147. error_status_t status = 0;
  148. wchar_t * szObj=L"";
  149. ULONG64 dwTotalSize=_dataXferRecv.dwTotalSize;
  150. //
  151. // Avoid idle-time shutdowns. If the call fails, we want to continue anyway.
  152. //
  153. SetThreadExecutionState( ES_SYSTEM_REQUIRED | ES_CONTINUOUS );
  154. status = Obex_Connect( dwTotalSize );
  155. if (status == ERROR_SUCCESS) {
  156. _Send_StartXfer( dwTotalSize, 0 );
  157. //
  158. // send the files one at a time
  159. //
  160. for( szObj = _files; *szObj != 0; szObj += lstrlen(szObj)+1 ) {
  161. DbgLog1( SEV_INFO, "Sending %S", szObj );
  162. _UpdateSendProgress( rpcBinding,
  163. _cookie,
  164. szObj,
  165. _dataXferRecv.dwTotalSize,
  166. _completedFilesSize,
  167. &status
  168. );
  169. if ( DirectoryExists(szObj) ) {
  170. status = _SendFolder( szObj );
  171. } else {
  172. status = _SendFile( szObj );
  173. }
  174. if ((status !=ERROR_SUCCESS) || g_fShutdown) {
  175. break;
  176. }
  177. }
  178. }
  179. //
  180. // Re-enable idle-time shutdowns.
  181. //
  182. SetThreadExecutionState( ES_CONTINUOUS );
  183. //
  184. // Make sure we show 100% for a completed transfer.
  185. //
  186. if (!status) {
  187. _UpdateSendProgress( rpcBinding,
  188. _cookie,
  189. _dataFileRecv.szFileName,
  190. _dataXferRecv.dwTotalSize,
  191. _dataXferRecv.dwTotalSize,
  192. &status
  193. );
  194. }
  195. if (status != ERROR_CANCELLED) {
  196. //
  197. // don't overwrite the error unless there isn't one
  198. //
  199. error_status_t errTemp;
  200. _Send_EndXfer();
  201. errTemp = Obex_Disconnect( status );
  202. if ( !status ) {
  203. status = errTemp;
  204. }
  205. }
  206. if ( status != ERROR_SUCCESS ) {
  207. // status = MapWinsockErrorToWin32( status );
  208. _OneSendFileFailed( rpcBinding, _cookie, szObj, status, locFileSend, &status );
  209. }
  210. _SendComplete( rpcBinding, _cookie, _dataXferRecv.dwTotalSent, &status );
  211. RemoveFromTransferList(this);
  212. DecrementRefCount();
  213. }
  214. error_status_t
  215. MapWinsockErrorToWin32(
  216. error_status_t status
  217. )
  218. {
  219. if (status)
  220. {
  221. DbgLog2(SEV_ERROR, "mapping error 0x%x (%d)", status, status);
  222. }
  223. if (status < WSABASEERR || status > WSABASEERR + 1000)
  224. {
  225. return status;
  226. }
  227. switch (status)
  228. {
  229. case WSAECONNREFUSED:
  230. return ERROR_CONNECTION_REFUSED;
  231. default:
  232. return ERROR_REQUEST_ABORTED;
  233. }
  234. }
  235. error_status_t
  236. _GetObjListStats(
  237. LPWSTR lpszObjList,
  238. LPDWORD lpdwFiles,
  239. LPDWORD lpdwFolders,
  240. __int64 * lpdwTotalSize
  241. )
  242. {
  243. error_status_t status = 0;
  244. LPWSTR szObj;
  245. HANDLE hFile;
  246. // get (a) number of files, (b) total file size
  247. //
  248. for( szObj = lpszObjList; *szObj != 0; szObj += lstrlen(szObj)+1 ) {
  249. hFile = CreateFile(
  250. szObj,
  251. GENERIC_READ,
  252. FILE_SHARE_READ,
  253. NULL,
  254. OPEN_EXISTING,
  255. FILE_ATTRIBUTE_NORMAL,
  256. NULL
  257. );
  258. if( INVALID_HANDLE_VALUE == hFile ) {
  259. // if it's a directory, get the total size of its files
  260. if( DirectoryExists(szObj) ) {
  261. *lpdwTotalSize += GetDirectorySize( szObj );
  262. (*lpdwFolders)++;
  263. continue;
  264. } else {
  265. DbgLog2(SEV_ERROR, "open file \'%S\' failed %d", szObj, GetLastError());
  266. ReportFileError( MC_IRXFER_OPEN_FAILED, szObj, GetLastError() );
  267. return GetLastError();
  268. }
  269. }
  270. *lpdwTotalSize += GetFileSize( hFile, NULL );
  271. (*lpdwFiles)++;
  272. CloseHandle( hFile );
  273. }
  274. return 0;
  275. }
  276. BOOL
  277. FILE_TRANSFER::Xfer_Init(
  278. wchar_t * files,
  279. unsigned length,
  280. OBEX_DIALECT dialect,
  281. OBEX_DEVICE_TYPE DeviceType,
  282. BOOL CreateSocket,
  283. SOCKET ListenSocket
  284. )
  285. {
  286. unsigned Timeout = 500;
  287. DWORD status = 0;
  288. m_ListenSocket=ListenSocket;
  289. _dialect = dialect;
  290. InitializeCriticalSection(&m_Lock);
  291. if (length)
  292. {
  293. _xferType = xferSEND;
  294. _files = new wchar_t[ length ];
  295. if (!_files)
  296. {
  297. goto cleanup;
  298. }
  299. memcpy(_files, files, sizeof(wchar_t) * length );
  300. }
  301. else
  302. {
  303. _xferType = xferRECV;
  304. _files = 0;
  305. }
  306. _dataXferRecv.fXferInProgress = FALSE;
  307. m_DeviceType=DeviceType;
  308. if (CreateSocket) {
  309. if (DeviceType == TYPE_IRDA) {
  310. _socket = socket( AF_IRDA, SOCK_STREAM, 0);
  311. } else {
  312. _socket = socket( AF_INET, SOCK_STREAM, 0);
  313. }
  314. if (!_socket) {
  315. goto cleanup;
  316. }
  317. setsockopt( _socket, SOL_SOCKET, SO_RCVTIMEO, (char *) &Timeout, sizeof(Timeout));
  318. } else {
  319. _socket = INVALID_SOCKET;
  320. }
  321. _event = CreateEvent( NULL, // no security
  322. TRUE, // manual-reset
  323. FALSE, // initially not set
  324. NULL // no name
  325. );
  326. if (!_event)
  327. {
  328. goto cleanup;
  329. }
  330. _state = BLANK;
  331. _guard = GUARD_MAGIC;
  332. if ( !Obex_Init())
  333. {
  334. goto cleanup;
  335. }
  336. return TRUE;
  337. cleanup:
  338. if (_files != NULL) {
  339. delete _files;
  340. _files=NULL;
  341. }
  342. if (_socket != INVALID_SOCKET ) {
  343. closesocket( _socket );
  344. _socket=INVALID_SOCKET;
  345. }
  346. if (_event != NULL) {
  347. CloseHandle( _event );
  348. _event=NULL;
  349. }
  350. return FALSE;
  351. }
  352. error_status_t
  353. FILE_TRANSFER::Xfer_ConnStart()
  354. {
  355. _uObjsReceived = 0;
  356. _dataXferRecv.fXferInProgress = TRUE;
  357. _dataXferRecv.dwTotalSize = 0;
  358. _dataXferRecv.dwTotalSent = 0;
  359. return _SetReceiveFolder( NULL );
  360. }
  361. VOID FILE_TRANSFER::Xfer_ConnEnd( VOID )
  362. {
  363. _dataXferRecv.fXferInProgress = FALSE;
  364. }
  365. error_status_t
  366. FILE_TRANSFER::Xfer_SetPath(
  367. LPWSTR szPath
  368. )
  369. {
  370. error_status_t status = 0;
  371. if( !szPath || lstrlen(szPath) == 0 )
  372. {
  373. // set default receive folder
  374. return _SetReceiveFolder( NULL );
  375. }
  376. if( lstrcmp(szPath, szPREVDIR) == 0 )
  377. {
  378. // pop up a level
  379. WCHAR sz[MAX_PATH];
  380. StringCbCopy(sz, sizeof(sz), _szRecvFolder );
  381. // remove trailing backslash
  382. if(bHasTrailingSlash(sz))
  383. sz[lstrlen(sz)-1] = cNIL;
  384. // strip last folder off path
  385. StripFile( sz );
  386. return _SetReceiveFolder( sz );
  387. }
  388. // format szPath and append it to the current receive folder
  389. WCHAR szRFF[MAX_PATH];
  390. LPWSTR lpsz;
  391. // remove preceding backslashes
  392. while( *szPath == cBACKSLASH )
  393. szPath++;
  394. // remove anything after a backslash
  395. lpsz = szPath;
  396. while( *lpsz != cNIL && *lpsz != cBACKSLASH )
  397. lpsz++;
  398. *lpsz = cNIL;
  399. StringCbCopy(szRFF, sizeof(szRFF), _szRecvFolder );
  400. GetUniqueName( szRFF, sizeof(szRFF)/sizeof(WCHAR), szPath, FALSE );
  401. _uObjsReceived++;
  402. return _SetReceiveFolder( szRFF );
  403. }
  404. VOID FILE_TRANSFER::Xfer_FileInit( VOID )
  405. {
  406. _dataXferRecv.dwFileSize = 0;
  407. _dataXferRecv.dwFileSent = 0;
  408. FillMemory( &_dataFileRecv.filetime, sizeof(_dataFileRecv.filetime), (BYTE)-1 );
  409. _dataFileRecv.szFileName[0]= TEXT('\0');
  410. _dataFileRecv.szFileSave[0]= TEXT('\0');
  411. _dataFileRecv.szFileTemp[0]= TEXT('\0');
  412. }
  413. error_status_t
  414. FILE_TRANSFER::Xfer_FileSetName( LPWSTR szName )
  415. {
  416. StringCbCopy(_dataFileRecv.szFileName, sizeof(_dataFileRecv.szFileName), szName );
  417. return _FileStart();
  418. }
  419. BOOL FILE_TRANSFER::Xfer_FileSetSize( BYTE4 b4Size )
  420. {
  421. _dataXferRecv.dwFileSize = b4Size;
  422. return ( IsRoomForFile(_dataXferRecv.dwFileSize, _szRecvFolder) );
  423. }
  424. error_status_t
  425. FILE_TRANSFER::Xfer_FileWriteBody(
  426. LPVOID lpvData,
  427. BYTE2 b2Size,
  428. BOOL fFinal
  429. )
  430. {
  431. error_status_t status = 0;
  432. DWORD dwSize = b2Size;
  433. DWORD dwBytesWritten;
  434. DbgLog1( SEV_FUNCTION, "Xfer_WriteBody: %ld bytes", dwSize );
  435. // has this file been opened yet?
  436. if( INVALID_HANDLE_VALUE == _dataFileRecv.hFile )
  437. {
  438. ASSERT( 0 );
  439. return ERROR_CANTOPEN;
  440. }
  441. // write the data to the file
  442. while( dwSize > 0 )
  443. {
  444. BOOL fRet;
  445. fRet = WriteFile( _dataFileRecv.hFile,
  446. lpvData,
  447. dwSize,
  448. &dwBytesWritten,
  449. NULL
  450. );
  451. if( !fRet )
  452. {
  453. status = GetLastError();
  454. break;
  455. }
  456. lpvData = (LPVOID)( (DWORD_PTR)lpvData + dwBytesWritten );
  457. dwSize -= dwBytesWritten;
  458. _dataXferRecv.dwTotalSent += dwBytesWritten;
  459. _dataXferRecv.dwFileSent += dwBytesWritten;
  460. }
  461. if( fFinal )
  462. {
  463. if (!status)
  464. {
  465. status = _FileEnd( TRUE );
  466. }
  467. else
  468. {
  469. _FileEnd( TRUE );
  470. }
  471. }
  472. return status;
  473. }
  474. VOID FILE_TRANSFER::Xfer_FileAbort( VOID )
  475. {
  476. _FileEnd( FALSE );
  477. }
  478. error_status_t
  479. FILE_TRANSFER::_FileStart()
  480. {
  481. WCHAR szFullPath[MAX_PATH];
  482. WCHAR szBaseFile[MAX_PATH];
  483. //
  484. // get path of file
  485. //
  486. StringCbCopy(szFullPath,sizeof(szFullPath), _szRecvFolder );
  487. //
  488. // strip path to get the base filename
  489. //
  490. StripPath(_dataFileRecv.szFileName ,szBaseFile, sizeof(szBaseFile)/sizeof(WCHAR) );
  491. GetUniqueName( szFullPath, sizeof(szFullPath)/sizeof(WCHAR), szBaseFile, TRUE );
  492. StringCbCopy(_dataFileRecv.szFileSave,sizeof(_dataFileRecv.szFileSave), szFullPath );
  493. DbgLog1( SEV_INFO, "Save file: [%S]", szFullPath );
  494. GetTempPath( sizeof(szBaseFile)/sizeof(WCHAR), szBaseFile );
  495. GetTempFileName( szBaseFile, TEMP_FILE_PREFIX, 0, szFullPath );
  496. StringCbCopy(_dataFileRecv.szFileTemp,sizeof(_dataFileRecv.szFileTemp), szFullPath );
  497. DbgLog1( SEV_INFO, "Temp file: [%S]", szFullPath );
  498. {
  499. wchar_t RFF[1+MAX_PATH];
  500. GetReceivedFilesFolder(RFF, MAX_PATH);
  501. wchar_t * PromptPath = _dataFileRecv.szFileSave + lstrlen(RFF);
  502. DbgLog2( SEV_INFO, "need to ask permission: \n new file = [%S]\n prompt file = [%S]",
  503. _dataFileRecv.szFileSave,
  504. PromptPath );
  505. error_status_t status = _GetPermission( rpcBinding, _cookie, PromptPath, FALSE );
  506. if (status)
  507. {
  508. DbgLog2( SEV_ERROR, "permission check failed, cookie %p error %d", (void *) _cookie, status );
  509. return status;
  510. }
  511. }
  512. //
  513. // Create the temporary file.
  514. //
  515. _dataFileRecv.hFile = CreateFile(
  516. szFullPath,
  517. GENERIC_WRITE,
  518. 0L,
  519. NULL,
  520. OPEN_ALWAYS,
  521. FILE_ATTRIBUTE_NORMAL,
  522. NULL
  523. );
  524. if ( INVALID_HANDLE_VALUE == _dataFileRecv.hFile )
  525. {
  526. ReportFileError( MC_IRXFER_OPEN_FAILED, szFullPath, GetLastError() );
  527. return GetLastError();
  528. }
  529. return 0;
  530. }
  531. error_status_t
  532. FILE_TRANSFER::_FileEnd( BOOL fSave )
  533. {
  534. error_status_t status = 0;
  535. // set the date stamp
  536. if( _dataFileRecv.filetime.dwLowDateTime != (DWORD)-1
  537. || _dataFileRecv.filetime.dwHighDateTime != (DWORD)-1 )
  538. {
  539. if( INVALID_HANDLE_VALUE != _dataFileRecv.hFile )
  540. SetFileTime( _dataFileRecv.hFile, NULL, NULL, &_dataFileRecv.filetime );
  541. }
  542. if( INVALID_HANDLE_VALUE != _dataFileRecv.hFile )
  543. {
  544. CloseHandle( _dataFileRecv.hFile );
  545. _dataFileRecv.hFile = INVALID_HANDLE_VALUE;
  546. }
  547. if( fSave )
  548. {
  549. _uObjsReceived++;
  550. if (!MoveFile( _dataFileRecv.szFileTemp, _dataFileRecv.szFileSave ))
  551. {
  552. status = GetLastError();
  553. ReportFileError( MC_IRXFER_MOVE_FAILED, _dataFileRecv.szFileSave, status );
  554. DbgLog3(SEV_ERROR, "%d moving %S -> %S", status, _dataFileRecv.szFileTemp, _dataFileRecv.szFileSave);
  555. }
  556. else
  557. {
  558. DbgLog2(SEV_INFO, "moved %S -> %S", _dataFileRecv.szFileTemp, _dataFileRecv.szFileSave);
  559. }
  560. }
  561. else
  562. {
  563. DeleteFile( _dataFileRecv.szFileTemp );
  564. }
  565. Xfer_FileInit();
  566. return status;
  567. }
  568. error_status_t
  569. FILE_TRANSFER::_SetReceiveFolder(
  570. LPWSTR szFolder
  571. )
  572. {
  573. error_status_t status = 0;
  574. WCHAR sz[MAX_PATH];
  575. WCHAR szFullPath[MAX_PATH] = { 0 };
  576. WCHAR* pszFilePart;
  577. DbgLog1( SEV_FUNCTION, "_SetReceiveFolder: [%S]", (szFolder?szFolder : L"NULL") );
  578. GetReceivedFilesFolder( sz, sizeof(sz) );
  579. //
  580. // Make sure the requested folder is within the root RFF, for security reasons.
  581. //
  582. if ( szFolder && lstrlen(szFolder) > 0 ) {
  583. DWORD dwLen = GetFullPathName(szFolder, MAX_PATH, szFullPath, &pszFilePart);
  584. //
  585. // normalize the path name first, so that the comparison can be meaningful
  586. //
  587. if (dwLen != 0 && dwLen < MAX_PATH) {
  588. if ( 0 == wcsncmp(sz, szFullPath, lstrlen(sz)) ) {
  589. StringCbCopy(_szRecvFolder,sizeof(_szRecvFolder), szFullPath );
  590. } else {
  591. //
  592. // can't go outside the RFF tree; use the root RFF.
  593. //
  594. StringCbCopy(_szRecvFolder,sizeof(_szRecvFolder),sz );
  595. }
  596. } else {
  597. StringCbCopy(_szRecvFolder,sizeof(_szRecvFolder),sz );
  598. }
  599. } else {
  600. StringCbCopy(_szRecvFolder,sizeof(_szRecvFolder),sz );
  601. }
  602. //
  603. // always end path with a backslash '\'
  604. //
  605. if( bNoTrailingSlash(_szRecvFolder) ) {
  606. StringCbCat(_szRecvFolder, sizeof(_szRecvFolder),szBACKSLASH );
  607. }
  608. //
  609. // Get permission to create this directory, unless we have not yet called ReceiveInProgress.
  610. // This latter will be true only during the connect. This seems harmless: a malicious
  611. // client can only create a couple of empty directories in my desktop w/o authorization.
  612. //
  613. if (_fInUiReceiveList)
  614. {
  615. wchar_t * PromptPath = _szRecvFolder + lstrlen(sz);
  616. DbgLog2( SEV_INFO, "need to ask permission: \n new dir = [%S]\n prompt dir = [%S]",
  617. _szRecvFolder,
  618. PromptPath );
  619. status = _GetPermission( rpcBinding, _cookie, PromptPath, TRUE );
  620. if (status)
  621. {
  622. DbgLog1( SEV_ERROR, "permission check failed %d", status );
  623. return status;
  624. }
  625. }
  626. DbgLog1( SEV_INFO, "Setting Receive Folder: [%S]", _szRecvFolder );
  627. if( !DirectoryExists( _szRecvFolder ) )
  628. {
  629. status = MdWork( _szRecvFolder );
  630. if (status)
  631. {
  632. ReportFileError( MC_IRXFER_CREATE_DIR_FAILED, _szRecvFolder, status );
  633. }
  634. }
  635. DbgLog1( SEV_FUNCTION, "_SetReceiveFolder leave %d", status);
  636. return status;
  637. }
  638. VOID
  639. FILE_TRANSFER::_Send_StartXfer( __int64 dwTotalSize,
  640. LPWSTR szDst
  641. )
  642. {
  643. _dataXferRecv.fXferInProgress = TRUE;
  644. _dataXferRecv.dwTotalSize = dwTotalSize;
  645. _dataXferRecv.dwTotalSent = 0;
  646. _completedFilesSize = 0;
  647. }
  648. VOID FILE_TRANSFER::_Send_EndXfer( VOID )
  649. {
  650. _dataXferRecv.fXferInProgress = FALSE;
  651. }
  652. error_status_t
  653. FILE_TRANSFER::_SendFile(
  654. LPWSTR wszFile
  655. )
  656. {
  657. error_status_t status = 0;
  658. DWORD dwFileTime = (DWORD)-1;
  659. HANDLE hFile=INVALID_HANDLE_VALUE;
  660. FILETIME filetime;
  661. DbgLog1(SEV_FUNCTION, "_SendFile( %S )", wszFile);
  662. StringCbCopy(_dataFileRecv.szFileName,sizeof(_dataFileRecv.szFileName), wszFile );
  663. hFile = CreateFileW(
  664. wszFile,
  665. GENERIC_READ,
  666. FILE_SHARE_READ,
  667. NULL,
  668. OPEN_EXISTING,
  669. FILE_ATTRIBUTE_NORMAL,
  670. NULL
  671. );
  672. if ( INVALID_HANDLE_VALUE == hFile ) {
  673. status=GetLastError();
  674. goto lExit;
  675. }
  676. if( !GetFileTime(hFile, NULL, NULL, &filetime) ) {
  677. status=GetLastError();
  678. goto lExit;
  679. }
  680. _dataXferRecv.dwFileSize = GetFileSize( hFile, NULL );
  681. _dataXferRecv.dwFileSent = 0;
  682. status = Obex_PutBegin( wszFile, _dataXferRecv.dwFileSize, &filetime );
  683. ExitOnErr( status );
  684. status = _PutFileBody( hFile, wszFile );
  685. ExitOnErr( status );
  686. _completedFilesSize += _dataXferRecv.dwFileSize;
  687. lExit:
  688. DbgLog1( SEV_FUNCTION, "_SendFile leave [%d]", status );
  689. if ( INVALID_HANDLE_VALUE != hFile ) {
  690. CloseHandle( hFile );
  691. }
  692. return status;
  693. }
  694. error_status_t
  695. FILE_TRANSFER::_SendFolder(
  696. LPWSTR wszFolder
  697. )
  698. {
  699. error_status_t status = 0;
  700. BOOL bContinue;
  701. HANDLE hFind = INVALID_HANDLE_VALUE;
  702. WCHAR wszDir[MAX_PATH];
  703. WCHAR wszSpec[MAX_PATH*2];
  704. WIN32_FIND_DATAW findData;
  705. // send this directory so it's created
  706. status = Obex_SetPath( wszFolder );
  707. ExitOnErr( status );
  708. //
  709. // get base directory ending with backslash
  710. //
  711. StringCbCopy(wszDir, sizeof(wszDir), wszFolder );
  712. if ( bNoTrailingSlash(wszDir) ) {
  713. StringCbCat(wszDir,sizeof(wszDir), szBACKSLASH );
  714. }
  715. //
  716. // form search string
  717. //
  718. StringCbCopyW(wszSpec,sizeof(wszSpec), wszDir );
  719. StringCbCatW(wszSpec,sizeof(wszSpec), L"*.*" );
  720. hFind = FindFirstFileW( wszSpec, &findData );
  721. bContinue = ( hFind != INVALID_HANDLE_VALUE );
  722. while( bContinue ) {
  723. WCHAR wszObj[MAX_PATH*2];
  724. StringCbCopy(wszObj, sizeof(wszObj), wszDir );
  725. StringCbCat(wszObj, sizeof(wszObj), findData.cFileName );
  726. if( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  727. // weed out "." and ".."
  728. if (0 != lstrcmp(findData.cFileName, szPERIOD) && 0 != lstrcmp(findData.cFileName, szPREVDIR))
  729. {
  730. status = _SendFolder( wszObj );
  731. }
  732. } else {
  733. status = _SendFile( wszObj );
  734. }
  735. if ( status ) {
  736. break;
  737. }
  738. bContinue = FindNextFileW( hFind, &findData );
  739. }
  740. // pop out of this directory
  741. {
  742. error_status_t errTemp = Obex_SetPath( NULL );
  743. // only set the error if there isn't one already
  744. if( !status )
  745. status = errTemp;
  746. }
  747. ExitOnErr( status );
  748. lExit:
  749. if ( hFind != INVALID_HANDLE_VALUE )
  750. {
  751. FindClose( hFind );
  752. }
  753. return status;
  754. }
  755. // if we have a file size of 0, we still want to write a
  756. // blank body once, hence fPutOnce
  757. error_status_t
  758. FILE_TRANSFER::_PutFileBody( HANDLE hFile, wchar_t FileName[] )
  759. {
  760. error_status_t status = 0;
  761. BOOL fPutOnce = FALSE;
  762. DWORD dwRead;
  763. BYTE1 b1Send[cbSOCK_BUFFER_SIZE];
  764. DWORD Extra = sizeof(b1Send) % (_dataRecv.b2MaxPacket-16);
  765. DbgLog( SEV_FUNCTION, "_PutFileBody" );
  766. while( !status && !g_fShutdown)
  767. {
  768. BOOL fRet = ReadFile(
  769. hFile,
  770. b1Send,
  771. sizeof(b1Send) - Extra,
  772. &dwRead,
  773. NULL
  774. );
  775. if( !fRet )
  776. return GetLastError();
  777. if( dwRead == 0 && fPutOnce )
  778. break;
  779. _dataXferRecv.dwTotalSent += dwRead;
  780. _dataXferRecv.dwFileSent += dwRead;
  781. // NOTE: casting dwRead from 4 bytes to 2 bytes requires
  782. // cbSOCK_BUFFER_SIZE to fit into 2 bytes
  783. status = Obex_PutBody( FileName,
  784. b1Send,
  785. (BYTE2)dwRead,
  786. _dataXferRecv.dwFileSent == _dataXferRecv.dwFileSize
  787. );
  788. fPutOnce = TRUE;
  789. }
  790. DbgLog1( SEV_FUNCTION, "_PutFileBody leave [%d]", status );
  791. return status;
  792. }
  793. VOID FILE_TRANSFER::Xfer_SetSize( BYTE4 b4Size )
  794. {
  795. _dataXferRecv.dwTotalSize = b4Size;
  796. }
  797. void
  798. FILE_TRANSFER::RecordDeviceName(
  799. SOCKADDR_IRDA * s
  800. )
  801. {
  802. char buffer[sizeof(DEVICELIST) + 8*sizeof(IRDA_DEVICE_INFO)];
  803. DEVICELIST * list = (DEVICELIST *) buffer;
  804. int size = sizeof(buffer);
  805. if (SOCKET_ERROR == getsockopt( _socket, SOL_IRLMP, IRLMP_ENUMDEVICES, buffer, &size)) {
  806. StringCbCopy(_DeviceName,sizeof(_DeviceName), g_UnknownDeviceName );
  807. return;
  808. }
  809. for (unsigned i=0; i < list->numDevice; ++i) {
  810. if (0 == memcmp(list->Device[i].irdaDeviceID, s->irdaDeviceID, sizeof(s->irdaDeviceID))) {
  811. UCHAR TempBuffer[sizeof(list->Device[i].irdaDeviceName)+3];
  812. unsigned MaxCharCount;
  813. //
  814. // zero out the whole buffer and then copy the string from the device to make sure it
  815. // is null terminated
  816. //
  817. ZeroMemory(&TempBuffer[0],sizeof(TempBuffer));
  818. CopyMemory(&TempBuffer[0],list->Device[i].irdaDeviceName,sizeof(list->Device[i].irdaDeviceName));
  819. //
  820. // get the character count of unicode destination buffer
  821. //
  822. MaxCharCount = sizeof(_DeviceName)/sizeof(wchar_t);
  823. if (list->Device[i].irdaCharSet != LmCharSetUNICODE) {
  824. MultiByteToWideChar(CP_ACP, 0,
  825. (LPCSTR)&TempBuffer[0],
  826. -1, // NULL terminated string
  827. _DeviceName,
  828. MaxCharCount
  829. );
  830. } else {
  831. //
  832. // the name is in unicode
  833. //
  834. StringCbCopy( _DeviceName,
  835. sizeof(_DeviceName),
  836. (wchar_t *)&TempBuffer[0]
  837. );
  838. }
  839. return;
  840. }
  841. }
  842. StringCbCopy(_DeviceName,sizeof(_DeviceName), g_UnknownDeviceName );
  843. }
  844. //
  845. // Code that I took from CMD.EXE
  846. //
  847. #define COLON ':'
  848. #define NULLC '\0'
  849. #define BSLASH '\\'
  850. BOOL IsValidDrv(TCHAR drv);
  851. /**************** START OF SPECIFICATIONS ***********************/
  852. /* */
  853. /* SUBROUTINE NAME: MdWork */
  854. /* */
  855. /* DESCRIPTIVE NAME: Make a directory */
  856. /* */
  857. /* FUNCTION: MdWork creates a new directory. */
  858. /* */
  859. /* INPUT: arg - a pointer to a NULL terminated string of the */
  860. /* new directory to create. */
  861. /* */
  862. /* EXIT-NORMAL: returns zero if the directory is made */
  863. /* successfully */
  864. /* */
  865. /* EXIT-ERROR: returns an error code otherwise */
  866. /* */
  867. /* EFFECTS: None. */
  868. /* */
  869. /**************** END OF SPECIFICATIONS *************************/
  870. DWORD
  871. MdWork(
  872. WCHAR *arg
  873. )
  874. {
  875. ULONG Status;
  876. WCHAR *lpw;
  877. WCHAR TempBuffer[MAX_PATH];
  878. /* Check if drive is valid because Dosmkdir does not
  879. return invalid drive @@5 */
  880. if ((arg[1] == COLON) && !IsValidDrv(*arg))
  881. {
  882. return ERROR_INVALID_DRIVE;
  883. }
  884. if (!GetFullPathName(arg, MAX_PATH, TempBuffer, &lpw))
  885. {
  886. return GetLastError();
  887. }
  888. if (CreateDirectory( arg, NULL ))
  889. {
  890. return 0;
  891. }
  892. Status = GetLastError();
  893. if (Status == ERROR_ALREADY_EXISTS)
  894. {
  895. return 0;
  896. }
  897. else if (Status != ERROR_PATH_NOT_FOUND)
  898. {
  899. return Status;
  900. }
  901. //
  902. // loop over input path and create any needed intermediary directories.
  903. //
  904. // Find the point in the string to begin the creation. Note, for UNC
  905. // names, we must skip the machine and the share
  906. //
  907. if (TempBuffer[1] == COLON) {
  908. //
  909. // Skip D:\
  910. //
  911. lpw = TempBuffer+3;
  912. } else if (TempBuffer[0] == BSLASH && TempBuffer[1] == BSLASH) {
  913. //
  914. // Skip \\server\share\
  915. //
  916. lpw = TempBuffer+2;
  917. while (*lpw && *lpw != BSLASH) {
  918. lpw++;
  919. }
  920. if (*lpw) {
  921. lpw++;
  922. }
  923. while (*lpw && *lpw != BSLASH) {
  924. lpw++;
  925. }
  926. if (*lpw) {
  927. lpw++;
  928. }
  929. } else {
  930. //
  931. // For some reason, GetFullPath has given us something we can't understand
  932. //
  933. return ERROR_CANNOT_MAKE;
  934. }
  935. //
  936. // Walk through the components creating them
  937. //
  938. while (*lpw) {
  939. //
  940. // Move forward until the next path separator
  941. //
  942. while (*lpw && *lpw != BSLASH) {
  943. lpw++;
  944. }
  945. //
  946. // If we've encountered a path character, then attempt to
  947. // make the given path.
  948. //
  949. if (*lpw == BSLASH) {
  950. *lpw = NULLC;
  951. if (!CreateDirectory( TempBuffer, NULL )) {
  952. Status = GetLastError();
  953. if (Status != ERROR_ALREADY_EXISTS) {
  954. return ERROR_CANNOT_MAKE;
  955. }
  956. }
  957. *lpw++ = BSLASH;
  958. }
  959. }
  960. if (!CreateDirectory( TempBuffer, NULL )) {
  961. Status = GetLastError( );
  962. if (Status != ERROR_ALREADY_EXISTS) {
  963. return Status;
  964. }
  965. }
  966. return 0;
  967. }
  968. /*** IsValidDrv - Check drive validity
  969. *
  970. * Purpose:
  971. * Check validity of passed drive letter.
  972. *
  973. * int IsValidDrv(WCHAR drv)
  974. *
  975. * Args:
  976. * drv - The letter of the drive to check
  977. *
  978. * Returns:
  979. * TRUE if drive is valid
  980. * FALSE if not
  981. *
  982. * Notes:
  983. *
  984. */
  985. BOOL
  986. IsValidDrv(WCHAR drv)
  987. {
  988. WCHAR temp[4];
  989. temp[ 0 ] = drv;
  990. temp[ 1 ] = COLON;
  991. temp[ 2 ] = BSLASH;
  992. temp[ 3 ] = NULLC;
  993. //
  994. // return of 0 or 1 mean can't determine or root
  995. // does not exists.
  996. //
  997. if (GetDriveType(temp) <= 1)
  998. return( FALSE );
  999. else {
  1000. return( TRUE );
  1001. }
  1002. }