# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1488029391 -3600
#      Sat Feb 25 14:29:51 2017 +0100
# Node ID e5f6cb72a00a2bf3919ccbae59eab265c670cf01
# Parent  eb6059699e3b178c3d99a96caf8eab1eb8636ca0
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 shorten_file_name that returns the 8.3 filename on
Windows.

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

diff -r eb6059699e3b -r e5f6cb72a00a libinterp/corefcn/dirfns.cc
--- a/libinterp/corefcn/dirfns.cc	Sat Feb 25 12:27:47 2017 +0100
+++ b/libinterp/corefcn/dirfns.cc	Sat Feb 25 14:29:51 2017 +0100
@@ -183,16 +183,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 eb6059699e3b -r e5f6cb72a00a libinterp/corefcn/load-path.cc
--- a/libinterp/corefcn/load-path.cc	Sat Feb 25 12:27:47 2017 +0100
+++ b/libinterp/corefcn/load-path.cc	Sat Feb 25 14:29:51 2017 +0100
@@ -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"
 
@@ -255,12 +256,13 @@
 {
   load_path::dir_info::fcn_file_map_type retval;
 
-  octave::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++)
@@ -291,11 +293,6 @@
             }
         }
     }
-  else
-    {
-      std::string msg = dir.error ();
-      warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
-    }
 
   return retval;
 }
@@ -2078,42 +2075,42 @@
 genpath (const std::string& dirname, const string_vector& skip)
 {
   std::string retval;
-
-  octave::sys::dir_entry dir (dirname);
-
-  if (dir)
+  string_vector dirlist;
+  std::string msg;
+
+  if (! octave::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++)
     {
-      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] == '+');
+
+      if (! skip_p)
         {
-          std::string elt = dirlist[i];
-
-          bool skip_p = (elt == "." || elt == ".." || elt[0] == '@'
-                         || elt[0] == '+');
+          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 = octave::sys::file_ops::concat (dirname, elt);
-
-                  octave::sys::file_stat fs (nm);
-
-                  if (fs && fs.is_dir ())
-                    retval += octave::directory_path::path_sep_str () + genpath (nm, skip);
-                }
+              std::string nm = octave::sys::file_ops::concat (dirname, elt);
+
+              octave::sys::file_stat fs (nm);
+
+              if (fs && fs.is_dir ())
+                retval += octave::directory_path::path_sep_str () + genpath (nm, skip);
             }
         }
     }
diff -r eb6059699e3b -r e5f6cb72a00a libinterp/corefcn/load-save.cc
--- a/libinterp/corefcn/load-save.cc	Sat Feb 25 12:27:47 2017 +0100
+++ b/libinterp/corefcn/load-save.cc	Sat Feb 25 14:29:51 2017 +0100
@@ -302,7 +302,7 @@
 
 #if defined (HAVE_HDF5)
   // check this before we open the file
-  if (H5Fis_hdf5 (fname.c_str ()) > 0)
+  if (H5Fis_hdf5 (octave::sys::shorten_file_name (fname).c_str ()) > 0)
     return LS_HDF5;
 #endif
 
@@ -1656,7 +1656,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::shorten_file_name (fname).c_str ()) > 0);
 
           hdf5_ofstream hdf5_file (fname.c_str (), mode);
 
diff -r eb6059699e3b -r e5f6cb72a00a libinterp/corefcn/ls-hdf5.cc
--- a/libinterp/corefcn/ls-hdf5.cc	Sat Feb 25 12:27:47 2017 +0100
+++ b/libinterp/corefcn/ls-hdf5.cc	Sat Feb 25 14:29:51 2017 +0100
@@ -91,13 +91,18 @@
 {
 #if defined (HAVE_HDF5)
 
+  const char *s_name = octave::sys::shorten_file_name (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);
     }
@@ -138,13 +143,18 @@
 
   clear ();
 
+  const char *s_name = octave::sys::shorten_file_name (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 eb6059699e3b -r e5f6cb72a00a libinterp/corefcn/sysdep.cc
--- a/libinterp/corefcn/sysdep.cc	Sat Feb 25 12:27:47 2017 +0100
+++ b/libinterp/corefcn/sysdep.cc	Sat Feb 25 14:29:51 2017 +0100
@@ -267,11 +267,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
@@ -279,14 +279,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 eb6059699e3b -r e5f6cb72a00a libinterp/dldfcn/gzip.cc
--- a/libinterp/dldfcn/gzip.cc	Sat Feb 25 12:27:47 2017 +0100
+++ b/libinterp/dldfcn/gzip.cc	Sat Feb 25 14:29:51 2017 +0100
@@ -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 ())
         {
-          octave::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 (octave::sys::file_ops::concat (path, dirlist(i)));
diff -r eb6059699e3b -r e5f6cb72a00a libinterp/parse-tree/oct-parse.in.yy
--- a/libinterp/parse-tree/oct-parse.in.yy	Sat Feb 25 12:27:47 2017 +0100
+++ b/libinterp/parse-tree/oct-parse.in.yy	Sat Feb 25 14:29:51 2017 +0100
@@ -64,6 +64,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"
@@ -4260,7 +4261,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 eb6059699e3b -r e5f6cb72a00a liboctave/system/file-ops.cc
--- a/liboctave/system/file-ops.cc	Sat Feb 25 12:27:47 2017 +0100
+++ b/liboctave/system/file-ops.cc	Sat Feb 25 14:29:51 2017 +0100
@@ -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"
@@ -415,7 +416,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);
@@ -553,7 +554,7 @@
 
       int status = -1;
 
