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