Introduction
Hello Wolrd! (sorry found humor in that), Currently in MonoDevelop as far as I can see when attempting to change file permissions on a file in Linux(Ubuntu 16.04 i386) we encounter a 'Not supported on this platform' error when using System.Security.AccessControl.FileSecurity to change permissions on a file, which led me to build this wrapper for chmod.
Background
This idea started when I needed to provide a way to make a custom generated chrome app desktop launcher to be executable. We could simply use the code below but what about other different scenarios? This is where my simple wrapper got its start.
System.Diagnostic.Process.Start("chmod", "755 $APPNAME$");
Using the code
The classes that we will be looking at today will be listed below. if you're not familiar with chmod you can check out the man page here.
1. [enum
] FileAccess.cs.
FileAccess
represents a single octal value (1 of 3) of chmod.
using System;
namespace Linux.FileSecurity
{
public enum FileAccess
{
None = 0,
Execute = 1,
Write = 2,
Read = 4,
}
}
2. [struct
] FilePermissionFlag.cs.
FilePermissionFlag
represents the 3 octal values required by chmod U(ser),G(roup),O(ther).
using System;
namespace Linux.FileSecurity
{
public struct FilePermissionFlag
{
public FileAccess User
{
get;
private set;
}
public FileAccess Group
{
get;
private set;
}
public FileAccess Others
{
get;
private set;
}
internal FilePermissionFlag(FileAccess User, FileAccess Group, FileAccess Others)
{
this.User = FilePermissionFlag.ToValidAccess(User);
this.Group = FilePermissionFlag.ToValidAccess(Group);
this.Others = FilePermissionFlag.ToValidAccess(Others);
}
public static FileAccess ToValidAccess(FileAccess Access)
{
int num = (int)Access;
return (FileAccess)(num < 0 ? 0 : num > 7 ? 7 : num);
}
}
}
3. [static class
] KnownAccess.cs.
KnownAccess
Contains the known FileAccess
values. Note missing FileAccess.Execute
(hindsight while writing code)
using System;
namespace Linux.FileSecurity
{
public static class KnownAccess
{
public static readonly FileAccess None = FileAccess.None;
public static readonly FileAccess Read = FileAccess.Read;
public static readonly FileAccess Write = FileAccess.Write;
public static readonly FileAccess Execute = FileAccess.Execute;
public static readonly FileAccess Read_Write = FileAccess.Read | FileAccess.Write;
public static readonly FileAccess Read_Execute = FileAccess.Read | FileAccess.Execute;
public static readonly FileAccess Write_Execute = FileAccess.Write | FileAccess.Execute;
public static readonly FileAccess Read_Write_Execute = FileAccess.Read |FileAccess.Write | FileAccess.Execute;
}
}
4. [sealed class
] FilePermission.cs.
FilePermission
takes in the file path and runs chmod against the file using the given FilePermissionFlag
.
using System;
namespace Linux.FileSecurity
{
public sealed class FilePermission
{
const string File = "chmod";
public string Process
{
get;
private set;
}
public FilePermissionFlag Flags
{
get;
private set;
}
public override string ToString ()
{
return string.Format ("{0}{1}{2} {3}",
(int)FilePermissionFlag.ToValidAccess(Flags.User),
(int)FilePermissionFlag.ToValidAccess(Flags.Group),
(int)FilePermissionFlag.ToValidAccess(Flags.Others),
Process);
}
public FilePermission (string filePath)
{
if (!System.IO.File.Exists (filePath))
throw new System.IO.FileLoadException ("error loading " + filePath, filePath);
this.Process = filePath;
}
public FilePermission(FilePermission permission, FileAccess user, FileAccess group, FileAccess others)
: this(permission.Process, user, group, others)
{
}
public static FilePermission SetPermission(string filePath, FileAccess user, FileAccess group, FileAccess others)
{
FilePermission permission = new FilePermission (filePath);
permission.Flags = new FilePermissionFlag (user, group, others);
return permission.Apply ();
}
public void Apply(FileAccess user, FileAccess group, FileAccess others)
{
this.Flags = new FilePermissionFlag (user, group, others);
this.Apply ();
}
private FilePermission Apply()
{
if (string.IsNullOrWhiteSpace (Process) || string.IsNullOrEmpty(Process))
{
Console.WriteLine ("File name cannot be empty.");
return null;
}
if (!System.IO.File.Exists (Process))
{
Console.WriteLine ("Error finding file " + Process + ".");
return null;
}
try
{
string permission = this.ToString();
System.Diagnostics.ProcessStartInfo filePermission =
new System.Diagnostics.ProcessStartInfo (
FilePermission.File, permission);
System.Diagnostics.Process.Start(filePermission);
return this;
}
catch
{
return null;
}
}
}
}
Points of Interest
Writing this workaround was fun and intuitive and learned a great deal about chmod and any and all comments, concerns, questions can be left below.
History
1. Jan 8th 2018 v1.0