Home | History | Annotate | Line # | Download | only in roken
      1 /*	$NetBSD: dirent.c,v 1.2 2017/01/28 21:31:50 christos Exp $	*/
      2 
      3 /***********************************************************************
      4  * Copyright (c) 2009, Secure Endpoints Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  *
     11  * - Redistributions of source code must retain the above copyright
     12  *   notice, this list of conditions and the following disclaimer.
     13  *
     14  * - Redistributions in binary form must reproduce the above copyright
     15  *   notice, this list of conditions and the following disclaimer in
     16  *   the documentation and/or other materials provided with the
     17  *   distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     30  * OF THE POSSIBILITY OF SUCH DAMAGE.
     31  *
     32  **********************************************************************/
     33 
     34 #include<config.h>
     35 
     36 #include <stdlib.h>
     37 #include <io.h>
     38 #include <string.h>
     39 #include <errno.h>
     40 #include "dirent.h"
     41 
     42 #ifndef _WIN32
     43 #error Only implemented for Win32
     44 #endif
     45 
     46 struct _dirent_dirinfo {
     47     int             magic;
     48     long            n_entries;
     49     long            nc_entries;
     50     long            cursor;
     51     struct dirent **entries;
     52 };
     53 #define DIRINFO_MAGIC 0xf8c0639d
     54 #define IS_DP(p) ((p) && ((DIR *)(p))->magic == DIRINFO_MAGIC)
     55 
     56 #define INITIAL_ENTRIES 16
     57 
     58 /**
     59  * Create a filespec for use with _findfirst() using a path spec
     60  *
     61  * If the last component of the path spec contains wildcards, we let
     62  * it be.  If the last component doesn't end with a slash, we add one.
     63  */
     64 static const char *
     65 filespec_from_dir_path(const char * path, char * buffer, size_t cch_buffer)
     66 {
     67     char *comp, *t;
     68     size_t pos;
     69     int found_sep = 0;
     70 
     71     if (strcpy_s(buffer, cch_buffer, path) != 0)
     72         return NULL;
     73 
     74     comp = strrchr(buffer, '\\');
     75     if (comp == NULL)
     76         comp = buffer;
     77     else
     78         found_sep = 1;
     79 
     80     t = strrchr(comp, '/');
     81     if (t != NULL) {
     82         comp = t;
     83         found_sep = 1;
     84     }
     85 
     86     if (found_sep)
     87         comp++;
     88 
     89     pos = strcspn(comp, "*?");
     90     if (comp[pos] != '\0')
     91         return buffer;
     92 
     93     /* We don't append a slash if pos == 0 because that changes the
     94      * meaning:
     95      *
     96      * "*.*" is all files in the current directory.
     97      * "\*.*" is all files in the root directory of the current drive.
     98      */
     99     if (pos > 0 && comp[pos - 1] != '\\' &&
    100         comp[pos - 1] != '/') {
    101         strcat_s(comp, cch_buffer - (comp - buffer), "\\");
    102     }
    103 
    104     strcat_s(comp, cch_buffer - (comp - buffer), "*.*");
    105 
    106     return buffer;
    107 }
    108 
    109 ROKEN_LIB_FUNCTION DIR * ROKEN_LIB_CALL
    110 opendir(const char * path)
    111 {
    112     DIR *              dp;
    113     struct _finddata_t fd;
    114     intptr_t           fd_handle;
    115     const char         *filespec;
    116     char               path_buffer[1024]="";
    117 
    118     memset(&fd, 0, sizeof(fd));
    119 
    120     filespec = filespec_from_dir_path(path, path_buffer, sizeof(path_buffer)/sizeof(char));
    121     if (filespec == NULL)
    122         return NULL;
    123 
    124     fd_handle = _findfirst(filespec, &fd);
    125 
    126     if (fd_handle == -1)
    127         return NULL;
    128 
    129     dp = malloc(sizeof(*dp));
    130     if (dp == NULL)
    131         goto done;
    132 
    133     memset(dp, 0, sizeof(*dp));
    134     dp->magic      = DIRINFO_MAGIC;
    135     dp->cursor     = 0;
    136     dp->n_entries  = 0;
    137     dp->nc_entries = INITIAL_ENTRIES;
    138     dp->entries    = calloc(dp->nc_entries, sizeof(dp->entries[0]));
    139 
    140     if (dp->entries == NULL) {
    141         closedir(dp);
    142         dp = NULL;
    143         goto done;
    144     }
    145 
    146     do {
    147         size_t len = strlen(fd.name);
    148         struct dirent * e;
    149 
    150         if (dp->n_entries == dp->nc_entries) {
    151 	    struct dirent ** ne;
    152 
    153             dp->nc_entries *= 2;
    154             ne = realloc(dp->entries, sizeof(dp->entries[0]) * dp->nc_entries);
    155 
    156             if (ne == NULL) {
    157                 closedir(dp);
    158                 dp = NULL;
    159                 goto done;
    160             }
    161 
    162 	    dp->entries = ne;
    163         }
    164 
    165         e = malloc(sizeof(*e) + len * sizeof(char));
    166         if (e == NULL) {
    167             closedir(dp);
    168             dp = NULL;
    169             goto done;
    170         }
    171 
    172         e->d_ino = 0;           /* no inodes :( */
    173         strcpy_s(e->d_name, len + 1, fd.name);
    174 
    175         dp->entries[dp->n_entries++] = e;
    176 
    177     } while (_findnext(fd_handle, &fd) == 0);
    178 
    179  done:
    180     if (fd_handle != -1)
    181         _findclose(fd_handle);
    182 
    183     return dp;
    184 }
    185 
    186 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
    187 closedir(DIR * dp)
    188 {
    189     if (!IS_DP(dp))
    190         return EINVAL;
    191 
    192     if (dp->entries) {
    193         long i;
    194 
    195         for (i=0; i < dp->n_entries; i++) {
    196             free(dp->entries[i]);
    197         }
    198 
    199         free(dp->entries);
    200     }
    201 
    202     free(dp);
    203 
    204     return 0;
    205 }
    206 
    207 ROKEN_LIB_FUNCTION struct dirent * ROKEN_LIB_CALL
    208 readdir(DIR * dp)
    209 {
    210     if (!IS_DP(dp) ||
    211         dp->cursor < 0 ||
    212         dp->cursor >= dp->n_entries)
    213 
    214         return NULL;
    215 
    216     return dp->entries[dp->cursor++];
    217 }
    218 
    219 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    220 rewinddir(DIR * dp)
    221 {
    222     if (IS_DP(dp))
    223         dp->cursor = 0;
    224 }
    225 
    226 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    227 seekdir(DIR * dp, long offset)
    228 {
    229     if (IS_DP(dp) && offset >= 0 && offset < dp->n_entries)
    230         dp->cursor = offset;
    231 }
    232 
    233 ROKEN_LIB_FUNCTION long ROKEN_LIB_CALL
    234 telldir(DIR * dp)
    235 {
    236     return dp->cursor;
    237 }
    238