Postfix3.3.1
scan_dir.c
[詳解]
1 /*++
2 /* NAME
3 /* scan_dir 3
4 /* SUMMARY
5 /* directory scanning
6 /* SYNOPSIS
7 /* #include <scan_dir.h>
8 /*
9 /* SCAN_DIR *scan_dir_open(path)
10 /* const char *path;
11 /*
12 /* char *scan_dir_next(scan)
13 /* SCAN_DIR *scan;
14 /*
15 /* char *scan_dir_path(scan)
16 /* SCAN_DIR *scan;
17 /*
18 /* void scan_push(scan, entry)
19 /* SCAN_DIR *scan;
20 /* const char *entry;
21 /*
22 /* SCAN_DIR *scan_pop(scan)
23 /* SCAN_DIR *scan;
24 /*
25 /* SCAN_DIR *scan_dir_close(scan)
26 /* SCAN_DIR *scan;
27 /* DESCRIPTION
28 /* These functions scan directories for names. The "." and
29 /* ".." names are skipped. Essentially, this is <dirent>
30 /* extended with error handling and with knowledge of the
31 /* name of the directory being scanned.
32 /*
33 /* scan_dir_open() opens the named directory and
34 /* returns a handle for subsequent use.
35 /*
36 /* scan_dir_close() terminates the directory scan, cleans up
37 /* and returns a null pointer.
38 /*
39 /* scan_dir_next() returns the next requested object in the specified
40 /* directory. It skips the "." and ".." entries.
41 /*
42 /* scan_dir_path() returns the name of the directory being scanned.
43 /*
44 /* scan_dir_push() causes the specified directory scan to enter the
45 /* named subdirectory.
46 /*
47 /* scan_dir_pop() leaves the directory being scanned and returns
48 /* to the previous one. The result is the argument, null if no
49 /* previous directory information is available.
50 /* DIAGNOSTICS
51 /* All errors are fatal.
52 /* LICENSE
53 /* .ad
54 /* .fi
55 /* The Secure Mailer license must be distributed with this software.
56 /* AUTHOR(S)
57 /* Wietse Venema
58 /* IBM T.J. Watson Research
59 /* P.O. Box 704
60 /* Yorktown Heights, NY 10598, USA
61 /*
62 /* Wietse Venema
63 /* Google, Inc.
64 /* 111 8th Avenue
65 /* New York, NY 10011, USA
66 /*--*/
67 
68 /* System library. */
69 
70 #include <sys_defs.h>
71 #ifdef HAVE_DIRENT_H
72 #include <dirent.h>
73 #else
74 #define dirent direct
75 #ifdef HAVE_SYS_NDIR_H
76 #include <sys/ndir.h>
77 #endif
78 #ifdef HAVE_SYS_DIR_H
79 #include <sys/dir.h>
80 #endif
81 #ifdef HAVE_NDIR_H
82 #include <ndir.h>
83 #endif
84 #endif
85 #include <string.h>
86 #include <errno.h>
87 
88 /* Utility library. */
89 
90 #include "msg.h"
91 #include "mymalloc.h"
92 #include "stringops.h"
93 #include "vstring.h"
94 #include "scan_dir.h"
95 
96  /*
97  * The interface is based on an opaque structure, so we don't have to expose
98  * the user to the guts. Subdirectory info sits in front of parent directory
99  * info: a simple last-in, first-out list.
100  */
101 typedef struct SCAN_INFO SCAN_INFO;
102 
103 struct SCAN_INFO {
104  char *path; /* directory name */
105  DIR *dir; /* directory structure */
106  SCAN_INFO *parent; /* linkage */
107 };
108 struct SCAN_DIR {
109  SCAN_INFO *current; /* current scan */
110 };
111 
112 #define SCAN_DIR_PATH(scan) (scan->current->path)
113 #define STR(x) vstring_str(x)
114 
115 /* scan_dir_path - return the path of the directory being read. */
116 
118 {
119  return (SCAN_DIR_PATH(scan));
120 }
121 
122 /* scan_dir_push - enter directory */
123 
124 void scan_dir_push(SCAN_DIR *scan, const char *path)
125 {
126  const char *myname = "scan_dir_push";
127  SCAN_INFO *info;
128 
129  info = (SCAN_INFO *) mymalloc(sizeof(*info));
130  if (scan->current)
131  info->path = concatenate(SCAN_DIR_PATH(scan), "/", path, (char *) 0);
132  else
133  info->path = mystrdup(path);
134  if ((info->dir = opendir(info->path)) == 0)
135  msg_fatal("%s: open directory %s: %m", myname, info->path);
136  if (msg_verbose > 1)
137  msg_info("%s: open %s", myname, info->path);
138  info->parent = scan->current;
139  scan->current = info;
140 }
141 
142 /* scan_dir_pop - leave directory */
143 
145 {
146  const char *myname = "scan_dir_pop";
147  SCAN_INFO *info = scan->current;
148  SCAN_INFO *parent;
149 
150  if (info == 0)
151  return (0);
152  parent = info->parent;
153  if (closedir(info->dir))
154  msg_fatal("%s: close directory %s: %m", myname, info->path);
155  if (msg_verbose > 1)
156  msg_info("%s: close %s", myname, info->path);
157  myfree(info->path);
158  myfree((void *) info);
159  scan->current = parent;
160  return (parent ? scan : 0);
161 }
162 
163 /* scan_dir_open - start directory scan */
164 
165 SCAN_DIR *scan_dir_open(const char *path)
166 {
167  SCAN_DIR *scan;
168 
169  scan = (SCAN_DIR *) mymalloc(sizeof(*scan));
170  scan->current = 0;
171  scan_dir_push(scan, path);
172  return (scan);
173 }
174 
175 /* scan_dir_next - find next entry */
176 
178 {
179  const char *myname = "scan_dir_next";
180  SCAN_INFO *info = scan->current;
181  struct dirent *dp;
182 
183 #define STREQ(x,y) (strcmp((x),(y)) == 0)
184 
185  if (info) {
186 
187  /*
188  * Fix 20150421: readdir() does not reset errno after reaching the
189  * end-of-directory. This dates back all the way to the initial
190  * implementation of 19970309.
191  */
192  errno = 0;
193  while ((dp = readdir(info->dir)) != 0) {
194  if (STREQ(dp->d_name, ".") || STREQ(dp->d_name, "..")) {
195  if (msg_verbose > 1)
196  msg_info("%s: skip %s", myname, dp->d_name);
197  continue;
198  } else {
199  if (msg_verbose > 1)
200  msg_info("%s: found %s", myname, dp->d_name);
201  return (dp->d_name);
202  }
203  }
204  }
205  return (0);
206 }
207 
208 /* scan_dir_close - terminate directory scan */
209 
211 {
212  while (scan->current)
213  scan_dir_pop(scan);
214  myfree((void *) scan);
215  return (0);
216 }
int msg_verbose
Definition: msg.c:177
void scan_dir_push(SCAN_DIR *scan, const char *path)
Definition: scan_dir.c:124
void myfree(void *ptr)
Definition: mymalloc.c:207
SCAN_INFO * parent
Definition: scan_dir.c:106
char * mystrdup(const char *str)
Definition: mymalloc.c:225
SCAN_DIR * scan_dir_pop(SCAN_DIR *scan)
Definition: scan_dir.c:144
#define SCAN_DIR_PATH(scan)
Definition: scan_dir.c:112
char * path
Definition: scan_dir.c:104
SCAN_DIR * scan_dir_open(const char *path)
Definition: scan_dir.c:165
char * scan_dir_path(SCAN_DIR *scan)
Definition: scan_dir.c:117
#define STREQ(x, y)
SCAN_DIR * scan_dir_close(SCAN_DIR *scan)
Definition: scan_dir.c:210
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
DIR * dir
Definition: scan_dir.c:105
SCAN_INFO * current
Definition: scan_dir.c:109
char * scan_dir_next(SCAN_DIR *scan)
Definition: scan_dir.c:177
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
void msg_info(const char *fmt,...)
Definition: msg.c:199