summaryrefslogtreecommitdiff
path: root/src/aio
diff options
context:
space:
mode:
Diffstat (limited to 'src/aio')
-rw-r--r--src/aio/CMakeLists.txt11
-rw-r--r--src/aio/include/aio.h39
-rw-r--r--src/aio/private_include/aio/types.h34
-rw-r--r--src/aio/src/CMakeLists.txt9
-rw-r--r--src/aio/src/free.c (renamed from src/aio/src/close.c)13
-rw-r--r--src/aio/src/mkdir.c137
-rw-r--r--src/aio/src/mount.c175
-rw-r--r--src/aio/src/open.c102
-rw-r--r--src/aio/src/poll.c74
-rw-r--r--src/aio/src/stat.c118
-rw-r--r--src/aio/src/write.c79
11 files changed, 755 insertions, 36 deletions
diff --git a/src/aio/CMakeLists.txt b/src/aio/CMakeLists.txt
index 3f4561a..a335457 100644
--- a/src/aio/CMakeLists.txt
+++ b/src/aio/CMakeLists.txt
@@ -1,6 +1,11 @@
set(src
- "src/close.c"
- "src/open.c"
+ src/free.c
+ src/mkdir.c
+ src/mount.c
+ src/open.c
+ src/poll.c
)
add_library(aio ${src})
-target_include_directories(aio PUBLIC "include" PRIVATE "private_include")
+add_subdirectory(src)
+target_include_directories(aio PUBLIC include PRIVATE private_include)
+target_link_libraries(aio PUBLIC fs INTERFACE state)
diff --git a/src/aio/include/aio.h b/src/aio/include/aio.h
index f9f76cb..cea6ee1 100644
--- a/src/aio/include/aio.h
+++ b/src/aio/include/aio.h
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wanix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -19,17 +19,40 @@
#ifndef AIO_H
#define AIO_H
+#include <fs/fs.h>
+#include <sys/types.h>
+#include <state.h>
+#include <stdbool.h>
#include <stddef.h>
-enum
+struct aio_poll
{
- AIO_POLLIN = 1,
- AIO_POLLOUT = 1 << 1
+ const struct aio *aio;
+ bool done;
+ int error;
+ struct aio_poll *prev, *next;
};
-struct aio *aio_open(const char *path, const char *mode);
-int aio_poll(struct aio **io, size_t n);
-int aio_event(const struct aio *io, int ev);
-int aio_close(struct aio *io);
+struct aio_done
+{
+ int (*f)(enum state state, void *args);
+ void *args;
+};
+
+struct aio_mount
+{
+ struct fs_mount mount;
+ const char *type;
+};
+
+struct aio *aio_mount(const struct aio_mount *m, const struct aio_done *d);
+struct aio *aio_mkdir(const struct fs_mkdir *m, const struct aio_done *d);
+struct aio *aio_open(const struct fs_open *o, const struct aio_done *d);
+struct aio *aio_read(const struct fs_read *r, const struct aio_done *d);
+struct aio *aio_write(const struct fs_write *w, const struct aio_done *d);
+struct aio *aio_close(const struct fs_close *c, const struct aio_done *d);
+struct aio *aio_stat(const struct fs_stat *s, const struct aio_done *d);
+int aio_poll(struct aio_poll *p, int ms);
+void aio_free(struct aio *io);
#endif
diff --git a/src/aio/private_include/aio/types.h b/src/aio/private_include/aio/types.h
index 31ee414..32a7545 100644
--- a/src/aio/private_include/aio/types.h
+++ b/src/aio/private_include/aio/types.h
@@ -1,16 +1,32 @@
-#ifndef AIO_PRV_OPEN_H
-#define AIO_PRV_OPEN_H
+/*
+ * wanix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
-enum aio_state
-{
- AIO_OK,
- AIO_AGAIN,
- AIO_FATAL
-};
+#ifndef AIO_TYPES_H
+#define AIO_TYPES_H
+
+#include <aio.h>
+#include <fs/fs.h>
struct aio
{
- enum aio_state (*next)(struct aio *);
+ int error;
+ struct fs_ret r;
+ struct aio_done done;
};
#endif
diff --git a/src/aio/src/CMakeLists.txt b/src/aio/src/CMakeLists.txt
new file mode 100644
index 0000000..8848842
--- /dev/null
+++ b/src/aio/src/CMakeLists.txt
@@ -0,0 +1,9 @@
+target_sources(aio PRIVATE
+ free.c
+ mkdir.c
+ mount.c
+ open.c
+ poll.c
+ stat.c
+ write.c
+)
diff --git a/src/aio/src/close.c b/src/aio/src/free.c
index a6067a8..3a84f1b 100644
--- a/src/aio/src/close.c
+++ b/src/aio/src/free.c
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wanix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -17,18 +17,9 @@
*/
#include <aio.h>
-#include <errno.h>
-#include <stdio.h>
#include <stdlib.h>
-int aio_close(struct aio *const aio)
+void aio_free(struct aio *const aio)
{
- if (!aio)
- {
- errno = EINVAL;
- return EOF;
- }
-
free(aio);
- return 0;
}
diff --git a/src/aio/src/mkdir.c b/src/aio/src/mkdir.c
new file mode 100644
index 0000000..3a7fae6
--- /dev/null
+++ b/src/aio/src/mkdir.c
@@ -0,0 +1,137 @@
+/*
+ * wanix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <aio/types.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct mkdir
+{
+ struct fs_mkdir mkdir;
+ struct aio_done done;
+ char *path, *parent;
+ struct aio *aio;
+};
+
+static void free_mkdir(struct mkdir *const mk)
+{
+ if (mk)
+ {
+ free(mk->path);
+ free(mk->parent);
+ }
+
+ free(mk);
+}
+
+static int done(const enum state state, void *const args)
+{
+ int ret = 0;
+ struct mkdir *const mk = args;
+ const struct aio_done *const d = &mk->done;
+
+ if (d->f)
+ ret = d->f(state, d->args);
+
+ free_mkdir(mk);
+ return ret;
+}
+
+static int search_done(const enum state state,
+ const char *const relpath, const struct fs_mp *const mp,
+ const union inode_result *const inode, void *const args)
+{
+ struct mkdir *const mk = args;
+ struct aio *const aio = mk->aio;
+ const struct fs *const fs = mp->fs;
+ const char *path = mk->path;
+ struct fs_ret r;
+
+ path += strlen(mp->tgt) + strlen(relpath);
+ mk->mkdir.path = path;
+
+ if (fs->mkdir(&mk->mkdir, mp, inode, &r))
+ goto failure;
+
+ aio->r = r;
+ return 0;
+
+failure:
+ aio->error = errno;
+ aio->done = mk->done;
+ free_mkdir(mk);
+ return -1;
+}
+
+struct aio *aio_mkdir(const struct fs_mkdir *const m,
+ const struct aio_done *const d)
+{
+ struct aio *aio = NULL;
+ struct mkdir *mk = NULL;
+ char *const pathdup = strdup(m->path), *parent = NULL;
+
+ if (!pathdup
+ || !(parent = fs_parent(m->path))
+ || !(mk = malloc(sizeof *mk))
+ || !(aio = malloc(sizeof *aio)))
+ goto failure;
+
+ *mk = (const struct mkdir)
+ {
+ .path = pathdup,
+ .parent = parent,
+ .aio = aio,
+ .mkdir = *m
+ };
+
+ *aio = (const struct aio)
+ {
+ .done =
+ {
+ .args = mk,
+ .f = done
+ }
+ };
+
+ const struct inode_search s =
+ {
+ .path = parent,
+ .done = search_done,
+ .args = mk
+ };
+
+ if (d)
+ mk->done = *d;
+ else if (inode_search(&s, &aio->r))
+ goto failure;
+
+ return aio;
+
+failure:
+ free(mk);
+ free(aio);
+ free(parent);
+ free(pathdup);
+ return NULL;
+}
diff --git a/src/aio/src/mount.c b/src/aio/src/mount.c
new file mode 100644
index 0000000..e90d8de
--- /dev/null
+++ b/src/aio/src/mount.c
@@ -0,0 +1,175 @@
+/*
+ * wanix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <aio/types.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct mount
+{
+ char *src, *tgt;
+ struct aio *aio;
+ const struct fs *fs;
+ struct fs_mount mount;
+ struct aio_done done;
+};
+
+static void free_mount(struct mount *const m)
+{
+ if (m)
+ {
+ free(m->src);
+ free(m->tgt);
+ }
+
+ free(m);
+}
+
+static int done(const enum state state, void *const args)
+{
+ int ret = 0;
+ struct mount *const m = args;
+ const struct aio_done *const d = &m->done;
+
+ if (d->f)
+ ret = d->f(state, d->args);
+
+ free_mount(m);
+ return ret;
+}
+
+static int search_done(const enum state s, const char *const relpath,
+ const struct fs_mp *const mp, const union inode_result *const inode,
+ void *const args)
+{
+ struct mount *const m = args;
+ struct aio *const aio = m->aio;
+ const struct fs *const fs = m->fs;
+
+ if (strcmp(m->tgt, "/"))
+ {
+ if (!inode)
+ {
+ aio->error = ENOENT;
+ goto failure;
+ }
+ else if (mp->fs->iops.flags(inode) & INODE_MOUNTPOINT)
+ {
+ aio->error = EBUSY;
+ goto failure;
+ }
+ }
+
+ if (fs->mount(&m->mount, &aio->r))
+ {
+ aio->error = errno;
+ goto failure;
+ }
+
+ return 0;
+
+failure:
+ aio->done = m->done;
+ free_mount(m);
+ return -1;
+}
+
+struct aio *aio_mount(const struct aio_mount *const am,
+ const struct aio_done *const d)
+{
+ struct aio *aio = NULL;
+ const struct fs_mount *const m = &am->mount;
+ const struct fs *const fs = fs_from_type(am->type);
+ char *srcdup = NULL, *tgtdup = NULL;
+ struct mount *pm = NULL;
+ struct fs_mp mp;
+
+ if (!fs)
+ {
+ errno = ENODEV;
+ goto failure;
+ }
+ else if (!m->src && fs->flags & FS_DEV_REQUIRED)
+ {
+ errno = ENOTBLK;
+ goto failure;
+ }
+ else if (!fs_mp_from_path(m->tgt, &mp)
+ && m->src && !strcmp(mp.src, m->src))
+ {
+ errno = EBUSY;
+ goto failure;
+ }
+ else if ((m->src && !(srcdup = strdup(m->src)))
+ || !(tgtdup = strdup(m->tgt))
+ || !(pm = malloc(sizeof *pm))
+ || !(aio = malloc(sizeof *aio)))
+ goto failure;
+
+ const struct inode_search s =
+ {
+ .path = m->tgt,
+ .done = search_done,
+ .args = pm
+ };
+
+ *pm = (const struct mount)
+ {
+ .aio = aio,
+ .src = srcdup,
+ .tgt = tgtdup,
+ .fs = fs,
+ .mount =
+ {
+ .src = srcdup,
+ .tgt = tgtdup,
+ .mode = m->mode,
+ .gid = m->gid,
+ .uid = m->uid
+ }
+ };
+
+ *aio = (const struct aio)
+ {
+ .done =
+ {
+ .f = done,
+ .args = pm
+ }
+ };
+
+ if (inode_search(&s, &aio->r))
+ goto failure;
+
+ if (d)
+ pm->done = *d;
+
+ return aio;
+
+failure:
+ free(tgtdup);
+ free(srcdup);
+ free(pm);
+ free(aio);
+ return NULL;
+}
diff --git a/src/aio/src/open.c b/src/aio/src/open.c
index 89fbbba..f3a84da 100644
--- a/src/aio/src/open.c
+++ b/src/aio/src/open.c
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wanix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -16,18 +16,110 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+#include <aio.h>
+#include <fs/fs.h>
#include <aio/types.h>
+#include <state.h>
+#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
-struct aio *aio_open(const char *const path, const char *const mode)
+struct open
{
- struct aio *const ret = malloc(sizeof *ret);
+ struct aio *aio;
+ struct fs_open open;
+ struct aio_done done;
+};
- if (!ret)
+static int done(const enum state s, void *const args)
+{
+ struct open *const o = args;
+
+ if (o->done.f)
+ o->done.f(s, o->done.args);
+
+ free(o);
+ return 0;
+}
+
+static enum state open_done(void *const args)
+{
+ return STATE_OK;
+}
+
+static int search_done(const enum state state, const char *const relpath,
+ const struct fs_mp *const mp, const union inode_result *const inode,
+ void *const args)
+{
+ struct open *const o = args;
+ struct aio *const aio = o->aio;
+ const struct fs *const fs = mp->fs;
+
+ if (!inode)
+ {
+ aio->error = ENOENT;
+ goto failure;
+ }
+
+ aio->r = (const struct fs_ret)
+ {
+ .f = open_done,
+ .args = o
+ };
+
+ if (fs->open(&o->open, mp, inode, &aio->r))
+ {
+ aio->error = errno;
+ goto failure;
+ }
+
+ return 0;
+
+failure:
+ aio->done = o->done;
+ return -1;
+}
+
+struct aio *aio_open(const struct fs_open *const op,
+ const struct aio_done *const d)
+{
+ struct aio *aio = NULL;
+ struct open *const o = malloc(sizeof *o);
+
+ if (!o || !(aio = malloc(sizeof *aio)))
goto failure;
+ *o = (const struct open)
+ {
+ .aio = aio,
+ .open = *op
+ };
+
+ *aio = (const struct aio)
+ {
+ .done =
+ {
+ .f = done,
+ .args = o
+ }
+ };
+
+ const struct inode_search s =
+ {
+ .path = op->path,
+ .done = search_done,
+ .args = o
+ };
+
+ if (inode_search(&s, &aio->r))
+ goto failure;
+
+ if (d)
+ o->done = *d;
+
+ return aio;
+
failure:
- free(ret);
+ free(aio);
return NULL;
}
diff --git a/src/aio/src/poll.c b/src/aio/src/poll.c
new file mode 100644
index 0000000..615f2de
--- /dev/null
+++ b/src/aio/src/poll.c
@@ -0,0 +1,74 @@
+/*
+ * wanix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <aio/types.h>
+#include <state.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <time.h>
+
+int aio_poll(struct aio_poll *const poll, int ms)
+{
+ struct timespec init;
+
+ if (ms > 0 && clock_gettime(CLOCK_REALTIME, &init))
+ return -1;
+
+ do
+ {
+ for (struct aio_poll *p = poll; p; p = p->next)
+ {
+ const struct aio *const aio = p->aio;
+ const struct fs_ret *const r = &aio->r;
+ const enum state s = r->f(r->args);
+
+ switch (s)
+ {
+ case STATE_AGAIN:
+ break;
+
+ case STATE_FATAL:
+ p->error = aio->error;
+ /* Fall through */
+ case STATE_OK:
+ {
+ const struct aio_done *const d = &aio->done;
+
+ if (d->f)
+ return d->f(s, d->args) ? -1 : 1;
+
+ p->done = true;
+ return 1;
+ }
+ }
+ }
+
+ if (ms > 0)
+ {
+ struct timespec after;
+
+ if (clock_gettime(CLOCK_REALTIME, &after))
+ return -1;
+
+ /* TODO */
+ }
+ } while (ms);
+
+ return 0;
+}
diff --git a/src/aio/src/stat.c b/src/aio/src/stat.c
new file mode 100644
index 0000000..9a7df76
--- /dev/null
+++ b/src/aio/src/stat.c
@@ -0,0 +1,118 @@
+/*
+ * wanix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <aio/types.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct stat_prv
+{
+ struct fs_stat stat;
+ struct aio_done done;
+ struct aio *aio;
+};
+
+static int done(const enum state state, void *const args)
+{
+ int ret = 0;
+ struct stat_prv *const p = args;
+ const struct aio_done *const d = &p->done;
+
+ if (d->f)
+ ret = d->f(state, d->args);
+
+ free(p);
+ return ret;
+}
+
+static int search_done(const enum state s, const char *const relpath,
+ const struct fs_mp *const mp, const union inode_result *const inode,
+ void *const args)
+{
+ struct stat_prv *const p = args;
+ struct aio *const aio = p->aio;
+ const struct fs *const fs = mp->fs;
+
+ if (!inode)
+ {
+ aio->error = ENOENT;
+ goto failure;
+ }
+ else if (fs->stat(&p->stat, mp, inode, &aio->r))
+ {
+ aio->error = errno;
+ goto failure;
+ }
+
+ return 0;
+
+failure:
+ aio->done = p->done;
+ free(p);
+ return -1;
+}
+
+struct aio *aio_stat(const struct fs_stat *const as,
+ const struct aio_done *const d)
+{
+ struct aio *const aio = malloc(sizeof *aio);
+ struct stat_prv *const p = malloc(sizeof *p);
+
+ if (!p || !aio)
+ goto failure;
+
+ const struct inode_search s =
+ {
+ .path = as->path,
+ .done = search_done,
+ .args = p
+ };
+
+ *p = (const struct stat_prv)
+ {
+ .aio = aio,
+ .stat = *as
+ };
+
+ *aio = (const struct aio)
+ {
+ .done =
+ {
+ .f = done,
+ .args = p
+ }
+ };
+
+ if (inode_search(&s, &aio->r))
+ goto failure;
+
+ if (d)
+ p->done = *d;
+
+ return aio;
+
+failure:
+ free(p);
+ free(aio);
+ return NULL;
+}
diff --git a/src/aio/src/write.c b/src/aio/src/write.c
new file mode 100644
index 0000000..116629f
--- /dev/null
+++ b/src/aio/src/write.c
@@ -0,0 +1,79 @@
+/*
+ * wanix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <fs/fs.h>
+#include <aio/types.h>
+#include <state.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct write
+{
+ struct aio *aio;
+ struct aio_done done;
+};
+
+static int done(const enum state s, void *const args)
+{
+ struct write *const w = args;
+
+ free(w);
+ return 0;
+}
+
+static enum state write_done(void *const args)
+{
+ return STATE_OK;
+}
+
+struct aio *aio_write(const struct fs_write *const fw,
+ const struct aio_done *const d)
+{
+ struct aio *aio = NULL;
+ struct write *const w = malloc(sizeof *w);
+ struct fs_fd *const fd = fw->fd;
+ const struct fs *const fs = fd->mp->fs;
+
+ if (!w || !(aio = malloc(sizeof *aio)))
+ goto failure;
+
+ *aio = (const struct aio)
+ {
+ .done =
+ {
+ .f = done,
+ .args = w
+ }
+ };
+
+ aio->r = (const struct fs_ret){.f = write_done};
+
+ if (fs->write(fw, &aio->r))
+ goto failure;
+
+ if (d)
+ w->done = *d;
+
+ return aio;
+
+failure:
+ free(w);
+ free(aio);
+ return NULL;
+}