etc/protocols - sync with NetBSD-8
[minix.git] / external / bsd / pkg_install / dist / lib / file.c
bloba16f0374b42515961ee3221c007e0b0292044131
1 /* $NetBSD: file.c,v 1.1.1.6 2011/02/18 22:32:30 aymeric Exp $ */
3 #if HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6 #include <nbcompat.h>
7 #if HAVE_SYS_CDEFS_H
8 #include <sys/cdefs.h>
9 #endif
10 #if HAVE_SYS_PARAM_H
11 #include <sys/param.h>
12 #endif
13 #if HAVE_SYS_QUEUE_H
14 #include <sys/queue.h>
15 #endif
16 __RCSID("$NetBSD: file.c,v 1.1.1.6 2011/02/18 22:32:30 aymeric Exp $");
19 * FreeBSD install - a package for the installation and maintainance
20 * of non-core utilities.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
31 * Jordan K. Hubbard
32 * 18 July 1993
34 * Miscellaneous file access utilities.
38 #include "lib.h"
40 #if HAVE_SYS_WAIT_H
41 #include <sys/wait.h>
42 #endif
44 #if HAVE_ASSERT_H
45 #include <assert.h>
46 #endif
47 #if HAVE_ERR_H
48 #include <err.h>
49 #endif
50 #if HAVE_GLOB_H
51 #include <glob.h>
52 #endif
53 #if HAVE_PWD_H
54 #include <pwd.h>
55 #endif
56 #if HAVE_TIME_H
57 #include <time.h>
58 #endif
59 #if HAVE_FCNTL_H
60 #include <fcntl.h>
61 #endif
65 * Quick check to see if a file (or dir ...) exists
67 Boolean
68 fexists(const char *fname)
70 struct stat dummy;
71 if (!lstat(fname, &dummy))
72 return TRUE;
73 return FALSE;
77 * Quick check to see if something is a directory
79 Boolean
80 isdir(const char *fname)
82 struct stat sb;
84 if (lstat(fname, &sb) != FAIL && S_ISDIR(sb.st_mode))
85 return TRUE;
86 else
87 return FALSE;
91 * Check if something is a link to a directory
93 Boolean
94 islinktodir(const char *fname)
96 struct stat sb;
98 if (lstat(fname, &sb) != FAIL && S_ISLNK(sb.st_mode)) {
99 if (stat(fname, &sb) != FAIL && S_ISDIR(sb.st_mode))
100 return TRUE; /* link to dir! */
101 else
102 return FALSE; /* link to non-dir */
103 } else
104 return FALSE; /* non-link */
108 * Check if something is a link that points to nonexistant target.
110 Boolean
111 isbrokenlink(const char *fname)
113 struct stat sb;
115 if (lstat(fname, &sb) != FAIL && S_ISLNK(sb.st_mode)) {
116 if (stat(fname, &sb) != FAIL)
117 return FALSE; /* link target exists! */
118 else
119 return TRUE; /* link target missing*/
120 } else
121 return FALSE; /* non-link */
125 * Check to see if file is a dir, and is empty
127 Boolean
128 isemptydir(const char *fname)
130 if (isdir(fname) || islinktodir(fname)) {
131 DIR *dirp;
132 struct dirent *dp;
134 dirp = opendir(fname);
135 if (!dirp)
136 return FALSE; /* no perms, leave it alone */
137 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
138 if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
139 closedir(dirp);
140 return FALSE;
143 (void) closedir(dirp);
144 return TRUE;
146 return FALSE;
150 * Check if something is a regular file
152 Boolean
153 isfile(const char *fname)
155 struct stat sb;
156 if (stat(fname, &sb) != FAIL && S_ISREG(sb.st_mode))
157 return TRUE;
158 return FALSE;
162 * Check to see if file is a file and is empty. If nonexistent or not
163 * a file, say "it's empty", otherwise return TRUE if zero sized.
165 Boolean
166 isemptyfile(const char *fname)
168 struct stat sb;
169 if (stat(fname, &sb) != FAIL && S_ISREG(sb.st_mode)) {
170 if (sb.st_size != 0)
171 return FALSE;
173 return TRUE;
176 /* This struct defines the leading part of a valid URL name */
177 typedef struct url_t {
178 const char *u_s; /* the leading part of the URL */
179 int u_len; /* its length */
180 } url_t;
182 /* A table of valid leading strings for URLs */
183 static const url_t urls[] = {
184 #define STR_AND_SIZE(str) { str, sizeof(str) - 1 }
185 STR_AND_SIZE("file://"),
186 STR_AND_SIZE("ftp://"),
187 STR_AND_SIZE("http://"),
188 STR_AND_SIZE("https://"),
189 #undef STR_AND_SIZE
190 {NULL, 0}
194 * Returns length of leading part of any URL from urls table, or -1
197 URLlength(const char *fname)
199 const url_t *up;
200 int i;
202 if (fname != (char *) NULL) {
203 for (i = 0; isspace((unsigned char) *fname); i++) {
204 fname++;
206 for (up = urls; up->u_s; up++) {
207 if (strncmp(fname, up->u_s, up->u_len) == 0) {
208 return i + up->u_len; /* ... + sizeof(up->u_s); - HF */
212 return -1;
216 * Takes a filename and package name, returning (in "try") the canonical
217 * "preserve" name for it.
219 Boolean
220 make_preserve_name(char *try, size_t max, const char *name, const char *file)
222 size_t len, i;
224 if ((len = strlen(file)) == 0)
225 return FALSE;
226 i = len - 1;
227 strncpy(try, file, max);
228 if (try[i] == '/') /* Catch trailing slash early and save checking in the loop */
229 --i;
230 for (; i; i--) {
231 if (try[i] == '/') {
232 try[i + 1] = '.';
233 strncpy(&try[i + 2], &file[i + 1], max - i - 2);
234 break;
237 if (!i) {
238 try[0] = '.';
239 strncpy(try + 1, file, max - 1);
241 /* I should probably be called rude names for these inline assignments */
242 strncat(try, ".", max -= strlen(try));
243 strncat(try, name, max -= strlen(name));
244 strncat(try, ".", max--);
245 strncat(try, "backup", max -= 6);
246 return TRUE;
249 void
250 remove_files(const char *path, const char *pattern)
252 char fpath[MaxPathSize];
253 glob_t globbed;
254 int i;
255 size_t j;
257 (void) snprintf(fpath, sizeof(fpath), "%s/%s", path, pattern);
258 if ((i=glob(fpath, GLOB_NOSORT, NULL, &globbed)) != 0) {
259 switch(i) {
260 case GLOB_NOMATCH:
261 warn("no files matching ``%s'' found", fpath);
262 break;
263 case GLOB_ABORTED:
264 warn("globbing aborted");
265 break;
266 case GLOB_NOSPACE:
267 warn("out-of-memory during globbing");
268 break;
269 default:
270 warn("unknown error during globbing");
271 break;
273 return;
276 /* deleting globbed files */
277 for (j = 0; j < globbed.gl_pathc; j++)
278 if (unlink(globbed.gl_pathv[j]) < 0)
279 warn("can't delete ``%s''", globbed.gl_pathv[j]);
281 return;
285 * Using fmt, replace all instances of:
287 * %F With the parameter "name"
288 * %D With the parameter "dir"
289 * %B Return the directory part ("base") of %D/%F
290 * %f Return the filename part of %D/%F
292 * Check that no overflows can occur.
295 format_cmd(char *buf, size_t size, const char *fmt, const char *dir, const char *name)
297 size_t remaining, quoted;
298 char *bufp, *tmp;
299 char *cp;
301 for (bufp = buf, remaining = size; remaining > 1 && *fmt;) {
302 if (*fmt != '%') {
303 *bufp++ = *fmt++;
304 --remaining;
305 continue;
308 if (*++fmt != 'D' && name == NULL) {
309 warnx("no last file available for '%s' command", buf);
310 return -1;
312 switch (*fmt) {
313 case 'F':
314 quoted = shquote(name, bufp, remaining);
315 if (quoted >= remaining) {
316 warnx("overflow during quoting");
317 return -1;
319 bufp += quoted;
320 remaining -= quoted;
321 break;
323 case 'D':
324 quoted = shquote(dir, bufp, remaining);
325 if (quoted >= remaining) {
326 warnx("overflow during quoting");
327 return -1;
329 bufp += quoted;
330 remaining -= quoted;
331 break;
333 case 'B':
334 tmp = xasprintf("%s/%s", dir, name);
335 cp = strrchr(tmp, '/');
336 *cp = '\0';
337 quoted = shquote(tmp, bufp, remaining);
338 free(tmp);
339 if (quoted >= remaining) {
340 warnx("overflow during quoting");
341 return -1;
343 bufp += quoted;
344 remaining -= quoted;
345 break;
347 case 'f':
348 tmp = xasprintf("%s/%s", dir, name);
349 cp = strrchr(tmp, '/') + 1;
350 quoted = shquote(cp, bufp, remaining);
351 free(tmp);
352 if (quoted >= remaining) {
353 warnx("overflow during quoting");
354 return -1;
356 bufp += quoted;
357 remaining -= quoted;
358 break;
360 default:
361 if (remaining == 1) {
362 warnx("overflow during quoting");
363 return -1;
365 *bufp++ = '%';
366 *bufp++ = *fmt;
367 remaining -= 2;
368 break;
370 ++fmt;
372 *bufp = '\0';
373 return 0;