void test_core_buffer__rfind_variants(void) { git_buf a = GIT_BUF_INIT; ssize_t len; cl_git_pass(git_buf_sets(&a, "/this/is/it/")); len = (ssize_t)git_buf_len(&a); cl_assert(git_buf_rfind(&a, '/') == len - 1); cl_assert(git_buf_rfind_next(&a, '/') == len - 4); cl_assert(git_buf_rfind(&a, 'i') == len - 3); cl_assert(git_buf_rfind_next(&a, 'i') == len - 3); cl_assert(git_buf_rfind(&a, 'h') == 2); cl_assert(git_buf_rfind_next(&a, 'h') == 2); cl_assert(git_buf_rfind(&a, 'q') == -1); cl_assert(git_buf_rfind_next(&a, 'q') == -1); git_buf_free(&a); }
int git_futils_mkdir( const char *path, const char *base, mode_t mode, uint32_t flags) { int error = -1; git_buf make_path = GIT_BUF_INIT; ssize_t root = 0, min_root_len; char lastch = '/', *tail; struct stat st; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&make_path, path, base, &root) < 0) return -1; if (make_path.size == 0) { giterr_set(GITERR_OS, "Attempt to create empty path"); goto done; } /* remove trailing slashes on path */ while (make_path.ptr[make_path.size - 1] == '/') { make_path.size--; make_path.ptr[make_path.size] = '\0'; } /* if we are not supposed to made the last element, truncate it */ if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) { git_buf_rtruncate_at_char(&make_path, '/'); flags |= GIT_MKDIR_SKIP_LAST; } if ((flags & GIT_MKDIR_SKIP_LAST) != 0) git_buf_rtruncate_at_char(&make_path, '/'); /* if nothing left after truncation, then we're done! */ if (!make_path.size) { error = 0; goto done; } /* if we are not supposed to make the whole path, reset root */ if ((flags & GIT_MKDIR_PATH) == 0) root = git_buf_rfind(&make_path, '/'); /* advance root past drive name or network mount prefix */ min_root_len = git_path_root(make_path.ptr); if (root < min_root_len) root = min_root_len; while (root >= 0 && make_path.ptr[root] == '/') ++root; /* clip root to make_path length */ if (root > (ssize_t)make_path.size) root = (ssize_t)make_path.size; /* i.e. NUL byte of string */ if (root < 0) root = 0; /* walk down tail of path making each directory */ for (tail = &make_path.ptr[root]; *tail; *tail = lastch) { /* advance tail to include next path component */ while (*tail == '/') tail++; while (*tail && *tail != '/') tail++; /* truncate path at next component */ lastch = *tail; *tail = '\0'; st.st_mode = 0; /* make directory */ if (p_mkdir(make_path.ptr, mode) < 0) { int tmp_errno = giterr_system_last(); /* ignore error if not at end or if directory already exists */ if (lastch == '\0' && (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) { giterr_system_set(tmp_errno); giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); goto done; } /* with exclusive create, existing dir is an error */ if ((flags & GIT_MKDIR_EXCL) != 0) { giterr_set(GITERR_OS, "Directory already exists '%s'", make_path.ptr); error = GIT_EEXISTS; goto done; } } /* chmod if requested and necessary */ if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 || (lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) && st.st_mode != mode && (error = p_chmod(make_path.ptr, mode)) < 0 && lastch == '\0') { giterr_set(GITERR_OS, "Failed to set permissions on '%s'", make_path.ptr); goto done; } } error = 0; /* check that full path really is a directory if requested & needed */ if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && lastch != '\0' && (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) { giterr_set(GITERR_OS, "Path is not a directory '%s'", make_path.ptr); error = GIT_ENOTFOUND; } done: git_buf_free(&make_path); return error; }
static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix) { ssize_t idx = git_buf_rfind(key, '.'); git_buf_truncate(key, (size_t)(idx + 1)); return git_buf_puts(key, suffix); }
int git_futils_mkdir_relative( const char *relative_path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts) { git_buf make_path = GIT_BUF_INIT; ssize_t root = 0, min_root_len; char lastch = '/', *tail; struct stat st; struct git_futils_mkdir_options empty_opts = {0}; int error; if (!opts) opts = &empty_opts; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&make_path, relative_path, base, &root) < 0) return -1; if ((error = mkdir_canonicalize(&make_path, flags)) < 0 || make_path.size == 0) goto done; /* if we are not supposed to make the whole path, reset root */ if ((flags & GIT_MKDIR_PATH) == 0) root = git_buf_rfind(&make_path, '/'); /* advance root past drive name or network mount prefix */ min_root_len = git_path_root(make_path.ptr); if (root < min_root_len) root = min_root_len; while (root >= 0 && make_path.ptr[root] == '/') ++root; /* clip root to make_path length */ if (root > (ssize_t)make_path.size) root = (ssize_t)make_path.size; /* i.e. NUL byte of string */ if (root < 0) root = 0; /* walk down tail of path making each directory */ for (tail = &make_path.ptr[root]; *tail; *tail = lastch) { bool mkdir_attempted = false; /* advance tail to include next path component */ while (*tail == '/') tail++; while (*tail && *tail != '/') tail++; /* truncate path at next component */ lastch = *tail; *tail = '\0'; st.st_mode = 0; if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr)) continue; /* See what's going on with this path component */ opts->perfdata.stat_calls++; retry_lstat: if (p_lstat(make_path.ptr, &st) < 0) { if (mkdir_attempted || errno != ENOENT) { giterr_set(GITERR_OS, "cannot access component in path '%s'", make_path.ptr); error = -1; goto done; } giterr_clear(); opts->perfdata.mkdir_calls++; mkdir_attempted = true; if (p_mkdir(make_path.ptr, mode) < 0) { if (errno == EEXIST) goto retry_lstat; giterr_set(GITERR_OS, "failed to make directory '%s'", make_path.ptr); error = -1; goto done; } } else { if ((error = mkdir_validate_dir( make_path.ptr, &st, mode, flags, opts)) < 0) goto done; } /* chmod if requested and necessary */ if ((error = mkdir_validate_mode( make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0) goto done; if (opts->dir_map && opts->pool) { char *cache_path; size_t alloc_size; GITERR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1); if (!git__is_uint32(alloc_size)) return -1; cache_path = git_pool_malloc(opts->pool, (uint32_t)alloc_size); GITERR_CHECK_ALLOC(cache_path); memcpy(cache_path, make_path.ptr, make_path.size + 1); git_strmap_insert(opts->dir_map, cache_path, cache_path, &error); if (error < 0) goto done; } } error = 0; /* check that full path really is a directory if requested & needed */ if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && lastch != '\0') { opts->perfdata.stat_calls++; if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) { giterr_set(GITERR_OS, "path is not a directory '%s'", make_path.ptr); error = GIT_ENOTFOUND; } } done: git_buf_free(&make_path); return error; }
int git_futils_mkdir_ext( const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts) { int error = -1; git_buf make_path = GIT_BUF_INIT; ssize_t root = 0, min_root_len, root_len; char lastch = '/', *tail; struct stat st; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&make_path, path, base, &root) < 0) return -1; if (make_path.size == 0) { giterr_set(GITERR_OS, "Attempt to create empty path"); goto done; } /* Trim trailing slashes (except the root) */ if ((root_len = git_path_root(make_path.ptr)) < 0) root_len = 0; else root_len++; while (make_path.size > (size_t)root_len && make_path.ptr[make_path.size - 1] == '/') make_path.ptr[--make_path.size] = '\0'; /* if we are not supposed to made the last element, truncate it */ if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) { git_path_dirname_r(&make_path, make_path.ptr); flags |= GIT_MKDIR_SKIP_LAST; } if ((flags & GIT_MKDIR_SKIP_LAST) != 0) { git_path_dirname_r(&make_path, make_path.ptr); } /* We were either given the root path (or trimmed it to * the root), we don't have anything to do. */ if (make_path.size <= (size_t)root_len) { error = 0; goto done; } /* if we are not supposed to make the whole path, reset root */ if ((flags & GIT_MKDIR_PATH) == 0) root = git_buf_rfind(&make_path, '/'); /* advance root past drive name or network mount prefix */ min_root_len = git_path_root(make_path.ptr); if (root < min_root_len) root = min_root_len; while (root >= 0 && make_path.ptr[root] == '/') ++root; /* clip root to make_path length */ if (root > (ssize_t)make_path.size) root = (ssize_t)make_path.size; /* i.e. NUL byte of string */ if (root < 0) root = 0; /* walk down tail of path making each directory */ for (tail = &make_path.ptr[root]; *tail; *tail = lastch) { /* advance tail to include next path component */ while (*tail == '/') tail++; while (*tail && *tail != '/') tail++; /* truncate path at next component */ lastch = *tail; *tail = '\0'; st.st_mode = 0; if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr)) continue; /* See what's going on with this path component */ opts->perfdata.stat_calls++; if (p_lstat(make_path.ptr, &st) < 0) { opts->perfdata.mkdir_calls++; if (errno != ENOENT || p_mkdir(make_path.ptr, mode) < 0) { giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); error = GIT_EEXISTS; goto done; } giterr_clear(); } else { /* with exclusive create, existing dir is an error */ if ((flags & GIT_MKDIR_EXCL) != 0) { giterr_set(GITERR_FILESYSTEM, "Failed to make directory '%s': directory exists", make_path.ptr); error = GIT_EEXISTS; goto done; } if ((error = validate_existing( make_path.ptr, &st, mode, flags, &opts->perfdata)) < 0) goto done; } /* chmod if requested and necessary */ if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 || (lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) && st.st_mode != mode) { opts->perfdata.chmod_calls++; if ((error = p_chmod(make_path.ptr, mode)) < 0 && lastch == '\0') { giterr_set(GITERR_OS, "Failed to set permissions on '%s'", make_path.ptr); goto done; } } if (opts->dir_map && opts->pool) { char *cache_path; size_t alloc_size; GITERR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1); if (!git__is_uint32(alloc_size)) return -1; cache_path = git_pool_malloc(opts->pool, (uint32_t)alloc_size); GITERR_CHECK_ALLOC(cache_path); memcpy(cache_path, make_path.ptr, make_path.size + 1); git_strmap_insert(opts->dir_map, cache_path, cache_path, error); if (error < 0) goto done; } } error = 0; /* check that full path really is a directory if requested & needed */ if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && lastch != '\0') { opts->perfdata.stat_calls++; if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) { giterr_set(GITERR_OS, "Path is not a directory '%s'", make_path.ptr); error = GIT_ENOTFOUND; } } done: git_buf_free(&make_path); return error; }
int git_futils_mkdir( const char *path, const char *base, mode_t mode, uint32_t flags) { git_buf make_path = GIT_BUF_INIT; ssize_t root = 0; char lastch, *tail; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&make_path, path, base, &root) < 0) return -1; if (make_path.size == 0) { giterr_set(GITERR_OS, "Attempt to create empty path"); goto fail; } /* remove trailing slashes on path */ while (make_path.ptr[make_path.size - 1] == '/') { make_path.size--; make_path.ptr[make_path.size] = '\0'; } /* if we are not supposed to made the last element, truncate it */ if ((flags & GIT_MKDIR_SKIP_LAST) != 0) git_buf_rtruncate_at_char(&make_path, '/'); /* if we are not supposed to make the whole path, reset root */ if ((flags & GIT_MKDIR_PATH) == 0) root = git_buf_rfind(&make_path, '/'); /* clip root to make_path length */ if (root >= (ssize_t)make_path.size) root = (ssize_t)make_path.size - 1; if (root < 0) root = 0; tail = & make_path.ptr[root]; while (*tail) { /* advance tail to include next path component */ while (*tail == '/') tail++; while (*tail && *tail != '/') tail++; /* truncate path at next component */ lastch = *tail; *tail = '\0'; /* make directory */ if (p_mkdir(make_path.ptr, mode) < 0 && (errno != EEXIST || (flags & GIT_MKDIR_EXCL) != 0)) { giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); goto fail; } /* chmod if requested */ if ((flags & GIT_MKDIR_CHMOD_PATH) != 0 || ((flags & GIT_MKDIR_CHMOD) != 0 && lastch == '\0')) { if (p_chmod(make_path.ptr, mode) < 0) { giterr_set(GITERR_OS, "Failed to set permissions on '%s'", make_path.ptr); goto fail; } } *tail = lastch; } git_buf_free(&make_path); return 0; fail: git_buf_free(&make_path); return -1; }