1243730Srwatson/*	$NetBSD$	*/
2243730Srwatson
3243730Srwatson/*++
4243730Srwatson/* NAME
5243730Srwatson/*	scan_dir 3
6243730Srwatson/* SUMMARY
7243730Srwatson/*	directory scanning
8243730Srwatson/* SYNOPSIS
9243730Srwatson/*	#include <scan_dir.h>
10243730Srwatson/*
11243730Srwatson/*	SCAN_DIR *scan_dir_open(path)
12243730Srwatson/*	const char *path;
13243730Srwatson/*
14243730Srwatson/*	char	*scan_dir_next(scan)
15243730Srwatson/*	SCAN_DIR *scan;
16243730Srwatson/*
17243730Srwatson/*	char	*scan_dir_path(scan)
18243730Srwatson/*	SCAN_DIR *scan;
19243730Srwatson/*
20243730Srwatson/*	void	scan_push(scan, entry)
21243730Srwatson/*	SCAN_DIR *scan;
22243730Srwatson/*	const char *entry;
23243730Srwatson/*
24243730Srwatson/*	SCAN_DIR *scan_pop(scan)
25243730Srwatson/*	SCAN_DIR *scan;
26243730Srwatson/*
27243730Srwatson/*	SCAN_DIR *scan_dir_close(scan)
28243730Srwatson/*	SCAN_DIR *scan;
29243730Srwatson/* DESCRIPTION
30243730Srwatson/*	These functions scan directories for names. The "." and
31243730Srwatson/*	".." names are skipped. Essentially, this is <dirent>
32243730Srwatson/*	extended with error handling and with knowledge of the
33243730Srwatson/*	name of the directory being scanned.
34243730Srwatson/*
35243730Srwatson/*	scan_dir_open() opens the named directory and
36243730Srwatson/*	returns a handle for subsequent use.
37243730Srwatson/*
38243730Srwatson/*	scan_dir_close() terminates the directory scan, cleans up
39243730Srwatson/*	and returns a null pointer.
40243730Srwatson/*
41243730Srwatson/*	scan_dir_next() returns the next requested object in the specified
42243730Srwatson/*	directory. It skips the "." and ".." entries.
43243730Srwatson/*
44243730Srwatson/*	scan_dir_path() returns the name of the directory being scanned.
45243730Srwatson/*
46243730Srwatson/*	scan_dir_push() causes the specified directory scan to enter the
47243730Srwatson/*	named subdirectory.
48243730Srwatson/*
49243730Srwatson/*	scan_dir_pop() leaves the directory being scanned and returns
50243730Srwatson/*	to the previous one. The result is the argument, null if no
51243730Srwatson/*	previous directory information is available.
52243730Srwatson/* DIAGNOSTICS
53243730Srwatson/*	All errors are fatal.
54243730Srwatson/* LICENSE
55243730Srwatson/* .ad
56243730Srwatson/* .fi
57243730Srwatson/*	The Secure Mailer license must be distributed with this software.
58243730Srwatson/* AUTHOR(S)
59243730Srwatson/*	Wietse Venema
60243730Srwatson/*	IBM T.J. Watson Research
61243730Srwatson/*	P.O. Box 704
62243730Srwatson/*	Yorktown Heights, NY 10598, USA
63243730Srwatson/*--*/
64243730Srwatson
65243730Srwatson/* System library. */
66243730Srwatson
67243730Srwatson#include <sys_defs.h>
68243730Srwatson#ifdef HAVE_DIRENT_H
69243730Srwatson#include <dirent.h>
70243730Srwatson#else
71243730Srwatson#define dirent direct
72243730Srwatson#ifdef HAVE_SYS_NDIR_H
73243730Srwatson#include <sys/ndir.h>
74243730Srwatson#endif
75243730Srwatson#ifdef HAVE_SYS_DIR_H
76243730Srwatson#include <sys/dir.h>
77243730Srwatson#endif
78243730Srwatson#ifdef HAVE_NDIR_H
79243730Srwatson#include <ndir.h>
80243730Srwatson#endif
81243730Srwatson#endif
82243730Srwatson#include <string.h>
83243730Srwatson
84243730Srwatson/* Utility library. */
85243730Srwatson
86243730Srwatson#include "msg.h"
87243730Srwatson#include "mymalloc.h"
88243730Srwatson#include "stringops.h"
89243730Srwatson#include "vstring.h"
90243730Srwatson#include "scan_dir.h"
91243730Srwatson
92243730Srwatson /*
93243730Srwatson  * The interface is based on an opaque structure, so we don't have to expose
94243730Srwatson  * the user to the guts. Subdirectory info sits in front of parent directory
95243730Srwatson  * info: a simple last-in, first-out list.
96243730Srwatson  */
97243730Srwatsontypedef struct SCAN_INFO SCAN_INFO;
98243730Srwatson
99243730Srwatsonstruct SCAN_INFO {
100243730Srwatson    char   *path;			/* directory name */
101243730Srwatson    DIR    *dir;			/* directory structure */
102243730Srwatson    SCAN_INFO *parent;			/* linkage */
103243730Srwatson};
104243730Srwatsonstruct SCAN_DIR {
105243730Srwatson    SCAN_INFO *current;			/* current scan */
106243730Srwatson};
107243730Srwatson
108243730Srwatson#define SCAN_DIR_PATH(scan)	(scan->current->path)
109243730Srwatson#define STR(x)			vstring_str(x)
110243730Srwatson
111243730Srwatson/* scan_dir_path - return the path of the directory being read.  */
112243730Srwatson
113243730Srwatsonchar   *scan_dir_path(SCAN_DIR *scan)
114243730Srwatson{
115243730Srwatson    return (SCAN_DIR_PATH(scan));
116243730Srwatson}
117243730Srwatson
118243730Srwatson/* scan_dir_push - enter directory */
119243730Srwatson
120243730Srwatsonvoid    scan_dir_push(SCAN_DIR *scan, const char *path)
121243730Srwatson{
122243730Srwatson    const char *myname = "scan_dir_push";
123243730Srwatson    SCAN_INFO *info;
124243730Srwatson
125243730Srwatson    info = (SCAN_INFO *) mymalloc(sizeof(*info));
126243730Srwatson    if (scan->current)
127243730Srwatson	info->path = concatenate(SCAN_DIR_PATH(scan), "/", path, (char *) 0);
128243730Srwatson    else
129243730Srwatson	info->path = mystrdup(path);
130243730Srwatson    if ((info->dir = opendir(info->path)) == 0)
131243730Srwatson	msg_fatal("%s: open directory %s: %m", myname, info->path);
132243730Srwatson    if (msg_verbose > 1)
133243730Srwatson	msg_info("%s: open %s", myname, info->path);
134243730Srwatson    info->parent = scan->current;
135243730Srwatson    scan->current = info;
136243730Srwatson}
137243730Srwatson
138243730Srwatson/* scan_dir_pop - leave directory */
139243730Srwatson
140243730SrwatsonSCAN_DIR *scan_dir_pop(SCAN_DIR *scan)
141243730Srwatson{
142243730Srwatson    const char *myname = "scan_dir_pop";
143243730Srwatson    SCAN_INFO *info = scan->current;
144243730Srwatson    SCAN_INFO *parent;
145243730Srwatson
146243730Srwatson    if (info == 0)
147243730Srwatson	return (0);
148243730Srwatson    parent = info->parent;
149243730Srwatson    if (closedir(info->dir))
150243730Srwatson	msg_fatal("%s: close directory %s: %m", myname, info->path);
151243730Srwatson    if (msg_verbose > 1)
152243730Srwatson	msg_info("%s: close %s", myname, info->path);
153243730Srwatson    myfree(info->path);
154243730Srwatson    myfree((char *) info);
155243730Srwatson    scan->current = parent;
156243730Srwatson    return (parent ? scan : 0);
157243730Srwatson}
158243730Srwatson
159243730Srwatson/* scan_dir_open - start directory scan */
160243730Srwatson
161243730SrwatsonSCAN_DIR *scan_dir_open(const char *path)
162243730Srwatson{
163243730Srwatson    SCAN_DIR *scan;
164243730Srwatson
165243730Srwatson    scan = (SCAN_DIR *) mymalloc(sizeof(*scan));
166243730Srwatson    scan->current = 0;
167243730Srwatson    scan_dir_push(scan, path);
168243730Srwatson    return (scan);
169243730Srwatson}
170243730Srwatson
171243730Srwatson/* scan_dir_next - find next entry */
172243730Srwatson
173243730Srwatsonchar   *scan_dir_next(SCAN_DIR *scan)
174243730Srwatson{
175243730Srwatson    const char *myname = "scan_dir_next";
176243730Srwatson    SCAN_INFO *info = scan->current;
177243730Srwatson    struct dirent *dp;
178243730Srwatson
179243730Srwatson#define STREQ(x,y)	(strcmp((x),(y)) == 0)
180243730Srwatson
181243730Srwatson    if (info) {
182243730Srwatson	while ((dp = readdir(info->dir)) != 0) {
183243730Srwatson	    if (STREQ(dp->d_name, ".") || STREQ(dp->d_name, "..")) {
184243730Srwatson		if (msg_verbose > 1)
185243730Srwatson		    msg_info("%s: skip %s", myname, dp->d_name);
186243730Srwatson		continue;
187243730Srwatson	    } else {
188243730Srwatson		if (msg_verbose > 1)
189243730Srwatson		    msg_info("%s: found %s", myname, dp->d_name);
190243730Srwatson		return (dp->d_name);
191243730Srwatson	    }
192243730Srwatson	}
193243730Srwatson    }
194243730Srwatson    return (0);
195243730Srwatson}
196243730Srwatson
197243730Srwatson/* scan_dir_close - terminate directory scan */
198243730Srwatson
199243730SrwatsonSCAN_DIR *scan_dir_close(SCAN_DIR *scan)
200243730Srwatson{
201243730Srwatson    while (scan->current)
202243730Srwatson	scan_dir_pop(scan);
203243730Srwatson    myfree((char *) scan);
204243730Srwatson    return (0);
205243730Srwatson}
206243730Srwatson