2 // Mono.Unix/UnixFileSystemInfo.cs
5 // Jonathan Pryor (jonpryor@vt.edu)
7 // (C) 2004-2006 Jonathan Pryor
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
36 public abstract class UnixFileSystemInfo
38 private Native.Stat stat;
39 private string fullPath;
40 private string originalPath;
41 private bool valid = false;
43 internal const FileSpecialAttributes AllSpecialAttributes =
44 FileSpecialAttributes.SetUserId | FileSpecialAttributes.SetGroupId |
45 FileSpecialAttributes.Sticky;
46 internal const FileTypes AllFileTypes =
47 FileTypes.Directory | FileTypes.CharacterDevice | FileTypes.BlockDevice |
48 FileTypes.RegularFile | FileTypes.Fifo | FileTypes.SymbolicLink |
51 protected UnixFileSystemInfo (string path)
53 UnixPath.CheckPath (path);
54 this.originalPath = path;
55 this.fullPath = UnixPath.GetFullPath (path);
59 internal UnixFileSystemInfo (String path, Native.Stat stat)
61 this.originalPath = path;
62 this.fullPath = UnixPath.GetFullPath (path);
67 protected string FullPath {
68 get {return fullPath;}
70 if (fullPath != value) {
71 UnixPath.CheckPath (value);
78 protected string OriginalPath {
79 get {return originalPath;}
80 set {originalPath = value;}
83 private void AssertValid ()
87 throw new InvalidOperationException ("Path doesn't exist!");
90 public virtual string FullName {
91 get {return FullPath;}
94 public abstract string Name {get;}
104 get {AssertValid (); return Convert.ToInt64 (stat.st_dev);}
108 get {AssertValid (); return Convert.ToInt64 (stat.st_ino);}
111 [CLSCompliant (false)]
112 public Native.FilePermissions Protection {
113 get {AssertValid (); return (Native.FilePermissions) stat.st_mode;}
115 int r = Native.Syscall.chmod (FullPath, value);
116 UnixMarshal.ThrowExceptionForLastErrorIf (r);
120 public FileTypes FileType {
123 return (FileTypes) (stat.st_mode & Native.FilePermissions.S_IFMT);
125 // no set as chmod(2) won't accept changing the file type.
128 public FileAccessPermissions FileAccessPermissions {
131 int perms = (int) stat.st_mode;
132 return (FileAccessPermissions) (perms & (int) FileAccessPermissions.AllPermissions);
136 int perms = (int) stat.st_mode;
137 perms &= (int) ~FileAccessPermissions.AllPermissions;
138 perms |= (int) value;
139 Protection = (Native.FilePermissions) perms;
143 public FileSpecialAttributes FileSpecialAttributes {
146 int attrs = (int) stat.st_mode;
147 return (FileSpecialAttributes) (attrs & (int) AllSpecialAttributes);
151 int perms = (int) stat.st_mode;
152 perms &= (int) ~AllSpecialAttributes;
153 perms |= (int) value;
154 Protection = (Native.FilePermissions) perms;
158 public long LinkCount {
159 get {AssertValid (); return Convert.ToInt64 (stat.st_nlink);}
162 public UnixUserInfo OwnerUser {
163 get {AssertValid (); return new UnixUserInfo (stat.st_uid);}
166 public long OwnerUserId {
167 get {AssertValid (); return stat.st_uid;}
170 public UnixGroupInfo OwnerGroup {
171 get {AssertValid (); return new UnixGroupInfo (stat.st_gid);}
174 public long OwnerGroupId {
175 get {AssertValid (); return stat.st_gid;}
178 public long DeviceType {
179 get {AssertValid (); return Convert.ToInt64 (stat.st_rdev);}
183 get {AssertValid (); return (long) stat.st_size;}
186 public long BlockSize {
187 get {AssertValid (); return (long) stat.st_blksize;}
190 public long BlocksAllocated {
191 get {AssertValid (); return (long) stat.st_blocks;}
194 public DateTime LastAccessTime {
195 get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_atime, stat.st_atime_nsec);}
198 public DateTime LastAccessTimeUtc {
199 get {return LastAccessTime.ToUniversalTime ();}
202 public DateTime LastWriteTime {
203 get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_mtime, stat.st_mtime_nsec);}
206 public DateTime LastWriteTimeUtc {
207 get {return LastWriteTime.ToUniversalTime ();}
210 public DateTime LastStatusChangeTime {
211 get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_ctime, stat.st_ctime_nsec);}
214 public DateTime LastStatusChangeTimeUtc {
215 get {return LastStatusChangeTime.ToUniversalTime ();}
218 public bool IsDirectory {
219 get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFDIR);}
222 public bool IsCharacterDevice {
223 get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFCHR);}
226 public bool IsBlockDevice {
227 get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFBLK);}
230 public bool IsRegularFile {
231 get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFREG);}
235 get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFIFO);}
238 public bool IsSymbolicLink {
239 get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFLNK);}
242 public bool IsSocket {
243 get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFSOCK);}
246 public bool IsSetUser {
247 get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISUID);}
250 public bool IsSetGroup {
251 get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISGID);}
254 public bool IsSticky {
255 get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISVTX);}
258 internal static bool IsFileType (Native.FilePermissions mode, Native.FilePermissions type)
260 return (mode & Native.FilePermissions.S_IFMT) == type;
263 internal static bool IsSet (Native.FilePermissions mode, Native.FilePermissions type)
265 return (mode & type) == type;
268 [CLSCompliant (false)]
269 public bool CanAccess (Native.AccessModes mode)
271 int r = Native.Syscall.access (FullPath, mode);
275 public UnixFileSystemInfo CreateLink (string path)
277 int r = Native.Syscall.link (FullName, path);
278 UnixMarshal.ThrowExceptionForLastErrorIf (r);
279 return GetFileSystemEntry (path);
282 public UnixSymbolicLinkInfo CreateSymbolicLink (string path)
284 int r = Native.Syscall.symlink (FullName, path);
285 UnixMarshal.ThrowExceptionForLastErrorIf (r);
286 return new UnixSymbolicLinkInfo (path);
289 public abstract void Delete ();
291 [CLSCompliant (false)]
292 public long GetConfigurationValue (Native.PathconfName name)
294 long r = Native.Syscall.pathconf (FullPath, name);
295 if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0)
296 UnixMarshal.ThrowExceptionForLastError ();
300 public void Refresh ()
305 internal void Refresh (bool force)
309 valid = GetFileStatus (FullPath, out this.stat);
312 protected virtual bool GetFileStatus (string path, out Native.Stat stat)
314 return Native.Syscall.stat (path, out stat) == 0;
317 public void SetLength (long length)
321 r = Native.Syscall.truncate (FullPath, length);
322 } while (UnixMarshal.ShouldRetrySyscall (r));
323 UnixMarshal.ThrowExceptionForLastErrorIf (r);
326 public virtual void SetOwner (long owner, long group)
328 uint _owner = Convert.ToUInt32 (owner);
329 uint _group = Convert.ToUInt32 (group);
330 int r = Native.Syscall.chown (FullPath, _owner, _group);
331 UnixMarshal.ThrowExceptionForLastErrorIf (r);
334 public void SetOwner (string owner)
336 Native.Passwd pw = Native.Syscall.getpwnam (owner);
338 throw new ArgumentException (Locale.GetText ("invalid username"), "owner");
339 uint uid = pw.pw_uid;
340 uint gid = pw.pw_gid;
341 SetOwner ((long) uid, (long) gid);
344 public void SetOwner (string owner, string group)
348 uid = new UnixUserInfo (owner).UserId;
351 gid = new UnixGroupInfo (group).GroupId;
356 public void SetOwner (UnixUserInfo owner)
367 public void SetOwner (UnixUserInfo owner, UnixGroupInfo group)
378 public override string ToString ()
383 public Native.Stat ToStat ()
389 public static UnixFileSystemInfo GetFileSystemEntry (string path)
391 UnixFileSystemInfo info;
392 if (TryGetFileSystemEntry (path, out info))
395 UnixMarshal.ThrowExceptionForLastError ();
397 // Throw DirectoryNotFoundException because lstat(2) probably failed
398 // because of ENOTDIR (e.g. "/path/to/file/wtf"), so
399 // DirectoryNotFoundException is what would have been thrown anyway.
400 throw new DirectoryNotFoundException ("UnixMarshal.ThrowExceptionForLastError didn't throw?!");
403 public static bool TryGetFileSystemEntry (string path, out UnixFileSystemInfo entry)
406 int r = Native.Syscall.lstat (path, out stat);
408 if (Native.Stdlib.GetLastError() == Native.Errno.ENOENT) {
409 entry = new UnixFileInfo (path);
416 if (IsFileType (stat.st_mode, Native.FilePermissions.S_IFDIR))
417 entry = new UnixDirectoryInfo (path, stat);
418 else if (IsFileType (stat.st_mode, Native.FilePermissions.S_IFLNK))
419 entry = new UnixSymbolicLinkInfo (path, stat);
421 entry = new UnixFileInfo (path, stat);