X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=fd.c;h=763f756cdc3b5086ee9d26f432dbbfb760e02e4a;hb=HEAD;hp=d0de66f41be6008c2d3be5afe6dae002fb06ceb5;hpb=a3b9a75159d2530c931aa43f4a662b4d9bd3a4a3;p=paraslash.git diff --git a/fd.c b/fd.c index d0de66f4..1af902f9 100644 --- a/fd.c +++ b/fd.c @@ -260,64 +260,44 @@ int read_nonblock(int fd, void *buf, size_t sz, size_t *num_bytes) } /** - * Read a buffer and check its content for a pattern. + * Read a buffer and compare its contents to a string, ignoring case. * - * \param fd The file descriptor to receive from. - * \param pattern The expected pattern. - * \param bufsize The size of the internal buffer. - * - * This function tries to read at most \a bufsize bytes from the non-blocking - * file descriptor \a fd. If at least \p strlen(\a pattern) bytes have been - * received, the beginning of the received buffer is compared with \a pattern, - * ignoring case. + * \param fd The file descriptor to read from. + * \param expectation The expected string to compare to. * - * \return Positive if \a pattern was received, negative on errors, zero if no data - * was available to read. + * The given file descriptor is expected to be in non-blocking mode. The string + * comparison is performed using strncasecmp(3). * - * \sa \ref read_nonblock(), \sa strncasecmp(3). + * \return Zero if no data was available, positive if a buffer was read whose + * contents compare as equal to the expected string, negative otherwise. + * Possible errors: (a) not enough data was read, (b) the buffer contents + * compared as non-equal, (c) a read error occurred. In the first two cases, + * -E_READ_PATTERN is returned. In the read error case the (negative) return + * value of the underlying call to \ref read_nonblock() is returned. */ -int read_pattern(int fd, const char *pattern, size_t bufsize) +int read_and_compare(int fd, const char *expectation) { - size_t n, len; - char *buf = alloc(bufsize + 1); - int ret = read_nonblock(fd, buf, bufsize, &n); + size_t n, len = strlen(expectation); + char *buf = alloc(len + 1); + int ret = read_nonblock(fd, buf, len, &n); - buf[n] = '\0'; if (ret < 0) goto out; + buf[n] = '\0'; ret = 0; if (n == 0) goto out; ret = -E_READ_PATTERN; - len = strlen(pattern); if (n < len) goto out; - if (strncasecmp(buf, pattern, len) != 0) + if (strncasecmp(buf, expectation, len) != 0) goto out; ret = 1; out: - if (ret < 0) { - PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); - PARA_NOTICE_LOG("recvd %zu bytes: %s\n", n, buf); - } free(buf); return ret; } -/** - * Check whether a file exists. - * - * \param fn The file name. - * - * \return True iff file exists. - */ -bool file_exists(const char *fn) -{ - struct stat statbuf; - - return !stat(fn, &statbuf); -} - /** * Set a file descriptor to blocking mode. * @@ -407,86 +387,32 @@ int para_open(const char *path, int flags, mode_t mode) } /** - * Wrapper for chdir(2). + * Create a directory, don't fail if it already exists. * - * \param path The specified directory. - * - * \return Standard. - */ -int para_chdir(const char *path) -{ - int ret = chdir(path); - - if (ret >= 0) - return 1; - return -ERRNO_TO_PARA_ERROR(errno); -} - -/** - * Save the cwd and open a given directory. - * - * \param dirname Path to the directory to open. - * \param dir Result pointer. - * \param cwd File descriptor of the current working directory. - * - * \return Standard. - * - * Opening the current directory (".") and calling fchdir() to return is - * usually faster and more reliable than saving cwd in some buffer and calling - * chdir() afterwards. - * - * If \a cwd is not \p NULL "." is opened and the resulting file descriptor is - * stored in \a cwd. If the function returns success, and \a cwd is not \p - * NULL, the caller must close this file descriptor (probably after calling - * fchdir(*cwd)). - * - * On errors, the function undos everything, so the caller needs neither close - * any files, nor change back to the original working directory. + * \param path Name of the directory to create. * - * \sa getcwd(3). + * This function passes the fixed mode value 0777 to mkdir(3) (which consults + * the file creation mask and restricts this value). * + * \return Zero if the path already existed as a directory or as a symbolic + * link which leads to a directory, one if the path did not exist and the + * directory has been created successfully, negative error code else. */ -static int para_opendir(const char *dirname, DIR **dir, int *cwd) +int para_mkdir(const char *path) { - int ret; + /* + * We call opendir(3) rather than relying on stat(2) because this way + * we don't need extra code to get the symlink case right. + */ + DIR *dir = opendir(path); - *dir = NULL; - if (cwd) { - ret = para_open(".", O_RDONLY, 0); - if (ret < 0) - return ret; - *cwd = ret; - } - ret = para_chdir(dirname); - if (ret < 0) - goto close_cwd; - *dir = opendir("."); - if (*dir) - return 1; - ret = -ERRNO_TO_PARA_ERROR(errno); - /* Ignore return value of fchdir() and close(). We're busted anyway. */ - if (cwd) { - int __a_unused ret2 = fchdir(*cwd); /* STFU, gcc */ + if (dir) { + closedir(dir); + return 0; } -close_cwd: - if (cwd) - close(*cwd); - return ret; -} - -/** - * A wrapper for mkdir(2). - * - * \param path Name of the directory to create. - * \param mode The permissions to use. - * - * \return Standard. - */ -int para_mkdir(const char *path, mode_t mode) -{ - if (!mkdir(path, mode)) - return 1; - return -ERRNO_TO_PARA_ERROR(errno); + if (errno != ENOENT) + return -ERRNO_TO_PARA_ERROR(errno); + return mkdir(path, 0777) == 0? 1 : -ERRNO_TO_PARA_ERROR(errno); } /** @@ -559,22 +485,21 @@ out: * \param start The start address of the memory mapping. * \param length The size of the mapping. * - * \return Standard. + * If NULL is passed as the start address, the length value is ignored and the + * function does nothing. + * + * \return Zero if NULL was passed, one if the memory area was successfully + * unmapped, a negative error code otherwise. * * \sa munmap(2), \ref mmap_full_file(). */ int para_munmap(void *start, size_t length) { - int err; - if (!start) return 0; if (munmap(start, length) >= 0) return 1; - err = errno; - PARA_ERROR_LOG("munmap (%p/%zu) failed: %s\n", start, length, - strerror(err)); - return -ERRNO_TO_PARA_ERROR(err); + return -ERRNO_TO_PARA_ERROR(errno); } /** @@ -653,64 +578,3 @@ void valid_fd_012(void) } } } - -/** - * Traverse the given directory recursively. - * - * \param dirname The directory to traverse. - * \param func The function to call for each entry. - * \param private_data Pointer to an arbitrary data structure. - * - * For each regular file under \a dirname, the supplied function \a func is - * called. The full path of the regular file and the \a private_data pointer - * are passed to \a func. Directories for which the calling process has no - * permissions to change to are silently ignored. - * - * \return Standard. - */ -int for_each_file_in_dir(const char *dirname, - int (*func)(const char *, void *), void *private_data) -{ - DIR *dir; - struct dirent *entry; - int cwd_fd, ret = para_opendir(dirname, &dir, &cwd_fd); - - if (ret < 0) - return ret == -ERRNO_TO_PARA_ERROR(EACCES)? 1 : ret; - /* scan cwd recursively */ - while ((entry = readdir(dir))) { - mode_t m; - char *tmp; - struct stat s; - - if (!strcmp(entry->d_name, ".")) - continue; - if (!strcmp(entry->d_name, "..")) - continue; - if (lstat(entry->d_name, &s) == -1) - continue; - m = s.st_mode; - if (!S_ISREG(m) && !S_ISDIR(m)) - continue; - tmp = make_message("%s/%s", dirname, entry->d_name); - if (!S_ISDIR(m)) { - ret = func(tmp, private_data); - free(tmp); - if (ret < 0) - goto out; - continue; - } - /* directory */ - ret = for_each_file_in_dir(tmp, func, private_data); - free(tmp); - if (ret < 0) - goto out; - } - ret = 1; -out: - closedir(dir); - if (fchdir(cwd_fd) < 0 && ret >= 0) - ret = -ERRNO_TO_PARA_ERROR(errno); - close(cwd_fd); - return ret; -}