dirent.c   [plain text]


/***********************************************************************
 * Copyright (c) 2009, Secure Endpoints Inc.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 **********************************************************************/

#ifdef HAVE_CONFIG_H
#include<config.h>
#endif

#include <stdlib.h>
#include <io.h>
#include <string.h>
#include <errno.h>
#include "dirent.h"

#ifndef _WIN32
#error Only implemented for Win32
#endif

struct _dirent_dirinfo {
    int             magic;
    long            n_entries;
    long            nc_entries;
    long            cursor;
    struct dirent **entries;
};
#define DIRINFO_MAGIC 0xf8c0639d
#define IS_DP(p) ((p) && ((DIR *)(p))->magic == DIRINFO_MAGIC)

#define INITIAL_ENTRIES 16

ROKEN_LIB_FUNCTION DIR * ROKEN_LIB_CALL
opendir(const char * filespec)
{
    DIR *              dp;
    struct _finddata_t fd;
    intptr_t           fd_handle;

    memset(&fd, 0, sizeof(fd));

    fd_handle = _findfirst(filespec, &fd);

    if (fd_handle == -1)
        return NULL;

    dp = malloc(sizeof(*dp));
    if (dp == NULL)
        goto done;

    memset(dp, 0, sizeof(*dp));
    dp->magic      = DIRINFO_MAGIC;
    dp->cursor     = 0;
    dp->n_entries  = 0;
    dp->nc_entries = INITIAL_ENTRIES;
    dp->entries    = calloc(dp->nc_entries, sizeof(dp->entries[0]));

    if (dp->entries == NULL) {
        closedir(dp);
        dp = NULL;
        goto done;
    }

    do {
        long len = strlen(fd.name);
        struct dirent * e;

        if (dp->n_entries == dp->nc_entries) {
	    struct dirent ** ne;

            dp->nc_entries *= 2;
            ne = realloc(dp->entries, sizeof(dp->entries[0]) * dp->nc_entries);

            if (ne == NULL) {
                closedir(dp);
                dp = NULL;
                goto done;
            }

	    dp->entries = ne;
        }

        e = malloc(sizeof(*e) + len * sizeof(char));
        if (e == NULL) {
            closedir(dp);
            dp = NULL;
            goto done;
        }

        e->d_ino = 0;           /* no inodes :( */
        strcpy_s(e->d_name, len + 1, fd.name);

        dp->entries[dp->n_entries++] = e;

    } while (_findnext(fd_handle, &fd) == 0);

 done:
    if (fd_handle != -1)
        _findclose(fd_handle);

    return dp;
}

ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
closedir(DIR * dp)
{
    if (!IS_DP(dp))
        return EINVAL;

    if (dp->entries) {
        long i;

        for (i=0; i < dp->n_entries; i++) {
            free(dp->entries[i]);
        }

        free(dp->entries);
    }

    free(dp);

    return 0;
}

ROKEN_LIB_FUNCTION struct dirent * ROKEN_LIB_CALL
readdir(DIR * dp)
{
    if (!IS_DP(dp) ||
        dp->cursor < 0 ||
        dp->cursor >= dp->n_entries)

        return NULL;

    return dp->entries[dp->cursor++];
}

ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
rewinddir(DIR * dp)
{
    if (IS_DP(dp))
        dp->cursor = 0;
}

ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
seekdir(DIR * dp, long offset)
{
    if (IS_DP(dp) && offset >= 0 && offset < dp->n_entries)
        dp->cursor = offset;
}

ROKEN_LIB_FUNCTION long ROKEN_LIB_CALL
telldir(DIR * dp)
{
    return dp->cursor;
}