summaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c133
1 files changed, 95 insertions, 38 deletions
diff --git a/main.c b/main.c
index f4aacb2..5f1f602 100644
--- a/main.c
+++ b/main.c
@@ -3,7 +3,6 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <ftw.h>
-#include <limits.h>
#include <sha1.h>
#include <stdarg.h>
#include <stdio.h>
@@ -19,9 +18,10 @@
#define EXCLUDE_PATHS ".vcxignore"
-#define BUFLEN 8192
+#define BUF_LEN 8192
#define MAX_DEPTH 256
#define MAX_PATH_LEN 4096
+#define HASH_LEN SHA1_DIGEST_STRING_LENGTH
#define KIND_DEL 'D'
#define KIND_MOD 'M'
@@ -38,14 +38,20 @@ static inline void init_stg_area(void);
static inline int cmp_links(const char *link1, const char *link2);
static inline int cmp_files(const char *file1, const char *file2);
-static inline void stage_file(const char *file, char kind, int islnk);
+static inline void stage_entry(const char *path, char kind, int islnk);
static inline void print_status(const char *file, char kind, int islnk);
static inline int scan_head(const char * path, const struct stat *st, int flag, struct FTW *ftwbuf);
static inline int scan_tree(const char * path, const struct stat *st, int flag, struct FTW *ftwbuf);
+static inline void mkcopy(const char *path, char dst[HASH_LEN]);
+static inline void mklink(const char *src, const char obj[HASH_LEN]);
+
static inline void mkdirs(const char *path);
+static inline void copy_link(const char *src);
static inline int copy_file(const char *src, const char *dst);
+
+static inline int linklen(const char *lnk);
static inline void concat(char *dst, size_t n, const char *arg1, ...);
static inline void *_xmalloc(size_t s, const char *file, int line);
@@ -120,7 +126,7 @@ static inline void add(int argc, char *argv[])
errx(1, "Usage: %s [<files>]", argv[0]);
init_stg_area();
- scan_res_cb = stage_file;
+ scan_res_cb = stage_entry;
for (i = 1; i < argc; i++) {
wt_path = argv[i];
@@ -206,7 +212,7 @@ static inline int cmp_files(const char *file1, const char *file2)
int rc;
int fd1, fd2;
ssize_t r1, r2;
- char buf1[BUFLEN], buf2[BUFLEN];
+ char buf1[BUF_LEN], buf2[BUF_LEN];
if ((fd1 = open(file1, O_RDONLY)) < 0)
err(1, "Couldn't open %s to compare", file1);
@@ -216,8 +222,8 @@ static inline int cmp_files(const char *file1, const char *file2)
rc = 0;
do {
- r1 = read(fd1, buf1, BUFLEN);
- r2 = read(fd2, buf2, BUFLEN);
+ r1 = read(fd1, buf1, BUF_LEN);
+ r2 = read(fd2, buf2, BUF_LEN);
if (r1 != r2 || memcmp(buf1, buf2, r1) != 0) {
rc = 1;
@@ -233,9 +239,14 @@ static inline int cmp_files(const char *file1, const char *file2)
static inline int cmp_links(const char *link1, const char *link2)
{
ssize_t len1, len2;
- char buf1[PATH_MAX], buf2[PATH_MAX];
+ int buflen1, buflen2;
+ buflen1 = linklen(link1);
+ char buf1[buflen1];
len1 = readlink(link1, buf1, sizeof(buf1) - 1);
+
+ buflen2 = linklen(link2);
+ char buf2[buflen2];
len2 = readlink(link2, buf2, sizeof(buf2) - 1);
if (len1 < 0 || len2 < 0)
@@ -272,42 +283,19 @@ static inline void init_stg_area(void)
}
}
-static inline void stage_file(const char *file, char kind, int islnk)
+static inline void stage_entry(const char *path, char kind, int islnk)
{
- int len, obj_len;
- char obj_name[SHA1_DIGEST_STRING_LENGTH];
+ char objname[HASH_LEN];
switch (kind) {
case KIND_MOD:
break;
case KIND_NEW:
if (!islnk) {
- len = strlen(file);
- obj_len = SHA1_DIGEST_STRING_LENGTH - 1;
-
- if (SHA1Data((const uint8_t *)file, len, obj_name) == NULL)
- err(1, "Failed to compute hash for %s", file);
-
- size_t obj_sz = strlen(OBJ_DIR) + obj_len + 6;
- char obj_path[obj_sz];
- concat(obj_path, obj_sz, OBJ_DIR, "/", obj_name, ".tmp", NULL);
- copy_file(file, obj_path);
-
- // create link relative to tmp/
- size_t lnkt_sz = strlen("../obj/") + obj_len + 5;
- char lnk_target[lnkt_sz];
- concat(lnk_target, lnkt_sz, "../obj/", obj_name, ".tmp", NULL);
-
- size_t lnkp_sz = strlen(TMP_DIR) + len + 2;
- char lnk_path[lnkp_sz];
- concat(lnk_path, lnkp_sz, TMP_DIR, "/", file, NULL);
-
- mkdirs(lnk_path);
- if (symlink(lnk_target, lnk_path) != 0)
- err(1, "symlink error on %s", file);
- } else {
-
- }
+ mkcopy(path, objname);
+ mklink(path, objname);
+ } else
+ copy_link(path);
break;
case KIND_DEL:
break;
@@ -316,11 +304,58 @@ static inline void stage_file(const char *file, char kind, int islnk)
}
}
+static inline void mkcopy(const char *path, char dst[HASH_LEN])
+{
+ int len, obj_len;
+ char obj_name[HASH_LEN];
+
+ len = strlen(path);
+ obj_len = HASH_LEN - 1;
+ if (SHA1Data((const uint8_t *)path, len, obj_name) == NULL)
+ err(1, "Failed to compute hash for %s", path);
+
+ size_t obj_sz = strlen(OBJ_DIR) + obj_len + 6;
+ char obj_path[obj_sz];
+ concat(obj_path, obj_sz, OBJ_DIR, "/", obj_name, ".tmp", NULL);
+ copy_file(path, obj_path);
+}
+
+static inline void mklink(const char *src, const char obj[HASH_LEN])
+{
+ // HASH_LEN includes null byte
+ size_t lnkt_sz = strlen("../obj/") + HASH_LEN + 4;
+ char lnk_target[lnkt_sz];
+ concat(lnk_target, lnkt_sz, "../obj/", obj, ".tmp", NULL);
+
+ size_t lnkp_sz = strlen(TMP_DIR) + strlen(src) + 2;
+ char lnk_path[lnkp_sz];
+ concat(lnk_path, lnkp_sz, TMP_DIR, "/", src, NULL);
+
+ mkdirs(lnk_path);
+ if (symlink(lnk_target, lnk_path) != 0)
+ err(1, "symlink error on %s", src);
+}
+
static inline void print_status(const char *file, char kind, int islnk)
{
printf("[%c] %s\n", kind, file);
}
+static inline int linklen(const char *lnk)
+{
+ int len;
+ struct stat st;
+
+ if (lstat(lnk, &st) != 0)
+ err(1, "lstat %s", lnk);
+
+ len = st.st_size + 1;
+ if (MAX_PATH_LEN < len)
+ errx(1, "Link too long: %s", lnk);
+
+ return len;
+}
+
static inline void concat(char *dst, size_t n, const char *arg1, ...)
{
va_list ap;
@@ -389,7 +424,7 @@ static inline int copy_file(const char *src, const char *dst)
{
int fdin, fdout;
struct stat st;
- char buf[BUFLEN], *outptr;
+ char buf[BUF_LEN], *outptr;
ssize_t nread, nwrite, res;
if ((fdin = open(src, O_RDONLY)) < 0)
@@ -431,6 +466,28 @@ static inline int copy_file(const char *src, const char *dst)
return (nread < 0) ? -1 : 0;
}
+static inline void copy_link(const char *src)
+{
+ int len;
+ ssize_t n;
+
+ len = linklen(src);
+ char target[len];
+ n = readlink(src, target, len);
+ if (n == -1)
+ err(1, "readlink %s", src);
+
+ target[n] = '\0';
+
+ size_t dst_sz = strlen(TMP_DIR) + strlen(src) + 2;
+ char dst[dst_sz];
+ concat(dst, dst_sz, TMP_DIR, src, NULL);
+ mkdirs(dst);
+
+ if (symlink(target, dst) != 0)
+ err(1, "Link copy error %s", src);
+}
+
static inline void mkdirs(const char *path)
{
char *p;