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;
public class CommonApplicationData
{
private string applicationFolder;
private string companyFolder;
private static readonly string directory =
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
public CommonApplicationData(string companyFolder, string applicationFolder)
: this(companyFolder, applicationFolder, false)
{ }
public CommonApplicationData(string companyFolder, string applicationFolder, bool allUsers)
{
this.applicationFolder = applicationFolder;
this.companyFolder = companyFolder;
CreateFolders(allUsers);
}
public string ApplicationFolderPath
{
get { return Path.Combine(CompanyFolderPath, applicationFolder); }
}
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);
}
}
}
public override string ToString()
{
return ApplicationFolderPath;
}
}