Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r82797 - trunk/boost/interprocess/detail
From: igaztanaga_at_[hidden]
Date: 2013-02-09 12:48:30


Author: igaztanaga
Date: 2013-02-09 12:48:29 EST (Sat, 09 Feb 2013)
New Revision: 82797
URL: http://svn.boost.org/trac/boost/changeset/82797

Log:
Fixes #7923
Text files modified:
   trunk/boost/interprocess/detail/os_file_functions.hpp | 2
   trunk/boost/interprocess/detail/win32_api.hpp | 327 ++++++++++++++++++++++-----------------
   2 files changed, 187 insertions(+), 142 deletions(-)

Modified: trunk/boost/interprocess/detail/os_file_functions.hpp
==============================================================================
--- trunk/boost/interprocess/detail/os_file_functions.hpp (original)
+++ trunk/boost/interprocess/detail/os_file_functions.hpp 2013-02-09 12:48:29 EST (Sat, 09 Feb 2013)
@@ -278,7 +278,7 @@
                //if(::SetFileAttributes(strFilePath.c_str(), winapi::file_attribute_normal) == 0)
                //return winapi::get_last_error();
                // Delete file
- winapi::delete_file(strFilePath.c_str());
+ winapi::unlink_file(strFilePath.c_str());
             }
          }
       //Go to the next file

Modified: trunk/boost/interprocess/detail/win32_api.hpp
==============================================================================
--- trunk/boost/interprocess/detail/win32_api.hpp (original)
+++ trunk/boost/interprocess/detail/win32_api.hpp 2013-02-09 12:48:29 EST (Sat, 09 Feb 2013)
@@ -90,6 +90,7 @@
 static const int file_share_valid_flags = 0x00000007;
 static const long file_delete_on_close = 0x00001000L;
 static const long obj_case_insensitive = 0x00000040L;
+static const long delete_flag = 0x00010000L;
 
 static const unsigned long movefile_copy_allowed = 0x02;
 static const unsigned long movefile_delay_until_reboot = 0x04;
@@ -834,6 +835,8 @@
    wchar_t NameBuffer[1];
 };
 
+//Kernel32.dll
+
 //Some windows API declarations
 extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
 extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
@@ -870,8 +873,6 @@
 extern "C" __declspec(dllimport) void * __stdcall MapViewOfFileEx (void *, unsigned long, unsigned long, unsigned long, std::size_t, void*);
 extern "C" __declspec(dllimport) void * __stdcall OpenFileMappingA (unsigned long, int, const char *);
 extern "C" __declspec(dllimport) void * __stdcall CreateFileA (const char *, unsigned long, unsigned long, struct interprocess_security_attributes*, unsigned long, unsigned long, void *);
-extern "C" __declspec(dllimport) int __stdcall DeleteFileA (const char *);
-extern "C" __declspec(dllimport) int __stdcall MoveFileExA (const char *, const char *, unsigned long);
 extern "C" __declspec(dllimport) void __stdcall GetSystemInfo (struct system_info *);
 extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile (void *, std::size_t);
 extern "C" __declspec(dllimport) int __stdcall VirtualUnlock (void *, std::size_t);
@@ -904,13 +905,14 @@
 extern "C" __declspec(dllimport) void *__stdcall GetProcAddress(void *, const char*);
 extern "C" __declspec(dllimport) void *__stdcall GetModuleHandleA(const char*);
 extern "C" __declspec(dllimport) void *__stdcall GetFileInformationByHandle(void *, interprocess_by_handle_file_information*);
-extern "C" __declspec(dllimport) unsigned long __stdcall GetMappedFileNameW(void *, void *, wchar_t *, unsigned long);
+extern "C" __declspec(dllimport) int __stdcall QueryPerformanceCounter(__int64 *lpPerformanceCount);
+
+//Advapi32.dll
 extern "C" __declspec(dllimport) long __stdcall RegOpenKeyExA(void *, const char *, unsigned long, unsigned long, void **);
 extern "C" __declspec(dllimport) long __stdcall RegQueryValueExA(void *, const char *, unsigned long*, unsigned long*, unsigned char *, unsigned long*);
 extern "C" __declspec(dllimport) long __stdcall RegCloseKey(void *);
