VirtualBox

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

Last change on this file since 5581 was 5581, checked in by vboxsync, 17 years ago

Fixed O_NONBLOCK / RTFILE_O_NON_BLOCK.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.7 KB
Line 
1/* $Id: fileio-posix.cpp 5581 2007-10-31 17:50:02Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - File I/O, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek 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
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP RTLOGGROUP_FILE
23
24#include <errno.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <sys/ioctl.h>
28#include <sys/fcntl.h>
29#include <fcntl.h>
30#ifdef _MSC_VER
31# include <io.h>
32# include <stdio.h>
33#else
34# include <unistd.h>
35# include <sys/time.h>
36#endif
37#if defined(RT_OS_OS2) && (!defined(__INNOTEK_LIBC__) || __INNOTEK_LIBC__ < 0x006)
38# include <io.h>
39#endif
40#ifdef RT_OS_L4
41/* This is currently ifdef'ed out in the relevant L4 header file */
42/* Same as `utimes', but takes an open file descriptor instead of a name. */
43extern int futimes(int __fd, __const struct timeval __tvp[2]) __THROW;
44#endif
45
46#ifdef RT_OS_SOLARIS
47# define futimes(filedes, timeval) futimesat(filedes, NULL, timeval)
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#ifdef 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, size_t cbToRead, size_t *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 return RTErrConvertFromErrno(errno);
281 }
282 cbRead += cbReadPart;
283 }
284 }
285 return VINF_SUCCESS;
286 }
287
288 return RTErrConvertFromErrno(errno);
289}
290
291
292RTR3DECL(int) RTFileWrite(RTFILE File, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
293{
294 if (cbToWrite <= 0)
295 return VINF_SUCCESS;
296
297 /*
298 * Attempt write.
299 */
300 ssize_t cbWritten = write((int)File, pvBuf, cbToWrite);
301 if (cbWritten >= 0)
302 {
303 if (pcbWritten)
304 /* caller can handle partial write. */
305 *pcbWritten = cbWritten;
306 else
307 {
308 /* Caller expects all to be write. */
309 while ((ssize_t)cbToWrite > cbWritten)
310 {
311 ssize_t cbWrittenPart = write((int)File, (const char *)pvBuf + cbWritten, cbToWrite - cbWritten);
312 if (cbWrittenPart <= 0)
313 return RTErrConvertFromErrno(errno);
314 cbWritten += cbWrittenPart;
315 }
316 }
317 return VINF_SUCCESS;
318 }
319 return RTErrConvertFromErrno(errno);
320}
321
322
323RTR3DECL(int) RTFileSetSize(RTFILE File, uint64_t cbSize)
324{
325 /*
326 * Validate offset.
327 */
328 if ( sizeof(off_t) < sizeof(cbSize)
329 && (cbSize >> 32) != 0)
330 {
331 AssertMsgFailed(("64-bit filesize not supported! cbSize=%lld\n", cbSize));
332 return VERR_NOT_SUPPORTED;
333 }
334
335#if defined(_MSC_VER) || (defined(RT_OS_OS2) && (!defined(__INNOTEK_LIBC__) || __INNOTEK_LIBC__ < 0x006))
336 if (chsize((int)File, (off_t)cbSize) == 0)
337#else
338 /* This relies on a non-standard feature of FreeBSD, Linux, and OS/2
339 * LIBC v0.6 and higher. (SuS doesn't define ftruncate() and size bigger
340 * than the file.)
341 */
342 if (ftruncate((int)File, (off_t)cbSize) == 0)
343#endif
344 return VINF_SUCCESS;
345 return RTErrConvertFromErrno(errno);
346}
347
348
349RTR3DECL(int) RTFileGetSize(RTFILE File, uint64_t *pcbSize)
350{
351 struct stat st;
352 if (!fstat((int)File, &st))
353 {
354 *pcbSize = st.st_size;
355 return VINF_SUCCESS;
356 }
357 return RTErrConvertFromErrno(errno);
358}
359
360
361RTR3DECL(bool) RTFileIsValid(RTFILE File)
362{
363 if (File != NIL_RTFILE)
364 {
365 int fFlags = fcntl(File, F_GETFD);
366 if (fFlags >= 0)
367 return true;
368 }
369 return false;
370}
371
372
373RTR3DECL(int) RTFileFlush(RTFILE File)
374{
375 if (fsync((int)File))
376 return RTErrConvertFromErrno(errno);
377 return VINF_SUCCESS;
378}
379
380
381RTR3DECL(int) RTFileIoCtl(RTFILE File, int iRequest, void *pvData, unsigned cbData, int *piRet)
382{
383 int rc = ioctl((int)File, iRequest, pvData);
384 if (piRet)
385 *piRet = rc;
386 return rc >= 0 ? VINF_SUCCESS : RTErrConvertFromErrno(errno);
387}
388
389
390RTR3DECL(int) RTFileQueryInfo(RTFILE File, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
391{
392 /*
393 * Validate input.
394 */
395 if (File == NIL_RTFILE)
396 {
397 AssertMsgFailed(("Invalid File=%RTfile\n", File));
398 return VERR_INVALID_PARAMETER;
399 }
400 if (!pObjInfo)
401 {
402 AssertMsgFailed(("Invalid pObjInfo=%p\n", pObjInfo));
403 return VERR_INVALID_PARAMETER;
404 }
405 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
406 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
407 {
408 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
409 return VERR_INVALID_PARAMETER;
410 }
411
412 /*
413 * Query file info.
414 */
415 struct stat Stat;
416 if (fstat((int)File, &Stat))
417 {
418 int rc = RTErrConvertFromErrno(errno);
419 Log(("RTFileQueryInfo(%RTfile,,%d): returns %Rrc\n", File, enmAdditionalAttribs, rc));
420 return rc;
421 }
422
423 /*
424 * Setup the returned data.
425 */
426 rtFsConvertStatToObjInfo(pObjInfo, &Stat, NULL, 0);
427
428 /*
429 * Requested attributes (we cannot provide anything actually).
430 */
431 switch (enmAdditionalAttribs)
432 {
433 case RTFSOBJATTRADD_EASIZE:
434 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
435 pObjInfo->Attr.u.EASize.cb = 0;
436 break;
437
438 case RTFSOBJATTRADD_NOTHING:
439 case RTFSOBJATTRADD_UNIX:
440 /* done */
441 break;
442
443 default:
444 AssertMsgFailed(("Impossible!\n"));
445 return VERR_INTERNAL_ERROR;
446 }
447
448 LogFlow(("RTFileQueryInfo(%RTfile,,%d): returns VINF_SUCCESS\n", File, enmAdditionalAttribs));
449 return VINF_SUCCESS;
450}
451
452
453RTR3DECL(int) RTFileSetTimes(RTFILE File, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
454 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
455{
456 /*
457 * We can only set AccessTime and ModificationTime, so if neither
458 * are specified we can return immediately.
459 */
460 if (!pAccessTime && !pModificationTime)
461 return VINF_SUCCESS;
462
463 /*
464 * Convert the input to timeval, getting the missing one if necessary,
465 * and call the API which does the change.
466 */
467 struct timeval aTimevals[2];
468 if (pAccessTime && pModificationTime)
469 {
470 RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]);
471 RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]);
472 }
473 else
474 {
475 RTFSOBJINFO ObjInfo;
476 int rc = RTFileQueryInfo(File, &ObjInfo, RTFSOBJATTRADD_UNIX);
477 if (RT_FAILURE(rc))
478 return rc;
479 RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]);
480 RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]);
481 }
482
483 if (futimes((int)File, aTimevals))
484 {
485 int rc = RTErrConvertFromErrno(errno);
486 Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", File, pAccessTime, pModificationTime, rc));
487 return rc;
488 }
489 return VINF_SUCCESS;
490}
491
492
493RTR3DECL(int) RTFileSetMode(RTFILE File, RTFMODE fMode)
494{
495 /*
496 * Normalize the mode and call the API.
497 */
498 fMode = rtFsModeNormalize(fMode, NULL, 0);
499 if (!rtFsModeIsValid(fMode))
500 return VERR_INVALID_PARAMETER;
501
502 if (fchmod((int)File, fMode & RTFS_UNIX_MASK))
503 {
504 int rc = RTErrConvertFromErrno(errno);
505 Log(("RTFileSetMode(%RTfile,%RTfmode): returns %Rrc\n", File, fMode));
506 return rc;
507 }
508 return VINF_SUCCESS;
509}
510
511
512RTR3DECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename)
513{
514 /*
515 * Validate input.
516 */
517 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
518 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
519 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
520 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
521 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
522
523 /*
524 * Take common cause with RTPathRename.
525 */
526 int rc = rtPathPosixRename(pszSrc, pszDst, fRename, RTFS_TYPE_FILE);
527
528 LogFlow(("RTDirRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
529 pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
530 return rc;
531}
532
533
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