Merge branch 'cecil-light'
[mono.git] / mcs / class / corlib / System.IO / DriveInfo.cs
1 //
2 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23
24 using System;
25 using System.Collections;
26 using System.Text;
27 using System.Runtime.Serialization;
28 using System.Runtime.CompilerServices;
29 using System.Runtime.InteropServices;
30
31 namespace System.IO {
32         [SerializableAttribute] 
33         [ComVisibleAttribute(true)] 
34         public sealed class DriveInfo : ISerializable {
35                 _DriveType _drive_type;
36                 string drive_format;
37                 string path;
38
39                 DriveInfo (_DriveType _drive_type, string path, string fstype)
40                 {
41                         this._drive_type = _drive_type;
42                         this.drive_format = fstype;
43                         this.path = path;
44                 }
45
46                 public DriveInfo (string driveName)
47                 {
48                         DriveInfo [] drives = GetDrives ();
49
50                         foreach (DriveInfo d in drives){
51                                 if (d.path == driveName){
52                                         this.path = d.path;
53                                         this.drive_format = d.drive_format;
54                                         this.path = d.path;
55                                         return;
56                                 }
57                         }
58                         throw new ArgumentException ("The drive name does not exist", "driveName");
59                 }
60                 
61                 enum _DriveType {
62                         GenericUnix,
63                         Linux,
64                         Windows,
65                 }
66
67                 static void GetDiskFreeSpace (string path, out ulong availableFreeSpace, out ulong totalSize, out ulong totalFreeSpace)
68                 {
69                         MonoIOError error;
70                         if (!GetDiskFreeSpaceInternal (path, out availableFreeSpace, out totalSize, out totalFreeSpace, out error))
71                                 throw MonoIO.GetException (path, error);
72                 }
73
74                 public long AvailableFreeSpace {
75                         get {
76                                 ulong availableFreeSpace;
77                                 ulong totalSize;
78                                 ulong totalFreeSpace;
79
80                                 GetDiskFreeSpace (path, out availableFreeSpace, out totalSize, out totalFreeSpace);
81                                 return availableFreeSpace > long.MaxValue ?  long.MaxValue : (long) availableFreeSpace;
82                         }
83                 }
84
85                 public long TotalFreeSpace {
86                         get {
87                                 ulong availableFreeSpace;
88                                 ulong totalSize;
89                                 ulong totalFreeSpace;
90
91                                 GetDiskFreeSpace (path, out availableFreeSpace, out totalSize, out totalFreeSpace);
92                                 return totalFreeSpace > long.MaxValue ?  long.MaxValue : (long) totalFreeSpace;
93                         }
94                 }
95
96                 public long TotalSize {
97                         get {
98                                 ulong availableFreeSpace;
99                                 ulong totalSize;
100                                 ulong totalFreeSpace;
101
102                                 GetDiskFreeSpace (path, out availableFreeSpace, out totalSize, out totalFreeSpace);
103                                 return totalSize > long.MaxValue ?  long.MaxValue : (long) totalSize;
104                         }
105                 }
106
107                 [MonoTODO ("Currently get only works on Mono/Unix; set not implemented")]
108                 public string VolumeLabel {
109                         get {
110                                 if (_drive_type != _DriveType.Windows)
111                                         return path;
112                                 else
113                                         return path;
114                         }
115                         set {
116                                 throw new NotImplementedException ();
117                         }
118                 }
119                 
120                 public string DriveFormat {
121                         get {
122                                 return drive_format;
123                         }
124                 }
125
126                 public DriveType DriveType {
127                         get {
128                                 return (DriveType) GetDriveTypeInternal (path);
129                         }
130                 }
131
132                 public string Name {
133                         get {
134                                 return path;
135                         }
136                 }
137
138                 public DirectoryInfo RootDirectory {
139                         get {
140                                 return new DirectoryInfo (path);
141                         }
142                 }
143
144                 [MonoTODO("It always returns true")]
145                 public bool IsReady {
146                         get {
147                                 if (_drive_type != _DriveType.Windows)
148                                         return true;
149
150                                 // Do something for Windows here.
151                                 return true;
152                         }
153                 }
154                 
155                 static StreamReader TryOpen (string name)
156                 {
157                         if (File.Exists (name))
158                                 return new StreamReader (name);
159                         return null;
160                 }
161
162                 static char [] space = { ' ' };
163                 static DriveInfo [] LinuxGetDrives ()
164                 {
165                         using (StreamReader mounts = TryOpen ("/proc/mounts")){
166                                 ArrayList drives = new ArrayList ();
167                                 string line;
168                                 
169                                 while ((line = mounts.ReadLine ()) != null){
170                                         if (line.StartsWith ("rootfs"))
171                                                 continue;
172                                         string [] parts = line.Split (space, 4);
173                                         if (parts.Length < 3)
174                                                 continue;
175                                         string path = Unescape (parts [1]);
176                                         string fstype = parts [2];
177                                         drives.Add (new DriveInfo (_DriveType.Linux, path, fstype));
178                                 }
179
180                                 return (DriveInfo []) drives.ToArray (typeof (DriveInfo));
181                         }
182                 }
183
184                 static string Unescape (string path)
185                 {
186                         StringBuilder sb = null;
187                         int start = 0;
188                         do {
189                                 int slash = path.IndexOf ('\\', start);
190                                 if (slash >= 0) {
191                                         if (sb == null)
192                                                 sb = new StringBuilder ();
193                                         sb.Append (path.Substring (start, slash - start));
194                                         char c = (char) ((path [slash + 1] - '0') << 6);
195                                         c += (char) ((path [slash + 2] - '0') << 3);
196                                         c += (char) (path [slash + 3] - '0');
197                                         sb.Append (c);
198                                         start = slash + 4;
199                                         continue;
200                                 }
201                                 if (start == 0)
202                                         return path;
203                                 sb.Append (path.Substring (start));
204                                 return sb.ToString ();
205                         } while (true);
206                 }
207                 
208                 static DriveInfo [] UnixGetDrives ()
209                 {
210                         DriveInfo [] di = null;
211
212                         try {
213                                 using (StreamReader linux_ostype = TryOpen ("/proc/sys/kernel/ostype")){
214                                         if (linux_ostype != null){
215                                                 string line = linux_ostype.ReadLine ();
216                                                 if (line == "Linux")
217                                                         di = LinuxGetDrives ();
218                                         }
219                                 }
220                                 
221                                 if (di != null)
222                                         return di;
223                         } catch (Exception) {
224                                 // If anything happens.
225                         }
226                         
227                         DriveInfo [] unknown = new DriveInfo [1];
228                         unknown [0]= new DriveInfo (_DriveType.GenericUnix, "/", "unixfs");
229
230                         return unknown;
231                 }
232
233                 static DriveInfo [] WindowsGetDrives ()
234                 {
235                         throw new NotImplementedException ();
236                 }
237                 
238                 [MonoTODO("Currently only implemented on Mono/Linux")]
239                 public static DriveInfo[] GetDrives ()
240                 {
241                         if (Environment.IsUnix)
242                                 return UnixGetDrives ();
243                         else
244                                 return WindowsGetDrives ();
245                 }
246
247                 void ISerializable.GetObjectData (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
248                 {
249                         throw new NotImplementedException ();
250                 }
251
252                 public override string ToString ()
253                 {
254                         return(Name);
255                 }
256
257                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
258                 extern static bool GetDiskFreeSpaceInternal (string pathName, out ulong freeBytesAvail,
259                                                              out ulong totalNumberOfBytes, out ulong totalNumberOfFreeBytes,
260                                                              out MonoIOError error);
261
262                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
263                 extern static uint GetDriveTypeInternal (string rootPathName);
264         }
265 }