65.9K
CodeProject is changing. Read more.
Home

Allow write/modify access to CommonApplicationData

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (14 votes)

Feb 28, 2010

CPOL

1 min read

viewsIcon

118298

Now your application can update it's saved data regrdless of the account it is running under.

This tip was prompted by a discussion here[^] yesterday in the C# forum. When you need to store data common to all users of an application locally, Microsoft recommend using System.Environment.SpecialFolder.CommonApplicationData. In addition they also suggest creating a sub folder here with your CompanyName and a sub folder in that of ApplicationName. The issue with this is the folders and files you create only have read/execute permissions for other users other than the creator. This means that they cannot be appended to or replaced by another user without UAC elevation. Whilst I understand the reasoning for this, in reality it creates a problem for a shared dynamic data store. The class below addresses this by setting read/write permissions to all users on the CompanyName folder and optionally setting read/write permissions of the ApplicationName folder on creation and sub folders/files inherit these permissions. Note: The permissions are only set on the ApplicationName folder creation. If it already exists the permissions will not be altered. This has only been tested on Windows 7 to date, but should work fine in Vista and XP (if required?). I will test these OSes when time allows and update this accordingly. Make sure you wrap any calls to this class in suitable try/catch blocks as there is no exception handling.
using System;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;

/// <summary>
/// Simplifies the creation of folders in the CommonApplicationData folder
/// and setting of permissions for all users.
/// </summary>
public class CommonApplicationData
{
    private string applicationFolder;
    private string companyFolder;
    private static readonly string directory = 
        Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);

    /// <summary>
    /// Creates a new instance of this class creating the specified company and application folders
    /// if they don't already exist and optionally allows write/modify to all users.
    /// </summary>
    /// <param name="companyFolder">The name of the company's folder (normally the company name).</param>
    /// <param name="applicationFolder">The name of the application's folder (normally the application name).</param>
    /// <remarks>If the application folder already exists then permissions if requested are NOT altered.</remarks>
    public CommonApplicationData(string companyFolder, string applicationFolder)
        : this(companyFolder, applicationFolder, false)
    { }
    /// <summary>
    /// Creates a new instance of this class creating the specified company and application folders
    /// if they don't already exist and optionally allows write/modify to all users.
    /// </summary>
    /// <param name="companyFolder">The name of the company's folder (normally the company name).</param>
    /// <param name="applicationFolder">The name of the application's folder (normally the application name).</param>
    /// <param name="allUsers">true to allow write/modify to all users; otherwise, false.</param>
    /// <remarks>If the application folder already exists then permissions if requested are NOT altered.</remarks>
    public CommonApplicationData(string companyFolder, string applicationFolder, bool allUsers)
    { 
        this.applicationFolder = applicationFolder;
        this.companyFolder = companyFolder;
        CreateFolders(allUsers);
    }

    /// <summary>
    /// Gets the path of the application's data folder.
    /// </summary>
    public string ApplicationFolderPath 
    { 
        get { return Path.Combine(CompanyFolderPath, applicationFolder); }
    }
    /// <summary>
    /// Gets the path of the company's data folder.
    /// </summary>
    public string CompanyFolderPath 
    { 
        get { return Path.Combine(directory, companyFolder); }
    }

    private void CreateFolders(bool allUsers) 
    {
        DirectoryInfo directoryInfo;
        DirectorySecurity directorySecurity;
        AccessRule rule;
        SecurityIdentifier securityIdentifier = new SecurityIdentifier
            (WellKnownSidType.BuiltinUsersSid, null);
        if (!Directory.Exists(CompanyFolderPath))
        {
            directoryInfo = Directory.CreateDirectory(CompanyFolderPath);
            bool modified;
            directorySecurity = directoryInfo.GetAccessControl();
            rule = new FileSystemAccessRule(
                    securityIdentifier,
                    FileSystemRights.Write |
                    FileSystemRights.ReadAndExecute |
                    FileSystemRights.Modify,
                    AccessControlType.Allow);
            directorySecurity.ModifyAccessRule(AccessControlModification.Add, rule, out modified);
            directoryInfo.SetAccessControl(directorySecurity);
        }
        if (!Directory.Exists(ApplicationFolderPath))
        {
            directoryInfo = Directory.CreateDirectory(ApplicationFolderPath);
            if (allUsers)
            {
                bool modified;
                directorySecurity = directoryInfo.GetAccessControl();
                rule = new FileSystemAccessRule(
                    securityIdentifier,
                    FileSystemRights.Write |
                    FileSystemRights.ReadAndExecute |
                    FileSystemRights.Modify,
                    InheritanceFlags.ContainerInherit |
                    InheritanceFlags.ObjectInherit,
                    PropagationFlags.InheritOnly,
                    AccessControlType.Allow);
                directorySecurity.ModifyAccessRule(AccessControlModification.Add, rule, out modified);
                directoryInfo.SetAccessControl(directorySecurity);
            }
        }
    }
    /// <summary>
    /// Returns the path of the application's data folder.
    /// </summary>
    /// <returns>The path of the application's data folder.</returns>
    public override string ToString() 
    { 
        return ApplicationFolderPath;
    }
}