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());
441 result.set_type(type);
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()) {
521 home_directory = ExecutionEnvironment::get_cwd();
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()) {
569 temp_directory = ExecutionEnvironment::get_cwd();
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()) {
626 user_appdata_directory = ExecutionEnvironment::get_cwd();
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()) {
676 common_appdata_directory = ExecutionEnvironment::get_cwd();
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;
1032 Filename cwd = ExecutionEnvironment::get_cwd();
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());
2514 string os_specific = component.to_os_specific();
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) {
3054 (*this) = ExecutionEnvironment::get_cwd();
3058 if (_wchdir(osdir.c_str()) < 0) {
3059 cerr <<
"Error! Cannot change back to " << osdir <<
"\n";
3066 if (::
chdir(os_specific.c_str()) >= 0) {
3068 (*this) = ExecutionEnvironment::get_cwd();
3072 if (::
chdir(osdir.c_str()) < 0) {
3073 cerr <<
"Error! Cannot change back to " << osdir <<
"\n";
3090 if (!dir.r_make_canonical(cwd)) {
Filename get_filename_index(int index) const
If the pattern flag is set for this Filename and the filename string actually includes a sequence of ...
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
std::string get_dirname() const
Returns the directory part of the filename.
void set_extension(const std::string &s)
Replaces the file extension.
bool get_pattern() const
Returns the flag indicating whether this is a filename pattern.
Filename()
Creates an empty Filename.
static Pointer get_ptr(const Pointer &var)
Atomically retrieves the snapshot value of the indicated variable.
bool open_append(std::ofstream &stream) const
Opens the indicated ofstream for writing the file, if possible.
std::string to_os_short_name() const
This works like to_os_generic(), but it returns the "short name" version of the filename,...
time_t get_timestamp() const
Returns a time_t value that represents the time the file was last modified, to within whatever precis...
This class can be used to convert text between multiple representations, e.g.
static Filename expand_from(const std::string &user_string, Type type=T_general)
Returns the same thing as from_os_specific(), but embedded environment variable references (e....
void set_type(Type type)
Sets the type of the file represented by the filename.
int get_hash() const
Returns a hash code that attempts to be mostly unique for different Filenames.
void set_binary()
Indicates that the filename represents a binary file.
time_t get_access_timestamp() const
Returns a time_t value that represents the time the file was last accessed, if this information is av...
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool resolve_filename(const DSearchPath &searchpath, const std::string &default_extension=std::string())
Searches the given search path for the filename.
bool make_canonical()
Converts this filename to a canonical name by replacing the directory part with the fully-qualified d...
bool make_true_case()
On a case-insensitive operating system (e.g.
void set_fullpath_wo_extension(const std::string &s)
Replaces the full filename–directory and basename parts–except for the extension.
bool copy_to(const Filename &other) const
Copies the file to the indicated new filename, by reading the contents and writing it to the new file...
std::wstring to_os_specific_w() const
The wide-string variant on to_os_specific().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void standardize()
Converts the filename to standard form by replacing consecutive slashes with a single slash,...
std::string to_os_generic() const
This is similar to to_os_specific(), but it is designed to generate a filename that can be understood...
set_text
Changes the text that is stored in the encoder.
bool atomic_compare_and_exchange_contents(std::string &orig_contents, const std::string &old_contents, const std::string &new_contents) const
Uses native file-locking mechanisms to atomically replace the contents of a (small) file with the spe...
Type get_type() const
Returns the type of the file represented by the filename, as previously set by set_type().
bool chdir() const
Changes directory to the specified location.
void set_fullpath(const std::string &s)
Replaces the entire filename: directory, basename, extension.
get_num_directories
Returns the number of directories on the search list.
static const Filename & get_home_directory()
Returns a path to the user's home directory, if such a thing makes sense in the current OS,...
bool is_executable() const
Returns true if the filename exists and is executable.
bool touch() const
Updates the modification time of the file to the current time.
static TextEncoder::Encoding get_filesystem_encoding()
Specifies the default encoding to be used for all subsequent Filenames objects.
The name of a file, such as a texture file or an Egg file.
bool atomic_read_contents(std::string &contents) const
Uses native file-locking mechanisms to atomically read the contents of a (small) file.
static std::string expand_string(const std::string &str)
Reads the string, looking for environment variable names marked by a $.
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
static int unicode_tolower(char32_t character)
Returns the uppercase equivalent of the given Unicode character.
void set_hash_to_end(const std::string &s)
Replaces the part of the filename from the beginning of the hash sequence to the end of the filename.
static const Filename & get_user_appdata_directory()
Returns a path to a system-defined directory appropriate for creating a subdirectory for storing appl...
std::string to_os_long_name() const
This is the opposite of to_os_short_name(): it returns the "long name" of the filename,...
bool unlink() const
Permanently deletes the file associated with the filename, if possible.
static const Filename & get_temp_directory()
Returns a path to a system-defined temporary directory.
void extract_components(vector_string &components) const
Extracts out the individual directory components of the path into a series of strings.
bool is_local() const
Returns true if the filename is local, e.g.
get_text
Returns the current text, as encoded via the current encoding system.
bool is_regular_file() const
Returns true if the filename exists and is the name of a regular file (i.e.
bool is_text() const
Returns true if the Filename has been indicated to represent a text file via a previous call to set_t...
std::string get_extension() const
Returns the file extension.
bool make_relative_to(Filename directory, bool allow_backups=true)
Adjusts this filename, which must be a fully-specified pathname beginning with a slash,...
int compare_timestamps(const Filename &other, bool this_missing_is_old=true, bool other_missing_is_old=true) const
Returns a number less than zero if the file named by this object is older than the given file,...
void set_basename_wo_extension(const std::string &s)
Replaces the basename part of the filename, without the file extension.
bool open_read_append(std::fstream &stream) const
Opens the indicated ifstream for reading and writing the file, if possible; writes are appended to th...
void make_absolute()
Converts the filename to a fully-qualified pathname from the root (if it is a relative pathname),...
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
void set_dirname(const std::string &s)
Replaces the directory part of the filename.
bool is_writable() const
Returns true if the filename exists and is either a directory or a regular file that can be written t...
void set_basename(const std::string &s)
Replaces the basename part of the filename.
get_directory
Returns the nth directory on the search list.
int find_on_searchpath(const DSearchPath &searchpath)
Performs the reverse of the resolve_filename() operation: assuming that the current filename is fully...
void set_encoding(Encoding encoding)
Specifies how the string set via set_text() is to be interpreted.
static const Filename & get_common_appdata_directory()
Returns a path to a system-defined directory appropriate for creating a subdirectory for storing appl...
std::streamsize get_file_size() const
Returns the size of the file in bytes, or 0 if there is an error.
static Filename temporary(const std::string &dirname, const std::string &prefix, const std::string &suffix=std::string(), Type type=T_general)
Generates a temporary filename within the indicated directory, using the indicated prefix.
This class stores a list of directories that can be searched, in order, to locate a particular file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool rmdir() const
The inverse of mkdir(): this removes the directory named by this Filename, if it is in fact a directo...
bool scan_directory(vector_string &contents) const
Attempts to open the named filename as if it were a directory and looks for the non-hidden files with...
bool open_read_write(std::fstream &stream, bool truncate=false) const
Opens the indicated fstream for read/write access to the file, if possible.
bool make_dir() const
Creates all the directories in the path to the file specified in the filename, except for the basenam...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const std::wstring & get_wtext() const
Returns the text associated with the TextEncoder, as a wide-character string.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool rename_to(const Filename &other) const
Renames the file to the indicated new filename.
static Filename from_os_specific_w(const std::wstring &os_specific, Type type=T_general)
The wide-string variant of from_os_specific().
void set_wtext(const std::wstring &wtext)
Changes the text that is stored in the encoder.
void set_pattern(bool pattern)
Sets the flag indicating whether this is a filename pattern.
bool is_binary_or_text() const
Returns true either is_binary() or is_text() is true; that is, that the filename has been specified a...
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
bool mkdir() const
Creates the directory named by this filename.
static Pointer compare_and_exchange_ptr(Pointer &mem, Pointer old_value, Pointer new_value)
Atomic compare and exchange.
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
std::wstring get_fullpath_w() const
Returns the entire filename as a wide-character string.
Filename find_file(const Filename &filename) const
Searches all the directories in the search list for the indicated file, in order.