123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 |
- /*
- * Tests for util/filemonitor-*.c
- *
- * Copyright 2018 Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- */
- #include "qemu/osdep.h"
- #include "qemu/main-loop.h"
- #include "qapi/error.h"
- #include "qemu/filemonitor.h"
- #include <utime.h>
- enum {
- QFILE_MONITOR_TEST_OP_ADD_WATCH,
- QFILE_MONITOR_TEST_OP_DEL_WATCH,
- QFILE_MONITOR_TEST_OP_EVENT,
- QFILE_MONITOR_TEST_OP_CREATE,
- QFILE_MONITOR_TEST_OP_APPEND,
- QFILE_MONITOR_TEST_OP_TRUNC,
- QFILE_MONITOR_TEST_OP_RENAME,
- QFILE_MONITOR_TEST_OP_TOUCH,
- QFILE_MONITOR_TEST_OP_UNLINK,
- QFILE_MONITOR_TEST_OP_MKDIR,
- QFILE_MONITOR_TEST_OP_RMDIR,
- };
- typedef struct {
- int type;
- const char *filesrc;
- const char *filedst;
- int64_t *watchid;
- int eventid;
- /*
- * Only valid with OP_EVENT - this event might be
- * swapped with the next OP_EVENT
- */
- bool swapnext;
- } QFileMonitorTestOp;
- typedef struct {
- int64_t id;
- QFileMonitorEvent event;
- char *filename;
- } QFileMonitorTestRecord;
- typedef struct {
- QemuMutex lock;
- GList *records;
- } QFileMonitorTestData;
- static QemuMutex evlock;
- static bool evstopping;
- static bool evrunning;
- static bool debug;
- /*
- * Main function for a background thread that is
- * running the event loop during the test
- */
- static void *
- qemu_file_monitor_test_event_loop(void *opaque G_GNUC_UNUSED)
- {
- qemu_mutex_lock(&evlock);
- while (!evstopping) {
- qemu_mutex_unlock(&evlock);
- main_loop_wait(true);
- qemu_mutex_lock(&evlock);
- }
- evrunning = false;
- qemu_mutex_unlock(&evlock);
- return NULL;
- }
- /*
- * File monitor event handler which simply maintains
- * an ordered list of all events that it receives
- */
- static void
- qemu_file_monitor_test_handler(int64_t id,
- QFileMonitorEvent event,
- const char *filename,
- void *opaque)
- {
- QFileMonitorTestData *data = opaque;
- QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1);
- if (debug) {
- g_printerr("Queue event id %" PRIx64 " event %d file %s\n",
- id, event, filename);
- }
- rec->id = id;
- rec->event = event;
- rec->filename = g_strdup(filename);
- qemu_mutex_lock(&data->lock);
- data->records = g_list_append(data->records, rec);
- qemu_mutex_unlock(&data->lock);
- }
- static void
- qemu_file_monitor_test_record_free(QFileMonitorTestRecord *rec)
- {
- g_free(rec->filename);
- g_free(rec);
- }
- /*
- * Get the next event record that has been received by
- * the file monitor event handler. Since events are
- * emitted in the background thread running the event
- * loop, we can't assume there is a record available
- * immediately. Thus we will sleep for upto 5 seconds
- * to wait for the event to be queued for us.
- */
- static QFileMonitorTestRecord *
- qemu_file_monitor_test_next_record(QFileMonitorTestData *data,
- QFileMonitorTestRecord *pushback)
- {
- GTimer *timer = g_timer_new();
- QFileMonitorTestRecord *record = NULL;
- GList *tmp;
- qemu_mutex_lock(&data->lock);
- while (!data->records && g_timer_elapsed(timer, NULL) < 5) {
- qemu_mutex_unlock(&data->lock);
- usleep(10 * 1000);
- qemu_mutex_lock(&data->lock);
- }
- if (data->records) {
- record = data->records->data;
- if (pushback) {
- data->records->data = pushback;
- } else {
- tmp = data->records;
- data->records = g_list_remove_link(data->records, tmp);
- g_list_free(tmp);
- }
- } else if (pushback) {
- qemu_file_monitor_test_record_free(pushback);
- }
- qemu_mutex_unlock(&data->lock);
- g_timer_destroy(timer);
- return record;
- }
- /*
- * Check whether the event record we retrieved matches
- * data we were expecting to see for the event
- */
- static bool
- qemu_file_monitor_test_expect(QFileMonitorTestData *data,
- int64_t id,
- QFileMonitorEvent event,
- const char *filename,
- bool swapnext)
- {
- QFileMonitorTestRecord *rec;
- bool ret = false;
- rec = qemu_file_monitor_test_next_record(data, NULL);
- retry:
- if (!rec) {
- g_printerr("Missing event watch id %" PRIx64 " event %d file %s\n",
- id, event, filename);
- return false;
- }
- if (id != rec->id) {
- if (swapnext) {
- rec = qemu_file_monitor_test_next_record(data, rec);
- swapnext = false;
- goto retry;
- }
- g_printerr("Expected watch id %" PRIx64 " but got %" PRIx64 "\n",
- id, rec->id);
- goto cleanup;
- }
- if (event != rec->event) {
- g_printerr("Expected event %d but got %d\n", event, rec->event);
- goto cleanup;
- }
- if (!g_str_equal(filename, rec->filename)) {
- g_printerr("Expected filename %s but got %s\n",
- filename, rec->filename);
- goto cleanup;
- }
- ret = true;
- cleanup:
- qemu_file_monitor_test_record_free(rec);
- return ret;
- }
- static void
- test_file_monitor_events(void)
- {
- int64_t watch0 = 0;
- int64_t watch1 = 0;
- int64_t watch2 = 0;
- int64_t watch3 = 0;
- int64_t watch4 = 0;
- int64_t watch5 = 0;
- QFileMonitorTestOp ops[] = {
- { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
- .filesrc = NULL, .watchid = &watch0 },
- { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
- .filesrc = "one.txt", .watchid = &watch1 },
- { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
- .filesrc = "two.txt", .watchid = &watch2 },
- { .type = QFILE_MONITOR_TEST_OP_CREATE,
- .filesrc = "one.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = &watch1,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_CREATE,
- .filesrc = "two.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch2,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_CREATE,
- .filesrc = "three.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "three.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_UNLINK,
- .filesrc = "three.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "three.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_DELETED },
- { .type = QFILE_MONITOR_TEST_OP_RENAME,
- .filesrc = "one.txt", .filedst = "two.txt" },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_DELETED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = &watch1,
- .eventid = QFILE_MONITOR_EVENT_DELETED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch2,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_APPEND,
- .filesrc = "two.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_MODIFIED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch2,
- .eventid = QFILE_MONITOR_EVENT_MODIFIED },
- { .type = QFILE_MONITOR_TEST_OP_TOUCH,
- .filesrc = "two.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_ATTRIBUTES },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch2,
- .eventid = QFILE_MONITOR_EVENT_ATTRIBUTES },
- { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
- .filesrc = "one.txt", .watchid = &watch1 },
- { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
- .filesrc = "one.txt", .watchid = &watch3 },
- { .type = QFILE_MONITOR_TEST_OP_CREATE,
- .filesrc = "one.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = &watch3,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
- .filesrc = "one.txt", .watchid = &watch3 },
- { .type = QFILE_MONITOR_TEST_OP_UNLINK,
- .filesrc = "one.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_DELETED },
- { .type = QFILE_MONITOR_TEST_OP_MKDIR,
- .filesrc = "fish", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "fish", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
- .filesrc = "fish/", .watchid = &watch4 },
- { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
- .filesrc = "fish/one.txt", .watchid = &watch5 },
- { .type = QFILE_MONITOR_TEST_OP_CREATE,
- .filesrc = "fish/one.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = &watch4,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = &watch5,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
- .filesrc = "fish/one.txt", .watchid = &watch5 },
- { .type = QFILE_MONITOR_TEST_OP_RENAME,
- .filesrc = "fish/one.txt", .filedst = "two.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = &watch4,
- .eventid = QFILE_MONITOR_EVENT_DELETED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch2,
- .eventid = QFILE_MONITOR_EVENT_CREATED },
- { .type = QFILE_MONITOR_TEST_OP_RMDIR,
- .filesrc = "fish", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "", .watchid = &watch4,
- .eventid = QFILE_MONITOR_EVENT_IGNORED,
- .swapnext = true },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "fish", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_DELETED },
- { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
- .filesrc = "fish", .watchid = &watch4 },
- { .type = QFILE_MONITOR_TEST_OP_UNLINK,
- .filesrc = "two.txt", },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch0,
- .eventid = QFILE_MONITOR_EVENT_DELETED },
- { .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = &watch2,
- .eventid = QFILE_MONITOR_EVENT_DELETED },
- { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
- .filesrc = "two.txt", .watchid = &watch2 },
- { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
- .filesrc = NULL, .watchid = &watch0 },
- };
- Error *local_err = NULL;
- GError *gerr = NULL;
- QFileMonitor *mon = qemu_file_monitor_new(&local_err);
- QemuThread th;
- GTimer *timer;
- gchar *dir = NULL;
- int err = -1;
- gsize i;
- char *pathsrc = NULL;
- char *pathdst = NULL;
- QFileMonitorTestData data;
- GHashTable *ids = g_hash_table_new(g_int64_hash, g_int64_equal);
- qemu_mutex_init(&data.lock);
- data.records = NULL;
- /*
- * The file monitor needs the main loop running in
- * order to receive events from inotify. We must
- * thus spawn a background thread to run an event
- * loop impl, while this thread triggers the
- * actual file operations we're testing
- */
- evrunning = 1;
- evstopping = 0;
- qemu_thread_create(&th, "event-loop",
- qemu_file_monitor_test_event_loop, NULL,
- QEMU_THREAD_JOINABLE);
- if (local_err) {
- g_printerr("File monitoring not available: %s",
- error_get_pretty(local_err));
- error_free(local_err);
- return;
- }
- dir = g_dir_make_tmp("test-util-filemonitor-XXXXXX",
- &gerr);
- if (!dir) {
- g_printerr("Unable to create tmp dir %s",
- gerr->message);
- g_error_free(gerr);
- abort();
- }
- /*
- * Run through the operation sequence validating events
- * as we go
- */
- for (i = 0; i < G_N_ELEMENTS(ops); i++) {
- const QFileMonitorTestOp *op = &(ops[i]);
- int fd;
- struct utimbuf ubuf;
- char *watchdir;
- const char *watchfile;
- pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc);
- if (op->filedst) {
- pathdst = g_strdup_printf("%s/%s", dir, op->filedst);
- }
- switch (op->type) {
- case QFILE_MONITOR_TEST_OP_ADD_WATCH:
- if (debug) {
- g_printerr("Add watch %s %s\n",
- dir, op->filesrc);
- }
- if (op->filesrc && strchr(op->filesrc, '/')) {
- watchdir = g_strdup_printf("%s/%s", dir, op->filesrc);
- watchfile = strrchr(watchdir, '/');
- *(char *)watchfile = '\0';
- watchfile++;
- if (*watchfile == '\0') {
- watchfile = NULL;
- }
- } else {
- watchdir = g_strdup(dir);
- watchfile = op->filesrc;
- }
- *op->watchid =
- qemu_file_monitor_add_watch(mon,
- watchdir,
- watchfile,
- qemu_file_monitor_test_handler,
- &data,
- &local_err);
- g_free(watchdir);
- if (*op->watchid < 0) {
- g_printerr("Unable to add watch %s",
- error_get_pretty(local_err));
- goto cleanup;
- }
- if (debug) {
- g_printerr("Watch ID %" PRIx64 "\n", *op->watchid);
- }
- if (g_hash_table_contains(ids, op->watchid)) {
- g_printerr("Watch ID %" PRIx64 "already exists", *op->watchid);
- goto cleanup;
- }
- g_hash_table_add(ids, op->watchid);
- break;
- case QFILE_MONITOR_TEST_OP_DEL_WATCH:
- if (debug) {
- g_printerr("Del watch %s %" PRIx64 "\n", dir, *op->watchid);
- }
- if (op->filesrc && strchr(op->filesrc, '/')) {
- watchdir = g_strdup_printf("%s/%s", dir, op->filesrc);
- watchfile = strrchr(watchdir, '/');
- *(char *)watchfile = '\0';
- } else {
- watchdir = g_strdup(dir);
- }
- g_hash_table_remove(ids, op->watchid);
- qemu_file_monitor_remove_watch(mon,
- watchdir,
- *op->watchid);
- g_free(watchdir);
- break;
- case QFILE_MONITOR_TEST_OP_EVENT:
- if (debug) {
- g_printerr("Event id=%" PRIx64 " event=%d file=%s\n",
- *op->watchid, op->eventid, op->filesrc);
- }
- if (!qemu_file_monitor_test_expect(&data, *op->watchid,
- op->eventid, op->filesrc,
- op->swapnext))
- goto cleanup;
- break;
- case QFILE_MONITOR_TEST_OP_CREATE:
- if (debug) {
- g_printerr("Create %s\n", pathsrc);
- }
- fd = open(pathsrc, O_WRONLY | O_CREAT, 0700);
- if (fd < 0) {
- g_printerr("Unable to create %s: %s",
- pathsrc, strerror(errno));
- goto cleanup;
- }
- close(fd);
- break;
- case QFILE_MONITOR_TEST_OP_APPEND:
- if (debug) {
- g_printerr("Append %s\n", pathsrc);
- }
- fd = open(pathsrc, O_WRONLY | O_APPEND, 0700);
- if (fd < 0) {
- g_printerr("Unable to open %s: %s",
- pathsrc, strerror(errno));
- goto cleanup;
- }
- if (write(fd, "Hello World", 10) != 10) {
- g_printerr("Unable to write %s: %s",
- pathsrc, strerror(errno));
- close(fd);
- goto cleanup;
- }
- close(fd);
- break;
- case QFILE_MONITOR_TEST_OP_TRUNC:
- if (debug) {
- g_printerr("Truncate %s\n", pathsrc);
- }
- if (truncate(pathsrc, 4) < 0) {
- g_printerr("Unable to truncate %s: %s",
- pathsrc, strerror(errno));
- goto cleanup;
- }
- break;
- case QFILE_MONITOR_TEST_OP_RENAME:
- if (debug) {
- g_printerr("Rename %s -> %s\n", pathsrc, pathdst);
- }
- if (rename(pathsrc, pathdst) < 0) {
- g_printerr("Unable to rename %s to %s: %s",
- pathsrc, pathdst, strerror(errno));
- goto cleanup;
- }
- break;
- case QFILE_MONITOR_TEST_OP_UNLINK:
- if (debug) {
- g_printerr("Unlink %s\n", pathsrc);
- }
- if (unlink(pathsrc) < 0) {
- g_printerr("Unable to unlink %s: %s",
- pathsrc, strerror(errno));
- goto cleanup;
- }
- break;
- case QFILE_MONITOR_TEST_OP_TOUCH:
- if (debug) {
- g_printerr("Touch %s\n", pathsrc);
- }
- ubuf.actime = 1024;
- ubuf.modtime = 1025;
- if (utime(pathsrc, &ubuf) < 0) {
- g_printerr("Unable to touch %s: %s",
- pathsrc, strerror(errno));
- goto cleanup;
- }
- break;
- case QFILE_MONITOR_TEST_OP_MKDIR:
- if (debug) {
- g_printerr("Mkdir %s\n", pathsrc);
- }
- if (mkdir(pathsrc, 0700) < 0) {
- g_printerr("Unable to mkdir %s: %s",
- pathsrc, strerror(errno));
- goto cleanup;
- }
- break;
- case QFILE_MONITOR_TEST_OP_RMDIR:
- if (debug) {
- g_printerr("Rmdir %s\n", pathsrc);
- }
- if (rmdir(pathsrc) < 0) {
- g_printerr("Unable to rmdir %s: %s",
- pathsrc, strerror(errno));
- goto cleanup;
- }
- break;
- default:
- g_assert_not_reached();
- }
- g_free(pathsrc);
- g_free(pathdst);
- pathsrc = pathdst = NULL;
- }
- g_assert_cmpint(g_hash_table_size(ids), ==, 0);
- err = 0;
- cleanup:
- g_free(pathsrc);
- g_free(pathdst);
- qemu_mutex_lock(&evlock);
- evstopping = 1;
- timer = g_timer_new();
- while (evrunning && g_timer_elapsed(timer, NULL) < 5) {
- qemu_mutex_unlock(&evlock);
- usleep(10 * 1000);
- qemu_mutex_lock(&evlock);
- }
- qemu_mutex_unlock(&evlock);
- if (g_timer_elapsed(timer, NULL) >= 5) {
- g_printerr("Event loop failed to quit after 5 seconds\n");
- }
- g_timer_destroy(timer);
- qemu_file_monitor_free(mon);
- g_list_foreach(data.records,
- (GFunc)qemu_file_monitor_test_record_free, NULL);
- g_list_free(data.records);
- qemu_mutex_destroy(&data.lock);
- if (dir) {
- for (i = 0; i < G_N_ELEMENTS(ops); i++) {
- const QFileMonitorTestOp *op = &(ops[i]);
- char *path = g_strdup_printf("%s/%s",
- dir, op->filesrc);
- if (op->type == QFILE_MONITOR_TEST_OP_MKDIR) {
- rmdir(path);
- g_free(path);
- } else {
- unlink(path);
- g_free(path);
- if (op->filedst) {
- path = g_strdup_printf("%s/%s",
- dir, op->filedst);
- unlink(path);
- g_free(path);
- }
- }
- }
- if (rmdir(dir) < 0) {
- g_printerr("Failed to remove %s: %s\n",
- dir, strerror(errno));
- abort();
- }
- }
- g_hash_table_unref(ids);
- g_free(dir);
- g_assert(err == 0);
- }
- int main(int argc, char **argv)
- {
- g_test_init(&argc, &argv, NULL);
- qemu_init_main_loop(&error_abort);
- qemu_mutex_init(&evlock);
- debug = getenv("FILEMONITOR_DEBUG") != NULL;
- g_test_add_func("/util/filemonitor", test_file_monitor_events);
- return g_test_run();
- }
|