# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1500485179 -7200
#      Wed Jul 19 19:26:19 2017 +0200
# Node ID 78aa7660321a41c14f54bbcf5fbec63908f5dced
# Parent  58cb2f52ce6702a9a3cdd7ae1e4d4144b98fcdf4
Use wide character Windows API for file system (bug #49118).

* lo-sysdep.[cc,h]: Use wide character API for getcwd, chdir, and
same_file_internal. Add functions octave_mkdir, octave_rmdir, stat,
get_dirlist, and fopen. Add conversion functions between utf-8 and
wchar_t. Add function get_ASCII_filename that returns valid filename without
non-ASCII characters.

* dirfns.cc, load-path.cc, load-save.cc, ls-hdf5.c, gzip.cc,
oct-parse.in.yy (parse_fcn_file), file-ops.cc, file-stat.cc,
url-transfer.cc: Use sysdep functions.

* sysdep.cc: First steps to get Octave to work when installed on path with
non-ASCII chars. Use wchar interface for __open_with_system_app__, same_file.

diff -r 58cb2f52ce67 -r 78aa7660321a libinterp/corefcn/dirfns.cc
--- a/libinterp/corefcn/dirfns.cc	Thu Jul 13 15:57:35 2017 -0700
+++ b/libinterp/corefcn/dirfns.cc	Wed Jul 19 19:26:19 2017 +0200
@@ -186,16 +186,16 @@
 
   dirname = octave::sys::file_ops::tilde_expand (dirname);
 
-  octave::sys::dir_entry dir (dirname);
+  string_vector dirlist;
+  std::string msg = std::string ("");
 
-  if (dir)
+  if (octave::sys::get_dirlist (dirname, dirlist, msg))
     {
-      string_vector dirlist = dir.read ();
       retval(0) = Cell (dirlist.sort ());
       retval(1) = 0.0;
     }
   else
-    retval(2) = dir.error ();
+    retval(2) = msg;
 
   return retval;
 }
diff -r 58cb2f52ce67 -r 78aa7660321a libinterp/corefcn/load-path.cc
--- a/libinterp/corefcn/load-path.cc	Thu Jul 13 15:57:35 2017 -0700
+++ b/libinterp/corefcn/load-path.cc	Wed Jul 19 19:26:19 2017 +0200
@@ -42,6 +42,7 @@
 #include "ov-usr-fcn.h"
 #include "pager.h"
 #include "parse.h"
+#include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
 
@@ -1068,12 +1069,13 @@
   {
     load_path::dir_info::fcn_file_map_type retval;
 
-    sys::dir_entry dir (d);
-
-    if (dir)
+    string_vector flist;
+    std::string msg;
+
+    if (! octave::sys::get_dirlist (d, flist, msg))
+      warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
+    else
       {
-        string_vector flist = dir.read ();
-
         octave_idx_type len = flist.numel ();
 
         for (octave_idx_type i = 0; i < len; i++)
@@ -1104,11 +1106,6 @@
               }
           }
       }
-    else
-      {
-        std::string msg = dir.error ();
-        warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
-      }
 
     return retval;
   }
