return mkstemp(path);
}
+/* git_mkstemps() - create tmp file with suffix honoring TMPDIR variable. */
+int git_mkstemps(char *path, size_t len, const char *template, int suffix_len)
+{
+ const char *tmp;
+ size_t n;
+
+ tmp = getenv("TMPDIR");
+ if (!tmp)
+ tmp = "/tmp";
+ n = snprintf(path, len, "%s/%s", tmp, template);
+ if (len <= n) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ return mkstemps(path, suffix_len);
+}
int validate_headref(const char *path)
{
return NULL;
}
-int adjust_shared_perm(const char *path)
+int set_shared_perm(const char *path, int mode)
{
struct stat st;
- int mode;
+ int tweak, shared, orig_mode;
- if (!shared_repository)
+ if (!shared_repository) {
+ if (mode)
+ return chmod(path, mode & ~S_IFMT);
return 0;
- if (lstat(path, &st) < 0)
- return -1;
- mode = st.st_mode;
-
- if (shared_repository) {
- int tweak = shared_repository;
- if (!(mode & S_IWUSR))
- tweak &= ~0222;
- mode |= tweak;
- } else {
- /* Preserve old PERM_UMASK behaviour */
- if (mode & S_IWUSR)
- mode |= S_IWGRP;
}
+ if (!mode) {
+ if (lstat(path, &st) < 0)
+ return -1;
+ mode = st.st_mode;
+ orig_mode = mode;
+ } else
+ orig_mode = 0;
+ if (shared_repository < 0)
+ shared = -shared_repository;
+ else
+ shared = shared_repository;
+ tweak = shared;
+
+ if (!(mode & S_IWUSR))
+ tweak &= ~0222;
+ if (mode & S_IXUSR)
+ /* Copy read bits to execute bits */
+ tweak |= (tweak & 0444) >> 2;
+ if (shared_repository < 0)
+ mode = (mode & ~0777) | tweak;
+ else
+ mode |= tweak;
if (S_ISDIR(mode)) {
- mode |= FORCE_DIR_SET_GID;
-
/* Copy read bits to execute bits */
- mode |= (shared_repository & 0444) >> 2;
+ mode |= (shared & 0444) >> 2;
+ mode |= FORCE_DIR_SET_GID;
}
- if ((mode & st.st_mode) != mode && chmod(path, mode) < 0)
+ if (((shared_repository < 0
+ ? (orig_mode & (FORCE_DIR_SET_GID | 0777))
+ : (orig_mode & mode)) != mode) &&
+ chmod(path, (mode & ~S_IFMT)) < 0)
return -2;
return 0;
}
return max_len;
}
+
+/* strip arbitrary amount of directory separators at end of path */
+static inline int chomp_trailing_dir_sep(const char *path, int len)
+{
+ while (len && is_dir_sep(path[len - 1]))
+ len--;
+ return len;
+}
+
+/*
+ * If path ends with suffix (complete path components), returns the
+ * part before suffix (sans trailing directory separators).
+ * Otherwise returns NULL.
+ */
+char *strip_path_suffix(const char *path, const char *suffix)
+{
+ int path_len = strlen(path), suffix_len = strlen(suffix);
+
+ while (suffix_len) {
+ if (!path_len)
+ return NULL;
+
+ if (is_dir_sep(path[path_len - 1])) {
+ if (!is_dir_sep(suffix[suffix_len - 1]))
+ return NULL;
+ path_len = chomp_trailing_dir_sep(path, path_len);
+ suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
+ }
+ else if (path[--path_len] != suffix[--suffix_len])
+ return NULL;
+ }
+
+ if (path_len && !is_dir_sep(path[path_len - 1]))
+ return NULL;
+ return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
+}
+
+int daemon_avoid_alias(const char *p)
+{
+ int sl, ndot;
+
+ /*
+ * This resurrects the belts and suspenders paranoia check by HPA
+ * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
+ * does not do getcwd() based path canonicalizations.
+ *
+ * sl becomes true immediately after seeing '/' and continues to
+ * be true as long as dots continue after that without intervening
+ * non-dot character.
+ */
+ if (!p || (*p != '/' && *p != '~'))
+ return -1;
+ sl = 1; ndot = 0;
+ p++;
+
+ while (1) {
+ char ch = *p++;
+ if (sl) {
+ if (ch == '.')
+ ndot++;
+ else if (ch == '/') {
+ if (ndot < 3)
+ /* reject //, /./ and /../ */
+ return -1;
+ ndot = 0;
+ }
+ else if (ch == 0) {
+ if (0 < ndot && ndot < 3)
+ /* reject /.$ and /..$ */
+ return -1;
+ return 0;
+ }
+ else
+ sl = ndot = 0;
+ }
+ else if (ch == 0)
+ return 0;
+ else if (ch == '/') {
+ sl = 1;
+ ndot = 0;
+ }
+ }
+}