-extern "C" __declspec(dllimport) int __stdcall QueryPerformanceCounter(__int64 *lpPerformanceCount);
 
-//COM API
+//Ole32.dll
 extern "C" __declspec(dllimport) long __stdcall CoInitializeEx(void *pvReserved, unsigned long dwCoInit);
 extern "C" __declspec(dllimport) long __stdcall CoInitializeSecurity(
                     void* pSecDesc,
@@ -932,18 +934,19 @@
                      unsigned long dwImpLevel,
                      void *pAuthInfo,
                      unsigned long dwCapabilities);
-
-extern "C" __declspec(dllimport) long __stdcall VariantClear(wchar_variant * pvarg);
 extern "C" __declspec(dllimport) long __stdcall CoCreateInstance(const GUID_BIPC & rclsid, IUnknown_BIPC *pUnkOuter,
                     unsigned long dwClsContext, const GUID_BIPC & riid, void** ppv);
 extern "C" __declspec(dllimport) void __stdcall CoUninitialize(void);
 
+//OleAut32.dll
+extern "C" __declspec(dllimport) long __stdcall VariantClear(wchar_variant * pvarg);
 
 
-//API function typedefs
-//Pointer to functions
+//ntdll.dll
 typedef long (__stdcall *NtDeleteFile_t)(object_attributes_t *ObjectAttributes);
 typedef long (__stdcall *NtSetInformationFile_t)(void *FileHandle, io_status_block_t *IoStatusBlock, void *FileInformation, unsigned long Length, int FileInformationClass );
+typedef long (__stdcall *NtOpenFile)(void **FileHandle, unsigned long DesiredAccess, object_attributes_t *ObjectAttributes
+ , io_status_block_t *IoStatusBlock, unsigned long ShareAccess, unsigned long Length, unsigned long OpenOptions);
 typedef long (__stdcall *NtQuerySystemInformation_t)(int, void*, unsigned long, unsigned long *);
 typedef long (__stdcall *NtQueryObject_t)(void*, object_information_class, void *, unsigned long, unsigned long *);
 typedef long (__stdcall *NtQuerySemaphore_t)(void*, unsigned int info_class, interprocess_semaphore_basic_information *pinfo, unsigned int info_size, unsigned int *ret_len);
@@ -951,14 +954,6 @@
 typedef long (__stdcall *NtQueryInformationFile_t)(void *,io_status_block_t *,void *, long, int);
 typedef long (__stdcall *NtOpenFile_t)(void*,unsigned long ,object_attributes_t*,io_status_block_t*,unsigned long,unsigned long);
 typedef long (__stdcall *NtClose_t) (void*);
-typedef long (__stdcall *RtlCreateUnicodeStringFromAsciiz_t)(unicode_string_t *, const char *);
-typedef void (__stdcall *RtlFreeUnicodeString_t)(unicode_string_t *);
-typedef void (__stdcall *RtlInitUnicodeString_t)( unicode_string_t *, const wchar_t * );
-typedef long (__stdcall *RtlAppendUnicodeToString_t)(unicode_string_t *Destination, const wchar_t *Source);
-typedef unsigned long (__stdcall * GetMappedFileName_t)(void *, void *, wchar_t *, unsigned long);
-typedef long (__stdcall * RegOpenKeyEx_t)(void *, const char *, unsigned long, unsigned long, void **);
-typedef long (__stdcall * RegQueryValueEx_t)(void *, const char *, unsigned long*, unsigned long*, unsigned char *, unsigned long*);
-typedef long (__stdcall * RegCloseKey_t)(void *);
 
 } //namespace winapi {
 } //namespace interprocess {
@@ -1125,12 +1120,6 @@
    return invalid_handle_value;
 }
 
