static DECLCALLBACK(int) drvHostParallelMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) { PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL); struct pollfd aFDs[2]; /* * We can wait for interrupts using poll on linux hosts. */ while (pThread->enmState == PDMTHREADSTATE_RUNNING) { int rc; aFDs[0].fd = RTFileToNative(pThis->hFileDevice); aFDs[0].events = POLLIN; aFDs[0].revents = 0; aFDs[1].fd = RTPipeToNative(pThis->hWakeupPipeR); aFDs[1].events = POLLIN | POLLERR | POLLHUP; aFDs[1].revents = 0; rc = poll(aFDs, RT_ELEMENTS(aFDs), -1); if (rc < 0) { AssertMsgFailed(("poll failed with rc=%d\n", RTErrConvertFromErrno(errno))); return RTErrConvertFromErrno(errno); } if (pThread->enmState != PDMTHREADSTATE_RUNNING) break; if (rc > 0 && aFDs[1].revents) { if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL)) break; /* notification to terminate -- drain the pipe */ char ch; size_t cbRead; RTPipeRead(pThis->hWakeupPipeR, &ch, 1, &cbRead); continue; } /* Interrupt occurred. */ rc = pThis->pDrvHostParallelPort->pfnNotifyInterrupt(pThis->pDrvHostParallelPort); AssertRC(rc); } return VINF_SUCCESS; }
RTDECL(int) RTFileAioReqPrepareFlush(RTFILEAIOREQ hReq, RTFILE hFile, void *pvUser) { PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)hReq; RTFILEAIOREQ_VALID_RETURN(pReqInt); Assert(hFile != NIL_RTFILE); RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS); pReqInt->fFlush = true; pReqInt->AioCB.aio_fildes = RTFileToNative(hFile); pReqInt->AioCB.aio_offset = 0; pReqInt->AioCB.aio_nbytes = 0; pReqInt->AioCB.aio_buf = NULL; pReqInt->pvUser = pvUser; RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); return VINF_SUCCESS; }
int VbCpuRepMsrProberInitPlatform(PVBCPUREPMSRACCESSORS pMsrAccessors) { RTFILE hFile; int rc = RTFileOpen(&hFile, MSR_DEV_NAME, RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN); if (RT_SUCCESS(rc)) { g_fdMsr = RTFileToNative(hFile); Assert(g_fdMsr != -1); pMsrAccessors->fAtomic = false; /* Can't modify/restore MSRs without trip to R3. */ pMsrAccessors->pfnMsrProberRead = linuxMsrProberRead; pMsrAccessors->pfnMsrProberWrite = linuxMsrProberWrite; pMsrAccessors->pfnMsrProberModify = linuxMsrProberModify; pMsrAccessors->pfnTerm = linuxMsrProberTerm; return VINF_SUCCESS; } vbCpuRepDebug("warning: Failed to open " MSR_DEV_NAME ": %Rrc\n", rc); return rc; }
/** * Destruct a host parallel driver instance. * * Most VM resources are freed by the VM. This callback is provided so that * any non-VM resources can be freed correctly. * * @param pDrvIns The driver instance data. */ static DECLCALLBACK(void) drvHostParallelDestruct(PPDMDRVINS pDrvIns) { int rc; PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL); LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); #ifndef VBOX_WITH_WIN_PARPORT_SUP if (pThis->hFileDevice != NIL_RTFILE) ioctl(RTFileToNative(pThis->hFileDevice), PPRELEASE); if (pThis->hWakeupPipeW != NIL_RTPIPE) { rc = RTPipeClose(pThis->hWakeupPipeW); AssertRC(rc); pThis->hWakeupPipeW = NIL_RTPIPE; } if (pThis->hWakeupPipeR != NIL_RTPIPE) { rc = RTPipeClose(pThis->hWakeupPipeR); AssertRC(rc); pThis->hWakeupPipeR = NIL_RTPIPE; } if (pThis->hFileDevice != NIL_RTFILE) { rc = RTFileClose(pThis->hFileDevice); AssertRC(rc); pThis->hFileDevice = NIL_RTFILE; } if (pThis->pszDevicePath) { MMR3HeapFree(pThis->pszDevicePath); pThis->pszDevicePath = NULL; } #else /* VBOX_WITH_WIN_PARPORT_SUP */ if (pThis->hWinFileDevice != NIL_RTFILE) { rc = RTFileClose(pThis->hWinFileDevice); AssertRC(rc); pThis->hWinFileDevice = NIL_RTFILE; } #endif /* VBOX_WITH_WIN_PARPORT_SUP */ }
RTR3DECL(int) RTFileSetSize(RTFILE hFile, uint64_t cbSize) { /* * Get current file pointer. */ int rc; uint64_t offCurrent; if (MySetFilePointer(hFile, 0, &offCurrent, FILE_CURRENT)) { /* * Set new file pointer. */ if (MySetFilePointer(hFile, cbSize, NULL, FILE_BEGIN)) { /* set file pointer */ if (SetEndOfFile((HANDLE)RTFileToNative(hFile))) { /* * Restore file pointer and return. * If the old pointer was beyond the new file end, ignore failure. */ if ( MySetFilePointer(hFile, offCurrent, NULL, FILE_BEGIN) || offCurrent > cbSize) return VINF_SUCCESS; } /* * Failed, try restoring the file pointer. */ rc = GetLastError(); MySetFilePointer(hFile, offCurrent, NULL, FILE_BEGIN); } else rc = GetLastError(); } else rc = GetLastError(); return RTErrConvertFromWin32(rc); }
/** * Changes the current mode of the host parallel port. * * @returns VBox status code. * @param pThis The host parallel port instance data. * @param enmMode The mode to change the port to. */ static int drvHostParallelSetMode(PDRVHOSTPARALLEL pThis, PDMPARALLELPORTMODE enmMode) { int iMode = 0; int rc = VINF_SUCCESS; LogFlowFunc(("mode=%d\n", enmMode)); # ifndef VBOX_WITH_WIN_PARPORT_SUP int rcLnx; if (pThis->enmModeCur != enmMode) { switch (enmMode) { case PDM_PARALLEL_PORT_MODE_SPP: iMode = IEEE1284_MODE_COMPAT; break; case PDM_PARALLEL_PORT_MODE_EPP_DATA: iMode = IEEE1284_MODE_EPP | IEEE1284_DATA; break; case PDM_PARALLEL_PORT_MODE_EPP_ADDR: iMode = IEEE1284_MODE_EPP | IEEE1284_ADDR; break; case PDM_PARALLEL_PORT_MODE_ECP: case PDM_PARALLEL_PORT_MODE_INVALID: default: return VERR_NOT_SUPPORTED; } rcLnx = ioctl(RTFileToNative(pThis->hFileDevice), PPSETMODE, &iMode); if (RT_UNLIKELY(rcLnx < 0)) rc = RTErrConvertFromErrno(errno); else pThis->enmModeCur = enmMode; } return rc; # else /* VBOX_WITH_WIN_PARPORT_SUP */ return VINF_SUCCESS; # endif /* VBOX_WITH_WIN_PARPORT_SUP */ }
RTR3DECL(int) RTFileSetTimes(RTFILE hFile, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime) { /* * We can only set AccessTime and ModificationTime, so if neither * are specified we can return immediately. */ if (!pAccessTime && !pModificationTime) return VINF_SUCCESS; /* * Convert the input to timeval, getting the missing one if necessary, * and call the API which does the change. */ struct timeval aTimevals[2]; if (pAccessTime && pModificationTime) { RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]); RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]); } else { RTFSOBJINFO ObjInfo; int rc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_UNIX); if (RT_FAILURE(rc)) return rc; RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]); RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]); } if (futimes(RTFileToNative(hFile), aTimevals)) { int rc = RTErrConvertFromErrno(errno); Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", hFile, pAccessTime, pModificationTime, rc)); return rc; } return VINF_SUCCESS; }
/** * @interface_method_impl{PDMIBASE,pfnWriteControl} */ static DECLCALLBACK(int) drvHostParallelWriteControl(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t fReg) { PDRVHOSTPARALLEL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPARALLEL, CTX_SUFF(IHostParallelConnector)); int rc = VINF_SUCCESS; int rcLnx = 0; LogFlowFunc(("fReg=%#x\n", fReg)); # ifndef VBOX_WITH_WIN_PARPORT_SUP rcLnx = ioctl(RTFileToNative(pThis->hFileDevice), PPWCONTROL, &fReg); if (RT_UNLIKELY(rcLnx < 0)) rc = RTErrConvertFromErrno(errno); # else /* VBOX_WITH_WIN_PARPORT_SUP */ uint64_t u64Data; u64Data = (uint8_t)fReg; if (pThis->fParportAvail) { LogFlowFunc(("calling R0 to write CTRL, data=%#x\n", u64Data)); rc = PDMDrvHlpCallR0(pThis->CTX_SUFF(pDrvIns), DRVHOSTPARALLELR0OP_WRITECONTROL, u64Data); AssertRC(rc); } # endif /* VBOX_WITH_WIN_PARPORT_SUP */ return rc; }
RTR3DECL(int) RTFileQueryFsSizes(RTFILE hFile, PRTFOFF pcbTotal, RTFOFF *pcbFree, uint32_t *pcbBlock, uint32_t *pcbSector) { struct statvfs StatVFS; RT_ZERO(StatVFS); if (fstatvfs(RTFileToNative(hFile), &StatVFS)) return RTErrConvertFromErrno(errno); /* * Calc the returned values. */ if (pcbTotal) *pcbTotal = (RTFOFF)StatVFS.f_blocks * StatVFS.f_frsize; if (pcbFree) *pcbFree = (RTFOFF)StatVFS.f_bavail * StatVFS.f_frsize; if (pcbBlock) *pcbBlock = StatVFS.f_frsize; /* no idea how to get the sector... */ if (pcbSector) *pcbSector = 512; return VINF_SUCCESS; }
RTR3DECL(bool) RTFileIsValid(RTFILE hFile) { if (hFile != NIL_RTFILE) { DWORD dwType = GetFileType((HANDLE)RTFileToNative(hFile)); switch (dwType) { case FILE_TYPE_CHAR: case FILE_TYPE_DISK: case FILE_TYPE_PIPE: case FILE_TYPE_REMOTE: return true; case FILE_TYPE_UNKNOWN: if (GetLastError() == NO_ERROR) return true; break; default: break; } } return false; }
static DECLCALLBACK(int) drvHostParallelSetPortDirection(PPDMIHOSTPARALLELCONNECTOR pInterface, bool fForward) { PDRVHOSTPARALLEL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPARALLEL, CTX_SUFF(IHostParallelConnector)); int rc = VINF_SUCCESS; int iMode = 0; if (!fForward) iMode = 1; # ifndef VBOX_WITH_WIN_PARPORT_SUP int rcLnx = ioctl(RTFileToNative(pThis->hFileDevice), PPDATADIR, &iMode); if (RT_UNLIKELY(rcLnx < 0)) rc = RTErrConvertFromErrno(errno); # else /* VBOX_WITH_WIN_PARPORT_SUP */ uint64_t u64Data; u64Data = (uint8_t)iMode; if (pThis->fParportAvail) { LogFlowFunc(("calling R0 to write CTRL, data=%#x\n", u64Data)); rc = PDMDrvHlpCallR0(pThis->CTX_SUFF(pDrvIns), DRVHOSTPARALLELR0OP_SETPORTDIRECTION, u64Data); AssertRC(rc); } # endif /* VBOX_WITH_WIN_PARPORT_SUP */ return rc; }
RTR3DECL(int) RTFileQueryInfo(RTFILE hFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs) { /* * Validate input. */ AssertReturn(hFile != NIL_RTFILE, VERR_INVALID_PARAMETER); AssertPtrReturn(pObjInfo, VERR_INVALID_PARAMETER); if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING || enmAdditionalAttribs > RTFSOBJATTRADD_LAST) { AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs)); return VERR_INVALID_PARAMETER; } /* * Query file info. */ struct stat Stat; if (fstat(RTFileToNative(hFile), &Stat)) { int rc = RTErrConvertFromErrno(errno); Log(("RTFileQueryInfo(%RTfile,,%d): returns %Rrc\n", hFile, enmAdditionalAttribs, rc)); return rc; } /* * Setup the returned data. */ rtFsConvertStatToObjInfo(pObjInfo, &Stat, NULL, 0); /* * Requested attributes (we cannot provide anything actually). */ switch (enmAdditionalAttribs) { case RTFSOBJATTRADD_NOTHING: case RTFSOBJATTRADD_UNIX: /* done */ break; case RTFSOBJATTRADD_UNIX_OWNER: rtFsObjInfoAttrSetUnixOwner(pObjInfo, Stat.st_uid); break; case RTFSOBJATTRADD_UNIX_GROUP: rtFsObjInfoAttrSetUnixGroup(pObjInfo, Stat.st_gid); break; case RTFSOBJATTRADD_EASIZE: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; pObjInfo->Attr.u.EASize.cb = 0; break; default: AssertMsgFailed(("Impossible!\n")); return VERR_INTERNAL_ERROR; } LogFlow(("RTFileQueryInfo(%RTfile,,%d): returns VINF_SUCCESS\n", hFile, enmAdditionalAttribs)); return VINF_SUCCESS; }
RTR3DECL(int) RTFileSetTimes(RTFILE hFile, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime) { NOREF(pChangeTime); NOREF(pBirthTime); /* * We can only set AccessTime and ModificationTime, so if neither * are specified we can return immediately. */ if (!pAccessTime && !pModificationTime) return VINF_SUCCESS; #ifdef USE_FUTIMENS struct timespec aTimespecs[2]; if (pAccessTime && pModificationTime) { memcpy(&aTimespecs[0], pAccessTime, sizeof(struct timespec)); memcpy(&aTimespecs[1], pModificationTime, sizeof(struct timespec)); } else { RTFSOBJINFO ObjInfo; int rc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_UNIX); if (RT_FAILURE(rc)) return rc; memcpy(&aTimespecs[0], pAccessTime ? pAccessTime : &ObjInfo.AccessTime, sizeof(struct timespec)); memcpy(&aTimespecs[1], pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, sizeof(struct timespec)); } if (futimens(RTFileToNative(hFile), aTimespecs)) { int rc = RTErrConvertFromErrno(errno); Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", hFile, pAccessTime, pModificationTime, rc)); return rc; } #else /* * Convert the input to timeval, getting the missing one if necessary, * and call the API which does the change. */ struct timeval aTimevals[2]; if (pAccessTime && pModificationTime) { RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]); RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]); } else { RTFSOBJINFO ObjInfo; int rc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_UNIX); if (RT_FAILURE(rc)) return rc; RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]); RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]); } /* XXX this falls back to utimes("/proc/self/fd/...",...) for older kernels/glibcs and this * will not work for hardened builds where this directory is owned by root.root and mode 0500 */ if (futimes(RTFileToNative(hFile), aTimevals)) { int rc = RTErrConvertFromErrno(errno); Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", hFile, pAccessTime, pModificationTime, rc)); return rc; } #endif return VINF_SUCCESS; }
/** * Construct a host parallel driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ static DECLCALLBACK(int) drvHostParallelConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL); LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); /* * Init basic data members and interfaces. * * Must be done before returning any failure because we've got a destructor. */ pThis->hFileDevice = NIL_RTFILE; #ifndef VBOX_WITH_WIN_PARPORT_SUP pThis->hWakeupPipeR = NIL_RTPIPE; pThis->hWakeupPipeW = NIL_RTPIPE; #else pThis->hWinFileDevice = NIL_RTFILE; #endif pThis->pDrvInsR3 = pDrvIns; #ifdef VBOX_WITH_DRVINTNET_IN_R0 pThis->pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns); #endif /* IBase. */ pDrvIns->IBase.pfnQueryInterface = drvHostParallelQueryInterface; /* IHostParallelConnector. */ pThis->IHostParallelConnectorR3.pfnWrite = drvHostParallelWrite; pThis->IHostParallelConnectorR3.pfnRead = drvHostParallelRead; pThis->IHostParallelConnectorR3.pfnSetPortDirection = drvHostParallelSetPortDirection; pThis->IHostParallelConnectorR3.pfnWriteControl = drvHostParallelWriteControl; pThis->IHostParallelConnectorR3.pfnReadControl = drvHostParallelReadControl; pThis->IHostParallelConnectorR3.pfnReadStatus = drvHostParallelReadStatus; /* * Validate the config. */ if (!CFGMR3AreValuesValid(pCfg, "DevicePath\0")) return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, N_("Unknown host parallel configuration option, only supports DevicePath")); /* * Query configuration. */ /* Device */ int rc = CFGMR3QueryStringAlloc(pCfg, "DevicePath", &pThis->pszDevicePath); if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Rra.\n", rc)); return rc; } /* * Open the device */ rc = RTFileOpen(&pThis->hFileDevice, pThis->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Parallel#%d could not open '%s'"), pDrvIns->iInstance, pThis->pszDevicePath); #ifndef VBOX_WITH_WIN_PARPORT_SUP /* * Try to get exclusive access to parallel port */ rc = ioctl(RTFileToNative(pThis->hFileDevice), PPEXCL); if (rc < 0) return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("Parallel#%d could not get exclusive access for parallel port '%s'" "Be sure that no other process or driver accesses this port"), pDrvIns->iInstance, pThis->pszDevicePath); /* * Claim the parallel port */ rc = ioctl(RTFileToNative(pThis->hFileDevice), PPCLAIM); if (rc < 0) return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("Parallel#%d could not claim parallel port '%s'" "Be sure that no other process or driver accesses this port"), pDrvIns->iInstance, pThis->pszDevicePath); /* * Get the IHostParallelPort interface of the above driver/device. */ pThis->pDrvHostParallelPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHOSTPARALLELPORT); if (!pThis->pDrvHostParallelPort) return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("Parallel#%d has no parallel port interface above"), pDrvIns->iInstance); /* * Create wakeup pipe. */ rc = RTPipeCreate(&pThis->hWakeupPipeR, &pThis->hWakeupPipeW, 0 /*fFlags*/); AssertRCReturn(rc, rc); /* * Start in SPP mode. */ pThis->enmModeCur = PDM_PARALLEL_PORT_MODE_INVALID; rc = drvHostParallelSetMode(pThis, PDM_PARALLEL_PORT_MODE_SPP); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostParallel#%d cannot change mode of parallel mode to SPP"), pDrvIns->iInstance); /* * Start waiting for interrupts. */ rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pMonitorThread, pThis, drvHostParallelMonitorThread, drvHostParallelWakeupMonitorThread, 0, RTTHREADTYPE_IO, "ParMon"); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostParallel#%d cannot create monitor thread"), pDrvIns->iInstance); #else /* VBOX_WITH_WIN_PARPORT_SUP */ pThis->fParportAvail = false; pThis->u32LptAddr = 0; pThis->u32LptAddrControl = 0; pThis->u32LptAddrStatus = 0; rc = drvWinHostGetparportAddr(pThis); /* If we have the char port availabe use it , else I am not getting exclusive access to parallel port. Read and write will be done only if addresses are available */ if (pThis->szParportName) { rc = RTFileOpen(&pThis->hWinFileDevice, (char *)pThis->szParportName, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); } #endif return VINF_SUCCESS; }
/** * Get the size of the given file. * Works for block devices too. * * @returns VBox status code. * @param hFile The file handle. * @param pcbSize Where to store the size of the file on success. */ static int pdmacFileEpNativeGetSize(RTFILE hFile, uint64_t *pcbSize) { int rc = VINF_SUCCESS; uint64_t cbSize = 0; rc = RTFileGetSize(hFile, &cbSize); if (RT_SUCCESS(rc) && (cbSize != 0)) *pcbSize = cbSize; else { #ifdef RT_OS_WINDOWS DISK_GEOMETRY DriveGeo; DWORD cbDriveGeo; if (DeviceIoControl((HANDLE)RTFileToNative(hFile), IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DriveGeo, sizeof(DriveGeo), &cbDriveGeo, NULL)) { if ( DriveGeo.MediaType == FixedMedia || DriveGeo.MediaType == RemovableMedia) { cbSize = DriveGeo.Cylinders.QuadPart * DriveGeo.TracksPerCylinder * DriveGeo.SectorsPerTrack * DriveGeo.BytesPerSector; GET_LENGTH_INFORMATION DiskLenInfo; DWORD junk; if (DeviceIoControl((HANDLE)RTFileToNative(hFile), IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &DiskLenInfo, sizeof(DiskLenInfo), &junk, (LPOVERLAPPED)NULL)) { /* IOCTL_DISK_GET_LENGTH_INFO is supported -- override cbSize. */ cbSize = DiskLenInfo.Length.QuadPart; } rc = VINF_SUCCESS; } else { rc = VERR_INVALID_PARAMETER; } } else rc = RTErrConvertFromWin32(GetLastError()); #elif defined(RT_OS_DARWIN) struct stat DevStat; if (!fstat(RTFileToNative(hFile), &DevStat) && S_ISBLK(DevStat.st_mode)) { uint64_t cBlocks; uint32_t cbBlock; if (!ioctl(RTFileToNative(hFile), DKIOCGETBLOCKCOUNT, &cBlocks)) { if (!ioctl(RTFileToNative(hFile), DKIOCGETBLOCKSIZE, &cbBlock)) cbSize = cBlocks * cbBlock; else rc = RTErrConvertFromErrno(errno); } else rc = RTErrConvertFromErrno(errno); } else rc = VERR_INVALID_PARAMETER; #elif defined(RT_OS_SOLARIS) struct stat DevStat; if ( !fstat(RTFileToNative(hFile), &DevStat) && ( S_ISBLK(DevStat.st_mode) || S_ISCHR(DevStat.st_mode))) { struct dk_minfo mediainfo; if (!ioctl(RTFileToNative(hFile), DKIOCGMEDIAINFO, &mediainfo)) cbSize = mediainfo.dki_capacity * mediainfo.dki_lbsize; else rc = RTErrConvertFromErrno(errno); } else rc = VERR_INVALID_PARAMETER; #elif defined(RT_OS_FREEBSD) struct stat DevStat; if (!fstat(RTFileToNative(hFile), &DevStat) && S_ISCHR(DevStat.st_mode)) { off_t cbMedia = 0; if (!ioctl(RTFileToNative(hFile), DIOCGMEDIASIZE, &cbMedia)) { cbSize = cbMedia; } else rc = RTErrConvertFromErrno(errno); } else rc = VERR_INVALID_PARAMETER; #else /* Could be a block device */ rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, &cbSize); #endif if (RT_SUCCESS(rc) && (cbSize != 0)) *pcbSize = cbSize; else if (RT_SUCCESS(rc)) rc = VERR_NOT_SUPPORTED; } return rc; }
/** * Reap URBs in-flight on a device. * * @returns Pointer to a completed URB. * @returns NULL if no URB was completed. * @param pProxyDev The device. * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all. */ static DECLCALLBACK(PVUSBURB) usbProxySolarisUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies) { //LogFlowFunc((USBPROXY ":usbProxySolarisUrbReap pProxyDev=%p cMillies=%u\n", pProxyDev, cMillies)); PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL); /* * Don't block if nothing is in the air. */ if (!pDevSol->pInFlightHead) return NULL; /* * Deque URBs inflight or those landed. */ if (cMillies > 0) { for (;;) { int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies; struct pollfd pfd[2]; pfd[0].fd = RTFileToNative(pDevSol->hFile); pfd[0].events = POLLIN; pfd[0].revents = 0; pfd[1].fd = RTPipeToNative(pDevSol->hPipeWakeupR); pfd[1].events = POLLIN; pfd[1].revents = 0; int rc = poll(&pfd[0], 2, cMilliesWait); if (rc > 0) { if (pfd[0].revents & POLLHUP) { LogRel((USBPROXY ":Reaping failed, USB Device '%s' disconnected!\n", pDevSol->pProxyDev->pUsbIns->pszName)); pProxyDev->fDetached = true; usbProxySolarisCloseFile(pDevSol); } if (pfd[1].revents & POLLIN) { /* Got woken up, drain pipe. */ uint8_t bRead; size_t cbIgnored = 0; RTPipeRead(pDevSol->hPipeWakeupR, &bRead, 1, &cbIgnored); /* * It is possible that we got woken up and have an URB pending * for completion. Do it on the way out. Otherwise return * immediately to the caller. */ if (!(pfd[0].revents & POLLIN)) return NULL; } break; } if (rc == 0) { //LogFlow((USBPROXY ":usbProxySolarisUrbReap: Timed out\n")); return NULL; } else if (rc != EAGAIN) { LogFlow((USBPROXY ":usbProxySolarisUrbReap Poll rc=%d errno=%d\n", rc, errno)); return NULL; } } } usbProxySolarisUrbComplete(pDevSol); /* * Any URBs pending delivery? */ PVUSBURB pUrb = NULL; while (pDevSol->pTaxingHead) { RTCritSectEnter(&pDevSol->CritSect); PUSBPROXYURBSOL pUrbSol = pDevSol->pTaxingHead; if (pUrbSol) { pUrb = pUrbSol->pVUsbUrb; if (pUrb) { pUrb->Dev.pvPrivate = NULL; usbProxySolarisUrbFree(pDevSol, pUrbSol); } } RTCritSectLeave(&pDevSol->CritSect); } return pUrb; }
DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir, void *pvBuf, uint32_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies) { /* * Minimal input validation. */ Assert(enmTxDir == PDMMEDIATXDIR_NONE || enmTxDir == PDMMEDIATXDIR_FROM_DEVICE || enmTxDir == PDMMEDIATXDIR_TO_DEVICE); Assert(!pvBuf || pcbBuf); Assert(pvBuf || enmTxDir == PDMMEDIATXDIR_NONE); Assert(pbSense || !cbSense); RT_NOREF(cbSense); AssertPtr(pbCmd); Assert(cbCmd <= 16 && cbCmd >= 1); /* Allocate the temporary buffer lazily. */ if(RT_UNLIKELY(!pThis->Os.pbDoubleBuffer)) { pThis->Os.pbDoubleBuffer = (uint8_t *)RTMemAlloc(SCSI_MAX_BUFFER_SIZE); if (!pThis->Os.pbDoubleBuffer) return VERR_NO_MEMORY; } int rc = VERR_GENERAL_FAILURE; int direction; struct cdrom_generic_command cgc; switch (enmTxDir) { case PDMMEDIATXDIR_NONE: Assert(*pcbBuf == 0); direction = CGC_DATA_NONE; break; case PDMMEDIATXDIR_FROM_DEVICE: Assert(*pcbBuf != 0); Assert(*pcbBuf <= SCSI_MAX_BUFFER_SIZE); /* Make sure that the buffer is clear for commands reading * data. The actually received data may be shorter than what * we expect, and due to the unreliable feedback about how much * data the ioctl actually transferred, it's impossible to * prevent that. Returning previous buffer contents may cause * security problems inside the guest OS, if users can issue * commands to the CDROM device. */ memset(pThis->Os.pbDoubleBuffer, '\0', *pcbBuf); direction = CGC_DATA_READ; break; case PDMMEDIATXDIR_TO_DEVICE: Assert(*pcbBuf != 0); Assert(*pcbBuf <= SCSI_MAX_BUFFER_SIZE); memcpy(pThis->Os.pbDoubleBuffer, pvBuf, *pcbBuf); direction = CGC_DATA_WRITE; break; default: AssertMsgFailed(("enmTxDir invalid!\n")); direction = CGC_DATA_NONE; } memset(&cgc, '\0', sizeof(cgc)); memcpy(cgc.cmd, pbCmd, RT_MIN(CDROM_PACKET_SIZE, cbCmd)); cgc.buffer = (unsigned char *)pThis->Os.pbDoubleBuffer; cgc.buflen = *pcbBuf; cgc.stat = 0; Assert(cbSense >= sizeof(struct request_sense)); cgc.sense = (struct request_sense *)pbSense; cgc.data_direction = direction; cgc.quiet = false; cgc.timeout = cTimeoutMillies; rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_SEND_PACKET, &cgc); if (rc < 0) { if (errno == EBUSY) rc = VERR_PDM_MEDIA_LOCKED; else if (errno == ENOSYS) rc = VERR_NOT_SUPPORTED; else { rc = RTErrConvertFromErrno(errno); if (rc == VERR_ACCESS_DENIED && cgc.sense->sense_key == SCSI_SENSE_NONE) cgc.sense->sense_key = SCSI_SENSE_ILLEGAL_REQUEST; Log2(("%s: error status %d, rc=%Rrc\n", __FUNCTION__, cgc.stat, rc)); } } switch (enmTxDir) { case PDMMEDIATXDIR_FROM_DEVICE: memcpy(pvBuf, pThis->Os.pbDoubleBuffer, *pcbBuf); break; default: ; } Log2(("%s: after ioctl: cgc.buflen=%d txlen=%d\n", __FUNCTION__, cgc.buflen, *pcbBuf)); /* The value of cgc.buflen does not reliably reflect the actual amount * of data transferred (for packet commands with little data transfer * it's 0). So just assume that everything worked ok. */ return rc; }
static int drvscsihostProcessRequestOne(PDRVSCSIHOST pThis, PPDMSCSIREQUEST pRequest) { int rc = VINF_SUCCESS; unsigned uTxDir; LogFlowFunc(("Entered\n")); #ifdef DEBUG drvscsihostDumpScsiRequest(pRequest); #endif /* We implement only one device. */ if (pRequest->uLogicalUnit != 0) { switch (pRequest->pbCDB[0]) { case SCSI_INQUIRY: { SCSIINQUIRYDATA ScsiInquiryReply; memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply)); ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN; ScsiInquiryReply.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED; drvscsihostScatterGatherListCopyFromBuffer(pRequest, &ScsiInquiryReply, sizeof(SCSIINQUIRYDATA)); drvscsihostCmdOk(pRequest); break; } default: AssertMsgFailed(("Command not implemented for attached device\n")); drvscsiCmdError(pRequest, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_NONE); } } else { #if defined(RT_OS_LINUX) sg_io_hdr_t ScsiIoReq; sg_iovec_t *paSG = NULL; /* Setup SCSI request. */ memset(&ScsiIoReq, 0, sizeof(sg_io_hdr_t)); ScsiIoReq.interface_id = 'S'; if (pRequest->uDataDirection == PDMSCSIREQUESTTXDIR_UNKNOWN) uTxDir = drvscsihostGetTransferDirectionFromCommand(pRequest->pbCDB[0]); else uTxDir = pRequest->uDataDirection; if (uTxDir == PDMSCSIREQUESTTXDIR_NONE) ScsiIoReq.dxfer_direction = SG_DXFER_NONE; else if (uTxDir == PDMSCSIREQUESTTXDIR_TO_DEVICE) ScsiIoReq.dxfer_direction = SG_DXFER_TO_DEV; else if (uTxDir == PDMSCSIREQUESTTXDIR_FROM_DEVICE) ScsiIoReq.dxfer_direction = SG_DXFER_FROM_DEV; else AssertMsgFailed(("Invalid transfer direction %u\n", uTxDir)); ScsiIoReq.cmd_len = pRequest->cbCDB; ScsiIoReq.mx_sb_len = pRequest->cbSenseBuffer; ScsiIoReq.dxfer_len = pRequest->cbScatterGather; if (pRequest->cScatterGatherEntries > 0) { if (pRequest->cScatterGatherEntries == 1) { ScsiIoReq.iovec_count = 0; ScsiIoReq.dxferp = pRequest->paScatterGatherHead[0].pvSeg; } else { ScsiIoReq.iovec_count = pRequest->cScatterGatherEntries; paSG = (sg_iovec_t *)RTMemAllocZ(pRequest->cScatterGatherEntries * sizeof(sg_iovec_t)); AssertReturn(paSG, VERR_NO_MEMORY); for (unsigned i = 0; i < pRequest->cScatterGatherEntries; i++) { paSG[i].iov_base = pRequest->paScatterGatherHead[i].pvSeg; paSG[i].iov_len = pRequest->paScatterGatherHead[i].cbSeg; } ScsiIoReq.dxferp = paSG; } } ScsiIoReq.cmdp = pRequest->pbCDB; ScsiIoReq.sbp = pRequest->pbSenseBuffer; ScsiIoReq.timeout = UINT_MAX; ScsiIoReq.flags |= SG_FLAG_DIRECT_IO; /* Issue command. */ rc = ioctl(RTFileToNative(pThis->hDeviceFile), SG_IO, &ScsiIoReq); if (rc < 0) { AssertMsgFailed(("Ioctl failed with rc=%d\n", rc)); } /* Request processed successfully. */ Log(("Command successfully processed\n")); if (ScsiIoReq.iovec_count > 0) RTMemFree(paSG); #endif } /* Notify device that request finished. */ rc = pThis->pDevScsiPort->pfnSCSIRequestCompleted(pThis->pDevScsiPort, pRequest, SCSI_STATUS_OK, false, VINF_SUCCESS); AssertMsgRC(rc, ("Notifying device above failed rc=%Rrc\n", rc)); return rc; }
RTR3DECL(int) RTFileRead(RTFILE hFile, void *pvBuf, size_t cbToRead, size_t *pcbRead) { if (cbToRead <= 0) return VINF_SUCCESS; ULONG cbToReadAdj = (ULONG)cbToRead; AssertReturn(cbToReadAdj == cbToRead, VERR_NUMBER_TOO_BIG); ULONG cbRead = 0; if (ReadFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToReadAdj, &cbRead, NULL)) { if (pcbRead) /* Caller can handle partial reads. */ *pcbRead = cbRead; else { /* Caller expects everything to be read. */ while (cbToReadAdj > cbRead) { ULONG cbReadPart = 0; if (!ReadFile((HANDLE)RTFileToNative(hFile), (char*)pvBuf + cbRead, cbToReadAdj - cbRead, &cbReadPart, NULL)) return RTErrConvertFromWin32(GetLastError()); if (cbReadPart == 0) return VERR_EOF; cbRead += cbReadPart; } } return VINF_SUCCESS; } /* * If it's a console, we might bump into out of memory conditions in the * ReadConsole call. */ DWORD dwErr = GetLastError(); if (dwErr == ERROR_NOT_ENOUGH_MEMORY) { ULONG cbChunk = cbToReadAdj / 2; if (cbChunk > 16*_1K) cbChunk = 16*_1K; else cbChunk = RT_ALIGN_32(cbChunk, 256); cbRead = 0; while (cbToReadAdj > cbRead) { ULONG cbToRead = RT_MIN(cbChunk, cbToReadAdj - cbRead); ULONG cbReadPart = 0; if (!ReadFile((HANDLE)RTFileToNative(hFile), (char *)pvBuf + cbRead, cbToRead, &cbReadPart, NULL)) { /* If we failed because the buffer is too big, shrink it and try again. */ dwErr = GetLastError(); if ( dwErr == ERROR_NOT_ENOUGH_MEMORY && cbChunk > 8) { cbChunk /= 2; continue; } return RTErrConvertFromWin32(dwErr); } cbRead += cbReadPart; /* Return if the caller can handle partial reads, otherwise try fill the buffer all the way up. */ if (pcbRead) { *pcbRead = cbRead; break; } if (cbReadPart == 0) return VERR_EOF; } return VINF_SUCCESS; } return RTErrConvertFromWin32(dwErr); }
DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir, void *pvBuf, uint32_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies) { /* * Minimal input validation. */ Assert(enmTxDir == PDMMEDIATXDIR_NONE || enmTxDir == PDMMEDIATXDIR_FROM_DEVICE || enmTxDir == PDMMEDIATXDIR_TO_DEVICE); Assert(!pvBuf || pcbBuf); Assert(pvBuf || enmTxDir == PDMMEDIATXDIR_NONE); Assert(pbSense || !cbSense); AssertPtr(pbCmd); Assert(cbCmd <= 16 && cbCmd >= 1); const uint32_t cbBuf = pcbBuf ? *pcbBuf : 0; if (pcbBuf) *pcbBuf = 0; int rc = VINF_SUCCESS; int rcBSD = 0; union ccb DeviceCCB; union ccb *pDeviceCCB = &DeviceCCB; u_int32_t fFlags; memset(pDeviceCCB, 0, sizeof(DeviceCCB)); pDeviceCCB->ccb_h.path_id = pThis->Os.ScsiBus; pDeviceCCB->ccb_h.target_id = pThis->Os.ScsiTargetID; pDeviceCCB->ccb_h.target_lun = pThis->Os.ScsiLunID; /* The SCSI INQUIRY command can't be passed through directly. */ if (pbCmd[0] == SCSI_INQUIRY) { pDeviceCCB->ccb_h.func_code = XPT_GDEV_TYPE; rcBSD = ioctl(RTFileToNative(pThis->Os.hFileDevice), CAMIOCOMMAND, pDeviceCCB); if (!rcBSD) { uint32_t cbCopy = cbBuf < sizeof(struct scsi_inquiry_data) ? cbBuf : sizeof(struct scsi_inquiry_data);; memcpy(pvBuf, &pDeviceCCB->cgd.inq_data, cbCopy); memset(pbSense, 0, cbSense); if (pcbBuf) *pcbBuf = cbCopy; } else rc = RTErrConvertFromErrno(errno); } else { /* Copy the CDB. */ memcpy(&pDeviceCCB->csio.cdb_io.cdb_bytes, pbCmd, cbCmd); /* Set direction. */ if (enmTxDir == PDMMEDIATXDIR_NONE) fFlags = CAM_DIR_NONE; else if (enmTxDir == PDMMEDIATXDIR_FROM_DEVICE) fFlags = CAM_DIR_IN; else fFlags = CAM_DIR_OUT; fFlags |= CAM_DEV_QFRZDIS; cam_fill_csio(&pDeviceCCB->csio, 1, NULL, fFlags, MSG_SIMPLE_Q_TAG, (u_int8_t *)pvBuf, cbBuf, cbSense, cbCmd, cTimeoutMillies ? cTimeoutMillies : 30000/* timeout */); /* Send command */ rcBSD = ioctl(RTFileToNative(pThis->Os.hFileDevice), CAMIOCOMMAND, pDeviceCCB); if (!rcBSD) { switch (pDeviceCCB->ccb_h.status & CAM_STATUS_MASK) { case CAM_REQ_CMP: rc = VINF_SUCCESS; break; case CAM_SEL_TIMEOUT: rc = VERR_DEV_IO_ERROR; break; case CAM_CMD_TIMEOUT: rc = VERR_TIMEOUT; break; default: rc = VERR_DEV_IO_ERROR; } if (pcbBuf) *pcbBuf = cbBuf - pDeviceCCB->csio.resid; if (pbSense) memcpy(pbSense, &pDeviceCCB->csio.sense_data, cbSense - pDeviceCCB->csio.sense_resid); } else rc = RTErrConvertFromErrno(errno); } }
/** * Reap URBs in-flight on a device. * * @returns Pointer to a completed URB. * @returns NULL if no URB was completed. * @param pProxyDev The device. * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all. */ static PVUSBURB usbProxyFreeBSDUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies) { struct usb_fs_endpoint *pXferEndpoint; PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD) pProxyDev->Backend.pv; PUSBENDPOINTFBSD pEndpointFBSD; PVUSBURB pUrb; struct usb_fs_complete UsbFsComplete; struct pollfd PollFd; int rc; LogFlow(("usbProxyFreeBSDUrbReap: pProxyDev=%p, cMillies=%u\n", pProxyDev, cMillies)); repeat: pUrb = NULL; /* check for cancelled transfers */ if (pDevFBSD->fCancelling) { for (unsigned n = 0; n < USBFBSD_MAXENDPOINTS; n++) { pEndpointFBSD = &pDevFBSD->aSwEndpoint[n]; if (pEndpointFBSD->fCancelling) { pEndpointFBSD->fCancelling = false; pUrb = pEndpointFBSD->pUrb; pEndpointFBSD->pUrb = NULL; if (pUrb != NULL) break; } } if (pUrb != NULL) { pUrb->enmStatus = VUSBSTATUS_INVALID; pUrb->Dev.pvPrivate = NULL; switch (pUrb->enmType) { case VUSBXFERTYPE_MSG: pUrb->cbData = 0; break; case VUSBXFERTYPE_ISOC: pUrb->cbData = 0; for (int n = 0; n < (int)pUrb->cIsocPkts; n++) pUrb->aIsocPkts[n].cb = 0; break; default: pUrb->cbData = 0; break; } return pUrb; } pDevFBSD->fCancelling = false; } /* Zero default */ memset(&UsbFsComplete, 0, sizeof(UsbFsComplete)); /* Check if any endpoints are complete */ rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_COMPLETE, &UsbFsComplete, true); if (RT_SUCCESS(rc)) { pXferEndpoint = &pDevFBSD->aHwEndpoint[UsbFsComplete.ep_index]; pEndpointFBSD = &pDevFBSD->aSwEndpoint[UsbFsComplete.ep_index]; LogFlow(("usbProxyFreeBSDUrbReap: Reaped " "URB %#p\n", pEndpointFBSD->pUrb)); if (pXferEndpoint->status == USB_ERR_CANCELLED) goto repeat; pUrb = pEndpointFBSD->pUrb; pEndpointFBSD->pUrb = NULL; if (pUrb == NULL) goto repeat; switch (pXferEndpoint->status) { case USB_ERR_NORMAL_COMPLETION: pUrb->enmStatus = VUSBSTATUS_OK; break; case USB_ERR_STALLED: pUrb->enmStatus = VUSBSTATUS_STALL; break; default: pUrb->enmStatus = VUSBSTATUS_INVALID; break; } pUrb->Dev.pvPrivate = NULL; switch (pUrb->enmType) { case VUSBXFERTYPE_MSG: pUrb->cbData = pEndpointFBSD->acbData[0] + pEndpointFBSD->acbData[1]; break; case VUSBXFERTYPE_ISOC: { int n; if (pUrb->enmDir == VUSBDIRECTION_OUT) break; pUrb->cbData = 0; for (n = 0; n < (int)pUrb->cIsocPkts; n++) { if (n >= (int)pEndpointFBSD->cMaxFrames) break; pUrb->cbData += pEndpointFBSD->acbData[n]; pUrb->aIsocPkts[n].cb = pEndpointFBSD->acbData[n]; } for (; n < (int)pUrb->cIsocPkts; n++) pUrb->aIsocPkts[n].cb = 0; break; } default: pUrb->cbData = pEndpointFBSD->acbData[0]; break; } LogFlow(("usbProxyFreeBSDUrbReap: Status=%d epindex=%u " "len[0]=%d len[1]=%d\n", (int)pXferEndpoint->status, (unsigned)UsbFsComplete.ep_index, (unsigned)pEndpointFBSD->acbData[0], (unsigned)pEndpointFBSD->acbData[1])); } else if (cMillies && rc == VERR_RESOURCE_BUSY) { /* Poll for finished transfers */ PollFd.fd = RTFileToNative(pDevFBSD->hFile); PollFd.events = POLLIN | POLLRDNORM; PollFd.revents = 0; rc = poll(&PollFd, 1, (cMillies == RT_INDEFINITE_WAIT) ? INFTIM : cMillies); if (rc >= 1) { goto repeat; } else { LogFlow(("usbProxyFreeBSDUrbReap: " "poll returned rc=%d\n", rc)); } } return pUrb; }
/** * Internal wrapper around various OS specific ioctl implementations. * * @returns VBox status code as returned by VBoxGuestCommonIOCtl, or * an failure returned by the OS specific ioctl APIs. * * @param iFunction The requested function. * @param pvData The input and output data buffer. * @param cbData The size of the buffer. * * @remark Exactly how the VBoxGuestCommonIOCtl is ferried back * here is OS specific. On BSD and Darwin we can use errno, * while on OS/2 we use the 2nd buffer of the IOCtl. */ int vbglR3DoIOCtl(unsigned iFunction, void *pvData, size_t cbData) { #if defined(RT_OS_WINDOWS) DWORD cbReturned = 0; if (!DeviceIoControl(g_hFile, iFunction, pvData, (DWORD)cbData, pvData, (DWORD)cbData, &cbReturned, NULL)) { /** @todo The passing of error codes needs to be tested and fixed (as does *all* the other hosts except for * OS/2). The idea is that the VBox status codes in ring-0 should be transferred without loss down to * ring-3. However, it's not vitally important right now (obviously, since the other guys has been * ignoring it for 1+ years now). On Linux and Solaris the transfer is done, but it is currently not * lossless, so still needs fixing. */ DWORD LastErr = GetLastError(); return RTErrConvertFromWin32(LastErr); } return VINF_SUCCESS; #elif defined(RT_OS_OS2) ULONG cbOS2Parm = cbData; int32_t vrc = VERR_INTERNAL_ERROR; ULONG cbOS2Data = sizeof(vrc); APIRET rc = DosDevIOCtl((uintptr_t)g_File, VBOXGUEST_IOCTL_CATEGORY, iFunction, pvData, cbData, &cbOS2Parm, &vrc, sizeof(vrc), &cbOS2Data); if (RT_LIKELY(!rc)) return vrc; return RTErrConvertFromOS2(rc); #elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) VBGLBIGREQ Hdr; Hdr.u32Magic = VBGLBIGREQ_MAGIC; Hdr.cbData = cbData; Hdr.pvDataR3 = pvData; # if HC_ARCH_BITS == 32 Hdr.u32Padding = 0; # endif /** @todo test status code passing! Check that the kernel doesn't do any * error checks using specific errno values, and just pass an VBox * error instead of an errno.h one. Alternatively, extend/redefine the * header with an error code return field (much better alternative * actually). */ #ifdef VBOX_VBGLR3_XFREE86 int rc = xf86ioctl(g_File, iFunction, &Hdr); #else int rc = ioctl(RTFileToNative(g_File), iFunction, &Hdr); #endif if (rc == -1) { rc = errno; return RTErrConvertFromErrno(rc); } return VINF_SUCCESS; #elif defined(RT_OS_LINUX) # ifdef VBOX_VBGLR3_XFREE86 int rc = xf86ioctl((int)g_File, iFunction, pvData); # else if (g_File == NIL_RTFILE) return VERR_INVALID_HANDLE; int rc = ioctl(RTFileToNative(g_File), iFunction, pvData); # endif if (RT_LIKELY(rc == 0)) return VINF_SUCCESS; /* Positive values are negated VBox error status codes. */ if (rc > 0) rc = -rc; else # ifdef VBOX_VBGLR3_XFREE86 rc = VERR_FILE_IO_ERROR; # else rc = RTErrConvertFromErrno(errno); # endif NOREF(cbData); return rc; #elif defined(VBOX_VBGLR3_XFREE86) /* PORTME - This is preferred over the RTFileIOCtl variant below, just be careful with the (int). */ /** @todo test status code passing! */ int rc = xf86ioctl(g_File, iFunction, pvData); if (rc == -1) return VERR_FILE_IO_ERROR; /* This is purely legacy stuff, it has to work and no more. */ return VINF_SUCCESS; #else /* Default implementation - PORTME: Do not use this without testings that passing errors works! */ /** @todo test status code passing! */ int rc2 = VERR_INTERNAL_ERROR; int rc = RTFileIoCtl(g_File, (int)iFunction, pvData, cbData, &rc2); if (RT_SUCCESS(rc)) rc = rc2; return rc; #endif }
RTR3DECL(int) RTFileWrite(RTFILE hFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten) { if (cbToWrite <= 0) return VINF_SUCCESS; ULONG cbToWriteAdj = (ULONG)cbToWrite; AssertReturn(cbToWriteAdj == cbToWrite, VERR_NUMBER_TOO_BIG); ULONG cbWritten = 0; if (WriteFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToWriteAdj, &cbWritten, NULL)) { if (pcbWritten) /* Caller can handle partial writes. */ *pcbWritten = cbWritten; else { /* Caller expects everything to be written. */ while (cbToWriteAdj > cbWritten) { ULONG cbWrittenPart = 0; if (!WriteFile((HANDLE)RTFileToNative(hFile), (char*)pvBuf + cbWritten, cbToWriteAdj - cbWritten, &cbWrittenPart, NULL)) { int rc = RTErrConvertFromWin32(GetLastError()); if ( rc == VERR_DISK_FULL && IsBeyondLimit(hFile, cbToWriteAdj - cbWritten, FILE_CURRENT) ) rc = VERR_FILE_TOO_BIG; return rc; } if (cbWrittenPart == 0) return VERR_WRITE_ERROR; cbWritten += cbWrittenPart; } } return VINF_SUCCESS; } /* * If it's a console, we might bump into out of memory conditions in the * WriteConsole call. */ DWORD dwErr = GetLastError(); if (dwErr == ERROR_NOT_ENOUGH_MEMORY) { ULONG cbChunk = cbToWriteAdj / 2; if (cbChunk > _32K) cbChunk = _32K; else cbChunk = RT_ALIGN_32(cbChunk, 256); cbWritten = 0; while (cbToWriteAdj > cbWritten) { ULONG cbToWrite = RT_MIN(cbChunk, cbToWriteAdj - cbWritten); ULONG cbWrittenPart = 0; if (!WriteFile((HANDLE)RTFileToNative(hFile), (const char *)pvBuf + cbWritten, cbToWrite, &cbWrittenPart, NULL)) { /* If we failed because the buffer is too big, shrink it and try again. */ dwErr = GetLastError(); if ( dwErr == ERROR_NOT_ENOUGH_MEMORY && cbChunk > 8) { cbChunk /= 2; continue; } int rc = RTErrConvertFromWin32(dwErr); if ( rc == VERR_DISK_FULL && IsBeyondLimit(hFile, cbToWriteAdj - cbWritten, FILE_CURRENT)) rc = VERR_FILE_TOO_BIG; return rc; } cbWritten += cbWrittenPart; /* Return if the caller can handle partial writes, otherwise try write out everything. */ if (pcbWritten) { *pcbWritten = cbWritten; break; } if (cbWrittenPart == 0) return VERR_WRITE_ERROR; } return VINF_SUCCESS; } int rc = RTErrConvertFromWin32(dwErr); if ( rc == VERR_DISK_FULL && IsBeyondLimit(hFile, cbToWriteAdj - cbWritten, FILE_CURRENT)) rc = VERR_FILE_TOO_BIG; return rc; }
RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags, PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser, const char *pszPassword, PRTPROCESS phProcess) { int rc; /* * Input validation */ AssertPtrReturn(pszExec, VERR_INVALID_POINTER); AssertReturn(*pszExec, VERR_INVALID_PARAMETER); AssertReturn(!(fFlags & ~RTPROC_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER); AssertReturn(!(fFlags & RTPROC_FLAGS_DETACHED) || !phProcess, VERR_INVALID_PARAMETER); AssertReturn(hEnv != NIL_RTENV, VERR_INVALID_PARAMETER); AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pszAsUser, VERR_INVALID_POINTER); AssertReturn(!pszAsUser || *pszAsUser, VERR_INVALID_PARAMETER); AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER); #if defined(RT_OS_OS2) if (fFlags & RTPROC_FLAGS_DETACHED) return VERR_PROC_DETACH_NOT_SUPPORTED; #endif /* * Get the file descriptors for the handles we've been passed. */ PCRTHANDLE paHandles[3] = { phStdIn, phStdOut, phStdErr }; int aStdFds[3] = { -1, -1, -1 }; for (int i = 0; i < 3; i++) { if (paHandles[i]) { AssertPtrReturn(paHandles[i], VERR_INVALID_POINTER); switch (paHandles[i]->enmType) { case RTHANDLETYPE_FILE: aStdFds[i] = paHandles[i]->u.hFile != NIL_RTFILE ? (int)RTFileToNative(paHandles[i]->u.hFile) : -2 /* close it */; break; case RTHANDLETYPE_PIPE: aStdFds[i] = paHandles[i]->u.hPipe != NIL_RTPIPE ? (int)RTPipeToNative(paHandles[i]->u.hPipe) : -2 /* close it */; break; case RTHANDLETYPE_SOCKET: aStdFds[i] = paHandles[i]->u.hSocket != NIL_RTSOCKET ? (int)RTSocketToNative(paHandles[i]->u.hSocket) : -2 /* close it */; break; default: AssertMsgFailedReturn(("%d: %d\n", i, paHandles[i]->enmType), VERR_INVALID_PARAMETER); } /** @todo check the close-on-execness of these handles? */ } } for (int i = 0; i < 3; i++) if (aStdFds[i] == i) aStdFds[i] = -1; for (int i = 0; i < 3; i++) AssertMsgReturn(aStdFds[i] < 0 || aStdFds[i] > i, ("%i := %i not possible because we're lazy\n", i, aStdFds[i]), VERR_NOT_SUPPORTED); /* * Resolve the user id if specified. */ uid_t uid = ~(uid_t)0; gid_t gid = ~(gid_t)0; if (pszAsUser) { rc = rtCheckCredentials(pszAsUser, pszPassword, &gid, &uid); if (RT_FAILURE(rc)) return rc; } /* * Create the child environment if either RTPROC_FLAGS_PROFILE or * RTPROC_FLAGS_ENV_CHANGE_RECORD are in effect. */ RTENV hEnvToUse = hEnv; if ( (fFlags & (RTPROC_FLAGS_ENV_CHANGE_RECORD | RTPROC_FLAGS_PROFILE)) && ( (fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD) || hEnv == RTENV_DEFAULT) ) { if (fFlags & RTPROC_FLAGS_PROFILE) rc = rtProcPosixCreateProfileEnv(&hEnvToUse, pszAsUser); else rc = RTEnvClone(&hEnvToUse, RTENV_DEFAULT); if (RT_SUCCESS(rc)) { if ((fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD) && hEnv != RTENV_DEFAULT) rc = RTEnvApplyChanges(hEnvToUse, hEnv); if (RT_FAILURE(rc)) RTEnvDestroy(hEnvToUse); } if (RT_FAILURE(rc)) return rc; } /* * Check for execute access to the file. */ char szRealExec[RTPATH_MAX]; if (access(pszExec, X_OK)) { rc = errno; if ( !(fFlags & RTPROC_FLAGS_SEARCH_PATH) || rc != ENOENT || RTPathHavePath(pszExec) ) rc = RTErrConvertFromErrno(rc); else { /* search */ char *pszPath = RTEnvDupEx(hEnvToUse, "PATH"); rc = RTPathTraverseList(pszPath, ':', rtPathFindExec, (void *)pszExec, &szRealExec[0]); RTStrFree(pszPath); if (RT_SUCCESS(rc)) pszExec = szRealExec; else rc = rc == VERR_END_OF_STRING ? VERR_FILE_NOT_FOUND : rc; } if (RT_FAILURE(rc)) return rtProcPosixCreateReturn(rc, hEnvToUse, hEnv); } pid_t pid = -1; const char * const *papszEnv = RTEnvGetExecEnvP(hEnvToUse); AssertPtrReturn(papszEnv, rtProcPosixCreateReturn(VERR_INVALID_HANDLE, hEnvToUse, hEnv)); /* * Take care of detaching the process. * * HACK ALERT! Put the process into a new process group with pgid = pid * to make sure it differs from that of the parent process to ensure that * the IPRT waitpid call doesn't race anyone (read XPCOM) doing group wide * waits. setsid() includes the setpgid() functionality. * 2010-10-11 XPCOM no longer waits for anything, but it cannot hurt. */ #ifndef RT_OS_OS2 if (fFlags & RTPROC_FLAGS_DETACHED) { # ifdef RT_OS_SOLARIS int templateFd = -1; if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) { templateFd = rtSolarisContractPreFork(); if (templateFd == -1) return rtProcPosixCreateReturn(VERR_OPEN_FAILED, hEnvToUse, hEnv); } # endif /* RT_OS_SOLARIS */ pid = fork(); if (!pid) { # ifdef RT_OS_SOLARIS if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) rtSolarisContractPostForkChild(templateFd); # endif setsid(); /* see comment above */ pid = -1; /* Child falls through to the actual spawn code below. */ } else { # ifdef RT_OS_SOLARIS if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) rtSolarisContractPostForkParent(templateFd, pid); # endif if (pid > 0) { /* Must wait for the temporary process to avoid a zombie. */ int status = 0; pid_t pidChild = 0; /* Restart if we get interrupted. */ do { pidChild = waitpid(pid, &status, 0); } while ( pidChild == -1 && errno == EINTR); /* Assume that something wasn't found. No detailed info. */ if (status) return rtProcPosixCreateReturn(VERR_PROCESS_NOT_FOUND, hEnvToUse, hEnv); if (phProcess) *phProcess = 0; return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv); } return rtProcPosixCreateReturn(RTErrConvertFromErrno(errno), hEnvToUse, hEnv); } } #endif /* * Spawn the child. * * Any spawn code MUST not execute any atexit functions if it is for a * detached process. It would lead to running the atexit functions which * make only sense for the parent. libORBit e.g. gets confused by multiple * execution. Remember, there was only a fork() so far, and until exec() * is successfully run there is nothing which would prevent doing anything * silly with the (duplicated) file descriptors. */ #ifdef HAVE_POSIX_SPAWN /** @todo OS/2: implement DETACHED (BACKGROUND stuff), see VbglR3Daemonize. */ if ( uid == ~(uid_t)0 && gid == ~(gid_t)0) { /* Spawn attributes. */ posix_spawnattr_t Attr; rc = posix_spawnattr_init(&Attr); if (!rc) { /* Indicate that process group and signal mask are to be changed, and that the child should use default signal actions. */ rc = posix_spawnattr_setflags(&Attr, POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF); Assert(rc == 0); /* The child starts in its own process group. */ if (!rc) { rc = posix_spawnattr_setpgroup(&Attr, 0 /* pg == child pid */); Assert(rc == 0); } /* Unmask all signals. */ if (!rc) { sigset_t SigMask; sigemptyset(&SigMask); rc = posix_spawnattr_setsigmask(&Attr, &SigMask); Assert(rc == 0); } /* File changes. */ posix_spawn_file_actions_t FileActions; posix_spawn_file_actions_t *pFileActions = NULL; if ((aStdFds[0] != -1 || aStdFds[1] != -1 || aStdFds[2] != -1) && !rc) { rc = posix_spawn_file_actions_init(&FileActions); if (!rc) { pFileActions = &FileActions; for (int i = 0; i < 3; i++) { int fd = aStdFds[i]; if (fd == -2) rc = posix_spawn_file_actions_addclose(&FileActions, i); else if (fd >= 0 && fd != i) { rc = posix_spawn_file_actions_adddup2(&FileActions, fd, i); if (!rc) { for (int j = i + 1; j < 3; j++) if (aStdFds[j] == fd) { fd = -1; break; } if (fd >= 0) rc = posix_spawn_file_actions_addclose(&FileActions, fd); } } if (rc) break; } } } if (!rc) rc = posix_spawn(&pid, pszExec, pFileActions, &Attr, (char * const *)papszArgs, (char * const *)papszEnv); /* cleanup */ int rc2 = posix_spawnattr_destroy(&Attr); Assert(rc2 == 0); NOREF(rc2); if (pFileActions) { rc2 = posix_spawn_file_actions_destroy(pFileActions); Assert(rc2 == 0); } /* return on success.*/ if (!rc) { /* For a detached process this happens in the temp process, so * it's not worth doing anything as this process must exit. */ if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(0); if (phProcess) *phProcess = pid; return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv); } } /* For a detached process this happens in the temp process, so * it's not worth doing anything as this process must exit. */ if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(124); } else #endif { #ifdef RT_OS_SOLARIS int templateFd = -1; if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) { templateFd = rtSolarisContractPreFork(); if (templateFd == -1) return rtProcPosixCreateReturn(VERR_OPEN_FAILED, hEnvToUse, hEnv); } #endif /* RT_OS_SOLARIS */ pid = fork(); if (!pid) { #ifdef RT_OS_SOLARIS if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) rtSolarisContractPostForkChild(templateFd); #endif /* RT_OS_SOLARIS */ if (!(fFlags & RTPROC_FLAGS_DETACHED)) setpgid(0, 0); /* see comment above */ /* * Change group and user if requested. */ #if 1 /** @todo This needs more work, see suplib/hardening. */ if (pszAsUser) { int ret = initgroups(pszAsUser, gid); if (ret) { if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(126); else exit(126); } } if (gid != ~(gid_t)0) { if (setgid(gid)) { if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(126); else exit(126); } } if (uid != ~(uid_t)0) { if (setuid(uid)) { if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(126); else exit(126); } } #endif /* * Some final profile environment tweaks, if running as user. */ if ( (fFlags & RTPROC_FLAGS_PROFILE) && pszAsUser && ( (fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD) || hEnv == RTENV_DEFAULT) ) { rc = rtProcPosixAdjustProfileEnvFromChild(hEnvToUse, fFlags, hEnv); papszEnv = RTEnvGetExecEnvP(hEnvToUse); if (RT_FAILURE(rc) || !papszEnv) { if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(126); else exit(126); } } /* * Unset the signal mask. */ sigset_t SigMask; sigemptyset(&SigMask); rc = sigprocmask(SIG_SETMASK, &SigMask, NULL); Assert(rc == 0); /* * Apply changes to the standard file descriptor and stuff. */ for (int i = 0; i < 3; i++) { int fd = aStdFds[i]; if (fd == -2) close(i); else if (fd >= 0) { int rc2 = dup2(fd, i); if (rc2 != i) { if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(125); else exit(125); } for (int j = i + 1; j < 3; j++) if (aStdFds[j] == fd) { fd = -1; break; } if (fd >= 0) close(fd); } } /* * Finally, execute the requested program. */ rc = execve(pszExec, (char * const *)papszArgs, (char * const *)papszEnv); if (errno == ENOEXEC) { /* This can happen when trying to start a shell script without the magic #!/bin/sh */ RTAssertMsg2Weak("Cannot execute this binary format!\n"); } else RTAssertMsg2Weak("execve returns %d errno=%d\n", rc, errno); RTAssertReleasePanic(); if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(127); else exit(127); } #ifdef RT_OS_SOLARIS if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT)) rtSolarisContractPostForkParent(templateFd, pid); #endif /* RT_OS_SOLARIS */ if (pid > 0) { /* For a detached process this happens in the temp process, so * it's not worth doing anything as this process must exit. */ if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(0); if (phProcess) *phProcess = pid; return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv); } /* For a detached process this happens in the temp process, so * it's not worth doing anything as this process must exit. */ if (fFlags & RTPROC_FLAGS_DETACHED) _Exit(124); return rtProcPosixCreateReturn(RTErrConvertFromErrno(errno), hEnvToUse, hEnv); } return rtProcPosixCreateReturn(VERR_NOT_IMPLEMENTED, hEnvToUse, hEnv); }
RTR3DECL(int) RTFileQueryInfo(RTFILE hFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs) { /* * Validate input. */ if (hFile == NIL_RTFILE) { AssertMsgFailed(("Invalid hFile=%RTfile\n", hFile)); return VERR_INVALID_PARAMETER; } if (!pObjInfo) { AssertMsgFailed(("Invalid pObjInfo=%p\n", pObjInfo)); return VERR_INVALID_PARAMETER; } if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING || enmAdditionalAttribs > RTFSOBJATTRADD_LAST) { AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs)); return VERR_INVALID_PARAMETER; } /* * Query file info. */ BY_HANDLE_FILE_INFORMATION Data; if (!GetFileInformationByHandle((HANDLE)RTFileToNative(hFile), &Data)) { DWORD dwErr = GetLastError(); /* Only return if we *really* don't have a valid handle value, * everything else is fine here ... */ if (dwErr == ERROR_INVALID_HANDLE) return RTErrConvertFromWin32(dwErr); RT_ZERO(Data); Data.dwFileAttributes = RTFS_DOS_NT_DEVICE; } /* * Setup the returned data. */ pObjInfo->cbObject = ((uint64_t)Data.nFileSizeHigh << 32) | (uint64_t)Data.nFileSizeLow; pObjInfo->cbAllocated = pObjInfo->cbObject; Assert(sizeof(uint64_t) == sizeof(Data.ftCreationTime)); RTTimeSpecSetNtTime(&pObjInfo->BirthTime, *(uint64_t *)&Data.ftCreationTime); RTTimeSpecSetNtTime(&pObjInfo->AccessTime, *(uint64_t *)&Data.ftLastAccessTime); RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, *(uint64_t *)&Data.ftLastWriteTime); pObjInfo->ChangeTime = pObjInfo->ModificationTime; pObjInfo->Attr.fMode = rtFsModeFromDos((Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, "", 0); /* * Requested attributes (we cannot provide anything actually). */ switch (enmAdditionalAttribs) { case RTFSOBJATTRADD_NOTHING: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; break; case RTFSOBJATTRADD_UNIX: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX; pObjInfo->Attr.u.Unix.uid = ~0U; pObjInfo->Attr.u.Unix.gid = ~0U; pObjInfo->Attr.u.Unix.cHardlinks = Data.nNumberOfLinks ? Data.nNumberOfLinks : 1; pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */ pObjInfo->Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */ pObjInfo->Attr.u.Unix.fFlags = 0; pObjInfo->Attr.u.Unix.GenerationId = 0; pObjInfo->Attr.u.Unix.Device = 0; break; case RTFSOBJATTRADD_UNIX_OWNER: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; pObjInfo->Attr.u.UnixOwner.uid = ~0U; pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ break; case RTFSOBJATTRADD_UNIX_GROUP: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; pObjInfo->Attr.u.UnixGroup.gid = ~0U; pObjInfo->Attr.u.UnixGroup.szName[0] = '\0'; break; case RTFSOBJATTRADD_EASIZE: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; pObjInfo->Attr.u.EASize.cb = 0; break; default: AssertMsgFailed(("Impossible!\n")); return VERR_INTERNAL_ERROR; } return VINF_SUCCESS; }
/** * Reap URBs in-flight on a device. * * @returns Pointer to a completed URB. * @returns NULL if no URB was completed. * @param pProxyDev The device. * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all. */ static DECLCALLBACK(PVUSBURB) usbProxyFreeBSDUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies) { struct usb_fs_endpoint *pXferEndpoint; PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD); PUSBENDPOINTFBSD pEndpointFBSD; PVUSBURB pUrb; struct usb_fs_complete UsbFsComplete; struct pollfd pfd[2]; int rc; LogFlow(("usbProxyFreeBSDUrbReap: pProxyDev=%p, cMillies=%u\n", pProxyDev, cMillies)); repeat: pUrb = NULL; /* check for cancelled transfers */ if (pDevFBSD->fCancelling) { for (unsigned n = 0; n < USBFBSD_MAXENDPOINTS; n++) { pEndpointFBSD = &pDevFBSD->aSwEndpoint[n]; if (pEndpointFBSD->fCancelling) { pEndpointFBSD->fCancelling = false; pUrb = pEndpointFBSD->pUrb; pEndpointFBSD->pUrb = NULL; if (pUrb != NULL) break; } } if (pUrb != NULL) { pUrb->enmStatus = VUSBSTATUS_INVALID; pUrb->Dev.pvPrivate = NULL; switch (pUrb->enmType) { case VUSBXFERTYPE_MSG: pUrb->cbData = 0; break; case VUSBXFERTYPE_ISOC: pUrb->cbData = 0; for (int n = 0; n < (int)pUrb->cIsocPkts; n++) pUrb->aIsocPkts[n].cb = 0; break; default: pUrb->cbData = 0; break; } return pUrb; } pDevFBSD->fCancelling = false; } /* Zero default */ memset(&UsbFsComplete, 0, sizeof(UsbFsComplete)); /* Check if any endpoints are complete */ rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_COMPLETE, &UsbFsComplete, true); if (RT_SUCCESS(rc)) { pXferEndpoint = &pDevFBSD->aHwEndpoint[UsbFsComplete.ep_index]; pEndpointFBSD = &pDevFBSD->aSwEndpoint[UsbFsComplete.ep_index]; LogFlow(("usbProxyFreeBSDUrbReap: Reaped " "URB %#p\n", pEndpointFBSD->pUrb)); if (pXferEndpoint->status == USB_ERR_CANCELLED) goto repeat; pUrb = pEndpointFBSD->pUrb; pEndpointFBSD->pUrb = NULL; if (pUrb == NULL) goto repeat; switch (pXferEndpoint->status) { case USB_ERR_NORMAL_COMPLETION: pUrb->enmStatus = VUSBSTATUS_OK; break; case USB_ERR_STALLED: pUrb->enmStatus = VUSBSTATUS_STALL; break; default: pUrb->enmStatus = VUSBSTATUS_INVALID; break; } pUrb->Dev.pvPrivate = NULL; switch (pUrb->enmType) { case VUSBXFERTYPE_MSG: pUrb->cbData = pEndpointFBSD->acbData[0] + pEndpointFBSD->acbData[1]; break; case VUSBXFERTYPE_ISOC: { int n; if (pUrb->enmDir == VUSBDIRECTION_OUT) break; pUrb->cbData = 0; for (n = 0; n < (int)pUrb->cIsocPkts; n++) { if (n >= (int)pEndpointFBSD->cMaxFrames) break; pUrb->cbData += pEndpointFBSD->acbData[n]; pUrb->aIsocPkts[n].cb = pEndpointFBSD->acbData[n]; } for (; n < (int)pUrb->cIsocPkts; n++) pUrb->aIsocPkts[n].cb = 0; break; } default: pUrb->cbData = pEndpointFBSD->acbData[0]; break; } LogFlow(("usbProxyFreeBSDUrbReap: Status=%d epindex=%u " "len[0]=%d len[1]=%d\n", (int)pXferEndpoint->status, (unsigned)UsbFsComplete.ep_index, (unsigned)pEndpointFBSD->acbData[0], (unsigned)pEndpointFBSD->acbData[1])); } else if (cMillies != 0 && rc == VERR_RESOURCE_BUSY) { for (;;) { pfd[0].fd = RTFileToNative(pDevFBSD->hFile); pfd[0].events = POLLIN | POLLRDNORM; pfd[0].revents = 0; pfd[1].fd = RTPipeToNative(pDevFBSD->hPipeWakeupR); pfd[1].events = POLLIN | POLLRDNORM; pfd[1].revents = 0; rc = poll(pfd, 2, (cMillies == RT_INDEFINITE_WAIT) ? INFTIM : cMillies); if (rc > 0) { if (pfd[1].revents & POLLIN) { /* Got woken up, drain pipe. */ uint8_t bRead; size_t cbIgnored = 0; RTPipeRead(pDevFBSD->hPipeWakeupR, &bRead, 1, &cbIgnored); /* Make sure we return from this function */ cMillies = 0; } break; } if (rc == 0) return NULL; if (errno != EAGAIN) return NULL; } goto repeat; } return pUrb; }
DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly) { RT_NOREF(fReadOnly); RTFILE hFileDevice; int rc = RTFileOpen(&hFileDevice, pThis->pszDevice, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); if (RT_FAILURE(rc)) return rc; /* * The current device handle can't passthrough SCSI commands. * We have to get he passthrough device path and open this. */ union ccb DeviceCCB; memset(&DeviceCCB, 0, sizeof(DeviceCCB)); DeviceCCB.ccb_h.func_code = XPT_GDEVLIST; int rcBSD = ioctl(RTFileToNative(hFileDevice), CAMGETPASSTHRU, &DeviceCCB); if (!rcBSD) { char *pszPassthroughDevice = NULL; rc = RTStrAPrintf(&pszPassthroughDevice, "/dev/%s%u", DeviceCCB.cgdl.periph_name, DeviceCCB.cgdl.unit_number); if (rc >= 0) { RTFILE hPassthroughDevice; rc = RTFileOpen(&hPassthroughDevice, pszPassthroughDevice, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); RTStrFree(pszPassthroughDevice); if (RT_SUCCESS(rc)) { /* Get needed device parameters. */ /* * The device path, target id and lun id. Those are * needed for the SCSI passthrough ioctl. */ memset(&DeviceCCB, 0, sizeof(DeviceCCB)); DeviceCCB.ccb_h.func_code = XPT_GDEVLIST; rcBSD = ioctl(RTFileToNative(hPassthroughDevice), CAMGETPASSTHRU, &DeviceCCB); if (!rcBSD) { if (DeviceCCB.cgdl.status != CAM_GDEVLIST_ERROR) { pThis->Os.ScsiBus = DeviceCCB.ccb_h.path_id; pThis->Os.ScsiTargetID = DeviceCCB.ccb_h.target_id; pThis->Os.ScsiLunID = DeviceCCB.ccb_h.target_lun; pThis->Os.hFileDevice = hPassthroughDevice; } else { /* The passthrough device wasn't found. */ rc = VERR_NOT_FOUND; } } else rc = RTErrConvertFromErrno(errno); if (RT_FAILURE(rc)) RTFileClose(hPassthroughDevice); } } else rc = VERR_NO_STR_MEMORY; } else rc = RTErrConvertFromErrno(errno); RTFileClose(hFileDevice); return rc; }