summaryrefslogtreecommitdiff
path: root/usr.bin/cvs
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/cvs')
-rw-r--r--usr.bin/cvs/cvs.h6
-rw-r--r--usr.bin/cvs/entries.c23
-rw-r--r--usr.bin/cvs/file.c9
-rw-r--r--usr.bin/cvs/req.c196
-rw-r--r--usr.bin/cvs/util.c117
5 files changed, 300 insertions, 51 deletions
diff --git a/usr.bin/cvs/cvs.h b/usr.bin/cvs/cvs.h
index 5af394a116f..0d93471478e 100644
--- a/usr.bin/cvs/cvs.h
+++ b/usr.bin/cvs/cvs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cvs.h,v 1.66 2005/06/17 08:09:13 xsa Exp $ */
+/* $OpenBSD: cvs.h,v 1.67 2005/06/17 15:09:55 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -236,7 +236,7 @@ struct cvsroot {
#define CVS_ENT_REG 0
#define CVS_ENT_ADDED 1
#define CVS_ENT_REMOVED 2
-
+#define CVS_ENT_UPTODATE 3
#define CVS_ENTF_SYNC 0x01 /* contents of disk and memory match */
#define CVS_ENTF_WR 0x02 /* file is opened for writing too */
@@ -291,6 +291,7 @@ typedef struct cvs_histfile {
} CVSHIST;
+extern char *cvs_req_modulename;
extern char *cvs_repo_base;
extern char *cvs_command;
extern char *cvs_editor;
@@ -392,6 +393,7 @@ int cvs_cksum (const char *, char *, size_t);
int cvs_exec (int, char **, int []);
int cvs_getargv (const char *, char **, int);
int cvs_remove_dir (const char *);
+int cvs_create_dir (const char *, int, char *, char *);
char** cvs_makeargv (const char *, int *);
void cvs_freeargv (char **, int);
size_t cvs_path_cat (const char *, const char *, char *, size_t);
diff --git a/usr.bin/cvs/entries.c b/usr.bin/cvs/entries.c
index b1f7f5902cf..15bb1d9af21 100644
--- a/usr.bin/cvs/entries.c
+++ b/usr.bin/cvs/entries.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: entries.c,v 1.37 2005/06/07 08:19:07 xsa Exp $ */
+/* $OpenBSD: entries.c,v 1.38 2005/06/17 15:09:55 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -379,15 +379,21 @@ cvs_ent_parse(const char *entry)
if ((fields[2][0] == '0') && (fields[2][1] == '\0'))
entp->ce_status = CVS_ENT_ADDED;
}
+
if ((entp->ce_rev = rcsnum_parse(sp)) == NULL) {
cvs_ent_free(entp);
return (NULL);
}
- if (strcmp(fields[3], CVS_DATE_DUMMY) == 0)
- entp->ce_mtime = CVS_DATE_DMSEC;
- else
- entp->ce_mtime = cvs_date_parse(fields[3]);
+ if (cvs_cmdop == CVS_OP_SERVER) {
+ if (!strcmp(fields[3], "up to date"))
+ entp->ce_status = CVS_ENT_UPTODATE;
+ } else {
+ if (strcmp(fields[3], CVS_DATE_DUMMY) == 0)
+ entp->ce_mtime = CVS_DATE_DMSEC;
+ else
+ entp->ce_mtime = cvs_date_parse(fields[3]);
+ }
}
entp->ce_opts = fields[4];
@@ -451,6 +457,13 @@ cvs_ent_write(CVSENTRIES *ef)
}
}
+ if (cvs_cmdop == CVS_OP_SERVER) {
+ if (ent->ce_status == CVS_ENT_UPTODATE)
+ strlcpy(timebuf, "up to date", sizeof(timebuf));
+ else
+ timebuf[0] = '\0';
+ }
+
fprintf(fp, "/%s/%s%s/%s/%s/%s\n", ent->ce_name,
(ent->ce_status == CVS_ENT_REMOVED) ? "-" : "", revbuf,
timebuf, "", "");
diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c
index 0b02b972e56..288fd7ca24a 100644
--- a/usr.bin/cvs/file.c
+++ b/usr.bin/cvs/file.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: file.c,v 1.89 2005/06/17 14:58:23 joris Exp $ */
+/* $OpenBSD: file.c,v 1.90 2005/06/17 15:09:55 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -1081,10 +1081,11 @@ cvs_file_lget(const char *path, int flags, CVSFILE *parent, struct cvs_ent *ent)
cfp->cf_cvstat = CVS_FST_ADDED;
else {
/* check last modified time */
- if (ent->ce_mtime == (time_t)st.st_mtime)
+ if (ent->ce_mtime == (time_t)st.st_mtime) {
cfp->cf_cvstat = CVS_FST_UPTODATE;
- else
+ } else {
cfp->cf_cvstat = CVS_FST_MODIFIED;
+ }
}
}
} else {
@@ -1104,6 +1105,8 @@ cvs_file_lget(const char *path, int flags, CVSFILE *parent, struct cvs_ent *ent)
if (ent->ce_status == CVS_ENT_REMOVED)
cfp->cf_cvstat = CVS_FST_REMOVED;
+ else if (ent->ce_status == CVS_ENT_UPTODATE)
+ cfp->cf_cvstat = CVS_FST_UPTODATE;
else
cfp->cf_cvstat = CVS_FST_LOST;
}
diff --git a/usr.bin/cvs/req.c b/usr.bin/cvs/req.c
index 7ba28b6d41a..bbcf4878f3a 100644
--- a/usr.bin/cvs/req.c
+++ b/usr.bin/cvs/req.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: req.c,v 1.21 2005/06/10 21:14:47 joris Exp $ */
+/* $OpenBSD: req.c,v 1.22 2005/06/17 15:09:55 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -30,6 +30,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -41,6 +42,7 @@
#include "proto.h"
+extern char *cvs_rootstr;
extern int verbosity;
extern int cvs_compress;
extern char *cvs_rsh;
@@ -119,7 +121,7 @@ struct cvs_reqhdlr {
{ cvs_req_command },
{ NULL },
{ cvs_req_command },
- { NULL },
+ { cvs_req_command },
{ NULL }, /* 50 */
{ NULL },
{ NULL },
@@ -147,16 +149,16 @@ struct cvs_reqhdlr {
/*
* Argument array built by `Argument' and `Argumentx' requests.
*/
+static char *cvs_req_args[CVS_PROTO_MAXARG];
+
+/* start at 1, because 0 will be the command name */
+static int cvs_req_nargs = 1;
+static char *cvs_req_modulename;
static char *cvs_req_rootpath;
static char *cvs_req_currentdir;
-static char *cvs_req_repopath;
-static char cvs_req_tmppath[MAXPATHLEN];
-
extern char cvs_server_tmpdir[MAXPATHLEN];
-static char *cvs_req_args[CVS_PROTO_MAXARG];
-static int cvs_req_nargs = 0;
-
+static CVSENTRIES *cvs_req_entf;
/*
* cvs_req_handle()
@@ -218,6 +220,8 @@ cvs_req_root(int reqid, char *line)
return (-1);
}
+ cvs_rootstr = cvs_req_rootpath;
+
return (0);
}
@@ -264,8 +268,12 @@ cvs_req_validresp(int reqid, char *line)
static int
cvs_req_directory(int reqid, char *line)
{
- int l;
+ int pwd;
+ size_t dirlen;
char rdir[MAXPATHLEN];
+ char *repo, *s, *p;
+
+ pwd = (!strcmp(line, "."));
if (cvs_getln(NULL, rdir, sizeof(rdir)) < 0)
return (-1);
@@ -279,27 +287,96 @@ cvs_req_directory(int reqid, char *line)
return (-1);
}
- /* now obtain the path relative to the Root directory */
- cvs_req_repopath = cvs_req_currentdir + strlen(cvs_req_rootpath) + 1;
+ dirlen = strlen(cvs_req_currentdir);
+
+ /*
+ * Lets make sure we always start at the correct
+ * directory.
+ */
+ if (chdir(cvs_server_tmpdir) == -1) {
+ cvs_log(LP_ERRNO, "failed to change to top directory");
+ return (-1);
+ }
+
+ /*
+ * Set repository path.
+ */
+ s = cvs_req_currentdir + strlen(cvs_req_rootpath) + 1;
+ if (s >= (cvs_req_currentdir + dirlen)) {
+ cvs_log(LP_ERR, "you're bad, go away");
+ return (-1);
+ }
- /* create tmp path */
- l = snprintf(cvs_req_tmppath, sizeof(cvs_req_tmppath), "%s/%s",
- cvs_server_tmpdir, cvs_req_repopath);
- if (l == -1 || l >= (int)sizeof(cvs_req_tmppath)) {
- errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", cvs_req_tmppath);
+ if ((repo = strdup(s)) == NULL) {
+ cvs_log(LP_ERR, "failed to save repository path");
return (-1);
}
- if ((mkdir(cvs_req_tmppath, 0755) == -1) && (errno != EEXIST)) {
- cvs_log(LP_ERRNO, "failed to create temporary directory '%s'",
- cvs_req_tmppath);
+ /*
+ * Skip back "foo/bar" part, so we can feed the repo
+ * as a startpoint for cvs_create_dir().
+ */
+ if (!pwd) {
+ s = repo + strlen(repo) - strlen(line) - 1;
+ if (*s != '/') {
+ cvs_log(LP_ERR, "malformed directory");
+ free(repo);
+ return (-1);
+ }
+
+ *s = '\0';
+ }
+
+ /*
+ * Obtain the modulename, we only need to do this at
+ * the very first time we get a Directory request.
+ */
+ if (cvs_req_modulename == NULL) {
+ if ((p = strchr(repo, '/')) != NULL)
+ *p = '\0';
+
+ if ((cvs_req_modulename = strdup(repo)) == NULL) {
+ cvs_log(LP_ERR, "failed to save modulename");
+ free(repo);
+ return (-1);
+ }
+
+ if (p != NULL)
+ *p = '/';
+
+ /*
+ * Now, create the admin files in the top-level
+ * directory for the temp repo.
+ */
+ if (cvs_mkadmin(cvs_server_tmpdir, cvs_rootstr, repo) < 0) {
+ cvs_log(LP_ERR, "failed to create admin files");
+ free(repo);
+ return (-1);
+ }
+ }
+
+ /*
+ * create the directory plus the administrative files.
+ */
+ if (cvs_create_dir(line, 1, cvs_rootstr, repo) < 0) {
+ free(repo);
return (-1);
}
- /* create the CVS/ administrative files */
- /* XXX - TODO */
+ /*
+ * cvs_create_dir() has already put us in the correct directory
+ * so now open it's Entry file for incoming files.
+ */
+ if (cvs_req_entf != NULL)
+ cvs_ent_close(cvs_req_entf);
+ cvs_req_entf = cvs_ent_open(".", O_RDWR);
+ if (cvs_req_entf == NULL) {
+ cvs_log(LP_ERR, "failed to open Entry file for %s", line);
+ free(repo);
+ return (-1);
+ }
+ free(repo);
return (0);
}
@@ -307,12 +384,20 @@ static int
cvs_req_entry(int reqid, char *line)
{
struct cvs_ent *ent;
- CVSFILE *cf;
+ /* parse received entry */
if ((ent = cvs_ent_parse(line)) == NULL)
return (-1);
- cf = cvs_file_create(NULL, ent->ce_name, DT_REG, 0644);
+ /* add it to the entry file and done */
+ if (cvs_ent_add(cvs_req_entf, ent) < 0) {
+ cvs_log(LP_ERR, "failed to add '%s' to the Entry file",
+ ent->ce_name);
+ return (-1);
+ }
+
+ /* XXX */
+ cvs_ent_write(cvs_req_entf);
return (0);
}
@@ -327,37 +412,52 @@ cvs_req_entry(int reqid, char *line)
static int
cvs_req_filestate(int reqid, char *line)
{
- int l;
+ int ret;
mode_t fmode;
BUF *fdata;
- char fpath[MAXPATHLEN];
+ struct cvs_ent *ent;
- if (reqid == CVS_REQ_MODIFIED) {
+ ret = 0;
+ switch (reqid) {
+ case CVS_REQ_MODIFIED:
fdata = cvs_recvfile(NULL, &fmode);
if (fdata == NULL)
return (-1);
- /* create full temporary path */
- l = snprintf(fpath, sizeof(fpath), "%s/%s", cvs_req_tmppath,
- line);
- if (l == -1 || l >= (int)sizeof(fpath)) {
- errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", fpath);
- cvs_buf_free(fdata);
- return (-1);
- }
-
/* write the file */
- if (cvs_buf_write(fdata, fpath, fmode) < 0) {
- cvs_log(LP_ERR, "failed to create file %s", fpath);
+ if (cvs_buf_write(fdata, line, fmode) < 0) {
+ cvs_log(LP_ERR, "failed to create file %s", line);
cvs_buf_free(fdata);
return (-1);
}
cvs_buf_free(fdata);
+ break;
+ case CVS_REQ_ISMODIFIED:
+ break;
+ case CVS_REQ_UNCHANGED:
+ ent = cvs_ent_get(cvs_req_entf, line);
+ if (ent == NULL) {
+ cvs_log(LP_ERR,
+ "received Unchanged request for a non-existing file");
+ ret = -1;
+ } else {
+ ent->ce_status = CVS_ENT_UPTODATE;
+ }
+ break;
+ case CVS_REQ_QUESTIONABLE:
+ break;
+ default:
+ cvs_log(LP_ERR, "wrong request id type");
+ ret = -1;
+ break;
}
- return (0);
+ /* XXX */
+ cvs_req_entf->cef_flags &= ~CVS_ENTF_SYNC;
+ cvs_ent_write(cvs_req_entf);
+
+ return (ret);
}
/*
@@ -551,7 +651,23 @@ cvs_req_command(int reqid, char *line)
return (-1);
}
+ /* close the Entry file if it's still open */
+ if (cvs_req_entf != NULL)
+ cvs_ent_close(cvs_req_entf);
+
+ /* fill in the command name */
+ cvs_req_args[0] = cmdp->cmd_name;
+
+ /* switch to the correct directory */
+ if (cmdp->cmd_op != CVS_OP_VERSION) {
+ if (chdir(cvs_server_tmpdir) == -1) {
+ cvs_log(LP_ERRNO, "failed to change dir");
+ return (-1);
+ }
+ }
+
ret = cvs_startcmd(cmdp, cvs_req_nargs, cvs_req_args);
+
if (ret == 0)
ret = cvs_sendresp(CVS_RESP_OK, NULL);
diff --git a/usr.bin/cvs/util.c b/usr.bin/cvs/util.c
index 0170e6c75d5..19fd6fcb638 100644
--- a/usr.bin/cvs/util.c
+++ b/usr.bin/cvs/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.33 2005/06/14 03:56:14 pat Exp $ */
+/* $OpenBSD: util.c,v 1.34 2005/06/17 15:09:55 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -563,6 +563,121 @@ done:
}
/*
+ * Create a directory, and the parent directories if needed.
+ * based upon mkpath() from mkdir.c
+ */
+int
+cvs_create_dir(const char *path, int create_adm, char *root, char *repo)
+{
+ size_t l;
+ int len, ret;
+ char *d, *s;
+ struct stat sb;
+ char rpath[MAXPATHLEN], entry[MAXPATHLEN];
+ CVSENTRIES *entf;
+ struct cvs_ent *ent;
+
+ if (create_adm == 1 && (root == NULL || repo == NULL)) {
+ cvs_log(LP_ERR, "missing stuff in cvs_create_dir");
+ return (-1);
+ }
+
+ if ((s = strdup(path)) == NULL)
+ return (-1);
+
+ if (strlcpy(rpath, repo, sizeof(rpath)) >= sizeof(rpath) ||
+ strlcat(rpath, "/", sizeof(rpath)) >= sizeof(rpath)) {
+ errno = ENAMETOOLONG;
+ cvs_log(LP_ERRNO, "%s", rpath);
+ free(s);
+ return (-1);
+ }
+
+ ret = -1;
+ entf = NULL;
+ d = strtok(s, "/");
+ while (d != NULL) {
+ if (stat(d, &sb)) {
+ /* try to create the directory */
+ if ((errno != ENOENT) || (mkdir(d, 0755) &&
+ errno != EEXIST)) {
+ cvs_log(LP_ERRNO, "failed to create `%s'", d);
+ goto done;
+ }
+ } else if (!S_ISDIR(sb.st_mode)) {
+ cvs_log(LP_ERR, "`%s' not a directory", d);
+ goto done;
+ }
+
+ /*
+ * Create administrative files if requested.
+ */
+ if (create_adm) {
+ l = strlcat(rpath, d, sizeof(rpath));
+ if (l >= sizeof(rpath))
+ goto done;
+
+ l = strlcat(rpath, "/", sizeof(rpath));
+ if (l >= sizeof(rpath))
+ goto done;
+
+ if (cvs_mkadmin(d, root, rpath) < 0) {
+ cvs_log(LP_ERR, "failed to create adm files");
+ goto done;
+ }
+ }
+
+ /*
+ * Add it to the parent directory entry file.
+ * (if any).
+ */
+ entf = cvs_ent_open(".", O_RDWR);
+ if (entf != NULL && strcmp(d, ".")) {
+ len = snprintf(entry, sizeof(entry), "D/%s////", d);
+ if (len == -1 || len >= (int)sizeof(entry)) {
+ errno = ENAMETOOLONG;
+ cvs_log(LP_ERRNO, "%s", entry);
+ goto done;
+ }
+
+ if ((ent = cvs_ent_parse(entry)) == NULL) {
+ cvs_log(LP_ERR, "failed to parse entry");
+ goto done;
+ }
+
+ cvs_ent_remove(entf, d);
+
+ if (cvs_ent_add(entf, ent) < 0) {
+ cvs_log(LP_ERR, "failed to add entry");
+ goto done;
+ }
+ }
+
+ if (entf != NULL) {
+ cvs_ent_close(entf);
+ entf = NULL;
+ }
+
+ /*
+ * All went ok, switch to the newly created directory.
+ */
+ if (chdir(d) == -1) {
+ cvs_log(LP_ERRNO, "failed to change dir to `%s'", d);
+ goto done;
+ }
+
+ d = strtok(NULL, "/");
+ }
+
+ ret = 0;
+done:
+ if (entf != NULL)
+ cvs_ent_close(entf);
+ free(s);
+ return (ret);
+}
+
+/*
* cvs_path_cat()
*
* Concatenate the two paths <base> and <end> and store the generated path