VirtualBox

Changeset 5258 in vbox


Ignore:
Timestamp:
Oct 12, 2007 9:57:23 AM (18 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
25242
Message:

Rewrote the shared folder create file function on the host to eliminate a race condition

Location:
trunk/src/VBox
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostServices/SharedFolders/vbsf.cpp

    r5090 r5258  
    362362                uint32_t len = strlen(pszFullPath);
    363363                char    *src = pszFullPath + len - 1;
    364        
     364
    365365                Log(("Handle case insenstive guest fs on top of host case sensitive fs for %s\n", pszFullPath));
    366366
     
    415415                        else
    416416                            rc = VERR_FILE_NOT_FOUND;
    417            
     417
    418418                        if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
    419419                        {
     
    460460}
    461461
    462 
    463 static int vbsfOpenFile (SHFLHANDLE *phHandle, const char *pszPath, SHFLCREATEPARMS *pParms, bool fCreate)
    464 {
     462/**
     463 * Convert shared folder create flags (see include/iprt/shflsvc.h) into iprt create flags.
     464 *
     465 * @returns iprt status code
     466 * @param  fShflFlags shared folder create flags
     467 * @retval pfOpen     iprt create flags
     468 */
     469static int vbsfConvertFileOpenFlags(unsigned fShflFlags, unsigned *pfOpen)
     470{
     471    unsigned fOpen = 0;
    465472    int rc = VINF_SUCCESS;
    466473
    467     LogFlow(("vbsfOpenFile: pszPath = %s, pParms = %p, fCreate = %d\n",
    468              pszPath, pParms, fCreate));
    469 
    470     /** @todo r=bird: You should've requested a better RTFileOpen API! This code could certainly have
    471      * benefitted from it. I've done the long overdue adjustment of RTFileOpen so it better reflect
    472      * what a decent OS should be able to do. I've also added some OS specific flags (non-blocking,
    473      * delete sharing), and I'm not picky about adding more if that required. (I'm only picky about
    474      * how they are treated on platforms which doesn't support them.)
    475      * Because of the restrictions in the old version of RTFileOpen this code contains dangerous race
    476      * conditions. File creation is one example where you may easily kill a file just created by
    477      * another user.
    478      */
    479 
    480     /* Open or create a file. */
    481     unsigned fOpen;
    482 
    483     Log(("SHFL create flags %08x\n", pParms->CreateFlags));
    484 
    485     if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
    486     {
    487         fOpen = RTFILE_O_OPEN;
    488     }
    489     else
    490         fOpen = fCreate? RTFILE_O_CREATE_REPLACE: RTFILE_O_OPEN;
    491 
    492     switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACCESS_MASK_RW))
     474    switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_RW))
    493475    {
    494476        default:
    495477        case SHFL_CF_ACCESS_NONE:
    496478        {
    497             /** @todo treat this as read access, but theoretically this could be a no access requested. */
     479            /** @todo treat this as read access, but theoretically this could be a no access request. */
    498480            fOpen |= RTFILE_O_READ;
    499481            Log(("FLAG: SHFL_CF_ACCESS_NONE\n"));
     
    524506
    525507    /* Sharing mask */
    526     switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACCESS_MASK_DENY))
     508    switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_DENY))
    527509    {
    528510    default:
     
    548530    }
    549531
    550     SHFLHANDLE      handle;
    551     SHFLFILEHANDLE *pHandle;
    552 
    553     if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
    554     {
    555         handle  = vbsfAllocDirHandle();
    556         pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_DIR);
     532    /* Open/Create action mask */
     533    switch (BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
     534    {
     535    case SHFL_CF_ACT_OPEN_IF_EXISTS:
     536        if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
     537        {
     538            fOpen |= RTFILE_O_OPEN_CREATE;
     539            Log(("FLAGS: SHFL_CF_ACT_OPEN_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
     540        }
     541        else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
     542        {
     543            fOpen |= RTFILE_O_OPEN;
     544            Log(("FLAGS: SHFL_CF_ACT_OPEN_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
     545        }
     546        else
     547        {
     548            Log(("FLAGS: invalid open/create action combination\n"));
     549            rc = VERR_INVALID_PARAMETER;
     550        }
     551        break;
     552    case SHFL_CF_ACT_FAIL_IF_EXISTS:
     553        if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
     554        {
     555            fOpen |= RTFILE_O_CREATE;
     556            Log(("FLAGS: SHFL_CF_ACT_FAIL_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
     557        }
     558        else
     559        {
     560            Log(("FLAGS: invalid open/create action combination\n"));
     561            rc = VERR_INVALID_PARAMETER;
     562        }
     563        break;
     564    case SHFL_CF_ACT_REPLACE_IF_EXISTS:
     565        if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
     566        {
     567            fOpen |= RTFILE_O_CREATE_REPLACE;
     568            Log(("FLAGS: SHFL_CF_ACT_REPLACE_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
     569        }
     570        else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
     571        {
     572            fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
     573            Log(("FLAGS: SHFL_CF_ACT_REPLACE_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
     574        }
     575        else
     576        {
     577            Log(("FLAGS: invalid open/create action combination\n"));
     578            rc = VERR_INVALID_PARAMETER;
     579        }
     580        break;
     581    case SHFL_CF_ACT_OVERWRITE_IF_EXISTS:
     582        if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
     583        {
     584            fOpen |= RTFILE_O_CREATE_REPLACE;
     585            Log(("FLAGS: SHFL_CF_ACT_OVERWRITE_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
     586        }
     587        else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
     588        {
     589            fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
     590            Log(("FLAGS: SHFL_CF_ACT_OVERWRITE_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
     591        }
     592        else
     593        {
     594            Log(("FLAGS: invalid open/create action combination\n"));
     595            rc = VERR_INVALID_PARAMETER;
     596        }
     597        break;
     598    default:
     599        rc = VERR_INVALID_PARAMETER;
     600        Log(("FLAG: SHFL_CF_ACT_MASK_IF_EXISTS - invalid parameter\n"));
     601    }
     602
     603    if (RT_SUCCESS(rc))
     604    {
     605        *pfOpen = fOpen;
     606    }
     607    return rc;
     608}
     609
     610/**
     611 * Open a file or create and open a new one.
     612 *
     613 * @returns IPRT status code
     614 * @param  pszPath               Path to the file or folder on the host.
     615 * @param  pParms->CreateFlags   Creation or open parameters, see include/VBox/shflsvc.h
     616 * @param  pParms->Info          When a new file is created this specifies the initial parameters.
     617 *                               When a file is created or overwritten, it also specifies the
     618 *                               initial size.
     619 * @retval pParms->Result        Shared folder status code, see include/VBox/shflsvc.h
     620 * @retval pParms->Handle        On success the (shared folder) handle of the file opened or
     621 *                               created
     622 * @retval pParms->Info          On success the parameters of the file opened or created
     623 */
     624static int vbsfOpenFile (const char *pszPath, SHFLCREATEPARMS *pParms)
     625{
     626    LogFlow(("vbsfOpenFile: pszPath = %s, pParms = %p\n", pszPath, pParms));
     627    Log(("SHFL create flags %08x\n", pParms->CreateFlags));
     628
     629    SHFLHANDLE      handle = SHFL_HANDLE_NIL;
     630    SHFLFILEHANDLE *pHandle = 0;
     631    /* Open or create a file. */
     632    unsigned fOpen = 0;
     633    int rc = vbsfConvertFileOpenFlags(pParms->CreateFlags, &fOpen);
     634    if (RT_SUCCESS(rc))
     635    {
     636        handle  = vbsfAllocFileHandle();
     637    }
     638    if (SHFL_HANDLE_NIL != handle)
     639    {
     640        rc = VERR_NO_MEMORY;  /* If this fails - rewritten immediately on success. */
     641        pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_FILE);
     642    }
     643    if (0 != pHandle)
     644    {
     645        rc = RTFileOpen(&pHandle->file.Handle, pszPath, fOpen);
     646    }
     647    if (RT_FAILURE (rc))
     648    {
     649        switch (rc)
     650        {
     651        case VERR_FILE_NOT_FOUND:
     652            pParms->Result = SHFL_FILE_NOT_FOUND;
     653            break;
     654        case VERR_PATH_NOT_FOUND:
     655            pParms->Result = SHFL_PATH_NOT_FOUND;
     656            break;
     657        case VERR_ALREADY_EXISTS:
     658            RTFSOBJINFO info;
     659
     660            /** @todo Possible race left here. */
     661            if (RT_SUCCESS(RTPathQueryInfo (pszPath, &info, RTFSOBJATTRADD_NOTHING)))
     662            {
     663                pParms->Info = info;
     664            }
     665            pParms->Result = SHFL_FILE_EXISTS;
     666            break;
     667        default:
     668            pParms->Result = SHFL_NO_RESULT;
     669        }
     670    }
     671    if (RT_SUCCESS(rc))
     672    {
     673        /** @note The shared folder status code is very approximate, as the runtime
     674          *       does not really provide this information. */
     675        pParms->Result = SHFL_FILE_EXISTS;  /* We lost the information as to whether it was
     676                                               created when we eliminated the race. */
     677        if (   (   SHFL_CF_ACT_REPLACE_IF_EXISTS
     678                == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
     679            || (   SHFL_CF_ACT_OVERWRITE_IF_EXISTS
     680                == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS)))
     681        {
     682            /* For now, we do not treat a failure here as fatal. */
     683            /* @todo Also set the size for SHFL_CF_ACT_CREATE_IF_NEW if
     684                     SHFL_CF_ACT_FAIL_IF_EXISTS is set. */
     685            RTFileSetSize(pHandle->file.Handle, pParms->Info.cbObject);
     686            pParms->Result = SHFL_FILE_REPLACED;
     687        }
     688        if (   (   SHFL_CF_ACT_FAIL_IF_EXISTS
     689                == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
     690            || (   SHFL_CF_ACT_CREATE_IF_NEW
     691                == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW)))
     692        {
     693            pParms->Result = SHFL_FILE_CREATED;
     694        }
     695#if 0
     696        /* @todo */
     697        /* Set new attributes. */
     698        if (   (   SHFL_CF_ACT_REPLACE_IF_EXISTS
     699                == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
     700            || (   SHFL_CF_ACT_CREATE_IF_NEW
     701                == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW)))
     702        {
     703            RTFileSetTimes(pHandle->file.Handle,
     704                          &pParms->Info.AccessTime,
     705                          &pParms->Info.ModificationTime,
     706                          &pParms->Info.ChangeTime,
     707                          &pParms->Info.BirthTime
     708                          );
     709
     710            RTFileSetMode (pHandle->file.Handle, pParms->Info.Attr.fMode);
     711        }
     712#endif
     713        RTFSOBJINFO info;
     714
     715        /* Get file information */
     716        rc = RTFileQueryInfo (pHandle->file.Handle, &info, RTFSOBJATTRADD_NOTHING);
     717        if (RT_SUCCESS(rc))
     718        {
     719            pParms->Info = info;
     720        }
     721    }
     722    if (RT_FAILURE(rc))
     723    {
     724        if (   (0 != pHandle)
     725            && (NIL_RTFILE != pHandle->file.Handle)
     726            && (0 != pHandle->file.Handle))
     727        {
     728            RTFileClose(pHandle->file.Handle);
     729            pHandle->file.Handle = NIL_RTFILE;
     730        }
     731        if (SHFL_HANDLE_NIL != handle)
     732        {
     733            vbsfFreeHandle (handle);
     734        }
    557735    }
    558736    else
    559737    {
    560         handle  = vbsfAllocFileHandle();
    561         pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_FILE);
    562     }
    563 
    564     if (pHandle == NULL)
    565     {
    566         rc = VERR_NO_MEMORY;
     738        pParms->Handle = handle;
     739    }
     740    LogFlow(("vbsfOpenFile: rc = %Vrc\n", rc));
     741    return rc;
     742}
     743
     744/**
     745 * Open a folder or create and open a new one.
     746 *
     747 * @returns IPRT status code
     748 * @param  pszPath               Path to the file or folder on the host.
     749 * @param  pParms->CreateFlags   Creation or open parameters, see include/VBox/shflsvc.h
     750 * @retval pParms->Result        Shared folder status code, see include/VBox/shflsvc.h
     751 * @retval pParms->Handle        On success the (shared folder) handle of the folder opened or
     752 *                               created
     753 * @retval pParms->Info          On success the parameters of the folder opened or created
     754 *
     755 * @note folders are created with fMode = 0777
     756 */
     757static int vbsfOpenDir (const char *pszPath, SHFLCREATEPARMS *pParms)
     758{
     759    LogFlow(("vbsfOpenDir: pszPath = %s, pParms = %p\n", pszPath, pParms));
     760    Log(("SHFL create flags %08x\n", pParms->CreateFlags));
     761
     762    int rc = VERR_NO_MEMORY;
     763    SHFLHANDLE      handle = vbsfAllocDirHandle();
     764    SHFLFILEHANDLE *pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_DIR);
     765    if (0 != pHandle)
     766    {
     767        rc = VINF_SUCCESS;
     768        pParms->Result = SHFL_FILE_EXISTS;  /* May be overwritten with SHFL_FILE_CREATED. */
     769        /** @todo Can anyone think of a sensible, race-less way to do this?  Although
     770                  I suspect that the race is inherent, due to the API available... */
     771        /* Try to create the folder first if "create if new" is specified.  If this
     772           fails, and "open if exists" is specified, then we ignore the failure and try
     773           to open the folder anyway. */
     774        if (   SHFL_CF_ACT_CREATE_IF_NEW
     775            == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
     776        {
     777            /** @todo render supplied attributes.
     778            * bird: The guest should specify this. For windows guests RTFS_DOS_DIRECTORY should suffice. */
     779            RTFMODE fMode = 0777;
     780
     781            pParms->Result = SHFL_FILE_CREATED;
     782            rc = RTDirCreate(pszPath, fMode);
     783            if (RT_FAILURE (rc))
     784            {
     785                switch (rc)
     786                {
     787                case VERR_ALREADY_EXISTS:
     788                    pParms->Result = SHFL_FILE_EXISTS;
     789                    break;
     790                case VERR_PATH_NOT_FOUND:
     791                    pParms->Result = SHFL_PATH_NOT_FOUND;
     792                    break;
     793                default:
     794                    pParms->Result = SHFL_NO_RESULT;
     795                }
     796            }
     797        }
     798        if (   RT_SUCCESS(rc)
     799            || (   SHFL_CF_ACT_OPEN_IF_EXISTS
     800                == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS)))
     801        {
     802            /* Open the directory now */
     803            rc = RTDirOpen (&pHandle->dir.Handle, pszPath);
     804            if (RT_SUCCESS(rc))
     805            {
     806                RTFSOBJINFO info;
     807
     808                rc = RTDirQueryInfo (pHandle->dir.Handle, &info, RTFSOBJATTRADD_NOTHING);
     809                if (RT_SUCCESS(rc))
     810                {
     811                    pParms->Info = info;
     812                }
     813            }
     814            else
     815            {
     816                switch (rc)
     817                {
     818                case VERR_FILE_NOT_FOUND:  /* Does this make sense? */
     819                    pParms->Result = SHFL_FILE_NOT_FOUND;
     820                    break;
     821                case VERR_PATH_NOT_FOUND:
     822                    pParms->Result = SHFL_PATH_NOT_FOUND;
     823                    break;
     824                case VERR_ACCESS_DENIED:
     825                    pParms->Result = SHFL_FILE_EXISTS;
     826                    break;
     827                default:
     828                    pParms->Result = SHFL_NO_RESULT;
     829                }
     830            }
     831        }
     832    }
     833    if (RT_FAILURE(rc))
     834    {
     835        if (   (0 != pHandle)
     836            && (0 != pHandle->dir.Handle))
     837        {
     838            RTDirClose(pHandle->dir.Handle);
     839            pHandle->dir.Handle = 0;
     840        }
     841        if (SHFL_HANDLE_NIL != handle)
     842        {
     843            vbsfFreeHandle (handle);
     844        }
    567845    }
    568846    else
    569847    {
    570         /* Must obviously create the directory, before trying to open it. */
    571         if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
    572         {
    573             if (fCreate)
    574             {
    575                 /** @todo render supplied attributes.
    576                 * bird: The guest should specify this. For windows guests RTFS_DOS_DIRECTORY should suffice. */
    577                 RTFMODE fMode = 0777;
    578 
    579                 rc = RTDirCreate(pszPath, fMode);
    580                 if (VBOX_FAILURE(rc))
    581                 {
    582                     vbsfFreeHandle (handle);
    583                     return rc;
    584                 }
    585             }
    586             /* Open the directory now */
    587             if (VBOX_SUCCESS(rc))
    588             {
    589                 rc = RTDirOpen (&pHandle->dir.Handle, pszPath);
    590                 if (VBOX_FAILURE (rc))
    591                 {
    592                     vbsfFreeHandle (handle);
    593                     *phHandle = SHFL_HANDLE_NIL;
    594                     return rc;
    595                 }
    596             }
    597         }
    598         else
    599         {
    600             rc = RTFileOpen(&pHandle->file.Handle, pszPath, fOpen);
    601         }
    602 
    603         if (VBOX_SUCCESS (rc))
    604         {
    605             *phHandle = handle;
    606         }
    607         else
    608         {
    609              vbsfFreeHandle (handle);
    610         }
    611     }
    612 
    613     LogFlow(("vbsfOpenFile: rc = %Vrc\n", rc));
    614 
    615 
    616     return rc;
    617 }
    618 
    619 static int vbsfOpenExisting (const char *pszFullPath, SHFLCREATEPARMS *pParms)
    620 {
    621     int rc = VINF_SUCCESS;
    622 
    623     LogFlow(("vbsfOpenExisting: pszFullPath = %s, pParms = %p\n",
    624              pszFullPath, pParms));
    625 
    626     /* Open file. */
    627     SHFLHANDLE      handle;
    628 
    629     rc = vbsfOpenFile (&handle, pszFullPath, pParms, false);
    630     if (VBOX_SUCCESS (rc))
    631     {
    632848        pParms->Handle = handle;
    633849    }
    634 
    635     LogFlow(("vbsfOpenExisting: rc = %d\n", rc));
    636 
    637     return rc;
    638 }
    639 
    640 
    641 static int vbsfOpenReplace (const char *pszPath, SHFLCREATEPARMS *pParms, bool bReplace, RTFSOBJINFO *pInfo)
    642 {
    643     int rc = VINF_SUCCESS;
    644 
    645     LogFlow(("vbsfOpenReplace: pszPath = %s, pParms = %p, bReplace = %d\n",
    646              pszPath, pParms, bReplace));
    647 
    648     if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
    649     {
    650         /* Replace operation is not applicable to a directory. */
    651         rc = VERR_INVALID_PARAMETER;
    652     }
    653     else
    654     {
    655         SHFLHANDLE handle = SHFL_HANDLE_NIL;
    656         SHFLFILEHANDLE *pHandle;
    657 
    658         rc = vbsfOpenFile (&handle, pszPath, pParms, true);
    659         // We are loosing an information regarding the cause of failure here
    660         // -- malc
    661         pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_FILE);
    662         if (!pHandle)
    663         {
    664             AssertFailed();
    665             rc = VERR_INVALID_HANDLE;
    666         }
    667 
    668         if (VBOX_SUCCESS (rc))
    669         {
    670 
    671             /* Set new file attributes */
    672 
    673             rc = RTFileSetSize(pHandle->file.Handle, pParms->Info.cbObject);
    674             if (rc != VINF_SUCCESS)
    675             {
    676                 AssertMsg(rc == VINF_SUCCESS, ("RTFileSetSize failed with %d\n", rc));
    677                 return rc;
    678             }
    679 
    680             if (bReplace)
    681             {
    682 #if 0
    683                 /* @todo */
    684                 /* Set new attributes. */
    685                 RTFileSetTimes(pHandle->file.Handle,
    686                                &pParms->Info.AccessTime,
    687                                &pParms->Info.ModificationTime,
    688                                &pParms->Info.ChangeTime,
    689                                &pParms->Info.BirthTime
    690                               );
    691 
    692                 RTFileSetMode (pHandle->file.Handle, pParms->Info.Attr.fMode);
    693 #endif
    694             }
    695 
    696             pParms->Result = SHFL_FILE_REPLACED;
    697             pParms->Handle = handle;
    698         }
    699     }
    700 
    701     LogFlow(("vbsfOpenReplace: rc = %Vrc\n", rc));
    702 
    703     return rc;
    704 }
    705 
    706 static int vbsfOpenCreate (const char *pszPath, SHFLCREATEPARMS *pParms)
    707 {
    708     int rc = VINF_SUCCESS;
    709 
    710     LogFlow(("vbsfOpenCreate: pszPath = %s, pParms = %p\n",
    711              pszPath, pParms));
    712 
    713     SHFLHANDLE      handle = SHFL_HANDLE_NIL;
    714     SHFLFILEHANDLE *pHandle;
    715 
    716     rc = vbsfOpenFile (&handle, pszPath, pParms, true);
    717     pHandle = (SHFLFILEHANDLE *)vbsfQueryHandle(handle, SHFL_HF_TYPE_FILE | SHFL_HF_TYPE_DIR);
    718     if (!pHandle)
    719     {
    720         AssertFailed();
    721         rc = VERR_INVALID_HANDLE;
    722     }
    723 
    724     if (VBOX_SUCCESS (rc))
    725     {
    726 #if 0
    727         if (!BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
    728         {
    729             /* @todo */
    730             RTFileSetSize(pHandle->file.Handle, pParms->Info.cbObject);
    731 
    732             RTFileSetTimes(pHandle->file.Handle,
    733                            &pParms->Info.AccessTime,
    734                            &pParms->Info.ModificationTime,
    735                            &pParms->Info.ChangeTime,
    736                            &pParms->Info.BirthTime
    737                           );
    738 
    739             RTFileSetMode (pHandle->file.Handle, pParms->Info.Attr.fMode);
    740         }
    741 #endif
    742 
    743         pParms->Result = SHFL_FILE_CREATED;
    744         pParms->Handle = handle;
    745     }
    746 
    747     LogFlow(("vbsfOpenCreate: rc = %Vrc\n", rc));
    748 
    749     return rc;
    750 }
    751 
     850    LogFlow(("vbsfOpenDir: rc = %Vrc\n", rc));
     851    return rc;
     852}
    752853
    753854static int vbsfCloseDir (SHFLFILEHANDLE *pHandle)
     
    789890}
    790891
    791 
     892/**
     893 * Look up file or folder information by host path.
     894 *
     895 * @returns iprt status code (currently VINF_SUCCESS)
     896 * @param   pszFullPath    The path of the file to be looked up
     897 * @retval  pParms->Result Status of the operation (success or error)
     898 * @retval  pParms->Info   On success, information returned about the file
     899 */
     900static int vbsfLookupFile(char *pszPath, SHFLCREATEPARMS *pParms)
     901{
     902    RTFSOBJINFO info;
     903    int rc;
     904
     905    rc = RTPathQueryInfo (pszPath, &info, RTFSOBJATTRADD_NOTHING);
     906    LogFlow(("SHFL_CF_LOOKUP\n"));
     907    /* Client just wants to know if the object exists. */
     908    switch (rc)
     909    {
     910        case VINF_SUCCESS:
     911        {
     912            pParms->Info = info;
     913            pParms->Result = SHFL_FILE_EXISTS;
     914            break;
     915        }
     916
     917        case VERR_FILE_NOT_FOUND:
     918        {
     919            pParms->Result = SHFL_FILE_NOT_FOUND;
     920            rc = VINF_SUCCESS;
     921            break;
     922        }
     923
     924        case VERR_PATH_NOT_FOUND:
     925        {
     926            pParms->Result = SHFL_PATH_NOT_FOUND;
     927            rc = VINF_SUCCESS;
     928            break;
     929        }
     930    }
     931    return rc;
     932}
     933
     934/**
     935 * Create or open a file or folder.  Perform character set and case
     936 * conversion on the file name if necessary.
     937 *
     938 * @returns IPRT status code, but see note below
     939 * @param   pClient        Data structure describing the client accessing the shared
     940 *                         folder
     941 * @param   root           The index of the shared folder in the table of mappings.
     942 *                         The host path of the shared folder is found using this.
     943 * @param   pPath          The path of the file or folder relative to the host path
     944 *                         indexed by root.
     945 * @param   cbPath         Presumably the length of the path in pPath.  Actually
     946 *                         ignored, as pPath contains a length parameter.
     947 * @param   pParms->Info   If a new file is created or an old one overwritten, set
     948 *                         these attributes
     949 * @retval  pParms->Result Shared folder result code, see include/VBox/shflsvc.h
     950 * @retval  pParms->Handle Shared folder handle to the newly opened file
     951 * @retval  pParms->Info   Attributes of the file or folder opened
     952 *
     953 * @note This function returns success if a "non-exceptional" error occurred,
     954 *       such as "no such file".  In this case, the caller should check the
     955 *       pParms->Result return value and whether pParms->Handle is valid.
     956 */
    792957int vbsfCreate (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, SHFLCREATEPARMS *pParms)
    793958{
     
    800965    /** @todo */
    801966
    802     /* Build a host full path for the given path
    803      * and convert ucs2 to utf8 if necessary.
     967    /* Build a host full path for the given path, handle file name case issues (if the guest
     968     * expects case-insensitive paths but the host is case-sensitive) and convert ucs2 to utf8 if
     969     * necessary.
    804970     */
    805971    char *pszFullPath = NULL;
     
    808974    rc = vbsfBuildFullPath (pClient, root, pPath, cbPath, &pszFullPath, &cbFullPathRoot);
    809975
    810     /* @todo This mess needs to change. RTFileOpen supports all the open/creation methods */
    811 
    812976    if (VBOX_SUCCESS (rc))
    813977    {
     
    816980        pParms->Handle = SHFL_HANDLE_NIL;
    817981
    818         /* Query path information. */
    819         RTFSOBJINFO info;
    820 
    821         /** r=bird: This is likely to create race conditions.
    822          * What is a file now can be a directory when you open it. */
    823         rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
    824         LogFlow(("RTPathQueryInfo returned %Vrc\n", rc));
    825 
    826982        if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_LOOKUP))
    827983        {
    828             LogFlow(("SHFL_CF_LOOKUP\n"));
    829             /* Client just wants to know if the object exists. */
    830             switch (rc)
    831             {
    832                 case VINF_SUCCESS:
     984            rc = vbsfLookupFile(pszFullPath, pParms);
     985        }
     986        else
     987        {
     988            /* Query path information. */
     989            RTFSOBJINFO info;
     990
     991            rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
     992            LogFlow(("RTPathQueryInfo returned %Vrc\n", rc));
     993
     994            if (RT_SUCCESS(rc))
     995            {
     996                /* Mark it as a directory in case the caller didn't. */
     997                /**
     998                  * @todo I left this in in order not to change the behaviour of the
     999                  *       function too much.  Is it really needed, and should it really be
     1000                  *       here?
     1001                  */
     1002                if (BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
    8331003                {
    834                     pParms->Info = info;
    835                     pParms->Result = SHFL_FILE_EXISTS;
    836                     break;
     1004                    pParms->CreateFlags |= SHFL_CF_DIRECTORY;
    8371005                }
    838 
    839                 case VERR_FILE_NOT_FOUND:
     1006                /**
     1007                  * @todo This should be in the Windows Guest Additions, as no-one else
     1008                  *       needs it.
     1009                  */
     1010                if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
    8401011                {
    841                     pParms->Result = SHFL_FILE_NOT_FOUND;
    842                     rc = VINF_SUCCESS;
    843                     break;
     1012                    vbsfStripLastComponent (pszFullPath, cbFullPathRoot);
     1013                    pParms->CreateFlags &= ~SHFL_CF_ACT_MASK_IF_EXISTS;
     1014                    pParms->CreateFlags &= ~SHFL_CF_ACT_MASK_IF_NEW;
     1015                    pParms->CreateFlags |= SHFL_CF_DIRECTORY;
     1016                    pParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
     1017                    pParms->CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
    8441018                }
    845 
    846                 case VERR_PATH_NOT_FOUND:
    847                 {
    848                     pParms->Result = SHFL_PATH_NOT_FOUND;
    849                     rc = VINF_SUCCESS;
    850                     break;
    851                 }
    852             }
    853         }
    854         else if (rc == VINF_SUCCESS)
    855         {
    856             /* File object exists. */
    857             pParms->Result = SHFL_FILE_EXISTS;
    858 
    859             /* Mark it as a directory in case the caller didn't. */
    860             if (BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
    861             {
    862                 pParms->CreateFlags |= SHFL_CF_DIRECTORY;
    863             }
    864 
    865             if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
    866             {
    867                 pParms->Info = info;
    868                 vbsfStripLastComponent (pszFullPath, cbFullPathRoot);
    869                 rc = vbsfOpenExisting (pszFullPath, pParms);
     1019            }
     1020            if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
     1021            {
     1022                rc = vbsfOpenDir (pszFullPath, pParms);
    8701023            }
    8711024            else
    8721025            {
    873                 if (    BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY)
    874                     && !BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
    875                 {
    876                     /* Caller wanted a directory but the existing object is not a directory.
    877                      * Do not open the object then.
    878                      */
    879                     ; /* do nothing */
    880                 }
    881                 else
    882                 {
    883                     switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
    884                     {
    885                         case SHFL_CF_ACT_OPEN_IF_EXISTS:
    886                         {
    887                             pParms->Info = info;
    888                             rc = vbsfOpenExisting (pszFullPath, pParms);
    889                             break;
    890                         }
    891 
    892                         case SHFL_CF_ACT_FAIL_IF_EXISTS:
    893                         {
    894                             /* NIL handle value will tell client that object was not opened.
    895                              * Just copy information about the object.
    896                              */
    897                             pParms->Info = info;
    898                             break;
    899                         }
    900 
    901                         case SHFL_CF_ACT_REPLACE_IF_EXISTS:
    902                         {
    903                             rc = vbsfOpenReplace (pszFullPath, pParms, true, &info);
    904                             break;
    905                         }
    906 
    907                         case SHFL_CF_ACT_OVERWRITE_IF_EXISTS:
    908                         {
    909                             rc = vbsfOpenReplace (pszFullPath, pParms, false, &info);
    910                             pParms->Info = info;
    911                             break;
    912                         }
    913 
    914                         default:
    915                         {
    916                             rc = VERR_INVALID_PARAMETER;
    917                         }
    918                     }
    919                 }
    920             }
    921         }
    922         else
    923         if (rc == VERR_FILE_NOT_FOUND)
    924         {
    925             LogFlow(("pParms->CreateFlags = %x\n", pParms->CreateFlags));
    926 
    927             rc = VINF_SUCCESS;
    928 
    929             /* File object does not exist. */
    930             pParms->Result = SHFL_FILE_NOT_FOUND;
    931 
    932             if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
    933             {
    934                 switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
    935                 {
    936                     case SHFL_CF_ACT_CREATE_IF_NEW:
    937                     {
    938                         rc = vbsfOpenCreate (pszFullPath, pParms);
    939                         break;
    940                     }
    941 
    942                     case SHFL_CF_ACT_FAIL_IF_NEW:
    943                     {
    944                         /* NIL handle value will tell client that object was not created. */
    945                         pParms->Result = SHFL_PATH_NOT_FOUND;
    946                         break;
    947                     }
    948 
    949                     default:
    950                     {
    951                         rc = VERR_INVALID_PARAMETER;
    952                         break;
    953                     }
    954                 }
    955             }
    956             else
    957             {
    958                 switch (BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
    959                 {
    960                     case SHFL_CF_ACT_CREATE_IF_NEW:
    961                     {
    962                         rc = vbsfOpenCreate (pszFullPath, pParms);
    963                         break;
    964                     }
    965 
    966                     case SHFL_CF_ACT_FAIL_IF_NEW:
    967                     {
    968                         /* NIL handle value will tell client that object was not created. */
    969                         break;
    970                     }
    971 
    972                     default:
    973                     {
    974                         rc = VERR_INVALID_PARAMETER;
    975                     }
    976                 }
    977             }
    978         }
    979         else
    980         if (rc == VERR_PATH_NOT_FOUND)
    981         {
    982             rc = VINF_SUCCESS;
    983  
    984             pParms->Result = SHFL_PATH_NOT_FOUND;
    985         }
    986 
    987         if (rc == VINF_SUCCESS && pParms->Handle != SHFL_HANDLE_NIL)
    988         {
    989             uint32_t bufsize = sizeof(pParms->Info);
    990 
    991             rc = vbsfQueryFileInfo(pClient, root, pParms->Handle, SHFL_INFO_GET|SHFL_INFO_FILE, &bufsize, (uint8_t *)&pParms->Info);
    992             AssertRC(rc);
     1026                rc = vbsfOpenFile (pszFullPath, pParms);
     1027            }
    9931028        }
    9941029
     
    16441679
    16451680#ifndef DEBUG_dmik
    1646         Assert(rc == VINF_SUCCESS || rc == VERR_DIR_NOT_EMPTY);
     1681        // VERR_ACCESS_DENIED for example?
     1682        // Assert(rc == VINF_SUCCESS || rc == VERR_DIR_NOT_EMPTY);
    16471683#endif
    16481684        /* free the path string */
  • trunk/src/VBox/Runtime/fileio.cpp

    r4372 r5258  
    128128    if (    (fOpen & (~RTFILE_O_VALID_MASK | RTFILE_O_NON_BLOCK))
    129129        ||  !(fOpen & RTFILE_O_ACCESS_MASK)
    130         ||  (fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_DENY_WRITE)) == RTFILE_O_TRUNCATE
     130        ||  (fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_WRITE)) == RTFILE_O_TRUNCATE
    131131       )
    132132    {
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