1 /* $NetBSD: file.c,v 1.29 2009/09/11 18:00:13 joerg Exp $ */
11 #include <sys/param.h>
14 #include <sys/queue.h>
16 __RCSID("$NetBSD: file.c,v 1.29 2009/09/11 18:00:13 joerg 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
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.
34 * Miscellaneous file access utilities.
65 * Quick check to see if a file (or dir ...) exists
68 fexists(const char *fname
)
71 if (!lstat(fname
, &dummy
))
77 * Quick check to see if something is a directory
80 isdir(const char *fname
)
84 if (lstat(fname
, &sb
) != FAIL
&& S_ISDIR(sb
.st_mode
))
91 * Check if something is a link to a directory
94 islinktodir(const char *fname
)
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! */
102 return FALSE
; /* link to non-dir */
104 return FALSE
; /* non-link */
108 * Check if something is a link that points to nonexistant target.
111 isbrokenlink(const char *fname
)
115 if (lstat(fname
, &sb
) != FAIL
&& S_ISLNK(sb
.st_mode
)) {
116 if (stat(fname
, &sb
) != FAIL
)
117 return FALSE
; /* link target exists! */
119 return TRUE
; /* link target missing*/
121 return FALSE
; /* non-link */
125 * Check to see if file is a dir, and is empty
128 isemptydir(const char *fname
)
130 if (isdir(fname
) || islinktodir(fname
)) {
134 dirp
= opendir(fname
);
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
, "..")) {
143 (void) closedir(dirp
);
150 * Check if something is a regular file
153 isfile(const char *fname
)
156 if (stat(fname
, &sb
) != FAIL
&& S_ISREG(sb
.st_mode
))
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.
166 isemptyfile(const char *fname
)
169 if (stat(fname
, &sb
) != FAIL
&& S_ISREG(sb
.st_mode
)) {
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 */
182 /* A table of valid leading strings for URLs */
183 static const url_t urls
[] = {
191 * Returns length of leading part of any URL from urls table, or -1
194 URLlength(const char *fname
)
199 if (fname
!= (char *) NULL
) {
200 for (i
= 0; isspace((unsigned char) *fname
); i
++) {
203 for (up
= urls
; up
->u_s
; up
++) {
204 if (strncmp(fname
, up
->u_s
, up
->u_len
) == 0) {
205 return i
+ up
->u_len
; /* ... + sizeof(up->u_s); - HF */
213 * Takes a filename and package name, returning (in "try") the canonical
214 * "preserve" name for it.
217 make_preserve_name(char *try, size_t max
, const char *name
, const char *file
)
221 if ((len
= strlen(file
)) == 0)
224 strncpy(try, file
, max
);
225 if (try[i
] == '/') /* Catch trailing slash early and save checking in the loop */
230 strncpy(&try[i
+ 2], &file
[i
+ 1], max
- i
- 2);
236 strncpy(try + 1, file
, max
- 1);
238 /* I should probably be called rude names for these inline assignments */
239 strncat(try, ".", max
-= strlen(try));
240 strncat(try, name
, max
-= strlen(name
));
241 strncat(try, ".", max
--);
242 strncat(try, "backup", max
-= 6);
247 remove_files(const char *path
, const char *pattern
)
249 char fpath
[MaxPathSize
];
254 (void) snprintf(fpath
, sizeof(fpath
), "%s/%s", path
, pattern
);
255 if ((i
=glob(fpath
, GLOB_NOSORT
, NULL
, &globbed
)) != 0) {
258 warn("no files matching ``%s'' found", fpath
);
261 warn("globbing aborted");
264 warn("out-of-memory during globbing");
267 warn("unknown error during globbing");
273 /* deleting globbed files */
274 for (j
= 0; j
< globbed
.gl_pathc
; j
++)
275 if (unlink(globbed
.gl_pathv
[j
]) < 0)
276 warn("can't delete ``%s''", globbed
.gl_pathv
[j
]);
282 * Using fmt, replace all instances of:
284 * %F With the parameter "name"
285 * %D With the parameter "dir"
286 * %B Return the directory part ("base") of %D/%F
287 * %f Return the filename part of %D/%F
289 * Check that no overflows can occur.
292 format_cmd(char *buf
, size_t size
, const char *fmt
, const char *dir
, const char *name
)
294 size_t remaining
, quoted
;
298 for (bufp
= buf
, remaining
= size
; remaining
> 1 && *fmt
;) {
305 if (*++fmt
!= 'D' && name
== NULL
) {
306 warnx("no last file available for '%s' command", buf
);
311 quoted
= shquote(name
, bufp
, remaining
);
312 if (quoted
>= remaining
) {
313 warnx("overflow during quoting");
321 quoted
= shquote(dir
, bufp
, remaining
);
322 if (quoted
>= remaining
) {
323 warnx("overflow during quoting");
331 tmp
= xasprintf("%s/%s", dir
, name
);
332 cp
= strrchr(tmp
, '/');
334 quoted
= shquote(tmp
, bufp
, remaining
);
336 if (quoted
>= remaining
) {
337 warnx("overflow during quoting");
345 tmp
= xasprintf("%s/%s", dir
, name
);
346 cp
= strrchr(tmp
, '/') + 1;
347 quoted
= shquote(cp
, bufp
, remaining
);
349 if (quoted
>= remaining
) {
350 warnx("overflow during quoting");
358 if (remaining
== 1) {
359 warnx("overflow during quoting");