PageRenderTime 51ms CodeModel.GetById 36ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/Visual Studio 2008/CSFTPDownload/FTPFileSystem.cs

#
C# | 319 lines | 138 code | 62 blank | 119 comment | 37 complexity | 4630abaa43d02a0beb5a772c7e81cd13 MD5 | raw file
  1/****************************** Module Header ******************************\
  2* Module Name:  FTPFileSystem.cs
  3* Project:	    CSFTPDownload
  4* Copyright (c) Microsoft Corporation.
  5* 
  6* The class FTPFileSystem represents a file on the remote FTP server. When run
  7* the FTP LIST protocol method to get a detailed listing of the files on an 
  8* FTP server, the server will response many records of information. Each record
  9* represents a file. Depended on the FTP Directory Listing Style of the server,
 10* the record is like 
 11* 1. MSDOS
 12*    1.1. Directory
 13*         12-13-10  12:41PM  <DIR>  Folder A
 14*    1.2. File
 15*         12-13-10  12:41PM  [Size] File B  
 16*         
 17*   NOTE: The date segment is like "12-13-10" instead of "12-13-2010" if Four-digit
 18*         years is not checked in IIS.
 19*        
 20* 2. UNIX
 21*    2.1. Directory
 22*         drwxrwxrwx 1 owner group 0 Dec 1 12:00 Folder A
 23*    2.2. File
 24*         -rwxrwxrwx 1 owner group [Size] Dec 1 12:00 File B
 25* 
 26*    NOTE: The date segment does not contains year.
 27* 
 28* 
 29* This source is subject to the Microsoft Public License.
 30* See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
 31* All other rights reserved.
 32* 
 33* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 34* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 35* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 36\***************************************************************************/
 37
 38using System;
 39using System.Text.RegularExpressions;
 40using System.Text;
 41
 42namespace CSFTPDownload
 43{
 44
 45    public class FTPFileSystem
 46    {
 47        /// <summary>
 48        /// The original record string.
 49        /// </summary>
 50        public string OriginalRecordString { get; set; }
 51
 52        /// <summary>
 53        /// MSDOS or UNIX.
 54        /// </summary>
 55        public FTPDirectoryListingStyle DirectoryListingStyle { get; set; }
 56
 57        /// <summary>
 58        /// The server Path.
 59        /// </summary>
 60        public Uri Url { get; set; }
 61
 62        /// <summary>
 63        /// The name of this FTPFileSystem instance.
 64        /// </summary>
 65        public string Name { get; set; }
 66
 67        /// <summary>
 68        /// Specify whether this FTPFileSystem instance is a directory.
 69        /// </summary>
 70        public bool IsDirectory { get; set; }
 71
 72        /// <summary>
 73        /// The last modified time of this FTPFileSystem instance.
 74        /// </summary>
 75        public DateTime ModifiedTime { get; set; }
 76
 77        /// <summary>
 78        /// The size of this FTPFileSystem instance if it is not a directory.
 79        /// </summary>
 80        public int Size { get; set; }
 81
 82        private FTPFileSystem() { }
 83
 84        /// <summary>
 85        /// Override the method ToString() to display a more friendly message.
 86        /// </summary>
 87        public override string ToString()
 88        {
 89            return string.Format("{0}\t{1}\t\t{2}",
 90                this.ModifiedTime.ToString("yyyy-MM-dd HH:mm"),
 91                this.IsDirectory ? "<DIR>" : this.Size.ToString(),
 92                this.Name);
 93        }
 94
 95        /// <summary>
 96        /// Find out the FTP Directory Listing Style from the recordString.
 97        /// </summary>
 98        public static FTPDirectoryListingStyle GetDirectoryListingStyle(string recordString)
 99        {
100            Regex regex = new System.Text.RegularExpressions.Regex(@"^[d-]([r-][w-][x-]){3}$");
101
102            string header = recordString.Substring(0, 10);
103
104            // If the style is UNIX, then the header is like "drwxrwxrwx".
105            if (regex.IsMatch(header))
106            {
107                return FTPDirectoryListingStyle.UNIX;
108            }
109            else
110            {
111                return FTPDirectoryListingStyle.MSDOS;
112            }
113        }
114
115        /// <summary>
116        /// Get an FTPFileSystem from the recordString. 
117        /// </summary>
118        public static FTPFileSystem ParseRecordString(Uri baseUrl, string recordString, FTPDirectoryListingStyle type)
119        {
120            FTPFileSystem fileSystem = null;
121
122            if (type == FTPDirectoryListingStyle.UNIX)
123            {
124                fileSystem = ParseUNIXRecordString(recordString);
125            }
126            else
127            {
128                fileSystem = ParseMSDOSRecordString(recordString);
129            }
130
131            // Add "/" to the url if it is a directory
132            fileSystem.Url = new Uri(baseUrl, fileSystem.Name + (fileSystem.IsDirectory ? "/" : string.Empty));
133
134            return fileSystem;
135        }
136
137        /// <summary>
138        /// The recordString is like
139        /// Directory: drwxrwxrwx   1 owner    group               0 Dec 13 11:25 Folder A
140        /// File:      -rwxrwxrwx   1 owner    group               1024 Dec 13 11:25 File B
141        /// NOTE: The date segment does not contains year.
142        /// </summary>
143        static FTPFileSystem ParseUNIXRecordString(string recordString)
144        {
145            FTPFileSystem fileSystem = new FTPFileSystem();
146
147            fileSystem.OriginalRecordString = recordString.Trim();
148            fileSystem.DirectoryListingStyle = FTPDirectoryListingStyle.UNIX;
149
150            // The segments is like "drwxrwxrwx", "",  "", "1", "owner", "", "", "", 
151            // "group", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 
152            // "0", "Dec", "13", "11:25", "Folder", "A".
153            string[] segments = fileSystem.OriginalRecordString.Split(' ');
154
155            int index = 0;
156
157            // The permission segment is like "drwxrwxrwx".
158            string permissionsegment = segments[index];
159
160            // If the property start with 'd', then it means a directory.
161            fileSystem.IsDirectory = permissionsegment[0] == 'd';
162
163            // Skip the empty segments.
164            while (segments[++index] == string.Empty) { }
165
166            // Skip the directories segment.
167
168            // Skip the empty segments.
169            while (segments[++index] == string.Empty) { }
170
171            // Skip the owner segment.
172
173            // Skip the empty segments.
174            while (segments[++index] == string.Empty) { }
175
176            // Skip the group segment.
177
178            // Skip the empty segments.
179            while (segments[++index] == string.Empty) { }
180
181            // If this fileSystem is a file, then the size is larger than 0. 
182            fileSystem.Size = int.Parse(segments[index]);
183
184            // Skip the empty segments.
185            while (segments[++index] == string.Empty) { }
186
187            // The month segment.
188            string monthsegment = segments[index];
189
190            // Skip the empty segments.
191            while (segments[++index] == string.Empty) { }
192
193            // The day segment.
194            string daysegment = segments[index];
195
196            // Skip the empty segments.
197            while (segments[++index] == string.Empty) { }
198
199            // The time segment.
200            string timesegment = segments[index];
201
202            fileSystem.ModifiedTime = DateTime.Parse(string.Format("{0} {1} {2} ",
203                timesegment, monthsegment, daysegment));
204
205            // Skip the empty segments.
206            while (segments[++index] == string.Empty) { }
207
208            // Calculate the index of the file name part in the original string.
209            int filenameIndex = 0;
210
211            for (int i = 0; i < index; i++)
212            {
213                // "" represents ' ' in the original string.
214                if (segments[i] == string.Empty)
215                {
216                    filenameIndex += 1;
217                }
218                else
219                {
220                    filenameIndex += segments[i].Length + 1;
221                }
222            }
223            // The file name may include many segments because the name can contain ' '.          
224            fileSystem.Name = fileSystem.OriginalRecordString.Substring(filenameIndex).Trim();
225
226            return fileSystem;
227        }
228
229        /// <summary>
230        /// 12-13-10  12:41PM       <DIR>          Folder A
231        /// </summary>
232        /// <param name="recordString"></param>
233        /// <returns></returns>
234        static FTPFileSystem ParseMSDOSRecordString(string recordString)
235        {
236            FTPFileSystem fileSystem = new FTPFileSystem();
237
238            fileSystem.OriginalRecordString = recordString.Trim();
239            fileSystem.DirectoryListingStyle = FTPDirectoryListingStyle.MSDOS;
240
241            // The segments is like "12-13-10",  "", "12:41PM", "", "","", "",
242            // "", "", "<DIR>", "", "", "", "", "", "", "", "", "", "Folder", "A".
243            string[] segments = fileSystem.OriginalRecordString.Split(' ');
244
245            int index = 0;
246
247            // The date segment is like "12-13-10" instead of "12-13-2010" if Four-digit years
248            // is not checked in IIS.
249            string dateSegment = segments[index];
250            string[] dateSegments = dateSegment.Split(new char[] { '-' },
251                StringSplitOptions.RemoveEmptyEntries);
252
253            int month = int.Parse(dateSegments[0]);
254            int day = int.Parse(dateSegments[1]);
255            int year = int.Parse(dateSegments[2]);
256
257            // If year >=50 and year <100, then  it means the year 19**
258            if (year >= 50 && year < 100)
259            {
260                year += 1900;
261            }
262
263            // If year <50, then it means the year 20**
264            else if (year < 50)
265            {
266                year += 2000;
267            }
268
269            // Skip the empty segments.
270            while (segments[++index] == string.Empty) { }
271
272            // The time segment.
273            string timesegment = segments[index];
274
275            fileSystem.ModifiedTime = DateTime.Parse(string.Format("{0}-{1}-{2} {3}",
276                year, month, day, timesegment));
277
278            // Skip the empty segments.
279            while (segments[++index] == string.Empty) { }
280
281            // The size or directory segment.
282            // If this segment is "<DIR>", then it means a directory, else it means the
283            // file size.
284            string sizeOrDirSegment = segments[index];
285
286            fileSystem.IsDirectory = sizeOrDirSegment.Equals("<DIR>",
287                StringComparison.OrdinalIgnoreCase);
288
289            // If this fileSystem is a file, then the size is larger than 0. 
290            if (!fileSystem.IsDirectory)
291            {
292                fileSystem.Size = int.Parse(sizeOrDirSegment);
293            }
294
295            // Skip the empty segments.
296            while (segments[++index] == string.Empty) { }
297
298            // Calculate the index of the file name part in the original string.
299            int filenameIndex = 0;
300
301            for (int i = 0; i < index; i++)
302            {
303                // "" represents ' ' in the original string.
304                if (segments[i] == string.Empty)
305                {
306                    filenameIndex += 1;
307                }
308                else
309                {
310                    filenameIndex += segments[i].Length + 1;
311                }
312            }
313            // The file name may include many segments because the name can contain ' '.          
314            fileSystem.Name = fileSystem.OriginalRecordString.Substring(filenameIndex).Trim();
315
316            return fileSystem;
317        }
318    }
319}