Createfile com o FILE_FLAG_DELETE_ON_CLOSE FLAG
-
21-09-2019 - |
Pergunta
Antes de descrever meu problema, aqui está uma descrição do programa (ihexplorer.exe) estou escrevendo:
Este é um aplicativo C ++.
O aplicativo iHexplorer é parecer o máximo possível de uma janela do Windows Explorer. Com uma exceção, e isso é que o lançamento de arquivos dentro desta janela Explorer os descriptografará primeiro para a pasta temporária do usuário e iniciará o aplicativo associado à extensão do arquivo e excluirá o arquivo em fechamento.
O problema que estou tendo é com a exclusão automática quando o arquivo é fechado. Aqui está um cenário:
- O usuário clica duas vezes em um arquivo .txt criptografado no iHexplorer.
O iHexplorer descriptografa o arquivo .txt na memória e depois o grava para % temp % usando :: createfile, que retorna um identificador ao arquivo (o iHexplorer deve manter esse identificador aberto pelo menos até que o arquivo .txt seja executado).
O iHexplorer Shell executa o arquivo .txt (ligando para :: shellexecute) a partir da localização da temperatura.
- Agora, o iHexplorer e o bloco de notas têm uma alça no arquivo aberto.
- O arquivo deve ser excluído automaticamente quando o iHexplorer e o bloco de notas fecharam a alça no arquivo, mesmo que o iHexplorer feche primeiro.
OK. Esse é um caso básico de usuário que descreve o que eu quero que aconteça. O problema que tenho é quando eu :: shellexecute (), o bloco de notas diz "o processo não pode acessar o arquivo porque está sendo usado por outro processo". (que seria iHexplorer). Eu preciso contornar isso e o bloco de notas abri -lo mesmo enquanto ainda tenho a alça aberta no iHexplorer.
Aqui está o meu chamado para :: createfile parece:
DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
HANDLE hFile = ::CreateFile(strTempFile.c_str(), GENERIC_WRITE, dwShareMode, &sa, CREATE_NEW, dwFlagsAndAttributes, NULL);
Observe que usei FILE_SHARE_DELETE para que outros processos (como o bloco de notas) possam abrir o arquivo com o exclusão de acesso.
Observe que usei o arquivo_attribute_temporary | FILE_FLAG_DELETE_ON_CLOSE Os atributos para indicar o arquivo é temporário e devem ser excluídos em fechar.
Observe também o parâmetro & sa. Esta é a estrutura Security_attributes que estou usando, e sinto (espero) é aqui que está meu problema. Aqui está o código novamente, desta vez publicarei toda a função para que você possa ver como preencher a estrutura Security_attributes:
int CIHExplorerDoc::OpenFile(std::string strFileName, bool bIsFullPath) {
std::string strFullFilePath;
if(bIsFullPath) {
strFullFilePath = strFileName;
strFileName = IHawk::RemovePath(strFileName);
}else {
strFullFilePath = m_strDirectory + strFileName;
}
if(!HasEncryptionFileExtension(strFullFilePath)) {
LaunchFile(strFullFilePath);
}else {
//it's an encrypted file, so open it and copy unencrypted file to temp.
IHawk::EncryptedFileHandle hEncryptedFile(strFullFilePath.c_str(), true, theApp.GetKeyServer());
if(hEncryptedFile.IsValid()) {
std::string strTempFile = g_strTempFolder + IHawk::ChangeFileExtension(strFileName, "");
//TODO: Determine what the LPSECURITY_ATTRIBUTES should be.
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
if(!InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION)) {
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to initialize security descriptor. GetLastError=" << dwLastError);
return dwLastError;
}
if(!SetSecurityDescriptorDacl(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure to which the function adds the DACL
TRUE, // presence of a DACL in the security descriptor
NULL, // allows all access to the object
FALSE // DACL has been explicitly specified by a user
))
{
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor DACL. GetLastError=" << dwLastError);
return dwLastError;
}
if(!SetSecurityDescriptorGroup(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure whose primary group is set by this function
NULL, // no primary group
FALSE // Indicates whether the primary group information was derived from a default mechanism
))
{
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor primary group. GetLastError=" << dwLastError);
return dwLastError;
}
if(!SetSecurityDescriptorOwner(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure whose owner is set by this function.
NULL, // If this parameter is NULL, the function clears the security descriptor's owner information. This marks the security descriptor as having no owner.
FALSE // Indicates whether the owner information is derived from a default mechanism.
))
{
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor owner information. GetLastError=" << dwLastError);
return dwLastError;
}
if(!SetSecurityDescriptorSacl(
&sd, // A pointer to the SECURITY_DESCRIPTOR structure to which the function adds the SACL
FALSE, // the security descriptor does not contain a SACL
NULL, // security descriptor has a NULL SACL
FALSE // A pointer to a flag that is set to the value of the SE_SACL_DEFAULTED flag in the SECURITY_DESCRIPTOR_CONTROL structure if a SACL exists for the security descriptor
))
{
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Cannot launch file '" << strFullFilePath << "'. Failed to set security descriptor SACL. GetLastError=" << dwLastError);
return dwLastError;
}
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = TRUE;
DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
// DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
HANDLE hFile = ::CreateFile(strTempFile.c_str(), GENERIC_WRITE, dwShareMode, &sa, CREATE_NEW, dwFlagsAndAttributes, NULL);
//verify we created the file.
if(hFile == INVALID_HANDLE_VALUE) {
DWORD dwLastError = ::GetLastError();
return dwLastError;
}
//copy to temp
char buffer[64*1024];
size_t nBytesRead = hEncryptedFile.Read(buffer, sizeof(buffer));
while(nBytesRead) {
DWORD numBytesWritten;
if(!::WriteFile(hFile, buffer, nBytesRead, &numBytesWritten, (LPOVERLAPPED) NULL)) {
DWORD dwLastError = ::GetLastError();
LOG4CPLUS_ERROR(m_Logger, "Failed to write file to %TEMP% folder. GetLastError=" << dwLastError);
return dwLastError;
}
nBytesRead = hEncryptedFile.Read(buffer, sizeof(buffer));
}
hEncryptedFile.Close();
//execute the file from temp.
LaunchFile(strTempFile);
}
}
return 0;
}
Eu acho que se eu determinar o Security_Descriptor correto para passar para :: createfile, ele pode funcionar como eu quero. Por favor ajude.
BTW, a função de lançamento acaba chamando :: shellexecute para iniciar o arquivo.
Solução
Depois de reler o MSDN Doc, temo ter respondido minha própria pergunta. FILE_FLAG_DELETE_ON_CLOSE O arquivo deve ser excluído imediatamente após o fechamento de todas as suas alças, o que inclui o identificador especificado e qualquer outra alça aberta ou duplicada. Se houver alças abertas existentes em um arquivo, a chamada falhará, a menos que todas tenham sido abertas com o modo de compartilhamento File_Share_Delete. As solicitações abertas subsequentes para o arquivo falharem, a menos que o modo FILE_SHARE_DELETE seja especificado. No meu caso, duvido que o bloco de notas esteja solicitando a permissão File_Share_Delete, para que não possa abrir o arquivo