diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4f762c6d2..794607dfa 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -22,5 +22,4 @@ In case of BSOD, please attach minidump or dump analyze output. # Support - Usage: - - - Your personal priority to solve this issue: - Support ability: diff --git a/.gitignore b/.gitignore index f4f436269..17d6e7196 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,5 @@ ReleasePS /dokan_wix/disk1 /dokan_wix/setup.inf /dokan_wix/setup.rpt +/fstools +/winfstest diff --git a/CHANGELOG.md b/CHANGELOG.md index 53aca8406..00b18ed20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,15 +3,52 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased] - 1.0.1.0000 +## [Unreleased] - 1.0.3.1000 + +## [1.0.2.1000] - 2017-01-20 +### Added +- FUSE - Add libfuse-compatible pkg-config +- Mirror - Add `DOKAN_OPTION_FILELOCK_USER_MODE` option with `/f` + +### Changed +- FUSE - Use pkg-config for building mirror +- Kernel - Many improvement allocation stack and heap +- Kernel - Enable PAGED_CODE for `DokanCheckShareAccess` +- Mirror - Return empty SACL if mirror doesn't have SeSecurityPrivilege +- Library - Use DeleteMountPoint for removing reparse point instead of `DeleteVolumeMountPoint` +- Library - Remove Redundant control flow jump + +### Fixed +- Driver - Less wide locking +- Kernel - Align security descriptor to 4-byte boundary in `DokanDispatchSetSecurity` +- Library - Fix dokan context leak when CreateFile fail +- Kernel - Fix BSOD. When drive is started using n option and procmon is attached the rename of files in the root folder is not possible +- Kernel - Relative path rename +- Library - Write Set correctly the userland NtStatus + +## [1.0.1.1000] - 2016-11-04 +### Added +- Library - `DokanMapStandardToGenericAccess` - Convert `IRP_MJ_CREATE` DesiredAccess to generic rights. ### Changed - Driver - Use atomic operations for FCB and CCB flags instead of locks. - Update Windows SDK to 10.0.14393 -- Library - Call now DeleteFile and DeleteDirectory with DeleteOnClose set at a delete request OR canceled. +- Library - Call now `DeleteFile` and `DeleteDirectory` with `DeleteOnClose` set at a delete request OR canceled. +- Driver - Double check that the returned security descriptor is valid before returning success on QuerySecurity. +- Installer - Enable dev tools by default. +- Driver - Return `STATUS_FILE_LOCKED_WITH_ONLY_READERS` during `PreAcquireForSectionSynchronization` when locked only with readers. +- Mirror - Open handle when `GetFileInformation` requested after cleanup. +- Kernel - Remove FCB `Resource` and `MainResource`. Use FCB Header `Resource` instead allocated with LookasideList. ### Fixed -- Driver - `CcPurgeCacheSection` could cause deadlock when fcb was locked in the same time. +- Driver - `CcPurgeCacheSection` could cause deadlock when FCB was locked in the same time. +- Driver - Deadlock on related FCB. +- FUSE - Race condition in Dokan FUSE. +- Driver - BSOD issue related to filesystem mount on Windows 10 build 14936. +- Driver - Unlock FCB during `FsRtlOplockBreakH` to let other request Lock FCB. +- FUSE - Set correctly Authenticated Users rights (Explorer menu context). +- Mirror - Reject when trying to open a file as a directory. +- Driver - Return correct status for `FSCTL_FILESYSTEM_GET_STATISTICS` - Can now net share on Windows Server 2012 R2 ## [1.0.0.5000] - 2016-09-20 ### Added @@ -198,7 +235,8 @@ Latest Dokan version from Hiroki Asakawa. [http://dokan-dev.net/en]( http://web.archive.org/web/20150419082954/http://dokan-dev.net/en/) -[Unreleased]: https://github.com/dokan-dev/dokany/compare/v1.0.0...master +[Unreleased]: https://github.com/dokan-dev/dokany/compare/v1.0.1...master +[1.0.1.1000]: https://github.com/dokan-dev/dokany/compare/v1.0.0...v1.0.1 [1.0.0.5000]: https://github.com/dokan-dev/dokany/compare/v0.8.0...v1.0.0 [0.8.0]: https://github.com/dokan-dev/dokany/compare/v0.7.4...v0.8.0 [0.7.4]: https://github.com/dokan-dev/dokany/compare/0.7.2...v0.7.4 diff --git a/Dokan.props b/Dokan.props index fe5b85b50..f6855ef43 100644 --- a/Dokan.props +++ b/Dokan.props @@ -3,7 +3,7 @@ 1 - 1.0.1 + 1.0.2 diff --git a/appveyor.yml b/appveyor.yml index afdbf5ad1..687e27603 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -71,7 +71,7 @@ function updateCygwin($cygwinexe, $installFolder, $cacheFolder) { Write-Host "Update Cygwin: $cygwinexe" - Exec-External {& cmd /c $cygwinexe -gqnNdO -R $installFolder -s http://mirrors.kernel.org/sourceware/cygwin/ -l $cacheFolder -P cmake -P make -P gcc-core -P gcc-g++} + Exec-External {& cmd /c $cygwinexe -gqnNdO -R $installFolder -s http://mirrors.kernel.org/sourceware/cygwin/ -l $cacheFolder -P cmake -P make -P gcc-core -P gcc-g++ -P pkg-config} Write-Host "Update Cygwin: $cygwinexe " -NoNewLine Write-Host "[ OK ]" -ForegroundColor Green } @@ -224,52 +224,30 @@ $buildArgs = @( "/m", "/l:C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll", - "/p:Configuration=Win10 Debug", + "/p:Configuration=Win8.1 Release", "/p:Platform=$env:PLATFORM") & $buildCmd $buildArgs - - installDokanCert - - .\cert\dokan-sign.ps1 - cp .\x64\Win10Debug\dokan1.sys C:\Windows\System32\drivers\ - Exec-External {& .\x64\Debug\dokanctl.exe /i d} - Exec-External {& .\x64\Debug\dokanctl.exe /i n} - New-Item C:\TMP -type directory | Out-Null - - $app = Start-Process -passthru .\x64\Debug\mirror.exe -ArgumentList "/r C:\TMP /l m" - Start-Sleep -s 5 - - Exec-External {git clone -q https://github.com/Liryna/fstools.git} $buildArgs = @( - ".\fstools\winfstest.sln", "/m", "/l:C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll", "/p:Configuration=Release", "/p:Platform=$env:PLATFORM") - Exec-External {& $buildCmd $buildArgs} - Exec-External {git clone -q https://github.com/Liryna/winfstest.git} - $buildArgs = @( - ".\winfstest\winfstest.sln", - "/m", - "/l:C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll", - "/p:Configuration=Debug", - "/p:Platform=$env:PLATFORM") - Exec-External {& $buildCmd $buildArgs} + & $buildCmd $buildArgs + + installDokanCert - Write-Host "Start FSX Test" -ForegroundColor Green - Exec-External {& .\fstools\src\fsx\fsx.exe -N 5000 M:\test} - Write-Host "FSX Test finished" -ForegroundColor Green + .\cert\dokan-sign.ps1 + + cp .\x64\Win8.1Release\dokan1.sys C:\Windows\System32\drivers\ + Exec-External {& .\x64\Release\dokanctl.exe /i d} + Exec-External {& .\x64\Release\dokanctl.exe /i n} + + cd .\samples + .\mirror_test.ps1 - Write-Host "Start WinFSTest" -ForegroundColor Green - Exec-External {& .\winfstest\TestSuite\run-winfstest.bat . M:\} - Write-Host "WinFSTest finished" -ForegroundColor Green - - Start-Sleep -s 5 - Stop-Process $app.Id - Start-Sleep -s 5 Exec-External {& verifier /query} } Write-Host Build Finished ! diff --git a/documentations/Doxyfile b/documentations/Doxyfile index 504629a1c..b3438abfa 100644 --- a/documentations/Doxyfile +++ b/documentations/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = Dokan # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.0.0 +PROJECT_NUMBER = 1.0.2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/dokan/access.c b/dokan/access.c index 734c692d7..dc4d2c1f7 100644 --- a/dokan/access.c +++ b/dokan/access.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/dokan/cleanup.c b/dokan/cleanup.c index 381efc9c6..ad1ea953a 100644 --- a/dokan/cleanup.c +++ b/dokan/cleanup.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -49,5 +49,4 @@ VOID DispatchCleanup(HANDLE Handle, PEVENT_CONTEXT EventContext, SendEventInformation(Handle, eventInfo, sizeOfEventInfo, DokanInstance); free(eventInfo); - return; } diff --git a/dokan/close.c b/dokan/close.c index bbc4285e9..ac1fe42b6 100644 --- a/dokan/close.c +++ b/dokan/close.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -55,6 +55,4 @@ VOID DispatchClose(HANDLE Handle, PEVENT_CONTEXT EventContext, } ReleaseDokanOpenInfo(eventInfo, DokanInstance); free(eventInfo); - - return; } diff --git a/dokan/create.c b/dokan/create.c index ca0d5cce6..f21817ea4 100644 --- a/dokan/create.c +++ b/dokan/create.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -332,5 +332,7 @@ VOID DispatchCreate(HANDLE Handle, // This handle is not for a file. It is for SendEventInformation(Handle, &eventInfo, sizeof(EVENT_INFORMATION), DokanInstance); - return; + + if (eventInfo.Status != STATUS_SUCCESS) + free((PDOKAN_OPEN_INFO)(UINT_PTR)eventInfo.Context); } diff --git a/dokan/directory.c b/dokan/directory.c index a2b6f3dbe..3efabd834 100644 --- a/dokan/directory.c +++ b/dokan/directory.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -441,8 +441,8 @@ VOID AddMissingCurrentAndParentFolder(PEVENT_CONTEXT EventContext, currentFolder = TRUE; if (wcscmp(find->FindData.cFileName, L"..") == 0) parentFolder = TRUE; - if (currentFolder == TRUE && parentFolder == TRUE) - return; // folders are already there + if (currentFolder == TRUE && parentFolder == TRUE) + return; // folders are already there } GetSystemTimeAsFileTime(&systime); @@ -611,7 +611,6 @@ VOID DispatchDirectoryInformation(HANDLE Handle, PEVENT_CONTEXT EventContext, // send directory information to driver SendEventInformation(Handle, eventInfo, sizeOfEventInfo, DokanInstance); free(eventInfo); - return; } #define DOS_STAR (L'<') diff --git a/dokan/dokan.c b/dokan/dokan.c index aa224c1b9..e032b9bcb 100644 --- a/dokan/dokan.c +++ b/dokan/dokan.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -774,29 +774,36 @@ BOOL SendToDevice(LPCWSTR DeviceName, DWORD IoControlCode, PVOID InputBuffer, BOOL DOKANAPI DokanGetMountPointList(PDOKAN_CONTROL list, ULONG length, BOOL uncOnly, PULONG nbRead) { ULONG returnedLength = 0; + PDOKAN_CONTROL dokanControl = + malloc(DOKAN_MAX_INSTANCES * sizeof(*dokanControl)); + if (dokanControl == NULL) { + return FALSE; + } - DOKAN_CONTROL dokanControl[DOKAN_MAX_INSTANCES]; - ZeroMemory(dokanControl, sizeof(dokanControl)); + ZeroMemory(dokanControl, DOKAN_MAX_INSTANCES * sizeof(*dokanControl)); *nbRead = 0; if (SendToDevice(DOKAN_GLOBAL_DEVICE_NAME, IOCTL_EVENT_MOUNTPOINT_LIST, NULL, - 0, dokanControl, sizeof(dokanControl), &returnedLength)) { + 0, dokanControl, sizeof(*dokanControl), &returnedLength)) { for (int i = 0; i < DOKAN_MAX_INSTANCES; ++i) { if (wcscmp(dokanControl[i].DeviceName, L"") == 0) { break; } if (!uncOnly || wcscmp(dokanControl[i].UNCName, L"") != 0) { - if (length < ((*nbRead) + 1)) + if (length < ((*nbRead) + 1)) { + free(dokanControl); return TRUE; + } CopyMemory(&list[*nbRead], &dokanControl[i], sizeof(DOKAN_CONTROL)); (*nbRead)++; } } - + free(dokanControl); return TRUE; } + free(dokanControl); return FALSE; } @@ -829,6 +836,7 @@ BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, LPVOID Reserved) { LeaveCriticalSection(&g_InstanceCriticalSection); DeleteCriticalSection(&g_InstanceCriticalSection); } break; + default: break; } return TRUE; } diff --git a/dokan/dokan.h b/dokan/dokan.h index cbfa088f3..7e9eaa8f0 100644 --- a/dokan/dokan.h +++ b/dokan/dokan.h @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -202,6 +202,8 @@ typedef struct _DOKAN_OPERATIONS { * If the file is a directory, CreateFile is also called. * In this case, CreateFile should return \c STATUS_SUCCESS when that directory * can be opened and DOKAN_FILE_INFO.IsDirectory has to be set to \c TRUE. + * On the other hand, if DOKAN_FILE_INFO.IsDirectory is set to \c TRUE + * but the path target a file, you need to return \c STATUS_NOT_A_DIRECTORY. * * DOKAN_FILE_INFO.Context can be use to store Data (like \c HANDLE) * that can be retrieved in all other request related to the Context diff --git a/dokan/dokan.rc b/dokan/dokan.rc index cb8bd6d47..f44986096 100644 --- a/dokan/dokan.rc +++ b/dokan/dokan.rc @@ -16,8 +16,8 @@ // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,1,0000 - PRODUCTVERSION 1,0,1,0000 + FILEVERSION 1,0,2,1000 + PRODUCTVERSION 1,0,2,1000 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -34,12 +34,12 @@ BEGIN BEGIN VALUE "CompanyName", "Dokan Project" VALUE "FileDescription", "Dokan Library" - VALUE "FileVersion", "1.0.1.0000" + VALUE "FileVersion", "1.0.2.1000" VALUE "InternalName", "dokan.dll" - VALUE "LegalCopyright", "Copyright (C) 2016" + VALUE "LegalCopyright", "Copyright (C) 2017" VALUE "OriginalFilename", "dokan.dll" VALUE "ProductName", "Dokan" - VALUE "ProductVersion", "1.0.1.0000" + VALUE "ProductVersion", "1.0.2.1000" END END BLOCK "VarFileInfo" diff --git a/dokan/dokanc.h b/dokan/dokanc.h index d9b3d8c2a..584ae5059 100644 --- a/dokan/dokanc.h +++ b/dokan/dokanc.h @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/dokan/dokani.h b/dokan/dokani.h index 1f191af48..68993875c 100644 --- a/dokan/dokani.h +++ b/dokan/dokani.h @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/dokan/fileinfo.c b/dokan/fileinfo.c index 6b5d24c0f..8511f55d2 100644 --- a/dokan/fileinfo.c +++ b/dokan/fileinfo.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -564,5 +564,4 @@ VOID DispatchQueryInformation(HANDLE Handle, PEVENT_CONTEXT EventContext, SendEventInformation(Handle, eventInfo, sizeOfEventInfo, DokanInstance); free(eventInfo); - return; } diff --git a/dokan/fileinfo.h b/dokan/fileinfo.h index 00ed88b90..6ea19dfda 100644 --- a/dokan/fileinfo.h +++ b/dokan/fileinfo.h @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/dokan/flush.c b/dokan/flush.c index fda3d1ac0..607657514 100644 --- a/dokan/flush.c +++ b/dokan/flush.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -58,5 +58,4 @@ VOID DispatchFlush(HANDLE Handle, PEVENT_CONTEXT EventContext, SendEventInformation(Handle, eventInfo, sizeOfEventInfo, DokanInstance); free(eventInfo); - return; } diff --git a/dokan/list.h b/dokan/list.h index f5d958c89..f1abf0259 100644 --- a/dokan/list.h +++ b/dokan/list.h @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/dokan/lock.c b/dokan/lock.c index 6694049a1..7554e4e32 100644 --- a/dokan/lock.c +++ b/dokan/lock.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -86,5 +86,4 @@ VOID DispatchLock(HANDLE Handle, PEVENT_CONTEXT EventContext, SendEventInformation(Handle, eventInfo, sizeOfEventInfo, DokanInstance); free(eventInfo); - return; } diff --git a/dokan/mount.c b/dokan/mount.c index 83613619d..9d2878748 100644 --- a/dokan/mount.c +++ b/dokan/mount.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -358,6 +358,8 @@ BOOL DOKANAPI DokanNetworkProviderUninstall() { if (wcsstr(buffer, commanp) != NULL) { WCHAR *dokan_pos = wcsstr(buffer, commanp); + if (dokan_pos == NULL) + return FALSE; wcsncpy_s(buffer2, sizeof(buffer2) / sizeof(WCHAR), buffer, dokan_pos - buffer); wcscat_s(buffer2, sizeof(buffer2) / sizeof(WCHAR), @@ -574,9 +576,7 @@ BOOL DOKANAPI DokanRemoveMountPointEx(LPCWSTR MountPoint, BOOL Safe) { if (length + 1 < MAX_PATH) { mountPoint[length] = L'\\'; mountPoint[length + 1] = L'\0'; - // Required to remove reparse point (could also be done through - // FSCTL_DELETE_REPARSE_POINT with DeleteMountPoint function) - DeleteVolumeMountPoint(mountPoint); + return DeleteMountPoint(mountPoint); } } else { // Notify applications / explorer diff --git a/dokan/ntstatus.c b/dokan/ntstatus.c index 7868335ff..807ac8979 100644 --- a/dokan/ntstatus.c +++ b/dokan/ntstatus.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows -Copyright (C) 2015 - 2016 Adrien J. and Maxime C. +Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/dokan/read.c b/dokan/read.c index abdc947b5..4941ac15f 100644 --- a/dokan/read.c +++ b/dokan/read.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -64,5 +64,4 @@ VOID DispatchRead(HANDLE Handle, PEVENT_CONTEXT EventContext, SendEventInformation(Handle, eventInfo, sizeOfEventInfo, DokanInstance); free(eventInfo); - return; } diff --git a/dokan/resource.h b/dokan/resource.h index 835bd4642..87b65734d 100644 --- a/dokan/resource.h +++ b/dokan/resource.h @@ -4,6 +4,7 @@ // Next default values for new objects // +#pragma once #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 diff --git a/dokan/security.c b/dokan/security.c index b1a2c20f2..593d12a51 100644 --- a/dokan/security.c +++ b/dokan/security.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/dokan/setfile.c b/dokan/setfile.c index 8b9f2bc82..23f055453 100644 --- a/dokan/setfile.c +++ b/dokan/setfile.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -264,6 +264,10 @@ VOID DispatchSetInformation(HANDLE Handle, PEVENT_CONTEXT EventContext, status = DokanSetValidDataLengthInformation(EventContext, &fileInfo, DokanInstance->DokanOperations); break; + default: + DbgPrint(" unknown FileInformationClass %d\n", + EventContext->Operation.SetFile.FileInformationClass); + break; } if (openInfo != NULL) @@ -301,5 +305,4 @@ VOID DispatchSetInformation(HANDLE Handle, PEVENT_CONTEXT EventContext, SendEventInformation(Handle, eventInfo, sizeOfEventInfo, DokanInstance); free(eventInfo); - return; } diff --git a/dokan/timeout.c b/dokan/timeout.c index 1ca03c311..3e9769d49 100644 --- a/dokan/timeout.c +++ b/dokan/timeout.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/dokan/version.c b/dokan/version.c index 9b10b027f..21e40375c 100644 --- a/dokan/version.c +++ b/dokan/version.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/dokan/volume.c b/dokan/volume.c index 2fd117a1f..7839b1b8a 100644 --- a/dokan/volume.c +++ b/dokan/volume.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -365,5 +365,4 @@ VOID DispatchQueryVolumeInformation(HANDLE Handle, PEVENT_CONTEXT EventContext, SendEventInformation(Handle, eventInfo, sizeOfEventInfo, NULL); free(eventInfo); - return; } diff --git a/dokan/write.c b/dokan/write.c index a66cd1a23..9818ad976 100644 --- a/dokan/write.c +++ b/dokan/write.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -90,15 +90,13 @@ VOID DispatchWrite(HANDLE Handle, PEVENT_CONTEXT EventContext, if (openInfo != NULL) openInfo->UserContext = fileInfo.Context; + eventInfo->Status = status; eventInfo->BufferLength = 0; if (status == STATUS_SUCCESS) { - eventInfo->Status = status; eventInfo->BufferLength = writtenLength; eventInfo->Operation.Write.CurrentByteOffset.QuadPart = EventContext->Operation.Write.ByteOffset.QuadPart + writtenLength; - } else { - eventInfo->Status = STATUS_INVALID_PARAMETER; } SendEventInformation(Handle, eventInfo, sizeOfEventInfo, DokanInstance); @@ -106,6 +104,4 @@ VOID DispatchWrite(HANDLE Handle, PEVENT_CONTEXT EventContext, if (bufferAllocated) free(EventContext); - - return; } diff --git a/dokan_control/dokanctl.c b/dokan_control/dokanctl.c index ddc590239..c9de1e6fb 100644 --- a/dokan_control/dokanctl.c +++ b/dokan_control/dokanctl.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -78,11 +78,11 @@ int InstallDriver(LPCWSTR driverFullPath) { if (!DokanServiceInstall(DOKAN_DRIVER_SERVICE, SERVICE_FILE_SYSTEM_DRIVER, DOKAN_DRIVER_FULL_PATH)) { - fprintf(stderr, "Driver install failed\n"); + fprintf(stderr, "Driver installation failed\n"); return EXIT_FAILURE; } - fprintf(stdout, "Driver installation succeeded!\n"); + fprintf(stdout, "Driver installation blaaaaah succeeded!\n"); return EXIT_SUCCESS; } @@ -192,7 +192,14 @@ int __cdecl wmain(int argc, PWCHAR argv[]) { // No admin rights required case L'l': { ULONG nbRead = 0; - DOKAN_CONTROL dokanControl[DOKAN_MAX_INSTANCES]; + PDOKAN_CONTROL dokanControl = + malloc(DOKAN_MAX_INSTANCES * sizeof(*dokanControl)); + if (dokanControl == NULL) { + fprintf(stderr, "Failed to allocate dokanControl\n"); + return EXIT_FAILURE; + } + + ZeroMemory(dokanControl, DOKAN_MAX_INSTANCES * sizeof(*dokanControl)); if (DokanGetMountPointList(dokanControl, DOKAN_MAX_INSTANCES, FALSE, &nbRead)) { fwprintf(stdout, L" Mount points: %d\n", nbRead); @@ -204,17 +211,18 @@ int __cdecl wmain(int argc, PWCHAR argv[]) { } else { fwprintf(stderr, L" Cannot retrieve mount point list.\n"); } + free(dokanControl); } break; case L'v': { - fprintf(stdout, "dokanctl : %s %s\n", __DATE__, __TIME__); - fprintf(stdout, "Dokan version : %d\n", DokanVersion()); - fprintf(stdout, "Dokan driver version : 0x%lx\n", DokanDriverVersion()); + fprintf(stdout, "dükanctl : %s %s\n", __DATE__, __TIME__); + fprintf(stdout, "Dükan version : %d\n", DokanVersion()); + fprintf(stdout, "Dükan driver version : 0x%lx\n", DokanDriverVersion()); } break; DEFAULT: default: - fprintf(stderr, "Unknown option - Use /? to show usage\n"); + fprintf(stderr, "Ünknown option - Use /? to show usage\n"); } return EXIT_SUCCESS; diff --git a/dokan_fuse/CMakeLists.txt b/dokan_fuse/CMakeLists.txt index 962ba5c7c..b67c9446a 100644 --- a/dokan_fuse/CMakeLists.txt +++ b/dokan_fuse/CMakeLists.txt @@ -7,6 +7,8 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) endif(NOT CMAKE_BUILD_TYPE) +option(FUSE_PKG_CONFIG "Install a libfuse-compatible pkg-config file (fuse.pc)" ON) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -mwin32 -Wall") add_definitions(-D_FILE_OFFSET_BITS=64) include_directories( @@ -14,6 +16,33 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../sys ) +if(FUSE_PKG_CONFIG) + # Defining helper-function to deal with setups that manually set an + # absolute path for CMAKE_INSTALL_(LIB|INCLUDE)DIR... + # We could also just make all paths absolute, but this way the + # pkg-config-file is more human-readable and pkg-config may be able to deal + # with varying prefixes. + # CMake does not have a ternary operator for generator expressions, so this + # looks more complicated than it is. + function ( make_pkg_config_absolute out_path in_path ) + if(IS_ABSOLUTE "${${in_path}}") + set(${out_path} "${${in_path}}" PARENT_SCOPE) + else() + set(${out_path} "\${prefix}/${${in_path}}" PARENT_SCOPE) + endif() + endfunction() + + set(pkg_config_file "${CMAKE_CURRENT_BINARY_DIR}/fuse.pc") + make_pkg_config_absolute(PKG_CONFIG_LIBDIR CMAKE_INSTALL_LIBDIR) + make_pkg_config_absolute(PKG_CONFIG_INCLUDEDIR CMAKE_INSTALL_INCLUDEDIR) + + CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/pkg-config.pc.in" + ${pkg_config_file} + @ONLY + ) +endif() + file(GLOB sources src/*.cpp src/*.c src/*.rc) set(install_headers include/fuse.h @@ -30,6 +59,9 @@ add_library(dokanfuse1 SHARED ${sources}) INSTALL(FILES ${install_headers} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/fuse/) INSTALL(FILES ${compat_headers} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +if(FUSE_PKG_CONFIG) + INSTALL(FILES ${pkg_config_file} DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() INSTALL(TARGETS dokanfuse1 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/dokan_fuse/build.ps1 b/dokan_fuse/build.ps1 index ee5aeb81d..0617b6729 100755 --- a/dokan_fuse/build.ps1 +++ b/dokan_fuse/build.ps1 @@ -10,7 +10,7 @@ $script:failed = 0 make -j `$(getconf _NPROCESSORS_ONLN) install" & C:\cygwin\bin\bash -lc " cd '$currentPath' && - gcc -o '$installDir'/mirror samples/fuse_mirror/fusexmp.c -I '$installDir/include' -D_FILE_OFFSET_BITS=64 -L $installDir/ -lcygdokanfuse1" + gcc -o '$installDir'/mirror samples/fuse_mirror/fusexmp.c `$(PKG_CONFIG_PATH='$installDir/lib/pkgconfig' pkg-config fuse --cflags --libs)" if ($LASTEXITCODE -ne 0) { $script:failed = $LASTEXITCODE } @@ -25,7 +25,7 @@ $script:failed = 0 make -j `$(getconf _NPROCESSORS_ONLN) install" & C:\cygwin64\bin\bash -lc " cd '$currentPath' && - gcc -o '$installDir'/mirror samples/fuse_mirror/fusexmp.c -I '$installDir/include' -D_FILE_OFFSET_BITS=64 -L $installDir/ -lcygdokanfuse1" + gcc -o '$installDir'/mirror samples/fuse_mirror/fusexmp.c `$(PKG_CONFIG_PATH='$installDir/lib/pkgconfig' pkg-config fuse --cflags --libs)" if ($LASTEXITCODE -ne 0) { $script:failed = $LASTEXITCODE } diff --git a/dokan_fuse/include/dokanfuse.h b/dokan_fuse/include/dokanfuse.h index 401a4b755..408f1442a 100644 --- a/dokan_fuse/include/dokanfuse.h +++ b/dokan_fuse/include/dokanfuse.h @@ -41,7 +41,7 @@ struct fuse_session struct fuse_chan { - fuse_chan():ResolvedDokanMain(NULL), ResolvedDokanUnmount(NULL), ResolvedDokanRemoveMountPoint(NULL), dokanDll(NULL) {} + fuse_chan():ResolvedDokanMain(nullptr), ResolvedDokanUnmount(nullptr), ResolvedDokanRemoveMountPoint(nullptr), dokanDll(nullptr) {} ~fuse_chan(); //This method dynamically loads DOKAN functions diff --git a/dokan_fuse/include/fuse.h b/dokan_fuse/include/fuse.h index ec0ec8bf0..23249184c 100644 --- a/dokan_fuse/include/fuse.h +++ b/dokan_fuse/include/fuse.h @@ -581,7 +581,6 @@ struct fuse_context *fuse_get_context(void); /** * Check if a request has already been interrupted * - * @param req request handle * @return 1 if the request has been interrupted, 0 otherwise */ int fuse_interrupted(void); diff --git a/dokan_fuse/include/fusemain.h b/dokan_fuse/include/fusemain.h index 6320dbf03..a178fe1dc 100644 --- a/dokan_fuse/include/fusemain.h +++ b/dokan_fuse/include/fusemain.h @@ -57,7 +57,7 @@ class win_error public: win_error(int _err): err(errno_to_ntstatus_error(_err)) {} win_error(int _err, bool): err(_err) {} - operator int() { return err; } + operator int() const { return err; } private: int err; }; @@ -99,7 +99,7 @@ class impl_fuse_context int do_delete_file(LPCWSTR file_name, PDOKAN_FILE_INFO dokan_file_info); - int convert_flags(DWORD Flags); + static int convert_flags(DWORD Flags); int resolve_symlink(const std::string &name, std::string *res); int check_and_resolve(std::string *name); @@ -199,7 +199,7 @@ class impl_file_lock int lock_file(impl_file_handle *file, long long start, long long len, bool mark=true); int unlock_file(impl_file_handle *file, long long start, long long len); public: - impl_file_lock(impl_file_locks* _locks, const std::string& name): name_(name), locks(_locks), first(NULL) { InitializeCriticalSection(&lock); } + impl_file_lock(impl_file_locks* _locks, const std::string& name): name_(name), locks(_locks), first(nullptr) { InitializeCriticalSection(&lock); } ~impl_file_lock() { DeleteCriticalSection(&lock); }; void remove_file(impl_file_handle *file); const std::string& get_name() const {return name_;} diff --git a/dokan_fuse/include/utils.h b/dokan_fuse/include/utils.h index c7398a92d..47e338ab5 100644 --- a/dokan_fuse/include/utils.h +++ b/dokan_fuse/include/utils.h @@ -30,7 +30,7 @@ std::string extract_dir_name(const std::string &str); template void convertStatlikeBuf(const struct FUSE_STAT *stbuf, const std::string &name, T * find_data) { - if (stbuf==NULL) return; + if (stbuf==nullptr) return; if ((stbuf->st_mode&S_IFDIR)==S_IFDIR) find_data->dwFileAttributes=FILE_ATTRIBUTE_DIRECTORY; @@ -41,7 +41,7 @@ template void convertStatlikeBuf(const struct FUSE_STAT *stbuf, const s find_data->nFileSizeLow=stbuf->st_size; #else //Support 64 sizes - find_data->nFileSizeLow=(DWORD) stbuf->st_size; + find_data->nFileSizeLow=static_cast(stbuf->st_size); find_data->nFileSizeHigh=stbuf->st_size>>32; #endif if (stbuf->st_ctim.tv_sec!=0) diff --git a/dokan_fuse/pkg-config.pc.in b/dokan_fuse/pkg-config.pc.in new file mode 100644 index 000000000..ebc0ade3a --- /dev/null +++ b/dokan_fuse/pkg-config.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=@PKG_CONFIG_LIBDIR@ +includedir=@PKG_CONFIG_INCLUDEDIR@ + +Name: Dokan FUSE +Description: FUSE-API compatibility library for the Dokan user mode filesystem driver for Windows +# Dokan FUSE provides compatibility with libfuse 2.6.x. +# The corresponding libfuse-version is therefore reported instead of the Dokan FUSE-version +Version: 2.6.0 +URL: https://dokan-dev.github.io +Libs: -L${libdir} -l@PROJECT_NAME@ +Cflags: -I${includedir} -D_FILE_OFFSET_BITS=64 diff --git a/dokan_fuse/src/dokanfuse.cpp b/dokan_fuse/src/dokanfuse.cpp index af7184da6..ed95be29f 100644 --- a/dokan_fuse/src/dokanfuse.cpp +++ b/dokan_fuse/src/dokanfuse.cpp @@ -130,7 +130,7 @@ CONST_VAL(FILE_OVERWRITE_IF) CONST_END(cDisposition) void DebugConstant(const char *name, ULONG value, Constant *c) { - while (c->name != NULL && c->value != value) + while (c->name != nullptr && c->value != value) ++c; fprintf(stderr, "%s: %s (" PRIxULONG ")\n", name, c->name ? c->name : "unknown!", value); @@ -160,7 +160,7 @@ void DebugConstantBit(const char *name, DWORD value, Constant *cs) { } } if (left || !started) - fprintf(stderr, "%s0x%lX", sep, (long unsigned)left); + fprintf(stderr, "%s0x%lX", sep, static_cast(left)); fprintf(stderr, "\n"); } @@ -218,7 +218,7 @@ static NTSTATUS DOKAN_CALLBACK FuseReadFile(LPCWSTR FileName, LPVOID Buffer, impl_fuse_context *impl = the_impl; if (impl->debug()) FPRINTF(stderr, "ReadFile: %ls from %lld len %u\n", FileName, - (__int64)Offset, (unsigned)BufferLength); + static_cast<__int64>(Offset), static_cast(BufferLength)); impl_chain_guard guard(impl, DokanFileInfo->ProcessId); return errno_to_ntstatus_error(impl->read_file( @@ -513,7 +513,7 @@ static DOKAN_OPERATIONS dokanOperations = { FuseFlushFileBuffers, FuseGetFileInformation, FuseFindFiles, - NULL, // FindFilesWithPattern + nullptr, // FindFilesWithPattern FuseSetFileAttributes, FuseSetFileTime, FuseDeleteFile, @@ -528,7 +528,7 @@ static DOKAN_OPERATIONS dokanOperations = { FuseMounted, FuseUnmounted, FuseGetFileSecurity, - NULL, // SetFileSecurity + nullptr, // SetFileSecurity }; int do_fuse_loop(struct fuse *fs, bool mt) { @@ -551,8 +551,8 @@ int do_fuse_loop(struct fuse *fs, bool mt) { fs->conf.volname); // Parse Dokan options - PDOKAN_OPTIONS dokanOptions = (PDOKAN_OPTIONS)malloc(sizeof(DOKAN_OPTIONS)); - if (dokanOptions == NULL) { + PDOKAN_OPTIONS dokanOptions = static_cast(malloc(sizeof(DOKAN_OPTIONS))); + if (dokanOptions == nullptr) { return -1; } ZeroMemory(dokanOptions, sizeof(DOKAN_OPTIONS)); @@ -594,15 +594,15 @@ bool fuse_chan::init() { typedef ULONG(__stdcall * DokanVersionType)(); DokanVersionType ResolvedDokanVersion; ResolvedDokanVersion = - (DokanVersionType)GetProcAddress(dokanDll, "DokanVersion"); + reinterpret_cast(GetProcAddress(dokanDll, "DokanVersion")); if (!ResolvedDokanVersion || ResolvedDokanVersion() < DOKAN_VERSION) return false; - ResolvedDokanMain = (DokanMainType)GetProcAddress(dokanDll, "DokanMain"); + ResolvedDokanMain = reinterpret_cast(GetProcAddress(dokanDll, "DokanMain")); ResolvedDokanUnmount = - (DokanUnmountType)GetProcAddress(dokanDll, "DokanUnmount"); - ResolvedDokanRemoveMountPoint = (DokanRemoveMountPointType)GetProcAddress( - dokanDll, "DokanRemoveMountPoint"); + reinterpret_cast(GetProcAddress(dokanDll, "DokanUnmount")); + ResolvedDokanRemoveMountPoint = reinterpret_cast(GetProcAddress( + dokanDll, "DokanRemoveMountPoint")); if (!ResolvedDokanMain || !ResolvedDokanUnmount || !ResolvedDokanRemoveMountPoint) @@ -660,7 +660,7 @@ static int fuse_lib_opt_proc(void *data, const char *arg, int key, (void)outargs; if (key == KEY_HELP) { - struct fuse_config *conf = (struct fuse_config *)data; + struct fuse_config *conf = static_cast(data); fuse_lib_help(); conf->help = 1; } @@ -677,8 +677,8 @@ int fuse_loop_mt(struct fuse *f) { return do_fuse_loop(f, true); } int fuse_loop(struct fuse *f) { return do_fuse_loop(f, false); } struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args) { - if (mountpoint == NULL || mountpoint[0] == '\0') - return NULL; + if (mountpoint == nullptr || mountpoint[0] == '\0') + return nullptr; std::unique_ptr chan(new fuse_chan()); // NOTE: we used to do chan->init() here to check that Dokan DLLs can be @@ -694,7 +694,7 @@ struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args) { } void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) { - if (mountpoint == NULL || mountpoint[0] == '\0') + if (mountpoint == nullptr || mountpoint[0] == '\0') return; fuse_chan chan; @@ -733,14 +733,14 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, res->user_data = user_data; // prepare 'safe' options - fuse_operations safe_ops = {0}; + fuse_operations safe_ops = {nullptr}; memcpy(&safe_ops, op, op_size > sizeof(safe_ops) ? sizeof(safe_ops) : op_size); res->ops = safe_ops; // Get debug param and filesystem name if (fuse_opt_parse(args, &res->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1) - return NULL; + return nullptr; // res->conf.debug=1; return res.release(); @@ -748,7 +748,7 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, void fuse_exit(struct fuse *f) { // A hack - unmount the attached filesystem, it will cause the loop to end - if (f == NULL || !f->ch.get() || f->ch->mountpoint.empty()) + if (f == nullptr || !f->ch.get() || f->ch->mountpoint.empty()) return; // Unmount attached FUSE filesystem f->ch->ResolvedDokanUnmount(f->ch->mountpoint.at(0)); // Ugly :( @@ -761,20 +761,20 @@ struct fuse *fuse_setup(int argc, char *argv[], char **mountpoint, int *multithreaded, void *user_data) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_chan *ch = NULL; + struct fuse_chan *ch = nullptr; struct fuse *fuse; int foreground; int res; res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); if (res == -1) - return NULL; + return nullptr; ch = fuse_mount(*mountpoint, &args); fuse = fuse_new(ch, &args, op, op_size, user_data); fuse_opt_free_args(&args); - if (fuse == NULL || ch == NULL) + if (fuse == nullptr || ch == nullptr) goto err_unmount; res = fuse_daemonize(foreground); @@ -794,7 +794,7 @@ struct fuse *fuse_setup(int argc, char *argv[], if (fuse) fuse_destroy(fuse); free(*mountpoint); - return NULL; + return nullptr; } void fuse_teardown(struct fuse *fuse, char *mountpoint) { @@ -822,7 +822,7 @@ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, fuse = fuse_setup(argc, argv, op, op_size, &mountpoint, &multithreaded, user_data); - if (fuse == NULL) + if (fuse == nullptr) return 1; // MT loops are only supported on MSVC diff --git a/dokan_fuse/src/dokanfuse.rc b/dokan_fuse/src/dokanfuse.rc index f2f7e3244..372e1fc39 100644 --- a/dokan_fuse/src/dokanfuse.rc +++ b/dokan_fuse/src/dokanfuse.rc @@ -16,8 +16,8 @@ // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,1,0000 - PRODUCTVERSION 1,0,1,0000 + FILEVERSION 1,0,2,1000 + PRODUCTVERSION 1,0,2,1000 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -34,12 +34,12 @@ BEGIN BEGIN VALUE "CompanyName", "Dokan Project" VALUE "FileDescription", "Dokan Fuse library" - VALUE "FileVersion", "1.0.1.0000" + VALUE "FileVersion", "1.0.2.1000" VALUE "InternalName", "dokanfuse.dll" - VALUE "LegalCopyright", "Copyright (C) 2016" + VALUE "LegalCopyright", "Copyright (C) 2017" VALUE "OriginalFilename", "dokanfuse.dll" VALUE "ProductName", "Dokan" - VALUE "ProductVersion", "1.0.1.0000" + VALUE "ProductVersion", "1.0.2.1000" END END BLOCK "VarFileInfo" diff --git a/dokan_fuse/src/fusemain.cpp b/dokan_fuse/src/fusemain.cpp index 371e75158..17259ddf9 100644 --- a/dokan_fuse/src/fusemain.cpp +++ b/dokan_fuse/src/fusemain.cpp @@ -37,7 +37,7 @@ /////////////////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER -__declspec(thread) impl_chain_link *cur_impl_chain_link = NULL; +__declspec(thread) impl_chain_link *cur_impl_chain_link = nullptr; #else static __thread impl_chain_link *cur_impl_chain_link = NULL; #endif @@ -45,7 +45,7 @@ static __thread impl_chain_link *cur_impl_chain_link = NULL; impl_chain_guard::impl_chain_guard(impl_fuse_context *ctx, int caller_pid) { link.call_ctx_.pid = caller_pid; link.call_ctx_.private_data = ctx->user_data_; - link.call_ctx_.fuse = (struct fuse *)(void *)ctx; // Hack, really... + link.call_ctx_.fuse = static_cast(static_cast(ctx)); // Hack, really... link.prev_link_ = cur_impl_chain_link; @@ -61,8 +61,8 @@ impl_chain_guard::~impl_chain_guard() { } struct fuse_context *fuse_get_context(void) { - if (cur_impl_chain_link == NULL) - return NULL; + if (cur_impl_chain_link == nullptr) + return nullptr; return &cur_impl_chain_link->call_ctx_; } @@ -99,7 +99,7 @@ int impl_fuse_context::cast_from_longlong(LONGLONG src, FUSE_OFF_T *res) { if (src > LONG_MAX || src < LONG_MIN) return -E2BIG; #endif - *res = (FUSE_OFF_T)src; + *res = static_cast(src); return 0; } @@ -312,7 +312,7 @@ int impl_fuse_context::walk_directory(void *buf, const char *name, int impl_fuse_context::walk_directory_getdir(fuse_dirh_t hndl, const char *name, int type, ino_t ino) { - walk_data *wd = (walk_data *)hndl; + walk_data *wd = reinterpret_cast(hndl); wd->getdir_data.push_back(name); // Add this name to list return 0; // Get more entries } @@ -337,14 +337,14 @@ int impl_fuse_context::find_files(LPCWSTR file_name, if (ops_.readdir) { impl_file_handle *hndl = reinterpret_cast(dokan_file_info->Context); - if (hndl != NULL) { + if (hndl != nullptr) { fuse_file_info finfo(hndl->make_finfo()); return ops_.readdir(fname.c_str(), &wd, &walk_directory, 0, &finfo); } else - return ops_.readdir(fname.c_str(), &wd, &walk_directory, 0, NULL); + return ops_.readdir(fname.c_str(), &wd, &walk_directory, 0, nullptr); } else { CHECKED( - ops_.getdir(fname.c_str(), (fuse_dirh_t)&wd, &walk_directory_getdir)); + ops_.getdir(fname.c_str(), reinterpret_cast(&wd), &walk_directory_getdir)); // Convert returned data The getdir_data array will be filled during // getdir() call. // We emulate FUSE behavior and do not pass information directly to Dokan @@ -355,7 +355,7 @@ int impl_fuse_context::find_files(LPCWSTR file_name, // See: cache.c file, function cache_dirfill() in SSHFS 2.2 for (std::vector::const_iterator f = wd.getdir_data.begin(); f != wd.getdir_data.end(); ++f) - CHECKED(walk_directory(&wd, f->c_str(), 0, 0)); + CHECKED(walk_directory(&wd, f->c_str(), nullptr, 0)); } return 0; @@ -382,7 +382,7 @@ int impl_fuse_context::open_directory(LPCWSTR file_name, if ((st.st_mode & S_IFDIR) != S_IFDIR) return -ENOTDIR; - dokan_file_info->Context = (ULONG64)NULL; // Do not want to attach anything + dokan_file_info->Context = 0; // Do not want to attach anything return 0; // Use readdir here? } @@ -544,7 +544,7 @@ int impl_fuse_context::read_file(LPCWSTR /*file_name*/, LPVOID buffer, if (to_read > MAX_READ_SIZE) to_read = MAX_READ_SIZE; - int res = ops_.read(hndl->get_name().c_str(), (char *)buffer, to_read, off, + int res = ops_.read(hndl->get_name().c_str(), static_cast(buffer), to_read, off, &finfo); if (res < 0) return res; // Error @@ -553,7 +553,7 @@ int impl_fuse_context::read_file(LPCWSTR /*file_name*/, LPVOID buffer, total_read += res; off += res; - buffer = (char *)buffer + res; + buffer = static_cast(buffer) + res; } // OK! *read_bytes = total_read; @@ -591,7 +591,7 @@ int impl_fuse_context::write_file(LPCWSTR /*file_name*/, LPCVOID buffer, CHECKED(cast_from_longlong(offset, &off)); fuse_file_info finfo(hndl->make_finfo()); - int res = ops_.write(hndl->get_name().c_str(), (const char *)buffer, + int res = ops_.write(hndl->get_name().c_str(), static_cast(buffer), num_bytes_to_write, off, &finfo); if (res < 0) return res; // Error @@ -818,7 +818,7 @@ int impl_fuse_context::set_file_time(PCWSTR file_name, impl_file_handle *hndl = reinterpret_cast(dokan_file_info->Context); if (!hndl) - return ops_.win_set_times(fname.c_str(), NULL, creation_time, + return ops_.win_set_times(fname.c_str(), nullptr, creation_time, last_access_time, last_write_time); if (hndl->is_dir()) @@ -877,11 +877,11 @@ int impl_fuse_context::get_disk_free_space(PULONGLONG free_bytes_available, struct statvfs vfs = {0}; CHECKED(ops_.statfs("/", &vfs)); - if (free_bytes_available != NULL) + if (free_bytes_available != nullptr) *free_bytes_available = uint64_t(vfs.f_bsize) * vfs.f_bavail; - if (number_of_free_bytes != NULL) + if (number_of_free_bytes != nullptr) *number_of_free_bytes = uint64_t(vfs.f_bsize) * vfs.f_bfree; - if (number_of_bytes != NULL) + if (number_of_bytes != nullptr) *number_of_bytes = uint64_t(vfs.f_bsize) * vfs.f_blocks; return 0; @@ -944,7 +944,7 @@ int impl_file_locks::get_file(const std::string &name, bool is_dir, file.reset(new impl_file_handle(is_dir, shared_mode)); // check previous files with same names - impl_file_lock *lock, *old_lock = NULL; + impl_file_lock *lock, *old_lock = nullptr; EnterCriticalSection(&this->lock); file_locks_t::iterator i = file_locks.find(name); if (i != file_locks.end()) { @@ -964,8 +964,8 @@ int impl_file_locks::get_file(const std::string &name, bool is_dir, // check previous files with same names DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - for (impl_file_handle *i = lock->first; i; i = i->next_file) - share &= i->shared_mode_; + for (impl_file_handle *p = lock->first; p; p = p->next_file) + share &= p->shared_mode_; if ((required_share(access_mode) | share) != share) { file.reset(); res = -EACCES; @@ -987,10 +987,10 @@ void impl_file_lock::remove_file(impl_file_handle *file) { EnterCriticalSection(&lock); impl_file_handle **p = &first; - while (*p != NULL) { + while (*p != nullptr) { if (*p == file) { *p = file->next_file; - file->next_file = NULL; + file->next_file = nullptr; continue; } p = &(*p)->next_file; @@ -1060,8 +1060,8 @@ int impl_file_lock::lock_file(impl_file_handle *file, long long start, } } else { // check last - impl_file_handle::locks_t::reverse_iterator j = i->locks.rbegin(); - if (j != i->locks.rend() && start - j->first < j->second) + impl_file_handle::locks_t::reverse_iterator p = i->locks.rbegin(); + if (p != i->locks.rend() && start - p->first < p->second) locked = true; } } @@ -1097,7 +1097,7 @@ int impl_file_lock::unlock_file(impl_file_handle *file, long long start, ////// File handle /////////////////////////////////////////////////////////////////////////////////////// impl_file_handle::impl_file_handle(bool is_dir, DWORD shared_mode) - : is_dir_(is_dir), fh_(-1), next_file(NULL), file_lock(NULL), shared_mode_(shared_mode) {} + : is_dir_(is_dir), fh_(-1), next_file(nullptr), file_lock(nullptr), shared_mode_(shared_mode) {} impl_file_handle::~impl_file_handle() { file_lock->remove_file(this); } diff --git a/dokan_fuse/src/utils.cpp b/dokan_fuse/src/utils.cpp index a36a05a06..d6e054dc7 100644 --- a/dokan_fuse/src/utils.cpp +++ b/dokan_fuse/src/utils.cpp @@ -61,7 +61,7 @@ static size_t put_utf8(unsigned char *buf, ICONV_CHAR c) { unsigned mask; if ((c & MASK(7)) == 0) { - *buf = (unsigned char)c; + *buf = static_cast(c); return 1; } @@ -134,8 +134,8 @@ typedef size_t (*put_convert_t)(unsigned char *buf, ICONV_CHAR c); static size_t convert_char(get_conver_t get_func, put_convert_t put_func, const void *src, size_t src_len, void *dest) { size_t il = src_len; - const unsigned char *ib = (const unsigned char *)src; - unsigned char *ob = (unsigned char *)dest; + const unsigned char *ib = static_cast(src); + unsigned char *ob = static_cast(dest); size_t total = 0; while (il) { @@ -159,17 +159,17 @@ static size_t convert_char(get_conver_t get_func, put_convert_t put_func, } static char *wchar_to_utf8(const wchar_t *str) { - if (str == NULL) - return NULL; + if (str == nullptr) + return nullptr; // Determine required length size_t ln = convert_char(get_utf16, put_utf8, str, - (wcslen(str) + 1) * sizeof(wchar_t), NULL); + (wcslen(str) + 1) * sizeof(wchar_t), nullptr); if (ln <= 0) - return NULL; - char *res = (char *)malloc(sizeof(char) * ln); - if (res == NULL) - return NULL; + return nullptr; + auto res = static_cast(malloc(sizeof(char) * ln)); + if (res == nullptr) + return nullptr; // Convert to Unicode convert_char(get_utf16, put_utf8, str, (wcslen(str) + 1) * sizeof(wchar_t), @@ -178,13 +178,13 @@ static char *wchar_to_utf8(const wchar_t *str) { } void utf8_to_wchar_buf(const char *src, wchar_t *res, int maxlen) { - if (res == NULL || maxlen == 0) + if (res == nullptr || maxlen == 0) return; size_t ln = convert_char(get_utf8, put_utf16, src, strlen(src) + 1, - NULL); /* | raise_w32_error()*/ + nullptr); /* | raise_w32_error()*/ ; - if (ln <= 0 || ln / sizeof(wchar_t) > (size_t)maxlen) { + if (ln <= 0 || ln / sizeof(wchar_t) > static_cast(maxlen)) { *res = L'\0'; return; } @@ -194,17 +194,17 @@ void utf8_to_wchar_buf(const char *src, wchar_t *res, int maxlen) { } void utf8_to_wchar_buf_old(const char *src, wchar_t *res, int maxlen) { - if (res == NULL || maxlen == 0) + if (res == nullptr || maxlen == 0) return; int ln = - MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0) /* | raise_w32_error()*/; + MultiByteToWideChar(CP_ACP, 0, src, -1, nullptr, 0) /* | raise_w32_error()*/; if (ln >= maxlen) { *res = L'\0'; return; } MultiByteToWideChar(CP_ACP, 0, src, -1, res, - (int)(strlen(src) + 1)) /* | raise_w32_error()*/; + static_cast(strlen(src) + 1)) /* | raise_w32_error()*/; } std::string wchar_to_utf8_cstr(const wchar_t *str) { @@ -218,7 +218,7 @@ std::string unixify(const std::string &str) { // Replace slashes std::string res = str; for (size_t f = 0; f < res.size(); ++f) { - char ch = res[f]; + auto ch = res[f]; if (ch == '\\') res[f] = '/'; } @@ -235,13 +235,13 @@ FILETIME unixTimeToFiletime(time_t t) { ll = Int32x32To64(t, 10000000) + 116444736000000000LL; FILETIME res; - res.dwLowDateTime = (DWORD)ll; - res.dwHighDateTime = (DWORD)(ll >> 32); + res.dwLowDateTime = static_cast(ll); + res.dwHighDateTime = static_cast(ll >> 32); return res; } bool is_filetime_set(const FILETIME *ft) { - if (ft == 0 || (ft->dwHighDateTime == 0 && ft->dwLowDateTime == 0)) + if (ft == nullptr || (ft->dwHighDateTime == 0 && ft->dwLowDateTime == 0)) return false; return true; } @@ -318,7 +318,7 @@ extern "C" int ntstatus_error_to_errno(int win_res) { if (win_res < 0) win_res = -win_res; - for (int f = 0; f < errtable_size; ++f) + for (auto f = 0; f < errtable_size; ++f) if (errtable[f].oscode == win_res) return errtable[f].errnocode; return EINVAL; @@ -330,19 +330,19 @@ extern "C" int errno_to_ntstatus_error(int err) { if (err < 0) err = -err; - for (int f = 0; f < errtable_size; ++f) + for (auto f = 0; f < errtable_size; ++f) if (errtable[f].errnocode == err) return errtable[f].oscode; return ERROR_INVALID_FUNCTION; } extern "C" char **convert_args(int argc, wchar_t *argv[]) { - char **arr = (char **)malloc(sizeof(char *) * (argc + 1)); - if (arr == NULL) - return NULL; - for (int f = 0; f < argc; ++f) + auto arr = static_cast(malloc(sizeof(char *) * (argc + 1))); + if (arr == nullptr) + return nullptr; + for (auto f = 0; f < argc; ++f) arr[f] = wchar_to_utf8(argv[f]); - arr[argc] = NULL; + arr[argc] = nullptr; return arr; } @@ -355,7 +355,7 @@ extern "C" void free_converted_args(int argc, char **argv) { std::string extract_file_name(const std::string &str) { std::string extracted; - for (std::string::const_reverse_iterator f = str.rbegin(), en = str.rend(); + for (auto f = str.rbegin(), en = str.rend(); f != en; ++f) if (*f == '/') { extracted = str.substr(en - f - 1); @@ -370,7 +370,7 @@ std::string extract_file_name(const std::string &str) { } std::string extract_dir_name(const std::string &str) { - for (std::string::const_reverse_iterator f = str.rbegin(), en = str.rend(); + for (auto f = str.rbegin(), en = str.rend(); f != en; ++f) if (*f == '/') return str.substr(0, en - f); diff --git a/dokan_np/dokan_np.rc b/dokan_np/dokan_np.rc index 7a3b4bd93..d17471f9b 100644 --- a/dokan_np/dokan_np.rc +++ b/dokan_np/dokan_np.rc @@ -16,8 +16,8 @@ // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,1,0000 - PRODUCTVERSION 1,0,1,0000 + FILEVERSION 1,0,2,1000 + PRODUCTVERSION 1,0,2,1000 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -34,12 +34,12 @@ BEGIN BEGIN VALUE "CompanyName", "Dokan Project" VALUE "FileDescription", "Dokan Network Provider" - VALUE "FileVersion", "1.0.1.0000" + VALUE "FileVersion", "1.0.2.1000" VALUE "InternalName", "dokan.dll" - VALUE "LegalCopyright", "Copyright (C) 2016" + VALUE "LegalCopyright", "Copyright (C) 2017" VALUE "OriginalFilename", "dokannp.dll" VALUE "ProductName", "Dokan" - VALUE "ProductVersion", "1.0.1.0000" + VALUE "ProductVersion", "1.0.2.1000" END END BLOCK "VarFileInfo" diff --git a/dokan_np/dokannp.c b/dokan_np/dokannp.c index 7f17933a6..6dffac2c1 100644 --- a/dokan_np/dokannp.c +++ b/dokan_np/dokannp.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows -Copyright (C) 2015 - 2016 Adrien J. and Maxime C. +Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/dokan_np/resource.h b/dokan_np/resource.h index 1bb92e7da..f2a8c5e56 100644 --- a/dokan_np/resource.h +++ b/dokan_np/resource.h @@ -4,6 +4,7 @@ // Next default values for new objects // +#pragma once #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 diff --git a/dokan_wix/Bootstrapper/Resources/licdata.rtf b/dokan_wix/Bootstrapper/Resources/licdata.rtf index a99e93fba..c43b7b841 100644 --- a/dokan_wix/Bootstrapper/Resources/licdata.rtf +++ b/dokan_wix/Bootstrapper/Resources/licdata.rtf @@ -30,7 +30,7 @@ {\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi-1296\li1296} {\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi-1440\li1440} {\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi-1584\li1584}\listid2} -}{\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}}{\*\generator LibreOffice/5.0.5.2$Windows_x86 LibreOffice_project/55b006a02d247b5f7215fc6ea0fde844b30035b3}{\info{\creatim\yr2015\mo10\dy20\hr10\min53}{\revtim\yr2016\mo6\dy4\hr12\min57}{\printim\yr0\mo0\dy0\hr0\min0}}\deftab720\deftab720 +}{\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}}{\*\generator LibreOffice/5.0.5.2$Windows_x86 LibreOffice_project/55b006a02d247b5f7215fc6ea0fde844b30035b3}{\info{\creatim\yr2015\mo10\dy20\hr10\min53}{\revtim\yr2017\mo6\dy4\hr12\min57}{\printim\yr0\mo0\dy0\hr0\min0}}\deftab720\deftab720 \hyphauto0\viewscale130 {\*\pgdsctbl {\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1417\margrsxn1417\margtsxn1417\margbsxn1134\pgdscnxt0 Default Style;}} diff --git a/dokan_wix/version.xml b/dokan_wix/version.xml index e6835e948..dbb1acf52 100644 --- a/dokan_wix/version.xml +++ b/dokan_wix/version.xml @@ -1,15 +1,15 @@ - + - + - + - + diff --git a/license.mit.txt b/license.mit.txt index c70b2e1e3..7fec1578c 100644 --- a/license.mit.txt +++ b/license.mit.txt @@ -1,4 +1,4 @@ -Copyright (C) 2015 - 2016 Adrien J. and Maxime C. +Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/samples/dokan_mirror/mirror.c b/samples/dokan_mirror/mirror.c index 5d357a64c..0cdd44679 100644 --- a/samples/dokan_mirror/mirror.c +++ b/samples/dokan_mirror/mirror.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -34,6 +34,7 @@ THE SOFTWARE. BOOL g_UseStdErr; BOOL g_DebugMode; +BOOL g_HasSeSecurityPrivilege; static void DbgPrint(LPCWSTR format, ...) { if (g_DebugMode) { @@ -1082,6 +1083,7 @@ static NTSTATUS DOKAN_CALLBACK MirrorGetFileSecurity( PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG BufferLength, PULONG LengthNeeded, PDOKAN_FILE_INFO DokanFileInfo) { WCHAR filePath[MAX_PATH]; + BOOLEAN requestingSaclInfo; UNREFERENCED_PARAMETER(DokanFileInfo); @@ -1105,13 +1107,19 @@ static NTSTATUS DOKAN_CALLBACK MirrorGetFileSecurity( MirrorCheckFlag(*SecurityInformation, UNPROTECTED_DACL_SECURITY_INFORMATION); MirrorCheckFlag(*SecurityInformation, UNPROTECTED_SACL_SECURITY_INFORMATION); + requestingSaclInfo = ((*SecurityInformation & SACL_SECURITY_INFORMATION) || + (*SecurityInformation & BACKUP_SECURITY_INFORMATION)); + + if (!g_HasSeSecurityPrivilege) { + *SecurityInformation &= ~SACL_SECURITY_INFORMATION; + *SecurityInformation &= ~BACKUP_SECURITY_INFORMATION; + } + DbgPrint(L" Opening new handle with READ_CONTROL access\n"); HANDLE handle = CreateFile( - filePath, - READ_CONTROL | (((*SecurityInformation & SACL_SECURITY_INFORMATION) || - (*SecurityInformation & BACKUP_SECURITY_INFORMATION)) - ? ACCESS_SYSTEM_SECURITY - : 0), + filePath, READ_CONTROL | ((requestingSaclInfo && g_HasSeSecurityPrivilege) + ? ACCESS_SYSTEM_SECURITY + : 0), FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, // security attribute OPEN_EXISTING, @@ -1324,6 +1332,7 @@ void ShowUsage() { " /u (UNC provider name ex. \\localhost\\myfs)\t UNC name used for network volume.\n" " /a Allocation unit size (ex. /a 512)\t\t Allocation Unit Size of the volume. This will behave on the disk file size.\n" " /k Sector size (ex. /k 512)\t\t\t Sector Size of the volume. This will behave on the disk file size.\n" + " /f User mode Lock\t\t\t\t Enable Lockfile/Unlockfile operations. Otherwise Dokan will take care of it.\n" " /i (Timeout in Milliseconds ex. /i 30000)\t Timeout until a running operation is aborted and the device is unmounted.\n\n" "Examples:\n" "\tmirror.exe /r C:\\Users /l M:\t\t\t# Mirror C:\\Users as RootDirectory into a drive of letter M:\\.\n" @@ -1399,6 +1408,9 @@ int __cdecl wmain(ULONG argc, PWCHAR argv[]) { case L'c': dokanOptions->Options |= DOKAN_OPTION_CURRENT_SESSION; break; + case L'f': + dokanOptions->Options |= DOKAN_OPTION_FILELOCK_USER_MODE; + break; case L'u': command++; wcscpy_s(UNCName, sizeof(UNCName) / sizeof(WCHAR), argv[command]); @@ -1463,7 +1475,8 @@ int __cdecl wmain(ULONG argc, PWCHAR argv[]) { // Add security name privilege. Required here to handle GetFileSecurity // properly. - if (!AddSeSecurityNamePrivilege()) { + g_HasSeSecurityPrivilege = AddSeSecurityNamePrivilege(); + if (!g_HasSeSecurityPrivilege) { fwprintf(stderr, L"Failed to add security privilege to process\n"); fwprintf(stderr, L"\t=> GetFileSecurity/SetFileSecurity may not work properly\n"); diff --git a/samples/mirror_test.ps1 b/samples/mirror_test.ps1 new file mode 100644 index 000000000..bed9bfe21 --- /dev/null +++ b/samples/mirror_test.ps1 @@ -0,0 +1,112 @@ +function Exec-External { + param( + [Parameter(Position=0,Mandatory=1)][scriptblock] $command + ) + & $command + if ($LASTEXITCODE -ne 0) { + throw ("Command returned non-zero error-code ${LASTEXITCODE}: $command") + } +} + +$fsTestPath = "FSTMP" +$Platforms = @("Win32", "x64") +$DokanDriverLetter = "M" +$Commands = @{ + "/l $DokanDriverLetter" = "$($DokanDriverLetter):" + "/l C:\DokanMount" = "C:\DokanMount" + "/l $DokanDriverLetter /m" = "$($DokanDriverLetter):" + "/l $DokanDriverLetter /o" = "$($DokanDriverLetter):" + "/l $DokanDriverLetter /n" = "$($DokanDriverLetter):" + "/l $DokanDriverLetter /n /u \myfs\dokan" = "\\myfs\dokan" +} + +$buildCmd = "C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" +$env:Path = $env:Path + ";C:\Program Files (x86)\Windows Kits\8.1\bin\x64\" +$env:CI_BUILD_ARG = "" +if ($env:APPVEYOR) { $env:CI_BUILD_ARG="/l:C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" } + +Write-Host Build mirrors -ForegroundColor Green +foreach ($Platform in $Platforms){ + $buildArgs = @( + "..\dokan.sln", + "/m", + "/p:Configuration=Release", + "/p:Platform=$Platform" + "$env:CI_BUILD_ARG") + + Exec-External { & $buildCmd $buildArgs } +} +Write-Host Build mirrors done. -ForegroundColor Green + +Write-Host Build test tools -ForegroundColor Green +if (!(Test-Path .\fstools\src\fsx\fsx.exe)) +{ + Exec-External {if (!(Test-Path fstools)) { git clone -q https://github.com/Liryna/fstools.git } } + Exec-External {cd fstools; git reset --hard f010a68f96e004e8ef76436c0582e64216f400a0; cd .. } + $buildArgs = @( + ".\fstools\winfstest.sln", + "/m", + "/p:Configuration=Release", + "/p:Platform=x64", + "$env:CI_BUILD_ARG") + Exec-External {& $buildCmd $buildArgs} +} + +if (!(Test-Path .\winfstest\TestSuite\winfstest.exe)) +{ + Exec-External {if (!(Test-Path winfstest)) { git clone -q https://github.com/Liryna/winfstest.git } } + Exec-External {cd winfstest; git reset --hard 41ea2b555d9d9abc9ebbd58e6472e0ff703997bd; cd .. } + $buildArgs = @( + ".\winfstest\winfstest.sln", + "/m", + "/p:Configuration=Release", + "/p:Platform=x64", + "$env:CI_BUILD_ARG") + Exec-External {& $buildCmd $buildArgs} +} +Write-Host Build test tools done. -ForegroundColor Green + +if (!(Test-Path "C:\$fsTestPath")) { New-Item "C:\$fsTestPath" -type directory | Out-Null } + +add-type -AssemblyName System.Windows.Forms + +foreach ($Platform in $Platforms){ + $Commands.Keys | % { + $command = $_ + $destination = $Commands.Item($_) + + Write-Host Test mirror $Platform with command $command with $destination as mount -ForegroundColor Green + if ($destination.StartsWith("C:\")) { + #Cleanup mount folder - Tag source folder to wait a not empty folder at mount + New-Item -Force "C:\$fsTestPath\tmp" | Out-Null + if (!(Test-Path $destination)) { New-Item $destination -type directory | Out-Null } + Remove-Item -Recurse -Force "$($destination)\*" + } + + $app = Start-Process -passthru ..\$Platform\Release\mirror.exe -ArgumentList "/r C:\$fsTestPath $command" + + $count = 20; + if ($destination.StartsWith("C:\")) { + while (!(Test-Path "$($destination)\*") -and ($count -ne 0)) { Start-Sleep -m 250; $count -= 1 } + } else { + while (!(Test-Path $destination) -and ($count -ne 0)) { Start-Sleep -m 250 ; $count -= 1 } + } + + if ($count -eq 0) { + throw ("Impossible to mount for command $command") + } + + Write-Host "Start FSX Test" -ForegroundColor Green + Exec-External {& .\fstools\src\fsx\fsx.exe -N 5000 "$($destination)\fsxtest"} + Write-Host "FSX Test finished" -ForegroundColor Green + + Write-Host "Start WinFSTest" -ForegroundColor Green + Exec-External {& .\winfstest\TestSuite\run-winfstest.bat . "$($destination)\"} + Write-Host "WinFSTest finished" -ForegroundColor Green + + [System.Windows.Forms.SendKeys]::SendWait("^{c}") + $app.WaitForExit() + Write-Host Test mirror $Platform ended. -ForegroundColor Green + } +} + diff --git a/sys/access.c b/sys/access.c index 4b9b7b406..b9a502062 100644 --- a/sys/access.c +++ b/sys/access.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -22,7 +22,7 @@ with this program. If not, see . #include "dokan.h" NTSTATUS -DokanGetAccessToken(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { +DokanGetAccessToken(__in PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) { KIRQL oldIrql = 0; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; diff --git a/sys/cleanup.c b/sys/cleanup.c index a525ecae7..2737d0c7d 100644 --- a/sys/cleanup.c +++ b/sys/cleanup.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -88,9 +88,11 @@ Return Value: if (fileObject->SectionObjectPointer != NULL && fileObject->SectionObjectPointer->DataSectionObject != NULL) { + ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE); CcFlushCache(&fcb->SectionObjectPointers, NULL, 0, NULL); CcPurgeCacheSection(&fcb->SectionObjectPointers, NULL, 0, FALSE); CcUninitializeCacheMap(fileObject, NULL, NULL); + ExReleaseResourceLite(&fcb->PagingIoResource); } DokanFCBLockRW(fcb); @@ -115,6 +117,7 @@ Return Value: RtlCopyMemory(eventContext->Operation.Cleanup.FileName, fcb->FileName.Buffer, fcb->FileName.Length); + // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); DokanFCBUnlock(fcb); @@ -171,12 +174,12 @@ VOID DokanCompleteCleanup(__in PIRP_ENTRY IrpEntry, fcb = ccb->Fcb; ASSERT(fcb != NULL); - DokanFCBLockRW(fcb); vcb = fcb->Vcb; status = EventInfo->Status; + DokanFCBLockRO(fcb); if (DokanFCBFlagsIsSet(fcb, DOKAN_DELETE_ON_CLOSE)) { if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) { DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_DIR_NAME, @@ -186,7 +189,7 @@ VOID DokanCompleteCleanup(__in PIRP_ENTRY IrpEntry, FILE_ACTION_REMOVED); } } - + DokanFCBUnlock(fcb); // // Unlock all outstanding file locks. // @@ -198,7 +201,6 @@ VOID DokanCompleteCleanup(__in PIRP_ENTRY IrpEntry, } IoRemoveShareAccess(irpSp->FileObject, &fcb->ShareAccess); - DokanFCBUnlock(fcb); DokanCompleteIrpRequest(irp, status, 0); diff --git a/sys/close.c b/sys/close.c index 1f890ec2a..1df6f3fdb 100644 --- a/sys/close.c +++ b/sys/close.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/sys/create.c b/sys/create.c index 27821a94c..6faee6586 100755 --- a/sys/create.c +++ b/sys/create.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -23,6 +23,7 @@ with this program. If not, see . #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, DokanDispatchCreate) +#pragma alloc_text(PAGE, DokanCheckShareAccess) #endif // We must NOT call without VCB lock @@ -204,7 +205,6 @@ DokanFreeFCB(__in PDokanFCB Fcb) { InterlockedIncrement(&vcb->FcbFreed); ExFreeToLookasideListEx(&g_DokanFCBLookasideList, Fcb); - } else { DokanFCBUnlock(Fcb); } @@ -327,7 +327,8 @@ NTSTATUS DokanGetParentDir(__in const WCHAR *fileName, __out WCHAR **parentDir, if (!*parentDir) return STATUS_INSUFFICIENT_RESOURCES; - wcscpy(*parentDir, fileName); + RtlZeroMemory(*parentDir, len + 1); + RtlStringCchCopyW(*parentDir, len, fileName); for (i = len - 1; i >= 0; i--) { if ((*parentDir)[i] == '\\') { @@ -393,7 +394,6 @@ Otherwise, STATUS_SHARING_VIOLATION is returned. NTSTATUS status; PAGED_CODE(); - DokanFCBLockRW(FcbOrDcb); #if (NTDDI_VERSION >= NTDDI_VISTA) // // Do an extra test for writeable user sections if the user did not allow @@ -408,7 +408,6 @@ Otherwise, STATUS_SHARING_VIOLATION is returned. MmDoesFileHaveUserWritableReferences(&FcbOrDcb->SectionObjectPointers)) { DDbgPrint(" DokanCheckShareAccess FCB has no write shared access\n"); - DokanFCBUnlock(FcbOrDcb); return STATUS_SHARING_VIOLATION; } #endif @@ -419,7 +418,6 @@ Otherwise, STATUS_SHARING_VIOLATION is returned. // Pass FALSE for update. We will update it later. status = IoCheckShareAccess(DesiredAccess, ShareAccess, FileObject, &FcbOrDcb->ShareAccess, FALSE); - DokanFCBUnlock(FcbOrDcb); return status; } @@ -475,6 +473,7 @@ Return Value: BOOLEAN BackoutOplock = FALSE; BOOLEAN EventContextConsumed = FALSE; DWORD disposition = 0; + BOOLEAN fcbLocked = FALSE; PAGED_CODE(); @@ -695,7 +694,6 @@ Return Value: RtlCopyMemory((PCHAR)fileName + relatedFileName->Length + (needBackSlashAfterRelatedFile ? sizeof(WCHAR) : 0), fileObject->FileName.Buffer, fileObject->FileName.Length); - } else { // if related file object is not specifed, copy the file name of file // object @@ -736,13 +734,17 @@ Return Value: status = STATUS_INSUFFICIENT_RESOURCES; __leave; } - DokanFCBLockRW(fcb); + DDbgPrint(" Create: FileName:%wZ got fcb %p\n", + &fileObject->FileName, fcb); if (fcb->FileCount > 1 && disposition == FILE_CREATE) { status = STATUS_OBJECT_NAME_COLLISION; __leave; } + fcbLocked = TRUE; + DokanFCBLockRW(fcb); + if (irpSp->Flags & SL_OPEN_PAGING_FILE) { fcb->AdvancedFCBHeader.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE; fcb->AdvancedFCBHeader.Flags2 &= ~FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS; @@ -990,6 +992,8 @@ Return Value: eventContext->Operation.Create.FileNameOffset + (parentDir ? fileNameLength : fcb->FileName.Length)) = 0; + DokanFCBUnlock(fcb); + fcbLocked = FALSE; // // Oplock // @@ -1042,12 +1046,11 @@ Return Value: FILE_COMPLETE_IF_OPLOCKED)) { POPLOCK oplock = DokanGetFcbOplock(fcb); - DokanFCBUnlock(fcb); + // This may enter a wait state! OplockBreakStatus = FsRtlOplockBreakH( oplock, Irp, 0, eventContext, NULL /* DokanOplockComplete */, // block instead of callback DokanPrePostIrp); - DokanFCBLockRW(fcb); // // If FsRtlOplockBreakH returned STATUS_PENDING, @@ -1112,7 +1115,6 @@ Return Value: // user mode create happens. // It is believed that FILE_COMPLETE_IF_OPLOCKED is extremely // rare and may never happend during normal operation. - } else { if (status == STATUS_SHARING_VIOLATION && @@ -1131,7 +1133,6 @@ Return Value: #endif } IoUpdateShareAccess(fileObject, &fcb->ShareAccess); - } else { IoSetShareAccess( eventContext->Operation.Create.SecurityContext.DesiredAccess, @@ -1150,6 +1151,7 @@ Return Value: // that the Oplock check proceeds against any added access we had // to give the caller. // + // This may block and enter wait state! if (fcb->FileCount > 1) { status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, @@ -1160,9 +1162,9 @@ Return Value: // to service an oplock break and we need to leave now. // if (status == STATUS_PENDING) { - DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING, fileName = " - "%wZ, fileCount = %lu\n", - fcb->FileName, fcb->FileCount); + DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING, fcb = " + "%p, fileCount = %lu\n", + fcb, fcb->FileCount); __leave; } } @@ -1171,6 +1173,7 @@ Return Value: // Let's make sure that if the caller provided an oplock key that it // gets stored in the file object. // + // OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY means that no blocking. status = FsRtlCheckOplockEx(DokanGetFcbOplock(fcb), Irp, @@ -1199,9 +1202,9 @@ Return Value: // if ((status != STATUS_SUCCESS) && (status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) { - DDbgPrint(" FsRtlOplockFsctrl failed with 0x%x, fileName = %wZ, " + DDbgPrint(" FsRtlOplockFsctrl failed with 0x%x, fcb = %p, " "fileCount = %lu\n", - status, fcb->FileName, fcb->FileCount); + status, fcb, fcb->FileCount); __leave; } else if (status == STATUS_OPLOCK_BREAK_IN_PROGRESS) { @@ -1218,7 +1221,6 @@ Return Value: status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); EventContextConsumed = TRUE; - } __finally { DDbgPrint(" Create: FileName:%wZ, status = 0x%08x\n", @@ -1248,7 +1250,7 @@ Return Value: } } #endif - if (fcb) + if (fcbLocked) DokanFCBUnlock(fcb); if (relatedFileName) { diff --git a/sys/device.c b/sys/device.c index 29733b42f..04fc30b12 100644 --- a/sys/device.c +++ b/sys/device.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -49,6 +49,7 @@ VOID PrintUnknownDeviceIoctlCode(__in ULONG IoctlCode) { case MOUNTMGRCONTROLTYPE: baseCodeStr = "MOUNTMGRCONTROLTYPE"; break; + default: break; } UNREFERENCED_PARAMETER(functionCode); DDbgPrint(" BaseCode: 0x%x(%s) FunctionCode 0x%x(%d)\n", baseCode, @@ -218,6 +219,9 @@ DiskDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { DDbgPrint(" IOCTL_DISK_GET_PARTITION_INFO_EX\n"); Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX); break; + default: + DDbgPrint(" unknown ioctl %d\n", ioctl); + break; } if (outputLength < Irp->IoStatus.Information) { @@ -507,8 +511,15 @@ DiskDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { status = STATUS_SUCCESS; if (!IsUnmountPending(DeviceObject) && mountdevName != NULL && mountdevName->NameLength > 0) { - WCHAR symbolicLinkNameBuf[MAXIMUM_FILENAME_LENGTH]; - RtlZeroMemory(symbolicLinkNameBuf, sizeof(symbolicLinkNameBuf)); + WCHAR *symbolicLinkNameBuf = + ExAllocatePool((mountdevName->NameLength + 1) * sizeof(WCHAR)); + if (symbolicLinkNameBuf == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + RtlZeroMemory(symbolicLinkNameBuf, + (mountdevName->NameLength + 1) * sizeof(WCHAR)); RtlCopyMemory(symbolicLinkNameBuf, mountdevName->Name, mountdevName->NameLength); DDbgPrint(" MountDev Name: %ws\n", symbolicLinkNameBuf); @@ -522,16 +533,22 @@ DiskDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { DDbgPrint(" Not current MountPoint. MountDev set as MountPoint\n"); dcb->MountPoint = DokanAllocateUnicodeString(symbolicLinkNameBuf); if (dcb->DiskDeviceName != NULL) { - DOKAN_CONTROL dokanControl; PMOUNT_ENTRY mountEntry; - RtlZeroMemory(&dokanControl, sizeof(dokanControl)); - RtlCopyMemory(dokanControl.DeviceName, dcb->DiskDeviceName->Buffer, + PDOKAN_CONTROL dokanControl = ExAllocatePool(sizeof(DOKAN_CONTROL)); + if (dokanControl == NULL) { + ExFreePool(symbolicLinkNameBuf); + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + RtlZeroMemory(dokanControl, sizeof(*dokanControl)); + RtlCopyMemory(dokanControl->DeviceName, dcb->DiskDeviceName->Buffer, dcb->DiskDeviceName->Length); if (dcb->UNCName->Buffer != NULL && dcb->UNCName->Length > 0) { - RtlCopyMemory(dokanControl.UNCName, dcb->UNCName->Buffer, + RtlCopyMemory(dokanControl->UNCName, dcb->UNCName->Buffer, dcb->UNCName->Length); } - mountEntry = FindMountEntry(dcb->Global, &dokanControl, TRUE); + mountEntry = FindMountEntry(dcb->Global, dokanControl, TRUE); + ExFreePool(dokanControl); if (mountEntry != NULL) { RtlStringCchCopyW(mountEntry->MountControl.MountPoint, MAXIMUM_FILENAME_LENGTH, symbolicLinkNameBuf); @@ -549,6 +566,7 @@ DiskDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { } else { DDbgPrint(" Mount Point is not DosDevices, ignored.\n"); } + ExFreePool(symbolicLinkNameBuf); } else { DDbgPrint(" MountDev Name is undefined or unmounting in progress.\n"); } @@ -559,8 +577,15 @@ DiskDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { status = STATUS_SUCCESS; if (dcb->UseMountManager) { if (mountdevName != NULL && mountdevName->NameLength > 0) { - WCHAR symbolicLinkNameBuf[MAXIMUM_FILENAME_LENGTH]; - RtlZeroMemory(symbolicLinkNameBuf, sizeof(symbolicLinkNameBuf)); + WCHAR *symbolicLinkNameBuf = + ExAllocatePool((mountdevName->NameLength + 1) * sizeof(WCHAR)); + if (symbolicLinkNameBuf == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + RtlZeroMemory(symbolicLinkNameBuf, + (mountdevName->NameLength + 1) * sizeof(WCHAR)); RtlCopyMemory(symbolicLinkNameBuf, mountdevName->Name, mountdevName->NameLength); DDbgPrint(" MountDev Name: %ws\n", symbolicLinkNameBuf); @@ -583,6 +608,7 @@ DiskDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { else { status = DokanEventRelease(vcb->DeviceObject, Irp); } + ExFreePool(symbolicLinkNameBuf); } else { DDbgPrint(" MountDev Name is undefined.\n"); } @@ -668,7 +694,7 @@ DiskDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { DDbgPrint(" PathNameLength = %d\n", pathReq->PathNameLength); DDbgPrint(" SecurityContext = %p\n", pathReq->SecurityContext); DDbgPrint(" FilePathName = %.*ls\n", - pathReq->PathNameLength / sizeof(WCHAR), + (unsigned int)(pathReq->PathNameLength / sizeof(WCHAR)), pathReq->FilePathName); lpPath = pathReq->FilePathName; @@ -697,7 +723,7 @@ DiskDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { DDbgPrint(" pEaBuffer = %p\n", pathReqEx->pEaBuffer); DDbgPrint(" PathNameLength = %d\n", pathReqEx->PathName.Length); DDbgPrint(" FilePathName = %*ls\n", - pathReqEx->PathName.Length / sizeof(WCHAR), + (unsigned int)(pathReqEx->PathName.Length / sizeof(WCHAR)), pathReqEx->PathName.Buffer); lpPath = pathReqEx->PathName.Buffer; @@ -765,20 +791,26 @@ DiskDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { mediaTypes->DeviceType = FILE_DEVICE_VIRTUAL_DISK; mediaTypes->MediaInfoCount = 1; - DISK_GEOMETRY diskGeometry; - DokanPopulateDiskGeometry(&diskGeometry); - mediaInfo->DeviceSpecific.DiskInfo.MediaType = diskGeometry.MediaType; + PDISK_GEOMETRY diskGeometry = ExAllocatePool(sizeof(DISK_GEOMETRY)); + if (diskGeometry == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + RtlZeroMemory(diskGeometry, sizeof(*diskGeometry)); + DokanPopulateDiskGeometry(diskGeometry); + mediaInfo->DeviceSpecific.DiskInfo.MediaType = diskGeometry->MediaType; mediaInfo->DeviceSpecific.DiskInfo.NumberMediaSides = 1; mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE); mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart = - diskGeometry.Cylinders.QuadPart; + diskGeometry->Cylinders.QuadPart; mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder = - diskGeometry.TracksPerCylinder; + diskGeometry->TracksPerCylinder; mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack = - diskGeometry.SectorsPerTrack; + diskGeometry->SectorsPerTrack; mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector = - diskGeometry.BytesPerSector; + diskGeometry->BytesPerSector; + ExFreePool(diskGeometry); status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(GET_MEDIA_TYPES); @@ -984,8 +1016,8 @@ Return Value: if (status != STATUS_PENDING) { if (IsDeletePending(DeviceObject)) { - DDbgPrint(" DeviceObject is invalid, so prevent BSOD"); - status = STATUS_DEVICE_REMOVED; + DDbgPrint(" DeviceObject is invalid, so prevent BSOD"); + status = STATUS_DEVICE_REMOVED; } DokanCompleteIrpRequest(Irp, status, Irp->IoStatus.Information); } diff --git a/sys/directory.c b/sys/directory.c index ec319aec4..5f95aba2a 100644 --- a/sys/directory.c +++ b/sys/directory.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/sys/dispatch.c b/sys/dispatch.c index 5365f816d..bd29c9ce4 100644 --- a/sys/dispatch.c +++ b/sys/dispatch.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -22,7 +22,7 @@ with this program. If not, see . #include "dokan.h" NTSTATUS -DokanBuildRequest(PDEVICE_OBJECT DeviceObject, PIRP Irp) { +DokanBuildRequest(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { BOOLEAN AtIrqlPassiveLevel = FALSE; BOOLEAN IsTopLevelIrp = FALSE; NTSTATUS Status = STATUS_UNSUCCESSFUL; diff --git a/sys/dokan.c b/sys/dokan.c index c7220d800..ce20b9335 100644 --- a/sys/dokan.c +++ b/sys/dokan.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -339,9 +339,10 @@ Return Value: UNICODE_STRING symbolicLinkName; PDOKAN_GLOBAL dokanGlobal; - // PAGED_CODE(); DDbgPrint("==> DokanUnload\n"); + PAGED_CODE(); + dokanGlobal = deviceObject->DeviceExtension; if (GetIdentifierType(dokanGlobal) == DGL) { DDbgPrint(" Delete Global DeviceObject\n"); @@ -365,7 +366,6 @@ Return Value: ExDeleteLookasideListEx(&g_DokanEResourceLookasideList); DDbgPrint("<== DokanUnload\n"); - return; } NTSTATUS @@ -406,7 +406,6 @@ VOID DokanNoOpRelease(__in PVOID Fcb) { UNREFERENCED_PARAMETER(Fcb); DDbgPrint("<== DokanNoOpRelease\n"); - return; } #define PrintStatus(val, flag) \ diff --git a/sys/dokan.h b/sys/dokan.h index 8043801bb..bd3889276 100644 --- a/sys/dokan.h +++ b/sys/dokan.h @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -308,7 +308,7 @@ typedef struct _DokanVolumeControlBlock { #define DCB_DELETE_PENDING 0x00000001 typedef struct _DokanFileControlBlock { - // Locking: Identifier is read-only, no locks needed. + // Locking: Identifier is read-only, no locks needed. FSD_IDENTIFIER Identifier; // Locking: FIXME @@ -322,25 +322,25 @@ typedef struct _DokanFileControlBlock { // Locking: Lock for paging io. ERESOURCE PagingIoResource; - // Locking: Vcb pointer is read-only, no locks needed. + // Locking: Vcb pointer is read-only, no locks needed. PDokanVCB Vcb; // Locking: DokanFCBLock{RO,RW} and usually vcb lock LIST_ENTRY NextFCB; // Locking: DokanFCBLock{RO,RW} LIST_ENTRY NextCCB; - // Locking: DokanFCBLock{RO,RW} + // Locking: Atomics - not behind an accessor. LONG FileCount; // Locking: Use atomic flag operations - DokanFCBFlags* ULONG Flags; - // Locking: DokanFCBLock{RO,RW} + // Locking: Functions are ok to call concurrently. SHARE_ACCESS ShareAccess; // Locking: DokanFCBLock{RO,RW} - e.g. renames change this field. UNICODE_STRING FileName; - // Locking: DokanFCBLock{RO,RW} + // Locking: FsRtl routines should be enough after initialization. FILE_LOCK FileLock; #if (NTDDI_VERSION < NTDDI_WIN8) @@ -523,6 +523,10 @@ DRIVER_DISPATCH DokanResetPendingIrpTimeout; DRIVER_DISPATCH DokanGetAccessToken; +NTSTATUS +DokanCheckShareAccess(_In_ PFILE_OBJECT FileObject, _In_ PDokanFCB FcbOrDcb, + _In_ ACCESS_MASK DesiredAccess, _In_ ULONG ShareAccess); + NTSTATUS DokanGetMountPointList(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PDOKAN_GLOBAL dokanGlobal); @@ -624,6 +628,9 @@ NTSTATUS IsMountPointDriveLetter(__in PUNICODE_STRING mountPoint); VOID DokanDeleteMountPoint(__in PDokanDCB Dcb); VOID DokanPrintNTStatus(NTSTATUS Status); +NTSTATUS DokanOplockRequest(__in PIRP *pIrp); +NTSTATUS DokanCommonLockControl(__in PIRP Irp); + NTSTATUS DokanRegisterUncProviderSystem(PDokanDCB dcb); VOID DokanCompleteIrpRequest(__in PIRP Irp, __in NTSTATUS Status, __in ULONG_PTR Info); @@ -634,7 +641,8 @@ VOID DokanNotifyReportChange0(__in PDokanFCB Fcb, __in PUNICODE_STRING FileName, VOID DokanNotifyReportChange(__in PDokanFCB Fcb, __in ULONG FilterMatch, __in ULONG Action); -PDokanFCB DokanAllocateFCB(__in PDokanVCB Vcb, __in PWCHAR FileName, __in ULONG FileNameLength); +PDokanFCB DokanAllocateFCB(__in PDokanVCB Vcb, __in PWCHAR FileName, + __in ULONG FileNameLength); NTSTATUS DokanFreeFCB(__in PDokanFCB Fcb); @@ -712,7 +720,7 @@ __inline VOID DokanClearFlag(PULONG Flags, ULONG FlagBit) { #define IsFlagOn(a, b) ((BOOLEAN)(FlagOn(a, b) == b)) #define DokanFCBFlagsGet(fcb) ((fcb)->Flags) -#define DokanFCBFlagsIsSet(fcb, bit) (((fcb)->Flags)&(bit)) +#define DokanFCBFlagsIsSet(fcb, bit) (((fcb)->Flags) & (bit)) #define DokanFCBFlagsSetBit(fcb, bit) SetLongFlag((fcb)->Flags, (bit)) #define DokanFCBFlagsClearBit(fcb, bit) ClearLongFlag((fcb)->Flags, (bit)) @@ -721,5 +729,4 @@ __inline VOID DokanClearFlag(PULONG Flags, ULONG FlagBit) { #define DokanCCBFlagsSetBit DokanFCBFlagsSetBit #define DokanCCBFlagsClearBit DokanFCBFlagsClearBit - #endif // DOKAN_H_ diff --git a/sys/dokan.inf b/sys/dokan.inf index 2dda97e8e..7c09f9722 100644 --- a/sys/dokan.inf +++ b/sys/dokan.inf @@ -3,7 +3,7 @@ Signature = "$Windows NT$" Class = DiskDrive ClassGuid = {4d36e967-e325-11ce-bfc1-08002be10318} Provider = %Dokan% -DriverVer = 01/01/2016,1.0.0.0 +DriverVer = 01/01/2017,1.0.0.0 CatalogFile = %DriverName%.cat DriverPackageType = FileSystem diff --git a/sys/dokan.rc b/sys/dokan.rc index 437438304..15a44f9ed 100644 --- a/sys/dokan.rc +++ b/sys/dokan.rc @@ -16,8 +16,8 @@ // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,1,0000 - PRODUCTVERSION 1,0,1,0000 + FILEVERSION 1,0,2,1000 + PRODUCTVERSION 1,0,2,1000 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -34,12 +34,12 @@ BEGIN BEGIN VALUE "CompanyName", "Dokan Project" VALUE "FileDescription", "Dokan Driver" - VALUE "FileVersion", "1.0.1.0000" + VALUE "FileVersion", "1.0.2.1000" VALUE "InternalName", "dokan.sys" - VALUE "LegalCopyright", "Copyright (C) 2016" + VALUE "LegalCopyright", "Copyright (C) 2017" VALUE "OriginalFilename", "dokan.sys" VALUE "ProductName", "Dokan" - VALUE "ProductVersion", "1.0.1.0000" + VALUE "ProductVersion", "1.0.2.1000" END END BLOCK "VarFileInfo" diff --git a/sys/event.c b/sys/event.c index ac556e564..757de7b24 100644 --- a/sys/event.c +++ b/sys/event.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -21,7 +21,12 @@ with this program. If not, see . #include "dokan.h" -VOID DokanIrpCancelRoutine(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, DokanOplockComplete) +#endif + +VOID DokanIrpCancelRoutine(_Inout_ PDEVICE_OBJECT DeviceObject, + _Inout_ _IRQL_uses_cancel_ PIRP Irp) { KIRQL oldIrql; PIRP_ENTRY irpEntry; ULONG serialNumber = 0; @@ -85,7 +90,6 @@ VOID DokanIrpCancelRoutine(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { DokanCompleteIrpRequest(Irp, STATUS_CANCELLED, 0); DDbgPrint("<== DokanIrpCancelRoutine\n"); - return; } VOID DokanOplockComplete(IN PVOID Context, IN PIRP Irp) @@ -120,8 +124,6 @@ None. } DDbgPrint("<== DokanOplockComplete\n"); - - return; } VOID DokanPrePostIrp(IN PVOID Context, IN PIRP Irp) @@ -257,7 +259,7 @@ DokanRegisterPendingIrp(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, NTSTATUS DokanRegisterPendingIrpForEvent(__in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp) { + _Inout_ PIRP Irp) { PDokanVCB vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { @@ -282,7 +284,7 @@ DokanRegisterPendingIrpForEvent(__in PDEVICE_OBJECT DeviceObject, NTSTATUS DokanRegisterPendingIrpForService(__in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp) { + _Inout_ PIRP Irp) { PDOKAN_GLOBAL dokanGlobal; DDbgPrint("DokanRegisterPendingIrpForService\n"); @@ -301,7 +303,7 @@ DokanRegisterPendingIrpForService(__in PDEVICE_OBJECT DeviceObject, // When user-mode file system application returns EventInformation, // search corresponding pending IRP and complete it NTSTATUS -DokanCompleteIrp(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { +DokanCompleteIrp(__in PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; @@ -449,18 +451,18 @@ DokanCompleteIrp(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { // start event dispatching NTSTATUS -DokanEventStart(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { +DokanEventStart(__in PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) { ULONG outBufferLen; ULONG inBufferLen; - PIO_STACK_LOCATION irpSp; - EVENT_START eventStart; - PEVENT_DRIVER_INFO driverInfo; - PDOKAN_GLOBAL dokanGlobal; - PDokanDCB dcb; + PIO_STACK_LOCATION irpSp = NULL; + PEVENT_START eventStart = NULL; + PEVENT_DRIVER_INFO driverInfo = NULL; + PDOKAN_GLOBAL dokanGlobal = NULL; + PDokanDCB dcb = NULL; NTSTATUS status; DEVICE_TYPE deviceType; ULONG deviceCharacteristics = 0; - WCHAR baseGuidString[64]; + WCHAR *baseGuidString; GUID baseGuid = DOKAN_BASE_GUID; UNICODE_STRING unicodeGuid; ULONG deviceNamePos; @@ -480,24 +482,34 @@ DokanEventStart(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { outBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength; inBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength; + eventStart = ExAllocatePool(sizeof(EVENT_START)); + baseGuidString = ExAllocatePool(64 * sizeof(WCHAR)); + if (outBufferLen != sizeof(EVENT_DRIVER_INFO) || - inBufferLen != sizeof(EVENT_START)) { + inBufferLen != sizeof(EVENT_START) || eventStart == NULL || + baseGuidString == NULL) { + if (eventStart) + ExFreePool(eventStart); + if (baseGuidString) + ExFreePool(baseGuidString); return STATUS_INSUFFICIENT_RESOURCES; } - RtlCopyMemory(&eventStart, Irp->AssociatedIrp.SystemBuffer, + RtlCopyMemory(eventStart, Irp->AssociatedIrp.SystemBuffer, sizeof(EVENT_START)); driverInfo = Irp->AssociatedIrp.SystemBuffer; - if (eventStart.UserVersion != DOKAN_DRIVER_VERSION) { + if (eventStart->UserVersion != DOKAN_DRIVER_VERSION) { driverInfo->DriverVersion = DOKAN_DRIVER_VERSION; driverInfo->Status = DOKAN_START_FAILED; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO); + ExFreePool(eventStart); + ExFreePool(baseGuidString); return STATUS_SUCCESS; } - switch (eventStart.DeviceType) { + switch (eventStart->DeviceType) { case DOKAN_DISK_FILE_SYSTEM: deviceType = FILE_DEVICE_DISK_FILE_SYSTEM; break; @@ -506,31 +518,31 @@ DokanEventStart(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { deviceCharacteristics |= FILE_REMOTE_DEVICE; break; default: - DDbgPrint(" Unknown device type: %d\n", eventStart.DeviceType); + DDbgPrint(" Unknown device type: %d\n", eventStart->DeviceType); deviceType = FILE_DEVICE_DISK_FILE_SYSTEM; } - if (eventStart.Flags & DOKAN_EVENT_REMOVABLE) { + if (eventStart->Flags & DOKAN_EVENT_REMOVABLE) { DDbgPrint(" DeviceCharacteristics |= FILE_REMOVABLE_MEDIA\n"); deviceCharacteristics |= FILE_REMOVABLE_MEDIA; } - if (eventStart.Flags & DOKAN_EVENT_WRITE_PROTECT) { + if (eventStart->Flags & DOKAN_EVENT_WRITE_PROTECT) { DDbgPrint(" DeviceCharacteristics |= FILE_READ_ONLY_DEVICE\n"); deviceCharacteristics |= FILE_READ_ONLY_DEVICE; } - if (eventStart.Flags & DOKAN_EVENT_MOUNT_MANAGER) { + if (eventStart->Flags & DOKAN_EVENT_MOUNT_MANAGER) { DDbgPrint(" Using Mount Manager\n"); useMountManager = TRUE; } - if (eventStart.Flags & DOKAN_EVENT_CURRENT_SESSION) { + if (eventStart->Flags & DOKAN_EVENT_CURRENT_SESSION) { DDbgPrint(" Mounting on current session only\n"); mountGlobally = FALSE; } - if (eventStart.Flags & DOKAN_EVENT_FILELOCK_USER_MODE) { + if (eventStart->Flags & DOKAN_EVENT_FILELOCK_USER_MODE) { DDbgPrint(" FileLock in User Mode\n"); fileLockUserMode = TRUE; } @@ -542,13 +554,13 @@ DokanEventStart(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { RtlZeroMemory(&dokanControl, sizeof(dokanControl)); RtlStringCchCopyW(dokanControl.MountPoint, MAXIMUM_FILENAME_LENGTH, L"\\DosDevices\\"); - if (wcslen(eventStart.MountPoint) == 1) { - dokanControl.MountPoint[12] = towupper(eventStart.MountPoint[0]); + if (wcslen(eventStart->MountPoint) == 1) { + dokanControl.MountPoint[12] = towupper(eventStart->MountPoint[0]); dokanControl.MountPoint[13] = L':'; dokanControl.MountPoint[14] = L'\0'; } else { RtlStringCchCatW(dokanControl.MountPoint, MAXIMUM_FILENAME_LENGTH, - eventStart.MountPoint); + eventStart->MountPoint); } DDbgPrint(" Checking for MountPoint %ls \n", dokanControl.MountPoint); @@ -561,6 +573,8 @@ DokanEventStart(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO); ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); + ExFreePool(eventStart); + ExFreePool(baseGuidString); return STATUS_SUCCESS; } @@ -571,23 +585,27 @@ DokanEventStart(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { if (!NT_SUCCESS(status)) { ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); + ExFreePool(eventStart); + ExFreePool(baseGuidString); return status; } - RtlZeroMemory(baseGuidString, sizeof(baseGuidString)); - RtlStringCchCopyW(baseGuidString, sizeof(baseGuidString) / sizeof(WCHAR), + RtlZeroMemory(baseGuidString, 64 * sizeof(WCHAR)); + RtlStringCchCopyW(baseGuidString, 64, unicodeGuid.Buffer); RtlFreeUnicodeString(&unicodeGuid); InterlockedIncrement((LONG *)&dokanGlobal->MountId); status = DokanCreateDiskDevice( - DeviceObject->DriverObject, dokanGlobal->MountId, eventStart.MountPoint, - eventStart.UNCName, baseGuidString, dokanGlobal, deviceType, + DeviceObject->DriverObject, dokanGlobal->MountId, eventStart->MountPoint, + eventStart->UNCName, baseGuidString, dokanGlobal, deviceType, deviceCharacteristics, mountGlobally, useMountManager, &dcb); if (!NT_SUCCESS(status)) { ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); + ExFreePool(eventStart); + ExFreePool(baseGuidString); return status; } @@ -613,21 +631,21 @@ DokanEventStart(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { // Set the irp timeout in milliseconds // If the IrpTimeout is 0, we assume that the value was not changed dcb->IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT; - if (eventStart.IrpTimeout > 0) { - if (eventStart.IrpTimeout > DOKAN_IRP_PENDING_TIMEOUT_RESET_MAX) { - eventStart.IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT_RESET_MAX; + if (eventStart->IrpTimeout > 0) { + if (eventStart->IrpTimeout > DOKAN_IRP_PENDING_TIMEOUT_RESET_MAX) { + eventStart->IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT_RESET_MAX; } - if (eventStart.IrpTimeout < DOKAN_IRP_PENDING_TIMEOUT) { - eventStart.IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT; + if (eventStart->IrpTimeout < DOKAN_IRP_PENDING_TIMEOUT) { + eventStart->IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT; } - dcb->IrpTimeout = eventStart.IrpTimeout; + dcb->IrpTimeout = eventStart->IrpTimeout; } DDbgPrint(" DeviceName:%ws\n", driverInfo->DeviceName); dcb->UseAltStream = 0; - if (eventStart.Flags & DOKAN_EVENT_ALTERNATIVE_STREAM_ON) { + if (eventStart->Flags & DOKAN_EVENT_ALTERNATIVE_STREAM_ON) { DDbgPrint(" ALT_STREAM_ON\n"); dcb->UseAltStream = 1; } @@ -642,6 +660,9 @@ DokanEventStart(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO); + ExFreePool(eventStart); + ExFreePool(baseGuidString); + DDbgPrint("<== DokanEventStart\n"); return Irp->IoStatus.Status; @@ -649,7 +670,7 @@ DokanEventStart(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { // user assinged bigger buffer that is enough to return WriteEventContext NTSTATUS -DokanEventWrite(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { +DokanEventWrite(__in PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; diff --git a/sys/except.c b/sys/except.c index d3e68e11f..667928070 100644 --- a/sys/except.c +++ b/sys/except.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/sys/fileinfo.c b/sys/fileinfo.c index 23485f5c3..590c3c851 100644 --- a/sys/fileinfo.c +++ b/sys/fileinfo.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -32,6 +32,7 @@ DokanDispatchQueryInformation(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { ULONG info = 0; ULONG eventLength; PEVENT_CONTEXT eventContext; + BOOLEAN isNormalized = FALSE; // PAGED_CODE(); @@ -99,31 +100,59 @@ DokanDispatchQueryInformation(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { case FileCompressionInformation: DDbgPrint(" FileCompressionInformation\n"); break; - case FileNormalizedNameInformation: // Fake implementation by returning - // FileNameInformation result. - // TODO: implement it - DDbgPrint(" FileNormalizedNameInformation\n"); + case FileNormalizedNameInformation: + DDbgPrint(" FileNormalizedNameInformation\n"); + isNormalized = TRUE; case FileNameInformation: { PFILE_NAME_INFORMATION nameInfo; DDbgPrint(" FileNameInformation\n"); + nameInfo = (PFILE_NAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + ASSERT(nameInfo != NULL); + + BOOLEAN isNetworkFileSystem = (vcb->Dcb->VolumeDeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM); + PUNICODE_STRING fileName = &fcb->FileName; + USHORT length = fcb->FileName.Length; + BOOLEAN doConcat = FALSE; + + if (isNetworkFileSystem) { + if (fcb->FileName.Length == 0 || fcb->FileName.Buffer[0] != L'\\') { + DDbgPrint(" NetworkFileSystem has no root folder. So return the full device name \n"); + fileName = vcb->Dcb->DiskDeviceName; + length = fileName->Length; + } + else { + if (isNormalized) { + DDbgPrint(" FullFileName should be returned \n"); + fileName = vcb->Dcb->DiskDeviceName; + length = fileName->Length + vcb->Dcb->DiskDeviceName->Length; + doConcat = TRUE; + } + } + } + if (irpSp->Parameters.QueryFile.Length < - sizeof(FILE_NAME_INFORMATION) + fcb->FileName.Length) { + sizeof(FILE_NAME_INFORMATION) + length) { info = irpSp->Parameters.QueryFile.Length; status = STATUS_BUFFER_OVERFLOW; } else { - nameInfo = (PFILE_NAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; - ASSERT(nameInfo != NULL); + RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.QueryFile.Length); + + nameInfo->FileNameLength = fileName->Length; + RtlCopyMemory(&nameInfo->FileName[0], fileName->Buffer, + fileName->Length); + + if (doConcat) { + DDbgPrint(" Concat the devicename with the filename to get the fullname of the file \n"); + RtlStringCchCatW(nameInfo->FileName, NTSTRSAFE_MAX_CCH, fcb->FileName.Buffer); + } - nameInfo->FileNameLength = fcb->FileName.Length; - RtlCopyMemory(nameInfo->FileName, fcb->FileName.Buffer, - fcb->FileName.Length); info = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + - fcb->FileName.Length; + length; status = STATUS_SUCCESS; } __leave; @@ -435,14 +464,18 @@ DokanDispatchSetInformation(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { FIELD_OFFSET(EVENT_CONTEXT, Operation.SetFile.FileName[0]) + fcb->FileName.Length + sizeof(WCHAR); // the last null char - // copy FileInformation - RtlCopyMemory( - (PCHAR)eventContext + eventContext->Operation.SetFile.BufferOffset, - Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.SetFile.Length); + BOOLEAN isRenameOrLink = irpSp->Parameters.SetFile.FileInformationClass == + FileRenameInformation || + irpSp->Parameters.SetFile.FileInformationClass == FileLinkInformation; + + if (!isRenameOrLink) { + // copy FileInformation + RtlCopyMemory( + (PCHAR)eventContext + eventContext->Operation.SetFile.BufferOffset, + Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.SetFile.Length); + } - if (irpSp->Parameters.SetFile.FileInformationClass == - FileRenameInformation || - irpSp->Parameters.SetFile.FileInformationClass == FileLinkInformation) { + if (isRenameOrLink) { // We need to hanle FileRenameInformation separetly because the structure // of FILE_RENAME_INFORMATION // has HANDLE type field, which size is different in 32 bit and 64 bit @@ -468,14 +501,28 @@ DokanDispatchSetInformation(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { // if Parameters.SetFile.FileObject is specified, replase // FILE_RENAME_INFO's file name by // FileObject's file name. The buffer size is already adjusted. + DDbgPrint(" renameContext->FileNameLength %d\n", - renameContext->FileNameLength); + renameContext->FileNameLength); DDbgPrint(" renameContext->FileName %ws\n", renameContext->FileName); RtlZeroMemory(renameContext->FileName, renameContext->FileNameLength); - RtlCopyMemory(renameContext->FileName, - targetFileObject->FileName.Buffer, - targetFileObject->FileName.Length); - renameContext->FileNameLength = targetFileObject->FileName.Length; + + PFILE_OBJECT parentFileObject = targetFileObject->RelatedFileObject; + if (parentFileObject != NULL) { + RtlCopyMemory(renameContext->FileName, + parentFileObject->FileName.Buffer, + parentFileObject->FileName.Length); + + RtlStringCchCatW(renameContext->FileName, NTSTRSAFE_MAX_CCH, L"\\"); + RtlStringCchCatW(renameContext->FileName, NTSTRSAFE_MAX_CCH, targetFileObject->FileName.Buffer); + renameContext->FileNameLength = targetFileObject->FileName.Length + + parentFileObject->FileName.Length + sizeof(WCHAR); + } else { + RtlCopyMemory(renameContext->FileName, + targetFileObject->FileName.Buffer, + targetFileObject->FileName.Length); + renameContext->FileNameLength = targetFileObject->FileName.Length; + } } if (irpSp->Parameters.SetFile.FileInformationClass == @@ -490,6 +537,7 @@ DokanDispatchSetInformation(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { RtlCopyMemory(eventContext->Operation.SetFile.FileName, fcb->FileName.Buffer, fcb->FileName.Length); + // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); diff --git a/sys/flush.c b/sys/flush.c index 3bf407e55..039335389 100644 --- a/sys/flush.c +++ b/sys/flush.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -79,6 +79,7 @@ DokanDispatchFlush(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { CcUninitializeCacheMap(fileObject, NULL, NULL); // fileObject->Flags &= FO_CLEANUP_COMPLETE; + // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); diff --git a/sys/fscontrol.c b/sys/fscontrol.c index 6cb8858b7..64cdae330 100644 --- a/sys/fscontrol.c +++ b/sys/fscontrol.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -22,6 +22,10 @@ with this program. If not, see . #include "dokan.h" #include +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, DokanOplockRequest) +#endif + NTSTATUS DokanOplockRequest(__in PIRP *pIrp) { NTSTATUS Status = STATUS_SUCCESS; ULONG FsControlCode; @@ -37,7 +41,6 @@ NTSTATUS DokanOplockRequest(__in PIRP *pIrp) { PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); BOOLEAN AcquiredVcb = FALSE; - BOOLEAN AcquiredFcb = FALSE; #if (NTDDI_VERSION >= NTDDI_WIN7) PREQUEST_OPLOCK_INPUT_BUFFER InputBuffer = NULL; @@ -131,8 +134,6 @@ NTSTATUS DokanOplockRequest(__in PIRP *pIrp) { ) { AcquiredVcb = ExAcquireResourceSharedLite(&(Fcb->Vcb->Resource), TRUE); - DokanFCBLockRW(Fcb); - AcquiredFcb = TRUE; #if (NTDDI_VERSION >= NTDDI_WIN7) if (!Dcb->FileLockInUserMode && FsRtlOplockIsSharedRequest(Irp)) { @@ -162,7 +163,7 @@ NTSTATUS DokanOplockRequest(__in PIRP *pIrp) { } else { // Shouldn't be something like UncleanCount counter and not FileCount // here? - OplockCount = Fcb->FileCount; + OplockCount = 0;//Fcb->FileCount; } } else if ((FsControlCode == FSCTL_OPLOCK_BREAK_ACKNOWLEDGE) || (FsControlCode == FSCTL_OPBATCH_ACK_CLOSE_PENDING) || @@ -174,8 +175,6 @@ NTSTATUS DokanOplockRequest(__in PIRP *pIrp) { #endif ) { - DokanFCBLockRO(Fcb); - AcquiredFcb = TRUE; #if (NTDDI_VERSION >= NTDDI_WIN7) } else if (FsControlCode == FSCTL_REQUEST_OPLOCK) { // @@ -183,13 +182,15 @@ NTSTATUS DokanOplockRequest(__in PIRP *pIrp) { // REQUEST_OPLOCK_INPUT_FLAG_ACK on the input buffer. // DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); - return STATUS_INVALID_PARAMETER; + Status = STATUS_INVALID_PARAMETER; + __leave; } else { #else } else { #endif DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); - return STATUS_INVALID_PARAMETER; + Status = STATUS_INVALID_PARAMETER; + __leave; } // @@ -207,7 +208,8 @@ NTSTATUS DokanOplockRequest(__in PIRP *pIrp) { DokanFCBFlagsIsSet(Fcb, DOKAN_DELETE_ON_CLOSE)) { DDbgPrint(" DokanOplockRequest STATUS_DELETE_PENDING\n"); - return STATUS_DELETE_PENDING; + Status = STATUS_DELETE_PENDING; + __leave; } // @@ -230,10 +232,6 @@ NTSTATUS DokanOplockRequest(__in PIRP *pIrp) { ExReleaseResourceLite(&(Fcb->Vcb->Resource)); } - if (AcquiredFcb) { - DokanFCBUnlock(Fcb); - } - DDbgPrint(" DokanOplockRequest return 0x%x\n", Status); } diff --git a/sys/init.c b/sys/init.c index 58bf75390..b4b9faa0d 100644 --- a/sys/init.c +++ b/sys/init.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -25,6 +25,10 @@ with this program. If not, see . #include #include +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, DokanDeleteDeviceObject) +#endif + static VOID FreeUnicodeString(PUNICODE_STRING UnicodeString) { if (UnicodeString != NULL) { ExFreePool(UnicodeString->Buffer); @@ -1112,190 +1116,219 @@ DokanCreateDiskDevice(__in PDRIVER_OBJECT DriverObject, __in ULONG MountId, __in ULONG DeviceCharacteristics, __in BOOLEAN MountGlobally, __in BOOLEAN UseMountManager, __out PDokanDCB *Dcb) { - WCHAR diskDeviceNameBuf[MAXIMUM_FILENAME_LENGTH]; - WCHAR symbolicLinkNameBuf[MAXIMUM_FILENAME_LENGTH]; - WCHAR mountPointBuf[MAXIMUM_FILENAME_LENGTH]; - PDEVICE_OBJECT diskDeviceObject; - PDokanDCB dcb; + WCHAR *diskDeviceNameBuf = NULL; + WCHAR *symbolicLinkNameBuf = NULL; + WCHAR *mountPointBuf = NULL; + PDEVICE_OBJECT diskDeviceObject = NULL; + PDokanDCB dcb = NULL; UNICODE_STRING diskDeviceName; - NTSTATUS status; BOOLEAN isNetworkFileSystem = (DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM); - DOKAN_CONTROL dokanControl; + PDOKAN_CONTROL dokanControl = NULL; + NTSTATUS status = STATUS_SUCCESS; + + __try { + + diskDeviceNameBuf = ExAllocatePool(MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR)); + symbolicLinkNameBuf = + ExAllocatePool(MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR)); + mountPointBuf = ExAllocatePool(MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR)); + dokanControl = ExAllocatePool(sizeof(*dokanControl)); + if (diskDeviceNameBuf == NULL || symbolicLinkNameBuf == NULL || + mountPointBuf == NULL || dokanControl == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + __leave; + } + + RtlZeroMemory(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR)); + RtlZeroMemory(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR)); + RtlZeroMemory(mountPointBuf, MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR)); + RtlZeroMemory(dokanControl, sizeof(*dokanControl)); - // make DeviceName and SymboliLink - if (isNetworkFileSystem) { + // make DeviceName and SymboliLink + if (isNetworkFileSystem) { #ifdef DOKAN_NET_PROVIDER - RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, - DOKAN_NET_DEVICE_NAME); - RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, - DOKAN_NET_SYMBOLIC_LINK_NAME); + RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, + DOKAN_NET_DEVICE_NAME); + RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, + DOKAN_NET_SYMBOLIC_LINK_NAME); #else - RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, - DOKAN_NET_DEVICE_NAME); - RtlStringCchCatW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); - RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, - DOKAN_NET_SYMBOLIC_LINK_NAME); - RtlStringCchCatW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); + RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, + DOKAN_NET_DEVICE_NAME); + RtlStringCchCatW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); + RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, + DOKAN_NET_SYMBOLIC_LINK_NAME); + RtlStringCchCatW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); #endif - } else { - RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, - DOKAN_DISK_DEVICE_NAME); - RtlStringCchCatW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); - RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, - DOKAN_SYMBOLIC_LINK_NAME); - RtlStringCchCatW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); - } - - RtlInitUnicodeString(&diskDeviceName, diskDeviceNameBuf); + } else { + RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, + DOKAN_DISK_DEVICE_NAME); + RtlStringCchCatW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); + RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, + DOKAN_SYMBOLIC_LINK_NAME); + RtlStringCchCatW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); + } - // - // Create DeviceObject for the Disk Device - // - if (!isNetworkFileSystem) { - status = - IoCreateDeviceSecure(DriverObject, // DriverObject - sizeof(DokanDCB), // DeviceExtensionSize - &diskDeviceName, // DeviceName - FILE_DEVICE_DISK, // DeviceType - DeviceCharacteristics, // DeviceCharacteristics - FALSE, // Not Exclusive - &sddl, // Default SDDL String - NULL, // Device Class GUID - &diskDeviceObject); // DeviceObject - } else { - status = IoCreateDevice(DriverObject, // DriverObject - sizeof(DokanDCB), // DeviceExtensionSize - NULL, // DeviceName - FILE_DEVICE_DISK, // DeviceType - DeviceCharacteristics, // DeviceCharacteristics - FALSE, // Not Exclusive - &diskDeviceObject); // DeviceObject - } + RtlInitUnicodeString(&diskDeviceName, diskDeviceNameBuf); + + // + // Create DeviceObject for the Disk Device + // + if (!isNetworkFileSystem) { + status = + IoCreateDeviceSecure(DriverObject, // DriverObject + sizeof(DokanDCB), // DeviceExtensionSize + &diskDeviceName, // DeviceName + FILE_DEVICE_DISK, // DeviceType + DeviceCharacteristics, // DeviceCharacteristics + FALSE, // Not Exclusive + &sddl, // Default SDDL String + NULL, // Device Class GUID + &diskDeviceObject); // DeviceObject + } else { + status = IoCreateDevice(DriverObject, // DriverObject + sizeof(DokanDCB), // DeviceExtensionSize + NULL, // DeviceName + FILE_DEVICE_DISK, // DeviceType + DeviceCharacteristics, // DeviceCharacteristics + FALSE, // Not Exclusive + &diskDeviceObject); // DeviceObject + } - if (!NT_SUCCESS(status)) { - DDbgPrint(" %s failed: 0x%x\n", - isNetworkFileSystem ? "IoCreateDevice(FILE_DEVICE_UNKNOWN)" - : "IoCreateDeviceSecure(FILE_DEVICE_DISK)", - status); - return status; - } + if (!NT_SUCCESS(status)) { + DDbgPrint(" %s failed: 0x%x\n", + isNetworkFileSystem ? "IoCreateDevice(FILE_DEVICE_UNKNOWN)" + : "IoCreateDeviceSecure(FILE_DEVICE_DISK)", + status); + __leave; + } - // - // Initialize the device extension. - // - dcb = diskDeviceObject->DeviceExtension; - *Dcb = dcb; - dcb->DeviceObject = diskDeviceObject; - dcb->Global = DokanGlobal; - - dcb->Identifier.Type = DCB; - dcb->Identifier.Size = sizeof(DokanDCB); - - dcb->MountId = MountId; - dcb->VolumeDeviceType = DeviceType; - dcb->DeviceType = FILE_DEVICE_DISK; - dcb->DeviceCharacteristics = DeviceCharacteristics; - KeInitializeEvent(&dcb->KillEvent, NotificationEvent, FALSE); - IoInitializeRemoveLock(&dcb->RemoveLock, TAG, 1, 100); - // - // Establish user-buffer access method. - // - diskDeviceObject->Flags |= DO_DIRECT_IO; - - // initialize Event and Event queue - DokanInitIrpList(&dcb->PendingIrp); - DokanInitIrpList(&dcb->PendingEvent); - DokanInitIrpList(&dcb->NotifyEvent); - - KeInitializeEvent(&dcb->ReleaseEvent, NotificationEvent, FALSE); - ExInitializeResourceLite(&dcb->Resource); - - dcb->CacheManagerNoOpCallbacks.AcquireForLazyWrite = &DokanNoOpAcquire; - dcb->CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = &DokanNoOpRelease; - dcb->CacheManagerNoOpCallbacks.AcquireForReadAhead = &DokanNoOpAcquire; - dcb->CacheManagerNoOpCallbacks.ReleaseFromReadAhead = &DokanNoOpRelease; - - dcb->MountGlobally = MountGlobally; - dcb->UseMountManager = UseMountManager; - if (wcscmp(MountPoint, L"") != 0) { - RtlStringCchCopyW(mountPointBuf, MAXIMUM_FILENAME_LENGTH, - L"\\DosDevices\\"); - if (wcslen(MountPoint) < 4) { - mountPointBuf[12] = towupper(MountPoint[0]); - mountPointBuf[13] = L':'; - mountPointBuf[14] = L'\0'; - if (isNetworkFileSystem) { + // + // Initialize the device extension. + // + dcb = diskDeviceObject->DeviceExtension; + *Dcb = dcb; + dcb->DeviceObject = diskDeviceObject; + dcb->Global = DokanGlobal; + + dcb->Identifier.Type = DCB; + dcb->Identifier.Size = sizeof(DokanDCB); + + dcb->MountId = MountId; + dcb->VolumeDeviceType = DeviceType; + dcb->DeviceType = FILE_DEVICE_DISK; + dcb->DeviceCharacteristics = DeviceCharacteristics; + KeInitializeEvent(&dcb->KillEvent, NotificationEvent, FALSE); + IoInitializeRemoveLock(&dcb->RemoveLock, TAG, 1, 100); + // + // Establish user-buffer access method. + // + diskDeviceObject->Flags |= DO_DIRECT_IO; + + // initialize Event and Event queue + DokanInitIrpList(&dcb->PendingIrp); + DokanInitIrpList(&dcb->PendingEvent); + DokanInitIrpList(&dcb->NotifyEvent); + + KeInitializeEvent(&dcb->ReleaseEvent, NotificationEvent, FALSE); + ExInitializeResourceLite(&dcb->Resource); + + dcb->CacheManagerNoOpCallbacks.AcquireForLazyWrite = &DokanNoOpAcquire; + dcb->CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = &DokanNoOpRelease; + dcb->CacheManagerNoOpCallbacks.AcquireForReadAhead = &DokanNoOpAcquire; + dcb->CacheManagerNoOpCallbacks.ReleaseFromReadAhead = &DokanNoOpRelease; + + dcb->MountGlobally = MountGlobally; + dcb->UseMountManager = UseMountManager; + if (wcscmp(MountPoint, L"") != 0) { + RtlStringCchCopyW(mountPointBuf, MAXIMUM_FILENAME_LENGTH, + L"\\DosDevices\\"); + if (wcslen(MountPoint) < 4) { + mountPointBuf[12] = towupper(MountPoint[0]); + mountPointBuf[13] = L':'; + mountPointBuf[14] = L'\0'; + if (isNetworkFileSystem) { + dcb->UseMountManager = FALSE; + } + } else { dcb->UseMountManager = FALSE; + RtlStringCchCatW(mountPointBuf, MAXIMUM_FILENAME_LENGTH, MountPoint); } } else { - dcb->UseMountManager = FALSE; - RtlStringCchCatW(mountPointBuf, MAXIMUM_FILENAME_LENGTH, MountPoint); + RtlStringCchCopyW(mountPointBuf, MAXIMUM_FILENAME_LENGTH, L""); } - } else { - RtlStringCchCopyW(mountPointBuf, MAXIMUM_FILENAME_LENGTH, L""); - } - - dcb->DiskDeviceName = DokanAllocateUnicodeString(diskDeviceNameBuf); - dcb->SymbolicLinkName = DokanAllocateUnicodeString(symbolicLinkNameBuf); - dcb->MountPoint = DokanAllocateUnicodeString(mountPointBuf); - if (UNCName != NULL) { - dcb->UNCName = DokanAllocateUnicodeString(UNCName); - } - - if (dcb->DiskDeviceName == NULL || dcb->SymbolicLinkName == NULL || - dcb->MountPoint == NULL || (dcb->UNCName == NULL && UNCName != NULL)) { - DDbgPrint(" Failed to allocate memory for device naming"); - FreeDcbNames(dcb); - ExDeleteResourceLite(&dcb->Resource); - IoDeleteDevice(diskDeviceObject); - return STATUS_INSUFFICIENT_RESOURCES; - } - DDbgPrint("DiskDeviceName: %wZ - SymbolicLinkName: %wZ - MountPoint: %wZ\n", - dcb->DiskDeviceName, dcb->SymbolicLinkName, dcb->MountPoint); - DDbgPrint(" IoCreateDevice DeviceType: %d\n", DeviceType); - - // - // Create a symbolic link for userapp to interact with the driver. - // - status = IoCreateSymbolicLink(dcb->SymbolicLinkName, dcb->DiskDeviceName); + dcb->DiskDeviceName = DokanAllocateUnicodeString(diskDeviceNameBuf); + dcb->SymbolicLinkName = DokanAllocateUnicodeString(symbolicLinkNameBuf); + dcb->MountPoint = DokanAllocateUnicodeString(mountPointBuf); + if (UNCName != NULL) { + dcb->UNCName = DokanAllocateUnicodeString(UNCName); + } - if (!NT_SUCCESS(status)) { - ExDeleteResourceLite(&dcb->Resource); - IoDeleteDevice(diskDeviceObject); - FreeDcbNames(dcb); - DDbgPrint(" IoCreateSymbolicLink returned 0x%x\n", status); - return status; - } - DDbgPrint("SymbolicLink: %wZ -> %wZ created\n", dcb->SymbolicLinkName, - dcb->DiskDeviceName); + if (dcb->DiskDeviceName == NULL || dcb->SymbolicLinkName == NULL || + dcb->MountPoint == NULL || (dcb->UNCName == NULL && UNCName != NULL)) { + DDbgPrint(" Failed to allocate memory for device naming"); + FreeDcbNames(dcb); + ExDeleteResourceLite(&dcb->Resource); + IoDeleteDevice(diskDeviceObject); + status = STATUS_INSUFFICIENT_RESOURCES; + __leave; + } + DDbgPrint("DiskDeviceName: %wZ - SymbolicLinkName: %wZ - MountPoint: %wZ\n", + dcb->DiskDeviceName, dcb->SymbolicLinkName, dcb->MountPoint); - // Mark devices as initialized - diskDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + DDbgPrint(" IoCreateDevice DeviceType: %d\n", DeviceType); - ObReferenceObject(diskDeviceObject); + // + // Create a symbolic link for userapp to interact with the driver. + // + status = IoCreateSymbolicLink(dcb->SymbolicLinkName, dcb->DiskDeviceName); - // DokanRegisterDeviceInterface(DriverObject, dcb->DeviceObject, dcb); - // DokanRegisterMountedDeviceInterface(dcb->DeviceObject, dcb); + if (!NT_SUCCESS(status)) { + ExDeleteResourceLite(&dcb->Resource); + IoDeleteDevice(diskDeviceObject); + FreeDcbNames(dcb); + DDbgPrint(" IoCreateSymbolicLink returned 0x%x\n", status); + __leave; + } + DDbgPrint("SymbolicLink: %wZ -> %wZ created\n", dcb->SymbolicLinkName, + dcb->DiskDeviceName); + + // Mark devices as initialized + diskDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + ObReferenceObject(diskDeviceObject); + + // DokanRegisterDeviceInterface(DriverObject, dcb->DeviceObject, dcb); + // DokanRegisterMountedDeviceInterface(dcb->DeviceObject, dcb); + + // Save to the global mounted list + RtlZeroMemory(dokanControl, sizeof(*dokanControl)); + RtlStringCchCopyW(dokanControl->DeviceName, + sizeof(dokanControl->DeviceName) / sizeof(WCHAR), + diskDeviceNameBuf); + RtlStringCchCopyW(dokanControl->MountPoint, + sizeof(dokanControl->MountPoint) / sizeof(WCHAR), + mountPointBuf); + if (UNCName != NULL) { + RtlStringCchCopyW(dokanControl->UNCName, + sizeof(dokanControl->UNCName) / sizeof(WCHAR), UNCName); + } + dokanControl->Type = DeviceType; - // Save to the global mounted list - RtlZeroMemory(&dokanControl, sizeof(dokanControl)); - RtlStringCchCopyW(dokanControl.DeviceName, - sizeof(dokanControl.DeviceName) / sizeof(WCHAR), - diskDeviceNameBuf); - RtlStringCchCopyW(dokanControl.MountPoint, - sizeof(dokanControl.MountPoint) / sizeof(WCHAR), - mountPointBuf); - if (UNCName != NULL) { - RtlStringCchCopyW(dokanControl.UNCName, - sizeof(dokanControl.UNCName) / sizeof(WCHAR), UNCName); + InsertMountEntry(DokanGlobal, dokanControl, FALSE); + } __finally { + if (diskDeviceNameBuf) + ExFreePool(diskDeviceNameBuf); + if (symbolicLinkNameBuf) + ExFreePool(symbolicLinkNameBuf); + if (mountPointBuf) + ExFreePool(mountPointBuf); + if (dokanControl) + ExFreePool(dokanControl); } - dokanControl.Type = DeviceType; - InsertMountEntry(DokanGlobal, &dokanControl, FALSE); - - return STATUS_SUCCESS; + return status; } VOID DokanDeleteDeviceObject(__in PDokanDCB Dcb) { diff --git a/sys/lock.c b/sys/lock.c index 52ec30798..91c35db03 100644 --- a/sys/lock.c +++ b/sys/lock.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -21,6 +21,10 @@ with this program. If not, see . #include "dokan.h" +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, DokanCommonLockControl) +#endif + NTSTATUS DokanCommonLockControl(__in PIRP Irp) { NTSTATUS Status = STATUS_SUCCESS; @@ -55,24 +59,22 @@ DokanCommonLockControl(__in PIRP Irp) { // as an invalid parameter // if (DokanFCBFlagsIsSet(Fcb, DOKAN_FILE_DIRECTORY)) { - DDbgPrint(" DokanCommonLockControl -> STATUS_INVALID_PARAMETER\n", 0); + DDbgPrint(" DokanCommonLockControl -> STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } - DokanFCBLockRW(Fcb); - try { - // // We check whether we can proceed // based on the state of the file oplocks. // #if (NTDDI_VERSION >= NTDDI_WIN8) - if (((IRP_MN_LOCK == irpSp->MinorFunction) && - ((ULONGLONG)irpSp->Parameters.LockControl.ByteOffset.QuadPart < - (ULONGLONG)Fcb->AdvancedFCBHeader.AllocationSize.QuadPart)) || - ((IRP_MN_LOCK != irpSp->MinorFunction) && - FsRtlAreThereWaitingFileLocks(&Fcb->FileLock))) { + // Fcb's AllocationSize is constant after creation. + if (((IRP_MN_LOCK == irpSp->MinorFunction) && + ((ULONGLONG)irpSp->Parameters.LockControl.ByteOffset.QuadPart < + (ULONGLONG)Fcb->AdvancedFCBHeader.AllocationSize.QuadPart)) || + ((IRP_MN_LOCK != irpSp->MinorFunction) && + FsRtlAreThereWaitingFileLocks(&Fcb->FileLock))) { // // Check whether we can proceed based on the state of file oplocks if doing @@ -85,28 +87,24 @@ DokanCommonLockControl(__in PIRP Irp) { // within AllocationSize! // #endif - // Dokan DokanOplockComplete sends the operation to user mode, which isn't - // what we want to do - // so now wait for the oplock to be broken (pass in NULL for the callback) - Status = - FsRtlCheckOplock(DokanGetFcbOplock(Fcb), Irp, NULL /* EventContext */, - NULL /*DokanOplockComplete*/, NULL); + // Dokan DokanOplockComplete sends the operation to user mode, which isn't + // what we want to do + // so now wait for the oplock to be broken (pass in NULL for the callback) + // This may block and enter wait state. + Status = + FsRtlCheckOplock(DokanGetFcbOplock(Fcb), Irp, NULL /* EventContext */, + NULL /*DokanOplockComplete*/, NULL); #if (NTDDI_VERSION >= NTDDI_WIN8) - } + } #endif // If we were waiting for the callback, then STATUS_PENDING would be ok too - if (Status != STATUS_SUCCESS) { - __leave; - } - + if (Status == STATUS_SUCCESS) { // // Now call the FsRtl routine to do the actual processing of the // Lock request // Status = FsRtlProcessFileLock(&Fcb->FileLock, Irp, NULL); - } finally { - DokanFCBUnlock(Fcb); } DDbgPrint("<== DokanCommonLockControl\n"); diff --git a/sys/notification.c b/sys/notification.c index 5eff6f8be..7de996ef6 100644 --- a/sys/notification.c +++ b/sys/notification.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/sys/pnp.c b/sys/pnp.c index 058b457eb..55d72862c 100644 --- a/sys/pnp.c +++ b/sys/pnp.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/sys/public.h b/sys/public.h index 2e255a663..ea7277156 100644 --- a/sys/public.h +++ b/sys/public.h @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io diff --git a/sys/read.c b/sys/read.c index 02c79ef82..1f03a54eb 100644 --- a/sys/read.c +++ b/sys/read.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -222,6 +222,7 @@ Return Value: // the file oplocks. // if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) { + // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); @@ -242,6 +243,7 @@ Return Value: // We have to check for read access according to the current // state of the file locks, and set FileSize from the Fcb. // + // FsRtlCheckLockForReadAccess does not block. if (!FsRtlCheckLockForReadAccess(&fcb->FileLock, Irp)) { status = STATUS_FILE_LOCK_CONFLICT; __leave; diff --git a/sys/security.c b/sys/security.c index d7c0bb15f..0f992954c 100644 --- a/sys/security.c +++ b/sys/security.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -125,7 +125,7 @@ DokanDispatchQuerySecurity(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, flags); } __finally { - if(fcb) + if (fcb) DokanFCBUnlock(fcb); DokanCompleteIrpRequest(Irp, status, info); @@ -161,10 +161,10 @@ VOID DokanCompleteQuerySecurity(__in PIRP_ENTRY IrpEntry, if (EventInfo->Status == STATUS_SUCCESS && EventInfo->BufferLength <= bufferLength && buffer != NULL) { if (!RtlValidRelativeSecurityDescriptor( - EventInfo->Buffer, - EventInfo->BufferLength, - irpSp->Parameters.QuerySecurity.SecurityInformation)) { + EventInfo->Buffer, EventInfo->BufferLength, + irpSp->Parameters.QuerySecurity.SecurityInformation)) { // No valid security descriptor to return. + DDbgPrint(" Security Descriptor is not valid.\n"); info = 0; status = STATUS_INVALID_PARAMETER; } else { @@ -278,8 +278,10 @@ DokanDispatchSetSecurity(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { // Assumes the parameter is self relative SD. securityDescLength = RtlLengthSecurityDescriptor(securityDescriptor); + // PSECURITY_DESCRIPTOR has to be aligned to a 4-byte boundary for use with win32 functions. + // So we add 3 bytes here, to make sure we have extra room to align BufferOffset. eventLength = - sizeof(EVENT_CONTEXT) + securityDescLength + fcb->FileName.Length; + sizeof(EVENT_CONTEXT) + securityDescLength + fcb->FileName.Length + 3; if (EVENT_CONTEXT_MAX_SIZE < eventLength) { // TODO: Handle this case like DispatchWrite. @@ -298,9 +300,12 @@ DokanDispatchSetSecurity(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { eventContext->Context = ccb->UserContext; eventContext->Operation.SetSecurity.SecurityInformation = *securityInfo; eventContext->Operation.SetSecurity.BufferLength = securityDescLength; + + // Align BufferOffset by adding 3, then zeroing the last 2 bits. eventContext->Operation.SetSecurity.BufferOffset = - FIELD_OFFSET(EVENT_CONTEXT, Operation.SetSecurity.FileName[0]) + - fcb->FileName.Length + sizeof(WCHAR); + (FIELD_OFFSET(EVENT_CONTEXT, Operation.SetSecurity.FileName[0]) + + fcb->FileName.Length + sizeof(WCHAR) + 3) & ~0x03; + RtlCopyMemory((PCHAR)eventContext + eventContext->Operation.SetSecurity.BufferOffset, securityDescriptor, securityDescLength); @@ -312,7 +317,7 @@ DokanDispatchSetSecurity(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { - if(fcb) + if (fcb) DokanFCBUnlock(fcb); DokanCompleteIrpRequest(Irp, status, info); diff --git a/sys/timeout.c b/sys/timeout.c index ea32ddd51..76d19fe75 100644 --- a/sys/timeout.c +++ b/sys/timeout.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -198,7 +198,7 @@ ReleaseTimeoutPendingIrp(__in PDokanDCB Dcb) { } NTSTATUS -DokanResetPendingIrpTimeout(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { +DokanResetPendingIrpTimeout(__in PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; diff --git a/sys/volume.c b/sys/volume.c index 5be747afc..ca496d9bf 100644 --- a/sys/volume.c +++ b/sys/volume.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -41,7 +41,8 @@ DokanDispatchQueryVolumeInformation(__in PDEVICE_OBJECT DeviceObject, vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { - return STATUS_INVALID_PARAMETER; + status = STATUS_INVALID_PARAMETER; + __leave; } dcb = vcb->Dcb; @@ -369,7 +370,8 @@ DokanDispatchSetVolumeInformation(__in PDEVICE_OBJECT DeviceObject, vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { - return STATUS_INVALID_PARAMETER; + status = STATUS_INVALID_PARAMETER; + __leave; } dcb = vcb->Dcb; @@ -384,8 +386,10 @@ DokanDispatchSetVolumeInformation(__in PDEVICE_OBJECT DeviceObject, DDbgPrint(" FileFsLabelInformation\n"); if (sizeof(FILE_FS_LABEL_INFORMATION) > - irpSp->Parameters.SetVolume.Length) - return STATUS_INVALID_PARAMETER; + irpSp->Parameters.SetVolume.Length) { + status = STATUS_INVALID_PARAMETER; + __leave; + } PFILE_FS_LABEL_INFORMATION Info = (PFILE_FS_LABEL_INFORMATION)buffer; ExAcquireResourceExclusiveLite(&dcb->Resource, TRUE); @@ -393,6 +397,12 @@ DokanDispatchSetVolumeInformation(__in PDEVICE_OBJECT DeviceObject, ExFreePool(dcb->VolumeLabel); dcb->VolumeLabel = ExAllocatePool(Info->VolumeLabelLength + sizeof(WCHAR)); + if (dcb->VolumeLabel == NULL) { + DDbgPrint(" can't allocate VolumeLabel\n"); + status = STATUS_INSUFFICIENT_RESOURCES; + __leave; + } + RtlCopyMemory(dcb->VolumeLabel, Info->VolumeLabel, Info->VolumeLabelLength); dcb->VolumeLabel[Info->VolumeLabelLength / sizeof(WCHAR)] = '\0'; @@ -401,6 +411,48 @@ DokanDispatchSetVolumeInformation(__in PDEVICE_OBJECT DeviceObject, status = STATUS_SUCCESS; break; + case FileFsVolumeInformation: + DDbgPrint(" FileFsVolumeInformation\n"); + break; + case FileFsSizeInformation: + DDbgPrint(" FileFsSizeInformation\n"); + break; + case FileFsDeviceInformation: + DDbgPrint(" FileFsDeviceInformation\n"); + break; + case FileFsAttributeInformation: + DDbgPrint(" FileFsAttributeInformation\n"); + break; + case FileFsControlInformation: + DDbgPrint(" FileFsControlInformation\n"); + break; + case FileFsFullSizeInformation: + DDbgPrint(" FileFsFullSizeInformation\n"); + break; + case FileFsObjectIdInformation: + DDbgPrint(" FileFsObjectIdInformation\n"); + break; + case FileFsDriverPathInformation: + DDbgPrint(" FileFsDriverPathInformation\n"); + break; + case FileFsVolumeFlagsInformation: + DDbgPrint(" FileFsVolumeFlagsInformation\n"); + break; + case FileFsSectorSizeInformation: + DDbgPrint(" FileFsSectorSizeInformation\n"); + break; + case FileFsDataCopyInformation: + DDbgPrint(" FileFsDataCopyInformation\n"); + break; + case FileFsMetadataSizeInformation: + DDbgPrint(" FileFsMetadataSizeInformation\n"); + break; + case FileFsMaximumInformation: + DDbgPrint(" FileFsMaximumInformation\n"); + break; + default: + DDbgPrint(" unknown FsInformationClass %d\n", FsInformationClass); + break; } } __finally { diff --git a/sys/write.c b/sys/write.c index 558a157e9..834d98080 100644 --- a/sys/write.c +++ b/sys/write.c @@ -1,7 +1,7 @@ /* Dokan : user-mode file system library for Windows - Copyright (C) 2015 - 2016 Adrien J. and Maxime C. + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -229,6 +229,7 @@ DokanDispatchWrite(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { // We now check whether we can proceed based on the state of // the file oplocks. // + // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) { status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); @@ -285,6 +286,7 @@ DokanDispatchWrite(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { // We now check whether we can proceed based on the state of // the file oplocks. // + // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) { status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, requestContext, DokanOplockComplete, DokanPrePostIrp);