VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.7 KB
Line 
1/* $Id: fileio-posix.cpp 4071 2007-08-07 17:07:59Z 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#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(RT_OS_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) RTFileIoCtl(RTFILE File, int iRequest, void *pvData, unsigned cbData, int *piRet)
383{
384 int rc = ioctl((int)File, iRequest, pvData);
385 if (piRet)
386 *piRet = rc;
387 return rc >= 0 ? VINF_SUCCESS : RTErrConvertFromErrno(errno);
388}
389
390
391RTR3DECL(int) RTFileQueryInfo(RTFILE File, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
392{
393 /*
394 * Validate input.
395 */
396 if (File == NIL_RTFILE)
397 {
398 AssertMsgFailed(("Invalid File=%RTfile\n", File));
399 return VERR_INVALID_PARAMETER;
400 }
401 if (!pObjInfo)
402 {
403 AssertMsgFailed(("Invalid pObjInfo=%p\n", pObjInfo));
404 return VERR_INVALID_PARAMETER;
405 }
406 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
407 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
408 {
409 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
410 return VERR_INVALID_PARAMETER;
411 }
412
413 /*
414 * Query file info.
415 */
416 struct stat Stat;
417 if (fstat((int)File, &Stat))
418 {
419 int rc = RTErrConvertFromErrno(errno);
420 Log(("RTFileQueryInfo(%RTfile,,%d): returns %Rrc\n", File, enmAdditionalAttribs, rc));
421 return rc;
422 }
423
424 /*
425 * Setup the returned data.
426 */
427 rtFsConvertStatToObjInfo(pObjInfo, &Stat, NULL, 0);
428
429 /*
430 * Requested attributes (we cannot provide anything actually).
431 */
432 switch (enmAdditionalAttribs)
433 {
434 case RTFSOBJATTRADD_EASIZE:
435 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
436 pObjInfo->Attr.u.EASize.cb = 0;
437 break;
438
439 case RTFSOBJATTRADD_NOTHING:
440 case RTFSOBJATTRADD_UNIX:
441 /* done */
442 break;
443
444 default:
445 AssertMsgFailed(("Impossible!\n"));
446 return VERR_INTERNAL_ERROR;
447 }
448
449 LogFlow(("RTFileQueryInfo(%RTfile,,%d): returns VINF_SUCCESS\n", File, enmAdditionalAttribs));
450 return VINF_SUCCESS;
451}
452
453
454RTR3DECL(int) RTFileSetTimes(RTFILE File, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
455 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
456{
457 /*
458 * We can only set AccessTime and ModificationTime, so if neither
459 * are specified we can return immediately.
460 */
461 if (!pAccessTime && !pModificationTime)
462 return VINF_SUCCESS;
463
464 /*
465 * Convert the input to timeval, getting the missing one if necessary,
466 * and call the API which does the change.
467 */
468 struct timeval aTimevals[2];
469 if (pAccessTime && pModificationTime)
470 {
471 RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]);
472 RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]);
473 }
474 else
475 {
476 RTFSOBJINFO ObjInfo;
477 int rc = RTFileQueryInfo(File, &ObjInfo, RTFSOBJATTRADD_UNIX);
478 if (RT_FAILURE(rc))
479 return rc;
480 RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]);
481 RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]);
482 }
483
484 if (futimes((int)File, aTimevals))
485 {
486 int rc = RTErrConvertFromErrno(errno);
487 Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", File, pAccessTime, pModificationTime, rc));
488 return rc;
489 }
490 return VINF_SUCCESS;
491}
492
493
494RTR3DECL(int) RTFileSetMode(RTFILE File, RTFMODE fMode)
495{
496 /*
497 * Normalize the mode and call the API.
498 */
499 fMode = rtFsModeNormalize(fMode, NULL, 0);
500 if (!rtFsModeIsValid(fMode))
501 return VERR_INVALID_PARAMETER;
502
503 if (fchmod((int)File, fMode & RTFS_UNIX_MASK))
504 {
505 int rc = RTErrConvertFromErrno(errno);
506 Log(("RTFileSetMode(%RTfile,%RTfmode): returns %Rrc\n", File, fMode));
507 return rc;
508 }
509 return VINF_SUCCESS;
510}
511
512
513RTR3DECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename)
514{
515 /*
516 * Validate input.
517 */
518 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
519 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
520 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
521 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
522 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
523
524 /*
525 * Take common cause with RTPathRename.
526 */
527 int rc = rtPathPosixRename(pszSrc, pszDst, fRename, RTFS_TYPE_FILE);
528
529 LogFlow(("RTDirRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
530 pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
531 return rc;
532}
533
534
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