@@ -2128,42 +2125,42 @@
   genpath (const std::string& dirname, const string_vector& skip)
   {
     std::string retval;
-
-    sys::dir_entry dir (dirname);
-
-    if (dir)
-      {
-        retval = dirname;
-
-        string_vector dirlist = dir.read ().sort (false);
-
-        octave_idx_type len = dirlist.numel ();
-
-        for (octave_idx_type i = 0; i < len; i++)
-          {
-            std::string elt = dirlist[i];
-
-            bool skip_p = (elt == "." || elt == ".." || elt[0] == '@'
-                           || elt[0] == '+');
+  string_vector dirlist;
+  std::string msg;
+
+  if (! sys::get_dirlist (dirname, dirlist, msg))
+    return retval;
+
+  retval = dirname;
+
+  dirlist = dirlist.sort (false);
+
+  octave_idx_type len = dirlist.numel ();
+
+  for (octave_idx_type i = 0; i < len; i++)
+    {
+      std::string elt = dirlist[i];
+
+      bool skip_p = (elt == "." || elt == ".." || elt[0] == '@'
+                     || elt[0] == '+');
+
+      if (! skip_p)
+        {
+          for (octave_idx_type j = 0; j < skip.numel (); j++)
+            {
+              skip_p = (elt == skip[j]);
+              if (skip_p)
+                break;
+            }
 
             if (! skip_p)
               {
-                for (octave_idx_type j = 0; j < skip.numel (); j++)
-                  {
-                    skip_p = (elt == skip[j]);
-                    if (skip_p)
-                      break;
-                  }
-
-                if (! skip_p)
-                  {
-                    std::string nm = sys::file_ops::concat (dirname, elt);
-
-                    sys::file_stat fs (nm);
-
-                    if (fs && fs.is_dir ())
-                      retval += directory_path::path_sep_str () + genpath (nm, skip);
-                  }
+                std::string nm = sys::file_ops::concat (dirname, elt);
+
+                sys::file_stat fs (nm);
+
+                if (fs && fs.is_dir ())
+                  retval += directory_path::path_sep_str () + genpath (nm, skip);
               }
           }
       }
diff -r 58cb2f52ce67 -r 78aa7660321a libinterp/corefcn/load-save.cc
--- a/libinterp/corefcn/load-save.cc	Thu Jul 13 15:57:35 2017 -0700
+++ b/libinterp/corefcn/load-save.cc	Wed Jul 19 19:26:19 2017 +0200
@@ -308,7 +308,7 @@
 
 #if defined (HAVE_HDF5)
   // check this before we open the file
-  if (H5Fis_hdf5 (fname.c_str ()) > 0)
+  if (H5Fis_hdf5 (octave::sys::get_ASCII_filename (fname).c_str ()) > 0)
     return LS_HDF5;
 #endif
 
@@ -1674,7 +1674,8 @@
             error ("save: appending to HDF5 files is not implemented");
 
           bool write_header_info
-            = ! (append && H5Fis_hdf5 (fname.c_str ()) > 0);
+            = ! (append && H5Fis_hdf5 (
+                 octave::sys::get_ASCII_filename (fname).c_str ()) > 0);
 
           hdf5_ofstream hdf5_file (fname.c_str (), mode);
 
diff -r 58cb2f52ce67 -r 78aa7660321a libinterp/corefcn/ls-hdf5.cc
--- a/libinterp/corefcn/ls-hdf5.cc	Thu Jul 13 15:57:35 2017 -0700
+++ b/libinterp/corefcn/ls-hdf5.cc	Wed Jul 19 19:26:19 2017 +0200
@@ -88,13 +88,19 @@
 {
 #if defined (HAVE_HDF5)
 
+  const char *s_name = 
+                  octave::sys::get_ASCII_filename (std::string (name)).c_str ();
+
   if (mode & std::ios::in)
-    file_id = H5Fopen (name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
+    file_id = H5Fopen (s_name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
   else if (mode & std::ios::out)
     {
-      if (mode & std::ios::app && H5Fis_hdf5 (name) > 0)
-        file_id = H5Fopen (name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
+      if (mode & std::ios::app && H5Fis_hdf5 (s_name) > 0)
+        file_id = H5Fopen (s_name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
       else
+        // FIXME: For Windows, create a file with an ASCII name in an
+        //        accessible folder, close the file move and rename using
+        //        wide character API and re-open.
         file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
                              octave_H5P_DEFAULT);
     }
@@ -135,13 +141,18 @@
 
   clear ();
 
+  const char *s_name = octave::sys::get_ASCII_filename (std::string (name)).c_str ();
+
   if (mode & std::ios::in)
-    file_id = H5Fopen (name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
+    file_id = H5Fopen (s_name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
   else if (mode & std::ios::out)
     {
-      if (mode & std::ios::app && H5Fis_hdf5 (name) > 0)
-        file_id = H5Fopen (name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
+      if (mode & std::ios::app && H5Fis_hdf5 (s_name) > 0)
+        file_id = H5Fopen (s_name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
       else
+        // FIXME: For Windows, create a file with an ASCII name in an
+        //        accessible folder, close the file move and rename using
+        //        wide character API and re-open.
         file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
                              octave_H5P_DEFAULT);
     }
diff -r 58cb2f52ce67 -r 78aa7660321a libinterp/corefcn/sysdep.cc
--- a/libinterp/corefcn/sysdep.cc	Thu Jul 13 15:57:35 2017 -0700
+++ b/libinterp/corefcn/sysdep.cc	Wed Jul 19 19:26:19 2017 +0200
@@ -122,26 +122,26 @@
 
   if (h != INVALID_HANDLE_VALUE)
     {
-      MODULEENTRY32 mod_info;
+      MODULEENTRY32W mod_info;
 
       ZeroMemory (&mod_info, sizeof (mod_info));
       mod_info.dwSize = sizeof (mod_info);
 
-      if (Module32First (h, &mod_info))
+      if (Module32FirstW (h, &mod_info))
         {
           do
             {
-              std::string mod_name (mod_info.szModule);
+              std::string mod_name (octave::sys::u8_from_wstring (mod_info.szModule));
 
               if (mod_name.find ("octinterp") != std::string::npos)
                 {
-                  bin_dir = mod_info.szExePath;
+                  bin_dir = octave::sys::u8_from_wstring (mod_info.szExePath);
                   if (bin_dir[bin_dir.length () - 1] != '\\')
                     bin_dir.append (1, '\\');
                   break;
                 }
             }
-          while (Module32Next (h, &mod_info));
+          while (Module32NextW (h, &mod_info));
         }
 
       CloseHandle (h);
@@ -213,7 +213,7 @@
   octave_value retval;
 
 #if defined (OCTAVE_USE_WINDOWS_API)
-  HINSTANCE status = ShellExecute (0, 0, file.c_str (), 0, 0,
+  HINSTANCE status = ShellExecuteW (0, 0, octave::sys::u8_to_wstring (file).c_str (), 0, 0,
                                    SW_SHOWNORMAL);
 
   // ShellExecute returns a value greater than 32 if successful.
@@ -262,11 +262,11 @@
 
   bool retval = false;
 
-  const char *f1 = file1.c_str ();
-  const char *f2 = file2.c_str ();
+  const wchar_t *f1 = octave::sys::u8_to_wstring (file1).c_str ();
+  const wchar_t *f2 = octave::sys::u8_to_wstring (file2).c_str ();
 
-  bool f1_is_dir = GetFileAttributes (f1) & FILE_ATTRIBUTE_DIRECTORY;
-  bool f2_is_dir = GetFileAttributes (f2) & FILE_ATTRIBUTE_DIRECTORY;
+  bool f1_is_dir = GetFileAttributesW (f1) & FILE_ATTRIBUTE_DIRECTORY;
+  bool f2_is_dir = GetFileAttributesW (f2) & FILE_ATTRIBUTE_DIRECTORY;
 
   // Windows native code
   // Reference: http://msdn2.microsoft.com/en-us/library/aa363788.aspx
@@ -274,14 +274,14 @@
   DWORD share = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
 
   HANDLE hfile1
-    = CreateFile (f1, 0, share, 0, OPEN_EXISTING,
-                  f1_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
+    = CreateFileW (f1, 0, share, 0, OPEN_EXISTING,
+                   f1_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
 
   if (hfile1 != INVALID_HANDLE_VALUE)
     {
       HANDLE hfile2
-        = CreateFile (f2, 0, share, 0, OPEN_EXISTING,
-                      f2_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
+        = CreateFileW (f2, 0, share, 0, OPEN_EXISTING,
+                       f2_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
 
       if (hfile2 != INVALID_HANDLE_VALUE)
         {
diff -r 58cb2f52ce67 -r 78aa7660321a libinterp/dldfcn/gzip.cc
--- a/libinterp/dldfcn/gzip.cc	Thu Jul 13 15:57:35 2017 -0700
+++ b/libinterp/dldfcn/gzip.cc	Wed Jul 19 19:26:19 2017 +0200
@@ -62,6 +62,7 @@
 #include "file-ops.h"
 #include "file-stat.h"
 #include "glob-match.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "str-vec.h"
 
@@ -484,13 +485,14 @@
       // is_dir and is_reg will return false if failed to stat.
       if (fs.is_dir ())
         {
-          sys::dir_entry dir (path);
-          if (dir)
+          string_vector dirlist;
+          std::string msg;
+
+          // Collect the whole list of filenames first, before recursion
+          // to avoid issues with infinite loop if the action generates
+          // files in the same directory (highly likely).
+          if (sys::get_dirlist (path, dirlist, msg))
             {
-              // Collect the whole list of filenames first, before recursion
-              // to avoid issues with infinite loop if the action generates
-              // files in the same directory (highly likely).
-              string_vector dirlist = dir.read ();
               for (octave_idx_type i = 0; i < dirlist.numel (); i++)
                 if (dirlist(i) != "." && dirlist(i) != "..")
                   walk (sys::file_ops::concat (path, dirlist(i)));
diff -r 58cb2f52ce67 -r 78aa7660321a libinterp/parse-tree/oct-parse.in.yy
--- a/libinterp/parse-tree/oct-parse.in.yy	Thu Jul 13 15:57:35 2017 -0700
+++ b/libinterp/parse-tree/oct-parse.in.yy	Wed Jul 19 19:26:19 2017 +0200
@@ -65,6 +65,7 @@
 #include "interpreter.h"
 #include "lex.h"
 #include "load-path.h"
+#include "lo-sysdep.h"
 #include "oct-hist.h"
 #include "oct-map.h"
 #include "ov-classdef.h"
@@ -4419,7 +4420,7 @@
   FILE *ffile = 0;
 
   if (! full_file.empty ())
-    ffile = std::fopen (full_file.c_str (), "rb");
+    ffile = octave::sys::fopen (full_file, "rb");
 
   if (ffile)
     {
diff -r 58cb2f52ce67 -r 78aa7660321a liboctave/system/file-ops.cc
--- a/liboctave/system/file-ops.cc	Thu Jul 13 15:57:35 2017 -0700
+++ b/liboctave/system/file-ops.cc	Wed Jul 19 19:26:19 2017 +0200
@@ -42,6 +42,7 @@
 #include "file-ops.h"
 #include "file-stat.h"
 #include "gen-tempname-wrapper.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-locbuf.h"
 #include "oct-passwd.h"
@@ -404,7 +405,7 @@
     {
       msg = "";
 
-      int status = octave_mkdir_wrapper (name.c_str (), mode);
+      int status = octave_mkdir (name.c_str (), mode);
 
       if (status < 0)
         msg = std::strerror (errno);
@@ -530,7 +531,7 @@
 
       int status = -1;
 
-      status = octave_rmdir_wrapper (name.c_str ());
+      status = octave_rmdir (name.c_str ());
 
       if (status < 0)
         msg = std::strerror (errno);
@@ -552,12 +553,10 @@
 
       int status = 0;
 
-      dir_entry dir (name);
+      string_vector dirlist;
 
-      if (dir)
+      if (get_dirlist (name, dirlist, msg))
         {
-          string_vector dirlist = dir.read ();
-
           for (octave_idx_type i = 0; i < dirlist.numel (); i++)
             {
               octave_quit ();
@@ -598,17 +597,10 @@
             }
 
           if (status >= 0)
-            {
-              dir.close ();
-              status = rmdir (name, msg);
-            }
+            status = rmdir (name, msg);
         }
       else
-        {
-          status = -1;
-
-          msg = dir.error ();
-        }
+        status = -1;
 
       return status;
     }
diff -r 58cb2f52ce67 -r 78aa7660321a liboctave/system/file-stat.cc
--- a/liboctave/system/file-stat.cc	Thu Jul 13 15:57:35 2017 -0700
+++ b/liboctave/system/file-stat.cc	Wed Jul 19 19:26:19 2017 +0200
@@ -30,6 +30,7 @@
 
 #include "file-ops.h"
 #include "file-stat.h"
+#include "lo-sysdep.h"
 #include "stat-wrappers.h"
 #include "strmode-wrapper.h"
 
@@ -194,20 +195,13 @@
             full_file_name.resize (full_file_name.length () - 1);
 #endif
 
-          const char *cname = full_file_name.c_str ();
-
           time_t sys_atime, sys_mtime, sys_ctime;
 
           int status
-            = (follow_links
-               ? octave_stat_wrapper (cname, &m_mode, &m_ino, &m_dev,
-                                      &m_nlink, &m_uid, &m_gid, &m_size,
-                                      &sys_atime, &sys_mtime, &sys_ctime,
-                                      &m_rdev, &m_blksize, &m_blocks)
-               : octave_lstat_wrapper (cname, &m_mode, &m_ino, &m_dev,
-                                       &m_nlink, &m_uid, &m_gid, &m_size,
-                                       &sys_atime, &sys_mtime, &sys_ctime,
-                                       &m_rdev, &m_blksize, &m_blocks));
+            = octave::sys::stat (full_file_name, follow_links, &m_mode, &m_ino, &m_dev,
+                                 &m_nlink, &m_uid, &m_gid, &m_size,
+                                 &sys_atime, &sys_mtime, &sys_ctime,
+                                 &m_rdev, &m_blksize, &m_blocks);
 
           if (status < 0)
             {
diff -r 58cb2f52ce67 -r 78aa7660321a liboctave/system/lo-sysdep.cc
--- a/liboctave/system/lo-sysdep.cc	Thu Jul 13 15:57:35 2017 -0700
+++ b/liboctave/system/lo-sysdep.cc	Wed Jul 19 19:26:19 2017 +0200
@@ -26,11 +26,22 @@
 
 #include <string>
 
+#include "dir-ops.h"
 #include "file-ops.h"
 #include "lo-error.h"
 #include "lo-sysdep.h"
+#include "stat-wrappers.h"
+#include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#  include <wchar.h>
+#  include <versionhelpers.h>
+
+#  include "lo-hash.h"
+#endif
+
 namespace octave
 {
   namespace sys
@@ -40,6 +51,14 @@
     {
       std::string retval;
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+      wchar_t *tmp = _wgetcwd (NULL, 0);
+
+      if (! tmp)
+        (*current_liboctave_error_handler) ("unable to find current directory");
+
+      retval = u8_from_wstring (tmp);
+#else
       // Using octave_getcwd_wrapper ensures that we have a getcwd that
       // will allocate a buffer as large as necessary if buf and size are
       // both 0.
@@ -50,6 +69,8 @@
         (*current_liboctave_error_handler) ("unable to find current directory");
 
       retval = tmp;
+#endif
+
       free (tmp);
 
       return retval;
@@ -65,7 +86,287 @@
         path += "\\";
 #endif
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+      return _wchdir (u8_to_wstring (path).c_str ());
+#else
       return octave_chdir_wrapper (path.c_str ());
+#endif
     }
+
+    int
+    octave_mkdir (const std::string& name, mode_t mode)
+    {
+      int status = -1;
+#if defined (OCTAVE_USE_WINDOWS_API)
+      status = _wmkdir (u8_to_wstring (name).c_str ());
+      octave_unused_parameter (mode);
+#else
+      status = octave_mkdir_wrapper (name.c_str (), mode);
+#endif
+      return status;
+    }
+
+    int
+    octave_rmdir (const std::string& name)
+    {
+      int status = -1;
+#if defined (OCTAVE_USE_WINDOWS_API)
+      status =  _wrmdir (u8_to_wstring (name).c_str ());
+#else
+      status =  octave_rmdir_wrapper (name.c_str ());
+#endif
+      return status;
+    }
+
+    int
+    stat (const std::string& full_file_name, bool follow_links, mode_t* mode, ino_t* ino,
+          dev_t* dev, nlink_t* nlink, uid_t* uid,
+          gid_t* gid, off_t* size, time_t* atime,
+          time_t* mtime, time_t* ctime, dev_t* rdev,
+          long* blksize, long* blocks)
+    {
+#  if defined (OCTAVE_USE_WINDOWS_API)
+      struct _stat buf;
+      int status = _wstat (u8_to_wstring (full_file_name).c_str (), &buf);
+//      assign_stat_fields (&buf, mode, ino, dev, nlink, uid, gid, size,
+//                          atime, mtime, ctime, rdev, blksize, blocks);
+
+      *mode = buf.st_mode;
+      *ino = buf.st_ino;
+      *dev = buf.st_dev;
+      *nlink = buf.st_nlink;
+      *uid = buf.st_uid;
+      *gid = buf.st_gid;
+      *size = buf.st_size;
+      *atime = buf.st_atime;
+      *mtime = buf.st_mtime;
+      *ctime = buf.st_ctime;
+
+#  if defined (HAVE_STRUCT_STAT_ST_RDEV)
+      *rdev = buf.st_rdev;
+#  else
+      *rdev = 0;
+#  endif
+
+#  if defined (HAVE_STRUCT_STAT_ST_BLKSIZE)
+      *blksize = buf.st_blksize;
+#  else
+      *blksize = 0;
+#  endif
+
+#  if defined (HAVE_STRUCT_STAT_ST_BLOCKS)
+      *blocks = buf.st_blocks;
+#  else
+      *blocks = 0;
+#  endif
+
+      octave_unused_parameter (follow_links);
+      return status;
+
+#else
+      const char *cname = full_file_name.c_str ();
+
+      return (follow_links
+              ? octave_stat_wrapper (cname, mode, ino, dev,
+                                     nlink, uid, gid, size,
+                                     atime, mtime, ctime,
+                                     rdev, blksize, blocks)
+              : octave_lstat_wrapper (cname, mode, ino, dev,
+                                      nlink, uid, gid, size,
+                                      atime, mtime, ctime,
+                                      rdev, blksize, blocks));
+#endif
+    }
+
+    bool
+    get_dirlist (const std::string& dirname, string_vector& dirlist, std::string& msg)
+    {
+       msg = "";
+#if defined (OCTAVE_USE_WINDOWS_API)
+      _WIN32_FIND_DATAW ffd;
+
+      std::string path_name (dirname);
+      path_name.append ("\\*");
+
+      // Find first file in directory.
+      HANDLE hFind = FindFirstFileW (u8_to_wstring (path_name).c_str (),
+                              &ffd);
+      if (INVALID_HANDLE_VALUE == hFind) 
+        {
+          DWORD errCode = GetLastError ();
+          char *errorText;
+          FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM |
+                         FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                         FORMAT_MESSAGE_IGNORE_INSERTS,
+                         NULL, errCode,
+                         MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+                         errorText, 0, NULL);
+          if (errorText != NULL)
+            {
+              msg = std::string (errorText);
+              LocalFree (errorText);
+            }
+          return false;
+        }
+
+      std::list<std::string> dirlist_str;
+      do
+        dirlist_str.push_back (u8_from_wstring (ffd.cFileName));
+      while (FindNextFileW (hFind, &ffd) != 0);
+
+      FindClose(hFind);
+
+      dirlist = string_vector (dirlist_str);
+
+#else
+
+      dir_entry dir (dirname);
+
+      if (! dir)
+        {
+          msg = dir.error ();
+          return false;
+        }
+
+      dirlist = dir.read ();
+
+      dir.close ();
+#endif
+
+      return true;
+    }
+
+    std::FILE*
+    fopen (const std::string& filename, const std::string& mode)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      return _wfopen (u8_to_wstring (filename).c_str (),
+                      u8_to_wstring (mode).c_str ());
+#else
+      return std::fopen (filename.c_str (), mode.c_str ());
+#endif
+    }
+
+    std::wstring
+    u8_to_wstring (const std::string& utf8_string)
+    {
+      // convert multibyte UTF-8 string to wide character string
+      const uint8_t *src = reinterpret_cast<const uint8_t *> (utf8_string.c_str ());
+      size_t srclen = utf8_string.length () * sizeof (char) / sizeof (uint8_t);
+
+      size_t length;
+      wchar_t *wchar_str = 0;
+
+      wchar_str = reinterpret_cast<wchar_t *>
+                  (octave_u8_conv_to_encoding ("wchar_t", src, srclen+1, &length));
+
+      // FIXME: What to do in case of error?
+//      if (! wchar_str)
+//        error ("u8_to_wstring: converting from UTF-8 to wchar_t '%s': %s",
+//               codepage, std::strerror (errno));
+
+      std::wstring retval = std::wstring (L"");
+      if (wchar_str != NULL)
+        {
+          retval = std::wstring (wchar_str, length * sizeof (char) / sizeof (wchar_t));
+          free (static_cast<void *> (wchar_str));
+        }
+
+      return retval;
+    }
+
+    std::string
+    u8_from_wstring (const std::wstring& wchar_string)
+    {
+      // convert wide character string to multibyte UTF-8 string
+      const char *src = reinterpret_cast<const char *> (wchar_string.c_str ());
+      size_t srclen = wchar_string.length () * sizeof (wchar_t) / sizeof (char);
+
+      size_t length;
+      char *mbchar_str = 0;
+
+      mbchar_str = reinterpret_cast<char *> (octave_u8_conv_from_encoding ("wchar_t", src, srclen+1, &length));
+
+      // FIXME: What to do in case of error?
+//        if (! mbchar_str)
+//          error ("u8_to_wstring: converting from UTF-8 to wchar_t '%s': %s",
+//                 codepage, std::strerror (errno));
+
+      std::string retval = std::string ("");
+      if (mbchar_str != NULL)
+        {
+          retval = std::string (mbchar_str, length);
+          free (static_cast<void *> (mbchar_str));
+        }
+
+      return retval;
+
+    }
+
+    std::string
+    get_ASCII_filename (const std::string& orig_file_name)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      // 1. Check whether filename contains non-ASCII (UTF-8) characters
+      std::string::const_iterator first_non_ASCII = 
+                std::find_if (orig_file_name.begin (), orig_file_name.end (),
+                [](char c){return (c < 0 || c >= 128);});
+      if (first_non_ASCII == orig_file_name.end ())
+        return orig_file_name;
+
+      // 2. Check if file system stores short filenames (always ASCII-only).
+      const wchar_t* w_orig_file_name = u8_to_wstring (orig_file_name).c_str ();
+      // get short filename (8.3) from UTF-16 filename
+      long length = GetShortPathNameW (w_orig_file_name, NULL, 0);
+
+      // Dynamically allocate the correct size 
+      // (terminating null char was included in length)
+      wchar_t* w_short_file_name = new wchar_t[length];
+      length = GetShortPathNameW (w_orig_file_name, w_short_file_name, length);
+ 
+      std::string short_file_name = u8_from_wstring (std::wstring (w_short_file_name));
+
+      if (short_file_name.compare (orig_file_name) != 0)
+        return short_file_name;
+
+      // 3. Create hard link with only-ASCII characters
+      // get longest folder that only contains ASCII chars
+      size_t pos = (std::string (orig_file_name.begin (), first_non_ASCII)).
+                        find_last_of (octave::sys::file_ops::dir_sep_chars ());
+      std::string par_dir = orig_file_name.substr (0, pos+1);
+      
+      // create .oct_ascii directory
+      std::string oct_ascii_dir = par_dir + ".oct_ascii";
+      std::string test_dir = canonicalize_file_name (oct_ascii_dir);
+      if (test_dir.empty ())
+      {
+        std::string msg;
+        int status = octave::sys::mkdir (oct_ascii_dir, 0777, msg);
+        if (status < 0)
+          return orig_file_name;
+        // set hidden property
+        SetFileAttributesA (oct_ascii_dir.c_str (), FILE_ATTRIBUTE_HIDDEN);
+      }
+
+      // create file from hash of full filename
+      std::string filename_hash = oct_ascii_dir + file_ops::dir_sep_str () +
+                                  octave::crypto::hash ("SHA1", orig_file_name);
+      std::string _filename_hash_ = canonicalize_file_name (filename_hash);
+      if (! _filename_hash_.empty ())
+        return _filename_hash_;
+
+      wchar_t w_filename_hash[filename_hash.length ()+1] = {0};
+      for (size_t i=0; i < filename_hash.length (); i++)
+        w_filename_hash[i] = filename_hash.at (i);
+      if (CreateHardLinkW (w_filename_hash, w_orig_file_name, NULL))
+        return filename_hash;
+
+      return orig_file_name;
+
+#else
+      return orig_file_name;
+#endif
+    }
+
   }
 }
diff -r 58cb2f52ce67 -r 78aa7660321a liboctave/system/lo-sysdep.h
--- a/liboctave/system/lo-sysdep.h	Thu Jul 13 15:57:35 2017 -0700
+++ b/liboctave/system/lo-sysdep.h	Wed Jul 19 19:26:19 2017 +0200
@@ -40,6 +40,27 @@
     extern std::string getcwd (void);
 
     extern int chdir (const std::string&);
+
+    extern int octave_mkdir (const std::string&, mode_t);
+
+    extern int octave_rmdir (const std::string&);
+
+    extern int stat (const std::string& full_file_name, bool follow_links,
+                     mode_t* mode, ino_t* ino, dev_t* dev, nlink_t* nlink,
+                     uid_t* uid, gid_t* gid, off_t* size, time_t* atime,
+                     time_t* mtime, time_t* ctime, dev_t* rdev, long* blksize,
+                     long* blocks);
+
+    extern bool get_dirlist (const std::string& dirname, string_vector& dirlist,
+                             std::string& msg);
+
+    extern std::FILE* fopen (const std::string& name, const std::string& mode);
+
+    extern std::wstring u8_to_wstring (const std::string&);
+
+    extern std::string u8_from_wstring (const std::wstring&);
+
+    extern std::string get_ASCII_filename (const std::string& long_file_name);
   }
 }
 
diff -r 58cb2f52ce67 -r 78aa7660321a liboctave/util/url-transfer.cc
--- a/liboctave/util/url-transfer.cc	Thu Jul 13 15:57:35 2017 -0700
+++ b/liboctave/util/url-transfer.cc	Wed Jul 19 19:26:19 2017 +0200
@@ -36,6 +36,7 @@
 #include "dir-ops.h"
 #include "file-ops.h"
 #include "file-stat.h"
+#include "lo-sysdep.h"
 #include "unwind-prot.h"
 #include "url-transfer.h"
 
@@ -149,62 +150,59 @@
 
         frame.add_fcn (reset_path, this);
 
-        sys::dir_entry dirlist (realdir);
-
-        if (dirlist)
-          {
-            string_vector files = dirlist.read ();
+        string_vector files;
+        std::string msg;
 
-            for (octave_idx_type i = 0; i < files.numel (); i++)
-              {
-                std::string file = files (i);
+        if (sys::get_dirlist (realdir, files, msg))
+          for (octave_idx_type i = 0; i < files.numel (); i++)
+            {
+              std::string file = files (i);
 
-                if (file == "." || file == "..")
-                  continue;
+              if (file == "." || file == "..")
+                continue;
 
-                std::string realfile = realdir + sys::file_ops::dir_sep_str () + file;
-                sys::file_stat fs (realfile);
+              std::string realfile = realdir + sys::file_ops::dir_sep_str () + file;
+              sys::file_stat fs (realfile);
 
-                if (! fs.exists ())
-                  {
-                    ok = false;
-                    errmsg = "__ftp__mput: file '" + realfile
-                             + "' does not exist";
-                    break;
-                  }
+              if (! fs.exists ())
+                {
+                  ok = false;
+                  errmsg = "__ftp__mput: file '" + realfile
+                           + "' does not exist";
+                  break;
+                }
 
-                if (fs.is_dir ())
-                  {
-                    file_list.append (mput_directory (realdir, file));
+              if (fs.is_dir ())
+                {
+                  file_list.append (mput_directory (realdir, file));
 
-                    if (! good ())
-                      break;
-                  }
-                else
-                  {
-                    // FIXME: Does ascii mode need to be flagged here?
-                    std::ifstream ifile (realfile.c_str (), std::ios::in |
-                                         std::ios::binary);
+                  if (! good ())
+                    break;
+                }
+              else
+                {
+                  // FIXME: Does ascii mode need to be flagged here?
+                  std::ifstream ifile (realfile.c_str (), std::ios::in |
+                                       std::ios::binary);
 
-                    if (! ifile.is_open ())
-                      {
-                        ok = false;
-                        errmsg = "__ftp_mput__: unable to open file '"
-                                 + realfile + "'";
-                        break;
-                      }
-
-                    put (file, ifile);
+                  if (! ifile.is_open ())
+                    {
+                      ok = false;
+                      errmsg = "__ftp_mput__: unable to open file '"
+                               + realfile + "'";
+                      break;
+                    }
 
-                    ifile.close ();
+                  put (file, ifile);
 
-                    if (! good ())
-                      break;
+                  ifile.close ();
 
-                    file_list.append (realfile);
-                  }
-              }
-          }
+                  if (! good ())
+                    break;
+
+                  file_list.append (realfile);
+                }
+            }
         else
           {
             ok = false;
