Click here to Skip to main content
15,890,438 members
Please Sign up or sign in to vote.
4.33/5 (3 votes)
Hi Guys,

I'm once again after some advice. . .

I've recently updated some code to use a FileStream. The reason for this is I encounterred an exception due to a file being deleted by a seperate application between calling an XmlDocument.Save(path) method and calling my SetOwner(path, impersonator) method (below). Using the file stream with the FileShare.None option specified would allow me to lock the file until all operations had successfully completed.

However, after changing the code I get a System.UnauthorizedAccessException exception. On investigation it seems to be the SetAccessControl method which is throwing the exception. I've included the relevant code below, as well as showing in comments how the working method can be called.

Any idea why the FileStream.SetAccessControl throws an access exception when the File.SetAccessControl doesn't?

Thanks in advance,

JB

C#
public void WriteFile(string path, Impersonator impersonator, XmlDocument xmlFile)
{
    impersonator.Impersonate();
    using (FileStream fs = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None))
    {
        xmlFile.Save(fs);
        SetOwner(fs, impersonator); //doesn't work
        fs.Close();
    }
    //SetOwner(path, impersonator); //works
    impersonator.StopImpersonating();
}


C#
void SetOwner(string path, Impersonator impersonator)
{
    System.Security.AccessControl.FileSecurity security = File.GetAccessControl(path);
    IdentityReference owner = new NTAccount(SecurityManager.JoinAccount(impersonator.Domain, impersonator.User));
    security.SetOwner(owner); //if setting to a different account to your own, requires backup operator or admin rights, if impersonation isn't used.
    File.SetAccessControl(path,security);
}

C#
void SetOwner(FileStream fileStream, Impersonator impersonator)
{
    System.Security.AccessControl.FileSecurity security = fileStream.GetAccessControl();
    IdentityReference owner = new NTAccount(SecurityManager.JoinAccount(impersonator.Domain, impersonator.User));
    security.SetOwner(owner); //if setting to a different account to your own, requires backup operator or admin rights, if impersonation isn't used.
    fileStream.SetAccessControl(security);
}


More info on the Impersonator class can be found here, should it be of relevance (the code has changed a little since then, but the basics are the same).
http://www.codeproject.com/Messages/3656550/Re-Impersonation-using-Csharp.aspx[^]

The exception stack trace is (editted to remove my company name from the namespace):

MSIL
System.UnauthorizedAccessException: Attempted to perform an unauthorized operation.
   at System.Security.AccessControl.Win32.SetSecurityInfo(ResourceType type, String name, SafeHandle handle, SecurityInfos securityInformation, SecurityIdentifier owner, SecurityIdentifier group, GenericAcl sacl, GenericAcl dacl)
   at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, SafeHandle handle, AccessControlSections includeSections, Object exceptionContext)
   at System.Security.AccessControl.NativeObjectSecurity.Persist(SafeHandle handle, AccessControlSections includeSections, Object exceptionContext)
   at System.Security.AccessControl.FileSystemSecurity.Persist(SafeFileHandle handle, String fullPath)
   at MyCompanyName.IO.FileSecurity.SetOwner(FileStream fileStream, Impersonator impersonator) in C:\Projects\MyCompanyName.InterfaceApp.Services\MyCompanyName.IO\FileSecurity.cs:line 87
   at MyCompanyName.IO.FileSecurity.WriteFile(String path, Impersonator impersonator, XmlDocument xmlFile) in C:\Projects\MyCompanyName.InterfaceApp.Services\MyCompanyName.IO\FileSecurity.cs:line 29
   at MyCompanyName.IO.FileSecurity.WriteFile(String path, String account, XmlDocument xmlFile) in C:\Projects\MyCompanyName.InterfaceApp.Services\MyCompanyName.IO\FileSecurity.cs:line 19
   at MyCompanyName.InterfaceAppLite.Port.XmlFileSystemSendPort.SendData(InterfaceData data) in C:\Projects\MyCompanyName.InterfaceApp.Services\MyCompanyName.Port\XmlFileSystemSendPort.cs:line 91
   at MyCompanyName.InterfaceAppLite.Port.AbstractSendPort.Process() in C:\Projects\MyCompanyName.InterfaceApp.Services\MyCompanyName.Port\AbstractSendPort.cs:line 31
   at MyCompanyName.InterfaceAppLite.Common.AbstractProcess.Run() in C:\Projects\MyCompanyName.InterfaceApp.Services\MyCompanyName.InterfaceAppLite.Common\AbstractProcess.cs:line 50
Posted

You can still use File.SetAccessControl() in your new method in place of FileStream.SetAccessControl(). I'd be willing to bet it works, too. MSDN actually recommends this practice:

"While the FileStream class and SetAccessControl can be used on an existing file, consider using the File.SetAccessControl method as it is easier to use."

http://msdn.microsoft.com/en-us/library/system.io.filestream.setaccesscontrol.aspx[^]
 
Share this answer
 
That's great - thanks Rick!

I've now updated my code as per your recommendation (included below), and it works perfectly. I'd not tried this as I thought the lock was owned by the file stream, so accessing the file from a different object would cause issues - nice to learn otherwise :).

Thanks again,

JB

C#
public void WriteFile(string path, Impersonator impersonator, XmlDocument xmlFile)
{
    impersonator.Impersonate();
    using (FileStream fs = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None))
    {
        xmlFile.Save(fs);
        SetOwner(path, impersonator);
        fs.Close();
    }
    impersonator.StopImpersonating();
}
 
Share this answer
 

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900