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 #ifdef HAVE_SYS_TYPES_H
00036 #include <sys/types.h>
00037 #endif
00038
00039 #ifdef HAVE_UNISTD_H
00040 #include <unistd.h>
00041 #endif
00042
00043 #include "file-ops.h"
00044 #include "oct-env.h"
00045 #include "oct-passwd.h"
00046 #include "pathlen.h"
00047 #include "statdefs.h"
00048 #include "str-vec.h"
00049
00050 #define NOT_SUPPORTED(nm) \
00051 nm ": not supported on this system"
00052
00053 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) \
00054 && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
00055 char file_ops::dir_sep_char = '\\';
00056 std::string file_ops::dir_sep_str ("\\");
00057 #else
00058 char file_ops::dir_sep_char = '/';
00059 std::string file_ops::dir_sep_str ("/");
00060 #endif
00061
00062 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) \
00063 && defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
00064 std::string file_ops::dir_sep_chars ("/\\");
00065 #else
00066 std::string file_ops::dir_sep_chars (file_ops::dir_sep_str);
00067 #endif
00068
00069
00070
00071 int
00072 file_ops::mkdir (const std::string& name, mode_t mode)
00073 {
00074 std::string msg;
00075 return mkdir (name, mode, msg);
00076 }
00077
00078 int
00079 file_ops::mkdir (const std::string& name, mode_t mode, std::string& msg)
00080 {
00081 msg = std::string ();
00082
00083 int status = -1;
00084
00085 #if defined (HAVE_MKDIR)
00086
00087 #if defined (MKDIR_TAKES_ONE_ARG)
00088 status = ::mkdir (name.c_str ());
00089 #else
00090 status = ::mkdir (name.c_str (), mode);
00091 #endif
00092
00093 if (status < 0)
00094 {
00095 using namespace std;
00096 msg = ::strerror (errno);
00097 }
00098 #else
00099 msg = NOT_SUPPORTED ("mkdir");
00100 #endif
00101
00102 return status;
00103 }
00104
00105
00106
00107 int
00108 file_ops::mkfifo (const std::string& name, mode_t mode)
00109 {
00110 std::string msg;
00111 return mkfifo (name, mode, msg);
00112 }
00113
00114 int
00115 file_ops::mkfifo (const std::string& name, mode_t mode, std::string& msg)
00116 {
00117 msg = std::string ();
00118
00119 int status = -1;
00120
00121 #if defined (HAVE_MKFIFO)
00122 status = ::mkfifo (name.c_str (), mode);
00123
00124 if (status < 0)
00125 {
00126 using namespace std;
00127 msg = ::strerror (errno);
00128 }
00129 #else
00130 msg = NOT_SUPPORTED ("mkfifo");
00131 #endif
00132
00133 return status;
00134 }
00135
00136
00137
00138 int
00139 file_ops::link (const std::string& old_name, const std::string& new_name)
00140 {
00141 std::string msg;
00142 return link (old_name, new_name, msg);
00143 }
00144
00145 int
00146 file_ops::link (const std::string& old_name,
00147 const std::string& new_name, std::string& msg)
00148 {
00149 msg = std::string ();
00150
00151 int status = -1;
00152
00153 #if defined (HAVE_LINK)
00154 status = ::link (old_name.c_str (), new_name.c_str ());
00155
00156 if (status < 0)
00157 {
00158 using namespace std;
00159 msg = ::strerror (errno);
00160 }
00161 #else
00162 msg = NOT_SUPPORTED ("link");
00163 #endif
00164
00165 return status;
00166 }
00167
00168
00169
00170 int
00171 file_ops::symlink (const std::string& old_name, const std::string& new_name)
00172 {
00173 std::string msg;
00174 return symlink (old_name, new_name, msg);
00175 }
00176
00177 int
00178 file_ops::symlink (const std::string& old_name,
00179 const std::string& new_name, std::string& msg)
00180 {
00181 msg = std::string ();
00182
00183 int status = -1;
00184
00185 #if defined (HAVE_SYMLINK)
00186
00187 OCTAVE_LOCAL_BUFFER (char, old_nm, old_name.length ());
00188 OCTAVE_LOCAL_BUFFER (char, new_nm, new_name.length ());
00189
00190 strcpy (old_nm, old_name.c_str ());
00191 strcpy (new_nm, new_name.c_str ());
00192
00193 status = ::symlink (old_nm, new_nm);
00194
00195 if (status < 0)
00196 {
00197 using namespace std;
00198 msg = ::strerror (errno);
00199 }
00200 #else
00201 msg = NOT_SUPPORTED ("symlink");
00202 #endif
00203
00204 return status;
00205 }
00206
00207
00208
00209 int
00210 file_ops::readlink (const std::string& path, std::string& result)
00211 {
00212 std::string msg;
00213 return readlink (path, result, msg);
00214 }
00215
00216 int
00217 file_ops::readlink (const std::string& path, std::string& result,
00218 std::string& msg)
00219 {
00220 int status = -1;
00221
00222 msg = std::string ();
00223
00224 #if defined (HAVE_READLINK)
00225 char buf[MAXPATHLEN+1];
00226
00227 OCTAVE_LOCAL_BUFFER (char, p, path.length ());
00228
00229 strcpy (p, path.c_str ());
00230
00231 status = ::readlink (p, buf, MAXPATHLEN);
00232
00233 if (status < 0)
00234 {
00235 using namespace std;
00236 msg = ::strerror (errno);
00237 }
00238 else
00239 {
00240 buf[status] = '\0';
00241 result = std::string (buf);
00242 status = 0;
00243 }
00244 #else
00245 msg = NOT_SUPPORTED ("rename");
00246 #endif
00247
00248 return status;
00249 }
00250
00251
00252
00253 int
00254 file_ops::rename (const std::string& from, const std::string& to)
00255 {
00256 std::string msg;
00257 return rename (from, to, msg);
00258 }
00259
00260 int
00261 file_ops::rename (const std::string& from, const std::string& to,
00262 std::string& msg)
00263 {
00264 int status = -1;
00265
00266 msg = std::string ();
00267
00268 #if defined (HAVE_RENAME)
00269 status = ::rename (from.c_str (), to.c_str ());
00270
00271 if (status < 0)
00272 {
00273 using namespace std;
00274 msg = ::strerror (errno);
00275 }
00276 #else
00277 msg = NOT_SUPPORTED ("rename");
00278 #endif
00279
00280 return status;
00281 }
00282
00283
00284
00285 int
00286 file_ops::rmdir (const std::string& name)
00287 {
00288 std::string msg;
00289 return rmdir (name, msg);
00290 }
00291
00292 int
00293 file_ops::rmdir (const std::string& name, std::string& msg)
00294 {
00295 msg = std::string ();
00296
00297 int status = -1;
00298
00299 #if defined (HAVE_RMDIR)
00300 status = ::rmdir (name.c_str ());
00301
00302 if (status < 0)
00303 {
00304 using namespace std;
00305 msg = ::strerror (errno);
00306 }
00307 #else
00308 msg = NOT_SUPPORTED ("rmdir");
00309 #endif
00310
00311 return status;
00312 }
00313
00314
00315
00316 std::string
00317 file_ops::tempnam (const std::string& dir, const std::string& pfx)
00318 {
00319 std::string msg;
00320 return tempnam (dir, pfx, msg);
00321 }
00322
00323 std::string
00324 file_ops::tempnam (const std::string& dir, const std::string& pfx,
00325 std::string& msg)
00326 {
00327 msg = std::string ();
00328
00329 std::string retval;
00330
00331 const char *pdir = dir.empty () ? 0 : dir.c_str ();
00332
00333 const char *ppfx = pfx.empty () ? 0 : pfx.c_str ();
00334
00335 char *tmp = ::tempnam (pdir, ppfx);
00336
00337 if (tmp)
00338 {
00339 retval = tmp;
00340
00341 ::free (tmp);
00342 }
00343 else
00344 {
00345 using namespace std;
00346 msg = ::strerror (errno);
00347 }
00348
00349 return retval;
00350 }
00351
00352
00353
00354
00355
00356
00357
00358 static const char *default_prefixes[] = { " ~", "\t~", ":~", 0 };
00359
00360
00361
00362
00363 static const char *default_suffixes[] = { " ", "\n", ":", 0 };
00364
00365
00366
00367
00368
00369
00370 file_ops::tilde_expansion_hook file_ops::tilde_expansion_preexpansion_hook = 0;
00371
00372
00373
00374
00375
00376
00377 file_ops::tilde_expansion_hook file_ops::tilde_expansion_failure_hook = 0;
00378
00379
00380
00381
00382 string_vector file_ops::tilde_additional_prefixes = default_prefixes;
00383
00384
00385
00386
00387 string_vector file_ops::tilde_additional_suffixes = default_suffixes;
00388
00389
00390
00391
00392
00393
00394 static size_t
00395 tilde_find_prefix (const std::string& s, size_t& len)
00396 {
00397 len = 0;
00398
00399 size_t s_len = s.length ();
00400
00401 if (s_len == 0 || s[0] == '~')
00402 return 0;
00403
00404 string_vector prefixes = file_ops::tilde_additional_prefixes;
00405
00406 if (! prefixes.empty ())
00407 {
00408 for (size_t i = 0; i < s_len; i++)
00409 {
00410 for (int j = 0; j < prefixes.length (); j++)
00411 {
00412 size_t pfx_len = prefixes[j].length ();
00413
00414 if (prefixes[j].compare (s.substr (i, pfx_len)) == 0)
00415 {
00416 len = pfx_len - 1;
00417 return i + len;
00418 }
00419 }
00420 }
00421 }
00422
00423 return s_len;
00424 }
00425
00426
00427
00428
00429 static size_t
00430 tilde_find_suffix (const std::string& s)
00431 {
00432 size_t s_len = s.length ();
00433
00434 string_vector suffixes = file_ops::tilde_additional_suffixes;
00435
00436 size_t i = 0;
00437
00438 for ( ; i < s_len; i++)
00439 {
00440 if (s[i] == file_ops::dir_sep_char)
00441 break;
00442
00443 if (! suffixes.empty ())
00444 {
00445 for (int j = 0; j < suffixes.length (); j++)
00446 {
00447 size_t sfx_len = suffixes[j].length ();
00448
00449 if (suffixes[j].compare (s.substr (i, sfx_len)) == 0)
00450 return i;
00451 }
00452 }
00453 }
00454
00455 return i;
00456 }
00457
00458
00459
00460 static std::string
00461 isolate_tilde_prefix (const std::string& fname)
00462 {
00463 size_t f_len = fname.length ();
00464
00465 size_t len = 1;
00466
00467 while (len < f_len && fname[len] != file_ops::dir_sep_char)
00468 len++;
00469
00470 return fname.substr (1, len);
00471 }
00472
00473
00474
00475
00476 static std::string
00477 tilde_expand_word (const std::string& filename)
00478 {
00479 size_t f_len = filename.length ();
00480
00481 if (f_len == 0 || filename[0] != '~')
00482 return filename;
00483
00484
00485
00486
00487
00488 if (f_len == 1 || filename[1] == file_ops::dir_sep_char)
00489 return octave_env::get_home_directory () + filename.substr (1);
00490
00491 std::string username = isolate_tilde_prefix (filename);
00492
00493 size_t user_len = username.length ();
00494
00495 std::string dirname;
00496
00497 if (file_ops::tilde_expansion_preexpansion_hook)
00498 {
00499 std::string expansion
00500 = file_ops::tilde_expansion_preexpansion_hook (username);
00501
00502 if (! expansion.empty ())
00503 return expansion + filename.substr (user_len+1);
00504 }
00505
00506
00507
00508
00509 octave_passwd pw = octave_passwd::getpwnam (username);
00510
00511 if (! pw)
00512 {
00513
00514
00515
00516 if (file_ops::tilde_expansion_failure_hook)
00517 {
00518 std::string expansion
00519 = file_ops::tilde_expansion_failure_hook (username);
00520
00521 if (! expansion.empty ())
00522 dirname = expansion + filename.substr (user_len+1);
00523 }
00524
00525
00526
00527
00528 if (dirname.length () == 0)
00529 dirname = filename;
00530 }
00531 else
00532 dirname = pw.dir () + filename.substr (user_len+1);
00533
00534 return dirname;
00535 }
00536
00537
00538
00539
00540 std::string
00541 file_ops::tilde_expand (const std::string& name)
00542 {
00543 std::string result;
00544
00545 size_t name_len = name.length ();
00546
00547
00548
00549 size_t pos = 0;
00550
00551 while (1)
00552 {
00553 if (pos > name_len)
00554 break;
00555
00556 size_t len;
00557
00558
00559
00560 size_t start = tilde_find_prefix (name.substr (pos), len);
00561
00562 result.append (name.substr (pos, start));
00563
00564
00565
00566 pos += start;
00567
00568
00569
00570
00571 size_t fini = tilde_find_suffix (name.substr (pos));
00572
00573
00574
00575 if (! (start || fini))
00576 break;
00577
00578
00579
00580 std::string tilde_word = name.substr (pos, fini);
00581
00582 pos += fini;
00583
00584 std::string expansion = tilde_expand_word (tilde_word);
00585
00586 result.append (expansion);
00587 }
00588
00589 return result;
00590 }
00591
00592
00593
00594 string_vector
00595 file_ops::tilde_expand (const string_vector& names)
00596 {
00597 string_vector retval;
00598
00599 int n = names.length ();
00600
00601 retval.resize (n);
00602
00603 for (int i = 0; i < n; i++)
00604 retval[i] = file_ops::tilde_expand (names[i]);
00605
00606 return retval;
00607 }
00608
00609 int
00610 file_ops::umask (mode_t mode)
00611 {
00612 #if defined (HAVE_UMASK)
00613 return ::umask (mode);
00614 #else
00615 return 0;
00616 #endif
00617 }
00618
00619 int
00620 file_ops::unlink (const std::string& name)
00621 {
00622 std::string msg;
00623 return unlink (name, msg);
00624 }
00625
00626 int
00627 file_ops::unlink (const std::string& name, std::string& msg)
00628 {
00629 msg = std::string ();
00630
00631 int status = -1;
00632
00633 #if defined (HAVE_UNLINK)
00634 status = ::unlink (name.c_str ());
00635
00636 if (status < 0)
00637 {
00638 using namespace std;
00639 msg = ::strerror (errno);
00640 }
00641 #else
00642 msg = NOT_SUPPORTED ("unlink");
00643 #endif
00644
00645 return status;
00646 }
00647
00648 bool
00649 file_ops::is_dir_sep (char c)
00650 {
00651 return dir_sep_chars.find (c) != NPOS;
00652 }
00653
00654
00655
00656
00657
00658