/* $Header: /CVSROOT/tinolib/old/filetool.h,v 1.12 2006/09/27 20:36:11 tino Exp $ * * Additionally file helpers * * Copyright (C)2004-2006 Valentin Hilbig, webmaster@scylla-charybdis.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Log: filetool.h,v $ * Revision 1.12 2006/09/27 20:36:11 tino * Bugs corrected * * Revision 1.11 2006/08/12 01:03:34 tino * const/nonconst for tino_file_filenameptr * * Revision 1.10 2006/07/23 00:27:16 tino * When searching for a free .~#~ slot, tino_file_backupname now has a * desparate mode in case of a DoS happens (somebody cleverly assigned * some files). It will then find a free slot in O(n) instead of O(ld n). * * Revision 1.9 2006/07/22 23:47:44 tino * see ChangeLog (changes for mvatom) * * Revision 1.8 2006/07/22 17:41:21 tino * See ChangeLog * * Revision 1.7 2005/12/05 02:11:12 tino * Copyright and COPYLEFT added * * Revision 1.6 2005/08/02 04:44:41 tino * C++ changes * * Revision 1.5 2005/08/01 17:35:39 tino * tino_file_filenameptr * * Revision 1.4 2005/06/04 14:35:28 tino * now passes unit test * * Revision 1.3 2005/04/25 23:07:01 tino * some new routines * * Revision 1.2 2005/04/24 13:44:11 tino * tino_file_notdir * * Revision 1.1 2005/04/24 12:55:38 tino * started GAT support and filetool added */ #ifndef tino_INC_filetool_h #define tino_INC_filetool_h #include "file.h" #include "fatal.h" #include "alloc.h" #include "str.h" /* well, be prepared for windows */ #define DRIVE_SEP_CHAR 0 /* untested */ #define PATH_SEP_CHAR '/' /* Most of the functions below which return char * * guarantee to return a buffer which is at least max * bytes long. This routine creates such a buffer. * * To alloc the buffer as tight as possible just give * buf=0 and max=0 * * ELSE THE RESULT CAN BE TRUNCATED, YOU HAVE BEEN WARNED! */ static void tino_file_gluebuffer(char **buf, size_t *max, size_t min) { if (!*buf) { if (*maxoffset) max = offset+1; return tino_strxcpy(buf, name, max); } static char * tino_file_filename(char *buf, size_t max, const char *name) { int offset; offset = tino_file_dirfileoffset(name, 1); tino_file_gluebuffer(&buf, &max, strlen(name+offset)+1); return tino_strxcpy(buf, name+offset, max); } static const char * tino_file_filenameptr_const(const char *path) { return path+tino_file_dirfileoffset(path, 1); } static char * tino_file_filenameptr(char *path) { return (char *)tino_file_filenameptr_const(path); } /* Create a directory subtree for a filepart * * Returns: * -1 could not create directory * 0 path was present or no action taken * 1 directory or path created */ static int tino_file_mkdirs_forfile(const char *path, const char *file) { size_t minoffset; int offset; char *name; minoffset = path ? strlen(path) : 0; name = tino_file_glue_path(NULL, 0, path, file); offset = tino_file_dirfileoffset(name, 0); if (offset<=minoffset) { free(name); return 0; } name[offset] = 0; if (!tino_file_notdir(name)) { free(name); return 0; } /* We do not have a directory, so we must create it. * * First, walk up the path until we can creat a directory. */ while (!tino_file_mkdir(name)) { if (errno!=ENOENT) { free(name); return -1; } offset = tino_file_dirfileoffset(name, 0); if (offset<=minoffset) { free(name); return -1; } name[offset] = 0; } /* Until we have reached the last component, * walk down the path and create the directory */ for (;;) { free(name); /* Rebuild the buffer * * Probably this can be done by poking PATH_SEP_CHAR back again, * but leave this to future optimizations. */ name = tino_file_glue_path(NULL, 0, path, file); offset = tino_file_pathchar(name, offset); if (offset<0) { /* We have reached the end, the directory was created */ free(name); return 1; } name[offset] = 0; if (tino_file_mkdir(name) && (errno!=EEXIST || tino_file_notdir(name))) break; } free(name); return -1; } /* Create a backup filename * This is "name.~#~" where # is something starting at 1 * It is guaranteed that this name does not exist (except for * race conditions). * * As I always handle hundreds of thousands of files * this must have O(ld(n)) complexity to find a free name. */ static char * tino_file_backupname(char *buf, size_t max, const char *name) { long i; unsigned long lower, upper, min; char tmp[15]; size_t len; len = strlen(name); tino_file_gluebuffer(&buf, &max, len+sizeof tmp); tino_strxcpy(buf, name, max); lower = 1; /* this always is a used slot + 1 */ upper = 1; /* this always is an unused slot */ i = 1; min = 1; for (;;) { snprintf(tmp, sizeof tmp, ".~%ld~", i); #if 0 fprintf(stderr, "back: %s\n", tmp); #endif if (len=i) break; upper = i; /* as lowerupper) { /* Upper points to an used slot, * so increase it quadratic! * i>=1, so upper=i+i >= lower=i+1 */ i += i; if (i<0) /* on overflow so something desparate */ i = ++min; upper = i; /* However if the current number already did not fit * in the buffer, this cannot change anything in future. * So bail out. */ if (len+strlen(tmp)>=max) return 0; continue; } /* as lower==i+1 and i