1/* $NetBSD$ */ 2 3/*++ 4/* NAME 5/* dir_forest 3 6/* SUMMARY 7/* file name to directory forest 8/* SYNOPSIS 9/* #include <dir_forest.h> 10/* 11/* char *dir_forest(buf, path, depth) 12/* VSTRING *buf; 13/* const char *path; 14/* int depth; 15/* DESCRIPTION 16/* This module implements support for directory forests: a file 17/* organization that introduces one or more levels of intermediate 18/* subdirectories in order to reduce the number of files per directory. 19/* 20/* dir_forest() maps a file basename to a directory forest and 21/* returns the resulting string: file name "abcd" becomes "a/b/" 22/* and so on. The number of subdirectory levels is adjustable. 23/* 24/* Arguments: 25/* .IP buf 26/* A buffer that is overwritten with the result. The result 27/* ends in "/" and is null terminated. If a null pointer is 28/* specified, the result is written to a private buffer that 29/* is overwritten upon each call. 30/* .IP path 31/* A null-terminated string of printable characters. Characters 32/* special to the file system are not permitted. 33/* The first subdirectory is named after the first character 34/* in \fIpath\fR, and so on. When the path is shorter than the 35/* desired number of subdirectory levels, directory names 36/* of '_' (underscore) are used as replacement. 37/* .IP depth 38/* The desired number of subdirectory levels. 39/* DIAGNOSTICS 40/* Panic: interface violations. Fatal error: out of memory. 41/* LICENSE 42/* .ad 43/* .fi 44/* The Secure Mailer license must be distributed with this software. 45/* AUTHOR(S) 46/* Wietse Venema 47/* IBM T.J. Watson Research 48/* P.O. Box 704 49/* Yorktown Heights, NY 10598, USA 50/*--*/ 51 52/* System library. */ 53 54#include <sys_defs.h> 55#include <ctype.h> 56 57/* Utility library. */ 58 59#include "msg.h" 60#include "dir_forest.h" 61 62/* dir_forest - translate base name to directory forest */ 63 64char *dir_forest(VSTRING *buf, const char *path, int depth) 65{ 66 const char *myname = "dir_forest"; 67 static VSTRING *private_buf = 0; 68 int n; 69 const char *cp; 70 int ch; 71 72 /* 73 * Sanity checks. 74 */ 75 if (*path == 0) 76 msg_panic("%s: empty path", myname); 77 if (depth < 1) 78 msg_panic("%s: depth %d", myname, depth); 79 80 /* 81 * Your buffer or mine? 82 */ 83 if (buf == 0) { 84 if (private_buf == 0) 85 private_buf = vstring_alloc(1); 86 buf = private_buf; 87 } 88 89 /* 90 * Generate one or more subdirectory levels, depending on the pathname 91 * contents. When the pathname is short, use underscores instead. 92 * Disallow non-printable characters or characters that are special to 93 * the file system. 94 */ 95 VSTRING_RESET(buf); 96 for (cp = path, n = 0; n < depth; n++) { 97 if ((ch = *cp) == 0) { 98 ch = '_'; 99 } else { 100 if (!ISPRINT(ch) || ch == '.' || ch == '/') 101 msg_panic("%s: invalid pathname: %s", myname, path); 102 cp++; 103 } 104 VSTRING_ADDCH(buf, ch); 105 VSTRING_ADDCH(buf, '/'); 106 } 107 VSTRING_TERMINATE(buf); 108 109 if (msg_verbose > 1) 110 msg_info("%s: %s -> %s", myname, path, vstring_str(buf)); 111 return (vstring_str(buf)); 112} 113