diff options
author | Joris Vink <joris@cvs.openbsd.org> | 2005-06-17 15:09:56 +0000 |
---|---|---|
committer | Joris Vink <joris@cvs.openbsd.org> | 2005-06-17 15:09:56 +0000 |
commit | 488e4ef1d130d7aa53c165deb4126e342e5c42e3 (patch) | |
tree | f6daed9c57b906b1d017ae9c66640e4fe4daa95f /usr.bin | |
parent | b5060d65ffb649e508235afa8b2f91a9497b8829 (diff) |
correctly build a temporary copy of the client its repository
localy, so the server can execute the local commands on it
and pipe the output to the client.
with this diff in, our server is now working, please note
that we currently don't have support for all commands yet,
but you can expect this soon.
ok xsa@
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/cvs/cvs.h | 6 | ||||
-rw-r--r-- | usr.bin/cvs/entries.c | 23 | ||||
-rw-r--r-- | usr.bin/cvs/file.c | 9 | ||||
-rw-r--r-- | usr.bin/cvs/req.c | 196 | ||||
-rw-r--r-- | usr.bin/cvs/util.c | 117 |
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 |