GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
file-ops.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2018 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <cerrno>
28 #include <cstdio>
29 #include <cstdlib>
30 #include <cstring>
31 
32 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
33 # include <algorithm>
34 #endif
35 
36 #include <iostream>
37 #include <vector>
38 
39 #include "areadlink-wrapper.h"
41 #include "dir-ops.h"
42 #include "file-ops.h"
43 #include "file-stat.h"
44 #include "gen-tempname-wrapper.h"
45 #include "oct-env.h"
46 #include "oct-locbuf.h"
47 #include "oct-passwd.h"
48 #include "quit.h"
49 #include "stat-wrappers.h"
50 #include "str-vec.h"
51 #include "unistd-wrappers.h"
52 
53 // The following tilde-expansion code was stolen and adapted from
54 // readline.
55 
56 // The default value of tilde_additional_prefixes. This is set to
57 // whitespace preceding a tilde so that simple programs which do not
58 // perform any word separation get desired behavior.
59 static const char *default_prefixes[] = { " ~", "\t~", ":~", nullptr };
60 
61 // The default value of tilde_additional_suffixes. This is set to
62 // whitespace or newline so that simple programs which do not perform
63 // any word separation get desired behavior.
64 static const char *default_suffixes[] = { " ", "\n", ":", nullptr };
65 
66 static size_t
67 tilde_find_prefix (const std::string& s, size_t& len)
68 {
69  len = 0;
70 
71  size_t s_len = s.length ();
72 
73  if (s_len == 0 || s[0] == '~')
74  return 0;
75 
77 
78  if (! prefixes.empty ())
79  {
80  for (size_t i = 0; i < s_len; i++)
81  {
82  for (int j = 0; j < prefixes.numel (); j++)
83  {
84  size_t pfx_len = prefixes[j].length ();
85 
86  if (prefixes[j] == s.substr (i, pfx_len))
87  {
88  len = pfx_len - 1;
89  return i + len;
90  }
91  }
92  }
93  }
94 
95  return s_len;
96 }
97 
98 // Find the end of a tilde expansion in S, and return the index
99 // of the character which ends the tilde definition.
100 
101 static size_t
103 {
104  size_t s_len = s.length ();
105 
107 
108  size_t i = 0;
109 
110  for ( ; i < s_len; i++)
111  {
113  break;
114 
115  if (! suffixes.empty ())
116  {
117  for (int j = 0; j < suffixes.numel (); j++)
118  {
119  size_t sfx_len = suffixes[j].length ();
120 
121  if (suffixes[j] == s.substr (i, sfx_len))
122  return i;
123  }
124  }
125  }
126 
127  return i;
128 }
129 
130 // Take FNAME and return the tilde prefix we want expanded.
131 
132 static std::string
134 {
135  size_t f_len = fname.length ();
136 
137  size_t len = 1;
138 
139  while (len < f_len && ! octave::sys::file_ops::is_dir_sep (fname[len]))
140  len++;
141 
142  return fname.substr (1, len);
143 }
144 
145 // Do the work of tilde expansion on FILENAME. FILENAME starts with a
146 // tilde.
147 
148 static std::string
150 {
151  size_t f_len = filename.length ();
152 
153  if (f_len == 0 || filename[0] != '~')
154  return std::string (filename);
155 
156  // A leading '~/' or a bare '~' is *always* translated to the value
157  // of $HOME or the home directory of the current user, regardless of
158  // any preexpansion hook.
159 
160  if (f_len == 1 || octave::sys::file_ops::is_dir_sep (filename[1]))
161  return octave::sys::env::get_home_directory () + filename.substr (1);
162 
164 
165  size_t user_len = username.length ();
166 
168 
170  {
171  std::string expansion
173 
174  if (! expansion.empty ())
175  return expansion + filename.substr (user_len+1);
176  }
177 
178  // No preexpansion hook, or the preexpansion hook failed. Look in the
179  // password database.
180 
182 
183  if (! pw)
184  {
185  // If the calling program has a special syntax for expanding tildes,
186  // and we couldn't find a standard expansion, then let them try.
187 
189  {
190  std::string expansion
192 
193  if (! expansion.empty ())
194  dirname = expansion + filename.substr (user_len+1);
195  }
196 
197  // If we don't have a failure hook, or if the failure hook did not
198  // expand the tilde, return a copy of what we were passed.
199 
200  if (dirname.empty ())
201  dirname = filename;
202  }
203  else
204  dirname = pw.dir () + filename.substr (user_len+1);
205 
206  return dirname;
207 }
208 
209 namespace octave
210 {
211  namespace sys
212  {
213  namespace file_ops
214  {
215  char dev_sep_char (void)
216  {
217 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
218  return ':';
219 #else
220  return 0;
221 #endif
222  }
223 
224  char dir_sep_char (void)
225  {
226 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
227  return '\\';
228 #else
229  return '/';
230 #endif
231  }
232 
234  {
235 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
236  return R"(\)";
237 #else
238  return "/";
239 #endif
240  }
241 
243  {
244 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
245  return R"(/\)";
246 #else
247  return dir_sep_str ();
248 #endif
249  }
250 
252 
254 
256 
258 
259  bool is_dev_sep (char c)
260  {
261 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
262  return c == dev_sep_char ();
263 #else
264  octave_unused_parameter (c);
265 
266  return false;
267 #endif
268  }
269 
270  bool is_dir_sep (char c)
271  {
273  return tmp.find (c) != std::string::npos;
274  }
275 
277  {
278  if (name.find ('~') == std::string::npos)
279  return std::string (name);
280  else
281  {
283 
284  size_t name_len = name.length ();
285 
286  // Scan through S expanding tildes as we come to them.
287 
288  size_t pos = 0;
289 
290  while (1)
291  {
292  if (pos > name_len)
293  break;
294 
295  size_t len;
296 
297  // Make START point to the tilde which starts the expansion.
298 
299  size_t start = tilde_find_prefix (name.substr (pos), len);
300 
301  result.append (name.substr (pos, start));
302 
303  // Advance STRING to the starting tilde.
304 
305  pos += start;
306 
307  // Make FINI be the index of one after the last character of the
308  // username.
309 
310  size_t fini = tilde_find_suffix (name.substr (pos));
311 
312  // If both START and FINI are zero, we are all done.
313 
314  if (! (start || fini))
315  break;
316 
317  // Expand the entire tilde word, and copy it into RESULT.
318 
319  std::string tilde_word = name.substr (pos, fini);
320 
321  pos += fini;
322 
323  std::string expansion = tilde_expand_word (tilde_word);
324 
325  result.append (expansion);
326  }
327 
328  return result;
329  }
330  }
331 
333  {
334  int n = names.numel ();
335 
336  string_vector retval (n);
337 
338  for (int i = 0; i < n; i++)
339  retval[i] = tilde_expand (names[i]);
340 
341  return retval;
342  }
343 
345  {
346  return dir.empty ()
347  ? file
348  : (is_dir_sep (dir.back ())
349  ? dir + file
350  : dir + dir_sep_char () + file);
351  }
352 
354  {
355  size_t ipos = path.find_last_of (dir_sep_chars ());
356 
357  return (ipos != std::string::npos) ? path.substr (0, ipos) : "";
358  }
359 
361  {
362  size_t ipos = path.find_last_of (dir_sep_chars ());
363 
364  if (ipos != std::string::npos)
365  ipos++;
366  else
367  ipos = 0;
368 
369  return path.substr (ipos);
370  }
371 
373  {
375 
376  if (dir_sep_char () == '/')
377  retval = path;
378  else
379  {
380  size_t n = path.length ();
381  for (size_t i = 0; i < n; i++)
382  {
383  if (path[i] == '/')
384  retval += dir_sep_char();
385  else
386  retval += path[i];
387  }
388  }
389 
390  return retval;
391  }
392  }
393 
394  int mkdir (const std::string& nm, mode_t md)
395  {
396  std::string msg;
397  return mkdir (nm, md, msg);
398  }
399 
400  int mkdir (const std::string& name, mode_t mode, std::string& msg)
401  {
402  msg = "";
403 
404  int status = octave_mkdir_wrapper (name.c_str (), mode);
405 
406  if (status < 0)
407  msg = std::strerror (errno);
408 
409  return status;
410  }
411 
412  int mkfifo (const std::string& nm, mode_t md)
413  {
414  std::string msg;
415  return mkfifo (nm, md, msg);
416  }
417 
418  int mkfifo (const std::string& name, mode_t mode, std::string& msg)
419  {
420  msg = "";
421 
422  int status = octave_mkfifo_wrapper (name.c_str (), mode);
423 
424  if (status < 0)
425  msg = std::strerror (errno);
426 
427  return status;
428  }
429 
430  int link (const std::string& old_name, const std::string& new_name)
431  {
432  std::string msg;
433  return link (old_name, new_name, msg);
434  }
435 
436  int link (const std::string& old_name, const std::string& new_name,
437  std::string& msg)
438  {
439  msg = "";
440 
441  int status = -1;
442 
443  status = octave_link_wrapper (old_name.c_str (), new_name.c_str ());
444 
445  if (status < 0)
446  msg = std::strerror (errno);
447 
448  return status;
449  }
450 
451  int symlink (const std::string& old_name, const std::string& new_name)
452  {
453  std::string msg;
454  return symlink (old_name, new_name, msg);
455  }
456 
457  int symlink (const std::string& old_name, const std::string& new_name,
458  std::string& msg)
459  {
460  msg = "";
461 
462  int status = -1;
463 
464  status = octave_symlink_wrapper (old_name.c_str (), new_name.c_str ());
465 
466  if (status < 0)
467  msg = std::strerror (errno);
468 
469  return status;
470  }
471 
473  {
474  std::string msg;
475  return readlink (path, result, msg);
476  }
477 
479  {
480  int status = -1;
481 
482  msg = "";
483 
484  char *buf = octave_areadlink_wrapper (path.c_str ());
485 
486  if (! buf)
487  msg = std::strerror (errno);
488  else
489  {
490  result = buf;
491  ::free (buf);
492  status = 0;
493  }
494 
495  return status;
496  }
497 
498  int rename (const std::string& from, const std::string& to)
499  {
500  std::string msg;
501  return rename (from, to, msg);
502  }
503 
504  int rename (const std::string& from, const std::string& to, std::string& msg)
505  {
506  int status = -1;
507 
508  msg = "";
509 
510  status = std::rename (from.c_str (), to.c_str ());
511 
512  if (status < 0)
513  msg = std::strerror (errno);
514 
515  return status;
516  }
517 
518  int rmdir (const std::string& name)
519  {
520  std::string msg;
521  return rmdir (name, msg);
522  }
523 
524  int rmdir (const std::string& name, std::string& msg)
525  {
526  msg = "";
527 
528  int status = -1;
529 
530  status = octave_rmdir_wrapper (name.c_str ());
531 
532  if (status < 0)
533  msg = std::strerror (errno);
534 
535  return status;
536  }
537 
538  // And a version that works recursively.
539 
541  {
542  std::string msg;
543  return recursive_rmdir (name, msg);
544  }
545 
547  {
548  msg = "";
549 
550  int status = 0;
551 
552  dir_entry dir (name);
553 
554  if (dir)
555  {
556  string_vector dirlist = dir.read ();
557 
558  for (octave_idx_type i = 0; i < dirlist.numel (); i++)
559  {
560  octave_quit ();
561 
562  std::string nm = dirlist[i];
563 
564  // Skip current directory and parent.
565  if (nm == "." || nm == "..")
566  continue;
567 
568  std::string fullnm = name + file_ops::dir_sep_str () + nm;
569 
570  // Get info about the file. Don't follow links.
571  file_stat fs (fullnm, false);
572 
573  if (fs)
574  {
575  if (fs.is_dir ())
576  {
577  status = recursive_rmdir (fullnm, msg);
578 
579  if (status < 0)
580  break;
581  }
582  else
583  {
584  status = unlink (fullnm, msg);
585 
586  if (status < 0)
587  break;
588  }
589  }
590  else
591  {
592  msg = fs.error ();
593  break;
594  }
595  }
596 
597  if (status >= 0)
598  {
599  dir.close ();
600  status = rmdir (name, msg);
601  }
602  }
603  else
604  {
605  status = -1;
606 
607  msg = dir.error ();
608  }
609 
610  return status;
611  }
612 
613  int umask (mode_t mode)
614  {
615  return octave_umask_wrapper (mode);
616  }
617 
618  int unlink (const std::string& name)
619  {
620  std::string msg;
621  return unlink (name, msg);
622  }
623 
624  int unlink (const std::string& name, std::string& msg)
625  {
626  msg = "";
627 
628  int status = -1;
629 
630  status = octave_unlink_wrapper (name.c_str ());
631 
632  if (status < 0)
633  msg = std::strerror (errno);
634 
635  return status;
636  }
637 
638  std::string tempnam (const std::string& dir, const std::string& pfx)
639  {
640  std::string msg;
641  return tempnam (dir, pfx, msg);
642  }
643 
644  std::string tempnam (const std::string& dir, const std::string& pfx,
645  std::string& msg)
646  {
647  msg = "";
648 
650 
651  // get dir path to use for template
652  std::string templatename;
653  if (dir.empty ())
654  templatename = env::get_temp_directory ();
655  else if (! file_stat (dir, false).is_dir ())
656  templatename = env::get_temp_directory ();
657  else
658  templatename = dir;
659 
660  // add dir sep char if it is not there
661  if (*templatename.rbegin () != file_ops::dir_sep_char ())
662  templatename += file_ops::dir_sep_char ();
663 
664  if (pfx.empty ())
665  templatename += "file";
666  else
667  templatename += pfx;
668 
669  // add the required XXXXXX for the template
670  templatename += "XXXXXX";
671 
672  // create and copy template to char array for call to gen_tempname
673  char tname [templatename.length () + 1];
674 
675  strcpy (tname, templatename.c_str ());
676 
677  if (octave_gen_tempname_wrapper (tname) == -1)
678  msg = std::strerror (errno);
679  else
680  retval = tname;
681 
682  return retval;
683  }
684 
686  {
687  std::string msg;
688  return canonicalize_file_name (name, msg);
689  }
690 
692  {
693  msg = "";
694 
696 
698 
699  if (tmp)
700  {
701  retval = tmp;
702  free (tmp);
703  }
704 
705 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
706  // Canonical Windows file separator is backslash.
707  std::replace (retval.begin (), retval.end (), '/', '\\');
708 #endif
709 
710  if (retval.empty ())
711  msg = std::strerror (errno);
712 
713  return retval;
714  }
715  }
716 }
std::string error(void) const
Definition: file-stat.h:146
bool is_dev_sep(char c)
Definition: file-ops.cc:259
static password getpwnam(const std::string &nm)
Definition: oct-passwd.cc:154
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:124
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:685
fname
Definition: load-save.cc:767
int octave_link_wrapper(const char *nm1, const char *nm2)
std::string dir(void) const
Definition: oct-passwd.cc:96
int unlink(const std::string &name)
Definition: file-ops.cc:618
int octave_rmdir_wrapper(const char *nm)
std::string dir_sep_chars(void)
Definition: file-ops.cc:242
int symlink(const std::string &old_name, const std::string &new_name)
Definition: file-ops.cc:451
Return the CPU time used by your Octave session The first output is the total time spent executing your process and is equal to the sum of second and third which are the number of CPU seconds spent executing in user mode and the number of CPU seconds spent executing in system mode
Definition: data.cc:6348
std::string tempnam(const std::string &dir, const std::string &pfx)
Definition: file-ops.cc:638
static size_t tilde_find_suffix(const std::string &s)
Definition: file-ops.cc:102
std::string tail(const std::string &path)
Definition: file-ops.cc:360
std::string tilde_expand(const std::string &name)
Definition: file-ops.cc:276
std::string native_separator_path(const std::string &path)
Definition: file-ops.cc:372
char dir_sep_char(void)
Definition: file-ops.cc:224
std::string filename
Definition: urlwrite.cc:121
std::string dirname(const std::string &path)
Definition: file-ops.cc:353
string_vector tilde_additional_prefixes
Definition: file-ops.cc:255
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
Definition: dir-ops.h:36
s
Definition: file-io.cc:2729
tilde_expansion_hook tilde_expansion_failure_hook
Definition: file-ops.cc:253
bool is_dir(void) const
Definition: file-stat.cc:57
int octave_gen_tempname_wrapper(char *tmpl)
std::string dir_sep_str(void)
Definition: file-ops.cc:233
int recursive_rmdir(const std::string &name)
Definition: file-ops.cc:540
int rename(const std::string &from, const std::string &to)
Definition: file-ops.cc:498
string_vector read(void)
Definition: dir-ops.cc:70
int octave_symlink_wrapper(const char *nm1, const char *nm2)
string_vector tilde_additional_suffixes
Definition: file-ops.cc:257
std::string concat(const std::string &dir, const std::string &file)
Definition: file-ops.cc:344
nd deftypefn *std::string name
Definition: sysdep.cc:647
bool is_dir_sep(char c)
Definition: file-ops.cc:270
OCTAVE_EXPORT octave_value_list isdir nd deftypefn *std::string nm
Definition: utils.cc:975
static std::string get_home_directory(void)
Definition: oct-env.cc:143
static const char * default_suffixes[]
Definition: file-ops.cc:64
static std::string get_temp_directory(void)
Definition: oct-env.cc:150
int octave_unlink_wrapper(const char *nm)
int link(const std::string &old_name, const std::string &new_name)
Definition: file-ops.cc:430
static const char * default_prefixes[]
Definition: file-ops.cc:59
static size_t tilde_find_prefix(const std::string &s, size_t &len)
Definition: file-ops.cc:67
static std::string tilde_expand_word(const std::string &filename)
Definition: file-ops.cc:149
char * octave_canonicalize_file_name_wrapper(const char *name)
double tmp
Definition: data.cc:6252
octave_value retval
Definition: data.cc:6246
int octave_umask_wrapper(mode_t mode)
Definition: stat-wrappers.c:52
static std::string isolate_tilde_prefix(const std::string &fname)
Definition: file-ops.cc:133
bool empty(void) const
Definition: str-vec.h:79
With real return the complex result
Definition: data.cc:3260
int umask(mode_t mode)
Definition: file-ops.cc:613
tilde_expansion_hook tilde_expansion_preexpansion_hook
Definition: file-ops.cc:251
int mkdir(const std::string &nm, mode_t md)
Definition: file-ops.cc:394
int rmdir(const std::string &name)
Definition: file-ops.cc:518
octave::sys::time start
Definition: graphics.cc:12337
int octave_mkfifo_wrapper(const char *name, mode_t mode)
Definition: stat-wrappers.c:46
std::string(* tilde_expansion_hook)(const std::string &)
Definition: file-ops.h:40
std::string error(void) const
Definition: dir-ops.h:77
int readlink(const std::string &path, std::string &result)
Definition: file-ops.cc:472
octave::sys::file_stat fs(filename)
for i
Definition: data.cc:5264
int octave_mkdir_wrapper(const char *name, mode_t mode)
Definition: stat-wrappers.c:40
int rename(const std::string &from, const std::string &to, std::string &msg)
Definition: file-ops.cc:504
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:366
octave_idx_type length(void) const
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
char dev_sep_char(void)
Definition: file-ops.cc:215
octave_idx_type length(void) const
Number of elements in the array.
Definition: Array.h:357
int mkfifo(const std::string &nm, mode_t md)
Definition: file-ops.cc:412
bool close(void)
Definition: dir-ops.cc:90