Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
12 kB · 563 lines
C++
at android
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564/*This file is part of Darling.
Copyright (C) 2012-2013 Lubos Dolezel
Darling is free software: you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or(at your option) any later version.
Darling is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.
You should have received a copy of the GNU General Public Licensealong with Darling. If not, see <http://www.gnu.org/licenses/>.*/
#include "FileManager.h"#include <cstdlib>#include <string>#include <cstring>#include <sys/stat.h>#include <sys/types.h>#include <unistd.h>#include <algorithm>#include <memory>#include <errno.h>#include <iconv.h>#include <alloca.h>#include <libgen.h>#include <sstream>#include <fstream>#include <map>#include <regex.h>#include <fcntl.h>#include <vector>#include "DateTimeUtils.h"#include <errno.h>
#define STUB() // TODO
// Doesn't resolve the last symlink// Mallocates a new bufferstatic char* realpath_ns(const char* path);/*static*/ bool FSRefMakePath(const FSRef* ref, std::string& out);static bool FSRefParamMakePath(const FSRefParam* param, std::string& out);// Is the current user member of the specified group?static bool hasgid(gid_t gid);
static bool string_endsWith(const std::string& str, const std::string& what){ if (str.size() < what.size()) return false; else return str.compare(str.size()-what.size(), what.size(), what) == 0;}
static std::vector<std::string> string_explode(const std::string& str, char delim, bool keepEmpty){ std::vector<std::string> rv; size_t start = 0, end;
do { std::string substr;
end = str.find(delim, start); substr = str.substr(start, (end != std::string::npos) ? end-start : std::string::npos);
if (keepEmpty || !substr.empty()) rv.push_back(substr); start = end+1; } while (end != std::string::npos);
return rv;}
OSStatus FSPathMakeRef(const uint8_t* path, FSRef* fsref, Boolean* isDirectory){ return FSPathMakeRefWithOptions(path, kFSPathMakeRefDoNotFollowLeafSymlink, fsref, isDirectory); }
OSStatus FSPathMakeRefWithOptions(const uint8_t* path, long options, FSRef* fsref, Boolean* isDirectory){ if (!path || !fsref) return paramErr;
std::string fullPath; char* rpath; if (options & kFSPathMakeRefDoNotFollowLeafSymlink) rpath = realpath_ns(reinterpret_cast<const char*>(path)); else rpath = realpath(reinterpret_cast<const char*>(path), nullptr);
if (!rpath) return fnfErr; if (std::count(rpath, rpath+strlen(rpath), '/') > FSRef_MAX_DEPTH) { free(rpath); return unimpErr; }
fullPath = rpath; free(rpath);
memset(fsref, 0, sizeof(*fsref));
if (fullPath == "/") { if (isDirectory) *isDirectory = true; return noErr; }
std::vector<std::string> components = string_explode(fullPath, '/', false); std::string position = "/"; size_t pos;
for (size_t pos = 0; pos < components.size(); pos++) { bool found = false; struct dirent* ent;
DIR* dir = opendir(position.c_str()); if (!dir) return makeOSStatus(errno);
while ((ent = readdir(dir))) { if (components[pos] == ent->d_name) { found = true; fsref->inodes[pos] = ent->d_ino;
if (pos+1 == components.size() && isDirectory != nullptr) *isDirectory = ent->d_type == DT_DIR; break; } }
closedir(dir);
if (!found) return fnfErr;
if (!string_endsWith(position, "/")) position += '/'; position += components[pos];
pos++; }
return noErr; }
char* realpath_ns(const char* path){ char *dup1, *dup2; char *dname, *bname; char *real, *complete;
dup1 = strdup(path); dup2 = strdup(path); dname = dirname(dup1); bname = basename(dup2);
real = realpath(dname, nullptr); complete = (char*) malloc(strlen(real) + strlen(bname) + 2);
strcpy(complete, real); if (strrchr(complete, '/') != complete+strlen(complete)-1) strcat(complete, "/"); strcat(complete, bname);
free(real); free(dup1); free(dup2);
return complete;}
bool FSRefMakePath(const FSRef* fsref, std::string& out){ out = '/'; for (int i = 0; i < FSRef_MAX_DEPTH && fsref->inodes[i] != 0; i++) { ino_t inode = fsref->inodes[i]; DIR* dir = opendir(out.c_str()); struct dirent* ent; bool found = false;
while ((ent = readdir(dir))) { if (strcmp(ent->d_name, "..") == 0 || strcmp(ent->d_name, ".") == 0) continue; if (ent->d_ino == inode) { found = true; if (!string_endsWith(out, "/")) out += '/'; out += ent->d_name; } }
closedir(dir);
if (!found) return false; } return true;}
bool FSRefParamMakePath(const FSRefParam* param, std::string& out){ std::string dir; CFStringRef str; std::unique_ptr<char[]> buf; size_t bufsize; Boolean success; if (!FSRefMakePath(param->ref, dir)) return false; out = dir; if (out.back() != '/') out += '/'; str = CFStringCreateWithCharacters(NULL, param->name, param->nameLength); bufsize = CFStringGetLength(str)*4+1; buf.reset(new char[bufsize]); success = CFStringGetCString(str, buf.get(), bufsize, kCFStringEncodingUTF8); CFRelease(str); if (success) { out += buf.get(); return true; } else return false;}
OSStatus FSRefMakePath(const FSRef* fsref, uint8_t* path, uint32_t maxSize){ std::string rpath;
if (!fsref || !path || !maxSize) return paramErr;
if (!FSRefMakePath(fsref, rpath)) return fnfErr;
strncpy((char*) path, rpath.c_str(), maxSize); path[maxSize-1] = 0;
return noErr;}
OSStatus FSGetCatalogInfo(const FSRef* ref, uint32_t infoBits, FSCatalogInfo* infoOut, HFSUniStr255* nameOut, FSSpecPtr fsspec, FSRef* parentDir){ std::string path;
if (!FSRefMakePath(ref, path)) return fnfErr;
if (nameOut) { CFStringRef cfstr = CFStringCreateWithCString(NULL, path.c_str(), kCFStringEncodingUTF8); nameOut->length = std::min<size_t>(path.length(), 255); CFStringGetCharacters(cfstr, CFRangeMake(0, nameOut->length), nameOut->unicode); CFRelease(cfstr); }
if (parentDir) { memcpy(parentDir, ref, sizeof(FSRef)); ino_t* last = std::find(parentDir->inodes, parentDir->inodes+FSRef_MAX_DEPTH, 0);
if (last != parentDir->inodes) *(last-1) = 0; }
if (infoOut && infoBits != kFSCatInfoNone) { struct stat st;
memset(infoOut, 0, sizeof(*infoOut));
if (::stat(path.c_str(), &st) != 0) return makeOSStatus(errno);
if (infoBits & kFSCatInfoNodeFlags) { if (S_ISDIR(st.st_mode)) infoOut->nodeFlags = 4; } if (infoBits & (kFSCatInfoParentDirID|kFSCatInfoNodeID)) { if (infoBits & kFSCatInfoNodeID) infoOut->nodeID = ref->inodes[0]; for (int i = FSRef_MAX_DEPTH-1; i > 0; i--) { if (ref->inodes[i] == 0) continue; if (infoBits & kFSCatInfoParentDirID) infoOut->parentDirID = ref->inodes[i-1]; if (infoBits & kFSCatInfoNodeID) infoOut->nodeID = ref->inodes[i]; } }
if (infoBits & kFSCatInfoDataSizes) { infoOut->dataLogicalSize = st.st_size; infoOut->dataPhysicalSize = st.st_blocks*512; } int uaccess; if (st.st_uid == getuid()) uaccess = st.st_mode & 0700; else if (hasgid(st.st_gid)) uaccess = st.st_mode & 070; else uaccess = st.st_mode & 07;
if (infoBits & kFSCatInfoPermissions) { const uid_t uid = getuid();
infoOut->fsPermissionInfo.userID = st.st_uid; infoOut->fsPermissionInfo.groupID = st.st_gid; infoOut->fsPermissionInfo.mode = st.st_mode & 07777; infoOut->fsPermissionInfo.userAccess = uaccess; }
if (infoBits & kFSCatInfoUserPrivs) { if (!(uaccess & 2)) infoOut->userPrivileges |= 0x4; // kioACUserNoMakeChangesMask if (getuid() != st.st_uid) infoOut->userPrivileges |= 0x80; // kioACUserNotOwnerMask } if (infoBits & kFSCatInfoCreateDate) infoOut->createDate = Darling::time_tToUTC(st.st_ctime); if (infoBits & kFSCatInfoContentMod) infoOut->attributeModDate = infoOut->contentModDate = Darling::time_tToUTC(st.st_mtime); if (infoBits & kFSCatInfoAccessDate) infoOut->accessDate = Darling::time_tToUTC(st.st_atime); }
return noErr;}
bool hasgid(gid_t gid){ gid_t* gids; int count;
if (getegid() == gid) return true;
while (true) { count = getgroups(0, nullptr); if (count == -1 && errno == EINVAL) continue;
gids = (gid_t*) alloca(sizeof(gid_t)*count); if (getgroups(count, gids) != count) { count = 0; break; } }
return std::find(gids, gids+count, gid) != (gids+count);}
static std::string getUserDirsConfigPath(){ std::stringstream ss; const char *home, *config; config = getenv("XDG_CONFIG_HOME"); if (!config) { home = getenv("HOME"); if (!home) return std::string(); ss << home << "/.config"; } else ss << config; ss << "user-dirs.dirs"; return ss.str();}
static std::string extractXDGValue(const char* home, const std::string& line){ regmatch_t matches[2]; static regex_t regexp = []() -> regex_t { regex_t re; regcomp(&re, "=\"([^\"]+)\"", REG_EXTENDED); return re; }(); if (regexec(®exp, line.c_str(), 2, matches, 0) == 0) { std::string value = line.substr(matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so); size_t pos = value.find("$HOME"); if (pos != std::string::npos) value.replace(pos, 5, home); return value; } return std::string();}
// TODO: Test this function!OSStatus FSFindFolder(long vRefNum, OSType folderType, Boolean createFolder, FSRef* location){ if (folderType == kTemporaryFolderType) { const char* tmpdir = getenv("TMPDIR"); if (!tmpdir) tmpdir = "/tmp"; FSPathMakeRef((const uint8_t*) tmpdir, location, nullptr); if (createFolder && access(tmpdir, F_OK) != 0) mkdir(tmpdir, 0777); return noErr; } else if (folderType == kDesktopFolderType || folderType == kSystemDesktopFolderType) { std::string xdgConfig = getUserDirsConfigPath(); std::ifstream cfg(xdgConfig.c_str()); std::string line, desktop; const char* home = getenv("HOME"); desktop = home; desktop += "/Desktop"; if (cfg.is_open()) { while (std::getline(cfg, line)) { if (line.compare(0, 17, "XDG_DESKTOP_DIR=\"") == 0) { std::string d = extractXDGValue(home, line); if (!d.empty()) desktop = d; break; } } } FSPathMakeRef((const uint8_t*) desktop.c_str(), location, nullptr); if (createFolder && access(desktop.c_str(), F_OK) != 0) mkdir(desktop.c_str(), 0777); return noErr; } else return unimpErr;}
OSErr PBCreateDirectoryUnicodeSync(FSRefParam* paramBlock){ std::string path; if (!FSRefParamMakePath(paramBlock, path)) return fnfErr; if (mkdir(path.c_str(), 0777) == -1) return makeOSStatus(errno); if (paramBlock->newRef) FSPathMakeRef((uint8_t*) path.c_str(), paramBlock->newRef, nullptr); return noErr;}
OSErr PBCreateFileUnicodeSync(FSRefParam* paramBlock){ std::string path; if (!FSRefParamMakePath(paramBlock, path)) return fnfErr; if (open(path.c_str(), O_CREAT|O_EXCL, 0666) == -1) return makeOSStatus(errno); if (paramBlock->newRef) FSPathMakeRef((uint8_t*) path.c_str(), paramBlock->newRef, nullptr); return noErr;}
OSErr PBGetCatalogInfoSync(FSRefParam *paramBlock){ STUB(); return unimpErr;}
OSErr PBMakeFSRefUnicodeSync(FSRefParam *paramBlock){ std::string path; if (!paramBlock->newRef) return paramErr; if (!FSRefParamMakePath(paramBlock, path)) return fnfErr; FSPathMakeRef((uint8_t*) path.c_str(), paramBlock->newRef, nullptr); return noErr;}
OSErr PBOpenForkSync(FSForkIOParam *paramBlock){ STUB(); return unimpErr;}
OSErr PBReadForkSync(FSForkIOParam *paramBlock){ STUB(); return unimpErr;}
OSErr PBWriteForkSync(FSForkIOParam *paramBlock){ STUB(); return unimpErr;}
OSErr PBIterateForksSync(FSForkIOParam *paramBlock){ STUB(); return unimpErr;}
OSErr PBCloseForkSync(FSForkIOParam *paramBlock){ STUB(); return unimpErr;}