/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include #include #include #include #include #include #include #include "gcc-compat.h" #include "err.h" #include "str.h" #include "file.h" /* * Call a function for each subdirectory of the current working directory. * * For each top-level directory under dirname, the supplied callback function * is called, passing the full path to the subdirectory and the private_data * pointer. * * If the callback returns a negative error value, the loop is terminated and * that negative value is returned to the caller. If the iteration completes * with no errors, the function returns non-negative. */ int for_each_subdir(int (*func)(const char *, void *), void *private_data) { struct dirent *entry; int ret; DIR *dir = opendir("."); if (!dir) return -ERRNO_TO_DSS_ERROR(errno); while ((entry = readdir(dir))) { mode_t m; struct stat s; if (!strcmp(entry->d_name, ".")) continue; if (!strcmp(entry->d_name, "..")) continue; ret = lstat(entry->d_name, &s) == -1; if (ret == -1) { ret = -ERRNO_TO_DSS_ERROR(errno); goto out; } m = s.st_mode; if (!S_ISDIR(m)) continue; ret = func(entry->d_name, private_data); if (ret < 0) goto out; } ret = 1; out: closedir(dir); return ret; } /* Set a file descriptor to non-blocking mode. */ __must_check int mark_fd_nonblocking(int fd) { int flags = fcntl(fd, F_GETFL); if (flags < 0) return -ERRNO_TO_DSS_ERROR(errno); flags = fcntl(fd, F_SETFL, ((long)flags) | O_NONBLOCK); if (flags < 0) return -ERRNO_TO_DSS_ERROR(errno); return 1; } /* * Call select(2) with no exceptfds and start over if the call was interrupted * by a signal. All arguments are passed verbatim to select(2). Returns the * return value of the underlying select call on success, a negative error code * on error. */ int dss_select(int n, fd_set *readfds, fd_set *writefds, struct timeval *timeout_tv) { int ret, err; do { ret = select(n, readfds, writefds, NULL, timeout_tv); err = errno; } while (ret < 0 && err == EINTR); if (ret < 0) return -ERRNO_TO_DSS_ERROR(errno); return ret; }