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