00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #include <cerrno>
00028 #include <cstdio>
00029 #include <cstdlib>
00030 #include <cstring>
00031
00032 #include <iostream>
00033 #include <vector>
00034
00035 #include <sys/stat.h>
00036 #include <sys/types.h>
00037 #include <unistd.h>
00038
00039 #include "pathmax.h"
00040
00041 #include "dir-ops.h"
00042 #include "file-ops.h"
00043 #include "file-stat.h"
00044 #include "oct-env.h"
00045 #include "oct-locbuf.h"
00046 #include "oct-passwd.h"
00047 #include "pathlen.h"
00048 #include "quit.h"
00049 #include "singleton-cleanup.h"
00050 #include "str-vec.h"
00051
00052 file_ops *file_ops::instance = 0;
00053
00054 bool
00055 file_ops::instance_ok (void)
00056 {
00057 bool retval = true;
00058
00059 if (! instance)
00060 {
00061 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
00062 char system_dir_sep_char = '\\';
00063 std::string system_dir_sep_str = "\\";
00064 #else
00065 char system_dir_sep_char = '/';
00066 std::string system_dir_sep_str = "/";
00067 #endif
00068 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
00069 std::string system_dir_sep_chars = "/\\";
00070 #else
00071 std::string system_dir_sep_chars = system_dir_sep_str;
00072 #endif
00073
00074 instance = new file_ops (system_dir_sep_char, system_dir_sep_str,
00075 system_dir_sep_chars);
00076
00077 if (instance)
00078 singleton_cleanup_list::add (cleanup_instance);
00079 }
00080
00081 if (! instance)
00082 {
00083 (*current_liboctave_error_handler)
00084 ("unable to create file_ops object!");
00085
00086 retval = false;
00087 }
00088
00089 return retval;
00090 }
00091
00092
00093
00094
00095
00096
00097
00098 static const char *default_prefixes[] = { " ~", "\t~", ":~", 0 };
00099
00100
00101
00102
00103 static const char *default_suffixes[] = { " ", "\n", ":", 0 };
00104
00105
00106
00107
00108
00109
00110 file_ops::tilde_expansion_hook file_ops::tilde_expansion_preexpansion_hook = 0;
00111
00112
00113
00114
00115
00116
00117 file_ops::tilde_expansion_hook file_ops::tilde_expansion_failure_hook = 0;
00118
00119
00120
00121
00122 string_vector file_ops::tilde_additional_prefixes = default_prefixes;
00123
00124
00125
00126
00127 string_vector file_ops::tilde_additional_suffixes = default_suffixes;
00128
00129
00130
00131
00132
00133
00134 static size_t
00135 tilde_find_prefix (const std::string& s, size_t& len)
00136 {
00137 len = 0;
00138
00139 size_t s_len = s.length ();
00140
00141 if (s_len == 0 || s[0] == '~')
00142 return 0;
00143
00144 string_vector prefixes = file_ops::tilde_additional_prefixes;
00145
00146 if (! prefixes.empty ())
00147 {
00148 for (size_t i = 0; i < s_len; i++)
00149 {
00150 for (int j = 0; j < prefixes.length (); j++)
00151 {
00152 size_t pfx_len = prefixes[j].length ();
00153
00154 if (prefixes[j].compare (s.substr (i, pfx_len)) == 0)
00155 {
00156 len = pfx_len - 1;
00157 return i + len;
00158 }
00159 }
00160 }
00161 }
00162
00163 return s_len;
00164 }
00165
00166
00167
00168
00169 static size_t
00170 tilde_find_suffix (const std::string& s)
00171 {
00172 size_t s_len = s.length ();
00173
00174 string_vector suffixes = file_ops::tilde_additional_suffixes;
00175
00176 size_t i = 0;
00177
00178 for ( ; i < s_len; i++)
00179 {
00180 if (file_ops::is_dir_sep (s[i]))
00181 break;
00182
00183 if (! suffixes.empty ())
00184 {
00185 for (int j = 0; j < suffixes.length (); j++)
00186 {
00187 size_t sfx_len = suffixes[j].length ();
00188
00189 if (suffixes[j].compare (s.substr (i, sfx_len)) == 0)
00190 return i;
00191 }
00192 }
00193 }
00194
00195 return i;
00196 }
00197
00198
00199
00200 static std::string
00201 isolate_tilde_prefix (const std::string& fname)
00202 {
00203 size_t f_len = fname.length ();
00204
00205 size_t len = 1;
00206
00207 while (len < f_len && ! file_ops::is_dir_sep (fname[len]))
00208 len++;
00209
00210 return fname.substr (1, len);
00211 }
00212
00213
00214
00215
00216 static std::string
00217 tilde_expand_word (const std::string& filename)
00218 {
00219 size_t f_len = filename.length ();
00220
00221 if (f_len == 0 || filename[0] != '~')
00222 return filename;
00223
00224
00225
00226
00227
00228 if (f_len == 1 || file_ops::is_dir_sep (filename[1]))
00229 return octave_env::get_home_directory () + filename.substr (1);
00230
00231 std::string username = isolate_tilde_prefix (filename);
00232
00233 size_t user_len = username.length ();
00234
00235 std::string dirname;
00236
00237 if (file_ops::tilde_expansion_preexpansion_hook)
00238 {
00239 std::string expansion
00240 = file_ops::tilde_expansion_preexpansion_hook (username);
00241
00242 if (! expansion.empty ())
00243 return expansion + filename.substr (user_len+1);
00244 }
00245
00246
00247
00248
00249 octave_passwd pw = octave_passwd::getpwnam (username);
00250
00251 if (! pw)
00252 {
00253
00254
00255
00256 if (file_ops::tilde_expansion_failure_hook)
00257 {
00258 std::string expansion
00259 = file_ops::tilde_expansion_failure_hook (username);
00260
00261 if (! expansion.empty ())
00262 dirname = expansion + filename.substr (user_len+1);
00263 }
00264
00265
00266
00267
00268 if (dirname.length () == 0)
00269 dirname = filename;
00270 }
00271 else
00272 dirname = pw.dir () + filename.substr (user_len+1);
00273
00274 return dirname;
00275 }
00276
00277
00278
00279
00280 std::string
00281 file_ops::tilde_expand (const std::string& name)
00282 {
00283 if (name.find ('~') == std::string::npos)
00284 return name;
00285 else
00286 {
00287 std::string result;
00288
00289 size_t name_len = name.length ();
00290
00291
00292
00293 size_t pos = 0;
00294
00295 while (1)
00296 {
00297 if (pos > name_len)
00298 break;
00299
00300 size_t len;
00301
00302
00303
00304 size_t start = tilde_find_prefix (name.substr (pos), len);
00305
00306 result.append (name.substr (pos, start));
00307
00308
00309
00310 pos += start;
00311
00312
00313
00314
00315 size_t fini = tilde_find_suffix (name.substr (pos));
00316
00317
00318
00319 if (! (start || fini))
00320 break;
00321
00322
00323
00324 std::string tilde_word = name.substr (pos, fini);
00325
00326 pos += fini;
00327
00328 std::string expansion = tilde_expand_word (tilde_word);
00329
00330 result.append (expansion);
00331 }
00332
00333 return result;
00334 }
00335 }
00336
00337
00338
00339 string_vector
00340 file_ops::tilde_expand (const string_vector& names)
00341 {
00342 string_vector retval;
00343
00344 int n = names.length ();
00345
00346 retval.resize (n);
00347
00348 for (int i = 0; i < n; i++)
00349 retval[i] = tilde_expand (names[i]);
00350
00351 return retval;
00352 }
00353
00354 std::string
00355 file_ops::concat (const std::string& dir, const std::string& file)
00356 {
00357 return dir.empty ()
00358 ? file
00359 : (is_dir_sep (dir[dir.length()-1])
00360 ? dir + file
00361 : dir + dir_sep_char () + file);
00362 }
00363
00364
00365 int
00366 octave_mkdir (const std::string& nm, mode_t md)
00367 {
00368 std::string msg;
00369 return octave_mkdir (nm, md, msg);
00370 }
00371
00372 int
00373 octave_mkdir (const std::string& name, mode_t mode, std::string& msg)
00374 {
00375 msg = std::string ();
00376
00377 int status = -1;
00378
00379 status = gnulib::mkdir (name.c_str (), mode);
00380
00381 if (status < 0)
00382 msg = gnulib::strerror (errno);
00383
00384 return status;
00385 }
00386
00387 int
00388 octave_mkfifo (const std::string& nm, mode_t md)
00389 {
00390 std::string msg;
00391 return octave_mkfifo (nm, md, msg);
00392 }
00393
00394 int
00395 octave_mkfifo (const std::string& name, mode_t mode, std::string& msg)
00396 {
00397 msg = std::string ();
00398
00399 int status = -1;
00400
00401
00402
00403
00404
00405 status = gnulib::mkfifo (name.c_str (), mode);
00406
00407 if (status < 0)
00408 msg = gnulib::strerror (errno);
00409
00410 return status;
00411 }
00412
00413 int
00414 octave_link (const std::string& old_name, const std::string& new_name)
00415 {
00416 std::string msg;
00417 return octave_link (old_name, new_name, msg);
00418 }
00419
00420 int
00421 octave_link (const std::string& old_name,
00422 const std::string& new_name, std::string& msg)
00423 {
00424 msg = std::string ();
00425
00426 int status = -1;
00427
00428 status = gnulib::link (old_name.c_str (), new_name.c_str ());
00429
00430 if (status < 0)
00431 msg = gnulib::strerror (errno);
00432
00433 return status;
00434 }
00435
00436 int
00437 octave_symlink (const std::string& old_name, const std::string& new_name)
00438 {
00439 std::string msg;
00440 return octave_symlink (old_name, new_name, msg);
00441 }
00442
00443 int
00444 octave_symlink (const std::string& old_name,
00445 const std::string& new_name, std::string& msg)
00446 {
00447 msg = std::string ();
00448
00449 int status = -1;
00450
00451 status = gnulib::symlink (old_name.c_str (), new_name.c_str ());
00452
00453 if (status < 0)
00454 msg = gnulib::strerror (errno);
00455
00456 return status;
00457 }
00458
00459 int
00460 octave_readlink (const std::string& path, std::string& result)
00461 {
00462 std::string msg;
00463 return octave_readlink (path, result, msg);
00464 }
00465
00466 int
00467 octave_readlink (const std::string& path, std::string& result,
00468 std::string& msg)
00469 {
00470 int status = -1;
00471
00472 msg = std::string ();
00473
00474 char buf[MAXPATHLEN+1];
00475
00476 status = gnulib::readlink (path.c_str (), buf, MAXPATHLEN);
00477
00478 if (status < 0)
00479 msg = gnulib::strerror (errno);
00480 else
00481 {
00482 buf[status] = '\0';
00483 result = std::string (buf);
00484 status = 0;
00485 }
00486
00487 return status;
00488 }
00489
00490 int
00491 octave_rename (const std::string& from, const std::string& to)
00492 {
00493 std::string msg;
00494 return octave_rename (from, to, msg);
00495 }
00496
00497 int
00498 octave_rename (const std::string& from, const std::string& to,
00499 std::string& msg)
00500 {
00501 int status = -1;
00502
00503 msg = std::string ();
00504
00505 status = gnulib::rename (from.c_str (), to.c_str ());
00506
00507 if (status < 0)
00508 msg = gnulib::strerror (errno);
00509
00510 return status;
00511 }
00512
00513 int
00514 octave_rmdir (const std::string& name)
00515 {
00516 std::string msg;
00517 return octave_rmdir (name, msg);
00518 }
00519
00520 int
00521 octave_rmdir (const std::string& name, std::string& msg)
00522 {
00523 msg = std::string ();
00524
00525 int status = -1;
00526
00527 status = gnulib::rmdir (name.c_str ());
00528
00529 if (status < 0)
00530 msg = gnulib::strerror (errno);
00531
00532 return status;
00533 }
00534
00535
00536
00537 int
00538 octave_recursive_rmdir (const std::string& name)
00539 {
00540 std::string msg;
00541 return octave_recursive_rmdir (name, msg);
00542 }
00543
00544 int
00545 octave_recursive_rmdir (const std::string& name, std::string& msg)
00546 {
00547 msg = std::string ();
00548
00549 int status = 0;
00550
00551 dir_entry dir (name);
00552
00553 if (dir)
00554 {
00555 string_vector dirlist = dir.read ();
00556
00557 for (octave_idx_type i = 0; i < dirlist.length (); i++)
00558 {
00559 octave_quit ();
00560
00561 std::string nm = dirlist[i];
00562
00563
00564 if (nm == "." || nm == "..")
00565 continue;
00566
00567 std::string fullnm = name + file_ops::dir_sep_str () + nm;
00568
00569
00570 file_stat fs (fullnm, false);
00571
00572 if (fs)
00573 {
00574 if (fs.is_dir ())
00575 {
00576 status = octave_recursive_rmdir (fullnm, msg);
00577
00578 if (status < 0)
00579 break;
00580 }
00581 else
00582 {
00583 status = octave_unlink (fullnm, msg);
00584
00585 if (status < 0)
00586 break;
00587 }
00588 }
00589 else
00590 {
00591 msg = fs.error ();
00592 break;
00593 }
00594 }
00595
00596 if (status >= 0)
00597 {
00598 dir.close ();
00599 status = octave_rmdir (name, msg);
00600 }
00601 }
00602 else
00603 {
00604 status = -1;
00605
00606 msg = dir.error ();
00607 }
00608
00609 return status;
00610 }
00611
00612 int
00613 octave_umask (mode_t mode)
00614 {
00615 #if defined (HAVE_UMASK)
00616 return umask (mode);
00617 #else
00618 return 0;
00619 #endif
00620 }
00621
00622 int
00623 octave_unlink (const std::string& name)
00624 {
00625 std::string msg;
00626 return octave_unlink (name, msg);
00627 }
00628
00629 int
00630 octave_unlink (const std::string& name, std::string& msg)
00631 {
00632 msg = std::string ();
00633
00634 int status = -1;
00635
00636 status = gnulib::unlink (name.c_str ());
00637
00638 if (status < 0)
00639 msg = gnulib::strerror (errno);
00640
00641 return status;
00642 }
00643
00644 std::string
00645 octave_tempnam (const std::string& dir, const std::string& pfx)
00646 {
00647 std::string msg;
00648 return octave_tempnam (dir, pfx, msg);
00649 }
00650
00651 std::string
00652 octave_tempnam (const std::string& dir, const std::string& pfx,
00653 std::string& msg)
00654 {
00655 msg = std::string ();
00656
00657 std::string retval;
00658
00659 const char *pdir = dir.empty () ? 0 : dir.c_str ();
00660
00661 const char *ppfx = pfx.empty () ? 0 : pfx.c_str ();
00662
00663 char *tmp = tempnam (pdir, ppfx);
00664
00665 if (tmp)
00666 {
00667 retval = tmp;
00668
00669 free (tmp);
00670 }
00671 else
00672 msg = gnulib::strerror (errno);
00673
00674 return retval;
00675 }
00676
00677 std::string
00678 octave_canonicalize_file_name (const std::string& name)
00679 {
00680 std::string msg;
00681 return octave_canonicalize_file_name (name, msg);
00682 }
00683
00684 std::string
00685 octave_canonicalize_file_name (const std::string& name, std::string& msg)
00686 {
00687 msg = std::string ();
00688
00689 std::string retval;
00690
00691 #if defined (HAVE_CANONICALIZE_FILE_NAME)
00692
00693 char *tmp = gnulib::canonicalize_file_name (name.c_str ());
00694
00695 if (tmp)
00696 {
00697 retval = tmp;
00698 free (tmp);
00699 }
00700
00701 #elif defined (HAVE_RESOLVEPATH)
00702
00703 #if !defined (errno)
00704 extern int errno;
00705 #endif
00706
00707 #if !defined (__set_errno)
00708 # define __set_errno(Val) errno = (Val)
00709 #endif
00710
00711 if (name.empty ())
00712 {
00713 __set_errno (ENOENT);
00714 return retval;
00715 }
00716
00717
00718
00719
00720
00721 std::string absolute_name = octave_env::make_absolute (name);
00722
00723 size_t resolved_size = absolute_name.length ();
00724
00725 while (true)
00726 {
00727 resolved_size = 2 * resolved_size + 1;
00728
00729 OCTAVE_LOCAL_BUFFER (char, resolved, resolved_size);
00730
00731 int resolved_len
00732 = resolvepath (absolute_name.c_str (), resolved, resolved_size);
00733
00734 if (resolved_len < 0)
00735 break;
00736
00737 if (resolved_len < resolved_size)
00738 {
00739 retval = resolved;
00740 break;
00741 }
00742 }
00743
00744 #elif defined (__WIN32__)
00745
00746 int n = 1024;
00747
00748 std::string win_path (n, '\0');
00749
00750 while (true)
00751 {
00752 int status = GetFullPathName (name.c_str (), n, &win_path[0], 0);
00753
00754 if (status == 0)
00755 break;
00756 else if (status < n)
00757 {
00758 win_path.resize (status);
00759 retval = win_path;
00760 break;
00761 }
00762 else
00763 {
00764 n *= 2;
00765 win_path.resize (n);
00766 }
00767 }
00768
00769 #elif defined (HAVE_REALPATH)
00770
00771 #if !defined (__set_errno)
00772 # define __set_errno(Val) errno = (Val)
00773 #endif
00774
00775 if (name.empty ())
00776 {
00777 __set_errno (ENOENT);
00778 return retval;
00779 }
00780
00781 OCTAVE_LOCAL_BUFFER (char, buf, PATH_MAX);
00782
00783 if (::realpath (name.c_str (), buf))
00784 retval = buf;
00785
00786 #else
00787
00788
00789 retval = name;
00790
00791 #endif
00792
00793 if (retval.empty ())
00794 msg = gnulib::strerror (errno);
00795
00796 return retval;
00797 }
00798