-inline bool delete_file(const char *name)
-{ return 0 != DeleteFileA(name); }
-
-inline bool move_file_ex(const char *source_filename, const char *destination_filename, unsigned long flags)
-{ return 0 != MoveFileExA(source_filename, destination_filename, flags); }
-
 inline void get_system_info(system_info *info)
 { GetSystemInfo(info); }
 
@@ -1213,9 +1202,6 @@
 inline void *get_module_handle(const char *name)
 { return GetModuleHandleA(name); }
 
-inline unsigned long get_mapped_file_name(void *process, void *lpv, wchar_t *lpfilename, unsigned long nSize)
-{ return GetMappedFileNameW(process, lpv, lpfilename, nSize); }
-
 inline long reg_open_key_ex(void *hKey, const char *lpSubKey, unsigned long ulOptions, unsigned long samDesired, void **phkResult)
 { return RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult); }
 
@@ -1254,11 +1240,14 @@
 template<int Dummy>
 struct function_address_holder
 {
- enum { NtSetInformationFile, NtQuerySystemInformation, NtQueryObject, NtQuerySemaphore, NtQuerySection, NumFunction };
+ enum { NtSetInformationFile, NtQuerySystemInformation, NtQueryObject, NtQuerySemaphore, NtQuerySection, NtOpenFile, NtClose, NumFunction };
    enum { NtDll_dll, NumModule };
 
    private:
+ static const char *FunctionNames[NumFunction];
+ static const char *ModuleNames[NumModule];
    static void *FunctionAddresses[NumFunction];
+ static unsigned int FunctionModules[NumFunction];
    static volatile long FunctionStates[NumFunction];
    static void *ModuleAddresses[NumModule];
    static volatile long ModuleStates[NumModule];
@@ -1266,10 +1255,7 @@
    static void *get_module_from_id(unsigned int id)
    {
       assert(id < (unsigned int)NumModule);
- const char *module[] = { "ntdll.dll" };
- bool compile_check[sizeof(module)/sizeof(module[0]) == NumModule];
- (void)compile_check;
- return get_module_handle(module[id]);
+ return get_module_handle(ModuleNames[id]);
    }
 
    static void *get_module(const unsigned int id)
@@ -1291,10 +1277,7 @@
    static void *get_address_from_dll(const unsigned int id)
    {
       assert(id < (unsigned int)NumFunction);
- const char *function[] = { "NtSetInformationFile", "NtQuerySystemInformation", "NtQueryObject", "NtQuerySemaphore", "NtQuerySection" };
- bool compile_check[sizeof(function)/sizeof(function[0]) == NumFunction];
- (void)compile_check;
- return get_proc_address(get_module(NtDll_dll), function[id]);
+ return get_proc_address(get_module(FunctionModules[id]), FunctionNames[id]);
    }
 
    public:
@@ -1316,6 +1299,37 @@
 };
 
 template<int Dummy>
+const char *function_address_holder<Dummy>::FunctionNames[function_address_holder<Dummy>::NumFunction] =
+{
+ "NtSetInformationFile",
+ "NtQuerySystemInformation",
+ "NtQueryObject",
+ "NtQuerySemaphore",
+ "NtQuerySection",
+ "NtOpenFile",
+ "NtClose"
+};
+
+template<int Dummy>
+unsigned int function_address_holder<Dummy>::FunctionModules[function_address_holder<Dummy>::NumFunction] =
+{
+ NtDll_dll,
+ NtDll_dll,
+ NtDll_dll,
+ NtDll_dll,
+ NtDll_dll,
+ NtDll_dll,
+ NtDll_dll
+};
+
+template<int Dummy>
+const char *function_address_holder<Dummy>::ModuleNames[function_address_holder<Dummy>::NumModule] =
+{
+ "ntdll.dll"
+};
+
+
+template<int Dummy>
 void *function_address_holder<Dummy>::FunctionAddresses[function_address_holder<Dummy>::NumFunction];
 
 template<int Dummy>
@@ -1340,47 +1354,6 @@
    ~library_unloader(){ free_library(lib_); }
 };
 
