GF_EXPORT GF_Err gf_move_file(const char *fileName, const char *newFileName) { #if defined(_WIN32_WCE) TCHAR swzName[MAX_PATH]; TCHAR swzNewName[MAX_PATH]; CE_CharToWide((char*)fileName, swzName); CE_CharToWide((char*)newFileName, swzNewName); return (MoveFile(swzName, swzNewName) == 0 ) ? GF_IO_ERR : GF_OK; #elif defined(WIN32) /* success if != 0 */ BOOL op_result; wchar_t* wcsFileName = utf8_to_wcs(fileName); wchar_t* wcsNewFileName = utf8_to_wcs(newFileName); if (!wcsFileName || !wcsNewFileName) { if (wcsFileName) gf_free(wcsFileName); if (wcsNewFileName) gf_free(wcsNewFileName); return GF_IO_ERR; } op_result = MoveFileW(wcsFileName, wcsNewFileName); gf_free(wcsFileName); gf_free(wcsNewFileName); return ( op_result == 0 ) ? GF_IO_ERR : GF_OK; #else GF_Err e = GF_IO_ERR; char cmd[1024], *arg1, *arg2; if (!fileName || !newFileName) return GF_IO_ERR; arg1 = gf_sanetize_single_quoted_string(fileName); arg2 = gf_sanetize_single_quoted_string(newFileName); if (snprintf(cmd, sizeof cmd, "mv %s %s", arg1, arg2) >= sizeof cmd) goto error; #if defined(GPAC_IPHONE) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 80000) { pid_t pid; char *argv[3]; argv[0] = "mv"; argv[1] = cmd; argv[2] = NULL; posix_spawn(&pid, argv[0], NULL, NULL, argv, environ); waitpid(pid, NULL, 0); } #else e = (system(cmd) == 0) ? GF_OK : GF_IO_ERR; #endif error: gf_free(arg1); gf_free(arg2); return e; #endif }
GF_Err gf_rmdir(const char *DirPathName) { #if defined (_WIN32_WCE) TCHAR swzName[MAX_PATH]; BOOL res; CE_CharToWide(DirPathName, swzName); res = RemoveDirectory(swzName); if (! res) { int err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete directory %s: last error %d\n", DirPathName, err )); } #elif defined (WIN32) int res; wchar_t* wcsDirPathName = utf8_to_wcs(DirPathName); if (!wcsDirPathName) return GF_IO_ERR; res = _wrmdir(wcsDirPathName); gf_free(wcsDirPathName); if (res == -1) { int err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete directory %s: last error %d\n", DirPathName, err )); return GF_IO_ERR; } #else int res = rmdir(DirPathName); if (res==-1) { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete directory %s: last error %d\n", DirPathName, errno )); return GF_IO_ERR; } #endif return GF_OK; }
GF_EXPORT Bool gf_dir_exists(const char* DirPathName) { #if defined (_WIN32_WCE) TCHAR swzName[MAX_PATH]; BOOL res; DWORD att; CE_CharToWide(DirPathName, swzName); att = GetFileAttributes(swzName); return (att != INVALID_FILE_ATTRIBUTES && (att & FILE_ATTRIBUTE_DIRECTORY)) ? GF_TRUE : GF_FALSE; #elif defined (WIN32) DWORD att; wchar_t* wcsDirPathName = utf8_to_wcs(DirPathName); if (!wcsDirPathName) return GF_FALSE; att = GetFileAttributesW(wcsDirPathName); gf_free(wcsDirPathName); return (att != INVALID_FILE_ATTRIBUTES && (att & FILE_ATTRIBUTE_DIRECTORY)) ? GF_TRUE : GF_FALSE; #else DIR* dir = opendir(DirPathName); if (!dir) return GF_FALSE; closedir(dir); return GF_TRUE; #endif return GF_FALSE; }
GF_EXPORT GF_Err gf_delete_file(const char *fileName) { if (!fileName) { GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("gf_delete_file deletes nothing - ignoring\n")); return GF_OK; } #if defined(_WIN32_WCE) TCHAR swzName[MAX_PATH]; CE_CharToWide((char*)fileName, swzName); return (DeleteFile(swzName)==0) ? GF_IO_ERR : GF_OK; #elif defined(WIN32) /* success if != 0 */ { BOOL op_result; wchar_t* wcsFileName = utf8_to_wcs(fileName); if (!wcsFileName) return GF_IO_ERR; op_result = DeleteFileW(wcsFileName); gf_free(wcsFileName); return (op_result==0) ? GF_IO_ERR : GF_OK; } #else /* success is == 0 */ return ( remove(fileName) == 0) ? GF_OK : GF_IO_ERR; #endif }
ZipCtx * MinizipUtils::open_output_file(std::string path) { ZipCtx *ctx = new(std::nothrow) ZipCtx(); if (!ctx) { return nullptr; } #if defined(MINIZIP_WIN32) auto converted = utf8_to_wcs(path); if (!converted) { delete ctx; return nullptr; } ctx->path = std::move(converted.value()); fill_win32_filefunc64W(&ctx->buf.filefunc64); #elif defined(MINIZIP_ANDROID) fill_android_filefunc64(&ctx->buf.filefunc64); ctx->path = std::move(path); #else fill_fopen64_filefunc(&ctx->buf.filefunc64); ctx->path = std::move(path); #endif fill_buffer_filefunc64(&ctx->z_func, &ctx->buf); ctx->zf = zipOpen2_64(ctx->path.c_str(), 0, nullptr, &ctx->z_func); if (!ctx->zf) { delete ctx; return nullptr; } return ctx; }
static bool get_file_time(const std::string &filename, uint32_t *dostime) { // Don't fail when building with -Werror (void) filename; (void) dostime; #ifdef _WIN32 FILETIME ft_local; HANDLE h_find; WIN32_FIND_DATAW ff32; auto w_filename = utf8_to_wcs(filename); if (!w_filename) { return false; } h_find = FindFirstFileW(w_filename.value().c_str(), &ff32); if (h_find != INVALID_HANDLE_VALUE) { FileTimeToLocalFileTime(&ff32.ftLastWriteTime, &ft_local); FileTimeToDosDateTime(&ft_local, reinterpret_cast<LPWORD>(dostime) + 1, reinterpret_cast<LPWORD>(dostime) + 0); FindClose(h_find); return true; } else { LOGE("%s: FindFirstFileW() failed: %s", filename.c_str(), ec_from_win32().message().c_str()); } #elif defined unix || defined __APPLE__ || defined __ANDROID__ struct stat sb; struct tm t; if (stat(filename.c_str(), &sb) == 0) { time_t mtime = sb.st_mtime; if (!localtime_r(&mtime, &t)) { LOGE("localtime() failed"); return false; } *dostime = tm_to_dosdate(&t); return true; } else { LOGE("%s: stat() failed: %s", filename.c_str(), strerror(errno)); } #endif return false; }
oc::result<void> FileUtils::open_file(StandardFile &file, const std::string &path, FileOpenMode mode) { #ifdef _WIN32 auto w_filename = utf8_to_wcs(path); if (!w_filename) { LOGE("%s: Failed to convert from UTF8 to WCS: %s", path.c_str(), w_filename.error().message().c_str()); return w_filename.as_failure(); } return file.open(w_filename.value(), mode); #else return file.open(path, mode); #endif }
GF_EXPORT u64 gf_file_modification_time(const char *filename) { #if defined(_WIN32_WCE) WCHAR _file[GF_MAX_PATH]; WIN32_FIND_DATA FindData; HANDLE fh; ULARGE_INTEGER uli; ULONGLONG time_ms; BOOL ret; CE_CharToWide((char *) filename, _file); fh = FindFirstFile(_file, &FindData); if (fh == INVALID_HANDLE_VALUE) return 0; uli.LowPart = FindData.ftLastWriteTime.dwLowDateTime; uli.HighPart = FindData.ftLastWriteTime.dwHighDateTime; ret = FindClose(fh); if (!ret) { DWORD err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_file_modification_time() returned the following error code: %d\n", err)); } time_ms = uli.QuadPart/10000; return time_ms; #elif defined(WIN32) && !defined(__GNUC__) struct _stat64 sb; int op_result; wchar_t* wcsFilename = utf8_to_wcs(filename); if (!wcsFilename) return 0; op_result = _wstat64(wcsFilename, &sb); gf_free(wcsFilename); if (op_result != 0) return 0; return sb.st_mtime; #else struct stat sb; if (stat(filename, &sb) != 0) return 0; return sb.st_mtime; #endif return 0; }
GF_EXPORT GF_Err gf_mkdir(const char* DirPathName) { #if defined (_WIN32_WCE) TCHAR swzName[MAX_PATH]; BOOL res; CE_CharToWide(DirPathName, swzName); res = CreateDirectory(swzName, NULL); if (! res) { int err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, err )); } #elif defined (WIN32) int res; wchar_t* wcsDirPathName = utf8_to_wcs(DirPathName); if (!wcsDirPathName) return GF_IO_ERR; res = _wmkdir(wcsDirPathName); gf_free(wcsDirPathName); if (res==-1) { int err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, err )); } #else int res = mkdir(DirPathName, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); if (res==-1) { if(errno == 17) { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s, it already exists: last error %d \n", DirPathName, errno )); return GF_BAD_PARAM; } else { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, errno )); return GF_IO_ERR; } } #endif return GF_OK; }
/*enumerate directories*/ GF_EXPORT GF_Err gf_enum_directory(const char *dir, Bool enum_directory, gf_enum_dir_item enum_dir_fct, void *cbck, const char *filter) { #ifdef WIN32 wchar_t item_path[GF_MAX_PATH]; #else char item_path[GF_MAX_PATH]; #endif GF_FileEnumInfo file_info; #if defined(_WIN32_WCE) char _path[GF_MAX_PATH]; unsigned short path[GF_MAX_PATH]; unsigned short w_filter[GF_MAX_PATH]; char file[GF_MAX_PATH]; #elif defined(WIN32) wchar_t path[GF_MAX_PATH], *file; wchar_t w_filter[GF_MAX_PATH]; wchar_t w_dir[GF_MAX_PATH]; char *mbs_file, *mbs_item_path; #else char path[GF_MAX_PATH], *file; #endif #ifdef WIN32 WIN32_FIND_DATAW FindData; HANDLE SearchH; #else DIR *the_dir; struct dirent* the_file; struct stat st; #endif if (!dir || !enum_dir_fct) return GF_BAD_PARAM; if (filter && (!strcmp(filter, "*") || !filter[0])) filter=NULL; memset(&file_info, 0, sizeof(GF_FileEnumInfo) ); if (!strcmp(dir, "/")) { #if defined(WIN32) && !defined(_WIN32_WCE) u32 len; char *drives, *volume; len = GetLogicalDriveStrings(0, NULL); drives = (char*)gf_malloc(sizeof(char)*(len+1)); drives[0]=0; GetLogicalDriveStrings(len, drives); len = (u32) strlen(drives); volume = drives; file_info.directory = GF_TRUE; file_info.drive = GF_TRUE; while (len) { enum_dir_fct(cbck, volume, "", &file_info); volume += len+1; len = (u32) strlen(volume); } gf_free(drives); return GF_OK; #elif defined(__SYMBIAN32__) RFs iFs; TDriveList aList; iFs.Connect(); iFs.DriveList(aList); for (TInt i=0; i<KMaxDrives; i++) { if (aList[i]) { char szDrive[10]; TChar aDrive; iFs.DriveToChar(i, aDrive); sprintf(szDrive, "%c:", (TUint)aDrive); enum_dir_fct(cbck, szDrive, "", &file_info); } } iFs.Close(); FlushItemList(); return GF_OK; #endif } #if defined (_WIN32_WCE) switch (dir[strlen(dir) - 1]) { case '/': case '\\': sprintf(_path, "%s*", dir); break; default: sprintf(_path, "%s%c*", dir, GF_PATH_SEPARATOR); break; } CE_CharToWide(_path, path); CE_CharToWide((char *)filter, w_filter); #elif defined(WIN32) { const char* tmpdir = dir; gf_utf8_mbstowcs(w_dir, sizeof(w_dir), &tmpdir); } switch (w_dir[wcslen(w_dir) - 1]) { case '/': case '\\': swprintf(path, MAX_PATH, L"%s*", w_dir); break; default: swprintf(path, MAX_PATH, L"%s%c*", w_dir, GF_PATH_SEPARATOR); break; } { const char* tmpfilter = filter; gf_utf8_mbstowcs(w_filter, sizeof(w_filter), &tmpfilter); } #else strcpy(path, dir); if (path[strlen(path)-1] != '/') strcat(path, "/"); #endif #ifdef WIN32 SearchH= FindFirstFileW(path, &FindData); if (SearchH == INVALID_HANDLE_VALUE) return GF_IO_ERR; #if defined (_WIN32_WCE) _path[strlen(_path)-1] = 0; #else path[wcslen(path)-1] = 0; #endif while (SearchH != INVALID_HANDLE_VALUE) { #else the_dir = opendir(path); if (the_dir == NULL) { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot open directory %s for enumeration: %d\n", path, errno)); return GF_IO_ERR; } the_file = readdir(the_dir); while (the_file) { #endif memset(&file_info, 0, sizeof(GF_FileEnumInfo) ); #if defined (_WIN32_WCE) if (!wcscmp(FindData.cFileName, _T(".") )) goto next; if (!wcscmp(FindData.cFileName, _T("..") )) goto next; #elif defined(WIN32) if (!wcscmp(FindData.cFileName, L".")) goto next; if (!wcscmp(FindData.cFileName, L"..")) goto next; #else if (!strcmp(the_file->d_name, "..")) goto next; if (the_file->d_name[0] == '.') goto next; #endif #ifdef WIN32 file_info.directory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? GF_TRUE : GF_FALSE; if (!enum_directory && file_info.directory) goto next; if (enum_directory && !file_info.directory) goto next; #endif if (filter) { #if defined (_WIN32_WCE) short ext[30]; short *sep = wcsrchr(FindData.cFileName, (wchar_t) '.'); if (!sep) goto next; wcscpy(ext, sep+1); wcslwr(ext); if (!wcsstr(w_filter, ext)) goto next; #elif defined(WIN32) wchar_t ext[30]; wchar_t *sep = wcsrchr(FindData.cFileName, L'.'); if (!sep) goto next; wcscpy(ext, sep+1); wcslwr(ext); if (!wcsstr(w_filter, ext)) goto next; #else char ext[30]; char *sep = strrchr(the_file->d_name, '.'); if (!sep) goto next; strcpy(ext, sep+1); strlwr(ext); if (!strstr(filter, sep+1)) goto next; #endif } #if defined(WIN32) file_info.hidden = (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? GF_TRUE : GF_FALSE; file_info.system = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? GF_TRUE : GF_FALSE; file_info.size = MAXDWORD; file_info.size += 1; file_info.size *= FindData.nFileSizeHigh; file_info.size += FindData.nFileSizeLow; file_info.last_modified = (u64) ((*(LONGLONG *) &FindData.ftLastWriteTime - TIMESPEC_TO_FILETIME_OFFSET) / 10000000); #endif #if defined (_WIN32_WCE) CE_WideToChar(FindData.cFileName, file); strcpy(item_path, _path); strcat(item_path, file); #elif defined(WIN32) wcscpy(item_path, path); wcscat(item_path, FindData.cFileName); file = FindData.cFileName; #else strcpy(item_path, path); strcat(item_path, the_file->d_name); GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Checking file %s for enum\n", item_path)); if (stat( item_path, &st ) != 0) goto next; file_info.directory = ((st.st_mode & S_IFMT) == S_IFDIR) ? GF_TRUE : GF_FALSE; if (enum_directory && !file_info.directory) goto next; if (!enum_directory && file_info.directory) goto next; file_info.size = st.st_size; { struct tm _t = * gmtime(& st.st_mtime); file_info.last_modified = mktime(&_t); } file = the_file->d_name; if (file && file[0]=='.') file_info.hidden = 1; if (file_info.directory) { char * parent_name = strrchr(item_path, '/'); if (!parent_name) { file_info.drive = GF_TRUE; } else { struct stat st_parent; parent_name[0] = 0; if (stat(item_path, &st_parent) == 0) { if ((st.st_dev != st_parent.st_dev) || ((st.st_dev == st_parent.st_dev) && (st.st_ino == st_parent.st_ino))) { file_info.drive = GF_TRUE; } } parent_name[0] = '/'; } } #endif #ifdef WIN32 mbs_file = wcs_to_utf8(file); mbs_item_path = wcs_to_utf8(item_path); if (!mbs_file || !mbs_item_path) { if (mbs_file) gf_free(mbs_file); if (mbs_item_path) gf_free(mbs_item_path); return GF_IO_ERR; } if (enum_dir_fct(cbck, mbs_file, mbs_item_path, &file_info)) { BOOL ret = FindClose(SearchH); if (!ret) { DWORD err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(1) the following error code: %d\n", err)); } #else if (enum_dir_fct(cbck, file, item_path, &file_info)) { #endif break; } #ifdef WIN32 gf_free(mbs_file); gf_free(mbs_item_path); #endif next: #ifdef WIN32 if (!FindNextFileW(SearchH, &FindData)) { BOOL ret = FindClose(SearchH); if (!ret) { DWORD err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(2) the following error code: %d\n", err)); } break; } #else the_file = readdir(the_dir); #endif } #ifndef WIN32 closedir(the_dir); #endif return GF_OK; } GF_EXPORT u64 gf_ftell(FILE *fp) { #if defined(_WIN32_WCE) return (u64) ftell(fp); #elif defined(GPAC_CONFIG_WIN32) && !defined(__CYGWIN__) /* mingw or cygwin */ #if (_FILE_OFFSET_BITS >= 64) return (u64) ftello64(fp); #else return (u64) ftell(fp); #endif #elif defined(WIN32) return (u64) _ftelli64(fp); #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) return (u64) ftello64(fp); #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) return (u64) ftello(fp); #else return (u64) ftell(fp); #endif } GF_EXPORT u64 gf_fseek(FILE *fp, s64 offset, s32 whence) { #if defined(_WIN32_WCE) return (u64) fseek(fp, (s32) offset, whence); #elif defined(GPAC_CONFIG_WIN32) && !defined(__CYGWIN__) /* mingw or cygwin */ #if (_FILE_OFFSET_BITS >= 64) return (u64) fseeko64(fp, offset, whence); #else return (u64) fseek(fp, (s32) offset, whence); #endif #elif defined(WIN32) return (u64) _fseeki64(fp, offset, whence); #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) return fseeko64(fp, (off64_t) offset, whence); #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) return fseeko(fp, (off_t) offset, whence); #else return fseek(fp, (s32) offset, whence); #endif } GF_EXPORT FILE *gf_fopen(const char *file_name, const char *mode) { FILE *res = NULL; #if defined(WIN32) wchar_t *wname; wchar_t *wmode; wname = utf8_to_wcs(file_name); wmode = utf8_to_wcs(mode); if (!wname || !wmode) { if (wname) gf_free(wname); if (wmode) gf_free(wmode); return NULL; } res = _wfsopen(wname, wmode, _SH_DENYNO); gf_free(wname); gf_free(wmode); #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) res = fopen64(file_name, mode); #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) res = fopen(file_name, mode); #else res = fopen(file_name, mode); #endif if (res) { gpac_file_handles++; GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] file %s opened in mode %s - %d file handles\n", file_name, mode, gpac_file_handles)); } else { if (strchr(mode, 'w') || strchr(mode, 'a')) { #if defined(WIN32) u32 err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] system failure for file opening of %s in mode %s: 0x%08x\n", file_name, mode, err)); #else GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] system failure for file opening of %s in mode %s: %d\n", file_name, mode, errno)); #endif } } return res; } GF_EXPORT s32 gf_fclose(FILE *file) { if (file) { assert(gpac_file_handles); gpac_file_handles--; } return fclose(file); } #if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! defined(_GNU_SOURCE) && !defined(WIN32) #define HAVE_STRERROR_R 1 #endif GF_EXPORT size_t gf_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { return fread(ptr, size, nmemb, stream); } GF_EXPORT size_t gf_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t result = fwrite(ptr, size, nmemb, stream); if (result != nmemb) { #ifdef _WIN32_WCE GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data: %d blocks to write but %d blocks written\n", nmemb, result)); #else #if defined WIN32 && !defined(GPAC_CONFIG_WIN32) errno_t errno_save; _get_errno(&errno_save); #else int errno_save = errno; #endif //if (errno_save!=0) { #ifdef HAVE_STRERROR_R #define ERRSTR_BUF_SIZE 256 char errstr[ERRSTR_BUF_SIZE]; if(strerror_r(errno_save, errstr, ERRSTR_BUF_SIZE) != 0) { strerror_r(0, errstr, ERRSTR_BUF_SIZE); } #else char *errstr = (char*)strerror(errno_save); #endif GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data (%s): %d blocks to write but %d blocks written\n", errstr, nmemb, result)); } #endif } return result; }
std::string FileUtils::create_temporary_dir(const std::string &directory) { #ifdef _WIN32 // This Win32 code is adapted from the awesome libuv library (MIT-licensed) // https://github.com/libuv/libuv/blob/v1.x/src/win/fs.c constexpr char possible[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; constexpr size_t num_chars = 62; constexpr size_t num_x = 6; constexpr char suffix[] = "\\mbpatcher-"; HCRYPTPROV h_prov; bool ret = CryptAcquireContext( &h_prov, // phProv nullptr, // pszContainer nullptr, // pszProvider PROV_RSA_FULL, // dwProvType CRYPT_VERIFYCONTEXT // dwFlags ); if (!ret) { LOGE("CryptAcquireContext() failed: %s", ec_from_win32().message().c_str()); return std::string(); } std::string new_path = directory; // Path new_path += suffix; // "\mbpatcher-" new_path.resize(new_path.size() + num_x); // Unique part char *unique = &new_path[new_path.size() - num_x]; unsigned int tries = TMP_MAX; do { uint64_t v; ret = CryptGenRandom( h_prov, // hProv sizeof(v), // dwLen reinterpret_cast<BYTE *>(&v) // pbBuffer ); if (!ret) { LOGE("CryptGenRandom() failed: %s", ec_from_win32().message().c_str()); break; } for (size_t i = 0; i < num_x; ++i) { unique[i] = possible[v % num_chars]; v /= num_chars; } // This is not particularly fast, but it'll do for now auto w_new_path = utf8_to_wcs(new_path); if (!w_new_path) { LOGE("Failed to convert UTF-8 to WCS: %s", w_new_path.error().message().c_str()); break; } ret = CreateDirectoryW( w_new_path.value().c_str(), // lpPathName nullptr // lpSecurityAttributes ); if (ret) { break; } else if (GetLastError() != ERROR_ALREADY_EXISTS) { LOGE("CreateDirectoryW() failed: %s", ec_from_win32().message().c_str()); new_path.clear(); break; } } while (--tries); bool released = CryptReleaseContext( h_prov, // hProv 0 // dwFlags ); assert(released); return new_path; #else std::string dir_template(directory); dir_template += "/mbpatcher-XXXXXX"; if (mkdtemp(&dir_template[0])) { return dir_template; } return {}; #endif }