diff options
Diffstat (limited to 'cras/src/common/cras_file_wait.c')
-rw-r--r-- | cras/src/common/cras_file_wait.c | 319 |
1 files changed, 0 insertions, 319 deletions
diff --git a/cras/src/common/cras_file_wait.c b/cras/src/common/cras_file_wait.c deleted file mode 100644 index 190a5e10..00000000 --- a/cras/src/common/cras_file_wait.c +++ /dev/null @@ -1,319 +0,0 @@ -/* Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include <errno.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <sys/inotify.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "cras_file_wait.h" - -#define CRAS_FILE_WAIT_EVENT_MIN_SIZE sizeof(struct inotify_event) -#define CRAS_FILE_WAIT_EVENT_SIZE (CRAS_FILE_WAIT_EVENT_MIN_SIZE + NAME_MAX + 1) -#define CRAS_FILE_WAIT_FLAG_MOCK_RACE (1u << 31) - -struct cras_file_wait { - cras_file_wait_callback_t callback; - void *callback_context; - const char *file_path; - size_t file_path_len; - char *watch_path; - char *watch_dir; - char *watch_file_name; - size_t watch_file_name_len; - int inotify_fd; - int watch_id; - char event_buf[CRAS_FILE_WAIT_EVENT_SIZE]; - cras_file_wait_flag_t flags; -}; - -int cras_file_wait_get_fd(struct cras_file_wait *file_wait) -{ - if (!file_wait) - return -EINVAL; - if (file_wait->inotify_fd < 0) - return -EINVAL; - return file_wait->inotify_fd; -} - -/* Defined for the unittest. */ -void cras_file_wait_mock_race_condition(struct cras_file_wait *file_wait); -void cras_file_wait_mock_race_condition(struct cras_file_wait *file_wait) -{ - if (file_wait) - file_wait->flags |= CRAS_FILE_WAIT_FLAG_MOCK_RACE; -} - -void cras_file_wait_destroy(struct cras_file_wait *file_wait) -{ - if (!file_wait) - return; - if (file_wait->inotify_fd >= 0) - close(file_wait->inotify_fd); - free(file_wait); -} - -static int cras_file_wait_rm_watch(struct cras_file_wait *file_wait) -{ - int rc; - - file_wait->watch_path[0] = 0; - file_wait->watch_dir[0] = 0; - file_wait->watch_file_name[0] = 0; - file_wait->watch_file_name_len = 0; - if (file_wait->inotify_fd >= 0 && file_wait->watch_id >= 0) { - rc = inotify_rm_watch(file_wait->inotify_fd, - file_wait->watch_id); - file_wait->watch_id = -1; - if (rc < 0) - return -errno; - } - return 0; -} - -int cras_file_wait_process_event(struct cras_file_wait *file_wait, - struct inotify_event *event) -{ - cras_file_wait_event_t file_wait_event; - - syslog(LOG_DEBUG, - "file_wait->watch_id: %d, event->wd: %d" - ", event->mask: %x, event->name: %s", - file_wait->watch_id, event->wd, event->mask, - event->len ? event->name : ""); - - if (event->wd != file_wait->watch_id) - return 0; - - if (event->mask & IN_IGNORED) { - /* The watch has been removed. */ - file_wait->watch_id = -1; - return cras_file_wait_rm_watch(file_wait); - } - - if (event->len == 0 || - memcmp(event->name, file_wait->watch_file_name, - file_wait->watch_file_name_len + 1) != 0) { - /* Some file we don't care about. */ - return 0; - } - - if ((event->mask & (IN_CREATE | IN_MOVED_TO)) != 0) - file_wait_event = CRAS_FILE_WAIT_EVENT_CREATED; - else if ((event->mask & (IN_DELETE | IN_MOVED_FROM)) != 0) - file_wait_event = CRAS_FILE_WAIT_EVENT_DELETED; - else - return 0; - - /* Found the file! */ - if (strcmp(file_wait->watch_path, file_wait->file_path) == 0) { - /* Tell the caller about this creation or deletion. */ - file_wait->callback(file_wait->callback_context, - file_wait_event, event->name); - } else { - /* Remove the watch for this file, move on. */ - return cras_file_wait_rm_watch(file_wait); - } - return 0; -} - -int cras_file_wait_dispatch(struct cras_file_wait *file_wait) -{ - struct inotify_event *event; - char *watch_dir_end; - size_t watch_dir_len; - char *watch_file_start; - size_t watch_path_len; - int rc = 0; - int flags; - ssize_t read_rc; - ssize_t read_offset; - - if (!file_wait) - return -EINVAL; - - /* If we have a file-descriptor, then read it and see what's up. */ - if (file_wait->inotify_fd >= 0) { - read_offset = 0; - read_rc = read(file_wait->inotify_fd, file_wait->event_buf, - CRAS_FILE_WAIT_EVENT_SIZE); - if (read_rc < 0) { - rc = -errno; - if ((rc == -EAGAIN || rc == -EWOULDBLOCK) && - file_wait->watch_id < 0) { - /* Really nothing to read yet: we need to - * setup a watch. */ - rc = 0; - } - } else if (read_rc < CRAS_FILE_WAIT_EVENT_MIN_SIZE) { - rc = -EIO; - } else if (file_wait->watch_id < 0) { - /* Processing messages related to old watches. */ - rc = 0; - } else - while (rc == 0 && read_offset < read_rc) { - event = (struct inotify_event - *)(file_wait->event_buf + - read_offset); - read_offset += sizeof(*event) + event->len; - rc = cras_file_wait_process_event(file_wait, - event); - } - } - - /* Report errors from above here. */ - if (rc < 0) - return rc; - - if (file_wait->watch_id >= 0) { - /* Assume that the watch that we have is the right one. */ - return 0; - } - - /* Initialize inotify if we haven't already. */ - if (file_wait->inotify_fd < 0) { - file_wait->inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); - if (file_wait->inotify_fd < 0) - return -errno; - } - - /* Figure out what we need to watch next. */ - rc = -ENOENT; - strcpy(file_wait->watch_dir, file_wait->file_path); - watch_dir_len = file_wait->file_path_len; - - while (rc == -ENOENT || rc == -EACCES) { - strcpy(file_wait->watch_path, file_wait->watch_dir); - watch_path_len = watch_dir_len; - - /* Find the end of the parent directory. */ - watch_dir_end = file_wait->watch_dir + watch_dir_len - 1; - while (watch_dir_end > file_wait->watch_dir && - *watch_dir_end != '/') - watch_dir_end--; - watch_file_start = watch_dir_end + 1; - /* Treat consecutive '/' characters as one. */ - while (watch_dir_end > file_wait->watch_dir && - *(watch_dir_end - 1) == '/') - watch_dir_end--; - watch_dir_len = watch_dir_end - file_wait->watch_dir; - - if (watch_dir_len == 0) { - /* We're looking for a file in the current directory. */ - strcpy(file_wait->watch_file_name, - file_wait->watch_path); - file_wait->watch_file_name_len = watch_path_len; - strcpy(file_wait->watch_dir, "."); - watch_dir_len = 1; - } else { - /* Copy out the file name that we're looking for, and - * mark the end of the directory path. */ - strcpy(file_wait->watch_file_name, watch_file_start); - file_wait->watch_file_name_len = - watch_path_len - - (watch_file_start - file_wait->watch_dir); - *watch_dir_end = 0; - } - - if (file_wait->flags & CRAS_FILE_WAIT_FLAG_MOCK_RACE) { - /* For testing only. */ - mknod(file_wait->watch_path, S_IFREG | 0600, 0); - file_wait->flags &= ~CRAS_FILE_WAIT_FLAG_MOCK_RACE; - } - - flags = IN_CREATE | IN_MOVED_TO | IN_DELETE | IN_MOVED_FROM; - file_wait->watch_id = inotify_add_watch( - file_wait->inotify_fd, file_wait->watch_dir, flags); - if (file_wait->watch_id < 0) { - rc = -errno; - continue; - } - - /* Satisfy the race condition between existence of the - * file and creation of the watch. */ - rc = access(file_wait->watch_path, F_OK); - if (rc < 0) { - rc = -errno; - if (rc == -ENOENT) { - /* As expected, the file still doesn't exist. */ - rc = 0; - } - continue; - } - - /* The file we're looking for exists. */ - if (strcmp(file_wait->watch_path, file_wait->file_path) == 0) { - file_wait->callback(file_wait->callback_context, - CRAS_FILE_WAIT_EVENT_CREATED, - file_wait->watch_file_name); - return 0; - } - - /* Start over again. */ - rc = cras_file_wait_rm_watch(file_wait); - if (rc < 0) - return rc; - rc = -ENOENT; - strcpy(file_wait->watch_dir, file_wait->file_path); - watch_dir_len = file_wait->file_path_len; - } - - /* Get out for permissions problems for example. */ - return rc; -} - -int cras_file_wait_create(const char *file_path, cras_file_wait_flag_t flags, - cras_file_wait_callback_t callback, - void *callback_context, - struct cras_file_wait **file_wait_out) -{ - struct cras_file_wait *file_wait; - size_t file_path_len; - int rc; - - if (!file_path || !*file_path || !callback || !file_wait_out) - return -EINVAL; - *file_wait_out = NULL; - - /* Create a struct cras_file_wait to track waiting for this file. */ - file_path_len = strlen(file_path); - file_wait = (struct cras_file_wait *)calloc( - 1, sizeof(*file_wait) + ((file_path_len + 1) * 5)); - if (!file_wait) - return -ENOMEM; - file_wait->callback = callback; - file_wait->callback_context = callback_context; - file_wait->inotify_fd = -1; - file_wait->watch_id = -1; - file_wait->file_path_len = file_path_len; - file_wait->flags = flags; - - /* We've allocated memory such that the file_path, watch_path, - * watch_dir, and watch_file_name data are appended to the end of - * our cras_file_wait structure. */ - file_wait->file_path = (const char *)file_wait + sizeof(*file_wait); - file_wait->watch_path = - (char *)file_wait->file_path + file_path_len + 1; - file_wait->watch_dir = file_wait->watch_path + file_path_len + 1; - file_wait->watch_file_name = file_wait->watch_dir + file_path_len + 1; - memcpy((void *)file_wait->file_path, file_path, file_path_len + 1); - - /* Setup the first watch. If that fails unexpectedly, then we destroy - * the file wait structure immediately. */ - rc = cras_file_wait_dispatch(file_wait); - if (rc < 0) { - cras_file_wait_destroy(file_wait); - return rc; - } - - *file_wait_out = file_wait; - return 0; -} |