# HG changeset patch # User Markus Mützel # Date 1530268389 -7200 # Node ID 8945a6a6c0eb3750ace9307ea25619e3c89ab217 # Parent c63f67d87b4ac6150440f13ee5f02034eac6afb0 Add Unicode support for getting directory listing in Windows (bug #49118). * lo-sysdep.[cc,h]: Add new function "get_dirlist". * dirfns.cc, load-path.cc, gzip.cc, file-ops.cc, url-transfer.cc: Replace uses of "dir_entry::read" with "get_dirlist". diff -r c63f67d87b4a -r 8945a6a6c0eb libinterp/corefcn/dirfns.cc --- a/libinterp/corefcn/dirfns.cc Thu Jun 28 14:39:46 2018 +0200 +++ b/libinterp/corefcn/dirfns.cc Fri Jun 29 12:33:09 2018 +0200 @@ -187,16 +187,16 @@ dirname = octave::sys::file_ops::tilde_expand (dirname); - octave::sys::dir_entry dir (dirname); + string_vector dirlist; + std::string msg; - 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 c63f67d87b4a -r 8945a6a6c0eb libinterp/corefcn/load-path.cc --- a/libinterp/corefcn/load-path.cc Thu Jun 28 14:39:46 2018 +0200 +++ b/libinterp/corefcn/load-path.cc Fri Jun 29 12:33:09 2018 +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" @@ -1074,12 +1075,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++) @@ -1118,11 +1120,6 @@ } } } - else - { - std::string msg = dir.error (); - warning ("load_path: %s: %s", d.c_str (), msg.c_str ()); - } return retval; } @@ -2151,42 +2148,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 c63f67d87b4a -r 8945a6a6c0eb libinterp/dldfcn/gzip.cc --- a/libinterp/dldfcn/gzip.cc Thu Jun 28 14:39:46 2018 +0200 +++ b/libinterp/dldfcn/gzip.cc Fri Jun 29 12:33:09 2018 +0200 @@ -61,6 +61,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" @@ -483,13 +484,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 c63f67d87b4a -r 8945a6a6c0eb liboctave/system/file-ops.cc --- a/liboctave/system/file-ops.cc Thu Jun 28 14:39:46 2018 +0200 +++ b/liboctave/system/file-ops.cc Fri Jun 29 12:33:09 2018 +0200 @@ -41,6 +41,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" @@ -548,12 +549,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 (); @@ -594,17 +593,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 c63f67d87b4a -r 8945a6a6c0eb liboctave/system/lo-sysdep.cc --- a/liboctave/system/lo-sysdep.cc Thu Jun 28 14:39:46 2018 +0200 +++ b/liboctave/system/lo-sysdep.cc Fri Jun 29 12:33:09 2018 +0200 @@ -26,12 +26,18 @@ #include +#include "dir-ops.h" #include "file-ops.h" #include "lo-error.h" #include "lo-sysdep.h" #include "uniconv-wrappers.h" #include "unistd-wrappers.h" +#if defined (OCTAVE_USE_WINDOWS_API) +# include +# include +#endif + namespace octave { namespace sys @@ -69,6 +75,71 @@ return octave_chdir_wrapper (path.c_str ()); } + bool + get_dirlist (const std::string& dirname, string_vector& dirlist, std::string& msg) + { + dirlist = ""; + msg = ""; +#if defined (OCTAVE_USE_WINDOWS_API) + _WIN32_FIND_DATAW ffd; + + std::string path_name (dirname); + if (path_name.empty ()) + return true; + + if (path_name.back () == '\\' || path_name.back () == '/') + path_name.push_back ('*'); + else + path_name.append (R"(\*)"); + + // 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 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::wstring u8_to_wstring (const std::string& utf8_string) { diff -r c63f67d87b4a -r 8945a6a6c0eb liboctave/system/lo-sysdep.h --- a/liboctave/system/lo-sysdep.h Thu Jun 28 14:39:46 2018 +0200 +++ b/liboctave/system/lo-sysdep.h Fri Jun 29 12:33:09 2018 +0200 @@ -41,6 +41,9 @@ extern int chdir (const std::string&); + extern bool get_dirlist (const std::string& dirname, string_vector& dirlist, + std::string& msg); + extern std::wstring u8_to_wstring (const std::string&); extern std::string u8_from_wstring (const std::wstring&); diff -r c63f67d87b4a -r 8945a6a6c0eb liboctave/util/url-transfer.cc --- a/liboctave/util/url-transfer.cc Thu Jun 28 14:39:46 2018 +0200 +++ b/liboctave/util/url-transfer.cc Fri Jun 29 12:33:09 2018 +0200 @@ -36,6 +36,7 @@ #include "dir-ops.h" #include "file-ops.h" #include "file-stat.h" +#include "lo-sysdep.h" #include "oct-env.h" #include "unwind-prot.h" #include "url-transfer.h" @@ -169,62 +170,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;