/branch/1.0.0.0/FtpConnection.cs

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