VirtualBox

Changeset 77209 in vbox


Ignore:
Timestamp:
Feb 7, 2019 11:46:50 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
128712
Message:

IPRT: Split RTFileWriteAt & RTFileReadAt out of fileio.cpp and into fileio-at-generic.cpp, and RTFileSgWriteAt & RTFileSgReadAt into fileio-sg-generic.cpp. bugref:9172

Location:
trunk/src/VBox/Runtime
Files:
2 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/Makefile.kmk

    r76553 r77209  
    815815        generic/RTDirExists-generic.cpp \
    816816        generic/RTDirSetTimes-generic.cpp \
     817        generic/fileio-at-generic.cpp \
     818        generic/fileio-sg-generic.cpp \
    817819        generic/RTFileExists-generic.cpp \
    818820        generic/RTFileSetAllocationSize-generic.cpp \
     
    906908        generic/RTDirQueryInfo-generic.cpp \
    907909        generic/RTDirSetTimes-generic.cpp \
     910        generic/fileio-at-generic.cpp \
     911        generic/fileio-sg-generic.cpp \
    908912        generic/RTFileMove-generic.cpp \
    909913        generic/RTLogWriteDebugger-generic.cpp \
     
    10041008        generic/RTDirQueryInfo-generic.cpp \
    10051009        generic/RTDirSetTimes-generic.cpp \
     1010        generic/fileio-at-generic.cpp \
     1011        generic/fileio-sg-generic.cpp \
    10061012        generic/RTFileMove-generic.cpp \
    10071013        generic/RTFileSetAllocationSize-generic.cpp \
     
    10851091        generic/RTDirQueryInfo-generic.cpp \
    10861092        generic/RTDirSetTimes-generic.cpp \
     1093        generic/fileio-at-generic.cpp \
     1094        generic/fileio-sg-generic.cpp \
    10871095        generic/RTFileMove-generic.cpp \
    10881096        generic/RTFileSetAllocationSize-generic.cpp \
     
    11671175        generic/RTDirQueryInfo-generic.cpp \
    11681176        generic/RTDirSetTimes-generic.cpp \
     1177        generic/fileio-at-generic.cpp \
     1178        generic/fileio-sg-generic.cpp \
    11691179        generic/RTFileMove-generic.cpp \
    11701180        generic/RTFileSetAllocationSize-generic.cpp \
     
    12471257        generic/RTDirQueryInfo-generic.cpp \
    12481258        generic/RTDirSetTimes-generic.cpp \
     1259        generic/fileio-at-generic.cpp \
     1260        generic/fileio-sg-generic.cpp \
    12491261        generic/RTFileMove-generic.cpp \
    12501262        generic/RTLogWriteDebugger-generic.cpp \
     
    13251337        generic/RTDirQueryInfo-generic.cpp \
    13261338        generic/RTDirSetTimes-generic.cpp \
     1339        generic/fileio-at-generic.cpp \
     1340        generic/fileio-sg-generic.cpp \
    13271341        generic/RTFileMove-generic.cpp \
    13281342        generic/RTLogWriteDebugger-generic.cpp \
     
    14141428        generic/RTDirQueryInfo-generic.cpp \
    14151429        generic/RTDirSetTimes-generic.cpp \
     1430        generic/fileio-at-generic.cpp \
     1431        generic/fileio-sg-generic.cpp \
    14161432        generic/RTFileMove-generic.cpp \
    14171433        generic/RTFileSetAllocationSize-generic.cpp \
     
    18031819        generic/cdrom-generic.cpp \
    18041820        generic/RTFileMove-generic.cpp \
     1821        generic/fileio-at-generic.cpp \
    18051822        generic/RTPathGetCurrentOnDrive-generic.cpp \
    18061823        generic/RTProcDaemonize-generic.cpp \
     
    18411858        generic/RTDirExists-generic.cpp \
    18421859        generic/RTDirSetTimes-generic.cpp \
     1860        generic/fileio-at-generic.cpp \
    18431861        generic/RTFileExists-generic.cpp \
    18441862        generic/RTFileSetAllocationSize-generic.cpp \
     
    19081926        generic/RTDirQueryInfo-generic.cpp \
    19091927        generic/RTDirSetTimes-generic.cpp \
     1928        generic/fileio-at-generic.cpp \
    19101929        generic/RTFileMove-generic.cpp \
    19111930        generic/RTFileSetAllocationSize-generic.cpp \
  • trunk/src/VBox/Runtime/generic/fileio-at-generic.cpp

    r77183 r77209  
    11/* $Id$ */
    22/** @file
    3  * IPRT - File I/O.
     3 * IPRT - File I/O, RTFileReadAt and RTFileWriteAt, generic.
    44 */
    55
     
    3232#include <iprt/file.h>
    3333
    34 #include <iprt/mem.h>
    35 #include <iprt/assert.h>
    36 #include <iprt/alloca.h>
    37 #include <iprt/string.h>
    38 #include <iprt/err.h>
    39 #include "internal/file.h"
    40 
    41 
    42 /*********************************************************************************************************************************
    43 *   Global Variables                                                                                                             *
    44 *********************************************************************************************************************************/
    45 /** Set of forced set open flags for files opened read-only. */
    46 static unsigned g_fOpenReadSet = 0;
    47 
    48 /** Set of forced cleared open flags for files opened read-only. */
    49 static unsigned g_fOpenReadMask = 0;
    50 
    51 /** Set of forced set open flags for files opened write-only. */
    52 static unsigned g_fOpenWriteSet = 0;
    53 
    54 /** Set of forced cleared open flags for files opened write-only. */
    55 static unsigned g_fOpenWriteMask = 0;
    56 
    57 /** Set of forced set open flags for files opened read-write. */
    58 static unsigned g_fOpenReadWriteSet = 0;
    59 
    60 /** Set of forced cleared open flags for files opened read-write. */
    61 static unsigned g_fOpenReadWriteMask = 0;
    62 
    63 
    64 /**
    65  * Force the use of open flags for all files opened after the setting is
    66  * changed. The caller is responsible for not causing races with RTFileOpen().
    67  *
    68  * @returns iprt status code.
    69  * @param   fOpenForAccess  Access mode to which the set/mask settings apply.
    70  * @param   fSet            Open flags to be forced set.
    71  * @param   fMask           Open flags to be masked out.
    72  */
    73 RTR3DECL(int)  RTFileSetForceFlags(unsigned fOpenForAccess, unsigned fSet, unsigned fMask)
    74 {
    75     /*
    76      * For now allow only RTFILE_O_WRITE_THROUGH. The other flags either
    77      * make no sense in this context or are not useful to apply to all files.
    78      */
    79     if ((fSet | fMask) & ~RTFILE_O_WRITE_THROUGH)
    80         return VERR_INVALID_PARAMETER;
    81     switch (fOpenForAccess)
    82     {
    83         case RTFILE_O_READ:
    84             g_fOpenReadSet = fSet;
    85             g_fOpenReadMask = fMask;
    86             break;
    87         case RTFILE_O_WRITE:
    88             g_fOpenWriteSet = fSet;
    89             g_fOpenWriteMask = fMask;
    90             break;
    91         case RTFILE_O_READWRITE:
    92             g_fOpenReadWriteSet = fSet;
    93             g_fOpenReadWriteMask = fMask;
    94             break;
    95         default:
    96             AssertMsgFailed(("Invalid access mode %d\n", fOpenForAccess));
    97             return VERR_INVALID_PARAMETER;
    98     }
    99     return VINF_SUCCESS;
    100 }
    101 
    102 
    103 /**
    104  * Adjusts and validates the flags.
    105  *
    106  * The adjustments are made according to the wishes specified using the RTFileSetForceFlags API.
    107  *
    108  * @returns IPRT status code.
    109  * @param   pfOpen      Pointer to the user specified flags on input.
    110  *                      Updated on successful return.
    111  * @internal
    112  */
    113 int rtFileRecalcAndValidateFlags(uint64_t *pfOpen)
    114 {
    115     /*
    116      * Recalc.
    117      */
    118     uint32_t fOpen = *pfOpen;
    119     switch (fOpen & RTFILE_O_ACCESS_MASK)
    120     {
    121         case RTFILE_O_READ:
    122             fOpen |= g_fOpenReadSet;
    123             fOpen &= ~g_fOpenReadMask;
    124             break;
    125         case RTFILE_O_WRITE:
    126             fOpen |= g_fOpenWriteSet;
    127             fOpen &= ~g_fOpenWriteMask;
    128             break;
    129         case RTFILE_O_READWRITE:
    130             fOpen |= g_fOpenReadWriteSet;
    131             fOpen &= ~g_fOpenReadWriteMask;
    132             break;
    133 #ifdef RT_OS_WINDOWS
    134         case RTFILE_O_ATTR_ONLY:
    135             if (fOpen & RTFILE_O_ACCESS_ATTR_MASK)
    136                 break;
    137 #endif
    138         default:
    139             AssertMsgFailed(("Invalid access mode value, fOpen=%#llx\n", fOpen));
    140             return VERR_INVALID_PARAMETER;
    141     }
    142 
    143     /*
    144      * Validate                                                                                                                                       .
    145      */
    146 #ifdef RT_OS_WINDOWS
    147     AssertMsgReturn((fOpen & RTFILE_O_ACCESS_MASK) || (fOpen & RTFILE_O_ACCESS_ATTR_MASK),
    148                     ("Missing RTFILE_O_READ/WRITE/ACCESS_ATTR: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    149 #else
    150     AssertMsgReturn(fOpen & RTFILE_O_ACCESS_MASK, ("Missing RTFILE_O_READ/WRITE: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    151 #endif
    152 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    153     AssertMsgReturn(!(fOpen & (~(uint64_t)RTFILE_O_VALID_MASK | RTFILE_O_NON_BLOCK)), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    154 #else
    155     AssertMsgReturn(!(fOpen & ~(uint64_t)RTFILE_O_VALID_MASK), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    156 #endif
    157     AssertMsgReturn((fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_WRITE)) != RTFILE_O_TRUNCATE, ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    158 
    159     switch (fOpen & RTFILE_O_ACTION_MASK)
    160     {
    161         case 0: /* temporarily */
    162             AssertMsgFailed(("Missing RTFILE_O_OPEN/CREATE*! (continuable assertion)\n"));
    163             fOpen |= RTFILE_O_OPEN;
    164             break;
    165         case RTFILE_O_OPEN:
    166             AssertMsgReturn(!(RTFILE_O_NOT_CONTENT_INDEXED & fOpen), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    167         case RTFILE_O_OPEN_CREATE:
    168         case RTFILE_O_CREATE:
    169         case RTFILE_O_CREATE_REPLACE:
    170             break;
    171         default:
    172             AssertMsgFailed(("Invalid action value: fOpen=%#llx\n", fOpen));
    173             return VERR_INVALID_PARAMETER;
    174     }
    175 
    176     switch (fOpen & RTFILE_O_DENY_MASK)
    177     {
    178         case 0: /* temporarily */
    179             AssertMsgFailed(("Missing RTFILE_O_DENY_*! (continuable assertion)\n"));
    180             fOpen |= RTFILE_O_DENY_NONE;
    181             break;
    182         case RTFILE_O_DENY_NONE:
    183         case RTFILE_O_DENY_READ:
    184         case RTFILE_O_DENY_WRITE:
    185         case RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
    186         case RTFILE_O_DENY_NOT_DELETE:
    187         case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ:
    188         case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE:
    189         case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
    190             break;
    191         default:
    192             AssertMsgFailed(("Invalid deny value: fOpen=%#llx\n", fOpen));
    193             return VERR_INVALID_PARAMETER;
    194     }
    195 
    196     /* done */
    197     *pfOpen = fOpen;
    198     return VINF_SUCCESS;
    199 }
     34#include <iprt/errcore.h>
    20035
    20136
     
    21348 *                      If NULL an error will be returned for a partial read.
    21449 */
    215 RTR3DECL(int)  RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
     50RTDECL(int)  RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
    21651{
    21752    int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
    21853    if (RT_SUCCESS(rc))
    21954        rc = RTFileRead(File, pvBuf, cbToRead, pcbRead);
    220     return rc;
    221 }
    222 
    223 
    224 /**
    225  * Read bytes from a file at a given offset into a S/G buffer.
    226  * This function may modify the file position.
    227  *
    228  * @returns iprt status code.
    229  * @param   hFile       Handle to the file.
    230  * @param   off         Where to read.
    231  * @param   pSgBuf      Pointer to the S/G buffer to read into.
    232  * @param   cbToRead    How much to read.
    233  * @param   pcbRead     How much we actually read.
    234  *                      If NULL an error will be returned for a partial read.
    235  */
    236 RTR3DECL(int)  RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)
    237 {
    238     int rc = VINF_SUCCESS;
    239     size_t cbRead = 0;
    240 
    241     while (cbToRead)
    242     {
    243         size_t cbThisRead = 0;
    244         size_t cbBuf = cbToRead;
    245         void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
    246 
    247         rc = RTFileReadAt(hFile, off, pvBuf, cbBuf, pcbRead ? &cbThisRead : NULL);
    248         if (RT_SUCCESS(rc))
    249             cbRead += cbThisRead;
    250 
    251         if (   RT_FAILURE(rc)
    252             || (   cbThisRead < cbBuf
    253                 && pcbRead))
    254             break;
    255 
    256         cbToRead -= cbBuf;
    257         off += cbBuf;
    258     }
    259 
    260     if (pcbRead)
    261         *pcbRead = cbRead;
    262 
    26355    return rc;
    26456}
     
    27769 *                      If NULL an error will be returned for a partial write.
    27870 */
    279 RTR3DECL(int)  RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
     71RTDECL(int)  RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
    28072{
    28173    int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
     
    28577}
    28678
    287 
    288 /**
    289  * Write bytes from a S/G buffer to a file at a given offset.
    290  * This function may modify the file position.
    291  *
    292  * @returns iprt status code.
    293  * @param   hFile       Handle to the file.
    294  * @param   off         Where to write.
    295  * @param   pSgBuf      What to write.
    296  * @param   cbToWrite   How much to write.
    297  * @param   pcbWritten  How much we actually wrote.
    298  *                      If NULL an error will be returned for a partial write.
    299  */
    300 RTR3DECL(int)  RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)
    301 {
    302     int rc = VINF_SUCCESS;
    303     size_t cbWritten = 0;
    304 
    305     while (cbToWrite)
    306     {
    307         size_t cbThisWritten = 0;
    308         size_t cbBuf = cbToWrite;
    309         void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
    310 
    311         rc = RTFileWriteAt(hFile, off, pvBuf, cbBuf, pcbWritten ? &cbThisWritten : NULL);
    312         if (RT_SUCCESS(rc))
    313             cbWritten += cbThisWritten;
    314 
    315         if (   RT_FAILURE(rc)
    316             || (   cbThisWritten < cbBuf
    317                 && pcbWritten))
    318             break;
    319 
    320         cbToWrite -= cbBuf;
    321         off += cbBuf;
    322     }
    323 
    324     if (pcbWritten)
    325         *pcbWritten = cbWritten;
    326 
    327     return rc;
    328 }
    329 
    330 
    331 /**
    332  * Gets the current file position.
    333  *
    334  * @returns File offset.
    335  * @returns ~0UUL on failure.
    336  * @param   File        File handle.
    337  */
    338 RTR3DECL(uint64_t)  RTFileTell(RTFILE File)
    339 {
    340     /*
    341      * Call the seek api to query the stuff.
    342      */
    343     uint64_t off = 0;
    344     int rc = RTFileSeek(File, 0, RTFILE_SEEK_CURRENT, &off);
    345     if (RT_SUCCESS(rc))
    346         return off;
    347     AssertMsgFailed(("RTFileSeek(%d) -> %d\n", File, rc));
    348     return ~0ULL;
    349 }
    350 
    351 
    352 /**
    353  * Determine the maximum file size.
    354  *
    355  * @returns The max size of the file.
    356  *          -1 on failure, the file position is undefined.
    357  * @param   File        Handle to the file.
    358  * @see     RTFileGetMaxSizeEx.
    359  */
    360 RTR3DECL(RTFOFF) RTFileGetMaxSize(RTFILE File)
    361 {
    362     RTFOFF cbMax;
    363     int rc = RTFileGetMaxSizeEx(File, &cbMax);
    364     return RT_SUCCESS(rc) ? cbMax : -1;
    365 }
    366 
    367 
    368 RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst)
    369 {
    370     return RTFileCopyByHandlesEx(FileSrc, FileDst, NULL, NULL);
    371 }
    372 
    373 
    374 RTDECL(int) RTFileCopyEx(const char *pszSrc, const char *pszDst, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
    375 {
    376     /*
    377      * Validate input.
    378      */
    379     AssertMsgReturn(VALID_PTR(pszSrc), ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);
    380     AssertMsgReturn(*pszSrc, ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);
    381     AssertMsgReturn(VALID_PTR(pszDst), ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);
    382     AssertMsgReturn(*pszDst, ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);
    383     AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
    384     AssertMsgReturn(!(fFlags & ~RTFILECOPY_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
    385 
    386     /*
    387      * Open the files.
    388      */
    389     RTFILE FileSrc;
    390     int rc = RTFileOpen(&FileSrc, pszSrc,
    391                         RTFILE_O_READ | RTFILE_O_OPEN
    392                         | (fFlags & RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
    393     if (RT_SUCCESS(rc))
    394     {
    395         RTFILE FileDst;
    396         rc = RTFileOpen(&FileDst, pszDst,
    397                         RTFILE_O_WRITE | RTFILE_O_CREATE
    398                         | (fFlags & RTFILECOPY_FLAGS_NO_DST_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
    399         if (RT_SUCCESS(rc))
    400         {
    401             /*
    402              * Call the ByHandles version and let it do the job.
    403              */
    404             rc = RTFileCopyByHandlesEx(FileSrc, FileDst, pfnProgress, pvUser);
    405 
    406             /*
    407              * Close the files regardless of the result.
    408              * Don't bother cleaning up or anything like that.
    409              */
    410             int rc2 = RTFileClose(FileDst);
    411             AssertRC(rc2);
    412             if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    413                 rc = rc2;
    414         }
    415 
    416         int rc2 = RTFileClose(FileSrc);
    417         AssertRC(rc2);
    418         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    419             rc = rc2;
    420     }
    421     return rc;
    422 }
    423 
    424 
    425 RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser)
    426 {
    427     /*
    428      * Validate input.
    429      */
    430     AssertMsgReturn(RTFileIsValid(FileSrc), ("FileSrc=%RTfile\n", FileSrc), VERR_INVALID_PARAMETER);
    431     AssertMsgReturn(RTFileIsValid(FileDst), ("FileDst=%RTfile\n", FileDst), VERR_INVALID_PARAMETER);
    432     AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
    433 
    434     /*
    435      * Save file offset.
    436      */
    437     RTFOFF offSrcSaved;
    438     int rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_CURRENT, (uint64_t *)&offSrcSaved);
    439     if (RT_FAILURE(rc))
    440         return rc;
    441 
    442     /*
    443      * Get the file size.
    444      */
    445     RTFOFF cbSrc;
    446     rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_END, (uint64_t *)&cbSrc);
    447     if (RT_FAILURE(rc))
    448         return rc;
    449 
    450     /*
    451      * Allocate buffer.
    452      */
    453     size_t      cbBuf;
    454     uint8_t    *pbBufFree = NULL;
    455     uint8_t    *pbBuf;
    456     if (cbSrc < _512K)
    457     {
    458         cbBuf = 8*_1K;
    459         pbBuf = (uint8_t *)alloca(cbBuf);
    460     }
    461     else
    462     {
    463         cbBuf = _128K;
    464         pbBuf = pbBufFree = (uint8_t *)RTMemTmpAlloc(cbBuf);
    465     }
    466     if (pbBuf)
    467     {
    468         /*
    469          * Seek to the start of each file
    470          * and set the size of the destination file.
    471          */
    472         rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_BEGIN, NULL);
    473         if (RT_SUCCESS(rc))
    474         {
    475             rc = RTFileSeek(FileDst, 0, RTFILE_SEEK_BEGIN, NULL);
    476             if (RT_SUCCESS(rc))
    477                 rc = RTFileSetSize(FileDst, cbSrc);
    478             if (RT_SUCCESS(rc) && pfnProgress)
    479                 rc = pfnProgress(0, pvUser);
    480             if (RT_SUCCESS(rc))
    481             {
    482                 /*
    483                  * Copy loop.
    484                  */
    485                 unsigned    uPercentage = 0;
    486                 RTFOFF      off = 0;
    487                 RTFOFF      cbPercent = cbSrc / 100;
    488                 RTFOFF      offNextPercent = cbPercent;
    489                 while (off < cbSrc)
    490                 {
    491                     /* copy block */
    492                     RTFOFF cbLeft = cbSrc - off;
    493                     size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;
    494                     rc = RTFileRead(FileSrc, pbBuf, cbBlock, NULL);
    495                     if (RT_FAILURE(rc))
    496                         break;
    497                     rc = RTFileWrite(FileDst, pbBuf, cbBlock, NULL);
    498                     if (RT_FAILURE(rc))
    499                         break;
    500 
    501                     /* advance */
    502                     off += cbBlock;
    503                     if (pfnProgress && offNextPercent < off && uPercentage < 100)
    504                     {
    505                         do
    506                         {
    507                             uPercentage++;
    508                             offNextPercent += cbPercent;
    509                         } while (offNextPercent < off && uPercentage < 100);
    510                         rc = pfnProgress(uPercentage, pvUser);
    511                         if (RT_FAILURE(rc))
    512                             break;
    513                     }
    514                 }
    515 
    516 #if 0
    517                 /*
    518                  * Copy OS specific data (EAs and stuff).
    519                  */
    520                 rtFileCopyOSStuff(FileSrc, FileDst);
    521 #endif
    522 
    523                 /* 100% */
    524                 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))
    525                     rc = pfnProgress(100, pvUser);
    526             }
    527         }
    528         RTMemTmpFree(pbBufFree);
    529     }
    530     else
    531         rc = VERR_NO_MEMORY;
    532 
    533     /*
    534      * Restore source position.
    535      */
    536     RTFileSeek(FileSrc, offSrcSaved, RTFILE_SEEK_BEGIN, NULL);
    537 
    538     return rc;
    539 }
    540 
    541 
    542 RTDECL(int) RTFileCompare(const char *pszFile1, const char *pszFile2)
    543 {
    544     return RTFileCompareEx(pszFile1, pszFile2, 0 /*fFlags*/, NULL, NULL);
    545 }
    546 
    547 
    548 RTDECL(int) RTFileCompareByHandles(RTFILE hFile1, RTFILE hFile2)
    549 {
    550     return RTFileCompareByHandlesEx(hFile1, hFile2, 0 /*fFlags*/, NULL, NULL);
    551 }
    552 
    553 
    554 RTDECL(int) RTFileCompareEx(const char *pszFile1, const char *pszFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
    555 {
    556     /*
    557      * Validate input.
    558      */
    559     AssertPtrReturn(pszFile1, VERR_INVALID_POINTER);
    560     AssertReturn(*pszFile1, VERR_INVALID_PARAMETER);
    561     AssertPtrReturn(pszFile2, VERR_INVALID_POINTER);
    562     AssertReturn(*pszFile2, VERR_INVALID_PARAMETER);
    563     AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
    564     AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
    565 
    566     /*
    567      * Open the files.
    568      */
    569     RTFILE hFile1;
    570     int rc = RTFileOpen(&hFile1, pszFile1,
    571                         RTFILE_O_READ | RTFILE_O_OPEN
    572                         | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
    573     if (RT_SUCCESS(rc))
    574     {
    575         RTFILE hFile2;
    576         rc = RTFileOpen(&hFile2, pszFile2,
    577                         RTFILE_O_READ | RTFILE_O_OPEN
    578                         | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
    579         if (RT_SUCCESS(rc))
    580         {
    581             /*
    582              * Call the ByHandles version and let it do the job.
    583              */
    584             rc = RTFileCompareByHandlesEx(hFile1, hFile2, fFlags,  pfnProgress, pvUser);
    585 
    586             /* Clean up */
    587             int rc2 = RTFileClose(hFile2);
    588             AssertRC(rc2);
    589             if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    590                 rc = rc2;
    591         }
    592 
    593         int rc2 = RTFileClose(hFile1);
    594         AssertRC(rc2);
    595         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    596             rc = rc2;
    597     }
    598     return rc;
    599 }
    600 
    601 
    602 RTDECL(int) RTFileCompareByHandlesEx(RTFILE hFile1, RTFILE hFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
    603 {
    604     /*
    605      * Validate input.
    606      */
    607     AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);
    608     AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);
    609     AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
    610     AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
    611 
    612     /*
    613      * Compare the file sizes first.
    614      */
    615     uint64_t cbFile1;
    616     int rc = RTFileGetSize(hFile1, &cbFile1);
    617     if (RT_FAILURE(rc))
    618         return rc;
    619 
    620     uint64_t cbFile2;
    621     rc = RTFileGetSize(hFile1, &cbFile2);
    622     if (RT_FAILURE(rc))
    623         return rc;
    624 
    625     if (cbFile1 != cbFile2)
    626         return VERR_NOT_EQUAL;
    627 
    628 
    629     /*
    630      * Allocate buffer.
    631      */
    632     size_t      cbBuf;
    633     uint8_t    *pbBuf1Free = NULL;
    634     uint8_t    *pbBuf1;
    635     uint8_t    *pbBuf2Free = NULL;
    636     uint8_t    *pbBuf2;
    637     if (cbFile1 < _512K)
    638     {
    639         cbBuf  = 8*_1K;
    640         pbBuf1 = (uint8_t *)alloca(cbBuf);
    641         pbBuf2 = (uint8_t *)alloca(cbBuf);
    642     }
    643     else
    644     {
    645         cbBuf = _128K;
    646         pbBuf1 = pbBuf1Free = (uint8_t *)RTMemTmpAlloc(cbBuf);
    647         pbBuf2 = pbBuf2Free = (uint8_t *)RTMemTmpAlloc(cbBuf);
    648     }
    649     if (pbBuf1 && pbBuf2)
    650     {
    651         /*
    652          * Seek to the start of each file
    653          * and set the size of the destination file.
    654          */
    655         rc = RTFileSeek(hFile1, 0, RTFILE_SEEK_BEGIN, NULL);
    656         if (RT_SUCCESS(rc))
    657         {
    658             rc = RTFileSeek(hFile2, 0, RTFILE_SEEK_BEGIN, NULL);
    659             if (RT_SUCCESS(rc) && pfnProgress)
    660                 rc = pfnProgress(0, pvUser);
    661             if (RT_SUCCESS(rc))
    662             {
    663                 /*
    664                  * Compare loop.
    665                  */
    666                 unsigned    uPercentage    = 0;
    667                 RTFOFF      off            = 0;
    668                 RTFOFF      cbPercent      = cbFile1 / 100;
    669                 RTFOFF      offNextPercent = cbPercent;
    670                 while (off < (RTFOFF)cbFile1)
    671                 {
    672                     /* read the blocks */
    673                     RTFOFF cbLeft = cbFile1 - off;
    674                     size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;
    675                     rc = RTFileRead(hFile1, pbBuf1, cbBlock, NULL);
    676                     if (RT_FAILURE(rc))
    677                         break;
    678                     rc = RTFileRead(hFile2, pbBuf2, cbBlock, NULL);
    679                     if (RT_FAILURE(rc))
    680                         break;
    681 
    682                     /* compare */
    683                     if (memcmp(pbBuf1, pbBuf2, cbBlock))
    684                     {
    685                         rc = VERR_NOT_EQUAL;
    686                         break;
    687                     }
    688 
    689                     /* advance */
    690                     off += cbBlock;
    691                     if (pfnProgress && offNextPercent < off)
    692                     {
    693                         while (offNextPercent < off)
    694                         {
    695                             uPercentage++;
    696                             offNextPercent += cbPercent;
    697                         }
    698                         rc = pfnProgress(uPercentage, pvUser);
    699                         if (RT_FAILURE(rc))
    700                             break;
    701                     }
    702                 }
    703 
    704 #if 0
    705                 /*
    706                  * Compare OS specific data (EAs and stuff).
    707                  */
    708                 if (RT_SUCCESS(rc))
    709                     rc = rtFileCompareOSStuff(hFile1, hFile2);
    710 #endif
    711 
    712                 /* 100% */
    713                 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))
    714                     rc = pfnProgress(100, pvUser);
    715             }
    716         }
    717     }
    718     else
    719         rc = VERR_NO_MEMORY;
    720     RTMemTmpFree(pbBuf2Free);
    721     RTMemTmpFree(pbBuf1Free);
    722 
    723     return rc;
    724 }
    725 
  • trunk/src/VBox/Runtime/generic/fileio-sg-generic.cpp

    r77183 r77209  
    11/* $Id$ */
    22/** @file
    3  * IPRT - File I/O.
     3 * IPRT - File I/O, RTFileSgReadAt & RTFileSgWriteAt, generic.
    44 */
    55
     
    3232#include <iprt/file.h>
    3333
    34 #include <iprt/mem.h>
    35 #include <iprt/assert.h>
    36 #include <iprt/alloca.h>
    37 #include <iprt/string.h>
    38 #include <iprt/err.h>
    39 #include "internal/file.h"
    40 
    41 
    42 /*********************************************************************************************************************************
    43 *   Global Variables                                                                                                             *
    44 *********************************************************************************************************************************/
    45 /** Set of forced set open flags for files opened read-only. */
    46 static unsigned g_fOpenReadSet = 0;
    47 
    48 /** Set of forced cleared open flags for files opened read-only. */
    49 static unsigned g_fOpenReadMask = 0;
    50 
    51 /** Set of forced set open flags for files opened write-only. */
    52 static unsigned g_fOpenWriteSet = 0;
    53 
    54 /** Set of forced cleared open flags for files opened write-only. */
    55 static unsigned g_fOpenWriteMask = 0;
    56 
    57 /** Set of forced set open flags for files opened read-write. */
    58 static unsigned g_fOpenReadWriteSet = 0;
    59 
    60 /** Set of forced cleared open flags for files opened read-write. */
    61 static unsigned g_fOpenReadWriteMask = 0;
    62 
    63 
    64 /**
    65  * Force the use of open flags for all files opened after the setting is
    66  * changed. The caller is responsible for not causing races with RTFileOpen().
    67  *
    68  * @returns iprt status code.
    69  * @param   fOpenForAccess  Access mode to which the set/mask settings apply.
    70  * @param   fSet            Open flags to be forced set.
    71  * @param   fMask           Open flags to be masked out.
    72  */
    73 RTR3DECL(int)  RTFileSetForceFlags(unsigned fOpenForAccess, unsigned fSet, unsigned fMask)
    74 {
    75     /*
    76      * For now allow only RTFILE_O_WRITE_THROUGH. The other flags either
    77      * make no sense in this context or are not useful to apply to all files.
    78      */
    79     if ((fSet | fMask) & ~RTFILE_O_WRITE_THROUGH)
    80         return VERR_INVALID_PARAMETER;
    81     switch (fOpenForAccess)
    82     {
    83         case RTFILE_O_READ:
    84             g_fOpenReadSet = fSet;
    85             g_fOpenReadMask = fMask;
    86             break;
    87         case RTFILE_O_WRITE:
    88             g_fOpenWriteSet = fSet;
    89             g_fOpenWriteMask = fMask;
    90             break;
    91         case RTFILE_O_READWRITE:
    92             g_fOpenReadWriteSet = fSet;
    93             g_fOpenReadWriteMask = fMask;
    94             break;
    95         default:
    96             AssertMsgFailed(("Invalid access mode %d\n", fOpenForAccess));
    97             return VERR_INVALID_PARAMETER;
    98     }
    99     return VINF_SUCCESS;
    100 }
    101 
    102 
    103 /**
    104  * Adjusts and validates the flags.
    105  *
    106  * The adjustments are made according to the wishes specified using the RTFileSetForceFlags API.
    107  *
    108  * @returns IPRT status code.
    109  * @param   pfOpen      Pointer to the user specified flags on input.
    110  *                      Updated on successful return.
    111  * @internal
    112  */
    113 int rtFileRecalcAndValidateFlags(uint64_t *pfOpen)
    114 {
    115     /*
    116      * Recalc.
    117      */
    118     uint32_t fOpen = *pfOpen;
    119     switch (fOpen & RTFILE_O_ACCESS_MASK)
    120     {
    121         case RTFILE_O_READ:
    122             fOpen |= g_fOpenReadSet;
    123             fOpen &= ~g_fOpenReadMask;
    124             break;
    125         case RTFILE_O_WRITE:
    126             fOpen |= g_fOpenWriteSet;
    127             fOpen &= ~g_fOpenWriteMask;
    128             break;
    129         case RTFILE_O_READWRITE:
    130             fOpen |= g_fOpenReadWriteSet;
    131             fOpen &= ~g_fOpenReadWriteMask;
    132             break;
    133 #ifdef RT_OS_WINDOWS
    134         case RTFILE_O_ATTR_ONLY:
    135             if (fOpen & RTFILE_O_ACCESS_ATTR_MASK)
    136                 break;
    137 #endif
    138         default:
    139             AssertMsgFailed(("Invalid access mode value, fOpen=%#llx\n", fOpen));
    140             return VERR_INVALID_PARAMETER;
    141     }
    142 
    143     /*
    144      * Validate                                                                                                                                       .
    145      */
    146 #ifdef RT_OS_WINDOWS
    147     AssertMsgReturn((fOpen & RTFILE_O_ACCESS_MASK) || (fOpen & RTFILE_O_ACCESS_ATTR_MASK),
    148                     ("Missing RTFILE_O_READ/WRITE/ACCESS_ATTR: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    149 #else
    150     AssertMsgReturn(fOpen & RTFILE_O_ACCESS_MASK, ("Missing RTFILE_O_READ/WRITE: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    151 #endif
    152 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    153     AssertMsgReturn(!(fOpen & (~(uint64_t)RTFILE_O_VALID_MASK | RTFILE_O_NON_BLOCK)), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    154 #else
    155     AssertMsgReturn(!(fOpen & ~(uint64_t)RTFILE_O_VALID_MASK), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    156 #endif
    157     AssertMsgReturn((fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_WRITE)) != RTFILE_O_TRUNCATE, ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    158 
    159     switch (fOpen & RTFILE_O_ACTION_MASK)
    160     {
    161         case 0: /* temporarily */
    162             AssertMsgFailed(("Missing RTFILE_O_OPEN/CREATE*! (continuable assertion)\n"));
    163             fOpen |= RTFILE_O_OPEN;
    164             break;
    165         case RTFILE_O_OPEN:
    166             AssertMsgReturn(!(RTFILE_O_NOT_CONTENT_INDEXED & fOpen), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
    167         case RTFILE_O_OPEN_CREATE:
    168         case RTFILE_O_CREATE:
    169         case RTFILE_O_CREATE_REPLACE:
    170             break;
    171         default:
    172             AssertMsgFailed(("Invalid action value: fOpen=%#llx\n", fOpen));
    173             return VERR_INVALID_PARAMETER;
    174     }
    175 
    176     switch (fOpen & RTFILE_O_DENY_MASK)
    177     {
    178         case 0: /* temporarily */
    179             AssertMsgFailed(("Missing RTFILE_O_DENY_*! (continuable assertion)\n"));
    180             fOpen |= RTFILE_O_DENY_NONE;
    181             break;
    182         case RTFILE_O_DENY_NONE:
    183         case RTFILE_O_DENY_READ:
    184         case RTFILE_O_DENY_WRITE:
    185         case RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
    186         case RTFILE_O_DENY_NOT_DELETE:
    187         case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ:
    188         case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE:
    189         case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
    190             break;
    191         default:
    192             AssertMsgFailed(("Invalid deny value: fOpen=%#llx\n", fOpen));
    193             return VERR_INVALID_PARAMETER;
    194     }
    195 
    196     /* done */
    197     *pfOpen = fOpen;
    198     return VINF_SUCCESS;
    199 }
    200 
    201 
    202 
    203 /**
    204  * Read bytes from a file at a given offset.
    205  * This function may modify the file position.
    206  *
    207  * @returns iprt status code.
    208  * @param   File        Handle to the file.
    209  * @param   off         Where to read.
    210  * @param   pvBuf       Where to put the bytes we read.
    211  * @param   cbToRead    How much to read.
    212  * @param   *pcbRead    How much we actually read.
    213  *                      If NULL an error will be returned for a partial read.
    214  */
    215 RTR3DECL(int)  RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
    216 {
    217     int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
    218     if (RT_SUCCESS(rc))
    219         rc = RTFileRead(File, pvBuf, cbToRead, pcbRead);
    220     return rc;
    221 }
     34#include <iprt/errcore.h>
    22235
    22336
     
    23447 *                      If NULL an error will be returned for a partial read.
    23548 */
    236 RTR3DECL(int)  RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)
     49RTDECL(int)  RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)
    23750{
    23851    int rc = VINF_SUCCESS;
    23952    size_t cbRead = 0;
    240 
    24153    while (cbToRead)
    24254    {
     55        size_t cbBuf = cbToRead;
     56        void  *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
     57
    24358        size_t cbThisRead = 0;
    244         size_t cbBuf = cbToRead;
    245         void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
    246 
    24759        rc = RTFileReadAt(hFile, off, pvBuf, cbBuf, pcbRead ? &cbThisRead : NULL);
    24860        if (RT_SUCCESS(rc))
    24961            cbRead += cbThisRead;
    250 
    251         if (   RT_FAILURE(rc)
    252             || (   cbThisRead < cbBuf
    253                 && pcbRead))
     62        else
     63            break;
     64        if (   cbThisRead < cbBuf
     65            && pcbRead)
    25466            break;
    25567
     
    26173        *pcbRead = cbRead;
    26274
    263     return rc;
    264 }
    265 
    266 
    267 /**
    268  * Write bytes to a file at a given offset.
    269  * This function may modify the file position.
    270  *
    271  * @returns iprt status code.
    272  * @param   File        Handle to the file.
    273  * @param   off         Where to write.
    274  * @param   pvBuf       What to write.
    275  * @param   cbToWrite   How much to write.
    276  * @param   *pcbWritten How much we actually wrote.
    277  *                      If NULL an error will be returned for a partial write.
    278  */
    279 RTR3DECL(int)  RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
    280 {
    281     int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
    282     if (RT_SUCCESS(rc))
    283         rc = RTFileWrite(File, pvBuf, cbToWrite, pcbWritten);
    28475    return rc;
    28576}
     
    29889 *                      If NULL an error will be returned for a partial write.
    29990 */
    300 RTR3DECL(int)  RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)
     91RTDECL(int)  RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)
    30192{
    30293    int rc = VINF_SUCCESS;
    30394    size_t cbWritten = 0;
    304 
    30595    while (cbToWrite)
    30696    {
     97        size_t cbBuf = cbToWrite;
     98        void  *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
     99
    307100        size_t cbThisWritten = 0;
    308         size_t cbBuf = cbToWrite;
    309         void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
    310 
    311101        rc = RTFileWriteAt(hFile, off, pvBuf, cbBuf, pcbWritten ? &cbThisWritten : NULL);
    312102        if (RT_SUCCESS(rc))
    313103            cbWritten += cbThisWritten;
    314 
    315         if (   RT_FAILURE(rc)
    316             || (   cbThisWritten < cbBuf
    317                 && pcbWritten))
     104        else
     105            break;
     106        if (   cbThisWritten < cbBuf
     107            && pcbWritten)
    318108            break;
    319109
     
    328118}
    329119
    330 
    331 /**
    332  * Gets the current file position.
    333  *
    334  * @returns File offset.
    335  * @returns ~0UUL on failure.
    336  * @param   File        File handle.
    337  */
    338 RTR3DECL(uint64_t)  RTFileTell(RTFILE File)
    339 {
    340     /*
    341      * Call the seek api to query the stuff.
    342      */
    343     uint64_t off = 0;
    344     int rc = RTFileSeek(File, 0, RTFILE_SEEK_CURRENT, &off);
    345     if (RT_SUCCESS(rc))
    346         return off;
    347     AssertMsgFailed(("RTFileSeek(%d) -> %d\n", File, rc));
    348     return ~0ULL;
    349 }
    350 
    351 
    352 /**
    353  * Determine the maximum file size.
    354  *
    355  * @returns The max size of the file.
    356  *          -1 on failure, the file position is undefined.
    357  * @param   File        Handle to the file.
    358  * @see     RTFileGetMaxSizeEx.
    359  */
    360 RTR3DECL(RTFOFF) RTFileGetMaxSize(RTFILE File)
    361 {
    362     RTFOFF cbMax;
    363     int rc = RTFileGetMaxSizeEx(File, &cbMax);
    364     return RT_SUCCESS(rc) ? cbMax : -1;
    365 }
    366 
    367 
    368 RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst)
    369 {
    370     return RTFileCopyByHandlesEx(FileSrc, FileDst, NULL, NULL);
    371 }
    372 
    373 
    374 RTDECL(int) RTFileCopyEx(const char *pszSrc, const char *pszDst, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
    375 {
    376     /*
    377      * Validate input.
    378      */
    379     AssertMsgReturn(VALID_PTR(pszSrc), ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);
    380     AssertMsgReturn(*pszSrc, ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);
    381     AssertMsgReturn(VALID_PTR(pszDst), ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);
    382     AssertMsgReturn(*pszDst, ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);
    383     AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
    384     AssertMsgReturn(!(fFlags & ~RTFILECOPY_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
    385 
    386     /*
    387      * Open the files.
    388      */
    389     RTFILE FileSrc;
    390     int rc = RTFileOpen(&FileSrc, pszSrc,
    391                         RTFILE_O_READ | RTFILE_O_OPEN
    392                         | (fFlags & RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
    393     if (RT_SUCCESS(rc))
    394     {
    395         RTFILE FileDst;
    396         rc = RTFileOpen(&FileDst, pszDst,
    397                         RTFILE_O_WRITE | RTFILE_O_CREATE
    398                         | (fFlags & RTFILECOPY_FLAGS_NO_DST_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
    399         if (RT_SUCCESS(rc))
    400         {
    401             /*
    402              * Call the ByHandles version and let it do the job.
    403              */
    404             rc = RTFileCopyByHandlesEx(FileSrc, FileDst, pfnProgress, pvUser);
    405 
    406             /*
    407              * Close the files regardless of the result.
    408              * Don't bother cleaning up or anything like that.
    409              */
    410             int rc2 = RTFileClose(FileDst);
    411             AssertRC(rc2);
    412             if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    413                 rc = rc2;
    414         }
    415 
    416         int rc2 = RTFileClose(FileSrc);
    417         AssertRC(rc2);
    418         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    419             rc = rc2;
    420     }
    421     return rc;
    422 }
    423 
    424 
    425 RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser)
    426 {
    427     /*
    428      * Validate input.
    429      */
    430     AssertMsgReturn(RTFileIsValid(FileSrc), ("FileSrc=%RTfile\n", FileSrc), VERR_INVALID_PARAMETER);
    431     AssertMsgReturn(RTFileIsValid(FileDst), ("FileDst=%RTfile\n", FileDst), VERR_INVALID_PARAMETER);
    432     AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
    433 
    434     /*
    435      * Save file offset.
    436      */
    437     RTFOFF offSrcSaved;
    438     int rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_CURRENT, (uint64_t *)&offSrcSaved);
    439     if (RT_FAILURE(rc))
    440         return rc;
    441 
    442     /*
    443      * Get the file size.
    444      */
    445     RTFOFF cbSrc;
    446     rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_END, (uint64_t *)&cbSrc);
    447     if (RT_FAILURE(rc))
    448         return rc;
    449 
    450     /*
    451      * Allocate buffer.
    452      */
    453     size_t      cbBuf;
    454     uint8_t    *pbBufFree = NULL;
    455     uint8_t    *pbBuf;
    456     if (cbSrc < _512K)
    457     {
    458         cbBuf = 8*_1K;
    459         pbBuf = (uint8_t *)alloca(cbBuf);
    460     }
    461     else
    462     {
    463         cbBuf = _128K;
    464         pbBuf = pbBufFree = (uint8_t *)RTMemTmpAlloc(cbBuf);
    465     }
    466     if (pbBuf)
    467     {
    468         /*
    469          * Seek to the start of each file
    470          * and set the size of the destination file.
    471          */
    472         rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_BEGIN, NULL);
    473         if (RT_SUCCESS(rc))
    474         {
    475             rc = RTFileSeek(FileDst, 0, RTFILE_SEEK_BEGIN, NULL);
    476             if (RT_SUCCESS(rc))
    477                 rc = RTFileSetSize(FileDst, cbSrc);
    478             if (RT_SUCCESS(rc) && pfnProgress)
    479                 rc = pfnProgress(0, pvUser);
    480             if (RT_SUCCESS(rc))
    481             {
    482                 /*
    483                  * Copy loop.
    484                  */
    485                 unsigned    uPercentage = 0;
    486                 RTFOFF      off = 0;
    487                 RTFOFF      cbPercent = cbSrc / 100;
    488                 RTFOFF      offNextPercent = cbPercent;
    489                 while (off < cbSrc)
    490                 {
    491                     /* copy block */
    492                     RTFOFF cbLeft = cbSrc - off;
    493                     size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;
    494                     rc = RTFileRead(FileSrc, pbBuf, cbBlock, NULL);
    495                     if (RT_FAILURE(rc))
    496                         break;
    497                     rc = RTFileWrite(FileDst, pbBuf, cbBlock, NULL);
    498                     if (RT_FAILURE(rc))
    499                         break;
    500 
    501                     /* advance */
    502                     off += cbBlock;
    503                     if (pfnProgress && offNextPercent < off && uPercentage < 100)
    504                     {
    505                         do
    506                         {
    507                             uPercentage++;
    508                             offNextPercent += cbPercent;
    509                         } while (offNextPercent < off && uPercentage < 100);
    510                         rc = pfnProgress(uPercentage, pvUser);
    511                         if (RT_FAILURE(rc))
    512                             break;
    513                     }
    514                 }
    515 
    516 #if 0
    517                 /*
    518                  * Copy OS specific data (EAs and stuff).
    519                  */
    520                 rtFileCopyOSStuff(FileSrc, FileDst);
    521 #endif
    522 
    523                 /* 100% */
    524                 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))
    525                     rc = pfnProgress(100, pvUser);
    526             }
    527         }
    528         RTMemTmpFree(pbBufFree);
    529     }
    530     else
    531         rc = VERR_NO_MEMORY;
    532 
    533     /*
    534      * Restore source position.
    535      */
    536     RTFileSeek(FileSrc, offSrcSaved, RTFILE_SEEK_BEGIN, NULL);
    537 
    538     return rc;
    539 }
    540 
    541 
    542 RTDECL(int) RTFileCompare(const char *pszFile1, const char *pszFile2)
    543 {
    544     return RTFileCompareEx(pszFile1, pszFile2, 0 /*fFlags*/, NULL, NULL);
    545 }
    546 
    547 
    548 RTDECL(int) RTFileCompareByHandles(RTFILE hFile1, RTFILE hFile2)
    549 {
    550     return RTFileCompareByHandlesEx(hFile1, hFile2, 0 /*fFlags*/, NULL, NULL);
    551 }
    552 
    553 
    554 RTDECL(int) RTFileCompareEx(const char *pszFile1, const char *pszFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
    555 {
    556     /*
    557      * Validate input.
    558      */
    559     AssertPtrReturn(pszFile1, VERR_INVALID_POINTER);
    560     AssertReturn(*pszFile1, VERR_INVALID_PARAMETER);
    561     AssertPtrReturn(pszFile2, VERR_INVALID_POINTER);
    562     AssertReturn(*pszFile2, VERR_INVALID_PARAMETER);
    563     AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
    564     AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
    565 
    566     /*
    567      * Open the files.
    568      */
    569     RTFILE hFile1;
    570     int rc = RTFileOpen(&hFile1, pszFile1,
    571                         RTFILE_O_READ | RTFILE_O_OPEN
    572                         | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
    573     if (RT_SUCCESS(rc))
    574     {
    575         RTFILE hFile2;
    576         rc = RTFileOpen(&hFile2, pszFile2,
    577                         RTFILE_O_READ | RTFILE_O_OPEN
    578                         | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
    579         if (RT_SUCCESS(rc))
    580         {
    581             /*
    582              * Call the ByHandles version and let it do the job.
    583              */
    584             rc = RTFileCompareByHandlesEx(hFile1, hFile2, fFlags,  pfnProgress, pvUser);
    585 
    586             /* Clean up */
    587             int rc2 = RTFileClose(hFile2);
    588             AssertRC(rc2);
    589             if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    590                 rc = rc2;
    591         }
    592 
    593         int rc2 = RTFileClose(hFile1);
    594         AssertRC(rc2);
    595         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    596             rc = rc2;
    597     }
    598     return rc;
    599 }
    600 
    601 
    602 RTDECL(int) RTFileCompareByHandlesEx(RTFILE hFile1, RTFILE hFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
    603 {
    604     /*
    605      * Validate input.
    606      */
    607     AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);
    608     AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);
    609     AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
    610     AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
    611 
    612     /*
    613      * Compare the file sizes first.
    614      */
    615     uint64_t cbFile1;
    616     int rc = RTFileGetSize(hFile1, &cbFile1);
    617     if (RT_FAILURE(rc))
    618         return rc;
    619 
    620     uint64_t cbFile2;
    621     rc = RTFileGetSize(hFile1, &cbFile2);
    622     if (RT_FAILURE(rc))
    623         return rc;
    624 
    625     if (cbFile1 != cbFile2)
    626         return VERR_NOT_EQUAL;
    627 
    628 
    629     /*
    630      * Allocate buffer.
    631      */
    632     size_t      cbBuf;
    633     uint8_t    *pbBuf1Free = NULL;
    634     uint8_t    *pbBuf1;
    635     uint8_t    *pbBuf2Free = NULL;
    636     uint8_t    *pbBuf2;
    637     if (cbFile1 < _512K)
    638     {
    639         cbBuf  = 8*_1K;
    640         pbBuf1 = (uint8_t *)alloca(cbBuf);
    641         pbBuf2 = (uint8_t *)alloca(cbBuf);
    642     }
    643     else
    644     {
    645         cbBuf = _128K;
    646         pbBuf1 = pbBuf1Free = (uint8_t *)RTMemTmpAlloc(cbBuf);
    647         pbBuf2 = pbBuf2Free = (uint8_t *)RTMemTmpAlloc(cbBuf);
    648     }
    649     if (pbBuf1 && pbBuf2)
    650     {
    651         /*
    652          * Seek to the start of each file
    653          * and set the size of the destination file.
    654          */
    655         rc = RTFileSeek(hFile1, 0, RTFILE_SEEK_BEGIN, NULL);
    656         if (RT_SUCCESS(rc))
    657         {
    658             rc = RTFileSeek(hFile2, 0, RTFILE_SEEK_BEGIN, NULL);
    659             if (RT_SUCCESS(rc) && pfnProgress)
    660                 rc = pfnProgress(0, pvUser);
    661             if (RT_SUCCESS(rc))
    662             {
    663                 /*
    664                  * Compare loop.
    665                  */
    666                 unsigned    uPercentage    = 0;
    667                 RTFOFF      off            = 0;
    668                 RTFOFF      cbPercent      = cbFile1 / 100;
    669                 RTFOFF      offNextPercent = cbPercent;
    670                 while (off < (RTFOFF)cbFile1)
    671                 {
    672                     /* read the blocks */
    673                     RTFOFF cbLeft = cbFile1 - off;
    674                     size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;
    675                     rc = RTFileRead(hFile1, pbBuf1, cbBlock, NULL);
    676                     if (RT_FAILURE(rc))
    677                         break;
    678                     rc = RTFileRead(hFile2, pbBuf2, cbBlock, NULL);
    679                     if (RT_FAILURE(rc))
    680                         break;
    681 
    682                     /* compare */
    683                     if (memcmp(pbBuf1, pbBuf2, cbBlock))
    684                     {
    685                         rc = VERR_NOT_EQUAL;
    686                         break;
    687                     }
    688 
    689                     /* advance */
    690                     off += cbBlock;
    691                     if (pfnProgress && offNextPercent < off)
    692                     {
    693                         while (offNextPercent < off)
    694                         {
    695                             uPercentage++;
    696                             offNextPercent += cbPercent;
    697                         }
    698                         rc = pfnProgress(uPercentage, pvUser);
    699                         if (RT_FAILURE(rc))
    700                             break;
    701                     }
    702                 }
    703 
    704 #if 0
    705                 /*
    706                  * Compare OS specific data (EAs and stuff).
    707                  */
    708                 if (RT_SUCCESS(rc))
    709                     rc = rtFileCompareOSStuff(hFile1, hFile2);
    710 #endif
    711 
    712                 /* 100% */
    713                 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))
    714                     rc = pfnProgress(100, pvUser);
    715             }
    716         }
    717     }
    718     else
    719         rc = VERR_NO_MEMORY;
    720     RTMemTmpFree(pbBuf2Free);
    721     RTMemTmpFree(pbBuf1Free);
    722 
    723     return rc;
    724 }
    725 
  • trunk/src/VBox/Runtime/r3/fileio.cpp

    r76553 r77209  
    197197    *pfOpen = fOpen;
    198198    return VINF_SUCCESS;
    199 }
    200 
    201 
    202 
    203 /**
    204  * Read bytes from a file at a given offset.
    205  * This function may modify the file position.
    206  *
    207  * @returns iprt status code.
    208  * @param   File        Handle to the file.
    209  * @param   off         Where to read.
    210  * @param   pvBuf       Where to put the bytes we read.
    211  * @param   cbToRead    How much to read.
    212  * @param   *pcbRead    How much we actually read.
    213  *                      If NULL an error will be returned for a partial read.
    214  */
    215 RTR3DECL(int)  RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
    216 {
    217     int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
    218     if (RT_SUCCESS(rc))
    219         rc = RTFileRead(File, pvBuf, cbToRead, pcbRead);
    220     return rc;
    221 }
    222 
    223 
    224 /**
    225  * Read bytes from a file at a given offset into a S/G buffer.
    226  * This function may modify the file position.
    227  *
    228  * @returns iprt status code.
    229  * @param   hFile       Handle to the file.
    230  * @param   off         Where to read.
    231  * @param   pSgBuf      Pointer to the S/G buffer to read into.
    232  * @param   cbToRead    How much to read.
    233  * @param   pcbRead     How much we actually read.
    234  *                      If NULL an error will be returned for a partial read.
    235  */
    236 RTR3DECL(int)  RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)
    237 {
    238     int rc = VINF_SUCCESS;
    239     size_t cbRead = 0;
    240 
    241     while (cbToRead)
    242     {
    243         size_t cbThisRead = 0;
    244         size_t cbBuf = cbToRead;
    245         void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
    246 
    247         rc = RTFileReadAt(hFile, off, pvBuf, cbBuf, pcbRead ? &cbThisRead : NULL);
    248         if (RT_SUCCESS(rc))
    249             cbRead += cbThisRead;
    250 
    251         if (   RT_FAILURE(rc)
    252             || (   cbThisRead < cbBuf
    253                 && pcbRead))
    254             break;
    255 
    256         cbToRead -= cbBuf;
    257         off += cbBuf;
    258     }
    259 
    260     if (pcbRead)
    261         *pcbRead = cbRead;
    262 
    263     return rc;
    264 }
    265 
    266 
    267 /**
    268  * Write bytes to a file at a given offset.
    269  * This function may modify the file position.
    270  *
    271  * @returns iprt status code.
    272  * @param   File        Handle to the file.
    273  * @param   off         Where to write.
    274  * @param   pvBuf       What to write.
    275  * @param   cbToWrite   How much to write.
    276  * @param   *pcbWritten How much we actually wrote.
    277  *                      If NULL an error will be returned for a partial write.
    278  */
    279 RTR3DECL(int)  RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
    280 {
    281     int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
    282     if (RT_SUCCESS(rc))
    283         rc = RTFileWrite(File, pvBuf, cbToWrite, pcbWritten);
    284     return rc;
    285 }
    286 
    287 
    288 /**
    289  * Write bytes from a S/G buffer to a file at a given offset.
    290  * This function may modify the file position.
    291  *
    292  * @returns iprt status code.
    293  * @param   hFile       Handle to the file.
    294  * @param   off         Where to write.
    295  * @param   pSgBuf      What to write.
    296  * @param   cbToWrite   How much to write.
    297  * @param   pcbWritten  How much we actually wrote.
    298  *                      If NULL an error will be returned for a partial write.
    299  */
    300 RTR3DECL(int)  RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)
    301 {
    302     int rc = VINF_SUCCESS;
    303     size_t cbWritten = 0;
    304 
    305     while (cbToWrite)
    306     {
    307         size_t cbThisWritten = 0;
    308         size_t cbBuf = cbToWrite;
    309         void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
    310 
    311         rc = RTFileWriteAt(hFile, off, pvBuf, cbBuf, pcbWritten ? &cbThisWritten : NULL);
    312         if (RT_SUCCESS(rc))
    313             cbWritten += cbThisWritten;
    314 
    315         if (   RT_FAILURE(rc)
    316             || (   cbThisWritten < cbBuf
    317                 && pcbWritten))
    318             break;
    319 
    320         cbToWrite -= cbBuf;
    321         off += cbBuf;
    322     }
    323 
    324     if (pcbWritten)
    325         *pcbWritten = cbWritten;
    326 
    327     return rc;
    328199}
    329200
Note: See TracChangeset for help on using the changeset viewer.

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