Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET File Access Violation

Tags:

c#

.net

I feel kind of stupid posting this, but it seems like a genuine issue that I've made sufficiently simple so as to demonstrate that it should not fail. As part of my work I am responsible for maintaining build systems that take files under version control, and copy them to other locations. Sounds simple, but I've constantly experienced file access violations when attempting to copy files that I've supposedly already set as 'Normal'.

The code sample below simply creates a set of test files, makes them read only, and then copies them over to another folder. If the files already exist in the destination folder, the RO attribute is cleared so that the file copy will not fail.

The code works to a point, but at seemingly random points an exception is thrown when the file copy is attempted. The code is all single threaded, so unless .NET is doing something under the hood that causes a delay on the setting of attributes I can't really explain the problem.

If anyone can explain why this is happening I'd be interested. I'm not looking for a solution unless there is something I am definitely doing wrong, as I've handled the issue already, I'm just curious as no one else seems to have reported anything related to this.

After a few iterations I get something like:

A first chance exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.dll Additional information: Access to the path 'C:\TempFolderB\TEMPFILENAME8903.txt' is denied.

One other fact, if you get the file attributes BEFORE the file copy, the resulting state says the file attributes indeed Normal, yet examination of the local file shows it as Read Only.

    /// <summary>
    /// Test copying multiple files from one folder to another while resetting RO attr
    /// </summary>
    static void MultiFileCopyTest()
    {
        /// Temp folders for our test files
        string folderA = @"C:\TempFolderA";
        string folderB = @"C:\TempFolderB";

        /// Number of files to create
        const int fileCount = 10000;

        /// If the test folders do not exist populate them with some test files
        if (System.IO.Directory.Exists(folderA) == false)
        {
            const int bufferSize = 32768;

            System.IO.Directory.CreateDirectory(folderA);
            System.IO.Directory.CreateDirectory(folderB);

            byte[] tempBuffer = new byte[bufferSize];

            /// Create a bunch of files and make them all Read Only
            for (int i = 0; i < fileCount; i++)
            {
                string filename = folderA + "\\" + "TEMPFILENAME" + i.ToString() + ".txt";

                if (System.IO.File.Exists(filename) == false)
                {
                    System.IO.FileStream str = System.IO.File.Create(filename);
                    str.Write(tempBuffer, 0, bufferSize);
                    str.Close();
                }

                /// Ensure files are Read Only
                System.IO.File.SetAttributes(filename, System.IO.FileAttributes.ReadOnly);
            }
        }

        /// Number of iterations around the folders
        const int maxIterations = 100;

        for (int idx = 0; idx < maxIterations; idx++)
        {
            Console.WriteLine("Iteration {0}", idx);

            /// Loop for copying all files after resetting the RO attribute
            for (int i = 0; i < fileCount; i++)
            {
                string filenameA = folderA + "\\" + "TEMPFILENAME" + i.ToString() + ".txt";
                string filenameB = folderB + "\\" + "TEMPFILENAME" + i.ToString() + ".txt";

                try
                {

                    if (System.IO.File.Exists(filenameB) == true)
                    {
                        System.IO.File.SetAttributes(filenameB, System.IO.FileAttributes.Normal);
                    }

                    System.IO.File.Copy(filenameA, filenameB, true);
                }
                catch (System.UnauthorizedAccessException ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
    }
like image 736
mindeater Avatar asked Jul 23 '14 16:07

mindeater


People also ask

What causes access violation?

An access violation is a non-specific error that occurs while installing, loading, or playing a game. This error can be caused by the following: an interfering software program (usually an antivirus application), an outdated video card driver, or an outdated version of DirectX.

What is exited with code 0xC0000005 access violation?

A 0xC0000005, or access violation, indicates that you are trying to access memory that doesn't belong to your process. This usually means you haven't allocated memory.

What is an access violation C++?

As its name says, this error occurs whenever you try to access a location that you are not allowed to access in the first place. In other words, whenever you will try to violate the norms of accessing a writing location set up by the C++ programming language, you will always come across this error.


2 Answers

(This isn't a full answer, but I don't have enough reputation yet to post comments...)

I don't think you are doing anything wrong, when I run your test code I can reproduce the problem every time. I have never got past 10 iterations without the error occurring.

I did a further test, which might shed some light on the issue:

I set all of the files in TempFolderA to hidden.

I then ensured all of the files in TempFolderB were NOT hidden.

I put a break-point on Console.WriteLine(ex.Message)

I ran the code, if it got past iteration 1 then I stopped, reset the hidden attributes and ran again.

After a couple of tries, I got a failure in the 1st iteration so I opened Windows Explorer on TempFolderB and scrolled down to the problematic file.

The file was 0 bytes in size, but had RHA attributes set.

Unfortunately I have no idea why this is. Process Monitor doesn't show any other activity which could be relevant.

like image 99
Mr Dan Avatar answered Oct 02 '22 07:10

Mr Dan


Well, right in the documentation for the System.IO.File.SetAttributes(string path, System.IO.FileAttributes attributes) method, I found the following:

Exceptions: System.UnauthorizedException:
   path specified a file that is read-only.
   -or- This operation is not supported on the current platform.
   -or- The caller does not have the required permission.

So, if I had to guess, the file in the destination (e.g. filenameB) did in fact already exist. It was marked Read-Only, and so, the exception was thrown as per the documentation above.

Instead, what you need to do is remove the Read-Only attribute via an inverse bit mask:

if (FileExists(filenameB))
{
    // Remove the read-only attribute
    FileAttributes attributes = File.GetAttributes(filenameB);
    attributes &= ~FileAttributes.ReadOnly;
    File.SetAttributes(filenameB, attributes);

    // You can't OR the Normal attribute with other attributes--see MSDN.
    File.SetAttributes(filenameB, FileAttributes.Normal);
}

To be fair, the documentation on the SetAttributes method isn't real clear about how to go about setting file attributes once a file is marked as Readonly. Sure, there's an example (using the Hidden attribute), but they don't explicitly say that you need to use an inverted bitmask to remove the Hidden or Readonly attributes. One could easily assume it's just how they chose to "unset" the attribute. It's also not clear from the documentation about what would happen, for instance, if you marked the file thusly:

File.SetAttributes(pathToFile, FileAttributes.Normal);
File.SetAttributes(pathToFile, FileAttributes.Archived);

Does this result in the file first having Normal attributes set, then only Archived, or does it result in the file having Normal set, and then _additionallyhavingArchived` set, resulting in a Normal, but Archived file? I believe it's the former, rather than the latter, based on how attributes are "removed" from a file using the inverted bitmask.

If anyone finds anything contrary, please post a comment and I'll update my answer accordingly.

HTH.

like image 32
fourpastmidnight Avatar answered Oct 02 '22 05:10

fourpastmidnight