-//pszFilename must have room for at least MaxPath+1 characters
-inline bool get_file_name_from_handle_function
- (void * hFile, wchar_t *pszFilename, std::size_t length, std::size_t &out_length)
-{
- if(length <= MaxPath){
- return false;
- }
-
-// void *hiPSAPI = load_library("PSAPI.DLL");
-// if (0 == hiPSAPI)
-// return 0;
-// library_unloader unloader(hiPSAPI);
-
-// Pointer to function getMappedFileName() in PSAPI.DLL
-// GetMappedFileName_t pfGMFN =
-// (GetMappedFileName_t)get_proc_address(hiPSAPI, "GetMappedFileNameW");
-// if (! pfGMFN){
-// return 0; // Failed: unexpected error
-// }
-
- bool bSuccess = false;
-
- // Create a file mapping object.
- void * hFileMap = create_file_mapping(hFile, page_readonly, 1, 0, 0);
- if(hFileMap){
- // Create a file mapping to get the file name.
- void* pMem = map_view_of_file_ex(hFileMap, file_map_read, 0, 1, 0);
-
- if (pMem){
- //out_length = pfGMFN(get_current_process(), pMem, pszFilename, MaxPath);
- out_length = get_mapped_file_name(get_current_process(), pMem, pszFilename, MaxPath);
- if(out_length){
- bSuccess = true;
- }
- unmap_view_of_file(pMem);
- }
- close_handle(hFileMap);
- }
-
- return(bSuccess);
-}
 
 inline bool get_system_time_of_day_information(system_timeofday_information &info)
 {
@@ -1437,6 +1410,21 @@
    return true;
 }
 
+//Writes the hexadecimal value of the buffer, in the wide character string.
+//str must be twice length
+inline void buffer_to_wide_str(const void *buf, std::size_t length, wchar_t *str)
+{
+ const wchar_t Characters [] =
+ { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7'
+ , L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F' };
+ std::size_t char_counter = 0;
+ const char *chbuf = static_cast<const char *>(buf);
+ for(std::size_t i = 0; i != length; ++i){
+ str[char_counter++] = Characters[(chbuf[i]&0xF0)>>4];
+ str[char_counter++] = Characters[(chbuf[i]&0x0F)];
+ }
+}
+
 inline bool get_boot_and_system_time_wstr(wchar_t *bootsystemstamp, std::size_t &s) //will write BootAndSystemstampLength chars
 {
    if(s < (BootAndSystemstampLength*2))
@@ -1446,14 +1434,8 @@
    if(!ret){
       return false;
    }
- const wchar_t Characters [] =
- { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7'
- , L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F' };
- std::size_t char_counter = 0;
- for(std::size_t i = 0; i != static_cast<std::size_t>(BootAndSystemstampLength); ++i){
- bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4];
- bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0x0F)];
- }
+
+ buffer_to_wide_str(&info.Reserved1[0], BootAndSystemstampLength, bootsystemstamp);
    s = BootAndSystemstampLength*2;
    return true;
 }
@@ -1475,10 +1457,51 @@
    struct ren_t
    {
       file_rename_information_t info;
- wchar_t buf[32767];
+ wchar_t buf[1];
    } ren;
 };
 
