Copied remotely
[mono.git] / mcs / class / Mono.Posix / Mono.Unix / UnixFileSystemInfo.cs
1 //
2 // Mono.Unix/UnixFileSystemInfo.cs
3 //
4 // Authors:
5 //   Jonathan Pryor (jonpryor@vt.edu)
6 //
7 // (C) 2004 Jonathan Pryor
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.IO;
31 using System.Text;
32 using Mono.Unix;
33
34 namespace Mono.Unix {
35
36         public abstract class UnixFileSystemInfo
37         {
38                 private Stat stat;
39                 private string path;
40                 private bool valid = false;
41
42                 protected UnixFileSystemInfo (string path)
43                 {
44                         this.path = path;
45                         Refresh (true);
46                 }
47
48                 internal UnixFileSystemInfo (String path, Stat stat)
49                 {
50                         this.path = path;
51                         this.stat = stat;
52                         this.valid = true;
53                 }
54
55                 protected string Path {
56                         get {return path;}
57                         set {path = value;}
58                 }
59
60                 private void AssertValid ()
61                 {
62                         Refresh (false);
63                         if (!valid)
64                                 throw new InvalidOperationException ("Path doesn't exist!");
65                 }
66
67                 public bool Exists {
68                         get {
69                                 int r = Syscall.access (path, AccessMode.F_OK);
70                                 if (r == 0)
71                                         return true;
72                                 return false;
73                         }
74                 }
75
76                 public ulong Device {
77                         get {AssertValid (); return stat.st_dev;}
78                 }
79
80                 public ulong Inode {
81                         get {AssertValid (); return stat.st_ino;}
82                 }
83
84                 public FilePermissions Mode {
85                         get {AssertValid (); return stat.st_mode;}
86                 }
87
88                 public FilePermissions Permissions {
89                         get {AssertValid (); return stat.st_mode & ~FilePermissions.S_IFMT;}
90                 }
91
92                 public FilePermissions FileType {
93                         get {AssertValid (); return stat.st_mode & FilePermissions.S_IFMT;}
94                 }
95
96                 public ulong LinkCount {
97                         get {AssertValid (); return (ulong) stat.st_nlink;}
98                 }
99
100                 public uint OwnerUser {
101                         get {AssertValid (); return stat.st_uid;}
102                 }
103
104                 public uint OwnerGroup {
105                         get {AssertValid (); return stat.st_gid;}
106                 }
107
108                 public ulong DeviceType {
109                         get {AssertValid (); return stat.st_rdev;}
110                 }
111
112                 public long Length {
113                         get {AssertValid (); return (long) stat.st_size;}
114                 }
115
116                 public long BlockSize {
117                         get {AssertValid (); return (long) stat.st_blksize;}
118                 }
119
120                 public long BlocksAllocated {
121                         get {AssertValid (); return (long) stat.st_blocks;}
122                 }
123
124                 public DateTime LastAccessTime {
125                         get {AssertValid (); return UnixConvert.ToDateTime (stat.st_atime);}
126                 }
127
128                 public DateTime LastAccessTimeUtc {
129                         get {return LastAccessTime.ToUniversalTime ();}
130                 }
131
132                 public DateTime LastWriteTime {
133                         get {AssertValid (); return UnixConvert.ToDateTime (stat.st_mtime);}
134                 }
135
136                 public DateTime LastWriteTimeUtc {
137                         get {return LastWriteTime.ToUniversalTime ();}
138                 }
139
140                 public DateTime LastStatusChangeTime {
141                         get {AssertValid (); return UnixConvert.ToDateTime (stat.st_ctime);}
142                 }
143
144                 public DateTime LastStatusChangeTimeUtc {
145                         get {return LastStatusChangeTime.ToUniversalTime ();}
146                 }
147
148                 public bool IsDirectory {
149                         get {AssertValid (); return IsType (stat.st_mode, FilePermissions.S_IFDIR);}
150                 }
151
152                 public bool IsCharacterDevice {
153                         get {AssertValid (); return IsType (stat.st_mode, FilePermissions.S_IFCHR);}
154                 }
155
156                 public bool IsBlockDevice {
157                         get {AssertValid (); return IsType (stat.st_mode, FilePermissions.S_IFBLK);}
158                 }
159
160                 public bool IsFile {
161                         get {AssertValid (); return IsType (stat.st_mode, FilePermissions.S_IFREG);}
162                 }
163
164                 public bool IsFIFO {
165                         get {AssertValid (); return IsType (stat.st_mode, FilePermissions.S_IFIFO);}
166                 }
167
168                 public bool IsSymbolicLink {
169                         get {AssertValid (); return IsType (stat.st_mode, FilePermissions.S_IFLNK);}
170                 }
171
172                 public bool IsSocket {
173                         get {AssertValid (); return IsType (stat.st_mode, FilePermissions.S_IFSOCK);}
174                 }
175
176                 public bool IsSetUser {
177                         get {AssertValid (); return IsType (stat.st_mode, FilePermissions.S_ISUID);}
178                 }
179
180                 public bool IsSetGroup {
181                         get {AssertValid (); return IsType (stat.st_mode, FilePermissions.S_ISGID);}
182                 }
183
184                 public bool IsSticky {
185                         get {AssertValid (); return IsType (stat.st_mode, FilePermissions.S_ISVTX);}
186                 }
187
188                 internal static bool IsType (FilePermissions mode, FilePermissions type)
189                 {
190                         return (mode & type) == type;
191                 }
192
193                 public bool CanAccess (AccessMode mode)
194                 {
195                         int r = Syscall.access (path, mode);
196                         return r == 0;
197                 }
198
199                 public abstract void Delete ();
200
201                 public long GetConfigurationValue (PathConf name)
202                 {
203                         Syscall.SetLastError ((Error) 0);
204                         long r = Syscall.pathconf (Path, name);
205                         if (r == -1 && Syscall.GetLastError() != (Error) 0)
206                                 UnixMarshal.ThrowExceptionForLastError ();
207                         return r;
208                 }
209
210                 // TODO: Should ReadLink be in UnixSymbolicLinkInfo?
211                 public string ReadLink ()
212                 {
213                         string r = TryReadLink ();
214                         if (r == null)
215                                 UnixMarshal.ThrowExceptionForLastError ();
216                         return r;
217                 }
218
219                 public string TryReadLink ()
220                 {
221                         // Who came up with readlink(2)?  There doesn't seem to be a way to
222                         // properly handle it.
223                         StringBuilder sb = new StringBuilder (512);
224                         int r = Syscall.readlink (path, sb);
225                         if (r == -1)
226                                 return null;
227                         return sb.ToString().Substring (0, r);
228                 }
229
230                 public new void Refresh ()
231                 {
232                         Refresh (true);
233                 }
234
235                 internal void Refresh (bool force)
236                 {
237                         if (valid && !force)
238                                 return;
239                         int r = Syscall.stat (path, out this.stat);
240                         valid = r == 0;
241                 }
242
243                 public void SetLength (long length)
244                 {
245                         int r;
246                         do {
247                                 r = Syscall.truncate (path, length);
248                         }       while (UnixMarshal.ShouldRetrySyscall (r));
249                         UnixMarshal.ThrowExceptionForLastErrorIf (r);
250                 }
251
252                 public void SetPermissions (FilePermissions perms)
253                 {
254                         int r = Syscall.chmod (path, perms);
255                         UnixMarshal.ThrowExceptionForLastErrorIf (r);
256                 }
257
258                 public virtual void SetOwner (uint owner, uint group)
259                 {
260                         int r = Syscall.chown (path, owner, group);
261                         UnixMarshal.ThrowExceptionForLastErrorIf (r);
262                 }
263
264                 public void SetOwner (string owner)
265                 {
266                         Passwd pw = Syscall.getpwnam (owner);
267                         if (pw == null)
268                                 throw new ArgumentException (Locale.GetText ("invalid username"), "owner");
269                         uint uid = pw.pw_uid;
270                         uint gid = pw.pw_gid;
271                         SetOwner (uid, gid);
272                 }
273
274                 public void SetOwner (string owner, string group)
275                 {
276                         uint uid = UnixUser.GetUserId (owner);
277                         uint gid = UnixGroup.GetGroupId (group);
278
279                         SetOwner (uid, gid);
280                 }
281
282                 public override string ToString ()
283                 {
284                         return path;
285                 }
286
287                 internal static UnixFileSystemInfo Create (string path)
288                 {
289                         Stat stat = UnixFile.GetFileStatus (path);
290                         if (IsType (stat.st_mode, FilePermissions.S_IFDIR))
291                                 return new UnixDirectoryInfo (path, stat);
292                         else if (IsType (stat.st_mode, FilePermissions.S_IFLNK))
293                                 return new UnixSymbolicLinkInfo (path, stat);
294                         return new UnixFileInfo (path, stat);
295                 }
296         }
297 }
298
299 // vim: noexpandtab