Annotation of embedaddon/pimd/libite/dir.c, revision 1.1.1.1

1.1       misho       1: /* Functions for operating on files in directories.
                      2:  *
                      3:  * Copyright (c) 2008-2014  Joachim Nilsson <troglobit@gmail.com>
                      4:  * 
                      5:  * Permission to use, copy, modify, and/or distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: 
                     18: #include <assert.h>
                     19: #include <dirent.h>
                     20: #include <stdio.h>
                     21: #include <stdlib.h>
                     22: #include <string.h>
                     23: 
                     24: static const char *matcher_type = NULL;
                     25: static int (*matcher_filter) (const char *file) = NULL;
                     26: static int matcher(const struct dirent *entry)
                     27: {
                     28:        char *pos = strrchr(entry->d_name, '.');
                     29: 
                     30:        if (matcher_filter && !matcher_filter(entry->d_name))
                     31:                /* User matcher overrides the rest. */
                     32:                return 0;
                     33: 
                     34:        /* Skip current dir "." from list of files. */
                     35:        if ((1 == strlen(entry->d_name) && entry->d_name[0] == '.') ||
                     36:            (2 == strlen(entry->d_name) && !strcmp(entry->d_name, "..")))
                     37:                return 0;
                     38: 
                     39:        /* filetype == "" */
                     40:        if (matcher_type[0] == 0)
                     41:                return 1;
                     42: 
                     43:        /* Entry has no "." */
                     44:        if (!pos)
                     45:                return 0;
                     46: 
                     47:        return !strcmp(pos, matcher_type);
                     48: }
                     49: 
                     50: /**
                     51:  * dir - List all files of a certain type in the given directory.
                     52:  * @dir:   Base directory for dir operation.
                     53:  * @type:  File type suffix, e.g. ".cfg".
                     54:  * @filter: Optional file name filter.
                     55:  * @list:  Pointer to an array of file names.
                     56:  * @strip: Flag, if set dir() strips the file type.
                     57:  *
                     58:  * This function returns a @list of files, matching the @type suffix,
                     59:  * in the given directory @dir.
                     60:  *
                     61:  * The @list argument is a pointer to where to store the dynamically
                     62:  * allocated list of file names.  This list should be free'd by first
                     63:  * calling free() on each file name and then on the list itself.
                     64:  *
                     65:  * If @filter is not %NULL it will be called for each file found.  If
                     66:  * @filter returns non-zero the @file argument will be included in the
                     67:  * resulting @list.  If @filter returns zero for given @file it will
                     68:  * be discarded.
                     69:  *
                     70:  * If the @strip flag is set the resulting @list of files has their
                     71:  * file type stripped, including the dot.  So a match "config0.cfg"
                     72:  * would be returned as "config0".
                     73:  *
                     74:  * Returns:
                     75:  * Number of files in @list, zero if no matching files of @type.
                     76:  */
                     77: int dir(const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip)
                     78: {
                     79:        int i, n, num = 0;
                     80:        char **files;
                     81:        struct dirent **namelist;
                     82: 
                     83:        assert(list);
                     84: 
                     85:        if (!dir)
                     86:                /* Assuming current directory */
                     87:                dir = ".";
                     88:        if (!type)
                     89:                /* Assuming all files. */
                     90:                type = "";
                     91: 
                     92:        matcher_type = type;
                     93:        matcher_filter = filter;
                     94:        n = scandir(dir, &namelist, matcher, alphasort);
                     95:        if (n < 0) {
                     96:                perror("scandir");
                     97:        } else if (n > 0) {
                     98:                files = (char **)malloc(n * sizeof(char *));
                     99:                for (i = 0; i < n; i++) {
                    100:                        if (files) {
                    101:                                char *name = namelist[i]->d_name;
                    102:                                char *type = strrchr(name, '.');
                    103: 
                    104:                                if (type && strip)
                    105:                                        *type = 0;
                    106: 
                    107:                                files[i] = strdup(name);
                    108:                                num++;
                    109:                        }
                    110:                        free(namelist[i]);
                    111:                }
                    112:                if (num)
                    113:                        *list = files;
                    114:        }
                    115: 
                    116:        if (namelist)
                    117:                free(namelist);
                    118: 
                    119:        return num;
                    120: }
                    121: 
                    122: #ifdef UNITTEST
                    123: #include <errno.h>
                    124: #include <sys/stat.h>
                    125: #include <fcntl.h>
                    126: #include "lite.h"
                    127: 
                    128: #define DIR_TYPE_IMAGE  ".img"
                    129: #define DIR_TYPE_SYSLOG ""
                    130: #define DIR_TYPE_CONFIG ".cfg"
                    131: #define STARTUP_CONFIG  "startup-config.cfg"
                    132: 
                    133: int simulate_files(int creat)
                    134: {
                    135:        int i;
                    136:        char *files[] =
                    137:            { "config0.cfg", "config1.cfg", "config2.cfg", "config3.cfg",
                    138:                "rr109.img", "rx100.img", "rx107.img", "rm957.img", "messages"
                    139:        };
                    140: 
                    141:        for (i = 0; i < NELEMS(files); i++) {
                    142:                if (creat)
                    143:                        touch(files[i]);
                    144:                else
                    145:                        erase(files[i]);
                    146:        }
                    147: 
                    148:        if (creat)
                    149:                symlink("config2.cfg", STARTUP_CONFIG);
                    150:        else
                    151:                erase(STARTUP_CONFIG);
                    152: 
                    153:        return 0;
                    154: }
                    155: 
                    156: static int cfg_dir_filter(const char *file)
                    157: {
                    158:        /* Skip the STARTUP_CONFIG file, it is a symbolic link to the
                    159:         * current startup configuration. */
                    160:        return ! !strcmp(file, STARTUP_CONFIG);
                    161: }
                    162: 
                    163: int main(int argc, char *argv[])
                    164: {
                    165:        int i, num;
                    166:        char *type = DIR_TYPE_CONFIG;
                    167:        char **files;
                    168:        int once = 1;
                    169: 
                    170:        int is_startup_config(const char *entry) {
                    171:                static char file[80];
                    172: 
                    173:                if (once) {
                    174:                        int len = readlink(STARTUP_CONFIG, file, sizeof(file));
                    175: 
                    176:                        if (len == -1)
                    177:                                return 0;
                    178: 
                    179:                        file[len] = 0;
                    180:                        once = 0;       /* Only once per call to dir() */
                    181:                }
                    182:                //printf ("Comparing link %s with entry %s\n", file, entry);
                    183:                return !strcmp(file, entry);
                    184:        }
                    185: 
                    186:        simulate_files(1);
                    187: 
                    188:        if (argc >= 2) {
                    189:                if (!strcasecmp("CONFIG", argv[1])) {
                    190:                        type = DIR_TYPE_CONFIG;
                    191:                        system("ls -l *" DIR_TYPE_CONFIG);
                    192:                }
                    193:                if (!strcasecmp("IMAGE", argv[1])) {
                    194:                        type = DIR_TYPE_IMAGE;
                    195:                        system("ls -l *" DIR_TYPE_IMAGE);
                    196:                }
                    197:                if (!strcasecmp("SYSLOG", argv[1])) {
                    198:                        type = DIR_TYPE_SYSLOG;
                    199:                        system("ls -l *");
                    200:                }
                    201:        }
                    202: 
                    203:        num = dir(NULL, type, cfg_dir_filter, &files, 0);
                    204:        if (num) {
                    205:                for (i = 0; i < num; i++) {
                    206:                        printf("%s", files[i]);
                    207:                        if (is_startup_config(files[i]))
                    208:                                printf(" --> startup-config");
                    209:                        printf("\n");
                    210: 
                    211:                        free(files[i]);
                    212:                }
                    213:                free(files);
                    214:        }
                    215: 
                    216:        simulate_files(0);
                    217: 
                    218:        return 0;
                    219: }
                    220: #endif /* UNITTEST */
                    221: 
                    222: /**
                    223:  * Local Variables:
                    224:  *  compile-command: "make V=1 -f dir.mk"
                    225:  *  version-control: t
                    226:  *  indent-tabs-mode: t
                    227:  *  c-file-style: "linux"
                    228:  * End:
                    229:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>