dirs.c 5.25 KB
Newer Older
Bernhard Link's avatar
Bernhard Link committed
1
/*  This file is part of "reprepro"
2 3
 *  Copyright (C) 2003 Bernhard R. Link
 *  This program is free software; you can redistribute it and/or modify
4
 *  it under the terms of the GNU General Public License version 2 as
Bernhard Link's avatar
Bernhard Link committed
5
 *  published by the Free Software Foundation.
6 7 8 9 10 11 12 13
 *
 *  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
Bernhard Link's avatar
Bernhard Link committed
14
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02111-1301  USA
15
 */
Bernhard Link's avatar
Bernhard Link committed
16 17
#include <config.h>

Bernhard Link's avatar
Bernhard Link committed
18
#include <errno.h>
19
#include <assert.h>
Bernhard Link's avatar
Bernhard Link committed
20 21 22
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
23
#include <unistd.h>
24
#include <stdlib.h>
Bernhard Link's avatar
Bernhard Link committed
25
#include <string.h>
26
#include "error.h"
27
#include "strlist.h"
Bernhard Link's avatar
Bernhard Link committed
28
#include "dirs.h"
29
#include "names.h"
Bernhard Link's avatar
Bernhard Link committed
30

Bernhard Link's avatar
Bernhard Link committed
31
/* create directory dirname. */
32
retvalue dirs_create(const char *dirname) {
Bernhard Link's avatar
Bernhard Link committed
33
	int ret, e;
Bernhard Link's avatar
Bernhard Link committed
34

35 36 37 38
	ret = mkdir(dirname, 0775);
	if (ret == 0) {
		if (verbose > 1)
			printf("Created directory \"%s\"\n", dirname);
39
		return RET_OK;
40
	} else if (ret < 0 && (e = errno) != EEXIST) {
Bernhard Link's avatar
Bernhard Link committed
41 42
		fprintf(stderr, "Error %d creating directory \"%s\": %s\n",
				e, dirname, strerror(e));
43
		return RET_ERROR;
Bernhard Link's avatar
Bernhard Link committed
44
	}
45
	return RET_NOTHING;
Bernhard Link's avatar
Bernhard Link committed
46 47 48
}

/* create recursively all parent directories before the last '/' */
49
retvalue dirs_make_parent(const char *filename) {
Bernhard Link's avatar
Bernhard Link committed
50 51 52
	const char *p;
	char *h;
	int i;
53
	retvalue r;
Bernhard Link's avatar
Bernhard Link committed
54

55 56 57 58 59
	for (p = filename+1, i = 1 ; *p != '\0' ; p++, i++) {
		if (*p == '/') {
			h = strndup(filename, i);
			if (FAILEDTOALLOC(h))
				return RET_ERROR_OOM;
60
			r = dirs_create(h);
61
			if (RET_WAS_ERROR(r)) {
Bernhard Link's avatar
Bernhard Link committed
62
				free(h);
63
				return r;
Bernhard Link's avatar
Bernhard Link committed
64 65 66 67
			}
			free(h);
		}
	}
68
	return RET_OK;
Bernhard Link's avatar
Bernhard Link committed
69 70
}

Bernhard Link's avatar
Bernhard Link committed
71
/* create dirname and any '/'-separated part of it */
72
retvalue dirs_make_recursive(const char *directory) {
73
	retvalue r, result;
74

75
	if (interrupted()) {
76
		return RET_ERROR_INTERRUPTED;
77
	}
78
	r = dirs_make_parent(directory);
79
	result = dirs_create(directory);
80
	RET_UPDATE(result, r);
81
	return result;
Bernhard Link's avatar
Bernhard Link committed
82
}
83

84 85 86 87 88 89 90 91 92
/* 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;

93
	if (interrupted()) {
94
		return RET_ERROR_INTERRUPTED;
95
	}
96
	while (len > 0 && directory[len-1] == '/')
97
		len--;
98
	while (len > 0) {
99
		this = strndup(directory, len);
100
		if (FAILEDTOALLOC(this))
101 102 103
			return RET_ERROR_OOM;
		ret = mkdir(this, 0777);
		e = errno;
104 105
		if (ret == 0) {
			if (verbose > 1)
106
				printf("Created directory \"%s\"\n", this);
107
		} else if (e == EEXIST) {
108 109
			free(this);
			break;
110
		/* normally ENOENT should be the only problem,
111 112 113 114
		 * 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",
115 116 117 118 119 120
					this, strerror(e), e);
			free(this);
			return RET_ERRNO(e);
		}
		free(this);
		depth++;
121
		while (len > 0 && directory[len-1] != '/')
122
			len--;
123
		while (len > 0 && directory[len-1] == '/')
124 125 126
			len--;
	}
	check = depth;
127
	while (directory[len] == '/')
128
		len++;
129 130
	while (directory[len] != '\0') {
		while (directory[len] != '\0' && directory[len] != '/')
131 132
			len++;
		this = strndup(directory, len);
133
		if (FAILEDTOALLOC(this))
134
			return RET_ERROR_OOM;
135
		r = dirs_create(this);
136
		free(this);
137
		if (RET_WAS_ERROR(r))
138 139 140
			return r;
		// TODO: if we get RET_NOTHING here, reduce depth?
		check--;
141
		while (directory[len] == '/')
142 143 144 145 146 147 148 149 150 151 152 153
			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;

154
	while (len > 0 && directory[len-1] == '/')
155
		len--;
156
	while (created > 0 && len > 0) {
157
		this = strndup(directory, len);
158
		if (FAILEDTOALLOC(this))
159 160
			return;
		ret = rmdir(this);
161 162 163 164 165
		if (ret == 0) {
			if (verbose > 1)
				printf(
"Removed empty directory \"%s\"\n",
					this);
166 167
		} else {
			int e = errno;
168 169 170
			if (e != ENOTEMPTY) {
				fprintf(stderr,
"Error removing directory \"%s\": %s(%d)\n",
171 172 173 174 175 176 177
						this, strerror(e), e);
			}
			free(this);
			return;
		}
		free(this);
		created--;
178
		while (len > 0 && directory[len-1] != '/')
179
			len--;
180
		while (len > 0 && directory[len-1] == '/')
181 182 183 184 185
			len--;
	}
	return;
}

186
retvalue dirs_getdirectory(const char *filename, char **directory) {
187 188
	size_t len;

189
	assert (filename != NULL && *filename != '\0');
190 191

	len = strlen(filename);
192
	while (len > 1 && filename[len-1] == '/') {
193 194
		len--;
	}
195
	while (len > 0 && filename[len-1] != '/') {
196 197
		len--;
	}
198
	if (len == 0) {
199 200
		*directory = strdup(".");
	} else {
201
		if (len == 1)
202 203
			*directory = strdup("/");
		else
204
			*directory = strndup(filename, len-1);
205
	}
206
	if (FAILEDTOALLOC(*directory))
207 208 209
		return RET_ERROR_OOM;
	else
		return RET_OK;
210

211
}
212 213
const char *dirs_basename(const char *filename) {
	const char *bn;
214

215 216
	bn = strrchr(filename, '/');
	if (bn == NULL)
217 218
		return filename;
	// not really suited for the basename of directories,
219
	// things like /bla/blub/ will give empty string...
220 221
	return bn+1;
}
222 223 224 225 226 227 228 229 230

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);
}