-
Notifications
You must be signed in to change notification settings - Fork 1
Ideas
We wanted to keep new_path around without creating yet another string copy, especially because libeio already does.
A simply (maybe hacky?) solution is to get hold of req->eio->ptr2
in uv__fs_after
(fs.c).
To do this we also have to guarantee libeio won't try free it.
The way I've done it is:
/*
* Get hold of ptr2 and make eio forget about it!
* We can exploit this using the flags
*/
req->ptr = req->eio->ptr2;
req->eio->ptr2 = NULL;
// ATTENTION: We only use ^ here because we know
// EIO_FLAG_PTR2_FREE was definitely set!
req->eio->flags ^= EIO_FLAG_PTR2_FREE;
And it's our lucky day, it just happens that, in case of error, req->ptr
should be NULL
(at least for rename).
My understanding of this is, req->ptr
is used to return the resulting data of a fs syscall so, it kind of makes sense to return the 'resulting data' of an error of the very same syscall.
Now you're probably thinking “yah, that's a bit too much just to get new_path” (either that or this is all rubbish, there's that possibility and if that's the case, ignore the rest of the page hehe).
The thing is, if we use the same approach we can remove this code here (uv__fs_after
fs.c):
case UV_FS_READDIR:
/*
* XXX This is pretty bad.
* We alloc and copy the large null terminated string list from libeio.
* This is done because libeio is going to free eio->ptr2 after this
* callback. We must keep it until uv_fs_req_cleanup. If we get rid of
* libeio this can be avoided.
*/
buflen = 0;
name = req->eio->ptr2;
for (i = 0; i < req->result; i++) {
namelen = strlen(name);
buflen += namelen + 1;
name += namelen;
assert(*name == '\0');
name++;
}
if (buflen) {
if ((req->ptr = malloc(buflen)))
memcpy(req->ptr, req->eio->ptr2, buflen);
else
uv__set_sys_error(req->loop, ENOMEM);
}
We could get hold of req->eio->ptr2
directly.
Key functions to look at:
eio_finish
(eio.c) ----> uv__fs_after
(fs.c)
|
eio_destroy
(eio.c) ---> eio_api_destroy
(eio.c)
What do you think?
Cheers,
Diogo