2 * FreeBSD install - a package for the installation and maintainance
3 * of non-core utilities.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
17 * Miscellaneous file access utilities.
19 * $FreeBSD: src/usr.sbin/pkg_install/lib/file.c,v 1.68 2004/07/28 16:03:13 stefanf Exp $
20 * $DragonFly: src/usr.sbin/pkg_install/lib/Attic/file.c,v 1.3 2004/07/30 04:46:13 dillon Exp $
29 /* Quick check to see if a file exists */
31 fexists(const char *fname)
34 if (!lstat(fname, &dummy))
39 /* Quick check to see if something is a directory or symlink to a directory */
41 isdir(const char *fname)
45 if (lstat(fname, &sb) != FAIL && S_ISDIR(sb.st_mode))
47 else if (lstat(strconcat(fname, "/."), &sb) != FAIL && S_ISDIR(sb.st_mode))
53 /* Check to see if file is a dir or symlink to a dir, and is empty */
55 isemptydir(const char *fname)
61 dirp = opendir(fname);
63 return FALSE; /* no perms, leave it alone */
64 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
65 if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
77 * Returns TRUE if file is a regular file or symlink pointing to a regular
81 isfile(const char *fname)
84 if (stat(fname, &sb) != FAIL && S_ISREG(sb.st_mode))
90 * Check to see if file is a file or symlink pointing to a file and is empty.
91 * If nonexistent or not a file, say "it's empty", otherwise return TRUE if
95 isemptyfile(const char *fname)
98 if (stat(fname, &sb) != FAIL && S_ISREG(sb.st_mode)) {
105 /* Returns TRUE if file is a symbolic link. */
107 issymlink(const char *fname)
110 if (lstat(fname, &sb) != FAIL && S_ISLNK(sb.st_mode))
115 /* Returns TRUE if file is a URL specification */
117 isURL(const char *fname)
120 * I'm sure there are other types of URL specifications that I could
121 * also be looking for here, but for now I'll just be happy to get ftp
126 while (isspace(*fname))
128 if (!strncmp(fname, "ftp://", 6) || !strncmp(fname, "http://", 7) ||
129 !strncmp(fname, "https://", 8) || !strncmp(fname, "file://", 7))
135 fileFindByPath(const char *base, const char *fname)
137 static char tmp[FILENAME_MAX];
139 const char *suffixes[] = {".tbz", ".tgz", ".tar", NULL};
142 if (fexists(fname) && isfile(fname)) {
149 cp = strrchr(tmp, '/');
151 *cp = '\0'; /* chop name */
152 cp = strrchr(tmp, '/');
155 for (i = 0; suffixes[i] != NULL; i++) {
159 strcat(cp, suffixes[i]);
165 cp = getenv("PKG_PATH");
167 char *cp2 = strsep(&cp, ":");
169 for (i = 0; suffixes[i] != NULL; i++) {
170 snprintf(tmp, FILENAME_MAX, "%s/%s%s", cp2 ? cp2 : cp, fname, suffixes[i]);
171 if (fexists(tmp) && isfile(tmp))
179 fileGetContents(const char *fname)
185 if (stat(fname, &sb) == FAIL) {
187 errx(2, "%s: can't stat '%s'", __func__, fname);
190 contents = (char *)malloc(sb.st_size + 1);
191 fd = open(fname, O_RDONLY, 0);
194 errx(2, "%s: unable to open '%s' for reading", __func__, fname);
196 if (read(fd, contents, sb.st_size) != sb.st_size) {
198 errx(2, "%s: short read on '%s' - did not get %lld bytes", __func__,
199 fname, (long long)sb.st_size);
202 contents[sb.st_size] = '\0';
207 * Takes a filename and package name, returning (in "try") the
208 * canonical "preserve" name for it.
211 make_preserve_name(char *try, int max, const char *name, const char *file)
215 if ((len = strlen(file)) == 0)
219 strncpy(try, file, max);
220 if (try[i] == '/') /* Catch trailing slash early and save checking in the loop */
225 strncpy(&try[i + 2], &file[i + 1], max - i - 2);
231 strncpy(try + 1, file, max - 1);
233 /* I should probably be called rude names for these inline assignments */
234 strncat(try, ".", max -= strlen(try));
235 strncat(try, name, max -= strlen(name));
236 strncat(try, ".", max--);
237 strncat(try, "backup", max -= 6);
241 /* Write the contents of "str" to a file */
243 write_file(const char *name, const char *str)
248 fp = fopen(name, "w");
251 errx(2, "%s: cannot fopen '%s' for writing", __func__, name);
254 if (fwrite(str, 1, len, fp) != len) {
256 errx(2, "%s: short fwrite on '%s', tried to write %ld bytes",
257 __func__, name, (long)len);
261 errx(2, "%s: failure to fclose '%s'", __func__, name);
266 copy_file(const char *dir, const char *fname, const char *to)
268 char cmd[FILENAME_MAX];
271 snprintf(cmd, FILENAME_MAX, "/bin/cp -r %s %s", fname, to);
273 snprintf(cmd, FILENAME_MAX, "/bin/cp -r %s/%s %s", dir, fname, to);
276 errx(2, "%s: could not perform '%s'", __func__, cmd);
281 move_file(const char *dir, const char *fname, const char *to)
283 char cmd[FILENAME_MAX];
286 snprintf(cmd, FILENAME_MAX, "/bin/mv %s %s", fname, to);
288 snprintf(cmd, FILENAME_MAX, "/bin/mv %s/%s %s", dir, fname, to);
291 errx(2, "%s: could not perform '%s'", __func__, cmd);
296 * Copy a hierarchy (possibly from dir) to the current directory, or
297 * if "to" is TRUE, from the current directory to a location someplace
300 * Though slower, using tar to copy preserves symlinks and everything
301 * without me having to write some big hairy routine to do it.
304 copy_hierarchy(const char *dir, const char *fname, Boolean to)
306 char cmd[FILENAME_MAX * 3];
309 /* If absolute path, use it */
312 snprintf(cmd, FILENAME_MAX * 3, "/usr/bin/tar cf - -C %s %s | /usr/bin/tar xpf -",
316 snprintf(cmd, FILENAME_MAX * 3, "/usr/bin/tar cf - %s | /usr/bin/tar xpf - -C %s",
319 printf("Using '%s' to copy trees.\n", cmd);
323 errx(2, "%s: could not perform '%s'", __func__, cmd);
327 /* Unpack a tar file */
329 unpack(const char *pkg, const char *flist)
331 const char *comp, *cp;
336 * Figure out by a crude heuristic whether this or not this is probably
337 * compressed and whichever compression utility was used (gzip or bzip2).
339 if (strcmp(pkg, "-")) {
340 cp = strrchr(pkg, '.');
342 strcpy(suff, cp + 1);
343 if (strchr(suff, 'z') || strchr(suff, 'Z')) {
344 if (strchr(suff, 'b'))
352 #if defined(__FreeBSD_version) && __FreeBSD_version >= 500039
357 if (vsystem("/usr/bin/tar -xp %s -f '%s' %s", comp, pkg, flist ? flist : "")) {
358 warnx("tar extract of %s failed!", pkg);
365 * Using fmt, replace all instances of:
367 * %F With the parameter "name"
368 * %D With the parameter "dir"
369 * %B Return the directory part ("base") of %D/%F
370 * %f Return the filename part of %D/%F
372 * Does not check for overflow - caution!
376 format_cmd(char *buf, int max, const char *fmt, const char *dir, const char *name)
378 char *cp, scratch[FILENAME_MAX * 2];
381 while (*fmt && max > 0) {
385 strncpy(buf, name, max);
391 strncpy(buf, dir, max);
397 snprintf(scratch, FILENAME_MAX * 2, "%s/%s", dir, name);
398 cp = &scratch[strlen(scratch) - 1];
399 while (cp != scratch && *cp != '/')
402 strncpy(buf, scratch, max);
408 snprintf(scratch, FILENAME_MAX * 2, "%s/%s", dir, name);
409 cp = &scratch[strlen(scratch) - 1];
410 while (cp != scratch && *(cp - 1) != '/')
412 strncpy(buf, cp, max);