37 #define GLOB_NOMATCH -3
51 #if defined(__ANDROID__) && !defined(PHAVE_LOCKF)
61 TextEncoder::Encoding Filename::_filesystem_encoding = TextEncoder::E_utf8;
63 TVOLATILE AtomicAdjust::Pointer Filename::_home_directory;
64 TVOLATILE AtomicAdjust::Pointer Filename::_temp_directory;
65 TVOLATILE AtomicAdjust::Pointer Filename::_user_appdata_directory;
66 TVOLATILE AtomicAdjust::Pointer Filename::_common_appdata_directory;
70 string Filename::_internal_data_dir;
85 #ifndef FILE_ATTRIBUTE_DEVICE
86 #define FILE_ATTRIBUTE_DEVICE 0x00000040
94 extern "C" void cygwin_conv_to_win32_path(
const char *path,
char *win32);
95 extern "C" void cygwin_conv_to_posix_path(
const char *path,
char *posix);
122 static const char *hosts_prefix =
"/hosts/";
123 static size_t hosts_prefix_length = 7;
126 front_to_back_slash(
const string &str) {
129 for (si = result.begin(); si != result.end(); ++si) {
139 back_to_front_slash(
const string &str) {
142 for (si = result.begin(); si != result.end(); ++si) {
151 static const string &
153 static string *panda_root =
nullptr;
155 if (panda_root ==
nullptr) {
156 panda_root =
new string;
157 const char *envvar = getenv(
"PANDA_ROOT");
158 if (envvar !=
nullptr) {
159 (*panda_root) = front_to_back_slash(envvar);
166 if ((*panda_root).empty() || (*panda_root)[(*panda_root).length() - 1] !=
'\\') {
167 (*panda_root) +=
'\\';
171 return (*panda_root);
175 convert_pathname(
const string &unix_style_pathname) {
176 if (unix_style_pathname.empty()) {
191 string windows_pathname;
193 if (unix_style_pathname[0] !=
'/') {
197 windows_pathname = front_to_back_slash(unix_style_pathname);
199 }
else if (unix_style_pathname.length() >= 2 &&
200 isalpha(unix_style_pathname[1]) &&
201 (unix_style_pathname.length() == 2 || unix_style_pathname[2] ==
'/')) {
205 string remainder = unix_style_pathname.substr(2);
206 if (remainder.empty()) {
210 remainder = front_to_back_slash(remainder);
216 string(1, (
char)toupper(unix_style_pathname[1])) +
":" + remainder;
218 }
else if (unix_style_pathname.length() > hosts_prefix_length &&
219 unix_style_pathname.substr(0, hosts_prefix_length) == hosts_prefix) {
221 windows_pathname =
"\\\\" + front_to_back_slash(unix_style_pathname.substr(hosts_prefix_length));
228 char result[4096] =
"";
229 cygwin_conv_to_win32_path(unix_style_pathname.c_str(), result);
230 windows_pathname = result;
234 windows_pathname = get_panda_root();
235 windows_pathname += front_to_back_slash(unix_style_pathname.substr(1));
237 #endif // HAVE_CYGWIN
240 return windows_pathname;
244 convert_dso_pathname(
const string &unix_style_pathname) {
246 size_t dot = unix_style_pathname.rfind(
'.');
247 if (dot == string::npos ||
248 unix_style_pathname.find(
'/', dot) != string::npos) {
250 return convert_pathname(unix_style_pathname);
252 if (unix_style_pathname.substr(dot) !=
".so") {
254 return convert_pathname(unix_style_pathname);
257 string dll_basename = unix_style_pathname.substr(0, dot);
270 return convert_pathname(dll_basename +
"_d.dll");
272 return convert_pathname(dll_basename +
".dll");
277 convert_executable_pathname(
const string &unix_style_pathname) {
279 size_t dot = unix_style_pathname.rfind(
'.');
280 if (dot == string::npos ||
281 unix_style_pathname.find(
'/', dot) != string::npos) {
283 return convert_pathname(unix_style_pathname +
".exe");
285 if (unix_style_pathname.substr(dot) !=
".exe") {
287 return convert_pathname(unix_style_pathname +
".exe");
290 return convert_pathname(unix_style_pathname);
300 if (dirname.empty()) {
303 _flags = basename._flags;
305 if (dirpath[dirpath.length() - 1] ==
'/') {
330 string result = back_to_front_slash(os_specific);
331 const string &panda_root = get_panda_root();
334 if (!panda_root.empty() && panda_root !=
string(
"\\") &&
335 panda_root.length() < result.length()) {
338 for (p = 0; p < panda_root.length() && matches; ++p) {
339 char c = tolower(panda_root[p]);
343 matches = (c == tolower(result[p]));
349 result = result.substr(panda_root.length());
350 assert(!result.empty());
351 if (result[0] !=
'/') {
352 result =
'/' + result;
362 if (result.size() >= 3 && isalpha(result[0]) &&
363 result[1] ==
':' && result[2] ==
'/') {
364 result[1] = tolower(result[0]);
369 if (result.size() == 3) {
370 result = result.substr(0, 2);
373 }
else if (result.substr(0, 2) ==
"//") {
375 result = hosts_prefix + result.substr(2);
424 temporary(
const string &dirname,
const string &prefix,
const string &suffix,
427 #if defined(_WIN32) || defined(ANDROID)
430 if (fdirname.empty()) {
435 if (fdirname.empty()) {
438 char *name = tempnam(
nullptr, prefix.c_str());
454 int hash = (clock() * time(
nullptr)) & 0xffffff;
457 sprintf_s(hex_code, 10,
"%06x", hash);
459 snprintf(hex_code, 10,
"%06x", hash);
463 }
while (result.
exists());
479 char *home = getenv(
"HOME");
480 if (home !=
nullptr) {
484 home_directory = dirname;
489 if (home_directory.empty()) {
491 wchar_t buffer[MAX_PATH];
494 if (SHGetSpecialFolderPathW(
nullptr, buffer, CSIDL_PERSONAL,
true)) {
498 home_directory = dirname;
503 #elif defined(ANDROID)
505 home_directory =
"/data/data/org.panda3d.sdk";
507 #elif defined(IS_OSX)
508 home_directory = get_osx_home_directory();
510 #elif defined(ANDROID)
511 home_directory = _internal_data_dir;
519 if (home_directory.empty()) {
527 assert(_home_directory !=
nullptr);
532 return (*(
Filename *)_home_directory);
544 static const size_t buffer_size = 4096;
545 wchar_t buffer[buffer_size];
546 if (GetTempPathW(buffer_size, buffer) != 0) {
550 temp_directory = dirname;
555 #elif defined(IS_OSX)
556 temp_directory = get_osx_temp_directory();
558 #elif defined(ANDROID)
564 temp_directory =
"/tmp";
567 if (temp_directory.empty()) {
575 assert(_temp_directory !=
nullptr);
580 return (*(
Filename *)_temp_directory);
594 wchar_t buffer[MAX_PATH];
596 if (SHGetSpecialFolderPathW(
nullptr, buffer, CSIDL_LOCAL_APPDATA,
true)) {
600 user_appdata_directory = dirname;
605 #elif defined(IS_OSX)
606 user_appdata_directory = get_osx_user_appdata_directory();
608 #elif defined(ANDROID)
609 user_appdata_directory.
set_dirname(_internal_data_dir);
615 const char *datadir = getenv(
"XDG_DATA_HOME");
616 if (datadir !=
nullptr && stat(datadir, &st) == 0 && S_ISDIR(st.st_mode)) {
617 user_appdata_directory = datadir;
624 if (user_appdata_directory.empty()) {
632 assert(_user_appdata_directory !=
nullptr);
637 return (*(
Filename *)_user_appdata_directory);
650 wchar_t buffer[MAX_PATH];
652 if (SHGetSpecialFolderPathW(
nullptr, buffer, CSIDL_COMMON_APPDATA,
true)) {
656 common_appdata_directory = dirname;
661 #elif defined(IS_OSX)
662 common_appdata_directory = get_osx_common_appdata_directory();
664 #elif defined(ANDROID)
665 common_appdata_directory.
set_dirname(_internal_data_dir);
668 #elif defined(__FreeBSD__)
669 common_appdata_directory =
"/usr/local/share";
671 common_appdata_directory =
"/usr/share";
674 if (common_appdata_directory.empty()) {
682 assert(_common_appdata_directory !=
nullptr);
687 return (*(
Filename *)_common_appdata_directory);
707 _filename.replace(0, _basename_start,
"");
709 int length_change = - ((int)_basename_start);
712 _basename_start += length_change;
713 _basename_end += length_change;
714 _extension_start += length_change;
721 if (s[s.length()-1] ==
'/') {
727 int length_change = (int)ss.length() - (int)_basename_start;
729 _filename.replace(0, _basename_start, ss);
731 _dirname_end = ss.length() - 1;
735 if (ss.length() == 1) {
739 _basename_start += length_change;
741 if (_basename_end != string::npos) {
742 _basename_end += length_change;
743 _extension_start += length_change;
755 _filename.replace(_basename_start, string::npos, s);
767 int length_change = (int)s.length() - (int)_basename_end;
769 _filename.replace(0, _basename_end, s);
771 if (_basename_end != string::npos) {
772 _basename_end += length_change;
773 _extension_start += length_change;
784 int length_change = (int)s.length() - (int)(_basename_end - _basename_start);
786 if (_basename_end == string::npos) {
787 _filename.replace(_basename_start, string::npos, s);
790 _filename.replace(_basename_start, _basename_end - _basename_start, s);
792 _basename_end += length_change;
793 _extension_start += length_change;
807 if (_basename_end != string::npos) {
808 _filename.replace(_basename_end, string::npos,
"");
809 _basename_end = string::npos;
810 _extension_start = string::npos;
813 }
else if (_basename_end == string::npos) {
815 _basename_end = _filename.length();
816 _extension_start = _filename.length() + 1;
817 _filename +=
'.' + s;
821 _filename.replace(_extension_start, string::npos, s);
839 if (_hash_end != _hash_start) {
840 std::ostringstream strm;
841 strm << _filename.substr(0, _hash_start)
842 << std::setw((
int)(_hash_end - _hash_start)) << std::setfill(
'0') << index
843 << _filename.substr(_hash_end);
857 _filename.replace(_hash_start, string::npos, s);
876 if (!_filename.empty() && _filename[0] ==
'/') {
880 while (p < _filename.length()) {
881 size_t q = _filename.find(
'/', p);
882 if (q == string::npos) {
883 components.push_back(_filename.substr(p));
886 components.push_back(_filename.substr(p, q - p));
891 components.push_back(
string());
901 assert(!_filename.empty());
902 if (_filename ==
".") {
907 vector_string components;
910 bool global = (_filename[0] ==
'/');
913 while (p < _filename.length() && _filename[p] ==
'/') {
916 while (p < _filename.length()) {
917 size_t slash = _filename.find(
'/', p);
918 string component = _filename.substr(p, slash - p);
919 if (component ==
"." && p != 0) {
921 }
else if (component ==
".." && !components.empty() &&
922 !(components.back() ==
"..")) {
923 if (components.back() ==
".") {
925 components.pop_back();
926 components.push_back(component);
929 components.pop_back();
932 components.push_back(component);
936 while (p < _filename.length() && _filename[p] ==
'/') {
946 if (!components.empty()) {
947 result += components[0];
948 for (
int i = 1; i < (int)components.size(); i++) {
949 result +=
"/" + components[i];
985 Filename new_filename(start_directory, _filename);
986 new_filename._flags = _flags;
987 (*this) = new_filename;
1024 char newpath [PATH_MAX + 1];
1025 if (realpath(c_str(), newpath) !=
nullptr) {
1027 newpath_fn._flags = _flags;
1028 (*this) = newpath_fn;
1033 if (!r_make_canonical(cwd)) {
1067 wchar_t short_name[MAX_PATH + 1];
1068 DWORD l = GetShortPathNameW(os_specific.c_str(), short_name, MAX_PATH + 1);
1077 assert(l < MAX_PATH + 1);
1079 wchar_t long_name[MAX_PATH + 1];
1080 l = GetLongPathNameW(short_name, long_name, MAX_PATH + 1);
1086 assert(l < MAX_PATH + 1);
1094 bool match = (orig_filename.length() == new_filename.length());
1095 for (
size_t i = 0; i < orig_filename.length() && match; ++i) {
1104 true_case._flags = _flags;
1105 (*this) = true_case;
1135 size_t dot = workname.rfind(
'.');
1136 if (dot != string::npos) {
1137 if (workname.substr(dot) ==
".so") {
1138 string dyLibBase = workname.substr(0, dot)+
".dylib";
1150 return convert_executable_pathname(standard.
get_fullpath());
1155 return standard.c_str();
1208 wchar_t short_name[MAX_PATH + 1];
1209 DWORD l = GetShortPathNameW(os_specific.c_str(), short_name, MAX_PATH + 1);
1218 assert(l < MAX_PATH + 1);
1242 wchar_t long_name[MAX_PATH + 1];
1243 DWORD l = GetLongPathNameW(os_specific.c_str(), long_name, MAX_PATH + 1);
1249 assert(l < MAX_PATH + 1);
1273 DWORD results = GetFileAttributesW(os_specific.c_str());
1274 if (results != -1) {
1281 struct stat this_buf;
1284 if (stat(os_specific.c_str(), &this_buf) == 0) {
1303 DWORD results = GetFileAttributesW(os_specific.c_str());
1304 if (results != -1) {
1305 isreg = ((results & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0);
1311 struct stat this_buf;
1314 if (stat(os_specific.c_str(), &this_buf) == 0) {
1315 isreg = S_ISREG(this_buf.st_mode);
1328 bool writable =
false;
1333 DWORD results = GetFileAttributesW(os_specific.c_str());
1334 if (results != -1) {
1335 if ((results & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1338 }
else if ((results & FILE_ATTRIBUTE_READONLY) == 0) {
1346 if (access(os_specific.c_str(), W_OK) == 0) {
1365 DWORD results = GetFileAttributesW(os_specific.c_str());
1366 if (results != -1) {
1367 isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
1372 struct stat this_buf;
1375 if (stat(os_specific.c_str(), &this_buf) == 0) {
1376 isdir = S_ISDIR(this_buf.st_mode);
1392 if (extension ==
"exe" || extension ==
"com") {
1398 if (access(os_specific.c_str(), X_OK) == 0) {
1418 bool this_missing_is_old,
1419 bool other_missing_is_old)
const {
1424 struct _stat this_buf;
1425 bool this_exists =
false;
1427 if (_wstat(os_specific.c_str(), &this_buf) == 0) {
1431 struct _stat other_buf;
1432 bool other_exists =
false;
1434 if (_wstat(other_os_specific.c_str(), &other_buf) == 0) {
1435 other_exists =
true;
1441 struct stat this_buf;
1442 bool this_exists =
false;
1444 if (stat(os_specific.c_str(), &this_buf) == 0) {
1448 struct stat other_buf;
1449 bool other_exists =
false;
1451 if (stat(other_os_specific.c_str(), &other_buf) == 0) {
1452 other_exists =
true;
1456 if (this_exists && other_exists) {
1458 return (
int)this_buf.st_mtime - (int)other_buf.st_mtime;
1460 }
else if (!this_exists && !other_exists) {
1462 if (this_missing_is_old == other_missing_is_old) {
1466 if (this_missing_is_old) {
1474 }
else if (!this_exists) {
1476 return this_missing_is_old ? -1 : 1;
1480 assert(!other_exists);
1483 return other_missing_is_old ? 1 : -1;
1501 struct _stat this_buf;
1503 if (_wstat(os_specific.c_str(), &this_buf) == 0) {
1504 return this_buf.st_mtime;
1509 struct stat this_buf;
1511 if (stat(os_specific.c_str(), &this_buf) == 0) {
1512 return this_buf.st_mtime;
1529 struct _stat this_buf;
1531 if (_wstat(os_specific.c_str(), &this_buf) == 0) {
1532 return this_buf.st_atime;
1537 struct stat this_buf;
1539 if (stat(os_specific.c_str(), &this_buf) == 0) {
1540 return this_buf.st_atime;
1555 struct _stat64 this_buf;
1559 if (_wstati64(os_specific.c_str(), &this_buf) == 0) {
1560 return this_buf.st_size;
1565 struct stat this_buf;
1567 if (stat(os_specific.c_str(), &this_buf) == 0) {
1568 return this_buf.st_size;
1582 const string &default_extension) {
1588 if (found.empty()) {
1591 if (
get_extension().empty() && !default_extension.empty()) {
1604 if (
get_extension().empty() && !default_extension.empty()) {
1614 if (!found.empty()) {
1641 if (_filename.empty() || directory.empty() ||
1642 _filename[0] !=
'/' || directory[0] !=
'/') {
1649 if (directory ==
"/") {
1656 size_t common = get_common_prefix(rel_to_file);
1663 int slashes = count_slashes(rel_to_file.substr(common));
1664 if (slashes > 0 && !allow_backups) {
1669 for (
int i = 0; i < slashes; i++) {
1672 result += _filename.substr(common);
1690 if (_filename.empty() || _filename[0] !=
'/') {
1695 for (
size_t i = 0; i < num_directories; ++i) {
1721 #if defined(WIN32_VC)
1724 size_t orig_size = contents.size();
1732 WIN32_FIND_DATAW find_data;
1734 HANDLE handle = FindFirstFileW(match.c_str(), &find_data);
1735 if (handle == INVALID_HANDLE_VALUE) {
1736 if (GetLastError() == ERROR_NO_MORE_FILES) {
1746 thread_consider_yield();
1747 wstring filename = find_data.cFileName;
1748 if (filename != L
"." && filename != L
"..") {
1750 contents.push_back(encoder.
get_text());
1752 }
while (FindNextFileW(handle, &find_data));
1754 bool scan_ok = (GetLastError() == ERROR_NO_MORE_FILES);
1757 sort(contents.begin() + orig_size, contents.end());
1760 #elif defined(PHAVE_DIRENT_H)
1763 size_t orig_size = contents.size();
1769 dirname = _filename;
1771 DIR *root = opendir(dirname.c_str());
1772 if (root ==
nullptr) {
1773 if (errno != ENOTDIR) {
1774 perror(dirname.c_str());
1781 while (d !=
nullptr) {
1782 thread_consider_yield();
1783 if (d->d_name[0] !=
'.') {
1784 contents.push_back(d->d_name);
1803 sort(contents.begin() + orig_size, contents.end());
1806 #elif defined(PHAVE_GLOB_H)
1814 }
else if (_filename[_filename.length() - 1] ==
'/') {
1815 dirname = _filename +
"*";
1817 dirname = _filename +
"/*";
1822 int r = glob(dirname.c_str(), GLOB_ERR,
nullptr, &globbuf);
1829 if (r != GLOB_NOMATCH) {
1830 perror(dirname.c_str());
1840 size_t offset = dirname.size() - 1;
1842 for (
int i = 0; globbuf.gl_pathv[i] !=
nullptr; i++) {
1843 contents.push_back(globbuf.gl_pathv[i] + offset);
1867 ios_openmode open_mode = ios::in;
1869 #ifdef HAVE_IOS_BINARY
1872 open_mode |= ios::binary;
1879 stream.open(os_specific.c_str(), open_mode);
1882 stream.open(os_specific.c_str(), open_mode);
1885 return (!stream.fail());
1903 ios_openmode open_mode = ios::out;
1906 open_mode |= ios::trunc;
1915 open_mode |= ios::in;
1919 #ifdef HAVE_IOS_BINARY
1922 open_mode |= ios::binary;
1932 stream.open(os_specific.c_str(), open_mode);
1934 return (!stream.fail());
1949 ios_openmode open_mode = ios::app;
1951 #ifdef HAVE_IOS_BINARY
1954 open_mode |= ios::binary;
1964 stream.open(os_specific.c_str(), open_mode);
1966 return (!stream.fail());
1981 ios_openmode open_mode = ios::out | ios::in;
1984 open_mode |= ios::trunc;
1993 #ifdef HAVE_IOS_BINARY
1996 open_mode |= ios::binary;
2006 stream.open(os_specific.c_str(), open_mode);
2008 return (!stream.fail());
2023 ios_openmode open_mode = ios::app | ios::in;
2025 #ifdef HAVE_IOS_BINARY
2028 open_mode |= ios::binary;
2038 stream.open(os_specific.c_str(), open_mode);
2040 return (!stream.fail());
2043 #ifdef USE_PANDAFILESTREAM
2056 ios_openmode open_mode = ios::in;
2058 #ifdef HAVE_IOS_BINARY
2061 open_mode |= ios::binary;
2067 stream.open(os_specific.c_str(), open_mode);
2068 return (!stream.fail());
2070 #endif // USE_PANDAFILESTREAM
2072 #ifdef USE_PANDAFILESTREAM
2084 open_write(pofstream &stream,
bool truncate)
const {
2088 ios_openmode open_mode = ios::out;
2091 open_mode |= ios::trunc;
2100 open_mode |= ios::in;
2104 #ifdef HAVE_IOS_BINARY
2107 open_mode |= ios::binary;
2113 stream.open(os_specific.c_str(), open_mode);
2115 return (!stream.fail());
2117 #endif // USE_PANDAFILESTREAM
2119 #ifdef USE_PANDAFILESTREAM
2132 ios_openmode open_mode = ios::app;
2134 #ifdef HAVE_IOS_BINARY
2137 open_mode |= ios::binary;
2143 stream.open(os_specific.c_str(), open_mode);
2145 return (!stream.fail());
2147 #endif // USE_PANDAFILESTREAM
2149 #ifdef USE_PANDAFILESTREAM
2162 ios_openmode open_mode = ios::out | ios::in;
2165 open_mode |= ios::trunc;
2174 #ifdef HAVE_IOS_BINARY
2177 open_mode |= ios::binary;
2183 stream.open(os_specific.c_str(), open_mode);
2185 return (!stream.fail());
2187 #endif // USE_PANDAFILESTREAM
2189 #ifdef USE_PANDAFILESTREAM
2202 ios_openmode open_mode = ios::app | ios::in;
2204 #ifdef HAVE_IOS_BINARY
2207 open_mode |= ios::binary;
2213 stream.open(os_specific.c_str(), open_mode);
2215 return (!stream.fail());
2217 #endif // USE_PANDAFILESTREAM
2233 fhandle = CreateFileW(os_specific.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
2234 nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
nullptr);
2235 if (fhandle == INVALID_HANDLE_VALUE) {
2242 GetSystemTime(&sysnow);
2243 if (!SystemTimeToFileTime(&sysnow, &ftnow)) {
2244 CloseHandle(fhandle);
2248 if (!SetFileTime(fhandle,
nullptr,
nullptr, &ftnow)) {
2249 CloseHandle(fhandle);
2253 CloseHandle(fhandle);
2256 #elif defined(PHAVE_UTIME_H)
2267 char result[4096] =
"";
2268 cygwin_conv_to_posix_path(os_specific.c_str(), result);
2269 os_specific = result;
2271 #endif // HAVE_CYGWIN
2272 int result = utime(os_specific.c_str(),
nullptr);
2274 if (errno == ENOENT) {
2276 int fd = creat(os_specific.c_str(), 0666);
2278 perror(os_specific.c_str());
2284 perror(os_specific.c_str());
2288 #else // WIN32, PHAVE_UTIME_H
2295 #endif // WIN32, PHAVE_UTIME_H
2306 return (_wchdir(os_specific.c_str()) >= 0);
2309 return (::
chdir(os_specific.c_str()) >= 0);
2324 _wchmod(os_specific.c_str(), 0644);
2325 return (_wunlink(os_specific.c_str()) == 0);
2328 return (::
unlink(os_specific.c_str()) == 0);
2342 if (*
this == other) {
2351 if (_wrename(os_specific.c_str(),
2352 other_os_specific.c_str()) == 0) {
2361 if (dirname.empty()) {
2366 if (!Filename::binary_filename(*this).
copy_to(temp)) {
2371 if (_wrename(temp_os_specific.c_str(),
2372 other_os_specific.c_str()) == 0) {
2380 if (_wrename(temp_os_specific.c_str(),
2381 other_os_specific.c_str()) == 0) {
2390 if (rename(os_specific.c_str(),
2391 other_os_specific.c_str()) == 0) {
2400 if (dirname.empty()) {
2405 if (!Filename::binary_filename(*this).
copy_to(temp)) {
2410 if (rename(temp_os_specific.c_str(),
2411 other_os_specific.c_str()) == 0) {
2419 if (rename(temp_os_specific.c_str(),
2420 other_os_specific.c_str()) == 0) {
2439 Filename this_filename = Filename::binary_filename(*
this);
2445 Filename other_filename = Filename::binary_filename(other);
2451 static const size_t buffer_size = 4096;
2452 char buffer[buffer_size];
2454 in.read(buffer, buffer_size);
2455 size_t count = in.gcount();
2456 while (count != 0) {
2457 out.write(buffer, count);
2462 in.read(buffer, buffer_size);
2463 count = in.gcount();
2490 if (_filename[_filename.length() - 1] ==
'/') {
2507 size_t slash = dirname.find(
'/');
2508 while (slash != string::npos) {
2509 Filename component(dirname.substr(0, slash));
2512 _wmkdir(os_specific.c_str());
2515 ::mkdir(os_specific.c_str(), 0777);
2517 slash = dirname.find(
'/', slash + 1);
2524 int result = _wmkdir(os_specific.c_str());
2527 int result =
::mkdir(os_specific.c_str(), 0777);
2530 return (result == 0);
2543 int result = _wmkdir(os_specific.c_str());
2546 int result =
::mkdir(os_specific.c_str(), 0777);
2549 return (result == 0);
2561 int result = _wrmdir(os_specific.c_str());
2565 _wchmod(os_specific.c_str(), 0777);
2566 result = _wrmdir(os_specific.c_str());
2571 int result =
::rmdir(os_specific.c_str());
2574 return (result == 0);
2583 static const int primes[] = {
2584 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
2585 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
2586 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
2587 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
2588 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
2589 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
2590 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
2591 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
2592 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
2593 467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
2594 547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
2595 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
2596 661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
2597 739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
2598 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
2599 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
2600 947, 953, 967, 971, 977, 983, 991, 997
2602 static const size_t num_primes =
sizeof(primes) /
sizeof(
int);
2605 for (
size_t i = 0; i < _filename.size(); ++i) {
2606 hash += (int)_filename[i] * primes[i % num_primes];
2643 const string &old_contents,
2644 const string &new_contents)
const {
2647 HANDLE hfile = CreateFileW(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE,
2648 0,
nullptr, OPEN_ALWAYS,
2649 FILE_ATTRIBUTE_NORMAL,
nullptr);
2650 while (hfile == INVALID_HANDLE_VALUE) {
2651 DWORD error = GetLastError();
2652 if (error == ERROR_SHARING_VIOLATION) {
2655 hfile = CreateFileW(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE,
2656 0,
nullptr, OPEN_ALWAYS,
2657 FILE_ATTRIBUTE_NORMAL,
nullptr);
2659 cerr <<
"Couldn't open file: " << os_specific
2660 <<
", error " << error <<
"\n";
2665 if (hfile == INVALID_HANDLE_VALUE) {
2666 cerr <<
"Couldn't open file: " << os_specific
2667 <<
", error " << GetLastError() <<
"\n";
2671 static const size_t buf_size = 512;
2674 orig_contents = string();
2677 if (!ReadFile(hfile, buf, buf_size, &bytes_read,
nullptr)) {
2678 cerr <<
"Error reading file: " << os_specific
2679 <<
", error " << GetLastError() <<
"\n";
2683 while (bytes_read > 0) {
2684 orig_contents += string(buf, bytes_read);
2686 if (!ReadFile(hfile, buf, buf_size, &bytes_read,
nullptr)) {
2687 cerr <<
"Error reading file: " << os_specific
2688 <<
", error " << GetLastError() <<
"\n";
2695 if (orig_contents == old_contents) {
2697 SetFilePointer(hfile, 0, 0, FILE_BEGIN);
2698 DWORD bytes_written;
2699 if (!WriteFile(hfile, new_contents.data(), new_contents.size(),
2700 &bytes_written,
nullptr)) {
2701 cerr <<
"Error writing file: " << os_specific
2702 <<
", error " << GetLastError() <<
"\n";
2713 int fd = open(os_specific.c_str(), O_RDWR | O_CREAT, 0666);
2715 perror(os_specific.c_str());
2719 static const size_t buf_size = 512;
2722 orig_contents = string();
2725 if (lockf(fd, F_LOCK, 0) != 0) {
2727 if (flock(fd, LOCK_EX) != 0) {
2729 perror(os_specific.c_str());
2734 ssize_t bytes_read = read(fd, buf, buf_size);
2735 while (bytes_read > 0) {
2736 orig_contents += string(buf, bytes_read);
2737 bytes_read = read(fd, buf, buf_size);
2740 if (bytes_read < 0) {
2741 perror(os_specific.c_str());
2747 if (orig_contents == old_contents) {
2749 lseek(fd, 0, SEEK_SET);
2750 ssize_t bytes_written = write(fd, new_contents.data(), new_contents.size());
2751 if (bytes_written < 0) {
2752 perror(os_specific.c_str());
2758 if (close(fd) < 0) {
2759 perror(os_specific.c_str());
2783 HANDLE hfile = CreateFileW(os_specific.c_str(), GENERIC_READ,
2784 FILE_SHARE_READ,
nullptr, OPEN_ALWAYS,
2785 FILE_ATTRIBUTE_NORMAL,
nullptr);
2786 while (hfile == INVALID_HANDLE_VALUE) {
2787 DWORD error = GetLastError();
2788 if (error == ERROR_SHARING_VIOLATION) {
2791 hfile = CreateFileW(os_specific.c_str(), GENERIC_READ,
2792 FILE_SHARE_READ,
nullptr, OPEN_ALWAYS,
2793 FILE_ATTRIBUTE_NORMAL,
nullptr);
2795 cerr <<
"Couldn't open file: " << os_specific
2796 <<
", error " << error <<
"\n";
2801 static const size_t buf_size = 512;
2804 contents = string();
2807 if (!ReadFile(hfile, buf, buf_size, &bytes_read,
nullptr)) {
2808 cerr <<
"Error reading file: " << os_specific
2809 <<
", error " << GetLastError() <<
"\n";
2813 while (bytes_read > 0) {
2814 contents += string(buf, bytes_read);
2816 if (!ReadFile(hfile, buf, buf_size, &bytes_read,
nullptr)) {
2817 cerr <<
"Error reading file: " << os_specific
2818 <<
", error " << GetLastError() <<
"\n";
2829 int fd = open(os_specific.c_str(), O_RDWR | O_CREAT, 0666);
2831 perror(os_specific.c_str());
2835 static const size_t buf_size = 512;
2838 contents = string();
2841 if (lockf(fd, F_LOCK, 0) != 0) {
2843 if (flock(fd, LOCK_EX) != 0) {
2845 perror(os_specific.c_str());
2850 ssize_t bytes_read = read(fd, buf, buf_size);
2851 while (bytes_read > 0) {
2852 contents += string(buf, bytes_read);
2853 bytes_read = read(fd, buf, buf_size);
2856 if (bytes_read < 0) {
2857 perror(os_specific.c_str());
2875 if (_filename.empty()) {
2877 _basename_start = 0;
2881 string::size_type slash = _filename.rfind(
'/');
2882 if (slash != string::npos) {
2883 _basename_start = slash + 1;
2884 _dirname_end = _basename_start;
2889 while (_dirname_end > 0 && _filename[_dirname_end-1] ==
'/') {
2896 if (_dirname_end == 0) {
2902 _basename_start = 0;
2922 locate_extension() {
2924 if (_filename.empty()) {
2925 _basename_end = string::npos;
2926 _extension_start = string::npos;
2929 string::size_type dot = _filename.length() - 1;
2931 while (dot+1 > _basename_start && _filename[dot] !=
'.') {
2935 if (dot+1 > _basename_start) {
2936 _basename_end = dot;
2937 _extension_start = dot + 1;
2939 _basename_end = string::npos;
2940 _extension_start = string::npos;
2961 _hash_end = string::npos;
2962 _hash_start = string::npos;
2967 _hash_end = _filename.rfind(
'#');
2968 if (_hash_end == string::npos) {
2969 _hash_end = string::npos;
2970 _hash_start = string::npos;
2973 _hash_start = _hash_end;
2975 while (_hash_start > 0 && _filename[_hash_start - 1] ==
'#') {
2989 get_common_prefix(
const string &other)
const {
2993 while (len < length() && len < other.length() &&
2994 _filename[len] == other[len]) {
2999 while (len > 0 && _filename[len-1] !=
'/') {
3011 count_slashes(
const string &str) {
3013 string::const_iterator si;
3016 while (si != str.end()) {
3022 while (*si ==
'/') {
3025 if (si == str.end()) {
3043 r_make_canonical(
const Filename &cwd) {
3052 if (_wchdir(os_specific.c_str()) >= 0) {
3058 if (_wchdir(osdir.c_str()) < 0) {
3059 cerr <<
"Error! Cannot change back to " << osdir <<
"\n";
3066 if (::
chdir(os_specific.c_str()) >= 0) {
3072 if (::
chdir(osdir.c_str()) < 0) {
3073 cerr <<
"Error! Cannot change back to " << osdir <<
"\n";
3090 if (!dir.r_make_canonical(cwd)) {