-      status = octave_rmdir_wrapper (name.c_str ());
+      status = octave_rmdir (name.c_str ());
 
       if (status < 0)
         msg = std::strerror (errno);
@@ -577,12 +578,10 @@
 
       int status = 0;
 
-      octave::sys::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 ();
@@ -623,17 +622,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 eb6059699e3b -r e5f6cb72a00a liboctave/system/file-stat.cc
--- a/liboctave/system/file-stat.cc	Sat Feb 25 12:27:47 2017 +0100
+++ b/liboctave/system/file-stat.cc	Sat Feb 25 14:29:51 2017 +0100
@@ -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 eb6059699e3b -r e5f6cb72a00a liboctave/system/lo-sysdep.cc
--- a/liboctave/system/lo-sysdep.cc	Sat Feb 25 12:27:47 2017 +0100
+++ b/liboctave/system/lo-sysdep.cc	Sat Feb 25 14:29:51 2017 +0100
@@ -26,11 +26,19 @@
 
 #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>
+#endif
+
 namespace octave
 {
   namespace sys
@@ -40,6 +48,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 +66,8 @@
         (*current_liboctave_error_handler) ("unable to find current directory");
 
       retval = tmp;
+#endif
+
       free (tmp);
 
       return retval;
@@ -65,7 +83,243 @@
         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;
+          FormatMessage (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));
+
+      // 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));
+
+      // 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
+    shorten_file_name (const std::string& long_file_name)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      const wchar_t* w_long_file_name = u8_to_wstring (long_file_name).c_str ();
+      // get short filename (8.3) from UTF-16 filename
+      long length = GetShortPathNameW (w_long_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_long_file_name, w_short_file_name, length);
+ 
+      std::string short_file_name = u8_from_wstring (std::wstring (w_short_file_name));
+
+      return short_file_name;
+#else
+      return long_file_name;
+#endif
+    }
+
   }
 }
diff -r eb6059699e3b -r e5f6cb72a00a liboctave/system/lo-sysdep.h
--- a/liboctave/system/lo-sysdep.h	Sat Feb 25 12:27:47 2017 +0100
+++ b/liboctave/system/lo-sysdep.h	Sat Feb 25 14:29:51 2017 +0100
@@ -37,9 +37,39 @@
 {
   namespace sys
   {
-    extern std::string getcwd (void);
+    extern std::string
+    getcwd (void);
 
-    extern int chdir (const std::string&);
+    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
+    shorten_file_name (const std::string& long_file_name);
+
   }
 }
 
diff -r eb6059699e3b -r e5f6cb72a00a liboctave/util/url-transfer.cc
--- a/liboctave/util/url-transfer.cc	Sat Feb 25 12:27:47 2017 +0100
+++ b/liboctave/util/url-transfer.cc	Sat Feb 25 14:29:51 2017 +0100
@@ -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);
 
-        octave::sys::dir_entry dirlist (realdir);
-
-        if (dirlist)
-          {
-            string_vector files = dirlist.read ();
-
-            for (octave_idx_type i = 0; i < files.numel (); i++)
-              {
-                std::string file = files (i);
-
-                if (file == "." || file == "..")
-                  continue;
-
-                std::string realfile = realdir + octave::sys::file_ops::dir_sep_str () + file;
-                octave::sys::file_stat fs (realfile);
-
-                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));
+        string_vector files;
+        std::string msg;
 
-                    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 (sys::get_dirlist (realdir, files, msg))
+          for (octave_idx_type i = 0; i < files.numel (); i++)
+            {
+              std::string file = files (i);
 
-                    if (! ifile.is_open ())
-                      {
-                        ok = false;
-                        errmsg = "__ftp_mput__: unable to open file '"
-                                 + realfile + "'";
-                        break;
-                      }
+              if (file == "." || file == "..")
+                continue;
 
-                    put (file, ifile);
-
-                    ifile.close ();
+              std::string realfile = realdir + octave::sys::file_ops::dir_sep_str () + file;
+              octave::sys::file_stat fs (realfile);
 
-                    if (! good ())
-                      break;
+              if (! fs.exists ())
+                {
+                  ok = false;
+                  errmsg = "__ftp__mput: file '" + realfile
+                           + "' does not exist";
+                  break;
+                }
 
-                    file_list.append (realfile);
-                  }
-              }
-          }
+              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 (! ifile.is_open ())
+                    {
+                      ok = false;
+                      errmsg = "__ftp_mput__: unable to open file '"
+                               + realfile + "'";
+                      break;
+                    }
+
+                  put (file, ifile);
+
+                  ifile.close ();
+
+                  if (! good ())
+                    break;
+
+                  file_list.append (realfile);
+                }
+            }
         else
           {
             ok = false;
