Exemple #1
0
char *
tr_sys_path_resolve (const char  * path,
                     tr_error   ** error)
{
  char * ret = NULL;
  wchar_t * wide_path;
  wchar_t * wide_ret = NULL;
  HANDLE handle;
  DWORD wide_ret_size;

  assert (path != NULL);

  wide_path = tr_win32_utf8_to_native (path, -1);
  if (wide_path == NULL)
    goto fail;

  handle = CreateFileW (wide_path, FILE_READ_EA,
                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                        NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  if (handle == INVALID_HANDLE_VALUE)
    goto fail;

  wide_ret_size = GetFinalPathNameByHandleW (handle, NULL, 0, 0);
  if (wide_ret_size == 0)
    goto fail;

  wide_ret = tr_new (wchar_t, wide_ret_size);
  if (GetFinalPathNameByHandleW (handle, wide_ret, wide_ret_size, 0) != wide_ret_size - 1)
    goto fail;

  /* Resolved path always begins with "\\?\", so skip those first four chars. */
  ret = tr_win32_native_to_utf8 (wide_ret + 4, -1);
  if (ret != NULL)
    goto cleanup;

fail:
  set_system_error (error, GetLastError ());

  tr_free (ret);
  ret = NULL;

cleanup:
  tr_free (wide_ret);
  tr_free (wide_path);

  if (handle != INVALID_HANDLE_VALUE)
    CloseHandle (handle);

  return ret;
}
Exemple #2
0
/* Convert an utf-8 file name to NT file name, return converted name length in characters, no NULL terminator is appended */
static int filename_to_nt_pathname(const char *filename, WCHAR *buf, int buf_size)
{
	HANDLE basedir_handle = CreateFileW(L".", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
		OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
	if (basedir_handle == INVALID_HANDLE_VALUE)
		return 0;
	WCHAR basedir[PATH_MAX];
	DWORD basedir_len = GetFinalPathNameByHandleW(basedir_handle, basedir, PATH_MAX, FILE_NAME_NORMALIZED);
	CloseHandle(basedir_handle);
	if (basedir_len > PATH_MAX)
		return 0;
	basedir[1] = L'?';

	if (buf_size < basedir_len)
		return 0;
	memcpy(buf, basedir, basedir_len * sizeof(WCHAR));
	buf += basedir_len;
	int out_size = basedir_len;
	buf_size -= basedir_len;
	if (filename[0] == 0)
		return out_size;
	if (buf_size < 1)
		return 0;
	*buf++ = L'\\';
	out_size++;
	buf_size--;
	int fl = utf8_to_utf16_filename(filename, strlen(filename), buf, buf_size);
	if (fl == 0)
		return 0;
	return out_size + fl;
}
Exemple #3
0
static posix_errno_t internal_read_link(const efile_path_t *path, efile_path_t *result) {
    DWORD required_length, actual_length;
    HANDLE link_handle;
    DWORD last_error;

    link_handle = CreateFileW((WCHAR*)path->data, GENERIC_READ,
        FILE_SHARE_FLAGS, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
    last_error = GetLastError();

    if(link_handle == INVALID_HANDLE_VALUE) {
        return windows_to_posix_errno(last_error);
    }

    required_length = GetFinalPathNameByHandleW(link_handle, NULL, 0, 0);
    last_error = GetLastError();

    if(required_length <= 0) {
        CloseHandle(link_handle);
        return windows_to_posix_errno(last_error);
    }

    /* Unlike many other path functions (eg. GetFullPathNameW), this one
     * includes the NUL terminator in its required length. */
    if(!enif_alloc_binary(required_length * sizeof(WCHAR), result)) {
        CloseHandle(link_handle);
        return ENOMEM;
    }

    actual_length = GetFinalPathNameByHandleW(link_handle,
        (WCHAR*)result->data, required_length, 0);
    last_error = GetLastError();

    CloseHandle(link_handle);

    if(actual_length == 0 || actual_length >= required_length) {
        enif_release_binary(result);
        return windows_to_posix_errno(last_error);
    }

    /* GetFinalPathNameByHandle always prepends with "\\?\" and NUL-terminates,
     * so we never have to touch-up the resulting path. */

    ASSERT_PATH_FORMAT(result);

    return 0;
}
Exemple #4
0
/*
 * @implemented
 */
DWORD
WINAPI
GetFinalPathNameByHandleA(IN HANDLE hFile,
                          OUT LPSTR lpszFilePath,
                          IN DWORD cchFilePath,
                          IN DWORD dwFlags)
{
    WCHAR FilePathW[MAX_PATH];
    UNICODE_STRING FilePathU;
    DWORD PrevLastError;
    DWORD Ret = 0;

    if (cchFilePath != 0 &&
        cchFilePath > sizeof(FilePathW) / sizeof(FilePathW[0]))
    {
        FilePathU.Length = 0;
        FilePathU.MaximumLength = (USHORT)cchFilePath * sizeof(WCHAR);
        FilePathU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
                                           0,
                                           FilePathU.MaximumLength);
        if (FilePathU.Buffer == NULL)
        {
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
            return 0;
        }
    }
    else
    {
        FilePathU.Length = 0;
        FilePathU.MaximumLength = sizeof(FilePathW);
        FilePathU.Buffer = FilePathW;
    }

    /* save the last error code */
    PrevLastError = GetLastError();
    SetLastError(ERROR_SUCCESS);

    /* call the unicode version that does all the work */
    Ret = GetFinalPathNameByHandleW(hFile,
                                    FilePathU.Buffer,
                                    cchFilePath,
                                    dwFlags);

    if (GetLastError() == ERROR_SUCCESS)
    {
        /* no error, restore the last error code and convert the string */
        SetLastError(PrevLastError);

        Ret = FilenameU2A_FitOrFail(lpszFilePath,
                                    cchFilePath,
                                    &FilePathU);
    }

    /* free allocated memory if necessary */
    if (FilePathU.Buffer != FilePathW)
    {
        RtlFreeHeap(RtlGetProcessHeap(),
                    0,
                    FilePathU.Buffer);
    }

    return Ret;
}
Exemple #5
0
static int
_g_win32_stat_utf16_no_trailing_slashes (const gunichar2    *filename,
                                         int                 fd,
                                         GWin32PrivateStat  *buf,
                                         gboolean            for_symlink)
{
  HANDLE file_handle;
  gboolean succeeded_so_far;
  DWORD error_code;
  struct __stat64 statbuf;
  BY_HANDLE_FILE_INFORMATION handle_info;
  FILE_STANDARD_INFO std_info;
  WIN32_FIND_DATAW finddata;
  DWORD immediate_attributes;
  gboolean is_symlink = FALSE;
  gboolean is_directory;
  DWORD open_flags;
  wchar_t *filename_target = NULL;
  int result;

  if (fd < 0)
    {
      immediate_attributes = GetFileAttributesW (filename);

      if (immediate_attributes == INVALID_FILE_ATTRIBUTES)
        {
          error_code = GetLastError ();
          errno = w32_error_to_errno (error_code);

          return -1;
        }

      is_symlink = (immediate_attributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT;
      is_directory = (immediate_attributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;

      open_flags = FILE_ATTRIBUTE_NORMAL;

      if (for_symlink && is_symlink)
        open_flags |= FILE_FLAG_OPEN_REPARSE_POINT;

      if (is_directory)
        open_flags |= FILE_FLAG_BACKUP_SEMANTICS;

      file_handle = CreateFileW (filename, FILE_READ_ATTRIBUTES,
                                 FILE_SHARE_READ, NULL, OPEN_EXISTING,
                                 open_flags,
                                 NULL);

      if (file_handle == INVALID_HANDLE_VALUE)
        {
          error_code = GetLastError ();
          errno = w32_error_to_errno (error_code);
          return -1;
        }
    }
  else
    {
      file_handle = (HANDLE) _get_osfhandle (fd);

      if (file_handle == INVALID_HANDLE_VALUE)
        return -1;
    }

  succeeded_so_far = GetFileInformationByHandle (file_handle,
                                                 &handle_info);
  error_code = GetLastError ();

  if (succeeded_so_far)
    {
      succeeded_so_far = GetFileInformationByHandleEx (file_handle,
                                                       FileStandardInfo,
                                                       &std_info,
                                                       sizeof (std_info));
      error_code = GetLastError ();
    }

  if (!succeeded_so_far)
    {
      if (fd < 0)
        CloseHandle (file_handle);
      errno = w32_error_to_errno (error_code);
      return -1;
    }

  /* It's tempting to use GetFileInformationByHandleEx(FileAttributeTagInfo),
   * but it always reports that the ReparseTag is 0.
   */
  if (fd < 0)
    {
      memset (&finddata, 0, sizeof (finddata));

      if (handle_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
        {
          HANDLE tmp = FindFirstFileW (filename,
                                       &finddata);

          if (tmp == INVALID_HANDLE_VALUE)
            {
              error_code = GetLastError ();
              errno = w32_error_to_errno (error_code);
              CloseHandle (file_handle);
              return -1;
            }

          FindClose (tmp);
        }

      if (is_symlink && !for_symlink)
        {
          /* If filename is a symlink, but we need the target.
           * To get information about the target we need to resolve
           * the symlink first.
           */
          DWORD filename_target_len;
          DWORD new_len;

          /* Just in case, give it a real memory location instead of NULL */
          new_len = GetFinalPathNameByHandleW (file_handle,
                                               (wchar_t *) &filename_target_len,
                                               0,
                                               FILE_NAME_NORMALIZED);

#define SANE_LIMIT 1024 * 10
          if (new_len >= SANE_LIMIT)
#undef SANE_LIMIT
            {
              new_len = 0;
              error_code = ERROR_BUFFER_OVERFLOW;
            }
          else if (new_len == 0)
            {
              error_code = GetLastError ();
            }

          if (new_len > 0)
            {
              /* Pretend that new_len doesn't count the terminating NUL char,
               * and ask for a bit more space than is needed, and allocate even more.
               */
              filename_target_len = new_len + 3;
              filename_target = g_malloc ((filename_target_len + 1) * sizeof (wchar_t));

              new_len = GetFinalPathNameByHandleW (file_handle,
                                                   filename_target,
                                                   filename_target_len,
                                                   FILE_NAME_NORMALIZED);

              /* filename_target_len is already larger than needed,
               * new_len should be smaller than that, even if the size
               * is off by 1 for some reason.
               */
              if (new_len >= filename_target_len - 1)
                {
                  new_len = 0;
                  error_code = ERROR_BUFFER_OVERFLOW;
                  g_clear_pointer (&filename_target, g_free);
                }
              else if (new_len == 0)
                {
                  g_clear_pointer (&filename_target, g_free);
                }
              /* GetFinalPathNameByHandle() is documented to return extended paths,
               * strip the extended prefix, if it is followed by a drive letter
               * and a colon. Otherwise keep it (the path could be
               * \\\\?\\Volume{GUID}\\ - it's only usable in extended form).
               */
              else if (new_len > 0)
                {
                  gsize len = new_len;

                  /* Account for NUL-terminator maybe not being counted.
                   * This is why we overallocated earlier.
                   */
                  if (filename_target[len] != L'\0')
                    {
                      len++;
                      filename_target[len] = L'\0';
                    }

                  _g_win32_strip_extended_ntobjm_prefix (filename_target, &len);
                  new_len = len;
                }

            }

          if (new_len == 0)
            succeeded_so_far = FALSE;
        }

      CloseHandle (file_handle);
    }
  /* else if fd >= 0 the file_handle was obtained via _get_osfhandle()
   * and must not be closed, it is owned by fd.
   */

  if (!succeeded_so_far)
    {
      errno = w32_error_to_errno (error_code);
      return -1;
    }

  /*
   * We can't use _wstat64() here, because with UCRT it now gives
   * information about the target, even if we want information about
   * the link itself (unlike MSVCRT, which gave information about
   * the link, and if we needed information about the target we were
   * able to resolve it by ourselves prior to calling _wstat64()).
   */
  if (fd < 0)
    result = _g_win32_fill_statbuf_from_handle_info (filename,
                                                     filename_target,
                                                     &handle_info,
                                                     &statbuf);
  else
    result = _fstat64 (fd, &statbuf);

  if (result != 0)
    {
      int errsv = errno;

      g_free (filename_target);
      errno = errsv;

      return -1;
    }

  g_free (filename_target);

  buf->st_dev = statbuf.st_dev;
  buf->st_mode = statbuf.st_mode;
  buf->volume_serial = handle_info.dwVolumeSerialNumber;
  buf->file_index = (((guint64) handle_info.nFileIndexHigh) << 32) | handle_info.nFileIndexLow;
  /* Note that immediate_attributes is for the symlink
   * (if it's a symlink), while handle_info contains info
   * about the symlink or the target, depending on the flags
   * we used earlier.
   */
  buf->attributes = handle_info.dwFileAttributes;
  buf->st_nlink = handle_info.nNumberOfLinks;
  buf->st_size = (((guint64) handle_info.nFileSizeHigh) << 32) | handle_info.nFileSizeLow;
  buf->allocated_size = std_info.AllocationSize.QuadPart;

  if (fd < 0 && buf->attributes & FILE_ATTRIBUTE_REPARSE_POINT)
    buf->reparse_tag = finddata.dwReserved0;
  else
    buf->reparse_tag = 0;

  buf->st_ctime = statbuf.st_ctime;
  buf->st_atime = statbuf.st_atime;
  buf->st_mtime = statbuf.st_mtime;

  return 0;
}
Exemple #6
0
w_string FileDescriptor::getOpenedPath() const {
#if defined(F_GETPATH)
  // macOS.  The kernel interface only allows MAXPATHLEN
  char buf[MAXPATHLEN + 1];
  if (fcntl(fd_, F_GETPATH, buf) == -1) {
    throw std::system_error(errno, std::generic_category(),
                            "fcntl for getOpenedPath");
  }
  return w_string(buf);
#elif defined(__linux__) || defined(__sun)
  char procpath[1024];
#if defined(__linux__)
  snprintf(procpath, sizeof(procpath), "/proc/%d/fd/%d", getpid(), fd_);
#elif defined(__sun)
  snprintf(procpath, sizeof(procpath), "/proc/%d/path/%d", getpid(), fd_);
#endif

  // Avoid an extra stat by speculatively attempting to read into
  // a reasonably sized buffer.
  char buf[WATCHMAN_NAME_MAX];
  auto len = readlink(procpath, buf, sizeof(buf));
  if (len == sizeof(buf)) {
    len = -1;
    // We need to stat it to discover the required length
    errno = ENAMETOOLONG;
  }

  if (len >= 0) {
    return w_string(buf, len);
  }

  if (errno == ENOENT) {
    // For this path to not exist must mean that /proc is not mounted.
    // Report this with an actionable message
    throw std::system_error(ENOSYS, std::generic_category(),
                            "getOpenedPath: need /proc to be mounted!");
  }

  if (errno != ENAMETOOLONG) {
    throw std::system_error(errno, std::generic_category(),
                            "readlink for getOpenedPath");
  }

  // Figure out how much space we need
  struct stat st;
  if (fstat(fd_, &st)) {
    throw std::system_error(errno, std::generic_category(),
                            "fstat for getOpenedPath");
  }
  std::string result;
  result.resize(st.st_size + 1, 0);

  len = readlink(procpath, &result[0], result.size());
  if (len == int(result.size())) {
    // It's longer than we expected; TOCTOU detected!
    throw std::system_error(
        ENAMETOOLONG, std::generic_category(),
        "readlinkat: link contents grew while examining file");
  }
  if (len >= 0) {
    return w_string(&result[0], len);
  }

  throw std::system_error(errno, std::generic_category(),
                          "readlink for getOpenedPath");
#elif defined(_WIN32)
  std::wstring wchar;
  wchar.resize(WATCHMAN_NAME_MAX);
  auto len = GetFinalPathNameByHandleW(
      (HANDLE)fd_,
      &wchar[0],
      wchar.size(),
      FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
  auto err = GetLastError();

  if (len >= wchar.size()) {
    // Grow it
    wchar.resize(len);
    len = GetFinalPathNameByHandleW(
        (HANDLE)fd_, &wchar[0], len, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
    err = GetLastError();
  }

  if (len == 0) {
    throw std::system_error(
        GetLastError(), std::system_category(), "GetFinalPathNameByHandleW");
  }

  return w_string(wchar.data(), len);
#else
  throw std::system_error(ENOSYS, std::generic_category(),
                          "getOpenedPath not implemented on this platform");
#endif
}
Exemple #7
0
static NTSTATUS PtfsCreate(PWSTR Path, PWSTR VolumePrefix, PWSTR MountPoint, UINT32 DebugFlags,
    PTFS **PPtfs)
{
    WCHAR FullPath[MAX_PATH];
    ULONG Length;
    HANDLE Handle;
    FILETIME CreationTime;
    DWORD LastError;
    FSP_FSCTL_VOLUME_PARAMS VolumeParams;
    PTFS *Ptfs = 0;
    NTSTATUS Result;

    *PPtfs = 0;

    Handle = CreateFileW(
        Path, FILE_READ_ATTRIBUTES, 0, 0,
        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
    if (INVALID_HANDLE_VALUE == Handle)
        return FspNtStatusFromWin32(GetLastError());

    Length = GetFinalPathNameByHandleW(Handle, FullPath, FULLPATH_SIZE - 1, 0);
    if (0 == Length)
    {
        LastError = GetLastError();
        CloseHandle(Handle);
        return FspNtStatusFromWin32(LastError);
    }
    if (L'\\' == FullPath[Length - 1])
        FullPath[--Length] = L'\0';

    if (!GetFileTime(Handle, &CreationTime, 0, 0))
    {
        LastError = GetLastError();
        CloseHandle(Handle);
        return FspNtStatusFromWin32(LastError);
    }

    CloseHandle(Handle);

    /* from now on we must goto exit on failure */

    Ptfs = malloc(sizeof *Ptfs);
    if (0 == Ptfs)
    {
        Result = STATUS_INSUFFICIENT_RESOURCES;
        goto exit;
    }
    memset(Ptfs, 0, sizeof *Ptfs);

    Length = (Length + 1) * sizeof(WCHAR);
    Ptfs->Path = malloc(Length);
    if (0 == Ptfs->Path)
    {
        Result = STATUS_INSUFFICIENT_RESOURCES;
        goto exit;
    }
    memcpy(Ptfs->Path, FullPath, Length);

    memset(&VolumeParams, 0, sizeof VolumeParams);
    VolumeParams.SectorSize = ALLOCATION_UNIT;
    VolumeParams.SectorsPerAllocationUnit = 1;
    VolumeParams.VolumeCreationTime = ((PLARGE_INTEGER)&CreationTime)->QuadPart;
    VolumeParams.VolumeSerialNumber = 0;
    VolumeParams.FileInfoTimeout = 1000;
    VolumeParams.CaseSensitiveSearch = 0;
    VolumeParams.CasePreservedNames = 1;
    VolumeParams.UnicodeOnDisk = 1;
    VolumeParams.PersistentAcls = 1;
    VolumeParams.PostCleanupWhenModifiedOnly = 1;
    VolumeParams.PassQueryDirectoryPattern = 1;
    VolumeParams.FlushAndPurgeOnCleanup = 1;
    VolumeParams.UmFileContextIsUserContext2 = 1;
    if (0 != VolumePrefix)
        wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix);
    wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR),
        L"" PROGNAME);

    Result = FspFileSystemCreate(
        VolumeParams.Prefix[0] ? L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME,
        &VolumeParams,
        &PtfsInterface,
        &Ptfs->FileSystem);
    if (!NT_SUCCESS(Result))
        goto exit;
    Ptfs->FileSystem->UserContext = Ptfs;

    Result = FspFileSystemSetMountPoint(Ptfs->FileSystem, MountPoint);
    if (!NT_SUCCESS(Result))
        goto exit;

    FspFileSystemSetDebugLog(Ptfs->FileSystem, DebugFlags);

    Result = STATUS_SUCCESS;

exit:
    if (NT_SUCCESS(Result))
        *PPtfs = Ptfs;
    else if (0 != Ptfs)
        PtfsDelete(Ptfs);

    return Result;
}
Exemple #8
0
static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
    PVOID FileContext0, PWSTR Pattern, PWSTR Marker,
    PVOID Buffer, ULONG BufferLength, PULONG PBytesTransferred)
{
    PTFS *Ptfs = (PTFS *)FileSystem->UserContext;
    PTFS_FILE_CONTEXT *FileContext = FileContext0;
    HANDLE Handle = HandleFromContext(FileContext);
    WCHAR FullPath[FULLPATH_SIZE];
    ULONG Length, PatternLength;
    HANDLE FindHandle;
    WIN32_FIND_DATAW FindData;
    union
    {
        UINT8 B[FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) + MAX_PATH * sizeof(WCHAR)];
        FSP_FSCTL_DIR_INFO D;
    } DirInfoBuf;
    FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.D;
    NTSTATUS DirBufferResult;

    DirBufferResult = STATUS_SUCCESS;
    if (FspFileSystemAcquireDirectoryBuffer(&FileContext->DirBuffer, 0 == Marker, &DirBufferResult))
    {
        if (0 == Pattern)
            Pattern = L"*";
        PatternLength = (ULONG)wcslen(Pattern);

        Length = GetFinalPathNameByHandleW(Handle, FullPath, FULLPATH_SIZE - 1, 0);
        if (0 == Length)
            DirBufferResult = FspNtStatusFromWin32(GetLastError());
        else if (Length + 1 + PatternLength >= FULLPATH_SIZE)
            DirBufferResult = STATUS_OBJECT_NAME_INVALID;
        if (!NT_SUCCESS(DirBufferResult))
        {
            FspFileSystemReleaseDirectoryBuffer(&FileContext->DirBuffer);
            return DirBufferResult;
        }

        if (L'\\' != FullPath[Length - 1])
            FullPath[Length++] = L'\\';
        memcpy(FullPath + Length, Pattern, PatternLength * sizeof(WCHAR));
        FullPath[Length + PatternLength] = L'\0';

        FindHandle = FindFirstFileW(FullPath, &FindData);
        if (INVALID_HANDLE_VALUE != FindHandle)
        {
            do
            {
                memset(DirInfo, 0, sizeof *DirInfo);
                Length = (ULONG)wcslen(FindData.cFileName);
                DirInfo->Size = (UINT16)(FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) + Length * sizeof(WCHAR));
                DirInfo->FileInfo.FileAttributes = FindData.dwFileAttributes;
                DirInfo->FileInfo.ReparseTag = 0;
                DirInfo->FileInfo.FileSize =
                    ((UINT64)FindData.nFileSizeHigh << 32) | (UINT64)FindData.nFileSizeLow;
                DirInfo->FileInfo.AllocationSize = (DirInfo->FileInfo.FileSize + ALLOCATION_UNIT - 1)
                    / ALLOCATION_UNIT * ALLOCATION_UNIT;
                DirInfo->FileInfo.CreationTime = ((PLARGE_INTEGER)&FindData.ftCreationTime)->QuadPart;
                DirInfo->FileInfo.LastAccessTime = ((PLARGE_INTEGER)&FindData.ftLastAccessTime)->QuadPart;
                DirInfo->FileInfo.LastWriteTime = ((PLARGE_INTEGER)&FindData.ftLastWriteTime)->QuadPart;
                DirInfo->FileInfo.ChangeTime = DirInfo->FileInfo.LastWriteTime;
                DirInfo->FileInfo.IndexNumber = 0;
                DirInfo->FileInfo.HardLinks = 0;
                memcpy(DirInfo->FileNameBuf, FindData.cFileName, Length * sizeof(WCHAR));

                if (!FspFileSystemFillDirectoryBuffer(&FileContext->DirBuffer, DirInfo, &DirBufferResult))
                    break;
            } while (FindNextFileW(FindHandle, &FindData));

            FindClose(FindHandle);
        }

        FspFileSystemReleaseDirectoryBuffer(&FileContext->DirBuffer);
    }

    if (!NT_SUCCESS(DirBufferResult))
        return DirBufferResult;

    FspFileSystemReadDirectoryBuffer(&FileContext->DirBuffer,
        Marker, Buffer, BufferLength, PBytesTransferred);

    return STATUS_SUCCESS;
}
std::string os_get_final_path(std::string path)
{
#if (_WIN32_WINNT >= 0x0600)
	std::wstring wret;

	if(path.size()<3 && path.find(":")==std::string::npos)
	{
		path+=":";
	}

	if(path.find("\\")==std::string::npos)
	{
		path+="\\";
	}

	HANDLE hFile = CreateFileW(ConvertToWchar(path).c_str(),               
                       GENERIC_READ,          
                       FILE_SHARE_READ,       
                       NULL,                  
                       OPEN_EXISTING,         
                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 
                       NULL);

	if( hFile==INVALID_HANDLE_VALUE )
	{
		Log("Could not open path in os_get_final_path for \""+path+"\"", LL_ERROR);
		return path;
	}

	DWORD dwBufsize = GetFinalPathNameByHandleW( hFile, NULL, 0, VOLUME_NAME_DOS );

	if(dwBufsize==0)
	{
		Log("Error getting path size in in os_get_final_path error="+convert((int)GetLastError())+" for \""+path+"\"", LL_ERROR);
		CloseHandle(hFile);
		return path;
	}

	wret.resize(dwBufsize+1);

	DWORD dwRet = GetFinalPathNameByHandleW( hFile, (LPWSTR)wret.c_str(), dwBufsize, VOLUME_NAME_DOS );

	CloseHandle(hFile);

	if(dwRet==0)
	{
		Log("Error getting path in in os_get_final_path error="+convert((int)GetLastError()), LL_ERROR);
	}
	else if(dwRet<wret.size())
	{
		wret.resize(dwRet);
		if(wret.find(L"\\\\?\\UNC")==0)
		{
			wret.erase(0, 7);
			wret=L"\\"+wret;
		}
		if(wret.find(L"\\\\?\\")==0)
		{
			wret.erase(0,4);
		}
		/*if(wret.size()>=2 && wret[wret.size()-2]=='.' && ret[wret.size()-1]=='.' )
		{
			wret.resize(ret.size()-2);
		}*/
		return ConvertFromWchar(wret);
	}
	else
	{
		Log("Error getting path (buffer too small) in in os_get_final_path error="+convert((int)GetLastError()), LL_ERROR);
	}

	return path;
#else
	return path;
#endif
}