00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "pent_include.h"
00022
00023 #include "FileSystem.h"
00024
00025 #ifdef HAVE_SYS_STAT_H
00026 #include <sys/stat.h>
00027 #endif
00028 #ifdef HAVE_SYS_TYPES_H
00029 #include <sys/types.h>
00030 #endif
00031 #ifdef HAVE_UNISTD_H
00032 #include <unistd.h>
00033 #endif
00034
00035 #include <string>
00036 using std::string;
00037
00038 #include "ListFiles.h"
00039
00040
00041 FileSystem* FileSystem::filesystem = 0;
00042
00043 FileSystem::FileSystem(bool noforced)
00044 : noforcedvpaths(noforced), allowdataoverride(true)
00045 {
00046 con.Print(MM_INFO, "Creating FileSystem...\n");
00047
00048 assert(filesystem == 0);
00049 filesystem = this;
00050
00051 #ifdef UNDER_CE
00052 TCHAR module_filename[256];
00053 TCHAR *c = module_filename;
00054 TCHAR *last = NULL;
00055 GetModuleFileName(NULL, module_filename, 256);
00056
00057 while (*c)
00058 {
00059 if (*c == '/' || *c == '\\')
00060 last = c;
00061
00062 c++;
00063 }
00064
00065 if (last)
00066 {
00067 *last = 0;
00068 }
00069 else
00070 {
00071 module_filename[0] = '\\';
00072 module_filename[1] = 0;
00073 }
00074
00075 size_t len = _tcslen (module_filename) + 1;
00076 char *str = (char*) _alloca(len);
00077 WideCharToMultiByte(CP_ACP, 0, module_filename, -1, str, len, NULL, NULL);
00078
00079 AddVirtualPath(".", str);
00080
00081 #endif
00082
00083 }
00084
00085 FileSystem::~FileSystem()
00086 {
00087 con.Print(MM_INFO, "Destroying FileSystem...\n");
00088
00089 filesystem = 0;
00090 }
00091
00092
00093
00094 IDataSource* FileSystem::ReadFile(const string &vfn, bool is_text)
00095 {
00096 string filename = vfn;
00097
00098 IDataSource* data = checkBuiltinData(vfn, is_text);
00099
00100
00101 if (!allowdataoverride && data) return data;
00102
00103 std::ifstream *f = new std::ifstream();
00104 if(!rawopen(*f, filename, is_text)) {
00105 delete f;
00106 return data;
00107 }
00108
00109 return new IFileDataSource(f);
00110 }
00111
00112
00113 ODataSource* FileSystem::WriteFile(const string &vfn, bool is_text)
00114 {
00115 string filename = vfn;
00116 std::ofstream *f = new std::ofstream();
00117 if(!rawopen(*f, filename, is_text)) {
00118 delete f;
00119 return 0;
00120 }
00121 return new OFileDataSource(f);
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 bool FileSystem::rawopen
00133 (
00134 std::ifstream& in,
00135 const string &fname,
00136 bool is_text
00137 )
00138 {
00139 string name = fname;
00140 if (!rewrite_virtual_path(name)) {
00141
00142 return false;
00143 }
00144
00145 #if defined(MACOS) || (__GNUG__ > 2)
00146 std::ios_base::openmode mode = std::ios::in;
00147 if (!is_text) mode |= std::ios::binary;
00148 #elif defined(UNIX)
00149 int mode = std::ios::in;
00150 #else
00151 int mode = std::ios::in;
00152 if (!is_text) mode |= std::ios::binary;
00153 #endif
00154 switch_slashes(name);
00155
00156 int uppercasecount = 0;
00157 do {
00158
00159
00160 in.clear();
00161 try {
00162 in.open(name.c_str(), mode);
00163 } catch (std::exception &)
00164 {}
00165 if (in.good() && !in.fail()) return true;
00166 } while (base_to_uppercase(name, ++uppercasecount));
00167
00168
00169 return false;
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 bool FileSystem::rawopen
00181 (
00182 std::ofstream& out,
00183 const string &fname,
00184 bool is_text
00185 )
00186 {
00187 string name = fname;
00188 if (!rewrite_virtual_path(name)) {
00189 con.Print_err(MM_MAJOR_WARN, "Illegal file access\n");
00190 return false;
00191 }
00192
00193 #if defined(MACOS) || (__GNUG__ > 2)
00194 std::ios_base::openmode mode = std::ios::out | std::ios::trunc;
00195 if (!is_text) mode |= std::ios::binary;
00196 #elif defined(UNIX)
00197 int mode = std::ios::out | std::ios::trunc;
00198 #else
00199 int mode = std::ios::out | std::ios::trunc;
00200 if (!is_text) mode |= std::ios::binary;
00201 #endif
00202 switch_slashes(name);
00203
00204
00205
00206 out.clear();
00207
00208 int uppercasecount = 0;
00209 do {
00210 out.open(name.c_str(), mode);
00211 if (out.good()) return true;
00212 out.clear();
00213 } while (base_to_uppercase(name, ++uppercasecount));
00214
00215
00216 return false;
00217 }
00218
00219 void FileSystem::switch_slashes(string &name)
00220 {
00221 #ifdef WIN32
00222 for(string::iterator X = name.begin(); X != name.end(); ++X)
00223 {
00224 if(*X == '/' )
00225 *X = '\\';
00226 }
00227 #elif defined(MACOS)
00228
00229
00230
00231
00232 string::size_type begIdx, endIdx;;
00233 string component;
00234 string new_name;
00235
00236 if( name.at(0) != '/' )
00237 new_name = ":";
00238
00239 begIdx = name.find_first_not_of('/');
00240 while( begIdx != string::npos )
00241 {
00242 endIdx = name.find_first_of('/', begIdx);
00243 if( endIdx == std::string::npos )
00244 component = name.substr(begIdx);
00245 else
00246 component = name.substr(begIdx, endIdx-begIdx);
00247 if( component == ".." )
00248 new_name += ":";
00249 else if( !component.empty() && component != "." )
00250 {
00251 new_name += component;
00252 if( endIdx != std::string::npos )
00253 new_name += ":";
00254 }
00255 begIdx = name.find_first_not_of('/', endIdx);
00256 }
00257
00258 name = new_name;
00259 #else
00260
00261 #endif
00262 }
00263
00264
00265
00266
00267
00268
00269 bool FileSystem::base_to_uppercase(string& str, int count)
00270 {
00271 if (count <= 0) return true;
00272
00273 int todo = count;
00274
00275 string::reverse_iterator X;
00276 for(X = str.rbegin(); X != str.rend(); ++X)
00277 {
00278
00279 if (*X == '/' || *X == '\\' || *X == ':')
00280 todo--;
00281 if (todo <= 0)
00282 break;
00283
00284 #if (defined(BEOS) || defined(OPENBSD) || defined(CYGWIN) || defined(__MORPHOS__))
00285 if ((*X >= 'a') && (*X <= 'z')) *X -= 32;
00286 #else
00287 *X = static_cast<char>(std::toupper(*X));
00288 #endif
00289 }
00290 if (X == str.rend())
00291 todo--;
00292
00293
00294 return (todo <= 0);
00295 }
00296
00297 bool FileSystem::AddVirtualPath(const string &vpath, const string &realpath, const bool create)
00298 {
00299 string vp = vpath, rp = realpath;
00300
00301
00302 if (vp.rfind('/') == vp.size() - 1)
00303 vp.erase(vp.rfind('/'));
00304
00305 if (rp.rfind('/') == rp.size() - 1)
00306 rp.erase(rp.rfind('/'));
00307
00308 if (rp.find("..") != string::npos) {
00309 con.Printf_err(MM_MINOR_ERR,
00310 "Error mounting virtual path \"%s\": \"..\" not allowed.\n",
00311 vp.c_str());
00312 return false;
00313 }
00314
00315
00316
00317 if (vp == "@memory" || vp.substr(0, 8) == "@memory/")
00318 {
00319 con.Printf_err(MM_MINOR_ERR,
00320 "Error mounting virtual path \"%s\": %s\"@memory\" is a reserved virtual path name.\n",
00321 vp.c_str());
00322 return false;
00323 }
00324
00325 string fullpath = rp;
00326 rewrite_virtual_path(fullpath);
00327
00328 #ifdef DEBUG
00329 con.Printf(MM_INFO, "virtual path \"%s\": %s\n", vp.c_str(), fullpath.c_str());
00330 #endif
00331 if (!(fullpath.substr(0, 8) == "@memory/"))
00332 {
00333 if (!IsDir(fullpath)) {
00334 if(!create) {
00335 #ifdef DEBUG
00336 con.Printf_err(MM_MINOR_WARN,
00337 "Problem mounting virtual path \"%s\": directory not found: %s\n",
00338 vp.c_str(), fullpath.c_str());
00339 #endif
00340 return false;
00341 }
00342 else {
00343 MkDir(fullpath);
00344 }
00345 }
00346 }
00347
00348 virtualpaths[vp] = rp;
00349 return true;
00350 }
00351
00352 bool FileSystem::RemoveVirtualPath(const string &vpath)
00353 {
00354 string vp = vpath;
00355
00356
00357 if (vp.rfind('/') == vp.size() - 1)
00358 vp.erase(vp.rfind('/'));
00359
00360 std::map<string, string>::iterator i = virtualpaths.find(vp);
00361
00362 if (i == virtualpaths.end()) {
00363 return false;
00364 } else {
00365 virtualpaths.erase(vp);
00366 return true;
00367 }
00368 }
00369
00370 IDataSource* FileSystem::checkBuiltinData(const std::string& vfn, bool is_text)
00371 {
00372
00373 std::map<string, MemoryFile*>::iterator mf = memoryfiles.find(vfn);
00374
00375 if (mf != memoryfiles.end())
00376 return new IBufferDataSource(mf->second->data,
00377 mf->second->len, is_text);
00378
00379 return 0;
00380 }
00381
00382 bool FileSystem::rewrite_virtual_path(string &vfn)
00383 {
00384 bool ret = false;
00385 string::size_type pos = vfn.size();
00386
00387 while ((pos = vfn.rfind('/', pos)) != std::string::npos) {
00388
00389 std::map<string, string>::iterator p = virtualpaths.find(
00390 vfn.substr(0, pos));
00391
00392 if (p != virtualpaths.end()) {
00393 ret = true;
00394
00395 vfn = p->second + vfn.substr(pos);
00396 pos = string::npos;
00397 } else {
00398 if (pos == 0)
00399 break;
00400 --pos;
00401 }
00402 }
00403
00404
00405 if (noforcedvpaths) ret = true;
00406
00407 return ret;
00408 }
00409
00410
00411 bool FileSystem::IsDir(const string &path)
00412 {
00413 #ifndef UNDER_CE
00414 bool exists;
00415 struct stat sbuf;
00416
00417 string name = path;
00418
00419 int uppercasecount = 0;
00420 do {
00421 exists = (stat(name.c_str(), &sbuf) == 0);
00422 if (exists) {
00423 if (S_ISDIR(sbuf.st_mode))
00424 return true;
00425 else
00426 return false;
00427 }
00428 } while (base_to_uppercase(name, ++uppercasecount));
00429 #else
00430
00431
00432 if (path == "." || path == "/" || path == "\\" ) return true;
00433
00434 const TCHAR *lpszT;
00435 WIN32_FIND_DATA fileinfo;
00436 HANDLE handle;
00437
00438 #ifdef UNICODE
00439 const char *name = path.c_str();
00440 std::size_t nLen = strlen(name)+1;
00441 LPTSTR lpszT2 = (LPTSTR) _alloca(nLen*2);
00442 lpszT = lpszT2;
00443 MultiByteToWideChar(CP_ACP, 0, name, -1, lpszT2, nLen);
00444 #else
00445 lpszT = path.c_str();
00446 #endif
00447
00448 handle = FindFirstFile (lpszT, &fileinfo);
00449
00450 if (handle != INVALID_HANDLE_VALUE)
00451 {
00452 FindClose (handle);
00453
00454 if (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) return true;
00455 }
00456 #endif
00457
00458 return false;
00459 }
00460
00461
00462
00463
00464
00465 int FileSystem::MkDir(const string &path)
00466 {
00467 string name = path;
00468 if(name[0]=='@')
00469 rewrite_virtual_path(name);
00470
00471 #if (defined(MACOSX) || defined(BEOS))
00472
00473 string::size_type pos = name.find_last_not_of('/');
00474 if (pos != string::npos)
00475 name.resize(pos+1);
00476 #endif
00477 #if defined(WIN32) && defined(UNICODE)
00478 const char *n = name.c_str();
00479 int nLen = std::strlen(n)+1;
00480 LPTSTR lpszT = (LPTSTR) alloca(nLen*2);
00481 MultiByteToWideChar(CP_ACP, 0, n, -1, lpszT, nLen);
00482 return CreateDirectory(lpszT, NULL);
00483 #elif defined(WIN32)
00484 return mkdir(name.c_str());
00485 #else
00486 return mkdir(name.c_str(), 0750);
00487 #endif
00488 }
00489
00490