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