20 # define access _taccess 
   21 #elif defined(__HAIKU__) 
   23 #include <storage/FindDirectory.h> 
   31 #ifdef WITH_XDG_BASEDIR 
   38 #define FIO_BUFFER_SIZE 512 
   50 #if defined(LIMITED_FDS) 
   93   if (fseek(_fio.
cur_fh, _fio.
pos, SEEK_SET) < 0) {
 
   98 #if defined(LIMITED_FDS) 
   99 static void FioRestoreFile(
int slot)
 
  102   if (_fio.
handles[slot] == NULL) {
 
  103     DEBUG(misc, 6, 
"Restoring file '%s' in slot '%d' from disk", _fio.
filenames[slot], slot);
 
  106   _fio.usage_count[slot]++;
 
  118 #if defined(LIMITED_FDS) 
  120   FioRestoreFile(slot);
 
  141     if (size == 0) 
return 0;
 
  143   return *_fio.buffer++;
 
  190   _fio.
pos += fread(ptr, 1, size, _fio.
cur_fh);
 
  199   if (_fio.
handles[slot] != NULL) {
 
  206 #if defined(LIMITED_FDS) 
  220 #if defined(LIMITED_FDS) 
  221 static void FioFreeHandle()
 
  224   if (_fio.open_handles + 1 == LIMITED_FDS) {
 
  232       if (_fio.
handles[i] != NULL && _fio.usage_count[i] < count) {
 
  233         count = _fio.usage_count[i];
 
  238     DEBUG(misc, 6, 
"Closing filehandler '%s' in slot '%d' because of fd-limit", _fio.
filenames[slot], slot);
 
  254 #if defined(LIMITED_FDS) 
  258   if (f == NULL) 
usererror(
"Cannot open file '%s'", filename);
 
  260   if (pos < 0) 
usererror(
"Cannot read file '%s'", filename);
 
  267   const char *t = strrchr(filename, PATHSEPCHAR);
 
  269   char *t2 = strrchr(_fio.
shortnames[slot], 
'.');
 
  270   if (t2 != NULL) *t2 = 
'\0';
 
  273 #if defined(LIMITED_FDS) 
  274   _fio.usage_count[slot] = 0;
 
  280 static const char * 
const _subdirs[] = {
 
  283   "save" PATHSEP 
"autosave" PATHSEP,
 
  285   "scenario" PATHSEP 
"heightmap" PATHSEP,
 
  292   "ai" PATHSEP 
"library" PATHSEP,
 
  294   "game" PATHSEP 
"library" PATHSEP,
 
  295   "screenshot" PATHSEP,
 
  303 typedef std::map<std::string, std::string> TarLinkList;
 
  315   if (f == NULL) 
return false;
 
  330   HANDLE hand = CreateFile(
OTTD2FS(filename), 0, 0, NULL, OPEN_EXISTING, 0, NULL);
 
  331   if (hand == INVALID_HANDLE_VALUE) 
return 1;
 
  335   return access(
OTTD2FS(filename), 0) == 0;
 
  347 char *FioGetFullPath(
char *buf, 
const char *last, 
Searchpath sp, 
Subdirectory subdir, 
const char *filename)
 
  350   assert(sp < NUM_SEARCHPATHS);
 
  352   seprintf(buf, last, 
"%s%s%s", _searchpaths[sp], _subdirs[subdir], filename);
 
  370     FioGetFullPath(buf, last, sp, subdir, filename);
 
  386   assert(sp < NUM_SEARCHPATHS);
 
  388   seprintf(buf, last, 
"%s%s", _searchpaths[sp], _subdirs[subdir]);
 
  392 char *FioGetDirectory(
char *buf, 
const char *last, 
Subdirectory subdir)
 
  398     char *ret = FioAppendDirectory(buf, last, sp, subdir);
 
  408 static FILE *FioFOpenFileSp(
const char *filename, 
const char *mode, 
Searchpath sp, 
Subdirectory subdir, 
size_t *filesize)
 
  410 #if defined(WIN32) && defined(UNICODE) 
  416   MultiByteToWideChar(CP_ACP, 0, mode, -1, Lmode, 
lengthof(Lmode));
 
  424     seprintf(buf, 
lastof(buf), 
"%s%s%s", _searchpaths[sp], _subdirs[subdir], filename);
 
  428   if (mode[0] == 
'r' && GetFileAttributes(
OTTD2FS(buf)) == INVALID_FILE_ATTRIBUTES) 
return NULL;
 
  431   f = fopen(buf, mode);
 
  434     f = fopen(buf, mode);
 
  437   if (f != NULL && filesize != NULL) {
 
  439     fseek(f, 0, SEEK_END);
 
  440     *filesize = ftell(f);
 
  441     fseek(f, 0, SEEK_SET);
 
  455   FILE *f = fopen(entry->tar_filename, 
"rb");
 
  456   if (f == NULL) 
return f;
 
  458   if (fseek(f, entry->position, SEEK_SET) < 0) {
 
  463   if (filesize != NULL) *filesize = entry->size;
 
  482     f = FioFOpenFileSp(filename, mode, sp, subdir, filesize);
 
  487   if (f == NULL && mode[0] == 
'r' && subdir != 
NO_DIRECTORY) {
 
  488     static const uint MAX_RESOLVED_LENGTH = 2 * (100 + 100 + 155) + 1; 
 
  489     char resolved_name[MAX_RESOLVED_LENGTH];
 
  495     size_t resolved_len = strlen(resolved_name);
 
  498     for (TarLinkList::iterator link = _tar_linklist[subdir].begin(); link != _tar_linklist[subdir].end(); link++) {
 
  499       const std::string &src = link->first;
 
  500       size_t len = src.length();
 
  501       if (resolved_len >= len && resolved_name[len - 1] == PATHSEPCHAR && strncmp(src.c_str(), resolved_name, len) == 0) {
 
  503         char resolved_name2[MAX_RESOLVED_LENGTH];
 
  504         const std::string &dest = link->second;
 
  505         strecpy(resolved_name2, &(resolved_name[len]), 
lastof(resolved_name2));
 
  507         strecpy(&(resolved_name[dest.length()]), resolved_name2, 
lastof(resolved_name));
 
  512     TarFileList::iterator it = _tar_filelist[subdir].find(resolved_name);
 
  513     if (it != _tar_filelist[subdir].end()) {
 
  524         if (f != NULL) 
break;
 
  547 #if defined(WIN32) || defined(WINCE) 
  548   CreateDirectory(
OTTD2FS(name), NULL);
 
  549 #elif defined(OS2) && !defined(__INNOTEK_LIBC__) 
  551 #elif defined(__MORPHOS__) || defined(__AMIGAOS__) 
  555   size_t len = strlen(name) - 1;
 
  556   if (buf[len] == 
'/') {
 
  575   size_t s = strlen(buf);
 
  578   if (s != 0 && buf[s - 1] != PATHSEPCHAR) {
 
  579     if (&buf[s] >= last) 
return false;
 
  581     seprintf(buf + s, last, 
"%c", PATHSEPCHAR);
 
  595   char *dest = MallocT<char>(MAX_PATH);
 
  596   char *last = dest + MAX_PATH - 1;
 
  600   const char *s = strchr(dest, PATHSEPCHAR);
 
  603   if (s == NULL || dest != s) {
 
  604     if (getcwd(dest, MAX_PATH) == NULL) *dest = 
'\0';
 
  620   TarList::iterator it = _tar_list[subdir].find(tarname);
 
  621   if (it == _tar_list[subdir].end()) 
return NULL;
 
  622   return (*it).second.dirname;
 
  625 static void TarAddLink(
const std::string &srcParam, 
const std::string &destParam, 
Subdirectory subdir)
 
  627   std::string src = srcParam;
 
  628   std::string dest = destParam;
 
  630   std::transform(src.begin(), src.end(), src.begin(), tolower);
 
  631   std::transform(dest.begin(), dest.end(), dest.begin(), tolower);
 
  633   TarFileList::iterator dest_file = _tar_filelist[subdir].find(dest);
 
  634   if (dest_file != _tar_filelist[subdir].end()) {
 
  636     _tar_filelist[subdir].insert(TarFileList::value_type(src, dest_file->second));
 
  640     const std::string src_path = ((*src.rbegin() == PATHSEPCHAR) ? src : src + PATHSEPCHAR);
 
  641     const std::string dst_path = (dest.length() == 0 ? 
"" : ((*dest.rbegin() == PATHSEPCHAR) ? dest : dest + PATHSEPCHAR));
 
  642     _tar_linklist[subdir].insert(TarLinkList::value_type(src_path, dst_path));
 
  646 void FioTarAddLink(
const char *src, 
const char *dest, 
Subdirectory subdir)
 
  648   TarAddLink(src, dest, subdir);
 
  662 #if (PATHSEPCHAR != '/') 
  663   for (
char *n = name; *n != 
'\0'; n++) 
if (*n == 
'/') *n = PATHSEPCHAR;
 
  674   _tar_filelist[sd].clear();
 
  675   _tar_list[sd].clear();
 
  676   uint num = this->
Scan(
".tar", sd, 
false);
 
  683   DEBUG(misc, 1, 
"Scanning for tars");
 
  704   DEBUG(misc, 1, 
"Scan complete, found %d files", num);
 
  717   return this->
AddFile(filename, 0);
 
  723   assert(tar_filename == NULL);
 
  748   TarList::iterator it = _tar_list[this->
subdir].find(filename);
 
  749   if (it != _tar_list[this->subdir].end()) 
return false;
 
  751   FILE *f = fopen(filename, 
"rb");
 
  756   if (f == NULL) 
return false;
 
  758   const char *dupped_filename = 
stredup(filename);
 
  759   _tar_list[this->
subdir][filename].filename = dupped_filename;
 
  760   _tar_list[this->
subdir][filename].dirname = NULL;
 
  765   char buf[
sizeof(th.name) + 1], *end;
 
  766   char name[
sizeof(th.prefix) + 1 + 
sizeof(th.name) + 1];
 
  767   char link[
sizeof(th.linkname) + 1];
 
  768   char dest[
sizeof(th.prefix) + 1 + 
sizeof(th.name) + 1 + 1 + 
sizeof(th.linkname) + 1];
 
  769   size_t num = 0, pos = 0;
 
  773   memset(&empty[0], 0, 
sizeof(empty));
 
  776     size_t num_bytes_read = fread(&th, 1, 512, f);
 
  777     if (num_bytes_read != 512) 
break;
 
  778     pos += num_bytes_read;
 
  781     if (strncmp(th.magic, 
"ustar", 5) != 0 && memcmp(&th.magic, &empty[0], 512 - offsetof(TarHeader, magic)) != 0) {
 
  783       if (memcmp(&th, &empty[0], 512) == 0) 
continue;
 
  785       DEBUG(misc, 0, 
"The file '%s' isn't a valid tar-file", filename);
 
  793     if (th.prefix[0] != 
'\0') {
 
  803     size_t skip = strtoul(buf, &end, 8);
 
  805     switch (th.typeflag) {
 
  809         if (skip == 0) 
break;
 
  811         if (strlen(name) == 0) 
break;
 
  815         entry.tar_filename = dupped_filename;
 
  817         entry.position     = pos;
 
  822         DEBUG(misc, 6, 
"Found file in tar: %s (" PRINTF_SIZE 
" bytes, " PRINTF_SIZE 
" offset)", name, skip, pos);
 
  823         if (_tar_filelist[this->subdir].insert(TarFileList::value_type(name, entry)).second) num++;
 
  833         if (strlen(name) == 0 || strlen(link) == 0) 
break;
 
  840         if (link[0] == PATHSEPCHAR) {
 
  841           DEBUG(misc, 1, 
"Ignoring absolute link in tar: %s -> %s", name, link);
 
  848         char *destpos = strrchr(dest, PATHSEPCHAR);
 
  849         if (destpos == NULL) destpos = dest;
 
  853         while (*pos != 
'\0') {
 
  854           char *next = strchr(pos, PATHSEPCHAR);
 
  856             next = pos + strlen(pos);
 
  862           if (strcmp(pos, 
".") == 0) {
 
  864           } 
else if (strcmp(pos, 
"..") == 0) {
 
  866             if (dest[0] == 
'\0') {
 
  867               DEBUG(misc, 1, 
"Ignoring link pointing outside of data directory: %s -> %s", name, link);
 
  873             destpos = strrchr(dest, PATHSEPCHAR);
 
  874             if (destpos == NULL) destpos = dest;
 
  878             if (destpos != dest) destpos = 
strecpy(destpos, PATHSEP, 
lastof(dest));
 
  882           if (destpos >= 
lastof(dest)) {
 
  883             DEBUG(misc, 0, 
"The length of a link in tar-file '%s' is too large (malformed?)", filename);
 
  892         DEBUG(misc, 6, 
"Found link in tar: %s -> %s", name, dest);
 
  893         links.insert(TarLinkList::value_type(name, dest));
 
  903         DEBUG(misc, 6, 
"Found dir in tar: %s", name);
 
  904         if (_tar_list[this->subdir][filename].dirname == NULL) _tar_list[this->
subdir][filename].dirname = 
stredup(name);
 
  913     skip = 
Align(skip, 512);
 
  914     if (fseek(f, skip, SEEK_CUR) < 0) {
 
  915       DEBUG(misc, 0, 
"The file '%s' can't be read as a valid tar-file", filename);
 
  922   DEBUG(misc, 1, 
"Found tar '%s' with " PRINTF_SIZE 
" new files", filename, num);
 
  934   for (TarLinkList::iterator link = links.begin(); link != links.end(); link++) {
 
  935     const std::string &src = link->first;
 
  936     const std::string &dest = link->second;
 
  937     TarAddLink(src, dest, this->subdir);
 
  952   TarList::iterator it = _tar_list[subdir].find(tar_filename);
 
  954   if (it == _tar_list[subdir].end()) 
return false;
 
  956   const char *dirname = (*it).second.dirname;
 
  959   if (dirname == NULL) 
return false;
 
  961   char filename[MAX_PATH];
 
  963   char *p = strrchr(filename, PATHSEPCHAR);
 
  965   if (p == NULL) 
return false;
 
  969   DEBUG(misc, 8, 
"Extracting %s to directory %s", tar_filename, filename);
 
  972   for (TarFileList::iterator it2 = _tar_filelist[subdir].begin(); it2 != _tar_filelist[subdir].end(); it2++) {
 
  973     if (strcmp((*it2).second.tar_filename, tar_filename) != 0) 
continue;
 
  977     DEBUG(misc, 9, 
"  extracting %s", filename);
 
  983       DEBUG(misc, 6, 
"Extracting %s failed; could not open %s", filename, tar_filename);
 
  988     FILE *out = fopen(filename, 
"wb");
 
  990       DEBUG(misc, 6, 
"Extracting %s failed; could not open %s", filename, filename);
 
  998     for (; to_copy != 0; to_copy -= read) {
 
  999       read = fread(buffer, 1, 
min(to_copy, 
lengthof(buffer)), in);
 
 1000       if (read <= 0 || fwrite(buffer, 1, read, out) != read) 
break;
 
 1008       DEBUG(misc, 6, 
"Extracting %s failed; still %i bytes to copy", filename, (
int)to_copy);
 
 1013   DEBUG(misc, 9, 
"  extraction successful");
 
 1017 #if defined(WIN32) || defined(WINCE) 
 1035   bool success = 
false;
 
 1037   char *app_bundle = strchr(exe, 
'.');
 
 1038   while (app_bundle != NULL && strncasecmp(app_bundle, 
".app", 4) != 0) app_bundle = strchr(&app_bundle[1], 
'.');
 
 1040   if (app_bundle != NULL) app_bundle[0] = 
'\0';
 
 1042   char *s = 
const_cast<char *
>(strrchr(exe, PATHSEPCHAR));
 
 1045 #if defined(__DJGPP__) 
 1047     if (s[-1] == 
':') chdir(
"/");
 
 1049     if (chdir(exe) != 0) {
 
 1050       DEBUG(misc, 0, 
"Directory with the binary does not exist?");
 
 1057   if (app_bundle != NULL) app_bundle[0] = 
'.';
 
 1078   if (strcmp(_searchpaths[
SP_WORKING_DIR], PATHSEP) == 0) 
return false;
 
 1084   seprintf(tmp, 
lastof(tmp), 
"%s%s", _searchpaths[SP_WORKING_DIR], PERSONAL_DIR);
 
 1096 #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) 
 1097   const char *xdg_data_home = xdgDataHome(NULL);
 
 1099       PERSONAL_DIR[0] == 
'.' ? &PERSONAL_DIR[1] : PERSONAL_DIR);
 
 1100   free(xdg_data_home);
 
 1103   _searchpaths[SP_PERSONAL_DIR_XDG] = 
stredup(tmp);
 
 1105 #if defined(__MORPHOS__) || defined(__AMIGA__) || defined(DOS) || defined(OS2) || !defined(WITH_PERSONAL_DIR) 
 1110   find_directory(B_USER_SETTINGS_DIRECTORY, &path);
 
 1111   const char *homedir = 
stredup(path.Path());
 
 1117   const char *homedir = getenv(
"HOME");
 
 1118   if (homedir != NULL) {
 
 1122   if (homedir == NULL) {
 
 1123     const struct passwd *pw = getpwuid(getuid());
 
 1124     homedir = (pw == NULL) ? NULL : 
stredup(pw->pw_dir);
 
 1128   if (homedir != NULL) {
 
 1130     seprintf(tmp, 
lastof(tmp), 
"%s" PATHSEP 
"%s", homedir, PERSONAL_DIR);
 
 1140 #if defined(WITH_SHARED_DIR) 
 1148 #if defined(__MORPHOS__) || defined(__AMIGA__) 
 1151   if (getcwd(tmp, MAX_PATH) == NULL) *tmp = 
'\0';
 
 1160     if (getcwd(tmp, MAX_PATH) == NULL) *tmp = 
'\0';
 
 1170       DEBUG(misc, 0, 
"Failed to return to working directory!");
 
 1174 #if defined(__MORPHOS__) || defined(__AMIGA__) || defined(DOS) || defined(OS2) 
 1182 extern void cocoaSetApplicationBundleDir();
 
 1183   cocoaSetApplicationBundleDir();
 
 1202 #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) 
 1203   char config_home[MAX_PATH];
 
 1205   const char *xdg_config_home = xdgConfigHome(NULL);
 
 1206   seprintf(config_home, 
lastof(config_home), 
"%s" PATHSEP 
"%s", xdg_config_home,
 
 1207       PERSONAL_DIR[0] == 
'.' ? &PERSONAL_DIR[1] : PERSONAL_DIR);
 
 1208   free(xdg_config_home);
 
 1216     DEBUG(misc, 4, 
"%s added as search path", _searchpaths[sp]);
 
 1222     char *end = strrchr(config_dir, PATHSEPCHAR);
 
 1224       config_dir[0] = 
'\0';
 
 1229     char personal_dir[MAX_PATH];
 
 1231       char *end = strrchr(personal_dir, PATHSEPCHAR);
 
 1232       if (end != NULL) end[1] = 
'\0';
 
 1233       config_dir = 
stredup(personal_dir);
 
 1236 #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) 
 1238       config_dir = config_home;
 
 1240       static const Searchpath new_openttd_cfg_order[] = {
 
 1245       for (uint i = 0; i < 
lengthof(new_openttd_cfg_order); i++) {
 
 1247           config_dir = 
stredup(_searchpaths[new_openttd_cfg_order[i]]);
 
 1251       assert(config_dir != NULL);
 
 1257   DEBUG(misc, 3, 
"%s found as config directory", config_dir);
 
 1260   extern char *_hotkeys_file;
 
 1261   _hotkeys_file = 
str_fmt(
"%shotkeys.cfg", config_dir);
 
 1263   _windows_file = 
str_fmt(
"%swindows.cfg", config_dir);
 
 1265 #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) 
 1266   if (config_dir == config_home) {
 
 1269     _personal_dir = _searchpaths[SP_PERSONAL_DIR_XDG];
 
 1274     _personal_dir = config_dir;
 
 1278 #if !defined(__MORPHOS__) && !defined(__AMIGA__) && defined(WITH_PERSONAL_DIR) 
 1283   DEBUG(misc, 3, 
"%s found as personal directory", _personal_dir);
 
 1286     SAVE_DIR, 
AUTOSAVE_DIR, 
SCENARIO_DIR, 
HEIGHTMAP_DIR, 
BASESET_DIR, 
NEWGRF_DIR, 
AI_DIR, 
AI_LIBRARY_DIR, 
GAME_DIR, 
GAME_LIBRARY_DIR, 
SCREENSHOT_DIR 
 1289   for (uint i = 0; i < 
lengthof(default_subdirs); i++) {
 
 1290     char *dir = 
str_fmt(
"%s%s", _personal_dir, _subdirs[default_subdirs[i]]);
 
 1297 #ifdef ENABLE_NETWORK 
 1302   for (uint i = 0; i < 
lengthof(dirs); i++) {
 
 1303     char *tmp = 
str_fmt(
"%s%s", _searchpaths[SP_AUTODOWNLOAD_DIR], _subdirs[dirs[i]]);
 
 1309   _log_file = 
str_fmt(
"%sopenttd.log",  _personal_dir);
 
 1313   if (!
FileExists(_searchpaths[SP_AUTODOWNLOAD_DIR]))  {
 
 1314     free(_searchpaths[SP_AUTODOWNLOAD_DIR]);
 
 1326   for (; *filename != 
'\0'; filename++) {
 
 1327     switch (*filename) {
 
 1330       case ':': 
case '\\': 
case '*': 
case '?': 
case '/':
 
 1331       case '<': 
case '>': 
case '|': 
case '"':
 
 1348   FILE *in = fopen(filename, 
"rb");
 
 1349   if (in == NULL) 
return NULL;
 
 1351   fseek(in, 0, SEEK_END);
 
 1352   size_t len = ftell(in);
 
 1353   fseek(in, 0, SEEK_SET);
 
 1354   if (len > maxsize) {
 
 1358   byte *mem = MallocT<byte>(len + 1);
 
 1360   if (fread(mem, len, 1, in) != 1) {
 
 1379   if (extension == NULL) 
return true;
 
 1381   const char *ext = strrchr(filename, extension[0]);
 
 1382   return ext != NULL && strcasecmp(ext, extension) == 0;
 
 1394 static uint 
ScanPath(
FileScanner *fs, 
const char *extension, 
const char *path, 
size_t basepath_length, 
bool recursive)
 
 1396   extern bool FiosIsValidFile(
const char *path, 
const struct dirent *ent, 
struct stat *sb);
 
 1400   struct dirent *dirent;
 
 1403   if (path == NULL || (dir = 
ttd_opendir(path)) == NULL) 
return 0;
 
 1405   while ((dirent = readdir(dir)) != NULL) {
 
 1406     const char *d_name = 
FS2OTTD(dirent->d_name);
 
 1407     char filename[MAX_PATH];
 
 1409     if (!FiosIsValidFile(path, dirent, &sb)) 
continue;
 
 1413     if (S_ISDIR(sb.st_mode)) {
 
 1415       if (!recursive) 
continue;
 
 1416       if (strcmp(d_name, 
".") == 0 || strcmp(d_name, 
"..") == 0) 
continue;
 
 1418       num += 
ScanPath(fs, extension, filename, basepath_length, recursive);
 
 1419     } 
else if (S_ISREG(sb.st_mode)) {
 
 1439   const char *filename = (*tar).first.c_str();
 
 1460   char path[MAX_PATH];
 
 1461   TarFileList::iterator tar;
 
 1468     FioAppendDirectory(path, 
lastof(path), sp, sd);
 
 1469     num += 
ScanPath(
this, extension, path, strlen(path), recursive);
 
 1473     FOR_ALL_TARS(tar, sd) {
 
 1474       num += 
ScanTar(
this, extension, tar);
 
 1502   char path[MAX_PATH];
 
 1505   return ScanPath(
this, extension, path, strlen(path), recursive);