RefCountedPtr<FileData> FileSourceFS::ReadFile(const std::string &path) { const std::string fullpath = JoinPathBelow(GetRoot(), path); FILE *fl = fopen(fullpath.c_str(), "rb"); if (!fl) { return RefCountedPtr<FileData>(0); } else { fseek(fl, 0, SEEK_END); long sz = ftell(fl); fseek(fl, 0, SEEK_SET); char *data = reinterpret_cast<char*>(std::malloc(sz)); if (!data) { // XXX handling memory allocation failure gracefully is too hard right now fprintf(stderr, "failed when allocating buffer for '%s'\n", fullpath.c_str()); fclose(fl); abort(); } size_t read_size = fread(data, 1, sz, fl); if (read_size != size_t(sz)) { fprintf(stderr, "file '%s' truncated!\n", fullpath.c_str()); memset(data + read_size, 0xee, sz - read_size); } fclose(fl); return RefCountedPtr<FileData>(new FileDataMalloc(MakeFileInfo(path, FileInfo::FT_FILE), sz, data)); } }
std::string GetDataDir(const char *subdir) { static const std::string data_path = FindDataDir(); if (subdir) return JoinPathBelow(data_path, subdir); else return data_path; }
std::string GetUserDir(const char *subdir) { static const std::string user_path = FindUserDir(); if (subdir) return JoinPathBelow(user_path, subdir); else return user_path; }
bool FileSourceFS::ReadDirectory(const std::string &dirpath, std::vector<FileInfo> &output) { const std::string fulldirpath = JoinPathBelow(GetRoot(), dirpath); DIR *dir = opendir(fulldirpath.c_str()); if (!dir) { return false; } struct dirent *entry; const size_t output_head_size = output.size(); while ((entry = readdir(dir))) { if (strcmp(entry->d_name, ".") == 0) continue; if (strcmp(entry->d_name, "..") == 0) continue; const std::string fullpath = JoinPath(fulldirpath, entry->d_name); FileInfo::FileType ty; switch (entry->d_type) { case DT_DIR: ty = FileInfo::FT_DIR; break; case DT_REG: ty = FileInfo::FT_FILE; break; case DT_LNK: case DT_UNKNOWN: { // if readdir() can't tell us whether we've got a file or directory then we need to stat // also stat for links to traverse them struct stat statinfo; if (stat(fullpath.c_str(), &statinfo) == 0) { if (S_ISREG(statinfo.st_mode)) { ty = FileInfo::FT_FILE; } else if (S_ISDIR(statinfo.st_mode)) { ty = FileInfo::FT_DIR; } else { ty = FileInfo::FT_SPECIAL; } } else { // XXX error out here? ty = FileInfo::FT_NON_EXISTENT; } break; } default: ty = FileInfo::FT_SPECIAL; break; } output.push_back(MakeFileInfo(fullpath.substr(GetRoot().size() + 1), ty)); } closedir(dir); std::sort(output.begin() + output_head_size, output.end()); return true; }
RefCountedPtr<FileData> FileSourceFS::ReadFile(const std::string &path) { const std::string fullpath = JoinPathBelow(GetRoot(), path); const std::wstring wfullpath = transcode_utf8_to_utf16(fullpath); HANDLE filehandle = CreateFileW(wfullpath.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (filehandle == INVALID_HANDLE_VALUE) return RefCountedPtr<FileData>(0); else { const Time::DateTime modtime = file_modtime_for_handle(filehandle); LARGE_INTEGER large_size; if (!GetFileSizeEx(filehandle, &large_size)) { Output("failed to get file size for '%s'\n", fullpath.c_str()); CloseHandle(filehandle); abort(); } size_t size = size_t(large_size.QuadPart); char *data = static_cast<char*>(std::malloc(size)); if (!data) { // XXX handling memory allocation failure gracefully is too hard right now Output("failed when allocating buffer for '%s'\n", fullpath.c_str()); CloseHandle(filehandle); abort(); } if (size > 0x7FFFFFFFull) { Output("file '%s' is too large (can't currently cope with files > 2GB)\n", fullpath.c_str()); CloseHandle(filehandle); abort(); } DWORD read_size; BOOL ret = ::ReadFile(filehandle, static_cast<LPVOID>(data), (DWORD)size, &read_size, 0); if (!ret) { Output("error while reading file '%s'\n", fullpath.c_str()); CloseHandle(filehandle); abort(); } if (size_t(read_size) != size) { Output("file '%s' truncated\n", fullpath.c_str()); memset(data + read_size, 0xee, size - read_size); } CloseHandle(filehandle); return RefCountedPtr<FileData>(new FileDataMalloc(MakeFileInfo(path, FileInfo::FT_FILE, modtime), size, data)); } }
FileInfo FileSourceFS::Lookup(const std::string &path) { const std::string fullpath = JoinPathBelow(GetRoot(), path); const std::wstring wfullpath = transcode_utf8_to_utf16(fullpath); DWORD attrs = GetFileAttributesW(wfullpath.c_str()); const FileInfo::FileType ty = file_type_for_attributes(attrs); Time::DateTime modtime; if (ty == FileInfo::FT_FILE || ty == FileInfo::FT_DIR) { HANDLE hfile = CreateFileW(wfullpath.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hfile != INVALID_HANDLE_VALUE) { modtime = file_modtime_for_handle(hfile); CloseHandle(hfile); } } return MakeFileInfo(path, ty, modtime); }
FileInfo FileSourceFS::Lookup(const std::string &path) { const std::string fullpath = JoinPathBelow(GetRoot(), path); struct stat statinfo; FileInfo::FileType ty; if (stat(fullpath.c_str(), &statinfo) == 0) { if (S_ISREG(statinfo.st_mode)) { ty = FileInfo::FT_FILE; } else if (S_ISDIR(statinfo.st_mode)) { ty = FileInfo::FT_DIR; } else { ty = FileInfo::FT_SPECIAL; } } else { ty = FileInfo::FT_NON_EXISTENT; } return MakeFileInfo(path, ty); }
bool FileSourceFS::ReadDirectory(const std::string &dirpath, std::vector<FileInfo> &output) { size_t output_head_size = output.size(); const std::wstring wsearchglob = transcode_utf8_to_utf16(JoinPathBelow(GetRoot(), dirpath)) + L"/*"; WIN32_FIND_DATAW findinfo; HANDLE dirhandle = FindFirstFileW(wsearchglob.c_str(), &findinfo); DWORD err; if (dirhandle == INVALID_HANDLE_VALUE) { err = GetLastError(); // if the directory was empty we succeeded even though FindFirstFile failed return (err == ERROR_FILE_NOT_FOUND); } do { std::string fname = transcode_utf16_to_utf8(findinfo.cFileName, wcslen(findinfo.cFileName)); if (fname != "." && fname != "..") { const FileInfo::FileType ty = file_type_for_attributes(findinfo.dwFileAttributes); const Time::DateTime modtime = datetime_for_filetime(findinfo.ftLastWriteTime); output.push_back(MakeFileInfo(JoinPath(dirpath, fname), ty, modtime)); } if (! FindNextFileW(dirhandle, &findinfo)) { err = GetLastError(); } else err = ERROR_SUCCESS; } while (err == ERROR_SUCCESS); FindClose(dirhandle); if (err != ERROR_NO_MORE_FILES) { output.resize(output_head_size); return false; } std::sort(output.begin() + output_head_size, output.end()); return true; }
bool FileSourceFS::MakeDirectory(const std::string &path) { const std::string fullpath = JoinPathBelow(GetRoot(), path); return make_directory_raw(fullpath); }
FILE* FileSourceFS::OpenWriteStream(const std::string &path, int flags) { const std::string fullpath = JoinPathBelow(GetRoot(), path); return open_file_raw(fullpath, (flags & WRITE_TEXT) ? L"w" : L"wb"); }
FILE* FileSourceFS::OpenReadStream(const std::string &path) { const std::string fullpath = JoinPathBelow(GetRoot(), path); return open_file_raw(fullpath, L"rb"); }
bool FileSourceFS::MakeDirectory(const std::string &path) { const std::string fullpath = JoinPathBelow(GetRoot(), path); const std::wstring wfullpath = transcode_utf8_to_utf16(fullpath); return make_directory_raw(wfullpath); }
FILE* FileSourceFS::OpenWriteStream(const std::string &path, int flags) { const std::string fullpath = JoinPathBelow(GetRoot(), path); return fopen(fullpath.c_str(), (flags & WRITE_TEXT) ? "w" : "wb"); }
FILE* FileSourceFS::OpenReadStream(const std::string &path) { const std::string fullpath = JoinPathBelow(GetRoot(), path); return fopen(fullpath.c_str(), "rb"); }