summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2020-04-02 11:39:54 +0100
committerEdward Thomson <ethomson@edwardthomson.com>2020-06-05 07:14:26 +0100
commit2cd125280281220b0dc429215a99157f5fef89de (patch)
tree9ef1e65ce64d30e0e984fd3411c364e9c1f07a56
parent8a81cfb53ce96b0fe008d8c6448b809fba7a2d51 (diff)
downloadlibgit2-2cd125280281220b0dc429215a99157f5fef89de.tar.gz
buf: introduce git_buf_shellquote
Introduce a helper method to quote a string in a shellsafe manner. This wraps the entire buffer in single quotes, escaping single-quotes and exclamation points.
-rw-r--r--src/util/buffer.c37
-rw-r--r--src/util/buffer.h6
-rw-r--r--tests/libgit2/buf/basic.c29
3 files changed, 72 insertions, 0 deletions
diff --git a/src/util/buffer.c b/src/util/buffer.c
index 5d84b99fc..28db5c20c 100644
--- a/src/util/buffer.c
+++ b/src/util/buffer.c
@@ -1155,3 +1155,40 @@ done:
git_buf_dispose(&replaced);
return error;
}
+
+int git_buf_shellquote(git_buf *buf)
+{
+ git_buf quoted = GIT_BUF_INIT;
+ size_t i;
+ int error = 0;
+
+ ENSURE_SIZE(&quoted, buf->size);
+
+ git_buf_putc(&quoted, '\'');
+
+ for (i = 0; i < buf->size; i++) {
+ switch (buf->ptr[i]) {
+ case '\'':
+ case '!':
+ git_buf_puts(&quoted, "'\\");
+ git_buf_putc(&quoted, buf->ptr[i]);
+ git_buf_putc(&quoted, '\'');
+ break;
+ default:
+ git_buf_putc(&quoted, buf->ptr[i]);
+ }
+ }
+
+ git_buf_putc(&quoted, '\'');
+
+ if (git_buf_oom(&quoted)) {
+ error = -1;
+ goto done;
+ }
+
+ git_buf_swap(&quoted, buf);
+
+done:
+ git_buf_dispose(&quoted);
+ return error;
+}
diff --git a/src/util/buffer.h b/src/util/buffer.h
index bc0133465..95953082d 100644
--- a/src/util/buffer.h
+++ b/src/util/buffer.h
@@ -269,4 +269,10 @@ int git_buf_replace(
const char *replacements[][2],
size_t replacements_len);
+/**
+ * Quote for shell safety. Wrap the given buffer in single quotes,
+ * escaping any single quotes and exclamation points.
+ */
+int git_buf_shellquote(git_buf *buf);
+
#endif
diff --git a/tests/libgit2/buf/basic.c b/tests/libgit2/buf/basic.c
index 0de860983..0cb180b7f 100644
--- a/tests/libgit2/buf/basic.c
+++ b/tests/libgit2/buf/basic.c
@@ -65,3 +65,32 @@ void test_buf_basic__replace(void)
git_buf_dispose(&buf);
}
+
+void test_buf_basic__shellquote(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_puts(&buf, "filename"));
+ cl_git_pass(git_buf_shellquote(&buf));
+ cl_assert_equal_s("\'filename\'", buf.ptr);
+
+ git_buf_clear(&buf);
+
+ cl_git_pass(git_buf_puts(&buf, "file name"));
+ cl_git_pass(git_buf_shellquote(&buf));
+ cl_assert_equal_s("\'file name\'", buf.ptr);
+
+ git_buf_clear(&buf);
+
+ cl_git_pass(git_buf_puts(&buf, "file\'name"));
+ cl_git_pass(git_buf_shellquote(&buf));
+ cl_assert_equal_s("\'file\'\\\'\'name\'", buf.ptr);
+
+ git_buf_clear(&buf);
+
+ cl_git_pass(git_buf_puts(&buf, "file!name"));
+ cl_git_pass(git_buf_shellquote(&buf));
+ cl_assert_equal_s("\'file\'\\!\'name\'", buf.ptr);
+
+ git_buf_dispose(&buf);
+}