Blame src/win/fs-event.c

Packit b5b901
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit b5b901
 *
Packit b5b901
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b5b901
 * of this software and associated documentation files (the "Software"), to
Packit b5b901
 * deal in the Software without restriction, including without limitation the
Packit b5b901
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b5b901
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b5b901
 * furnished to do so, subject to the following conditions:
Packit b5b901
 *
Packit b5b901
 * The above copyright notice and this permission notice shall be included in
Packit b5b901
 * all copies or substantial portions of the Software.
Packit b5b901
 *
Packit b5b901
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b5b901
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b5b901
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit b5b901
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit b5b901
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit b5b901
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit b5b901
 * IN THE SOFTWARE.
Packit b5b901
 */
Packit b5b901
Packit b5b901
#include <assert.h>
Packit b5b901
#include <errno.h>
Packit b5b901
#include <stdio.h>
Packit b5b901
#include <string.h>
Packit b5b901
Packit b5b901
#include "uv.h"
Packit b5b901
#include "internal.h"
Packit b5b901
#include "handle-inl.h"
Packit b5b901
#include "req-inl.h"
Packit b5b901
Packit b5b901
Packit b5b901
const unsigned int uv_directory_watcher_buffer_size = 4096;
Packit b5b901
Packit b5b901
Packit b5b901
static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
Packit b5b901
    uv_fs_event_t* handle) {
Packit b5b901
  assert(handle->dir_handle != INVALID_HANDLE_VALUE);
Packit b5b901
  assert(!handle->req_pending);
Packit b5b901
Packit b5b901
  memset(&(handle->req.u.io.overlapped), 0,
Packit b5b901
         sizeof(handle->req.u.io.overlapped));
Packit b5b901
  if (!ReadDirectoryChangesW(handle->dir_handle,
Packit b5b901
                             handle->buffer,
Packit b5b901
                             uv_directory_watcher_buffer_size,
Packit b5b901
                             (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
Packit b5b901
                             FILE_NOTIFY_CHANGE_FILE_NAME      |
Packit b5b901
                               FILE_NOTIFY_CHANGE_DIR_NAME     |
Packit b5b901
                               FILE_NOTIFY_CHANGE_ATTRIBUTES   |
Packit b5b901
                               FILE_NOTIFY_CHANGE_SIZE         |
Packit b5b901
                               FILE_NOTIFY_CHANGE_LAST_WRITE   |
Packit b5b901
                               FILE_NOTIFY_CHANGE_LAST_ACCESS  |
Packit b5b901
                               FILE_NOTIFY_CHANGE_CREATION     |
Packit b5b901
                               FILE_NOTIFY_CHANGE_SECURITY,
Packit b5b901
                             NULL,
Packit b5b901
                             &handle->req.u.io.overlapped,
Packit b5b901
                             NULL)) {
Packit b5b901
    /* Make this req pending reporting an error. */
Packit b5b901
    SET_REQ_ERROR(&handle->req, GetLastError());
Packit b5b901
    uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  handle->req_pending = 1;
Packit b5b901
}
Packit b5b901
Packit b5b901
static void uv_relative_path(const WCHAR* filename,
Packit b5b901
                             const WCHAR* dir,
Packit b5b901
                             WCHAR** relpath) {
Packit b5b901
  size_t relpathlen;
Packit b5b901
  size_t filenamelen = wcslen(filename);
Packit b5b901
  size_t dirlen = wcslen(dir);
Packit b5b901
  assert(!_wcsnicmp(filename, dir, dirlen));
Packit b5b901
  if (dirlen > 0 && dir[dirlen - 1] == '\\')
Packit b5b901
    dirlen--;
Packit b5b901
  relpathlen = filenamelen - dirlen - 1;
Packit b5b901
  *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR));
Packit b5b901
  if (!*relpath)
Packit b5b901
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
  wcsncpy(*relpath, filename + dirlen + 1, relpathlen);
Packit b5b901
  (*relpath)[relpathlen] = L'\0';
Packit b5b901
}
Packit b5b901
Packit b5b901
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
Packit b5b901
    WCHAR** file) {
Packit b5b901
  size_t len, i;
Packit Service e08953
  DWORD dir_len;
Packit Service e08953
Packit b5b901
  if (filename == NULL) {
Packit b5b901
    if (dir != NULL)
Packit b5b901
      *dir = NULL;
Packit b5b901
    *file = NULL;
Packit b5b901
    return 0;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  len = wcslen(filename);
Packit b5b901
  i = len;
Packit b5b901
  while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
Packit b5b901
Packit b5b901
  if (i == 0) {
Packit b5b901
    if (dir) {
Packit Service e08953
      dir_len = GetCurrentDirectoryW(0, NULL);
Packit Service e08953
      if (dir_len == 0) {
Packit Service e08953
        return -1;
Packit Service e08953
      }
Packit Service e08953
      *dir = (WCHAR*)uv__malloc(dir_len * sizeof(WCHAR));
Packit b5b901
      if (!*dir) {
Packit b5b901
        uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
      }
Packit b5b901
Packit Service e08953
      if (!GetCurrentDirectoryW(dir_len, *dir)) {
Packit b5b901
        uv__free(*dir);
Packit b5b901
        *dir = NULL;
Packit b5b901
        return -1;
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
Packit b5b901
    *file = wcsdup(filename);
Packit b5b901
  } else {
Packit b5b901
    if (dir) {
Packit b5b901
      *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
Packit b5b901
      if (!*dir) {
Packit b5b901
        uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
      }
Packit b5b901
      wcsncpy(*dir, filename, i + 1);
Packit b5b901
      (*dir)[i + 1] = L'\0';
Packit b5b901
    }
Packit b5b901
Packit b5b901
    *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
Packit b5b901
    if (!*file) {
Packit b5b901
      uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
    }
Packit b5b901
    wcsncpy(*file, filename + i + 1, len - i - 1);
Packit b5b901
    (*file)[len - i - 1] = L'\0';
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
Packit b5b901
  uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
Packit b5b901
  handle->dir_handle = INVALID_HANDLE_VALUE;
Packit b5b901
  handle->buffer = NULL;
Packit b5b901
  handle->req_pending = 0;
Packit b5b901
  handle->filew = NULL;
Packit b5b901
  handle->short_filew = NULL;
Packit b5b901
  handle->dirw = NULL;
Packit b5b901
Packit b5b901
  UV_REQ_INIT(&handle->req, UV_FS_EVENT_REQ);
Packit b5b901
  handle->req.data = handle;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_fs_event_start(uv_fs_event_t* handle,
Packit b5b901
                      uv_fs_event_cb cb,
Packit b5b901
                      const char* path,
Packit b5b901
                      unsigned int flags) {
Packit b5b901
  int name_size, is_path_dir, size;
Packit b5b901
  DWORD attr, last_error;
Packit b5b901
  WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
Packit Service e08953
  DWORD short_path_buffer_len;
Packit Service e08953
  WCHAR *short_path_buffer;
Packit b5b901
  WCHAR* short_path, *long_path;
Packit b5b901
Packit Service e08953
  short_path = NULL;
Packit b5b901
  if (uv__is_active(handle))
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  handle->cb = cb;
Packit b5b901
  handle->path = uv__strdup(path);
Packit b5b901
  if (!handle->path) {
Packit b5b901
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv__handle_start(handle);
Packit b5b901
Packit b5b901
  /* Convert name to UTF16. */
Packit b5b901
Packit b5b901
  name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) *
Packit b5b901
              sizeof(WCHAR);
Packit b5b901
  pathw = (WCHAR*)uv__malloc(name_size);
Packit b5b901
  if (!pathw) {
Packit b5b901
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!MultiByteToWideChar(CP_UTF8,
Packit b5b901
                           0,
Packit b5b901
                           path,
Packit b5b901
                           -1,
Packit b5b901
                           pathw,
Packit b5b901
                           name_size / sizeof(WCHAR))) {
Packit b5b901
    return uv_translate_sys_error(GetLastError());
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Determine whether path is a file or a directory. */
Packit b5b901
  attr = GetFileAttributesW(pathw);
Packit b5b901
  if (attr == INVALID_FILE_ATTRIBUTES) {
Packit b5b901
    last_error = GetLastError();
Packit b5b901
    goto error;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
Packit b5b901
Packit b5b901
  if (is_path_dir) {
Packit b5b901
     /* path is a directory, so that's the directory that we will watch. */
Packit b5b901
Packit b5b901
    /* Convert to long path. */
Packit b5b901
    size = GetLongPathNameW(pathw, NULL, 0);
Packit b5b901
Packit b5b901
    if (size) {
Packit b5b901
      long_path = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
Packit b5b901
      if (!long_path) {
Packit b5b901
        uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
      }
Packit b5b901
Packit b5b901
      size = GetLongPathNameW(pathw, long_path, size);
Packit b5b901
      if (size) {
Packit b5b901
        long_path[size] = '\0';
Packit b5b901
      } else {
Packit b5b901
        uv__free(long_path);
Packit b5b901
        long_path = NULL;
Packit b5b901
      }
Packit b5b901
Packit Service e08953
      if (long_path) {
Packit Service e08953
        uv__free(pathw);
Packit Service e08953
        pathw = long_path;
Packit Service e08953
      }
Packit b5b901
    }
Packit b5b901
Packit b5b901
    dir_to_watch = pathw;
Packit b5b901
  } else {
Packit b5b901
    /*
Packit b5b901
     * path is a file.  So we split path into dir & file parts, and
Packit b5b901
     * watch the dir directory.
Packit b5b901
     */
Packit b5b901
Packit b5b901
    /* Convert to short path. */
Packit Service e08953
    short_path_buffer = NULL;
Packit Service e08953
    short_path_buffer_len = GetShortPathNameW(pathw, NULL, 0);
Packit Service e08953
    if (short_path_buffer_len == 0) {
Packit Service e08953
      goto short_path_done;
Packit Service e08953
    }
Packit Service e08953
    short_path_buffer = uv__malloc(short_path_buffer_len * sizeof(WCHAR));
Packit Service e08953
    if (short_path_buffer == NULL) {
Packit Service e08953
      goto short_path_done;
Packit Service e08953
    }
Packit Service e08953
    if (GetShortPathNameW(pathw,
Packit Service e08953
                          short_path_buffer,
Packit Service e08953
                          short_path_buffer_len) == 0) {
Packit Service e08953
      uv__free(short_path_buffer);
Packit Service e08953
      short_path_buffer = NULL;
Packit b5b901
    }
Packit Service e08953
short_path_done:
Packit Service e08953
    short_path = short_path_buffer;
Packit b5b901
Packit b5b901
    if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
Packit b5b901
      last_error = GetLastError();
Packit b5b901
      goto error;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
Packit b5b901
      last_error = GetLastError();
Packit b5b901
      goto error;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    dir_to_watch = dir;
Packit b5b901
    uv__free(pathw);
Packit b5b901
    pathw = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  handle->dir_handle = CreateFileW(dir_to_watch,
Packit b5b901
                                   FILE_LIST_DIRECTORY,
Packit b5b901
                                   FILE_SHARE_READ | FILE_SHARE_DELETE |
Packit b5b901
                                     FILE_SHARE_WRITE,
Packit b5b901
                                   NULL,
Packit b5b901
                                   OPEN_EXISTING,
Packit b5b901
                                   FILE_FLAG_BACKUP_SEMANTICS |
Packit b5b901
                                     FILE_FLAG_OVERLAPPED,
Packit b5b901
                                   NULL);
Packit b5b901
Packit b5b901
  if (dir) {
Packit b5b901
    uv__free(dir);
Packit b5b901
    dir = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (handle->dir_handle == INVALID_HANDLE_VALUE) {
Packit b5b901
    last_error = GetLastError();
Packit b5b901
    goto error;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (CreateIoCompletionPort(handle->dir_handle,
Packit b5b901
                             handle->loop->iocp,
Packit b5b901
                             (ULONG_PTR)handle,
Packit b5b901
                             0) == NULL) {
Packit b5b901
    last_error = GetLastError();
Packit b5b901
    goto error;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!handle->buffer) {
Packit b5b901
    handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
Packit b5b901
  }
Packit b5b901
  if (!handle->buffer) {
Packit b5b901
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
  }
Packit b5b901
Packit b5b901
  memset(&(handle->req.u.io.overlapped), 0,
Packit b5b901
         sizeof(handle->req.u.io.overlapped));
Packit b5b901
Packit b5b901
  if (!ReadDirectoryChangesW(handle->dir_handle,
Packit b5b901
                             handle->buffer,
Packit b5b901
                             uv_directory_watcher_buffer_size,
Packit b5b901
                             (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
Packit b5b901
                             FILE_NOTIFY_CHANGE_FILE_NAME      |
Packit b5b901
                               FILE_NOTIFY_CHANGE_DIR_NAME     |
Packit b5b901
                               FILE_NOTIFY_CHANGE_ATTRIBUTES   |
Packit b5b901
                               FILE_NOTIFY_CHANGE_SIZE         |
Packit b5b901
                               FILE_NOTIFY_CHANGE_LAST_WRITE   |
Packit b5b901
                               FILE_NOTIFY_CHANGE_LAST_ACCESS  |
Packit b5b901
                               FILE_NOTIFY_CHANGE_CREATION     |
Packit b5b901
                               FILE_NOTIFY_CHANGE_SECURITY,
Packit b5b901
                             NULL,
Packit b5b901
                             &handle->req.u.io.overlapped,
Packit b5b901
                             NULL)) {
Packit b5b901
    last_error = GetLastError();
Packit b5b901
    goto error;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  assert(is_path_dir ? pathw != NULL : pathw == NULL);
Packit b5b901
  handle->dirw = pathw;
Packit b5b901
  handle->req_pending = 1;
Packit b5b901
  return 0;
Packit b5b901
Packit b5b901
error:
Packit b5b901
  if (handle->path) {
Packit b5b901
    uv__free(handle->path);
Packit b5b901
    handle->path = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (handle->filew) {
Packit b5b901
    uv__free(handle->filew);
Packit b5b901
    handle->filew = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (handle->short_filew) {
Packit b5b901
    uv__free(handle->short_filew);
Packit b5b901
    handle->short_filew = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv__free(pathw);
Packit b5b901
Packit b5b901
  if (handle->dir_handle != INVALID_HANDLE_VALUE) {
Packit b5b901
    CloseHandle(handle->dir_handle);
Packit b5b901
    handle->dir_handle = INVALID_HANDLE_VALUE;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (handle->buffer) {
Packit b5b901
    uv__free(handle->buffer);
Packit b5b901
    handle->buffer = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (uv__is_active(handle))
Packit b5b901
    uv__handle_stop(handle);
Packit b5b901
Packit Service e08953
  uv__free(short_path);
Packit Service e08953
Packit b5b901
  return uv_translate_sys_error(last_error);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_fs_event_stop(uv_fs_event_t* handle) {
Packit b5b901
  if (!uv__is_active(handle))
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  if (handle->dir_handle != INVALID_HANDLE_VALUE) {
Packit b5b901
    CloseHandle(handle->dir_handle);
Packit b5b901
    handle->dir_handle = INVALID_HANDLE_VALUE;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv__handle_stop(handle);
Packit b5b901
Packit b5b901
  if (handle->filew) {
Packit b5b901
    uv__free(handle->filew);
Packit b5b901
    handle->filew = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (handle->short_filew) {
Packit b5b901
    uv__free(handle->short_filew);
Packit b5b901
    handle->short_filew = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (handle->path) {
Packit b5b901
    uv__free(handle->path);
Packit b5b901
    handle->path = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (handle->dirw) {
Packit b5b901
    uv__free(handle->dirw);
Packit b5b901
    handle->dirw = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) {
Packit b5b901
  size_t str_len;
Packit b5b901
Packit b5b901
  if (str == NULL)
Packit b5b901
    return -1;
Packit b5b901
Packit b5b901
  str_len = wcslen(str);
Packit b5b901
Packit b5b901
  /*
Packit b5b901
    Since we only care about equality, return early if the strings
Packit b5b901
    aren't the same length
Packit b5b901
  */
Packit b5b901
  if (str_len != (file_name_len / sizeof(WCHAR)))
Packit b5b901
    return -1;
Packit b5b901
Packit b5b901
  return _wcsnicmp(str, file_name, str_len);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
Packit b5b901
    uv_fs_event_t* handle) {
Packit b5b901
  FILE_NOTIFY_INFORMATION* file_info;
Packit b5b901
  int err, sizew, size;
Packit b5b901
  char* filename = NULL;
Packit b5b901
  WCHAR* filenamew = NULL;
Packit b5b901
  WCHAR* long_filenamew = NULL;
Packit b5b901
  DWORD offset = 0;
Packit b5b901
Packit b5b901
  assert(req->type == UV_FS_EVENT_REQ);
Packit b5b901
  assert(handle->req_pending);
Packit b5b901
  handle->req_pending = 0;
Packit b5b901
Packit b5b901
  /* Don't report any callbacks if:
Packit b5b901
   * - We're closing, just push the handle onto the endgame queue
Packit b5b901
   * - We are not active, just ignore the callback
Packit b5b901
   */
Packit b5b901
  if (!uv__is_active(handle)) {
Packit b5b901
    if (handle->flags & UV_HANDLE_CLOSING) {
Packit b5b901
      uv_want_endgame(loop, (uv_handle_t*) handle);
Packit b5b901
    }
Packit b5b901
    return;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
Packit b5b901
Packit b5b901
  if (REQ_SUCCESS(req)) {
Packit b5b901
    if (req->u.io.overlapped.InternalHigh > 0) {
Packit b5b901
      do {
Packit b5b901
        file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
Packit b5b901
        assert(!filename);
Packit b5b901
        assert(!filenamew);
Packit b5b901
        assert(!long_filenamew);
Packit b5b901
Packit b5b901
        /*
Packit b5b901
         * Fire the event only if we were asked to watch a directory,
Packit b5b901
         * or if the filename filter matches.
Packit b5b901
         */
Packit b5b901
        if (handle->dirw ||
Packit b5b901
            file_info_cmp(handle->filew,
Packit b5b901
                          file_info->FileName,
Packit b5b901
                          file_info->FileNameLength) == 0 ||
Packit b5b901
            file_info_cmp(handle->short_filew,
Packit b5b901
                          file_info->FileName,
Packit b5b901
                          file_info->FileNameLength) == 0) {
Packit b5b901
Packit b5b901
          if (handle->dirw) {
Packit b5b901
            /*
Packit b5b901
             * We attempt to resolve the long form of the file name explicitly.
Packit b5b901
             * We only do this for file names that might still exist on disk.
Packit b5b901
             * If this fails, we use the name given by ReadDirectoryChangesW.
Packit b5b901
             * This may be the long form or the 8.3 short name in some cases.
Packit b5b901
             */
Packit b5b901
            if (file_info->Action != FILE_ACTION_REMOVED &&
Packit b5b901
              file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
Packit b5b901
              /* Construct a full path to the file. */
Packit b5b901
              size = wcslen(handle->dirw) +
Packit b5b901
                file_info->FileNameLength / sizeof(WCHAR) + 2;
Packit b5b901
Packit b5b901
              filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
Packit b5b901
              if (!filenamew) {
Packit b5b901
                uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
              }
Packit b5b901
Packit b5b901
              _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
Packit b5b901
                file_info->FileNameLength / (DWORD)sizeof(WCHAR),
Packit b5b901
                file_info->FileName);
Packit b5b901
Packit b5b901
              filenamew[size - 1] = L'\0';
Packit b5b901
Packit b5b901
              /* Convert to long name. */
Packit b5b901
              size = GetLongPathNameW(filenamew, NULL, 0);
Packit b5b901
Packit b5b901
              if (size) {
Packit b5b901
                long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
Packit b5b901
                if (!long_filenamew) {
Packit b5b901
                  uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
Packit b5b901
                }
Packit b5b901
Packit b5b901
                size = GetLongPathNameW(filenamew, long_filenamew, size);
Packit b5b901
                if (size) {
Packit b5b901
                  long_filenamew[size] = '\0';
Packit b5b901
                } else {
Packit b5b901
                  uv__free(long_filenamew);
Packit b5b901
                  long_filenamew = NULL;
Packit b5b901
                }
Packit b5b901
              }
Packit b5b901
Packit b5b901
              uv__free(filenamew);
Packit b5b901
Packit b5b901
              if (long_filenamew) {
Packit b5b901
                /* Get the file name out of the long path. */
Packit b5b901
                uv_relative_path(long_filenamew,
Packit b5b901
                                 handle->dirw,
Packit b5b901
                                 &filenamew);
Packit b5b901
                uv__free(long_filenamew);
Packit b5b901
                long_filenamew = filenamew;
Packit b5b901
                sizew = -1;
Packit b5b901
              } else {
Packit b5b901
                /* We couldn't get the long filename, use the one reported. */
Packit b5b901
                filenamew = file_info->FileName;
Packit b5b901
                sizew = file_info->FileNameLength / sizeof(WCHAR);
Packit b5b901
              }
Packit b5b901
            } else {
Packit b5b901
              /*
Packit b5b901
               * Removed or renamed events cannot be resolved to the long form.
Packit b5b901
               * We therefore use the name given by ReadDirectoryChangesW.
Packit b5b901
               * This may be the long form or the 8.3 short name in some cases.
Packit b5b901
               */
Packit b5b901
              filenamew = file_info->FileName;
Packit b5b901
              sizew = file_info->FileNameLength / sizeof(WCHAR);
Packit b5b901
            }
Packit b5b901
          } else {
Packit b5b901
            /* We already have the long name of the file, so just use it. */
Packit b5b901
            filenamew = handle->filew;
Packit b5b901
            sizew = -1;
Packit b5b901
          }
Packit b5b901
Packit b5b901
          /* Convert the filename to utf8. */
Packit b5b901
          uv__convert_utf16_to_utf8(filenamew, sizew, &filename);
Packit b5b901
Packit b5b901
          switch (file_info->Action) {
Packit b5b901
            case FILE_ACTION_ADDED:
Packit b5b901
            case FILE_ACTION_REMOVED:
Packit b5b901
            case FILE_ACTION_RENAMED_OLD_NAME:
Packit b5b901
            case FILE_ACTION_RENAMED_NEW_NAME:
Packit b5b901
              handle->cb(handle, filename, UV_RENAME, 0);
Packit b5b901
              break;
Packit b5b901
Packit b5b901
            case FILE_ACTION_MODIFIED:
Packit b5b901
              handle->cb(handle, filename, UV_CHANGE, 0);
Packit b5b901
              break;
Packit b5b901
          }
Packit b5b901
Packit b5b901
          uv__free(filename);
Packit b5b901
          filename = NULL;
Packit b5b901
          uv__free(long_filenamew);
Packit b5b901
          long_filenamew = NULL;
Packit b5b901
          filenamew = NULL;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        offset = file_info->NextEntryOffset;
Packit b5b901
      } while (offset && !(handle->flags & UV_HANDLE_CLOSING));
Packit b5b901
    } else {
Packit b5b901
      handle->cb(handle, NULL, UV_CHANGE, 0);
Packit b5b901
    }
Packit b5b901
  } else {
Packit b5b901
    err = GET_REQ_ERROR(req);
Packit b5b901
    handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!(handle->flags & UV_HANDLE_CLOSING)) {
Packit b5b901
    uv_fs_event_queue_readdirchanges(loop, handle);
Packit b5b901
  } else {
Packit b5b901
    uv_want_endgame(loop, (uv_handle_t*)handle);
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
Packit b5b901
  uv_fs_event_stop(handle);
Packit b5b901
Packit b5b901
  uv__handle_closing(handle);
Packit b5b901
Packit b5b901
  if (!handle->req_pending) {
Packit b5b901
    uv_want_endgame(loop, (uv_handle_t*)handle);
Packit b5b901
  }
Packit b5b901
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
Packit b5b901
  if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) {
Packit b5b901
    assert(!(handle->flags & UV_HANDLE_CLOSED));
Packit b5b901
Packit b5b901
    if (handle->buffer) {
Packit b5b901
      uv__free(handle->buffer);
Packit b5b901
      handle->buffer = NULL;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    uv__handle_close(handle);
Packit b5b901
  }
Packit b5b901
}