VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/dir-posix.cpp@ 3888

Last change on this file since 3888 was 3888, checked in by vboxsync, 18 years ago

Solaris.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.2 KB
Line 
1/* $Id: dir-posix.cpp 3888 2007-07-26 16:26:39Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Directory manipulation, 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.215389.xyz. 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_DIR
27#include <errno.h>
28#include <unistd.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <dirent.h>
32#include <stdio.h>
33
34#include <iprt/dir.h>
35#include <iprt/path.h>
36#include <iprt/alloc.h>
37#include <iprt/alloca.h>
38#include <iprt/string.h>
39#include <iprt/assert.h>
40#include <iprt/err.h>
41#include <iprt/log.h>
42#include "internal/dir.h"
43#include "internal/fs.h"
44#include "internal/path.h"
45
46#if !defined(RT_OS_SOLARIS)
47# define HAVE_DIRENT_D_TYPE 1
48#endif
49
50
51RTDECL(bool) RTDirExists(const char *pszPath)
52{
53 bool fRc = false;
54 char *pszNativePath;
55 int rc = rtPathToNative(&pszNativePath, pszPath);
56 if (RT_SUCCESS(rc))
57 {
58 struct stat s;
59 fRc = !stat(pszNativePath, &s)
60 && S_ISDIR(s.st_mode);
61
62 rtPathFreeNative(pszNativePath);
63 }
64
65 LogFlow(("RTDirExists(%p={%s}): returns %RTbool\n", pszPath, pszPath, fRc));
66 return fRc;
67}
68
69
70RTDECL(int) RTDirCreate(const char *pszPath, RTFMODE fMode)
71{
72 int rc;
73 fMode = rtFsModeNormalize(fMode, pszPath, 0);
74 if (rtFsModeIsValidPermissions(fMode))
75 {
76 char *pszNativePath;
77 rc = rtPathToNative(&pszNativePath, pszPath);
78 if (RT_SUCCESS(rc))
79 {
80 if (mkdir(pszNativePath, fMode & RTFS_UNIX_MASK))
81 rc = RTErrConvertFromErrno(errno);
82 }
83
84 rtPathFreeNative(pszNativePath);
85 }
86 else
87 {
88 AssertMsgFailed(("Invalid file mode! %RTfmode\n", fMode));
89 rc = VERR_INVALID_FMODE;
90 }
91 LogFlow(("RTDirCreate(%p={%s}, %RTfmode): returns %Rrc\n", pszPath, pszPath, fMode, rc));
92 return rc;
93}
94
95
96RTDECL(int) RTDirRemove(const char *pszPath)
97{
98 char *pszNativePath;
99 int rc = rtPathToNative(&pszNativePath, pszPath);
100 if (RT_SUCCESS(rc))
101 {
102 if (rmdir(pszNativePath))
103 rc = RTErrConvertFromErrno(errno);
104
105 rtPathFreeNative(pszNativePath);
106 }
107
108 LogFlow(("RTDirRemove(%p={%s}): returns %Rrc\n", pszPath, pszPath, rc));
109 return rc;
110}
111
112
113int rtOpenDirNative(PRTDIR pDir, char *pszPathBuf)
114{
115 /*
116 * Convert to a native path and try opendir.
117 */
118 char *pszNativePath;
119 int rc = rtPathToNative(&pszNativePath, pDir->pszPath);
120 if (RT_SUCCESS(rc))
121 {
122 pDir->pDir = opendir(pszNativePath);
123 if (pDir->pDir)
124 {
125 /*
126 * Init data.
127 */
128 pDir->fDataUnread = false;
129 memset(&pDir->Data, 0, sizeof(pDir->Data)); /* not strictly necessary */
130 }
131 else
132 rc = RTErrConvertFromErrno(errno);
133
134 rtPathFreeNative(pszNativePath);
135 }
136
137 return rc;
138}
139
140
141RTDECL(int) RTDirClose(PRTDIR pDir)
142{
143 /*
144 * Validate input.
145 */
146 if (!pDir)
147 return VERR_INVALID_PARAMETER;
148 if (pDir->u32Magic != RTDIR_MAGIC)
149 {
150 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
151 return VERR_INVALID_PARAMETER;
152 }
153
154 /*
155 * Close the handle.
156 */
157 int rc = VINF_SUCCESS;
158 pDir->u32Magic = RTDIR_MAGIC_DEAD;
159 if (closedir(pDir->pDir))
160 {
161 rc = RTErrConvertFromErrno(errno);
162 AssertMsgFailed(("closedir(%p) -> errno=%d (%Rrc)\n", pDir->pDir, errno, rc));
163 }
164
165 RTMemFree(pDir);
166 return rc;
167}
168
169
170/**
171 * Ensure that there is unread data in the buffer
172 * and that there is a converted filename hanging around.
173 *
174 * @returns IPRT status code.
175 * @param pDir the open directory. Fully validated.
176 */
177static int rtDirReadMore(PRTDIR pDir)
178{
179 /** @todo try avoid the rematching on buffer overflow errors. */
180 for (;;)
181 {
182 /*
183 * Fetch data?
184 */
185 if (!pDir->fDataUnread)
186 {
187 struct dirent *pResult = NULL;
188 int rc = readdir_r(pDir->pDir, &pDir->Data, &pResult);
189 if (rc)
190 {
191 rc = RTErrConvertFromErrno(rc);
192 AssertRC(rc);
193 return rc;
194 }
195 if (!pResult)
196 return VERR_NO_MORE_FILES;
197 }
198
199#ifndef RT_DONT_CONVERT_FILENAMES
200 /*
201 * Convert the filename to UTF-8.
202 */
203 if (!pDir->pszName)
204 {
205 int rc = rtPathFromNativeEx(&pDir->pszName, pDir->Data.d_name, pDir->pszPath);
206 if (RT_FAILURE(rc))
207 {
208 pDir->pszName = NULL;
209 return rc;
210 }
211 pDir->cchName = strlen(pDir->pszName);
212 }
213 if ( !pDir->pfnFilter
214 || pDir->pfnFilter(pDir, pDir->pszName))
215 break;
216 RTStrFree(pDir->pszName);
217 pDir->pszName = NULL;
218#else
219 if ( !pDir->pfnFilter
220 || pDir->pfnFilter(pDir, pDir->Data.d_name))
221 break;
222#endif
223 pDir->fDataUnread = false;
224 }
225
226 pDir->fDataUnread = true;
227 return VINF_SUCCESS;
228}
229
230
231#ifdef HAVE_DIRENT_D_TYPE
232/**
233 * Converts the d_type field to IPRT directory entry type.
234 *
235 * @returns IPRT directory entry type.
236 * @param Unix
237 */
238static RTDIRENTRYTYPE rtDirType(int iType)
239{
240 switch (iType)
241 {
242 case DT_UNKNOWN: return RTDIRENTRYTYPE_UNKNOWN;
243 case DT_FIFO: return RTDIRENTRYTYPE_FIFO;
244 case DT_CHR: return RTDIRENTRYTYPE_DEV_CHAR;
245 case DT_DIR: return RTDIRENTRYTYPE_DIRECTORY;
246 case DT_BLK: return RTDIRENTRYTYPE_DEV_BLOCK;
247 case DT_REG: return RTDIRENTRYTYPE_FILE;
248 case DT_LNK: return RTDIRENTRYTYPE_SYMLINK;
249 case DT_SOCK: return RTDIRENTRYTYPE_SOCKET;
250 case DT_WHT: return RTDIRENTRYTYPE_WHITEOUT;
251 default:
252 AssertMsgFailed(("iType=%d\n", iType));
253 return RTDIRENTRYTYPE_UNKNOWN;
254 }
255}
256#endif /*HAVE_DIRENT_D_TYPE */
257
258
259RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, unsigned *pcbDirEntry)
260{
261 /*
262 * Validate and digest input.
263 */
264 if (!rtDirValidHandle(pDir))
265 return VERR_INVALID_PARAMETER;
266 AssertMsgReturn(VALID_PTR(pDirEntry), ("%p\n", pDirEntry), VERR_INVALID_POINTER);
267
268 unsigned cbDirEntry = sizeof(*pDirEntry);
269 if (pcbDirEntry)
270 {
271 AssertMsgReturn(VALID_PTR(pcbDirEntry), ("%p\n", pcbDirEntry), VERR_INVALID_POINTER);
272 cbDirEntry = *pcbDirEntry;
273 AssertMsgReturn(cbDirEntry >= (unsigned)RT_OFFSETOF(RTDIRENTRY, szName[2]),
274 ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
275 VERR_INVALID_PARAMETER);
276 }
277
278 /*
279 * Fetch more data if necessary and/or convert the name.
280 */
281 int rc = rtDirReadMore(pDir);
282 if (RT_SUCCESS(rc))
283 {
284 /*
285 * Check if we've got enough space to return the data.
286 */
287#ifdef RT_DONT_CONVERT_FILENAMES
288 const char *pszName = pDir->Data.d_name;
289 const size_t cchName = strlen(pszName);
290#else
291 const char *pszName = pDir->pszName;
292 const size_t cchName = pDir->cchName;
293#endif
294 const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName;
295 if (pcbDirEntry)
296 *pcbDirEntry = cbRequired;
297 if (cbRequired <= cbDirEntry)
298 {
299 /*
300 * Setup the returned data.
301 */
302 pDirEntry->INodeId = pDir->Data.d_ino; /* may need #ifdefing later */
303#ifdef HAVE_DIRENT_D_TYPE
304 pDirEntry->enmType = rtDirType(pDir->Data.d_type);
305#else
306 pDirEntry->enmType = RTDIRENTRYTYPE_UNKNOWN;
307#endif
308 pDirEntry->cbName = (uint16_t)cchName;
309 Assert(pDirEntry->cbName == cchName);
310 memcpy(pDirEntry->szName, pszName, cchName + 1);
311
312 /* free cached data */
313 pDir->fDataUnread = false;
314#ifndef RT_DONT_CONVERT_FILENAMES
315 RTStrFree(pDir->pszName);
316 pDir->pszName = NULL;
317#endif
318 }
319 else
320 rc = VERR_BUFFER_OVERFLOW;
321 }
322
323 LogFlow(("RTDirRead(%p:{%s}, %p:{%s}, %p:{%u}): returns %Rrc\n",
324 pDir, pDir->pszPath, pDirEntry, RT_SUCCESS(rc) ? pDirEntry->szName : "<failed>",
325 pcbDirEntry, pcbDirEntry ? *pcbDirEntry : 0, rc));
326 return rc;
327}
328
329
330/**
331 * Fills dummy info into the info structure.
332 * This function is called if we cannot stat the file.
333 *
334 * @param pInfo The struct in question.
335 * @param
336 */
337static void rtDirSetDummyInfo(PRTFSOBJINFO pInfo, RTDIRENTRYTYPE enmType)
338{
339 pInfo->cbObject = 0;
340 pInfo->cbAllocated = 0;
341 RTTimeSpecSetNano(&pInfo->AccessTime, 0);
342 RTTimeSpecSetNano(&pInfo->ModificationTime, 0);
343 RTTimeSpecSetNano(&pInfo->ChangeTime, 0);
344 RTTimeSpecSetNano(&pInfo->BirthTime, 0);
345 memset(&pInfo->Attr, 0, sizeof(pInfo->Attr));
346 pInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
347 switch (enmType)
348 {
349 default:
350 case RTDIRENTRYTYPE_UNKNOWN: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL;
351 case RTDIRENTRYTYPE_FIFO: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FIFO;
352 case RTDIRENTRYTYPE_DEV_CHAR: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_DEV_CHAR;
353 case RTDIRENTRYTYPE_DIRECTORY: pInfo->Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY;
354 case RTDIRENTRYTYPE_DEV_BLOCK: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_DEV_BLOCK;
355 case RTDIRENTRYTYPE_FILE: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE;
356 case RTDIRENTRYTYPE_SYMLINK: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_SYMLINK;
357 case RTDIRENTRYTYPE_SOCKET: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_SOCKET;
358 case RTDIRENTRYTYPE_WHITEOUT: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_WHITEOUT;
359 }
360}
361
362
363RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, unsigned *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs)
364{
365 /*
366 * Validate and digest input.
367 */
368 if (!rtDirValidHandle(pDir))
369 return VERR_INVALID_PARAMETER;
370 AssertMsgReturn(VALID_PTR(pDirEntry), ("%p\n", pDirEntry), VERR_INVALID_POINTER);
371 AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING
372 && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
373 ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs),
374 VERR_INVALID_PARAMETER);
375 unsigned cbDirEntry = sizeof(*pDirEntry);
376 if (pcbDirEntry)
377 {
378 AssertMsgReturn(VALID_PTR(pcbDirEntry), ("%p\n", pcbDirEntry), VERR_INVALID_POINTER);
379 cbDirEntry = *pcbDirEntry;
380 AssertMsgReturn(cbDirEntry >= (unsigned)RT_OFFSETOF(RTDIRENTRYEX, szName[2]),
381 ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
382 VERR_INVALID_PARAMETER);
383 }
384
385 /*
386 * Fetch more data if necessary and/or convert the name.
387 */
388 int rc = rtDirReadMore(pDir);
389 if (RT_SUCCESS(rc))
390 {
391 /*
392 * Check if we've got enough space to return the data.
393 */
394#ifdef RT_DONT_CONVERT_FILENAMES
395 const char *pszName = pDir->Data.d_name;
396 const size_t cchName = strlen(pszName);
397#else
398 const char *pszName = pDir->pszName;
399 const size_t cchName = pDir->cchName;
400#endif
401 const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName;
402 if (pcbDirEntry)
403 *pcbDirEntry = cbRequired;
404 if (cbRequired <= cbDirEntry)
405 {
406 /*
407 * Setup the returned data.
408 */
409 pDirEntry->cucShortName = 0;
410 pDirEntry->uszShortName[0] = 0;
411 pDirEntry->cbName = (uint16_t)cchName;
412 Assert(pDirEntry->cbName == cchName);
413 memcpy(pDirEntry->szName, pszName, cchName + 1);
414
415 /* get the info data */
416 size_t cch = cchName + pDir->cchPath + 1;
417 char *pszNamePath = (char *)alloca(cch);
418 if (pszNamePath)
419 {
420 memcpy(pszNamePath, pDir->pszPath, pDir->cchPath);
421 memcpy(pszNamePath + pDir->cchPath, pszName, cchName + 1);
422 rc = RTPathQueryInfo(pszNamePath, &pDirEntry->Info, enmAdditionalAttribs);
423 }
424 else
425 rc = VERR_NO_MEMORY;
426 if (RT_FAILURE(rc))
427 {
428#ifdef HAVE_DIRENT_D_TYPE
429 rtDirSetDummyInfo(&pDirEntry->Info, rtDirType(pDir->Data.d_type));
430#else
431 rtDirSetDummyInfo(&pDirEntry->Info, RTDIRENTRYTYPE_UNKNOWN);
432#endif
433 rc = VWRN_NO_DIRENT_INFO;
434 }
435
436 /* free cached data */
437 pDir->fDataUnread = false;
438#ifndef RT_DONT_CONVERT_FILENAMES
439 RTStrFree(pDir->pszName);
440 pDir->pszName = NULL;
441#endif
442 }
443 else
444 rc = VERR_BUFFER_OVERFLOW;
445 }
446
447 return rc;
448}
449
450
451RTDECL(int) RTDirRename(const char *pszSrc, const char *pszDst, unsigned fRename)
452{
453 /*
454 * Validate input.
455 */
456 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
457 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
458 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
459 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
460 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
461
462 /*
463 * Take common cause with RTPathRename.
464 */
465 int rc = rtPathPosixRename(pszSrc, pszDst, fRename, RTFS_TYPE_DIRECTORY);
466
467 LogFlow(("RTDirRename(%p:{%s}, %p:{%s}): returns %Rrc\n",
468 pszSrc, pszSrc, pszDst, pszDst, rc));
469 return rc;
470}
471
Note: See TracBrowser for help on using the repository browser.

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