VirtualBox

root/trunk/src/VBox/Runtime/r3/posix/dir-posix.cpp

Revision 14062, 15.0 kB (checked in by vboxsync, 1 week ago)

RTDirRead/RTDirReadEx: sizes are size_t not unsigned.

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

© 2008 Sun Microsystems, Inc.
ContactPrivacy policy