Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

A simple project to change file permissions on linux using chmod and monodevelop

5.00/5 (2 votes)
7 Jan 2018CPOL1 min read 10.4K  
A simple workaround for FilePermission in monodevelop

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.

C#
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.

C#
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).

C#
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)
        {
            //file access should be 0 to 7
            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)

C#
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.

C#
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)