Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / referencesource / mscorlib / system / io / filesysteminfo.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  FileSystemInfo    
9 ** 
10 ** <OWNER>Microsoft</OWNER>
11 **
12 **
13 ** Purpose: 
14 **
15 **
16 ===========================================================*/
17
18 using System;
19 using System.Collections;
20 using System.Security;
21 #if MONO_FEATURE_CAS
22 using System.Security.Permissions;
23 #endif
24 using Microsoft.Win32;
25 using System.Text;
26 using System.Runtime.InteropServices;
27 using System.Runtime.Serialization;
28 using System.Runtime.Versioning;
29 using System.Diagnostics.Contracts;
30
31 namespace System.IO {
32     [Serializable]
33 #if !FEATURE_CORECLR && MONO_FEATURE_CAS
34     [FileIOPermissionAttribute(SecurityAction.InheritanceDemand,Unrestricted=true)]
35 #endif
36     [ComVisible(true)]
37 #if FEATURE_REMOTING || MONO
38     public abstract class FileSystemInfo : MarshalByRefObject, ISerializable
39     {
40 #else // FEATURE_REMOTING
41     public abstract class FileSystemInfo : ISerializable
42     {
43 #endif  //FEATURE_REMOTING      
44 #if MONO
45         internal MonoIOStat _data;
46 #else
47         [System.Security.SecurityCritical] // auto-generated
48         internal Win32Native.WIN32_FILE_ATTRIBUTE_DATA _data; // Cache the file information
49 #endif
50         internal int _dataInitialised = -1; // We use this field in conjunction with the Refresh methods, if we succeed
51                                             // we store a zero, on failure we store the HResult in it so that we can
52                                             // give back a generic error back.
53
54         private const int ERROR_INVALID_PARAMETER = 87;
55         internal const int ERROR_ACCESS_DENIED = 0x5;
56
57         protected String FullPath;          // fully qualified path of the directory
58         protected String OriginalPath;      // path passed in by the user
59         private String _displayPath = "";   // path that can be displayed to the user
60
61         #if FEATURE_CORECLR
62 #if FEATURE_CORESYSTEM
63         [System.Security.SecurityCritical]
64 #else
65         [System.Security.SecuritySafeCritical]
66 #endif //FEATURE_CORESYSTEM
67 #endif
68         protected FileSystemInfo()
69         {
70         }
71
72         [ResourceExposure(ResourceScope.None)]
73         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
74         protected FileSystemInfo(SerializationInfo info, StreamingContext context)
75         {
76             if (info == null)
77                 throw new ArgumentNullException("info");
78             Contract.EndContractBlock();
79             
80             // Must use V1 field names here, since V1 didn't implement 
81             // ISerializable.
82             FullPath = Path.GetFullPathInternal(info.GetString("FullPath"));
83             OriginalPath = info.GetString("OriginalPath");
84
85             // Lazily initialize the file attributes.
86             _dataInitialised = -1;
87         }
88
89         [System.Security.SecurityCritical]
90         internal void InitializeFrom(Win32Native.WIN32_FIND_DATA findData)
91         {
92 #if MONO
93             throw new NotImplementedException ();
94 #else
95             _data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
96             _data.PopulateFrom(findData);
97             _dataInitialised = 0;
98 #endif
99         }
100
101         // Full path of the direcory/file
102         public virtual string FullName
103         {
104             [SecuritySafeCritical]
105             get
106             {
107 #if MONO_FEATURE_CAS
108 #if FEATURE_CORECLR
109                 FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, FullPath);
110                 sourceState.EnsureState();
111 #else
112                 FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, FullPath);
113 #endif
114 #endif
115                 return FullPath;
116             }
117         }
118
119         internal virtual string UnsafeGetFullName
120         {
121             [SecurityCritical]
122             get
123             {
124 #if MONO_FEATURE_CAS
125 #if !FEATURE_CORECLR
126                 FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, FullPath);
127 #endif
128 #endif
129                 return FullPath;
130             }
131         }
132
133         public String Extension 
134         {
135             get
136             {
137                 // GetFullPathInternal would have already stripped out the terminating "." if present.
138                int length = FullPath.Length;
139                 for (int i = length; --i >= 0;) {
140                     char ch = FullPath[i];
141                     if (ch == '.')
142                         return FullPath.Substring(i, length - i);
143                     if (ch == Path.DirectorySeparatorChar || ch == Path.AltDirectorySeparatorChar || ch == Path.VolumeSeparatorChar)
144                         break;
145                 }
146                 return String.Empty;
147             }
148         }
149
150         // For files name of the file is returned, for directories the last directory in hierarchy is returned if possible,
151         // otherwise the fully qualified name s returned
152         public abstract String Name {
153             get;
154         }
155         
156         // Whether a file/directory exists
157         public abstract bool Exists
158         {
159             get;
160         }
161
162         // Delete a file/directory
163         public abstract void Delete();
164
165         public DateTime CreationTime
166         {
167             get {
168                     // depends on the security check in get_CreationTimeUtc
169                     return CreationTimeUtc.ToLocalTime();
170             }
171
172             set {
173                 CreationTimeUtc = value.ToUniversalTime();
174             }
175         }
176
177        [ComVisible(false)]
178        public DateTime CreationTimeUtc {
179            [System.Security.SecuritySafeCritical]
180             get {
181 #if FEATURE_CORECLR
182                 // get_CreationTime also depends on this security check
183                 FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, FullPath);
184                 sourceState.EnsureState();
185 #endif
186                 if (_dataInitialised == -1) {
187 #if !MONO
188                     _data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
189 #endif
190                     Refresh();
191                 }
192
193                 if (_dataInitialised != 0) // Refresh was unable to initialise the data
194                     __Error.WinIOError(_dataInitialised, DisplayPath);
195                 
196 #if MONO
197                 long fileTime = _data.CreationTime;
198 #else
199                 long fileTime = ((long)_data.ftCreationTimeHigh << 32) | _data.ftCreationTimeLow;
200 #endif
201                 return DateTime.FromFileTimeUtc(fileTime);
202                 
203             }
204         
205             [ResourceExposure(ResourceScope.None)]
206             [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
207             set {
208                 if (this is DirectoryInfo)
209                     Directory.SetCreationTimeUtc(FullPath,value);
210                 else
211                     File.SetCreationTimeUtc(FullPath,value);
212                 _dataInitialised = -1;
213             }
214         }
215
216
217         public DateTime LastAccessTime
218        {
219            get {
220                 // depends on the security check in get_LastAccessTimeUtc
221                 return LastAccessTimeUtc.ToLocalTime();
222            }
223            set {
224                 LastAccessTimeUtc = value.ToUniversalTime();
225             }
226         }
227
228         [ComVisible(false)]
229         public DateTime LastAccessTimeUtc {
230             [System.Security.SecuritySafeCritical]
231             get {
232 #if FEATURE_CORECLR
233                 // get_LastAccessTime also depends on this security check
234                 FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, FullPath);
235                 sourceState.EnsureState();
236 #endif
237                 if (_dataInitialised == -1) {
238 #if !MONO
239                     _data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
240 #endif
241                     Refresh();
242                 }
243
244                 if (_dataInitialised != 0) // Refresh was unable to initialise the data
245                     __Error.WinIOError(_dataInitialised, DisplayPath);
246                     
247 #if MONO
248                 long fileTime = _data.LastAccessTime;
249 #else
250                 long fileTime = ((long)_data.ftLastAccessTimeHigh << 32) | _data.ftLastAccessTimeLow;
251 #endif
252                 return DateTime.FromFileTimeUtc(fileTime);
253     
254             }
255
256             [ResourceExposure(ResourceScope.None)]
257             [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
258             set {
259                 if (this is DirectoryInfo)
260                     Directory.SetLastAccessTimeUtc(FullPath,value);
261                 else
262                     File.SetLastAccessTimeUtc(FullPath,value);
263                 _dataInitialised = -1;
264             }
265         }
266
267         public DateTime LastWriteTime
268         {
269             get {
270                 // depends on the security check in get_LastWriteTimeUtc
271                 return LastWriteTimeUtc.ToLocalTime();
272             }
273
274             set {
275                 LastWriteTimeUtc = value.ToUniversalTime();
276             }
277         }
278
279         [ComVisible(false)]
280         public DateTime LastWriteTimeUtc {
281             [System.Security.SecuritySafeCritical]
282             get {
283 #if FEATURE_CORECLR
284                 // get_LastWriteTime also depends on this security check
285                 FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, FullPath);
286                 sourceState.EnsureState();
287 #endif
288                 if (_dataInitialised == -1) {
289 #if !MONO
290                     _data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
291 #endif
292                     Refresh();
293                 }
294
295                 if (_dataInitialised != 0) // Refresh was unable to initialise the data
296                     __Error.WinIOError(_dataInitialised, DisplayPath);
297         
298 #if MONO
299                 long fileTime = _data.LastWriteTime;
300 #else
301                 long fileTime = ((long)_data.ftLastWriteTimeHigh << 32) | _data.ftLastWriteTimeLow;
302 #endif
303                 return DateTime.FromFileTimeUtc(fileTime);
304             }
305
306             [ResourceExposure(ResourceScope.None)]
307             [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
308             set {
309                 if (this is DirectoryInfo)
310                     Directory.SetLastWriteTimeUtc(FullPath,value);
311                 else
312                     File.SetLastWriteTimeUtc(FullPath,value);
313                 _dataInitialised = -1;
314             }
315         }
316
317         [System.Security.SecuritySafeCritical]  // auto-generated
318         [ResourceExposure(ResourceScope.None)]
319         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
320         public void Refresh()
321         {
322             _dataInitialised = File.FillAttributeInfo(FullPath, ref _data, false, false);
323         }
324
325         public FileAttributes Attributes {
326             [System.Security.SecuritySafeCritical]
327             get
328             {
329 #if FEATURE_CORECLR
330                 FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, FullPath);
331                 sourceState.EnsureState();
332 #endif
333                 if (_dataInitialised == -1) {
334 #if !MONO
335                     _data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
336 #endif
337                     Refresh(); // Call refresh to intialise the data
338                 }
339
340                 if (_dataInitialised != 0) // Refresh was unable to initialise the data
341                     __Error.WinIOError(_dataInitialised, DisplayPath);
342
343                 return (FileAttributes) _data.fileAttributes;
344             }
345             #if FEATURE_CORECLR
346             [System.Security.SecurityCritical] // auto-generated
347             #else
348             [System.Security.SecuritySafeCritical]
349             #endif
350             set {
351 #if MONO_FEATURE_CAS
352 #if !FEATURE_CORECLR
353                 FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, FullPath);
354 #endif
355 #endif
356 #if MONO
357                 MonoIOError error;
358                 if (!MonoIO.SetFileAttributes (FullPath, value, out error)) {
359                     int hr = (int) error;
360 #else
361                 bool r = Win32Native.SetFileAttributes(FullPath, (int) value);
362                 if (!r) {
363                     int hr = Marshal.GetLastWin32Error();
364 #endif
365                     
366                     if (hr==ERROR_INVALID_PARAMETER)
367                         throw new ArgumentException(Environment.GetResourceString("Arg_InvalidFileAttrs"));
368                     
369                     // For whatever reason we are turning ERROR_ACCESS_DENIED into 
370                     // ArgumentException here (probably done for some 9x code path).
371                     // We can't change this now but special casing the error message instead.
372                     if (hr == ERROR_ACCESS_DENIED)
373                         throw new ArgumentException(Environment.GetResourceString("UnauthorizedAccess_IODenied_NoPathName"));
374                     __Error.WinIOError(hr, DisplayPath);
375                 }
376                 _dataInitialised = -1;
377             }
378         }
379
380         [System.Security.SecurityCritical]  // auto-generated_required
381         [ComVisible(false)]
382         public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
383         {
384 #if MONO_FEATURE_CAS
385 #if !FEATURE_CORECLR
386             FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, FullPath);
387 #endif
388 #endif
389
390             info.AddValue("OriginalPath", OriginalPath, typeof(String));
391             info.AddValue("FullPath", FullPath, typeof(String));
392         }
393
394         internal String DisplayPath
395         {
396             get
397             {
398                 return _displayPath;
399             }
400             set
401             {
402                 _displayPath = value;
403             }
404         }
405     }       
406 }