+class nt_query_mem_deleter
+{
+ static const std::size_t rename_offset = offsetof(ntquery_mem_t, ren.info.FileName) -
+ offsetof(ntquery_mem_t, name.Name.Buffer);
+ // Timestamp process id atomic count
+ static const std::size_t rename_suffix = (SystemTimeOfDayInfoLength + sizeof(unsigned long) + sizeof(boost::uint32_t))*2;
+
+ public:
+ nt_query_mem_deleter(std::size_t object_name_information_size)
+ : m_size(object_name_information_size + rename_offset + rename_suffix)
+ , m_buf(new char [m_size])
+ {}
+
+ ~nt_query_mem_deleter()
+ {
+ delete[]m_buf;
+ }
+
+ void realloc(std::size_t num_bytes)
+ {
+ num_bytes += rename_suffix + rename_offset;
+ char *buf = m_buf;
+ m_buf = new char[num_bytes];
+ delete[]buf;
+ m_size = num_bytes;
+ }
+
+ ntquery_mem_t *query_mem() const
+ { return static_cast<ntquery_mem_t *>(static_cast<void*>(m_buf)); }
+
+ unsigned long object_name_information_size() const
+ { return static_cast<unsigned long>(m_size - rename_offset - SystemTimeOfDayInfoLength*2); }
+
+ std::size_t file_rename_information_size() const
+ { return static_cast<unsigned long>(m_size); }
+
+ private:
+ std::size_t m_size;
+ char *m_buf;
+};
+
 inline bool unlink_file(const char *filename)
 {
    //Don't try to optimize doing a DeleteFile first
@@ -1499,71 +1522,96 @@
    try{
       NtSetInformationFile_t pNtSetInformationFile =
          (NtSetInformationFile_t)dll_func::get(dll_func::NtSetInformationFile);
- if(!pNtSetInformationFile){
- return false;
- }
 
- NtQueryObject_t pNtQueryObject =
- (NtQueryObject_t)dll_func::get(dll_func::NtQueryObject);
+ NtQueryObject_t pNtQueryObject = (NtQueryObject_t)dll_func::get(dll_func::NtQueryObject);
 
       //First step: Obtain a handle to the file using Win32 rules. This resolves relative paths
- void *fh = create_file(filename, generic_read | delete_access, open_existing,
- file_flag_backup_semantics | file_flag_delete_on_close, 0);
+ void *fh = create_file(filename, generic_read | delete_access, open_existing, 0, 0);
       if(fh == invalid_handle_value){
          return false;
       }
 
       handle_closer h_closer(fh);
+ {
+ //Obtain name length
+ unsigned long size;
+ const std::size_t initial_string_mem = 512u;
+
+ nt_query_mem_deleter nt_query_mem(sizeof(ntquery_mem_t)+initial_string_mem);
+ //Obtain file name with guessed length
+ if(pNtQueryObject(fh, object_name_information, nt_query_mem.query_mem(), nt_query_mem.object_name_information_size(), &size)){
+ //Obtain file name with exact length buffer
+ nt_query_mem.realloc(size);
+ if(pNtQueryObject(fh, object_name_information, nt_query_mem.query_mem(), nt_query_mem.object_name_information_size(), &size)){
+ return false;
+ }
+ }
+ ntquery_mem_t *pmem = nt_query_mem.query_mem();
+ file_rename_information_t *pfri = &pmem->ren.info;
+ const std::size_t RenMaxNumChars =
+ (((char*)(pmem) + nt_query_mem.file_rename_information_size()) - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t);
+
+ //Copy filename to the rename member
+ std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length);
+ std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t);
+
+ //Search '\\' character to replace from it
+ for(std::size_t i = filename_string_length; i != 0; --filename_string_length){
+ if(pmem->ren.info.FileName[--i] == L'\\')
+ break;
+ }
 
- std::auto_ptr<ntquery_mem_t> pmem(new ntquery_mem_t);
- file_rename_information_t *pfri = &pmem->ren.info;
- const std::size_t RenMaxNumChars =
- ((char*)pmem.get() - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t);
-
- //Obtain file name
- unsigned long size;
- if(pNtQueryObject(fh, object_name_information, pmem.get(), sizeof(ntquery_mem_t), &size)){
- return false;
- }
-
- //Copy filename to the rename member
- std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length);
- std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t);
-
- //Second step: obtain the complete native-nt filename
- //if(!get_file_name_from_handle_function(fh, pfri->FileName, RenMaxNumChars, filename_string_length)){
- //return 0;
- //}
-
- //Add trailing mark
- if((RenMaxNumChars-filename_string_length) < (SystemTimeOfDayInfoLength*2)){
- return false;
- }
-
- //Search '\\' character to replace it
- for(std::size_t i = filename_string_length; i != 0; --filename_string_length){
- if(pmem->ren.info.FileName[--i] == L'\\')
- break;
- }
+ //Add random number
+ std::size_t s = RenMaxNumChars - filename_string_length;
+ if(!get_boot_and_system_time_wstr(&pfri->FileName[filename_string_length], s)){
+ return false;
+ }
+ filename_string_length += s;
 
