Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access Denied exception in BitOutputArchive::compressToFile #231

Open
dhananjay-gune opened this issue Aug 11, 2024 · 4 comments
Open

Access Denied exception in BitOutputArchive::compressToFile #231

dhananjay-gune opened this issue Aug 11, 2024 · 4 comments
Assignees

Comments

@dhananjay-gune
Copy link

I have whole bunch of automated test for my application and some of them randomly throw this error.
If I try again e.g. via debugger, it works.

here is my calling code:

BitArchiveEditor editor(lib, archivePath, archiveFormat);
if (!password.empty())
{
    editor.setPassword(password);
}

editor.setUpdateMode(UpdateMode::Update); // overwrites files already existing in the archive
editor.addFile(bytesInStreamToArchive, nameOfTheEntryInTheArchive); //  vector<byte_t>
editor.applyChanges();

I don't see this error in my application (user actions), but only in the automated tests.
As a work around, I have introduced a 'retry' attempt in my application, where I call the same function again and it works.

Under what circumstances would the rename() fail?
is the out_stream.Release(); still 'holding on' to the handle somehow?

Could there be another way of adding a 'stream' of bytes into the archive that might not exhibit this issue?

bitoutputarchive cpp_AccessDenied

@rikyoz rikyoz self-assigned this Aug 12, 2024
@rikyoz
Copy link
Owner

rikyoz commented Aug 12, 2024

Hi!
Most of the time, I come across such errors when the archive being modified is still opened by an instance of BitArchiveReader, e.g.:

BitArchiveReader reader(lib, archivePath, archiveFormat);
// do something with reader...

BitArchiveEditor editor(lib, archivePath, archiveFormat);
// do something with editor
editor.applyChanges(); // ERROR (cannot update the archive, as it is still opened by the reader).

BitArchiveReader is an RAII class, so the solution is usually to put the reader instance in a different scope, e.g.:

{
    BitArchiveReader reader(lib, archivePath, archiveFormat);
    // do something with reader...
} // The reader goes out of scope, releasing the archive and allowing the editor to modify it.

BitArchiveEditor editor(lib, archivePath, archiveFormat);
// do something with editor
editor.applyChanges(); // OK.

If this is not your case, I'll have to investigate it further.
I cannot rule out some strange bug in MSVC's implementation of std::filesystem::rename, in this case.

@dhananjay-gune
Copy link
Author

Many thanks for your reply.

In my workflow I make 3 calls to the archive one after the other in succession.

  1. a new archive is created as following (snippet):
if (createNewArchive)
{
    if (fileExists(archivePath))
    {
        std::filesystem::remove(archivePath);
    }
    BitFileCompressor compressor(lib, archiveFormat);
    if (!password.empty())
    {
        compressor.setPassword(password);
    }
    compressor.compress(fileMap, archivePath);
}
  1. In subsequent 2 calls, I add streams to that archive and one of them randomly throws the error.
    2024-08-12 22_20_32-Window

Is there a way to simplify this logic - say only using one class i.e. either BitArchiveWriter or BitArchiveEditor?
Are both capable of 1) creating a new archive AND 2) editing an existing file.
How to choose which one to use?

Thanks for your help 🙏

@rikyoz
Copy link
Owner

rikyoz commented Aug 13, 2024

Many thanks for your reply.

No problem!

Is there a way to simplify this logic - say only using one class i.e. either BitArchiveWriter or BitArchiveEditor?

Are both capable of 1) creating a new archive AND 2) editing an existing file.

How to choose which one to use?

In this particular case, you can just use BitArchiveWriter.

Both classes have constructors for opening already existing archives. The only difference is that BitArchiveWriter doesn't require for the archive to already exist on the filesystem, while BitArchiveEditor does (and will throw an exception in case).

BitArchiveWriter can be used to update an existing archive for adding new items (or updating existing items when setting setUpdateMode(UpdateMode::Update)).
BitArchiveEditor extends BitArchiveWriter, and adds methods for renaming/deleting items inside archives.

In other words, your code can be simplified as follows:

Bit7zLibrary lib(this->m_7ZipDllPath);
if (!fileExists(archivePath) && !createNewArchive)
{
    createNewArchive = true;
}

const BitInOutFormat& archiveFormat = convertToBit7zArchiveFormat(this->m_ArchiveFormat);

if (createNewArchive && fileExists(archivePath)) // during project creation
{
    std::filesystem::remove(archivePath);
}

BitArchiveWriter writer(lib, archivePath, archiveFormat);
if (!password.empty())
{
    writer.setPassword(password);
}
writer.setUpdateMode(UpdateMode::Update);
writer.addFile(bytesInStreamToArchive, nameOfTheEntryInTheArchive);
writer.compressTo(archivePath);

As for the random exceptions, I cannot find a possible explanation, at least reading your code.
In my tests, updating archives always work fine, provided that no other class instance (like BitArchiveReader) is keeping an open handle on them.
Also BitArchiveWriter and BitArchiveEditor keep an open handle to the input archive, if it exists, but this is automatically closed when the class instance goes out of scope.
So if all other class instances go out of scope, there shouldn't be any open handle on the archive file, and a BitArchiveWriter or BitArchiveEditor should be able to update it without issues.
Unless there's some new and unknown bug, of course.

@dhananjay-gune
Copy link
Author

🙏 Many Thanks! I will adapt my code as per your suggestions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants