/branch/1.0.1.1/FtpConnection.cs

# · C# · 560 lines · 476 code · 75 blank · 9 comment · 93 complexity · e6dd343c16cf457993c9ea599f8fb790 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. using System.ComponentModel;
  6. using System.Runtime.InteropServices;
  7. namespace FtpLib
  8. {
  9. public class FtpConnection : IDisposable
  10. {
  11. public FtpConnection(string host)
  12. {
  13. _host = host;
  14. }
  15. public FtpConnection(string host, int port)
  16. {
  17. _host = host;
  18. _port = port;
  19. }
  20. public FtpConnection(string host, string username, string password)
  21. {
  22. _host = host;
  23. _username = username;
  24. _password = password;
  25. }
  26. public FtpConnection(string host, int port, string username, string password)
  27. {
  28. _host = host;
  29. _port = port;
  30. _username = username;
  31. _password = password;
  32. }
  33. public void Open()
  34. {
  35. _hInternet = WININET.InternetOpen(
  36. System.Environment.UserName,
  37. WININET.INTERNET_OPEN_TYPE_PRECONFIG,
  38. null,
  39. null,
  40. WININET.INTERNET_FLAG_SYNC);
  41. if (_hInternet == IntPtr.Zero)
  42. {
  43. Error();
  44. }
  45. }
  46. public void Login()
  47. {
  48. Login(_username, _password);
  49. }
  50. public void Login(string username, string password)
  51. {
  52. _hConnect = WININET.InternetConnect(_hInternet,
  53. _host,
  54. _port,
  55. username,
  56. password,
  57. WININET.INTERNET_SERVICE_FTP,
  58. WININET.INTERNET_FLAG_PASSIVE,
  59. IntPtr.Zero);
  60. if (_hConnect == IntPtr.Zero)
  61. {
  62. Error();
  63. }
  64. }
  65. public void SetCurrentDirectory(string directory)
  66. {
  67. int ret = WININET.FtpSetCurrentDirectory(
  68. _hConnect,
  69. directory);
  70. if (ret == 0)
  71. {
  72. Error();
  73. }
  74. }
  75. public void SetLocalDirectory(string directory)
  76. {
  77. if(Directory.Exists(directory))
  78. System.Environment.CurrentDirectory = directory;
  79. else
  80. throw new InvalidDataException(String.Format("{0} is not a directory!", directory));
  81. }
  82. public string GetCurrentDirectory()
  83. {
  84. int buffLength = WINAPI.MAX_PATH + 1;
  85. StringBuilder str = new StringBuilder(buffLength);
  86. int ret = WININET.FtpGetCurrentDirectory(_hConnect, str, ref buffLength);
  87. if (ret == 0)
  88. {
  89. Error();
  90. return null;
  91. }
  92. return str.ToString();
  93. }
  94. public FtpDirectoryInfo GetCurrentDirectoryInfo()
  95. {
  96. string dir = GetCurrentDirectory();
  97. return new FtpDirectoryInfo(this, dir);
  98. }
  99. public void GetFile(string remoteFile, bool failIfExists)
  100. {
  101. GetFile(remoteFile, remoteFile, failIfExists);
  102. }
  103. public void GetFile(string remoteFile, string localFile, bool failIfExists)
  104. {
  105. int ret = WININET.FtpGetFile(_hConnect,
  106. remoteFile,
  107. localFile,
  108. failIfExists,
  109. WINAPI.FILE_ATTRIBUTE_NORMAL,
  110. WININET.FTP_TRANSFER_TYPE_BINARY,
  111. IntPtr.Zero);
  112. if (ret == 0)
  113. {
  114. Error();
  115. }
  116. }
  117. public void PutFile(string fileName)
  118. {
  119. PutFile(fileName, Path.GetFileName(fileName));
  120. }
  121. public void PutFile(string localFile, string remoteFile)
  122. {
  123. int ret = WININET.FtpPutFile(_hConnect,
  124. localFile,
  125. remoteFile,
  126. WININET.FTP_TRANSFER_TYPE_BINARY,
  127. IntPtr.Zero);
  128. if (ret == 0)
  129. {
  130. Error();
  131. }
  132. }
  133. public void RenameFile(string existingFile, string newFile)
  134. {
  135. int ret = WININET.FtpRenameFile(_hConnect, existingFile, newFile);
  136. if (ret == 0)
  137. Error();
  138. }
  139. public void RemoveFile(string fileName)
  140. {
  141. int ret = WININET.FtpDeleteFile(_hConnect, fileName);
  142. if (ret == 0)
  143. {
  144. Error();
  145. }
  146. }
  147. public void RemoveDirectory(string directory)
  148. {
  149. int ret = WININET.FtpRemoveDirectory(_hConnect, directory);
  150. if (ret == 0)
  151. Error();
  152. }
  153. /// <summary>
  154. /// List all files and directories in the current working directory.
  155. /// </summary>
  156. /// <returns>A list of file and directory names.</returns>
  157. [Obsolete("Use GetFiles or GetDirectories instead.")]
  158. public List<string> List()
  159. {
  160. return List(null, false);
  161. }
  162. /// <summary>
  163. /// Provides backwards compatibility
  164. /// </summary>
  165. /// <param name="mask">The file mask used in the search.</param>
  166. /// <returns>A list of file matching the mask.</returns>
  167. [Obsolete("Use GetFiles or GetDirectories instead.")]
  168. public List<string> List(string mask)
  169. {
  170. return List(mask, false);
  171. }
  172. [Obsolete("Will be removed in later releases.")]
  173. private List<string> List(bool onlyDirectories)
  174. {
  175. return List(null, onlyDirectories);
  176. }
  177. [Obsolete("Will be removed in later releases.")]
  178. private List<string> List(string mask, bool onlyDirectories)
  179. {
  180. WINAPI.WIN32_FIND_DATA findData = new WINAPI.WIN32_FIND_DATA();
  181. IntPtr hFindFile = WININET.FtpFindFirstFile(
  182. _hConnect,
  183. mask,
  184. ref findData,
  185. WININET.INTERNET_FLAG_NO_CACHE_WRITE,
  186. IntPtr.Zero);
  187. try
  188. {
  189. List<string> files = new List<string>();
  190. if (hFindFile == IntPtr.Zero)
  191. {
  192. if (Marshal.GetLastWin32Error() == WINAPI.ERROR_NO_MORE_FILES)
  193. {
  194. return files;
  195. }
  196. else
  197. {
  198. Error();
  199. return files;
  200. }
  201. }
  202. if (onlyDirectories && (findData.dfFileAttributes & WINAPI.FILE_ATTRIBUTE_DIRECTORY) == WINAPI.FILE_ATTRIBUTE_DIRECTORY)
  203. {
  204. files.Add(new string(findData.fileName).TrimEnd('\0'));
  205. }
  206. else if (!onlyDirectories)
  207. {
  208. files.Add(new string(findData.fileName).TrimEnd('\0'));
  209. }
  210. findData = new WINAPI.WIN32_FIND_DATA();
  211. while (WININET.InternetFindNextFile(hFindFile, ref findData) != 0)
  212. {
  213. if (onlyDirectories && (findData.dfFileAttributes & WINAPI.FILE_ATTRIBUTE_DIRECTORY) == WINAPI.FILE_ATTRIBUTE_DIRECTORY)
  214. {
  215. files.Add(new string(findData.fileName).TrimEnd('\0'));
  216. }
  217. else if (!onlyDirectories)
  218. {
  219. files.Add(new string(findData.fileName).TrimEnd('\0'));
  220. }
  221. findData = new WINAPI.WIN32_FIND_DATA();
  222. }
  223. if (Marshal.GetLastWin32Error() != WINAPI.ERROR_NO_MORE_FILES)
  224. Error();
  225. return files;
  226. }
  227. finally
  228. {
  229. if(hFindFile != IntPtr.Zero)
  230. WININET.InternetCloseHandle(hFindFile);
  231. }
  232. }
  233. public FtpFileInfo[] GetFiles()
  234. {
  235. return GetFiles(GetCurrentDirectory());
  236. }
  237. public FtpFileInfo[] GetFiles(string mask)
  238. {
  239. WINAPI.WIN32_FIND_DATA findData = new WINAPI.WIN32_FIND_DATA();
  240. IntPtr hFindFile = WININET.FtpFindFirstFile(
  241. _hConnect,
  242. mask,
  243. ref findData,
  244. WININET.INTERNET_FLAG_NO_CACHE_WRITE,
  245. IntPtr.Zero);
  246. try
  247. {
  248. List<FtpFileInfo> files = new List<FtpFileInfo>();
  249. if (hFindFile == IntPtr.Zero)
  250. {
  251. if (Marshal.GetLastWin32Error() == WINAPI.ERROR_NO_MORE_FILES)
  252. {
  253. return files.ToArray();
  254. }
  255. else
  256. {
  257. Error();
  258. return files.ToArray();
  259. }
  260. }
  261. if ((findData.dfFileAttributes & WINAPI.FILE_ATTRIBUTE_DIRECTORY) != WINAPI.FILE_ATTRIBUTE_DIRECTORY)
  262. {
  263. FtpFileInfo file = new FtpFileInfo(this, new string(findData.fileName).TrimEnd('\0'));
  264. file.LastAccessTime = findData.ftLastAccessTime.ToDateTime();
  265. file.LastWriteTime = findData.ftLastWriteTime.ToDateTime();
  266. file.CreationTime = findData.ftCreationTime.ToDateTime();
  267. file.Attributes = (FileAttributes)findData.dfFileAttributes;
  268. files.Add(file);
  269. }
  270. findData = new WINAPI.WIN32_FIND_DATA();
  271. while (WININET.InternetFindNextFile(hFindFile, ref findData) != 0)
  272. {
  273. if ((findData.dfFileAttributes & WINAPI.FILE_ATTRIBUTE_DIRECTORY) != WINAPI.FILE_ATTRIBUTE_DIRECTORY)
  274. {
  275. FtpFileInfo file = new FtpFileInfo(this, new string(findData.fileName).TrimEnd('\0'));
  276. file.LastAccessTime = findData.ftLastAccessTime.ToDateTime();
  277. file.LastWriteTime = findData.ftLastWriteTime.ToDateTime();
  278. file.CreationTime = findData.ftCreationTime.ToDateTime();
  279. file.Attributes = (FileAttributes)findData.dfFileAttributes;
  280. files.Add(file);
  281. }
  282. findData = new WINAPI.WIN32_FIND_DATA();
  283. }
  284. if (Marshal.GetLastWin32Error() != WINAPI.ERROR_NO_MORE_FILES)
  285. Error();
  286. return files.ToArray();
  287. }
  288. finally
  289. {
  290. if (hFindFile != IntPtr.Zero)
  291. WININET.InternetCloseHandle(hFindFile);
  292. }
  293. }
  294. public FtpDirectoryInfo[] GetDirectories()
  295. {
  296. return GetDirectories(this.GetCurrentDirectory());
  297. }
  298. public FtpDirectoryInfo[] GetDirectories(string path)
  299. {
  300. WINAPI.WIN32_FIND_DATA findData = new WINAPI.WIN32_FIND_DATA();
  301. IntPtr hFindFile = WININET.FtpFindFirstFile(
  302. _hConnect,
  303. path,
  304. ref findData,
  305. WININET.INTERNET_FLAG_NO_CACHE_WRITE,
  306. IntPtr.Zero);
  307. try
  308. {
  309. List<FtpDirectoryInfo> directories = new List<FtpDirectoryInfo>();
  310. if (hFindFile == IntPtr.Zero)
  311. {
  312. if (Marshal.GetLastWin32Error() == WINAPI.ERROR_NO_MORE_FILES)
  313. {
  314. return directories.ToArray();
  315. }
  316. else
  317. {
  318. Error();
  319. return directories.ToArray();
  320. }
  321. }
  322. if ((findData.dfFileAttributes & WINAPI.FILE_ATTRIBUTE_DIRECTORY) == WINAPI.FILE_ATTRIBUTE_DIRECTORY)
  323. {
  324. FtpDirectoryInfo dir = new FtpDirectoryInfo(this, new string(findData.fileName).TrimEnd('\0'));
  325. dir.LastAccessTime = findData.ftLastAccessTime.ToDateTime();
  326. dir.LastWriteTime = findData.ftLastWriteTime.ToDateTime();
  327. dir.CreationTime = findData.ftCreationTime.ToDateTime();
  328. dir.Attributes = (FileAttributes)findData.dfFileAttributes;
  329. directories.Add(dir);
  330. }
  331. findData = new WINAPI.WIN32_FIND_DATA();
  332. while (WININET.InternetFindNextFile(hFindFile, ref findData) != 0)
  333. {
  334. if ((findData.dfFileAttributes & WINAPI.FILE_ATTRIBUTE_DIRECTORY) == WINAPI.FILE_ATTRIBUTE_DIRECTORY)
  335. {
  336. FtpDirectoryInfo dir = new FtpDirectoryInfo(this, new string(findData.fileName).TrimEnd('\0'));
  337. dir.LastAccessTime = findData.ftLastAccessTime.ToDateTime();
  338. dir.LastWriteTime = findData.ftLastWriteTime.ToDateTime();
  339. dir.CreationTime = findData.ftCreationTime.ToDateTime();
  340. dir.Attributes = (FileAttributes)findData.dfFileAttributes;
  341. directories.Add(dir);
  342. }
  343. findData = new WINAPI.WIN32_FIND_DATA();
  344. }
  345. if (Marshal.GetLastWin32Error() != WINAPI.ERROR_NO_MORE_FILES)
  346. Error();
  347. return directories.ToArray();
  348. }
  349. finally
  350. {
  351. if (hFindFile != IntPtr.Zero)
  352. WININET.InternetCloseHandle(hFindFile);
  353. }
  354. }
  355. public void CreateDirectory(string path)
  356. {
  357. if (WININET.FtpCreateDirectory(_hConnect, path) == 0)
  358. {
  359. Error();
  360. }
  361. }
  362. public bool DirectoryExists(string path)
  363. {
  364. WINAPI.WIN32_FIND_DATA findData = new WINAPI.WIN32_FIND_DATA();
  365. IntPtr hFindFile = WININET.FtpFindFirstFile(
  366. _hConnect,
  367. path,
  368. ref findData,
  369. WININET.INTERNET_FLAG_NO_CACHE_WRITE,
  370. IntPtr.Zero);
  371. try
  372. {
  373. if (hFindFile == IntPtr.Zero && Marshal.GetLastWin32Error() != WINAPI.ERROR_NO_MORE_FILES)
  374. {
  375. return false;
  376. }
  377. return true;
  378. }
  379. finally
  380. {
  381. if (hFindFile != IntPtr.Zero)
  382. WININET.InternetCloseHandle(hFindFile);
  383. }
  384. }
  385. public bool FileExists(string path)
  386. {
  387. WINAPI.WIN32_FIND_DATA findData = new WINAPI.WIN32_FIND_DATA();
  388. IntPtr hFindFile = WININET.FtpFindFirstFile(
  389. _hConnect,
  390. path,
  391. ref findData,
  392. WININET.INTERNET_FLAG_NO_CACHE_WRITE,
  393. IntPtr.Zero);
  394. try
  395. {
  396. if (hFindFile == IntPtr.Zero)
  397. {
  398. return false;
  399. }
  400. return true;
  401. }
  402. finally
  403. {
  404. if (hFindFile != IntPtr.Zero)
  405. WININET.InternetCloseHandle(hFindFile);
  406. }
  407. }
  408. public string SendCommand(string cmd)
  409. {
  410. int result;
  411. IntPtr dataSocket = new IntPtr();
  412. switch(cmd)
  413. {
  414. case "PASV":
  415. result = WININET.FtpCommand(_hConnect, false, WININET.FTP_TRANSFER_TYPE_ASCII, cmd, IntPtr.Zero, ref dataSocket);
  416. break;
  417. default:
  418. result = WININET.FtpCommand(_hConnect, false, WININET.FTP_TRANSFER_TYPE_ASCII, cmd, IntPtr.Zero, ref dataSocket);
  419. break;
  420. }
  421. int BUFFER_SIZE = 8192;
  422. if(result == 0){
  423. Error();
  424. }
  425. else if(dataSocket != IntPtr.Zero)
  426. {
  427. StringBuilder buffer = new StringBuilder(BUFFER_SIZE);
  428. int bytesRead = 0;
  429. do
  430. {
  431. result = WININET.InternetReadFile(dataSocket, buffer, BUFFER_SIZE, ref bytesRead);
  432. } while (result == 1 && bytesRead > 1);
  433. return buffer.ToString();
  434. }
  435. return "";
  436. }
  437. public void Close()
  438. {
  439. WININET.InternetCloseHandle(_hConnect);
  440. _hConnect = IntPtr.Zero;
  441. WININET.InternetCloseHandle(_hInternet);
  442. _hInternet = IntPtr.Zero;
  443. }
  444. private string InternetLastResponseInfo(ref int code)
  445. {
  446. int BUFFER_SIZE = 8192;
  447. StringBuilder buff = new StringBuilder(BUFFER_SIZE);
  448. WININET.InternetGetLastResponseInfo(ref code, buff, ref BUFFER_SIZE);
  449. return buff.ToString();
  450. }
  451. private void Error()
  452. {
  453. int code = Marshal.GetLastWin32Error();
  454. if (code == WININET.ERROR_INTERNET_EXTENDED_ERROR)
  455. {
  456. string errorText = InternetLastResponseInfo(ref code);
  457. throw new FtpException(code, errorText);
  458. }
  459. else
  460. {
  461. throw new Win32Exception(code);
  462. }
  463. }
  464. public int Port
  465. {
  466. get { return _port; }
  467. set { _port = value; }
  468. }
  469. private IntPtr _hInternet;
  470. private IntPtr _hConnect;
  471. private string _host;
  472. private string _username;
  473. private string _password;
  474. private int _port = WININET.INTERNET_DEFAULT_FTP_PORT;
  475. #region IDisposable Members
  476. public void Dispose()
  477. {
  478. if(_hConnect != IntPtr.Zero)
  479. WININET.InternetCloseHandle(_hConnect);
  480. if(_hInternet != IntPtr.Zero)
  481. WININET.InternetCloseHandle(_hInternet);
  482. }
  483. #endregion
  484. }
  485. }