Allow write/modify access to CommonApplicationData
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;
}
}