From: "Bradford C. Smith" <bradford.carl.smith@gmail.com>
To: git@vger.kernel.org
Cc: Junio C Hamano <gitster@pobox.com>,
"Bradford C. Smith" <bradford.carl.smith@gmail.com>
Subject: [PATCH 1/2] resolve symlinks when creating lockfiles
Date: Wed, 25 Jul 2007 12:49:52 -0400 [thread overview]
Message-ID: <11853821951367-git-send-email-bradford.carl.smith@gmail.com> (raw)
In-Reply-To: <11853821932079-git-send-email-bradford.carl.smith@gmail.com>
From: Bradford C. Smith <bradford.carl.smith@gmail.com>
Without this fix, the lockfile code will replace a symlink with a real file.
Signed-off-by: "Bradford C. Smith" <bradford.carl.smith@gmail.com>
---
lockfile.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 86 insertions(+), 1 deletions(-)
diff --git a/lockfile.c b/lockfile.c
index fb8f13b..4c35224 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -25,10 +25,95 @@ static void remove_lock_file_on_signal(int signo)
raise(signo);
}
+/**
+ * p = absolute or relative path name
+ *
+ * Return a pointer into p showing the beginning of the last path name
+ * element. If p is empty or the root directory ("/"), just return p.
+ */
+static char * last_path_elm(char * p)
+{
+ int p_len = strlen(p);
+ char * r;
+
+ if (p_len < 1) return p;
+ /* r points to last non-null character in p */
+ r = p + p_len - 1;
+ /* first skip any trailing slashes */
+ while (*r == '/' && r > p) r--;
+ /* then go back to the first non-slash */
+ while (r > p && *(r-1) != '/') r--;
+ return r;
+}
+
+/**
+ * p = char array containing path to existing file or symlink
+ * s = size of p
+ *
+ * If p indicates a valid symlink to an existing file, overwrite p with
+ * the path to the real file. Otherwise, leave p unmodified.
+ *
+ * Always returns p in any case.
+ *
+ * NOTE: This is a best-effort routine. It will give no indication of
+ * failure if it is unable to fully resolve p. However, it is
+ * guaranteed to leave p in one of the following states if there isn't
+ * enough room in p or some other failure occurs:
+ *
+ * 1. unmodified
+ * OR
+ * 2. path to a different symlink in a chain that eventually leads to a
+ * real file or directory.
+ */
+static char * resolve_symlink(char * p, size_t s)
+{
+ struct stat st;
+ char link[PATH_MAX];
+ int link_len;
+
+ /* To avoid an infinite loop of symlinks, try a normal stat()
+ * first. This will fail if p is a symlink that cannot be
+ * resolved, so we won't waste our time following a bad link. */
+ if (stat(p, &st)) return p;
+ /* if I can stat() the file, I sure ought to be able to lstat()
+ * it, but if something bizarre happens, just return p. */
+ if (lstat(p, &st)) return p;
+ /* if not a link, return p unmodified */
+ if (!S_ISLNK(st.st_mode)) return p;
+ link_len = st.st_size;
+ /* link is too big, so just return p */
+ if (link_len >= sizeof(link)) return p;
+ /* fail if readlink fails, and just return p */
+ if (link_len != readlink(p, link, sizeof(link))) return p;
+ /* readlink never null-terminates */
+ link[link_len] = '\0';
+ if (link[0] == '/') {
+ /* absolute path simply replaces p */
+ /* fail if link won't fit in p */
+ if (link_len >= s) return p;
+ strcpy(p, link);
+ } else {
+ /* link is relative path, so we must replace the last
+ * element of p with it. */
+ char * r = last_path_elm(p);
+ /* make sure there's room in p for us to replace the
+ * last element with the link contents */
+ if (r - p + link_len >= s) return p;
+ strcpy(r, link);
+ }
+ /* try again in case we've resolved to another symlink */
+ return resolve_symlink(p, s);
+}
+
static int lock_file(struct lock_file *lk, const char *path)
{
int fd;
- sprintf(lk->filename, "%s.lock", path);
+ if (strlen(path) >= sizeof(lk->filename)) return -1;
+ strcpy(lk->filename, path);
+ /* subtract 5 from size to make sure there's room for adding
+ * ".lock" for the lock file name */
+ resolve_symlink(lk->filename, sizeof(lk->filename)-5);
+ strcat(lk->filename, ".lock");
fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
if (0 <= fd) {
if (!lock_file_list) {
--
1.5.3.rc2.30.g1c06-dirty
next prev parent reply other threads:[~2007-07-25 16:50 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-07-15 21:27 git-config: replaces ~/.gitconfig symlink with real file Bradford Smith
2007-07-15 23:30 ` Johannes Schindelin
2007-07-16 9:37 ` Nikolai Weibull
2007-07-16 11:33 ` Bradford Smith
2007-07-16 13:26 ` Bradford Smith
2007-07-16 22:46 ` Junio C Hamano
2007-07-25 16:49 ` [PATCH 0/2] git-config should not replace symlink Bradford C. Smith
2007-07-25 16:49 ` Bradford C. Smith [this message]
2007-07-25 16:49 ` [PATCH 2/2] use lockfile.c routines in git_commit_set_multivar() Bradford C. Smith
2007-07-25 23:35 ` [PATCH 1/2] resolve symlinks when creating lockfiles Junio C Hamano
2007-07-26 16:55 ` [PATCH] use lockfile.c routines in git_commit_set_multivar() Bradford C. Smith
2007-07-26 18:31 ` Johannes Schindelin
2007-07-26 18:48 ` Bradford Smith
2007-07-27 4:30 ` Junio C Hamano
2007-07-27 4:53 ` Junio C Hamano
2007-07-27 9:05 ` Johannes Schindelin
2007-07-27 18:24 ` Bradford Smith
2007-07-26 17:34 ` [PATCH] fully resolve symlinks when creating lockfiles Bradford C. Smith
2007-07-26 18:35 ` Johannes Schindelin
2007-07-26 19:34 ` Morten Welinder
2007-07-27 16:50 ` Bradford Smith
2007-07-27 7:05 ` Junio C Hamano
2007-07-17 13:56 ` git-config: replaces ~/.gitconfig symlink with real file Johannes Schindelin
2007-07-17 14:27 ` Matthieu Moy
2007-07-17 20:35 ` Fredrik Tolf
2007-07-17 20:48 ` Johannes Schindelin
2007-07-17 13:39 ` Catalin Marinas
2007-07-17 16:09 ` Johannes Schindelin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=11853821951367-git-send-email-bradford.carl.smith@gmail.com \
--to=bradford.carl.smith@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).