3c1f479b9d
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
429 lines
11 KiB
C#
429 lines
11 KiB
C#
//
|
|
// Mono.Unix/UnixFileSystemInfo.cs
|
|
//
|
|
// Authors:
|
|
// Jonathan Pryor (jonpryor@vt.edu)
|
|
//
|
|
// (C) 2004-2006 Jonathan Pryor
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using Mono.Unix;
|
|
|
|
namespace Mono.Unix {
|
|
|
|
public abstract class UnixFileSystemInfo
|
|
{
|
|
private Native.Stat stat;
|
|
private string fullPath;
|
|
private string originalPath;
|
|
private bool valid = false;
|
|
|
|
internal const FileSpecialAttributes AllSpecialAttributes =
|
|
FileSpecialAttributes.SetUserId | FileSpecialAttributes.SetGroupId |
|
|
FileSpecialAttributes.Sticky;
|
|
internal const FileTypes AllFileTypes =
|
|
FileTypes.Directory | FileTypes.CharacterDevice | FileTypes.BlockDevice |
|
|
FileTypes.RegularFile | FileTypes.Fifo | FileTypes.SymbolicLink |
|
|
FileTypes.Socket;
|
|
|
|
protected UnixFileSystemInfo (string path)
|
|
{
|
|
UnixPath.CheckPath (path);
|
|
this.originalPath = path;
|
|
this.fullPath = UnixPath.GetFullPath (path);
|
|
Refresh (true);
|
|
}
|
|
|
|
internal UnixFileSystemInfo (String path, Native.Stat stat)
|
|
{
|
|
this.originalPath = path;
|
|
this.fullPath = UnixPath.GetFullPath (path);
|
|
this.stat = stat;
|
|
this.valid = true;
|
|
}
|
|
|
|
protected string FullPath {
|
|
get {return fullPath;}
|
|
set {
|
|
if (fullPath != value) {
|
|
UnixPath.CheckPath (value);
|
|
valid = false;
|
|
fullPath = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected string OriginalPath {
|
|
get {return originalPath;}
|
|
set {originalPath = value;}
|
|
}
|
|
|
|
private void AssertValid ()
|
|
{
|
|
Refresh (false);
|
|
if (!valid)
|
|
throw new InvalidOperationException ("Path doesn't exist!");
|
|
}
|
|
|
|
public virtual string FullName {
|
|
get {return FullPath;}
|
|
}
|
|
|
|
public abstract string Name {get;}
|
|
|
|
public bool Exists {
|
|
get {
|
|
Refresh (true);
|
|
return valid;
|
|
}
|
|
}
|
|
|
|
public long Device {
|
|
get {AssertValid (); return Convert.ToInt64 (stat.st_dev);}
|
|
}
|
|
|
|
public long Inode {
|
|
get {AssertValid (); return Convert.ToInt64 (stat.st_ino);}
|
|
}
|
|
|
|
[CLSCompliant (false)]
|
|
public Native.FilePermissions Protection {
|
|
get {AssertValid (); return (Native.FilePermissions) stat.st_mode;}
|
|
set {
|
|
int r = Native.Syscall.chmod (FullPath, value);
|
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
}
|
|
}
|
|
|
|
public FileTypes FileType {
|
|
get {
|
|
AssertValid ();
|
|
return (FileTypes) (stat.st_mode & Native.FilePermissions.S_IFMT);
|
|
}
|
|
// no set as chmod(2) won't accept changing the file type.
|
|
}
|
|
|
|
public FileAccessPermissions FileAccessPermissions {
|
|
get {
|
|
AssertValid ();
|
|
int perms = (int) stat.st_mode;
|
|
return (FileAccessPermissions) (perms & (int) FileAccessPermissions.AllPermissions);
|
|
}
|
|
set {
|
|
AssertValid ();
|
|
int perms = (int) stat.st_mode;
|
|
perms &= (int) ~FileAccessPermissions.AllPermissions;
|
|
perms |= (int) value;
|
|
Protection = (Native.FilePermissions) perms;
|
|
}
|
|
}
|
|
|
|
public FileSpecialAttributes FileSpecialAttributes {
|
|
get {
|
|
AssertValid ();
|
|
int attrs = (int) stat.st_mode;
|
|
return (FileSpecialAttributes) (attrs & (int) AllSpecialAttributes);
|
|
}
|
|
set {
|
|
AssertValid ();
|
|
int perms = (int) stat.st_mode;
|
|
perms &= (int) ~AllSpecialAttributes;
|
|
perms |= (int) value;
|
|
Protection = (Native.FilePermissions) perms;
|
|
}
|
|
}
|
|
|
|
public long LinkCount {
|
|
get {AssertValid (); return Convert.ToInt64 (stat.st_nlink);}
|
|
}
|
|
|
|
public UnixUserInfo OwnerUser {
|
|
get {AssertValid (); return new UnixUserInfo (stat.st_uid);}
|
|
}
|
|
|
|
public long OwnerUserId {
|
|
get {AssertValid (); return stat.st_uid;}
|
|
}
|
|
|
|
public UnixGroupInfo OwnerGroup {
|
|
get {AssertValid (); return new UnixGroupInfo (stat.st_gid);}
|
|
}
|
|
|
|
public long OwnerGroupId {
|
|
get {AssertValid (); return stat.st_gid;}
|
|
}
|
|
|
|
public long DeviceType {
|
|
get {AssertValid (); return Convert.ToInt64 (stat.st_rdev);}
|
|
}
|
|
|
|
public long Length {
|
|
get {AssertValid (); return (long) stat.st_size;}
|
|
}
|
|
|
|
public long BlockSize {
|
|
get {AssertValid (); return (long) stat.st_blksize;}
|
|
}
|
|
|
|
public long BlocksAllocated {
|
|
get {AssertValid (); return (long) stat.st_blocks;}
|
|
}
|
|
|
|
public DateTime LastAccessTime {
|
|
get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_atime, stat.st_atime_nsec);}
|
|
}
|
|
|
|
public DateTime LastAccessTimeUtc {
|
|
get {return LastAccessTime.ToUniversalTime ();}
|
|
}
|
|
|
|
public DateTime LastWriteTime {
|
|
get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_mtime, stat.st_mtime_nsec);}
|
|
}
|
|
|
|
public DateTime LastWriteTimeUtc {
|
|
get {return LastWriteTime.ToUniversalTime ();}
|
|
}
|
|
|
|
public DateTime LastStatusChangeTime {
|
|
get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_ctime, stat.st_ctime_nsec);}
|
|
}
|
|
|
|
public DateTime LastStatusChangeTimeUtc {
|
|
get {return LastStatusChangeTime.ToUniversalTime ();}
|
|
}
|
|
|
|
public bool IsDirectory {
|
|
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFDIR);}
|
|
}
|
|
|
|
public bool IsCharacterDevice {
|
|
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFCHR);}
|
|
}
|
|
|
|
public bool IsBlockDevice {
|
|
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFBLK);}
|
|
}
|
|
|
|
public bool IsRegularFile {
|
|
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFREG);}
|
|
}
|
|
|
|
public bool IsFifo {
|
|
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFIFO);}
|
|
}
|
|
|
|
public bool IsSymbolicLink {
|
|
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFLNK);}
|
|
}
|
|
|
|
public bool IsSocket {
|
|
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFSOCK);}
|
|
}
|
|
|
|
public bool IsSetUser {
|
|
get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISUID);}
|
|
}
|
|
|
|
public bool IsSetGroup {
|
|
get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISGID);}
|
|
}
|
|
|
|
public bool IsSticky {
|
|
get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISVTX);}
|
|
}
|
|
|
|
internal static bool IsFileType (Native.FilePermissions mode, Native.FilePermissions type)
|
|
{
|
|
return (mode & Native.FilePermissions.S_IFMT) == type;
|
|
}
|
|
|
|
internal static bool IsSet (Native.FilePermissions mode, Native.FilePermissions type)
|
|
{
|
|
return (mode & type) == type;
|
|
}
|
|
|
|
[CLSCompliant (false)]
|
|
public bool CanAccess (Native.AccessModes mode)
|
|
{
|
|
int r = Native.Syscall.access (FullPath, mode);
|
|
return r == 0;
|
|
}
|
|
|
|
public UnixFileSystemInfo CreateLink (string path)
|
|
{
|
|
int r = Native.Syscall.link (FullName, path);
|
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
return GetFileSystemEntry (path);
|
|
}
|
|
|
|
public UnixSymbolicLinkInfo CreateSymbolicLink (string path)
|
|
{
|
|
int r = Native.Syscall.symlink (FullName, path);
|
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
return new UnixSymbolicLinkInfo (path);
|
|
}
|
|
|
|
public abstract void Delete ();
|
|
|
|
[CLSCompliant (false)]
|
|
public long GetConfigurationValue (Native.PathconfName name)
|
|
{
|
|
long r = Native.Syscall.pathconf (FullPath, name);
|
|
if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0)
|
|
UnixMarshal.ThrowExceptionForLastError ();
|
|
return r;
|
|
}
|
|
|
|
public void Refresh ()
|
|
{
|
|
Refresh (true);
|
|
}
|
|
|
|
internal void Refresh (bool force)
|
|
{
|
|
if (valid && !force)
|
|
return;
|
|
valid = GetFileStatus (FullPath, out this.stat);
|
|
}
|
|
|
|
protected virtual bool GetFileStatus (string path, out Native.Stat stat)
|
|
{
|
|
return Native.Syscall.stat (path, out stat) == 0;
|
|
}
|
|
|
|
public void SetLength (long length)
|
|
{
|
|
int r;
|
|
do {
|
|
r = Native.Syscall.truncate (FullPath, length);
|
|
} while (UnixMarshal.ShouldRetrySyscall (r));
|
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
}
|
|
|
|
public virtual void SetOwner (long owner, long group)
|
|
{
|
|
uint _owner = Convert.ToUInt32 (owner);
|
|
uint _group = Convert.ToUInt32 (group);
|
|
int r = Native.Syscall.chown (FullPath, _owner, _group);
|
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
}
|
|
|
|
public void SetOwner (string owner)
|
|
{
|
|
Native.Passwd pw = Native.Syscall.getpwnam (owner);
|
|
if (pw == null)
|
|
throw new ArgumentException (Locale.GetText ("invalid username"), "owner");
|
|
uint uid = pw.pw_uid;
|
|
uint gid = pw.pw_gid;
|
|
SetOwner ((long) uid, (long) gid);
|
|
}
|
|
|
|
public void SetOwner (string owner, string group)
|
|
{
|
|
long uid = -1;
|
|
if (owner != null)
|
|
uid = new UnixUserInfo (owner).UserId;
|
|
long gid = -1;
|
|
if (group != null)
|
|
gid = new UnixGroupInfo (group).GroupId;
|
|
|
|
SetOwner (uid, gid);
|
|
}
|
|
|
|
public void SetOwner (UnixUserInfo owner)
|
|
{
|
|
long uid, gid;
|
|
uid = gid = -1;
|
|
if (owner != null) {
|
|
uid = owner.UserId;
|
|
gid = owner.GroupId;
|
|
}
|
|
SetOwner (uid, gid);
|
|
}
|
|
|
|
public void SetOwner (UnixUserInfo owner, UnixGroupInfo group)
|
|
{
|
|
long uid, gid;
|
|
uid = gid = -1;
|
|
if (owner != null)
|
|
uid = owner.UserId;
|
|
if (group != null)
|
|
gid = owner.GroupId;
|
|
SetOwner (uid, gid);
|
|
}
|
|
|
|
public override string ToString ()
|
|
{
|
|
return FullPath;
|
|
}
|
|
|
|
public Native.Stat ToStat ()
|
|
{
|
|
AssertValid ();
|
|
return stat;
|
|
}
|
|
|
|
public static UnixFileSystemInfo GetFileSystemEntry (string path)
|
|
{
|
|
UnixFileSystemInfo info;
|
|
if (TryGetFileSystemEntry (path, out info))
|
|
return info;
|
|
|
|
UnixMarshal.ThrowExceptionForLastError ();
|
|
|
|
// Throw DirectoryNotFoundException because lstat(2) probably failed
|
|
// because of ENOTDIR (e.g. "/path/to/file/wtf"), so
|
|
// DirectoryNotFoundException is what would have been thrown anyway.
|
|
throw new DirectoryNotFoundException ("UnixMarshal.ThrowExceptionForLastError didn't throw?!");
|
|
}
|
|
|
|
public static bool TryGetFileSystemEntry (string path, out UnixFileSystemInfo entry)
|
|
{
|
|
Native.Stat stat;
|
|
int r = Native.Syscall.lstat (path, out stat);
|
|
if (r == -1) {
|
|
if (Native.Stdlib.GetLastError() == Native.Errno.ENOENT) {
|
|
entry = new UnixFileInfo (path);
|
|
return true;
|
|
}
|
|
entry = null;
|
|
return false;
|
|
}
|
|
|
|
if (IsFileType (stat.st_mode, Native.FilePermissions.S_IFDIR))
|
|
entry = new UnixDirectoryInfo (path, stat);
|
|
else if (IsFileType (stat.st_mode, Native.FilePermissions.S_IFLNK))
|
|
entry = new UnixSymbolicLinkInfo (path, stat);
|
|
else
|
|
entry = new UnixFileInfo (path, stat);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// vim: noexpandtab
|