scandir函数的研究【笔记】

以下是本人的学习笔记,代码并非原创,均摘自官方源码,贴出来仅供学习记录用

scandir 的使用要注意内存泄漏的问题

scandir函数实现:

vi ./uClibc-0.9.33.2/libc/misc/dirent/scandir.c

/*
 * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
 *
 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 */

#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include "dirstream.h"

int scandir(const char *dir, struct dirent ***namelist,
    int (*selector) (const struct dirent *),
    int (*compar) (const struct dirent **, const struct dirent **))
{
    DIR *dp = opendir (dir);
    struct dirent *current;
    struct dirent **names = NULL;
    size_t names_size = 0, pos;
    int save;

    if (dp == NULL)
    return -1;

    save = errno;
    __set_errno (0);

    pos = 0;
    while ((current = readdir (dp)) != NULL) {
    int use_it = selector == NULL;

    if (! use_it)
    {
        use_it = (*selector) (current);
        /* The selector function might have changed errno.
         * It was zero before and it need to be again to make
         * the latter tests work.  */
        if (! use_it)
        __set_errno (0);
    }
    if (use_it)
    {
        struct dirent *vnew;
        size_t dsize;

        /* Ignore errors from selector or readdir */
        __set_errno (0);

        if (unlikely(pos == names_size))
        {
        struct dirent **new;
        if (names_size == 0)
            names_size = 10;
        else
            names_size *= 2;
        new = (struct dirent **) realloc (names,
                    names_size * sizeof (struct dirent *));
        if (new == NULL)
            break;
        names = new;
        }

        dsize = &current->d_name[_D_ALLOC_NAMLEN(current)] - (char*)current;
        vnew = (struct dirent *) malloc (dsize);
        if (vnew == NULL)
        break;

        names[pos++] = (struct dirent *) memcpy (vnew, current, dsize);
    }
    }

    if (unlikely(errno != 0))
    {
    save = errno;
    closedir (dp);
    while (pos > 0)
        free (names[--pos]);
    free (names);
    __set_errno (save);
    return -1;
    }

    closedir (dp);
    __set_errno (save);

    /* Sort the list if we have a comparison function to sort with.  */
    if (compar != NULL)
    qsort (names, pos, sizeof (struct dirent *), (comparison_fn_t) compar);
    *namelist = names;
    return pos;
}

例子参考1:

vi ./uClibc-0.9.33.2/test/stdlib/qsort.c

#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <unistd.h>

static int select_files(const struct dirent *dirbuf)
{
    if (dirbuf->d_name[0] == '.')
        return 0;
    else
        return 1;
}

int main(void)
{
    struct dirent **array;
    struct dirent *dirbuf;

    int i, numdir;

    chdir("/");
    numdir = scandir(".", &array, select_files, NULL);
    printf("\nGot %d entries from scandir().\n", numdir);
    for (i = 0; i < numdir; ++i) {
        dirbuf = array[i];
        printf("[%d] %s\n", i, dirbuf->d_name);
        free(array[i]);
    }
    free(array);
    numdir = scandir(".", &array, select_files, alphasort);
    printf("\nGot %d entries from scandir() using alphasort().\n", numdir);
    for (i = 0; i < numdir; ++i) {
        dirbuf = array[i];
        printf("[%d] %s\n", i, dirbuf->d_name);
    }
    printf("\nCalling qsort()\n");
    /* Even though some manpages say that alphasort should be
     * int alphasort(const void *a, const void *b),
     * in reality glibc and uclibc have const struct dirent**
     * instead of const void*.
     * Therefore we get a warning here unless we use a cast,
     * which makes people think that alphasort prototype
     * needs to be fixed in uclibc headers.
     */
    qsort(array, numdir, sizeof(struct dirent *), (void*) alphasort);
    for (i = 0; i < numdir; ++i) {
        dirbuf = array[i];
        printf("[%d] %s\n", i, dirbuf->d_name);
        free(array[i]);
    }
    free(array);
    return (0);
}

例子参考2:

man scandir

EXAMPLE
       #define _SVID_SOURCE
       /* print files in current directory in reverse order */
       #include <dirent.h>

       int
       main(void)
       {
           struct dirent **namelist;
           int n;

           n = scandir(".", &namelist, NULL, alphasort);
           if (n < 0)
               perror("scandir");
           else {
               while (n--) {
                   printf("%s\n", namelist[n]->d_name);
                   free(namelist[n]);
               }
               free(namelist);
           }
       }

 

posted @ 2018-01-03 15:24  Sky&Zhang  阅读(2719)  评论(0编辑  收藏  举报