VirtualBox

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

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

Solaris.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.9 KB
Line 
1/* $Id: fileio-posix.cpp 3916 2007-07-29 22:25:12Z 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 * 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(RT_OS_OS2) && (!defined(__INNOTEK_LIBC__) || __INNOTEK_LIBC__ < 0x006)
42# include <io.h>
43#endif
44#ifdef RT_OS_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#ifdef RT_OS_SOLARIS
51# define futimes(filedes, timeval) futimesat(filedes, NULL, timeval)
52#endif
53
54#include <iprt/file.h>
55#include <iprt/path.h>
56#include <iprt/assert.h>
57#include <iprt/string.h>
58#include <iprt/err.h>
59#include <iprt/log.h>
60#include "internal/file.h"
61#include "internal/fs.h"
62#include "internal/path.h"
63
64
65
66/*******************************************************************************
67* Defined Constants And Macros *
68*******************************************************************************/
69/** @def RT_DONT_CONVERT_FILENAMES
70 * Define this to pass UTF-8 unconverted to the kernel. */
71#ifdef __DOXYGEN__
72#define RT_DONT_CONVERT_FILENAMES 1
73#endif
74
75/** Default file permissions for newly created files. */
76#if defined(S_IRUSR) && defined(S_IWUSR)
77# define RT_FILE_PERMISSION (S_IRUSR | S_IWUSR)
78#else
79# define RT_FILE_PERMISSION (00600)
80#endif
81
82
83RTR3DECL(int) RTFileOpen(PRTFILE pFile, const char *pszFilename, unsigned fOpen)
84{
85 /*
86 * Validate input.
87 */
88 if (!VALID_PTR(pFile))
89 {
90 AssertMsgFailed(("Invalid pFile %p\n", pFile));
91 return VERR_INVALID_PARAMETER;
92 }
93 *pFile = NIL_RTFILE;
94 if (!VALID_PTR(pszFilename))
95 {
96 AssertMsgFailed(("Invalid pszFilename %p\n", pszFilename));
97 return VERR_INVALID_PARAMETER;
98 }
99
100 /*
101 * Merge forced open flags and validate them.
102 */
103 int rc = rtFileRecalcAndValidateFlags(&fOpen);
104 if (RT_FAILURE(rc))
105 return rc;
106#ifndef O_NONBLOCK
107 if (fOpen & RTFILE_O_NON_BLOCK)
108 {
109 AssertMsgFailed(("Invalid parameters! fOpen=%#x\n", fOpen));
110 return VERR_INVALID_PARAMETER;
111 }
112#endif
113
114 /*
115 * Calculate open mode flags.
116 */
117 int fOpenMode = 0;
118#ifdef O_BINARY
119 fOpenMode |= O_BINARY; /* (pc) */
120#endif
121#ifdef O_LARGEFILE
122 fOpenMode |= O_LARGEFILE; /* (linux) */
123#endif
124#ifdef O_NOINHERIT
125 if (!(fOpen & RTFILE_O_INHERIT))
126 fOpenMode |= O_NOINHERIT;
127#endif
128#ifndef O_NONBLOCK
129 if (fOpen & RTFILE_O_NON_BLOCK)
130 fOpenMode |= O_NONBLOCK
131#endif
132#ifdef O_SYNC
133 if (fOpen & RTFILE_O_WRITE_THROUGH)
134 fOpenMode |= O_SYNC;
135#endif
136
137 /* create/truncate file */
138 switch (fOpen & RTFILE_O_ACTION_MASK)
139 {
140 case RTFILE_O_OPEN: break;
141 case RTFILE_O_OPEN_CREATE: fOpenMode |= O_CREAT; break;
142 case RTFILE_O_CREATE: fOpenMode |= O_CREAT | O_EXCL; break;
143 case RTFILE_O_CREATE_REPLACE: fOpenMode |= O_CREAT | O_TRUNC; break; /** @todo replacing needs fixing, this is *not* a 1:1 mapping! */
144 }
145 if (fOpen & RTFILE_O_TRUNCATE)
146 fOpenMode |= O_TRUNC;
147
148 switch (fOpen & RTFILE_O_ACCESS_MASK)
149 {
150 case RTFILE_O_READ: fOpenMode |= O_RDONLY; break;
151 case RTFILE_O_WRITE: fOpenMode |= O_WRONLY; break;
152 case RTFILE_O_READWRITE: fOpenMode |= O_RDWR; break;
153 default:
154 AssertMsgFailed(("RTFileOpen received an invalid RW value, fOpen=%#x\n", fOpen));
155 return VERR_INVALID_PARAMETER;
156 }
157
158 /** @todo sharing! */
159
160 /*
161 * Open/create the file.
162 */
163#ifdef RT_DONT_CONVERT_FILENAMES
164 int fh = open(pszFilename, fOpenMode, RT_FILE_PERMISSION);
165 int iErr = errno;
166#else
167 char *pszNativeFilename;
168 rc = rtPathToNative(&pszNativeFilename, pszFilename);
169 if (RT_FAILURE(rc))
170 return (rc);
171
172 int fh = open(pszNativeFilename, fOpenMode, RT_FILE_PERMISSION);
173 int iErr = errno;
174 rtPathFreeNative(pszNativeFilename);
175#endif
176 if (fh >= 0)
177 {
178 /*
179 * Mark the file handle close on exec, unless inherit is specified.
180 */
181 if ( !(fOpen & RTFILE_O_INHERIT)
182#ifdef O_NOINHERIT
183 || (fOpenMode & O_NOINHERIT) /* careful since it could be a dummy. */
184#endif
185 || fcntl(fh, F_SETFD, FD_CLOEXEC) >= 0)
186 {
187 *pFile = (RTFILE)fh;
188 Assert((int)*pFile == fh);
189 LogFlow(("RTFileOpen(%p:{%RTfile}, %p:{%s}, %#x): returns %Rrc\n",
190 pFile, *pFile, pszFilename, pszFilename, fOpen, rc));
191 return VINF_SUCCESS;
192 }
193 iErr = errno;
194 close(fh);
195 }
196 return RTErrConvertFromErrno(iErr);
197}
198
199
200RTR3DECL(int) RTFileClose(RTFILE File)
201{
202 if (close((int)File) == 0)
203 return VINF_SUCCESS;
204 return RTErrConvertFromErrno(errno);
205}
206
207
208RTR3DECL(int) RTFileDelete(const char *pszFilename)
209{
210 char *pszNativeFilename;
211 int rc = rtPathToNative(&pszNativeFilename, pszFilename);
212 if (RT_SUCCESS(rc))
213 {
214 if (unlink(pszNativeFilename) != 0)
215 rc = RTErrConvertFromErrno(errno);
216 rtPathFreeNative(pszNativeFilename);
217 }
218 return rc;
219}
220
221
222RTR3DECL(int) RTFileSeek(RTFILE File, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
223{
224 static const unsigned aSeekRecode[] =
225 {
226 SEEK_SET,
227 SEEK_CUR,
228 SEEK_END,
229 };
230
231 /*
232 * Validate input.
233 */
234 if (uMethod > RTFILE_SEEK_END)
235 {
236 AssertMsgFailed(("Invalid uMethod=%d\n", uMethod));
237 return VERR_INVALID_PARAMETER;
238 }
239
240 /* check that within off_t range. */
241 if ( sizeof(off_t) < sizeof(offSeek)
242 && ( (offSeek > 0 && (unsigned)(offSeek >> 32) != 0)
243 || (offSeek < 0 && (unsigned)(-offSeek >> 32) != 0)))
244 {
245 AssertMsgFailed(("64-bit search not supported\n"));
246 return VERR_NOT_SUPPORTED;
247 }
248
249 off_t offCurrent = lseek((int)File, (off_t)offSeek, aSeekRecode[uMethod]);
250 if (offCurrent != ~0)
251 {
252 if (poffActual)
253 *poffActual = (uint64_t)offCurrent;
254 return VINF_SUCCESS;
255 }
256 return RTErrConvertFromErrno(errno);
257}
258
259
260RTR3DECL(int) RTFileRead(RTFILE File, void *pvBuf, unsigned cbToRead, unsigned *pcbRead)
261{
262 if (cbToRead <= 0)
263 return VINF_SUCCESS;
264
265 /*
266 * Attempt read.
267 */
268 ssize_t cbRead = read((int)File, pvBuf, cbToRead);
269 if (cbRead >= 0)
270 {
271 if (pcbRead)
272 /* caller can handle partial read. */
273 *pcbRead = cbRead;
274 else
275 {
276 /* Caller expects all to be read. */
277 while ((ssize_t)cbToRead > cbRead)
278 {
279 ssize_t cbReadPart = read((int)File, (char*)pvBuf + cbRead, cbToRead - cbRead);
280 if (cbReadPart <= 0)
281 {
282 if (cbReadPart == 0)
283 return VERR_EOF;
284 else
285 return RTErrConvertFromErrno(errno);
286 }
287 cbRead += cbReadPart;
288 }
289 }
290 return VINF_SUCCESS;
291 }
292
293 return RTErrConvertFromErrno(errno);
294}
295
296
297RTR3DECL(int) RTFileWrite(RTFILE File, const void *pvBuf, unsigned cbToWrite, unsigned *pcbWritten)
298{
299 if (cbToWrite <= 0)
300 return VINF_SUCCESS;
301
302 /*
303 * Attempt write.
304 */
305 ssize_t cbWritten = write((int)File, pvBuf, cbToWrite);
306 if (cbWritten >= 0)
307 {
308 if (pcbWritten)
309 /* caller can handle partial write. */
310 *pcbWritten = cbWritten;
311 else
312 {
313 /* Caller expects all to be write. */
314 while ((ssize_t)cbToWrite > cbWritten)
315 {
316 ssize_t cbWrittenPart = write((int)File, (const char *)pvBuf + cbWritten, cbToWrite - cbWritten);
317 if (cbWrittenPart <= 0)
318 return RTErrConvertFromErrno(errno);
319 cbWritten += cbWrittenPart;
320 }
321 }
322 return VINF_SUCCESS;
323 }
324 return RTErrConvertFromErrno(errno);
325}
326
327
328RTR3DECL(int) RTFileSetSize(RTFILE File, uint64_t cbSize)
329{
330 /*
331 * Validate offset.
332 */
333 if ( sizeof(off_t) < sizeof(cbSize)
334 && (cbSize >> 32) != 0)
335 {
336 AssertMsgFailed(("64-bit filesize not supported! cbSize=%lld\n", cbSize));
337 return VERR_NOT_SUPPORTED;
338 }
339
340#if defined(_MSC_VER) || (defined(RT_OS_OS2) && (!defined(__INNOTEK_LIBC__) || __INNOTEK_LIBC__ < 0x006))
341 if (chsize((int)File, (off_t)cbSize) == 0)
342#else
343 /* This relies on a non-standard feature of FreeBSD, Linux, and OS/2
344 * LIBC v0.6 and higher. (SuS doesn't define ftruncate() and size bigger
345 * than the file.)
346 */
347 if (ftruncate((int)File, (off_t)cbSize) == 0)
348#endif
349 return VINF_SUCCESS;
350 return RTErrConvertFromErrno(errno);
351}
352
353
354RTR3DECL(int) RTFileGetSize(RTFILE File, uint64_t *pcbSize)
355{
356 struct stat st;
357 if (!fstat((int)File, &st))
358 {
359 *pcbSize = st.st_size;
360 return VINF_SUCCESS;
361 }
362 return RTErrConvertFromErrno(errno);
363}
364
365
366RTR3DECL(bool) RTFileIsValid(RTFILE File)
367{
368 if (File != NIL_RTFILE)
369 {
370 int fFlags = fcntl(File, F_GETFD);
371 if (fFlags >= 0)
372 return true;
373 }
374 return false;
375}
376
377
378RTR3DECL(int) RTFileFlush(RTFILE File)
379{
380 if (fsync((int)File))
381 return RTErrConvertFromErrno(errno);
382 return VINF_SUCCESS;
383}
384
385
386RTR3DECL(int) RTFileIoCtl(RTFILE File, int iRequest, void *pvData, unsigned cbData, int *piRet)
387{
388 int rc = ioctl((int)File, iRequest, pvData);
389 if (piRet)
390 *piRet = rc;
391 return rc >= 0 ? VINF_SUCCESS : RTErrConvertFromErrno(errno);
392}
393
394
395RTR3DECL(int) RTFileQueryInfo(RTFILE File, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
396{
397 /*
398 * Validate input.
399 */
400 if (File == NIL_RTFILE)
401 {
402 AssertMsgFailed(("Invalid File=%RTfile\n", File));
403 return VERR_INVALID_PARAMETER;
404 }
405 if (!pObjInfo)
406 {
407 AssertMsgFailed(("Invalid pObjInfo=%p\n", pObjInfo));
408 return VERR_INVALID_PARAMETER;
409 }
410 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
411 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
412 {
413 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
414 return VERR_INVALID_PARAMETER;
415 }
416
417 /*
418 * Query file info.
419 */
420 struct stat Stat;
421 if (fstat((int)File, &Stat))
422 {
423 int rc = RTErrConvertFromErrno(errno);
424 Log(("RTFileQueryInfo(%RTfile,,%d): returns %Rrc\n", File, enmAdditionalAttribs, rc));
425 return rc;
426 }
427
428 /*
429 * Setup the returned data.
430 */
431 rtFsConvertStatToObjInfo(pObjInfo, &Stat, NULL, 0);
432
433 /*
434 * Requested attributes (we cannot provide anything actually).
435 */
436 switch (enmAdditionalAttribs)
437 {
438 case RTFSOBJATTRADD_EASIZE:
439 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
440 pObjInfo->Attr.u.EASize.cb = 0;
441 break;
442
443 case RTFSOBJATTRADD_NOTHING:
444 case RTFSOBJATTRADD_UNIX:
445 /* done */
446 break;
447
448 default:
449 AssertMsgFailed(("Impossible!\n"));
450 return VERR_INTERNAL_ERROR;
451 }
452
453 LogFlow(("RTFileQueryInfo(%RTfile,,%d): returns VINF_SUCCESS\n", File, enmAdditionalAttribs));
454 return VINF_SUCCESS;
455}
456
457
458RTR3DECL(int) RTFileSetTimes(RTFILE File, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
459 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
460{
461 /*
462 * We can only set AccessTime and ModificationTime, so if neither
463 * are specified we can return immediately.
464 */
465 if (!pAccessTime && !pModificationTime)
466 return VINF_SUCCESS;
467
468 /*
469 * Convert the input to timeval, getting the missing one if necessary,
470 * and call the API which does the change.
471 */
472 struct timeval aTimevals[2];
473 if (pAccessTime && pModificationTime)
474 {
475 RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]);
476 RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]);
477 }
478 else
479 {
480 RTFSOBJINFO ObjInfo;
481 int rc = RTFileQueryInfo(File, &ObjInfo, RTFSOBJATTRADD_UNIX);
482 if (RT_FAILURE(rc))
483 return rc;
484 RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]);
485 RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]);
486 }
487
488 if (futimes((int)File, aTimevals))
489 {
490 int rc = RTErrConvertFromErrno(errno);
491 Log(("RTFileSetTimes(%RTfile,%p,%p,,): returns %Rrc\n", File, pAccessTime, pModificationTime, rc));
492 return rc;
493 }
494 return VINF_SUCCESS;
495}
496
497
498RTR3DECL(int) RTFileSetMode(RTFILE File, RTFMODE fMode)
499{
500 /*
501 * Normalize the mode and call the API.
502 */
503 fMode = rtFsModeNormalize(fMode, NULL, 0);
504 if (!rtFsModeIsValid(fMode))
505 return VERR_INVALID_PARAMETER;
506
507 if (fchmod((int)File, fMode & RTFS_UNIX_MASK))
508 {
509 int rc = RTErrConvertFromErrno(errno);
510 Log(("RTFileSetMode(%RTfile,%RTfmode): returns %Rrc\n", File, fMode));
511 return rc;
512 }
513 return VINF_SUCCESS;
514}
515
516
517RTR3DECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename)
518{
519 /*
520 * Validate input.
521 */
522 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
523 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
524 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
525 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
526 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
527
528 /*
529 * Take common cause with RTPathRename.
530 */
531 int rc = rtPathPosixRename(pszSrc, pszDst, fRename, RTFS_TYPE_FILE);
532
533 LogFlow(("RTDirRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
534 pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
535 return rc;
536}
537
538
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