/* * rmtree * * Delete a directory tree recursively. * Assumes path points to a valid directory. * Deletes everything under path. * If rmtopdir is true deletes the directory too. * Returns true if successful, false if there was any problem. * (The details of the problem are reported already, so caller * doesn't really have to say anything more, but most do.) */ bool rmtree(const char *path, bool rmtopdir) { bool result = true; char pathbuf[MAXPGPATH]; char **filenames; char **filename; struct stat statbuf; /* * we copy all the names out of the directory before we start modifying * it. */ filenames = pgfnames(path); if (filenames == NULL) return false; /* now we have the names we can start removing things */ for (filename = filenames; *filename; filename++) { snprintf(pathbuf, MAXPGPATH, "%s/%s", path, *filename); /* * It's ok if the file is not there anymore; we were just about to * delete it anyway. * * This is not an academic possibility. One scenario where this * happens is when bgwriter has a pending unlink request for a file in * a database that's being dropped. In dropdb(), we call * ForgetDatabaseFsyncRequests() to flush out any such pending unlink * requests, but because that's asynchronous, it's not guaranteed that * the bgwriter receives the message in time. */ if (lstat(pathbuf, &statbuf) != 0) { if (errno != ENOENT) { #ifndef FRONTEND elog(WARNING, "could not stat file or directory \"%s\": %m", pathbuf); #else fprintf(stderr, _("could not stat file or directory \"%s\": %s\n"), pathbuf, strerror(errno)); #endif result = false; } continue; } if (S_ISDIR(statbuf.st_mode)) { /* call ourselves recursively for a directory */ if (!rmtree(pathbuf, true)) { /* we already reported the error */ result = false; } } else { if (unlink(pathbuf) != 0) { if (errno != ENOENT) { #ifndef FRONTEND elog(WARNING, "could not remove file or directory \"%s\": %m", pathbuf); #else fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"), pathbuf, strerror(errno)); #endif result = false; } } } } if (rmtopdir) { if (rmdir(path) != 0) { #ifndef FRONTEND elog(WARNING, "could not remove file or directory \"%s\": %m", path); #else fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"), path, strerror(errno)); #endif result = false; } } pgfnames_cleanup(filenames); return result; }
/* * Recursively scan the timezone database looking for the best match to * the system timezone behavior. * * tzdir points to a buffer of size MAXPGPATH. On entry, it holds the * pathname of a directory containing TZ files. We internally modify it * to hold pathnames of sub-directories and files, but must restore it * to its original contents before exit. * * tzdirsub points to the part of tzdir that represents the subfile name * (ie, tzdir + the original directory name length, plus one for the * first added '/'). * * tt tells about the system timezone behavior we need to match. * * *bestscore and *bestzonename on entry hold the best score found so far * and the name of the best zone. We overwrite them if we find a better * score. bestzonename must be a buffer of length TZ_STRLEN_MAX + 1. */ static void scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry *tt, int *bestscore, char *bestzonename) { int tzdir_orig_len = strlen(tzdir); char **names; char **namep; names = pgfnames(tzdir); if (!names) return; for (namep = names; *namep; namep++) { char *name = *namep; struct stat statbuf; /* Ignore . and .., plus any other "hidden" files */ if (name[0] == '.') continue; snprintf(tzdir + tzdir_orig_len, MAXPGPATH - tzdir_orig_len, "/%s", name); if (stat(tzdir, &statbuf) != 0) { #ifdef DEBUG_IDENTIFY_TIMEZONE fprintf(stderr, "could not stat \"%s\": %s\n", tzdir, strerror(errno)); #endif tzdir[tzdir_orig_len] = '\0'; continue; } if (S_ISDIR(statbuf.st_mode)) { /* Recurse into subdirectory */ scan_available_timezones(tzdir, tzdirsub, tt, bestscore, bestzonename); } else { /* Load and test this file */ int score = score_timezone(tzdirsub, tt); if (score > *bestscore) { *bestscore = score; strlcpy(bestzonename, tzdirsub, TZ_STRLEN_MAX + 1); } else if (score == *bestscore) { /* Consider how to break a tie */ if (strlen(tzdirsub) < strlen(bestzonename) || (strlen(tzdirsub) == strlen(bestzonename) && strcmp(tzdirsub, bestzonename) < 0)) strlcpy(bestzonename, tzdirsub, TZ_STRLEN_MAX + 1); } } /* Restore tzdir */ tzdir[tzdir_orig_len] = '\0'; } pgfnames_cleanup(names); }