/* This file is part of "reprepro" * Copyright (C) 2003 Bernhard R. Link * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include "error.h" #include "strlist.h" #include "dirs.h" #include "names.h" /* create directory dirname. */ retvalue dirs_create(const char *dirname) { int ret, e; ret = mkdir(dirname,0775); if( ret == 0 ) { if( verbose > 1) printf("Created directory \"%s\"\n",dirname); return RET_OK; } else if( ret < 0 && ( e = errno ) != EEXIST ) { fprintf(stderr, "Error %d creating directory \"%s\": %s\n", e, dirname, strerror(e)); return RET_ERROR; } return RET_NOTHING; } /* create recursively all parent directories before the last '/' */ retvalue dirs_make_parent(const char *filename) { const char *p; char *h; int i; retvalue r; for( p = filename+1, i = 1 ; *p != '\0' ; p++,i++) { if( *p == '/' ) { h = strndup(filename,i); r = dirs_create(h); if( RET_WAS_ERROR(r) ) { free(h); return r; } free(h); } } return RET_OK; } /* create dirname and any '/'-separated part of it */ retvalue dirs_make_recursive(const char *directory) { retvalue r,result; if( interrupted() ) { return RET_ERROR_INTERRUPTED; } r = dirs_make_parent(directory); result = dirs_create(directory); RET_UPDATE(result,r); return result; } /* create directory and return the number of created directoried */ retvalue dir_create_needed(const char *directory, int *createddepth) { retvalue r; int ret; size_t len = strlen(directory); int check, depth = 0; char *this; int e; if( interrupted() ) { return RET_ERROR_INTERRUPTED; } while( len > 0 && directory[len-1] == '/' ) len--; while( len > 0 ) { this = strndup(directory, len); if( this == NULL ) return RET_ERROR_OOM; ret = mkdir(this, 0777); e = errno; if( ret == 0 ) { if( verbose > 1) printf("Created directory \"%s\"\n", this); } else if( e == EEXIST ) { free(this); break; /* normaly ENOENT should be the only problem, but check the others * to be nice to annoying filesystems */ } else if( e != ENOENT && e != EACCES && e != EPERM ) { fprintf(stderr, "Cannot create directory \"%s\": %s(%d)\n", this, strerror(e), e); free(this); return RET_ERRNO(e); } free(this); depth++; while( len > 0 && directory[len-1] != '/' ) len--; while( len > 0 && directory[len-1] == '/' ) len--; } check = depth; while( directory[len] == '/' ) len++; while( directory[len] != '\0' ) { while( directory[len] != '\0' && directory[len] != '/' ) len++; this = strndup(directory, len); if( this == NULL ) return RET_ERROR_OOM; r = dirs_create(this); free(this); if( RET_WAS_ERROR(r) ) return r; // TODO: if we get RET_NOTHING here, reduce depth? check--; while( directory[len] == '/' ) len++; } assert(check == 0); *createddepth = depth; return RET_OK; } void dir_remove_new(const char *directory, int created) { size_t len = strlen(directory); char *this; int ret; while( len > 0 && directory[len-1] == '/' ) len--; while( created > 0 && len > 0 ) { this = strndup(directory, len); if( this == NULL ) return; ret = rmdir(this); if( ret == 0 ) { if( verbose > 1) printf("Removed empty directory \"%s\"\n", this); } else { int e = errno; if( e != ENOTEMPTY ) { fprintf(stderr, "Error removing directory \"%s\": %s(%d)\n", this, strerror(e), e); } free(this); return; } free(this); created--; while( len > 0 && directory[len-1] != '/' ) len--; while( len > 0 && directory[len-1] == '/' ) len--; } return; } retvalue dirs_getdirectory(const char *filename,char **directory) { size_t len; assert( filename != NULL && *filename != '\0' ); len = strlen(filename); while( len > 1 && filename[len-1] == '/' ) { len--; } while( len > 0 && filename[len-1] != '/' ) { len--; } if( len == 0 ) { *directory = strdup("."); } else { if( len == 1 ) *directory = strdup("/"); else *directory = strndup(filename,len-1); } if( *directory == NULL ) return RET_ERROR_OOM; else return RET_OK; } const char *dirs_basename(const char *filename) { const char *bn; bn = strrchr(filename,'/'); if( bn == NULL ) return filename; // not really suited for the basename of directories, // things like /bla/blub/ will give emtpy string... return bn+1; } bool isdir(const char *fullfilename) { struct stat s; int i; assert(fullfilename != NULL); i = stat(fullfilename, &s); return i == 0 && S_ISDIR(s.st_mode); }