Changeset 891 in vbox
- Timestamp:
- Feb 14, 2007 9:35:20 AM (18 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/posix/rand-posix.cpp
r839 r891 1 1 /* $Id$ */ 2 2 /** @file 3 * InnoTek Portable Runtime - File I/O, POSIX.3 * InnoTek Portable Runtime - Random Numbers and Byte Streams, POSIX. 4 4 */ 5 5 … … 24 24 * Header Files * 25 25 *******************************************************************************/ 26 #define LOG_GROUP RTLOGGROUP_FILE27 28 26 #include <errno.h> 29 27 #include <sys/stat.h> … … 39 37 # include <sys/time.h> 40 38 #endif 41 #if defined(__OS2__) && (!defined(__INNOTEK_LIBC__) || __INNOTEK_LIBC__ < 0x006)42 # include <io.h>43 #endif44 #ifdef __L4__45 /* This is currently ifdef'ed out in the relevant L4 header file */46 /* Same as `utimes', but takes an open file descriptor instead of a name. */47 extern int futimes (int __fd, __const struct timeval __tvp[2]) __THROW;48 #endif49 39 50 #include <iprt/ file.h>51 #include <iprt/ path.h>40 #include <iprt/rand.h> 41 #include <iprt/err.h> 52 42 #include <iprt/assert.h> 53 #include <iprt/string.h> 54 #include <iprt/err.h> 55 #include <iprt/log.h> 56 #include "internal/file.h" 57 #include "internal/fs.h" 58 #include "internal/path.h" 59 43 #include "internal/rand.h" 60 44 61 45 62 46 /******************************************************************************* 63 * Defined Constants And Macros*47 * Global Variables * 64 48 *******************************************************************************/ 65 /** @def RT_DONT_CONVERT_FILENAMES 66 * Define this to pass UTF-8 unconverted to the kernel. */ 67 #ifdef __DOXYGEN__ 68 #define RT_DONT_CONVERT_FILENAMES 1 69 #endif 70 71 /** Default file permissions for newly created files. */ 72 #if defined(S_IRUSR) && defined(S_IWUSR) 73 # define RT_FILE_PERMISSION (S_IRUSR | S_IWUSR) 74 #else 75 # define RT_FILE_PERMISSION (00600) 76 #endif 49 /** File handle of /dev/random. */ 50 static int g_fhDevRandom = -1; 77 51 78 52 79 RTR3DECL(int) RTFileOpen(PRTFILE pFile, const char *pszFilename, unsigned fOpen)53 void rtRandLazyInitNative(void) 80 54 { 81 /* 82 * Validate input. 83 */ 84 if (!VALID_PTR(pFile)) 85 { 86 AssertMsgFailed(("Invalid pFile %p\n", pFile)); 87 return VERR_INVALID_PARAMETER; 88 } 89 *pFile = NIL_RTFILE; 90 if (!VALID_PTR(pszFilename)) 91 { 92 AssertMsgFailed(("Invalid pszFilename %p\n", pszFilename)); 93 return VERR_INVALID_PARAMETER; 94 } 55 if (g_fhDevRandom != -1) 56 return; 95 57 96 /* 97 * Merge forced open flags and validate them. 98 */ 99 int rc = rtFileRecalcAndValidateFlags(&fOpen); 100 if (RT_FAILURE(rc)) 101 return rc; 102 #ifndef O_NONBLOCK 103 if (fOpen & RTFILE_O_NON_BLOCK) 104 { 105 AssertMsgFailed(("Invalid parameters! fOpen=%#x\n", fOpen)); 106 return VERR_INVALID_PARAMETER; 107 } 108 #endif 109 110 /* 111 * Calculate open mode flags. 112 */ 113 int fOpenMode = 0; 114 #ifdef O_BINARY 115 fOpenMode |= O_BINARY; /* (pc) */ 116 #endif 117 #ifdef O_LARGEFILE 118 fOpenMode |= O_LARGEFILE; /* (linux) */ 119 #endif 120 #ifdef O_NOINHERIT 121 if (!(fOpen & RTFILE_O_INHERIT)) 122 fOpenMode |= O_NOINHERIT; 123 #endif 124 #ifndef O_NONBLOCK 125 if (fOpen & RTFILE_O_NON_BLOCK) 126 fOpenMode |= O_NONBLOCK 127 #endif 128 #ifdef O_SYNC 129 if (fOpen & RTFILE_O_WRITE_THROUGH) 130 fOpenMode |= O_SYNC; 131 #endif 132 133 /* create/truncate file */ 134 switch (fOpen & RTFILE_O_ACTION_MASK) 135 { 136 case RTFILE_O_OPEN: break; 137 case RTFILE_O_OPEN_CREATE: fOpenMode |= O_CREAT; break; 138 case RTFILE_O_CREATE: fOpenMode |= O_CREAT | O_EXCL; break; 139 case RTFILE_O_CREATE_REPLACE: fOpenMode |= O_CREAT | O_TRUNC; break; /** @todo replacing needs fixing, this is *not* a 1:1 mapping! */ 140 } 141 if (fOpen & RTFILE_O_TRUNCATE) 142 fOpenMode |= O_TRUNC; 143 144 switch (fOpen & RTFILE_O_ACCESS_MASK) 145 { 146 case RTFILE_O_READ: fOpenMode |= O_RDONLY; break; 147 case RTFILE_O_WRITE: fOpenMode |= O_WRONLY; break; 148 case RTFILE_O_READWRITE: fOpenMode |= O_RDWR; break; 149 default: 150 AssertMsgFailed(("RTFileOpen received an invalid RW value, fOpen=%#x\n", fOpen)); 151 return VERR_INVALID_PARAMETER; 152 } 153 154 /** @todo sharing! */ 155 156 /* 157 * Open/create the file. 158 */ 159 #ifdef RT_DONT_CONVERT_FILENAMES 160 int fh = open(pszFilename, fOpenMode, RT_FILE_PERMISSION); 161 int iErr = errno; 162 #else 163 char *pszNativeFilename; 164 rc = rtPathToNative(&pszNativeFilename, pszFilename); 165 if (RT_FAILURE(rc)) 166 return (rc); 167 168 int fh = open(pszNativeFilename, fOpenMode, RT_FILE_PERMISSION); 169 int iErr = errno; 170 rtPathFreeNative(pszNativeFilename); 171 #endif 58 int fh = open("/dev/urandom", O_RDONLY); 59 if (fh <= 0) 60 fh = open("/dev/random", O_RDONLY | O_NONBLOCK); 172 61 if (fh >= 0) 173 62 { 174 /* 175 * Mark the file handle close on exec, unless inherit is specified. 176 */ 177 if ( !(fOpen & RTFILE_O_INHERIT) 178 #ifdef O_NOINHERIT 179 || (fOpenMode & O_NOINHERIT) /* careful since it could be a dummy. */ 180 #endif 181 || fcntl(fh, F_SETFD, FD_CLOEXEC) >= 0) 182 { 183 *pFile = (RTFILE)fh; 184 Assert((int)*pFile == fh); 185 LogFlow(("RTFileOpen(%p:{%RTfile}, %p:{%s}, %#x): returns %Rrc\n", 186 pFile, *pFile, pszFilename, pszFilename, fOpen, rc)); 187 return VINF_SUCCESS; 188 } 189 iErr = errno; 190 close(fh); 63 fcntl(fh, F_SETFD, FD_CLOEXEC); 64 g_fhDevRandom = fh; 191 65 } 192 return RTErrConvertFromErrno(iErr);193 66 } 194 67 195 68 196 RTR3DECL(int) RTFileClose(RTFILE File)69 int rtRandGenBytesNative(void *pv, size_t cb) 197 70 { 198 if (close((int)File) == 0) 199 return VINF_SUCCESS; 200 return RTErrConvertFromErrno(errno); 201 } 71 int fh = g_fhDevRandom; 72 if (fh == -1) 73 return VERR_NOT_SUPPORTED; 202 74 203 204 RTR3DECL(int) RTFileDelete(const char *pszFilename) 205 { 206 char *pszNativeFilename; 207 int rc = rtPathToNative(&pszNativeFilename, pszFilename); 208 if (RT_SUCCESS(rc)) 75 ssize_t cbRead = read(fh, pv, cb); 76 if ((size_t)cbRead != cb) 209 77 { 210 if (unlink(pszNativeFilename) != 0) 211 rc = RTErrConvertFromErrno(errno); 212 rtPathFreeNative(pszNativeFilename); 213 } 214 return rc; 215 } 216 217 218 RTR3DECL(int) RTFileSeek(RTFILE File, int64_t offSeek, unsigned uMethod, uint64_t *poffActual) 219 { 220 static const unsigned aSeekRecode[] = 221 { 222 SEEK_SET, 223 SEEK_CUR, 224 SEEK_END, 225 }; 226 227 /* 228 * Validate input. 229 */ 230 if (uMethod > RTFILE_SEEK_END) 231 { 232 AssertMsgFailed(("Invalid uMethod=%d\n", uMethod)); 233 return VERR_INVALID_PARAMETER; 234 } 235 236 /* check that within off_t range. */ 237 if ( sizeof(off_t) < sizeof(offSeek) 238 && ( (offSeek > 0 && (unsigned)(offSeek >> 32) != 0) 239 || (offSeek < 0 && (unsigned)(-offSeek >> 32) != 0))) 240 { 241 AssertMsgFailed(("64-bit search not supported\n")); 242 return VERR_NOT_SUPPORTED; 243 } 244 245 off_t offCurrent = lseek((int)File, (off_t)offSeek, aSeekRecode[uMethod]); 246 if (offCurrent != ~0) 247 { 248 if (poffActual) 249 *poffActual = (uint64_t)offCurrent; 250 return VINF_SUCCESS; 251 } 252 return RTErrConvertFromErrno(errno); 253 } 254 255 256 RTR3DECL(int) RTFileRead(RTFILE File, void *pvBuf, unsigned cbToRead, unsigned *pcbRead) 257 { 258 if (cbToRead <= 0) 259 return VINF_SUCCESS; 260 261 /* 262 * Attempt read. 263 */ 264 ssize_t cbRead = read((int)File, pvBuf, cbToRead); 265 if (cbRead >= 0) 266 { 267 if (pcbRead) 268 /* caller can handle partial read. */ 269 *pcbRead = cbRead; 270 else 78 /* 79 * Use the fallback for the remainder if /dev/urandom / /dev/random 80 * is out to lunch. 81 */ 82 if (cbRead <= 0) 83 rtRandGenBytesFallback(pv, cb); 84 else 271 85 { 272 /* Caller expects all to be read. */ 273 while ((ssize_t)cbToRead > cbRead) 274 { 275 ssize_t cbReadPart = read((int)File, (char*)pvBuf + cbRead, cbToRead - cbRead); 276 if (cbReadPart <= 0) 277 { 278 if (cbReadPart == 0) 279 return VERR_EOF; 280 else 281 return RTErrConvertFromErrno(errno); 282 } 283 cbRead += cbReadPart; 284 } 86 AssertRelease((size_t)cbRead < cb); 87 rtRandGenBytesFallback((uint8_t *)pv + cbRead, cb - cbRead); 285 88 } 286 return VINF_SUCCESS;287 }288 289 return RTErrConvertFromErrno(errno);290 }291 292 293 RTR3DECL(int) RTFileWrite(RTFILE File, const void *pvBuf, unsigned cbToWrite, unsigned *pcbWritten)294 {295 if (cbToWrite <= 0)296 return VINF_SUCCESS;297 298 /*299 * Attempt write.300 */301 ssize_t cbWritten = write((int)File, pvBuf, cbToWrite);302 if (cbWritten >= 0)303 {304 if (pcbWritten)305 /* caller can handle partial write. */306 *pcbWritten = cbWritten;307 else308 {309 /* Caller expects all to be write. */310 while ((ssize_t)cbToWrite > cbWritten)311 {312 ssize_t cbWrittenPart = write((int)File, (const char *)pvBuf + cbWritten, cbToWrite - cbWritten);313 if (cbWrittenPart <= 0)314 return RTErrConvertFromErrno(errno);315 cbWritten += cbWrittenPart;316 }317 }318 return VINF_SUCCESS;319 }320 return RTErrConvertFromErrno(errno);321 }322 323 324 RTR3DECL(int) RTFileSetSize(RTFILE File, uint64_t cbSize)325 {326 /*327 * Validate offset.328 */329 if ( sizeof(off_t) < sizeof(cbSize)330 && (cbSize >> 32) != 0)331 {332 AssertMsgFailed(("64-bit filesize not supported! cbSize=%lld\n", cbSize));333 return VERR_NOT_SUPPORTED;334 }335 336 #if defined(_MSC_VER) || (defined(__OS2__) && (!defined(__INNOTEK_LIBC__) || __INNOTEK_LIBC__ < 0x006))337 if (chsize((int)File, (off_t)cbSize) == 0)338 #else339 /* This relies on a non-standard feature of FreeBSD, Linux, and OS/2340 * LIBC v0.6 and higher. (SuS doesn't define ftruncate() and size bigger341 * than the file.)342 */343 if (ftruncate((int)File, (off_t)cbSize) == 0)344 #endif345 return VINF_SUCCESS;346 return RTErrConvertFromErrno(errno);347 }348 349 350 RTR3DECL(int) RTFileGetSize(RTFILE File, uint64_t *pcbSize)351 {352 struct stat st;353 if (!fstat((int)File, &st))354 {355 *pcbSize = st.st_size;356 return VINF_SUCCESS;357 }358 return RTErrConvertFromErrno(errno);359 }360 361 362 RTR3DECL(bool) RTFileIsValid(RTFILE File)363 {364 if (File != NIL_RTFILE)365 {366 int fFlags = fcntl(File, F_GETFD);367 if (fFlags >= 0)368 return true;369 }370 return false;371 }372 373 374 RTR3DECL(int) RTFileFlush(RTFILE File)375 {376 if (fsync((int)File))377 return RTErrConvertFromErrno(errno);378 return VINF_SUCCESS;379 }380 381 382 RTR3DECL(int) RTFileLock(RTFILE File, unsigned fLock, int64_t offLock, uint64_t cbLock)383 {384 Assert(offLock >= 0);385 386 /* Check arguments. */387 if (fLock & ~RTFILE_LOCK_MASK)388 {389 AssertMsgFailed(("Invalid fLock=%08X\n", fLock));390 return VERR_INVALID_PARAMETER;391 }392 393 /*394 * Validate offset.395 */396 if ( sizeof(off_t) < sizeof(cbLock)397 && ( (offLock >> 32) != 0398 || (cbLock >> 32) != 0399 || ((offLock + cbLock) >> 32) != 0))400 {401 AssertMsgFailed(("64-bit file i/o not supported! offLock=%lld cbLock=%lld\n", offLock, cbLock));402 return VERR_NOT_SUPPORTED;403 }404 405 /* Prepare flock structure. */406 struct flock fl;407 Assert(RTFILE_LOCK_WRITE);408 fl.l_type = (fLock & RTFILE_LOCK_WRITE) ? F_WRLCK : F_RDLCK;409 fl.l_whence = SEEK_SET;410 fl.l_start = (off_t)offLock;411 fl.l_len = (off_t)cbLock;412 fl.l_pid = 0;413 414 Assert(RTFILE_LOCK_WAIT);415 if (fcntl(File, (fLock & RTFILE_LOCK_WAIT) ? F_SETLKW : F_SETLK, &fl) >= 0)416 return VINF_SUCCESS;417 418 int iErr = errno;419 if ( iErr == EAGAIN420 || iErr == EACCES)421 return VERR_FILE_LOCK_VIOLATION;422 423 return RTErrConvertFromErrno(iErr);424 }425 426 427 RTR3DECL(int) RTFileChangeLock(RTFILE File, unsigned fLock, int64_t offLock, uint64_t cbLock)428 {429 /* @todo We never returns VERR_FILE_NOT_LOCKED for now. */430 return RTFileLock(File, fLock, offLock, cbLock);431 }432 433 434 RTR3DECL(int) RTFileUnlock(RTFILE File, int64_t offLock, uint64_t cbLock)435 {436 Assert(offLock >= 0);437 438 /*439 * Validate offset.440 */441 if ( sizeof(off_t) < sizeof(cbLock)442 && ( (offLock >> 32) != 0443 || (cbLock >> 32) != 0444 || ((offLock + cbLock) >> 32) != 0))445 {446 AssertMsgFailed(("64-bit file i/o not supported! offLock=%lld cbLock=%lld\n", offLock, cbLock));447 return VERR_NOT_SUPPORTED;448 }449 450 /* Prepare flock structure. */451 struct flock fl;452 fl.l_type = F_UNLCK;453 fl.l_whence = SEEK_SET;454 fl.l_start = (off_t)offLock;455 fl.l_len = (off_t)cbLock;456 fl.l_pid = 0;457 458 if (fcntl(File, F_SETLK, &fl) >= 0)459 return VINF_SUCCESS;460 461 /* @todo check error codes for non existing lock. */462 int iErr = errno;463 if ( iErr == EAGAIN464 || iErr == EACCES)465 return VERR_FILE_LOCK_VIOLATION;466 467 return RTErrConvertFromErrno(iErr);468 }469 470 471 RTR3DECL(int) RTFileIoCtl(RTFILE File, int iRequest, void *pvData, unsigned cbData, int *piRet)472 {473 int rc = ioctl((int)File, iRequest, pvData);474 if (piRet)475 *piRet = rc;476 return rc >= 0 ? VINF_SUCCESS : RTErrConvertFromErrno(errno);477 }478 479 480 RTR3DECL(int) RTFileQueryInfo(RTFILE File, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)481 {482 /*483 * Validate input.484 */485 if (File == NIL_RTFILE)486 {487 AssertMsgFailed(("Invalid File=%RTfile\n", File));488 return VERR_INVALID_PARAMETER;489 }490 if (!pObjInfo)491 {492 AssertMsgFailed(("Invalid pObjInfo=%p\n", pObjInfo));493 return VERR_INVALID_PARAMETER;494 }495 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING496 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)497 {498 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));499 return VERR_INVALID_PARAMETER;500 }501 502 /*503 * Query file info.504 */505 struct stat Stat;506 if (fstat((int)File, &Stat))507 {508 int rc = RTErrConvertFromErrno(errno);509 Log(("RTFileQueryInfo(%RTfile,,%d): returns %Rrc\n", File, enmAdditionalAttribs, rc));510 return rc;511 }512 513 /*514 * Setup the returned data.515 */516 rtFsConvertStatToObjInfo(pObjInfo, &Stat);517 518 /*519 * Requested attributes (we cannot provide anything actually).520 */521 switch (enmAdditionalAttribs)522 {523 case RTFSOBJATTRADD_EASIZE:524 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;525 pObjInfo->Attr.u.EASize.cb = 0;526 break;527 528 case RTFSOBJATTRADD_NOTHING:529 case RTFSOBJATTRADD_UNIX:530 /* done */531 break;532 533 default:534 AssertMsgFailed(("Impossible!\n"));535 return VERR_INTERNAL_ERROR;536 }537 538 LogFlow(("RTFileQueryInfo(%RTfile,,%d): returns VINF_SUCCESS\n", File, enmAdditionalAttribs));539 return VINF_SUCCESS;540 }541 542 543 RTR3DECL(int) RTFileSetTimes(RTFILE File, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,544 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)545 {546 /*547 * We can only set AccessTime and ModificationTime, so if neither548 * are specified we can return immediately.549 */550 if (!pAccessTime && !pModificationTime)551 return VINF_SUCCESS;552 553 /*554 * Convert the input to timeval, getting the missing one if necessary,555 * and call the API which does the change.556 */557 struct timeval aTimevals[2];558 if (pAccessTime && pModificationTime)559 {560 RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]);561 RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]);562 }563 else564 {565 RTFSOBJINFO ObjInfo;566 int rc = RTFileQueryInfo(File, &ObjInfo, RTFSOBJATTRADD_UNIX);567 if (RT_FAILURE(rc))568 return rc;569 RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]);570 RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]);571 }572 573 if (futimes((int)File, aTimevals))574 {575 int rc = RTErrConvertFromErrno(errno);576 Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", File, pAccessTime, pModificationTime, rc));577 return rc;578 89 } 579 90 return VINF_SUCCESS; 580 91 } 581 92 582 583 RTR3DECL(int) RTFileSetMode(RTFILE File, RTFMODE fMode)584 {585 /*586 * Normalize the mode and call the API.587 */588 fMode = rtFsModeNormalize(fMode, NULL, 0);589 if (!rtFsModeIsValid(fMode))590 return VERR_INVALID_PARAMETER;591 592 if (fchmod((int)File, fMode & RTFS_UNIX_MASK))593 {594 int rc = RTErrConvertFromErrno(errno);595 Log(("RTFileSetMode(%RTfile,%RTfmode): returns %Rrc\n", File, fMode));596 return rc;597 }598 return VINF_SUCCESS;599 }600 601 602 RTR3DECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename)603 {604 /*605 * Validate input.606 */607 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);608 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);609 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);610 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);611 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);612 613 /*614 * Take common cause with RTPathRename.615 */616 int rc = rtPathPosixRename(pszSrc, pszDst, fRename, RTFS_TYPE_FILE);617 618 LogFlow(("RTDirRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",619 pszSrc, pszSrc, pszDst, pszDst, fRename, rc));620 return rc;621 }622 623
Note:
See TracChangeset
for help on using the changeset viewer.