- //Add random number
- std::size_t s = RenMaxNumChars - filename_string_length;
- if(!get_boot_and_system_time_wstr(&pfri->FileName[filename_string_length], s)){
- return false;
+ //Sometimes the precission of the timestamp is not enough and we need to add another random number.
+ //The process id (to exclude concurrent processes) and an atomic count (to exclude concurrent threads).
+ //should be enough
+ const unsigned long pid = get_current_process_id();
+ buffer_to_wide_str(&pid, sizeof(pid), &pfri->FileName[filename_string_length]);
+ filename_string_length += sizeof(pid)*2;
+
+ static volatile boost::uint32_t u32_count = 0;
+ interlocked_decrement(reinterpret_cast<volatile long*>(&u32_count));
+ buffer_to_wide_str(const_cast<const boost::uint32_t *>(&u32_count), sizeof(boost::uint32_t), &pfri->FileName[filename_string_length]);
+ filename_string_length += sizeof(boost::uint32_t)*2;
+
+ //Fill rename information (FileNameLength is in bytes)
+ pfri->FileNameLength = static_cast<unsigned long>(sizeof(wchar_t)*(filename_string_length));
+ pfri->Replace = 1;
+ pfri->RootDir = 0;
+
+ //Cange the name of the in-use file...
+ io_status_block_t io;
+ if(0 != pNtSetInformationFile(fh, &io, pfri, nt_query_mem.file_rename_information_size(), file_rename_information)){
+ return false;
+ }
       }
- filename_string_length += s;
-
- //Fill rename information (FileNameLength is in bytes)
- pfri->FileNameLength = static_cast<unsigned long>(sizeof(wchar_t)*(filename_string_length));
- pfri->Replace = 1;
- pfri->RootDir = 0;
-
- //Final step: change the name of the in-use file:
- io_status_block_t io;
- if(0 != pNtSetInformationFile(fh, &io, pfri, sizeof(ntquery_mem_t::ren_t), file_rename_information)){
- return false;
+ //...and mark it as delete-on-close
+ {
+ //Don't use pNtSetInformationFile with file_disposition_information as it can return STATUS_CANNOT_DELETE
+ //if the file is still mapped. Reopen it with NtOpenFile and file_delete_on_close
+ NtOpenFile_t pNtOpenFile = (NtOpenFile_t)dll_func::get(dll_func::NtOpenFile);
+ NtClose_t pNtClose = (NtClose_t)dll_func::get(dll_func::NtClose);
+ const wchar_t empty_str [] = L"";
+ unicode_string_t ustring = { sizeof(empty_str) - sizeof (wchar_t) //length in bytes without null
+ , sizeof(empty_str) //total size in bytes of memory allocated for Buffer.
+ , const_cast<wchar_t*>(empty_str)
+ };
+ object_attributes_t object_attr;
+ initialize_object_attributes(&object_attr, &ustring, 0, fh, 0);
+ void* fh2 = 0;
+ io_status_block_t io;
+ pNtOpenFile( &fh2, delete_flag, &object_attr, &io
+ , file_share_read | file_share_write | file_share_delete, file_delete_on_close);
+ pNtClose(fh2);
+ //Even if NtOpenFile fails, the file was renamed and the original no longer exists, so return a success status
+ return true;
       }
- return true;
    }
    catch(...){
       return false;
@@ -1573,9 +1621,6 @@
 
 struct reg_closer
 {
- //reg_closer(RegCloseKey_t func, void *key) : func_(func), key_(key){}
- //~reg_closer(){ (*func_)(key_); }
- //RegCloseKey_t func_;
    void *key_;
    reg_closer(void *key) : key_(key){}
    ~reg_closer(){ reg_close_key(key_); }


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk