Skip to content
DiogoNeves edited this page Feb 3, 2012 · 7 revisions

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;
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.

What do you think?

Cheers,
Diogo

Clone this wiki locally