1 /* $NetBSD: dir_forest.c,v 1.1.1.1 2009/06/23 10:08:59 tron Exp $ */ 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 64 char *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