VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/fileio-posix.cpp@ 1321

Last change on this file since 1321 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.1 KB
Line 
1/* $Id: fileio-posix.cpp 1 1970-01-01 00:00:00Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - File I/O, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP RTLOGGROUP_FILE
27
28#include <errno.h>
29#include <sys/stat.h>
30#include <sys/types.h>
31#include <sys/ioctl.h>
32#include <sys/fcntl.h>
33#include <fcntl.h>
34#ifdef _MSC_VER
35# include <io.h>
36# include <stdio.h>
37#else
38# include <unistd.h>
39# include <sys/time.h>
40#endif
41#if defined(__OS2__) && (!defined(__INNOTEK_LIBC__) || __INNOTEK_LIBC__ < 0x006)
42# include <io.h>
43#endif
44#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. */
47extern int futimes (int __fd, __const struct timeval __tvp[2]) __THROW;
48#endif
49
50#include <iprt/file.h>
51#include <iprt/path.h>
52#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
60
61
62/*******************************************************************************
63* Defined Constants And Macros *
64*******************************************************************************/
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
77
78
79RTR3DECL(int) RTFileOpen(PRTFILE pFile, const char *pszFilename, unsigned fOpen)
80{
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 }
95
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
172 if (fh >= 0)
173 {
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);
191 }
192 return RTErrConvertFromErrno(iErr);
193}
194
195
196RTR3DECL(int) RTFileClose(RTFILE File)
197{
198 if (close((int)File) == 0)
199 return VINF_SUCCESS;
200 return RTErrConvertFromErrno(errno);
201}
202
203
204RTR3DECL(int) RTFileDelete(const char *pszFilename)
205{
206 char *pszNativeFilename;
207 int rc = rtPathToNative(&pszNativeFilename, pszFilename);
208 if (RT_SUCCESS(rc))
209 {
210 if (unlink(pszNativeFilename) != 0)
211 rc = RTErrConvertFromErrno(errno);
212 rtPathFreeNative(pszNativeFilename);
213 }
214 return rc;
215}
216
217
218RTR3DECL(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
256RTR3DECL(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
271 {
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 }
285 }
286 return VINF_SUCCESS;
287 }
288
289 return RTErrConvertFromErrno(errno);
290}
291
292
293RTR3DECL(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 else
308 {
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
324RTR3DECL(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#else
339 /* This relies on a non-standard feature of FreeBSD, Linux, and OS/2
340 * LIBC v0.6 and higher. (SuS doesn't define ftruncate() and size bigger
341 * than the file.)
342 */
343 if (ftruncate((int)File, (off_t)cbSize) == 0)
344#endif
345 return VINF_SUCCESS;
346 return RTErrConvertFromErrno(errno);
347}
348
349
350RTR3DECL(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
362RTR3DECL(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
374RTR3DECL(int) RTFileFlush(RTFILE File)
375{
376 if (fsync((int)File))
377 return RTErrConvertFromErrno(errno);
378 return VINF_SUCCESS;
379}
380
381
382RTR3DECL(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) != 0
398 || (cbLock >> 32) != 0
399 || ((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 == EAGAIN
420 || iErr == EACCES)
421 return VERR_FILE_LOCK_VIOLATION;
422
423 return RTErrConvertFromErrno(iErr);
424}
425
426
427RTR3DECL(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
434RTR3DECL(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) != 0
443 || (cbLock >> 32) != 0
444 || ((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 == EAGAIN
464 || iErr == EACCES)
465 return VERR_FILE_LOCK_VIOLATION;
466
467 return RTErrConvertFromErrno(iErr);
468}
469
470
471RTR3DECL(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
480RTR3DECL(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_NOTHING
496 || 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
543RTR3DECL(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 neither
548 * 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 else
564 {
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 }
579 return VINF_SUCCESS;
580}
581
582
583RTR3DECL(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
602RTR3DECL(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 TracBrowser for help on using the repository browser.

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