/*------------------------------------------------------------------------- * * pgcheckdir.c * * A simple subroutine to check whether a directory exists and is empty or not. * Useful in both initdb and the backend. * * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * src/port/pgcheckdir.c *------------------------------------------------------------------------- */ #include "c.h" #include /* * Test to see if a directory exists and is empty or not. * * Returns: * 0 if nonexistent * 1 if exists and empty * 2 if exists and contains _only_ dot files * 3 if exists and contains a mount point * 4 if exists and not empty * -1 if trouble accessing directory (errno reflects the error) */ int pg_check_dir(const char *dir) { int result = 1; DIR *chkdir; struct dirent *file; bool dot_found = false; bool mount_found = false; int readdir_errno; chkdir = opendir(dir); if (chkdir == NULL) return (errno == ENOENT) ? 0 : -1; while (errno = 0, (file = readdir(chkdir)) != NULL) { if (strcmp(".", file->d_name) == 0 || strcmp("..", file->d_name) == 0) { /* skip this and parent directory */ continue; } #ifndef WIN32 /* file starts with "." */ else if (file->d_name[0] == '.') { dot_found = true; } /* lost+found directory */ else if (strcmp("lost+found", file->d_name) == 0) { mount_found = true; } #endif else { result = 4; /* not empty */ break; } } if (errno) result = -1; /* some kind of I/O error? */ /* Close chkdir and avoid overwriting the readdir errno on success */ readdir_errno = errno; if (closedir(chkdir)) result = -1; /* error executing closedir */ else errno = readdir_errno; /* We report on mount point if we find a lost+found directory */ if (result == 1 && mount_found) result = 3; /* We report on dot-files if we _only_ find dot files */ if (result == 1 && dot_found) result = 2; return result; }