/** atomically allocate a Message-ID unless it's already present. * to avoid texpire nuking the file right away, you must give another * file name that is linked into the Message-ID directory. * \return * - 0 for success * - 1 if MID already in use * - -1 for OS trouble. */ int msgid_allocate(const char *file /** file to link into message.id */, const char *mid /** Non-NULL Message-ID to allocate */) { char *m = lookup(mid); if (mkdir_parent(m, 0700)) return 0; if (sync_link(file, m) == 0) { return 0; } if (errno == EEXIST) return 1; return -1; }
char* c4pkg_github_download(const char *repo) { if (!repo) { return NULL; } static callback_table_t cbtable = { .print = printf, .notify = NULL, .start = NULL }; char *save = NULL; char *url = c4pkg_github_get_package_url(repo); if (!url) { gitdl_set_error("Failed to get package url"); return NULL; } const char *basename = c4pkg_net_extract_file_from_url(url); if (!basename) { gitdl_set_error("Failed to extract file name from url"); goto fail; } save = string_concat(C4PKG_TMP_PATH, "/", basename, NULL); if (!save) { gitdl_set_error("Internal Error: Failed to generate tmp file path"); goto fail; } if (!mkdir_parent(save, 0755)) { gitdl_set_error("Failed to mkdir for %s: %s", save, strerror(errno)); goto fail; } if (!c4pkg_net_download(save, url, &cbtable, NULL, 10, true, false)) { gitdl_set_error("Failed to download package"); goto fail; } return save; fail: free(url); if (save) { free(save); } return NULL; }
static int mkdir_parent(const wchar_t *path) { // Copy the path to a temporary buffer. wchar_t buffer[4096]; size_t buflen = wcslen(path); if (buflen + 1 >= _countof(buffer)) { return 0; } wcscpy_s(buffer, _countof(buffer), path); // Seek back to find the last path separator. while (buflen-- > 0) { if (buffer[buflen] == '/' || buffer[buflen] == '\\') { buffer[buflen] = 0; break; } } if (buflen == (size_t)-1 || buflen == 0) { // There was no path separator, or this was the root directory. return 0; } if (CreateDirectoryW(buffer, NULL) != 0) { // Success! return 1; } // Failed. DWORD last_error = GetLastError(); if (last_error == ERROR_ALREADY_EXISTS) { // Not really an error: the directory is already there. return 1; } if (last_error == ERROR_PATH_NOT_FOUND) { // We need to make the parent directory first. if (mkdir_parent(buffer)) { // Parent successfully created. Try again to make the child. if (CreateDirectoryW(buffer, NULL) != 0) { // Got it! return 1; } } } return 0; }
static int mkdir_parent(const char *path) { // Copy the path to a temporary buffer. char buffer[4096]; size_t buflen = strlen(path); if (buflen + 1 >= sizeof(buffer)) { return 0; } strcpy(buffer, path); // Seek back to find the last path separator. while (buflen-- > 0) { if (buffer[buflen] == '/') { buffer[buflen] = 0; break; } } if (buflen == (size_t)-1 || buflen == 0) { // There was no path separator, or this was the root directory. return 0; } if (mkdir(buffer, 0755) == 0) { // Success! return 1; } // Failed. if (errno == EEXIST) { // Not really an error: the directory is already there. return 1; } if (errno == ENOENT || errno == EACCES) { // We need to make the parent directory first. if (mkdir_parent(buffer)) { // Parent successfully created. Try again to make the child. if (mkdir(buffer, 0755) == 0) { // Got it! return 1; } } } return 0; }
bool zipentry_extract_to(zipentry_t entry, const char *dir) { if (!entry || !dir) { return false; } const char *name = zipentry_get_name(entry); size_t esz = zipentry_get_size(entry); size_t name_len = strlen(name); size_t dir_len = strlen(dir); if (name_len == 0 || dir_len == 0) { return false; } size_t total = name_len + dir_len + 1; bool increased = false; if (dir[dir_len - 1] != '/') { total++; increased = true; } char *dest_path = (char*) malloc(sizeof(char) * total); if (!dest_path) { return false; } memset(dest_path, '\0', total); strcat(dest_path, dir); if (increased) { // make sure that at least one slash in path string strcat(dest_path, "/"); } strcat(dest_path, name); if (name[name_len - 1] == '/' && esz == 0) { // Is a directory, just create it. bool r = mkdir_recursive(dest_path, 0755); free(dest_path); return r; } if (!mkdir_parent(dest_path, 0755)) { goto fail; } FILE *dest = fopen(dest_path, "wb"); if (!dest) { goto fail; } char *ebuf = (char*) malloc(sizeof(char) * (esz + 1)); if (!ebuf) { goto fail_file; } zipentry_decompress(entry, ebuf, esz); ebuf[esz] = '\0'; fwrite(ebuf, esz, 1, dest); fclose(dest); free(dest_path); return true; fail_file: fclose(dest); fail: free(dest_path); return false; }
/** * Redirects the output streams to point to the log file with the given path. * * @param path specifies the location of log file, may start with ~ * @param append should be nonzero if it should not truncate the log file. */ static int setup_logging(const char *path, int append) { #ifdef _WIN32 // Does it start with a tilde? Perform tilde expansion if so. wchar_t pathw[MAX_PATH * 2]; size_t offset = 0; if (path[0] == '~' && (path[1] == 0 || path[1] == '/' || path[1] == '\\')) { // Strip off the tilde. ++path; // Get the home directory path for the current user. if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, pathw))) { return 0; } offset = wcslen(pathw); } // We need to convert the rest of the path from UTF-8 to UTF-16. if (MultiByteToWideChar(CP_UTF8, 0, path, -1, pathw + offset, (int)(_countof(pathw) - offset)) == 0) { return 0; } DWORD access = append ? FILE_APPEND_DATA : (GENERIC_READ | GENERIC_WRITE); int creation = append ? OPEN_ALWAYS : CREATE_ALWAYS; HANDLE handle = CreateFileW(pathw, access, FILE_SHARE_DELETE | FILE_SHARE_READ, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL); if (handle == INVALID_HANDLE_VALUE) { // Make the parent directories first. mkdir_parent(pathw); handle = CreateFileW(pathw, access, FILE_SHARE_DELETE | FILE_SHARE_READ, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL); } if (handle == INVALID_HANDLE_VALUE) { return 0; } if (append) { SetFilePointer(handle, 0, NULL, FILE_END); } SetStdHandle(STD_OUTPUT_HANDLE, handle); SetStdHandle(STD_ERROR_HANDLE, handle); // If we are running under the UCRT in a GUI application, we can't be sure // that we have valid fds for stdout and stderr, so we have to set them up. // One way to do this is to reopen them to something silly (like NUL). if (_fileno(stdout) < 0) { _close(1); _wfreopen(L"\\\\.\\NUL", L"w", stdout); } if (_fileno(stderr) < 0) { _close(2); _wfreopen(L"\\\\.\\NUL", L"w", stderr); } // Now replace the stdout and stderr file descriptors with one pointing to // our desired handle. int fd = _open_osfhandle((intptr_t)handle, _O_WRONLY | _O_TEXT | (append ? _O_APPEND : 0)); _dup2(fd, _fileno(stdout)); _dup2(fd, _fileno(stderr)); _close(fd); return 1; #else // Does it start with a tilde? Perform tilde expansion if so. char buffer[PATH_MAX * 2]; size_t offset = 0; if (path[0] == '~' && (path[1] == 0 || path[1] == '/')) { // Strip off the tilde. ++path; // Get the home directory path for the current user. const char *home_dir = getenv("HOME"); if (home_dir == NULL) { home_dir = getpwuid(getuid())->pw_dir; } offset = strlen(home_dir); assert(offset < sizeof(buffer)); strncpy(buffer, home_dir, sizeof(buffer)); } // Copy over the rest of the path. strcpy(buffer + offset, path); mode_t mode = O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC); int fd = open(buffer, mode, 0644); if (fd == -1) { // Make the parent directories first. mkdir_parent(buffer); fd = open(buffer, mode, 0644); } if (fd == -1) { perror(buffer); return 0; } fflush(stdout); fflush(stderr); dup2(fd, 1); dup2(fd, 2); close(fd); return 1; #endif }