VirtualBox

Changeset 82834 in vbox for trunk/src/VBox/Runtime/r3/win


Ignore:
Timestamp:
Jan 22, 2020 4:25:19 PM (5 years ago)
Author:
vboxsync
Message:

IPRT/win: Reimplemented RTFileSetSize to support truncating files opened with RTFILE_O_APPEND to assist shared folders with POSIX O_APPEND semantics on windows hosts. ticketref:19003

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/win/fileio-win.cpp

    r80585 r82834  
    4444#include <iprt/ldr.h>
    4545#include <iprt/log.h>
     46#include <iprt/utf16.h>
    4647#include "internal/file.h"
    4748#include "internal/fs.h"
     
    753754
    754755
     756#if 0
     757/**
     758 * If @a hFile is opened in append mode, try return a handle with
     759 * FILE_WRITE_DATA permissions.
     760 *
     761 * @returns Duplicate handle.
     762 * @param   hFile               The NT handle to check & duplicate.
     763 *
     764 * @todo    It would be much easier to implement this by not dropping the
     765 *          FILE_WRITE_DATA access and instead have the RTFileWrite APIs
     766 *          enforce the appending.  That will require keeping additional
     767 *          information along side the handle (instance structure).  However, on
     768 *          windows you can grant append permissions w/o giving people access to
     769 *          overwrite existing data, so the RTFileOpenEx code would have to deal
     770 *          with those kinds of STATUS_ACCESS_DENIED too then.
     771 */
     772static HANDLE rtFileReOpenAppendOnlyWithFullWriteAccess(HANDLE hFile)
     773{
     774    OBJECT_BASIC_INFORMATION BasicInfo = {0};
     775    ULONG                    cbActual  = 0;
     776    NTSTATUS rcNt = NtQueryObject(hFile, ObjectBasicInformation, &BasicInfo, sizeof(BasicInfo), &cbActual);
     777    if (NT_SUCCESS(rcNt))
     778    {
     779        if ((BasicInfo.GrantedAccess & (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
     780        {
     781            /*
     782             * We cannot use NtDuplicateObject here as it is not possible to
     783             * upgrade the access on files, only making it more strict.  So,
     784             * query the path and re-open it (we could do by file/object/whatever
     785             * id too, but that may not work with all file systems).
     786             */
     787            for (uint32_t i = 0; i < 16; i++)
     788            {
     789                UNICODE_STRING  NtName;
     790                int rc = RTNtPathFromHandle(&NtName, hFile, 0);
     791                AssertRCReturn(rc, INVALID_HANDLE_VALUE);
     792
     793                HANDLE              hDupFile = RTNT_INVALID_HANDLE_VALUE;
     794                IO_STATUS_BLOCK     Ios      = RTNT_IO_STATUS_BLOCK_INITIALIZER;
     795                OBJECT_ATTRIBUTES   ObjAttr;
     796                InitializeObjectAttributes(&ObjAttr, &NtName, BasicInfo.Attributes & ~OBJ_INHERIT, NULL, NULL);
     797
     798                NTSTATUS rcNt = NtCreateFile(&hDupFile,
     799                                             BasicInfo.GrantedAccess | FILE_WRITE_DATA,
     800                                             &ObjAttr,
     801                                             &Ios,
     802                                             NULL /* AllocationSize*/,
     803                                             FILE_ATTRIBUTE_NORMAL,
     804                                             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     805                                             FILE_OPEN,
     806                                             FILE_OPEN_FOR_BACKUP_INTENT,
     807                                             NULL /*EaBuffer*/,
     808                                             0 /*EaLength*/);
     809                RTUtf16Free(NtName.Buffer);
     810                if (NT_SUCCESS(rcNt))
     811                {
     812                    /** @todo Check that the two handles are for the same file object. */
     813
     814                    return hDupFile;
     815                }
     816            }
     817        }
     818    }
     819    return INVALID_HANDLE_VALUE;
     820}
     821#endif
     822
     823
    755824RTR3DECL(int) RTFileSetSize(RTFILE hFile, uint64_t cbSize)
    756825{
     826#if 0
     827    HANDLE hNtFile  = (HANDLE)RTFileToNative(hFile);
     828    HANDLE hDupFile = INVALID_HANDLE_VALUE;
     829    union
     830    {
     831        FILE_END_OF_FILE_INFORMATION Eof;
     832        FILE_ALLOCATION_INFORMATION  Alloc;
     833    } uInfo;
     834
     835    /*
     836     * Change the EOF marker.  We may have to
     837     */
     838    IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
     839    uInfo.Eof.EndOfFile.QuadPart = cbSize;
     840    NTSTATUS rcNt = NtSetInformationFile(hNtFile, &Ios, &uInfo.Eof, sizeof(uInfo.Eof), FileEndOfFileInformation);
     841    if (rcNt == STATUS_ACCESS_DENIED)
     842    {
     843        hDupFile = rtFileReOpenAppendOnlyWithFullWriteAccess(hNtFile);
     844        if (hDupFile != INVALID_HANDLE_VALUE)
     845        {
     846            hNtFile = hDupFile;
     847            uInfo.Eof.EndOfFile.QuadPart = cbSize;
     848            rcNt = NtSetInformationFile(hNtFile, &Ios, &uInfo.Eof, sizeof(uInfo.Eof), FileEndOfFileInformation);
     849        }
     850    }
     851
     852    if (NT_SUCCESS(rcNt))
     853    {
     854        /*
     855         * Change the allocation.
     856         */
     857        uInfo.Alloc.AllocationSize.QuadPart = cbSize;
     858        rcNt = NtSetInformationFile(hNtFile, &Ios, &uInfo.Eof, sizeof(uInfo.Alloc), FileAllocationInformation);
     859    }
     860
     861    /*
     862     * Close the temporary file handle:
     863     */
     864    if (hDupFile != INVALID_HANDLE_VALUE)
     865        NtClose(hDupFile);
     866
     867    if (RT_SUCCESS(rcNt))
     868        return VINF_SUCCESS;
     869    return RTErrConvertFromNtStatus(rcNt);
     870
     871#else /* this version of the code will fail to truncate files when RTFILE_O_APPEND is in effect, which isn't what we want... */
    757872    /*
    758873     * Get current file pointer.
     
    795910
    796911    return RTErrConvertFromWin32(rc);
     912#endif
    797913}
    798914
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette