summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorJoris Vink <joris@cvs.openbsd.org>2005-07-23 11:19:47 +0000
committerJoris Vink <joris@cvs.openbsd.org>2005-07-23 11:19:47 +0000
commit316e7b4ce9ddeaa9df048f14eb629be01439aa55 (patch)
treef4f74e1c0f91731e6481818a3caeac96f0c80c34 /usr.bin
parent9cb789f35012b533e6bb67128d89a9154482620c (diff)
rewrite of the file code. the previous one was just
a mess and not clean. this code is much cleaner, faster, and uses less memory overall. tested by xsa@, brad@, Michael Knudsen, and myself. okay xsa@
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/cvs/add.c4
-rw-r--r--usr.bin/cvs/cmd.c35
-rw-r--r--usr.bin/cvs/commit.c24
-rw-r--r--usr.bin/cvs/cvs.c8
-rw-r--r--usr.bin/cvs/cvs.h4
-rw-r--r--usr.bin/cvs/file.c777
-rw-r--r--usr.bin/cvs/file.h23
-rw-r--r--usr.bin/cvs/proto.c4
-rw-r--r--usr.bin/cvs/resp.c84
-rw-r--r--usr.bin/cvs/update.c5
10 files changed, 570 insertions, 398 deletions
diff --git a/usr.bin/cvs/add.c b/usr.bin/cvs/add.c
index 7247edd92b1..8ab9641f32a 100644
--- a/usr.bin/cvs/add.c
+++ b/usr.bin/cvs/add.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: add.c,v 1.23 2005/07/10 21:55:30 joris Exp $ */
+/* $OpenBSD: add.c,v 1.24 2005/07/23 11:19:46 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -131,7 +131,7 @@ cvs_add_remote(CVSFILE *cf, void *arg)
return (ret);
}
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
+ if (cf->cf_cvstat == CVS_FST_ADDED)
ret = cvs_sendreq(root, CVS_REQ_ISMODIFIED,
cf->cf_name);
diff --git a/usr.bin/cvs/cmd.c b/usr.bin/cvs/cmd.c
index a5639a76977..b32f2c19099 100644
--- a/usr.bin/cvs/cmd.c
+++ b/usr.bin/cvs/cmd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd.c,v 1.30 2005/07/21 11:42:24 xsa Exp $ */
+/* $OpenBSD: cmd.c,v 1.31 2005/07/23 11:19:46 joris Exp $ */
/*
* Copyright (c) 2005 Joris Vink <joris@openbsd.org>
* All rights reserved.
@@ -148,7 +148,7 @@ cvs_startcmd(struct cvs_cmd *cmd, int argc, char **argv)
int ret;
struct cvsroot *root;
int (*ex_hdlr)(CVSFILE *, void *);
- char fpath[MAXPATHLEN];
+ CVSFILE *cf;
/* if the command requested is the server one, just call the
* cvs_server() function to handle it, and return after it.
@@ -187,17 +187,15 @@ cvs_startcmd(struct cvs_cmd *cmd, int argc, char **argv)
ex_hdlr = cmd->cmd_exec_remote;
if (argc > 0) {
- cvs_files = cvs_file_getspec(argv, argc, cmd->file_flags,
- ex_hdlr, NULL);
+ ret = cvs_file_getspec(argv, argc, cmd->file_flags,
+ ex_hdlr, NULL, NULL);
} else {
- cvs_files = cvs_file_get(".", cmd->file_flags,
- ex_hdlr, NULL);
+ ret = cvs_file_get(".", cmd->file_flags,
+ ex_hdlr, NULL, NULL);
}
- if (cvs_files == NULL)
- return (CVS_EX_DATA);
-
- cvs_file_getpath(cvs_files, fpath, sizeof(fpath));
+ if (ret != CVS_EX_OK)
+ return (cvs_error);
if (cmd->cmd_post_exec != NULL) {
if ((ret = cmd->cmd_post_exec(root)) != 0)
@@ -205,9 +203,19 @@ cvs_startcmd(struct cvs_cmd *cmd, int argc, char **argv)
}
if (root->cr_method != CVS_METHOD_LOCAL) {
+ /*
+ * If we have to send the directory the command
+ * has been issued in, obtain it.
+ */
if (cmd->cmd_flags & CVS_CMD_SENDDIR) {
- if (cvs_senddir(root, cvs_files) < 0)
+ cf = cvs_file_loadinfo(".", CF_NOFILES, NULL, NULL, 1);
+ if (cf == NULL)
+ return (CVS_EX_DATA);
+ if (cvs_senddir(root, cf) < 0) {
+ cvs_file_free(cf);
return (CVS_EX_PROTO);
+ }
+ cvs_file_free(cf);
}
if (cmd->cmd_flags & CVS_CMD_SENDARGS2) {
@@ -217,7 +225,8 @@ cvs_startcmd(struct cvs_cmd *cmd, int argc, char **argv)
}
}
- if (cmd->cmd_req != CVS_REQ_NONE && cvs_sendreq(root, cmd->cmd_req,
+ if (cmd->cmd_req != CVS_REQ_NONE &&
+ cvs_sendreq(root, cmd->cmd_req,
(cmd->cmd_op == CVS_OP_INIT) ? root->cr_dir : NULL) < 0)
return (CVS_EX_PROTO);
}
@@ -225,8 +234,10 @@ cvs_startcmd(struct cvs_cmd *cmd, int argc, char **argv)
if (cmd->cmd_cleanup != NULL)
(*cmd->cmd_cleanup)();
+#if 0
if (cvs_cmdop != CVS_OP_SERVER && cmd->cmd_flags & CVS_CMD_PRUNEDIRS)
cvs_file_prune(fpath);
+#endif
if (root->cr_method != CVS_METHOD_LOCAL)
cvs_disconnect(root);
diff --git a/usr.bin/cvs/commit.c b/usr.bin/cvs/commit.c
index a3d6286ed77..a269133e003 100644
--- a/usr.bin/cvs/commit.c
+++ b/usr.bin/cvs/commit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: commit.c,v 1.43 2005/07/23 00:03:00 joris Exp $ */
+/* $OpenBSD: commit.c,v 1.44 2005/07/23 11:19:46 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -126,7 +126,7 @@ cvs_commit_pre_exec(struct cvsroot *root)
{
CVSFILE *cfp;
CVSFILE *tmp;
- int i, flags = CF_RECURSE | CF_IGNORE | CF_SORT;
+ int ret, i, flags = CF_RECURSE | CF_IGNORE | CF_SORT;
struct cvs_flist added, modified, removed, *cl[3];
int stattype[] = { CVS_FST_ADDED, CVS_FST_MODIFIED, CVS_FST_REMOVED };
@@ -138,26 +138,26 @@ cvs_commit_pre_exec(struct cvsroot *root)
cl[1] = &modified;
cl[2] = &removed;
+ if ((tmp = cvs_file_loadinfo(".", CF_NOFILES, NULL, NULL, 1)) == NULL)
+ return (CVS_EX_DATA);
+
/*
* Obtain the file lists for the logmessage.
*/
- tmp = NULL;
for (i = 0; i < 3; i++) {
- if (tmp != NULL)
- cvs_file_free(tmp);
-
wantedstatus = stattype[i];
-
if (commit_fcount != 0) {
- tmp = cvs_file_getspec(commit_files, commit_fcount,
- flags, cvs_commit_prepare, cl[i]);
+ ret = cvs_file_getspec(commit_files, commit_fcount,
+ flags, cvs_commit_prepare, cl[i], NULL);
} else {
- tmp = cvs_file_get(".", flags, cvs_commit_prepare,
- cl[i]);
+ ret = cvs_file_get(".", flags, cvs_commit_prepare,
+ cl[i], NULL);
}
- if (tmp == NULL)
+ if (ret != CVS_EX_OK) {
+ cvs_file_free(tmp);
return (CVS_EX_DATA);
+ }
}
/*
diff --git a/usr.bin/cvs/cvs.c b/usr.bin/cvs/cvs.c
index f2215929eb5..da9f7cb6a56 100644
--- a/usr.bin/cvs/cvs.c
+++ b/usr.bin/cvs/cvs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cvs.c,v 1.72 2005/07/07 14:27:57 joris Exp $ */
+/* $OpenBSD: cvs.c,v 1.73 2005/07/23 11:19:46 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -57,7 +57,7 @@ int cvs_nolog = 0;
int cvs_readonly = 0;
int cvs_nocase = 0; /* set to 1 to disable filename case sensitivity */
int cvs_noexec = 0; /* set to 1 to disable disk operations (-n option) */
-
+int cvs_error = -1; /* set to the correct error code on failure */
char *cvs_defargs; /* default global arguments from .cvsrc */
char *cvs_command; /* name of the command we are running */
int cvs_cmdop;
@@ -70,7 +70,6 @@ char *cvs_msg = NULL;
/* hierarchy of all the files affected by the command */
CVSFILE *cvs_files;
-
static TAILQ_HEAD(, cvs_var) cvs_variables;
@@ -212,6 +211,9 @@ main(int argc, char **argv)
cvs_log(LP_ABORT,
"or set the CVSROOT enviroment variable.");
break;
+ case CVS_EX_ERR:
+ cvs_log(LP_ABORT, "yeah, we failed, and we don't know why");
+ break;
default:
break;
}
diff --git a/usr.bin/cvs/cvs.h b/usr.bin/cvs/cvs.h
index 5df82557544..c0628f882dd 100644
--- a/usr.bin/cvs/cvs.h
+++ b/usr.bin/cvs/cvs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cvs.h,v 1.71 2005/07/23 10:49:35 xsa Exp $ */
+/* $OpenBSD: cvs.h,v 1.72 2005/07/23 11:19:46 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -309,7 +309,7 @@ extern int cvs_cmdop;
extern int cvs_nocase;
extern int cvs_noexec;
extern int cvs_readonly;
-
+extern int cvs_error;
extern CVSFILE *cvs_files;
extern struct cvs_cmd *cvs_cdt[];
diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c
index caa58fee658..aa6b0bc1d9b 100644
--- a/usr.bin/cvs/file.c
+++ b/usr.bin/cvs/file.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: file.c,v 1.99 2005/07/22 16:27:29 joris Exp $ */
+/* $OpenBSD: file.c,v 1.100 2005/07/23 11:19:46 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -44,7 +44,6 @@
#include "log.h"
#include "strtab.h"
-
#define CVS_IGN_STATIC 0x01 /* pattern is static, no need to glob */
#define CVS_CHAR_ISMETA(c) ((c == '*') || (c == '?') || (c == '['))
@@ -106,8 +105,9 @@ static RCSNUM *cvs_addedrev;
TAILQ_HEAD(, cvs_ignpat) cvs_ign_pats;
+static int cvs_file_getdir(CVSFILE *, int, int (*)(CVSFILE *, void *),
+ void *, int);
-static int cvs_file_getdir(CVSFILE *, int, char *, int (*)(CVSFILE *, void *), void *);
static int cvs_load_dirinfo (CVSFILE *, int);
static int cvs_file_sort (struct cvs_flist *, u_int);
static int cvs_file_cmp (const void *, const void *);
@@ -248,7 +248,6 @@ CVSFILE*
cvs_file_create(CVSFILE *parent, const char *path, u_int type, mode_t mode)
{
int fd, l;
- int bail;
char fp[MAXPATHLEN], repo[MAXPATHLEN];
CVSFILE *cfp;
CVSENTRIES *ent;
@@ -257,32 +256,14 @@ cvs_file_create(CVSFILE *parent, const char *path, u_int type, mode_t mode)
if (cfp == NULL)
return (NULL);
- bail = l = 0;
+ l = 0;
cfp->cf_mode = mode;
cfp->cf_parent = parent;
if (type == DT_DIR) {
cfp->cf_root = cvsroot_get(path);
-
- /*
- * If we do not have a valid root for this, try looking at
- * the parent its root.
- */
if (cfp->cf_root == NULL) {
- if (parent != NULL && parent->cf_root != NULL) {
- cfp->cf_root =
- cvsroot_parse(parent->cf_root->cr_str);
- if (cfp->cf_root == NULL)
- bail = 1;
- } else {
- bail = 1;
- }
- }
-
- /* we tried, too bad */
- if (bail) {
- cvs_log(LP_ERR, "failed to obtain root info for `%s'",
- path);
+ cvs_file_free(cfp);
return (NULL);
}
@@ -385,132 +366,283 @@ cvs_file_copy(CVSFILE *orig)
* with cvs_file_free().
*/
-CVSFILE*
+int
cvs_file_get(const char *path, int flags, int (*cb)(CVSFILE *, void *),
- void *arg)
+ void *arg, struct cvs_flist *list)
{
char *files[1];
files[0] = path;
- return cvs_file_getspec(files, 1, flags, cb, arg);
+ return cvs_file_getspec(files, 1, flags, cb, arg, list);
}
/*
* cvs_file_getspec()
*
- * Load a specific set of files whose paths are given in the vector <fspec>,
- * whose size is given in <fsn>.
- * Returns a pointer to the lowest common subdirectory to all specified
- * files.
+ * Obtain the info about the supplied files or directories.
*/
-CVSFILE*
+int
cvs_file_getspec(char **fspec, int fsn, int flags, int (*cb)(CVSFILE *, void *),
- void *arg)
+ void *arg, struct cvs_flist *list)
{
- int i;
- int pwd;
- char *sp, *np, pcopy[MAXPATHLEN];
- CVSFILE *base, *nf;
- CVSENTRIES *entfile;
- struct cvs_ent *ent;
+ int i, freecf;
+ char pcopy[MAXPATHLEN];
+ CVSFILE *cf;
+ extern char *cvs_rootstr;
- base = cvs_file_lget(".", 0, NULL, NULL);
- if (base == NULL)
- return (NULL);
+ freecf = (list == NULL);
+ cvs_error = CVS_EX_DATA;
- entfile = cvs_ent_open(".", O_RDONLY);
+ /* init the list */
+ if (list != NULL)
+ SIMPLEQ_INIT(list);
+
+ /*
+ * Fetch the needed information about ".", so we can setup a few
+ * things to get ourselfs going.
+ */
+ cf = cvs_file_lget(".", 0, NULL, NULL);
+ if (cf == NULL) {
+ cvs_log(LP_ERR, "arrrr i failed captain!");
+ return (-1);
+ }
/*
- * fill in the repository base (needed to construct repo's in
- * cvs_file_create).
+ * save the base repository path so we can use it to create
+ * the correct full repopath later on.
*/
- if (base->cf_repo != NULL) {
- cvs_repo_base = strdup(base->cf_repo);
+ if (cf->cf_repo != NULL) {
+ if (cvs_repo_base != NULL)
+ free(cvs_repo_base);
+ cvs_repo_base = strdup(cf->cf_repo);
if (cvs_repo_base == NULL) {
- cvs_log(LP_ERR, "failed to duplicate repository base");
- cvs_file_free(base);
- if (entfile)
- cvs_ent_close(entfile);
- return (NULL);
+ cvs_log(LP_ERRNO, "strdup failed");
+ cvs_file_free(cf);
+ return (-1);
}
}
/*
- * XXX - needed for some commands
+ * This will go away when we have support for multiple Roots.
*/
- if (cb != NULL) {
- if (cb(base, arg) != CVS_EX_OK) {
- cvs_file_free(base);
- if (entfile)
- cvs_ent_close(entfile);
- return (NULL);
+ if (cvs_rootstr == NULL && cf->cf_root != NULL) {
+ cvs_rootstr = strdup(cf->cf_root->cr_str);
+ if (cvs_rootstr == NULL) {
+ cvs_log(LP_ERRNO, "strdup failed");
+ cvs_file_free(cf);
+ return (-1);
}
}
+ cvs_error = CVS_EX_OK;
+ cvs_file_free(cf);
+
+ /*
+ * Since some commands don't require any files to operate
+ * we can stop right here for those.
+ */
+ if (cvs_cmdop == CVS_OP_CHECKOUT || cvs_cmdop == CVS_OP_VERSION)
+ return (0);
+
for (i = 0; i < fsn; i++) {
strlcpy(pcopy, fspec[i], sizeof(pcopy));
- sp = pcopy;
- pwd = (!strcmp(pcopy, "."));
- np = strchr(sp, '/');
- if (np != NULL)
- *np = '\0';
+ /*
+ * Load the information.
+ */
+ cf = cvs_file_loadinfo(pcopy, flags, cb, arg, freecf);
+ if (cf == NULL)
+ continue;
- if (pwd) {
- nf = base;
+ /*
+ * If extra actions are needed, do them now.
+ */
+ if (cf->cf_type == DT_DIR) {
+ /* do possible extra actions .. */
} else {
- nf = cvs_file_find(base, pcopy);
- if (nf == NULL) {
- if (entfile != NULL)
- ent = cvs_ent_get(entfile, pcopy);
- else
- ent = NULL;
- nf = cvs_file_lget(pcopy, 0, base, ent);
- if (nf == NULL) {
- cvs_file_free(base);
- if (entfile)
- cvs_ent_close(entfile);
- return (NULL);
- }
-
- if (cvs_file_attach(base, nf) < 0) {
- cvs_file_free(base);
- if (entfile)
- cvs_ent_close(entfile);
- return (NULL);
- }
- }
+ /* do possible extra actions .. */
}
- if (nf->cf_type == DT_DIR) {
- if (np != NULL)
- *np++;
+ /*
+ * Attach it to a list if requested, otherwise
+ * just free it again.
+ */
+ if (list != NULL)
+ SIMPLEQ_INSERT_TAIL(list, cf, cf_list);
+ else
+ cvs_file_free(cf);
+ }
+
+ return (0);
+}
- if (cvs_file_getdir(nf, flags, np, cb, arg) < 0) {
- cvs_file_free(base);
- if (entfile)
- cvs_ent_close(entfile);
- return (NULL);
- }
- } else {
- if (cb != NULL) {
- if (cb(nf, arg) != CVS_EX_OK) {
- cvs_file_free(base);
- if (entfile)
- cvs_ent_close(entfile);
- return (NULL);
- }
- }
+/*
+ * Load the neccesary information about file or directory <path>.
+ * Returns a pointer to the loaded information on success, or NULL
+ * on failure.
+ *
+ * If cb is not NULL, the requested path will be passed to that callback
+ * with <arg> as an argument.
+ *
+ * the <freecf> argument is passed to cvs_file_getdir, if this is 1
+ * CVSFILE * structs will be free'd once we are done with them.
+ */
+CVSFILE *
+cvs_file_loadinfo(char *path, int flags, int (*cb)(CVSFILE *, void *),
+ void *arg, int freecf)
+{
+ CVSFILE *cf, *base;
+ CVSENTRIES *entf;
+ struct cvs_ent *ent;
+ char *p;
+ char parent[MAXPATHLEN], item[MAXPATHLEN];
+ int type;
+ struct stat st;
+ struct cvsroot *root;
+
+ type = 0;
+ base = cf = NULL;
+ entf = NULL;
+ ent = NULL;
+
+ /*
+ * We first have to find out what type of item we are
+ * dealing with. A file or a directory.
+ *
+ * We can do this by stat(2)'ing the item, but since it
+ * might be gone we also check the Entries file in the
+ * parent directory.
+ */
+
+ /* get parent directory */
+ if ((p = strrchr(path, '/')) != NULL) {
+ *p++ = '\0';
+ strlcpy(parent, path, sizeof(parent));
+ strlcpy(item, p, sizeof(item));
+ *--p = '/';
+ } else {
+ strlcpy(parent, ".", sizeof(parent));
+ strlcpy(item, path, sizeof(item));
+ }
+
+ /*
+ * There might not be an Entries file, so do not fail if there
+ * is none available to get the info from.
+ */
+ entf = cvs_ent_open(parent, O_RDONLY);
+
+ /*
+ * Load the Entry if we successfully opened the Entries file.
+ */
+ if (entf != NULL)
+ ent = cvs_ent_get(entf, item);
+
+ /*
+ * No Entry available? fall back to stat(2)'ing the item, if
+ * that fails, bail out in client mode, or assume a file in
+ * server mode (it will show up as CVS_FST_UNKNOWN).
+ */
+ if (ent == NULL) {
+ if (stat(path, &st) == -1) {
+ if (cvs_cmdop != CVS_OP_SERVER)
+ goto fail;
+ type = DT_REG;
+ } else
+ type = IFTODT(st.st_mode);
+ } else {
+ if (ent->ce_type == CVS_ENT_DIR)
+ type = DT_DIR;
+ else
+ type = DT_REG;
+ }
+
+ /*
+ * Get the base, which is <parent> for a normal file or
+ * <path> for a directory.
+ */
+ if (type == DT_DIR)
+ base = cvs_file_lget(path, flags, NULL, ent);
+ else
+ base = cvs_file_lget(parent, flags, NULL, NULL);
+
+ if (base == NULL) {
+ cvs_log(LP_ERR, "failed to obtain directory info for '%s'",
+ parent);
+ goto fail;
+ }
+
+ /*
+ * Sanity.
+ */
+ if (base->cf_type != DT_DIR) {
+ cvs_log(LP_ERR, "base directory isn't a directory at all");
+ goto fail;
+ }
+
+ root = CVS_DIR_ROOT(base);
+ if (root == NULL) {
+ cvs_log(LP_ERR, "no Root in base directory found");
+ goto fail;
+ }
+
+ /*
+ * If we have a normal file, get the info and link it
+ * to the base.
+ */
+ if (type != DT_DIR) {
+ cf = cvs_file_lget(path, flags, base, ent);
+ if (cf == NULL) {
+ cvs_log(LP_ERR, "failed to fetch '%s'", path);
+ goto fail;
}
+
+ cvs_file_attach(base, cf);
+ }
+
+ if (entf != NULL) {
+ cvs_ent_close(entf);
+ entf = NULL;
}
- if (entfile)
- cvs_ent_close(entfile);
+ /*
+ * Always pass the base directory, unless:
+ * - we are running in server or local mode and the path is not "."
+ * - the directory does not exist on disk.
+ * - the callback is NULL.
+ */
+ if (!(((cvs_cmdop == CVS_OP_SERVER) ||
+ (root->cr_method == CVS_METHOD_LOCAL)) && (strcmp(path, "."))) &&
+ (base->cf_flags & CVS_FILE_ONDISK) && (cb != NULL) &&
+ ((cvs_error = cb(base, arg)) != CVS_EX_OK))
+ goto fail;
+
+ /*
+ * If we have a normal file, pass it as well.
+ */
+ if (type != DT_DIR) {
+ if ((cb != NULL) && ((cvs_error = cb(cf, arg)) != CVS_EX_OK))
+ goto fail;
+ } else {
+ /*
+ * If the directory exists, recurse through it.
+ */
+ if ((base->cf_flags & CVS_FILE_ONDISK) &&
+ cvs_file_getdir(base, flags, cb, arg, freecf) < 0) {
+ cvs_log(LP_ERR, "cvs_file_getdir failed");
+ goto fail;
+ }
+ }
return (base);
-}
+fail:
+ if (entf != NULL)
+ cvs_ent_close(entf);
+ if (base != NULL)
+ cvs_file_free(base);
+ return (NULL);
+}
/*
* cvs_file_find()
@@ -569,46 +701,21 @@ cvs_file_find(CVSFILE *hier, const char *path)
* Get the full path of the file <file> and store it in <buf>, which is of
* size <len>. For portability, it is recommended that <buf> always be
* at least MAXPATHLEN bytes long.
- * Returns a pointer to the start of the path on success, or NULL on failure.
+ * Returns a pointer to the start of the path.
*/
char*
cvs_file_getpath(CVSFILE *file, char *buf, size_t len)
{
- u_int i;
- const char *fp, *namevec[CVS_FILE_MAXDEPTH];
- CVSFILE *top;
-
- buf[0] = '\0';
- i = CVS_FILE_MAXDEPTH;
- memset(namevec, 0, sizeof(namevec));
-
- /* find the top node */
- for (top = file; (top != NULL) && (i > 0); top = top->cf_parent) {
- fp = top->cf_name;
-
- /* skip self-references */
- if ((fp[0] == '.') && (fp[1] == '\0'))
- continue;
- namevec[--i] = fp;
- }
-
- if (i == 0)
- return (NULL);
- else if (i == CVS_FILE_MAXDEPTH) {
- strlcpy(buf, ".", len);
- return (buf);
- }
-
- while (i < CVS_FILE_MAXDEPTH - 1) {
- strlcat(buf, namevec[i++], len);
+ memset(buf, '\0', len);
+ if (file->cf_dir != NULL) {
+ strlcat(buf, file->cf_dir, len);
strlcat(buf, "/", len);
}
- strlcat(buf, namevec[i], len);
+ strlcat(buf, file->cf_name, len);
return (buf);
}
-
/*
* cvs_file_attach()
*
@@ -641,19 +748,20 @@ cvs_load_dirinfo(CVSFILE *cf, int flags)
int l;
cvs_file_getpath(cf, fpath, sizeof(fpath));
+
+ /*
+ * Try to obtain the Root for this given directory, if we cannot
+ * get it, fail, unless we are dealing with a directory that is
+ * unknown or not on disk.
+ */
cf->cf_root = cvsroot_get(fpath);
if (cf->cf_root == NULL) {
- /*
- * Do not fail here for an unknown directory.
- */
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
+ if (cf->cf_cvstat == CVS_FST_UNKNOWN ||
+ !(cf->cf_flags & CVS_FILE_ONDISK))
return (0);
return (-1);
}
-
- if (flags & CF_MKADMIN)
- cvs_mkadmin(fpath, cf->cf_root->cr_str, NULL);
-
+
/* if the CVS administrative directory exists, load the info */
l = snprintf(pbuf, sizeof(pbuf), "%s/" CVS_PATH_CVSDIR, fpath);
if (l == -1 || l >= (int)sizeof(pbuf)) {
@@ -671,8 +779,25 @@ cvs_load_dirinfo(CVSFILE *cf, int flags)
return (-1);
}
}
+ } else {
+ /*
+ * Fill in the repo path ourselfs.
+ */
+ l = snprintf(pbuf, sizeof(pbuf), "%s/%s",
+ cvs_repo_base, fpath);
+ if (l == -1 || l >= (int)sizeof(pbuf))
+ return (-1);
+
+ cf->cf_repo = strdup(pbuf);
+ if (cf->cf_repo == NULL) {
+ cvs_log(LP_ERRNO, "failed to dup repo string");
+ return (-1);
+ }
}
+ if (flags & CF_MKADMIN)
+ cvs_mkadmin(fpath, cf->cf_root->cr_str, NULL);
+
return (0);
}
@@ -684,191 +809,152 @@ cvs_load_dirinfo(CVSFILE *cf, int flags)
* is performed by cvs_file_free().
*/
static int
-cvs_file_getdir(CVSFILE *cf, int flags, char *path, int (*cb)(CVSFILE *, void *), void *arg)
+cvs_file_getdir(CVSFILE *cf, int flags, int (*cb)(CVSFILE *, void *),
+ void *arg, int freecf)
{
- int l, ret;
- int check_entry;
- u_int ndirs, nfiles;
- char *cur, *np;
- char pbuf[MAXPATHLEN], fpath[MAXPATHLEN];
- struct dirent *ent;
+ int ret;
+ size_t len;
+ DIR *dp;
+ struct dirent *de;
+ char fpath[MAXPATHLEN], pbuf[MAXPATHLEN];
+ CVSENTRIES *entf;
CVSFILE *cfp;
- struct cvs_ent *cvsent;
+ struct cvs_ent *ent;
struct cvs_flist dirs;
- DIR *dirp;
- CVSENTRIES *entfile;
-
- ret = -1;
- check_entry = 1;
- ndirs = nfiles = 0;
- SIMPLEQ_INIT(&dirs);
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
-
- cur = np = NULL;
- if (path != NULL) {
- cur = strchr(path, '/');
- if (cur != NULL) {
- *cur = '\0';
- np = cur + 1;
- if (np != NULL && *np == '\0')
- np = NULL;
- }
- }
+ int nfiles, ndirs;
if ((flags & CF_KNOWN) && (cf->cf_cvstat == CVS_FST_UNKNOWN))
return (0);
- /*
- * XXX - Do not call the callback for ".", this has
- * already been done in cvs_file_getspec().
- */
- if (cb != NULL && strcmp(cf->cf_name, ".")) {
- if (cb(cf, arg) != CVS_EX_OK)
- return (-1);
- }
-
- cf->cf_root = cvsroot_get(fpath);
- if (cf->cf_root == NULL) {
- /*
- * Do not fail here for an unknown directory.
- */
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- return (0);
- return (-1);
- }
+ nfiles = ndirs = 0;
+ SIMPLEQ_INIT(&dirs);
+ cvs_file_getpath(cf, fpath, sizeof(fpath));
- dirp = opendir(fpath);
- if (dirp == NULL) {
- cvs_log(LP_ERRNO, "failed to open directory %s", fpath);
+ if ((dp = opendir(fpath)) == NULL) {
+ cvs_log(LP_ERRNO, "failed to open directory '%s'", fpath);
return (-1);
}
- entfile = cvs_ent_open(fpath, O_RDONLY);
- while ((ent = readdir(dirp)) != NULL) {
- if ((flags & CF_IGNORE) && cvs_file_chkign(ent->d_name))
+ ret = -1;
+ entf = cvs_ent_open(fpath, O_RDONLY);
+ while ((de = readdir(dp)) != NULL) {
+ if (!strcmp(de->d_name, ".") ||
+ !strcmp(de->d_name, ".."))
continue;
- if ((flags & CF_NOSYMS) && (ent->d_type == DT_LNK))
+ /*
+ * Do some filtering on the current directory item.
+ */
+ if ((flags & CF_IGNORE) && cvs_file_chkign(de->d_name))
continue;
- if (!(flags & CF_RECURSE) && (ent->d_type == DT_DIR)) {
- if (entfile != NULL)
- (void)cvs_ent_remove(entfile,
- ent->d_name);
+ if (!(flags & CF_RECURSE) && (de->d_type == DT_DIR)) {
+ if (entf != NULL)
+ (void)cvs_ent_remove(entf, de->d_name);
continue;
}
- if ((ent->d_type != DT_DIR) && (flags & CF_NOFILES))
+ if ((de->d_type != DT_DIR) && (flags & CF_NOFILES))
continue;
- if (path != NULL) {
- if (strcmp(path, ent->d_name))
- continue;
- }
-
- l = snprintf(pbuf, sizeof(pbuf), "%s/%s", fpath,
- ent->d_name);
- if (l == -1 || l >= (int)sizeof(pbuf)) {
- errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", pbuf);
- closedir(dirp);
+ /*
+ * Obtain info about the item.
+ */
+ len = cvs_path_cat(fpath, de->d_name, pbuf, sizeof(pbuf));
+ if (len >= sizeof(pbuf))
goto done;
- }
- cfp = cvs_file_find(cf, ent->d_name);
- if (cfp == NULL) {
- if (entfile != NULL)
- cvsent = cvs_ent_get(entfile, ent->d_name);
- else
- cvsent = NULL;
-
- cfp = cvs_file_lget(pbuf, flags, cf, cvsent);
-
- if (cfp == NULL) {
- closedir(dirp);
- goto done;
- }
- if (entfile != NULL)
- cvs_ent_remove(entfile, cfp->cf_name);
+ if (entf != NULL)
+ ent = cvs_ent_get(entf, de->d_name);
+ else
+ ent = NULL;
- if (cfp->cf_type != DT_DIR) {
- SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp,
- cf_list);
- nfiles++;
- }
- } else {
- cfp->cf_flags |= CVS_GDIR_IGNORE;
+ cfp = cvs_file_lget(pbuf, flags, cf, ent);
+ if (cfp == NULL) {
+ cvs_log(LP_ERR, "failed to get '%s'", pbuf);
+ goto done;
}
- if (cfp->cf_type == DT_DIR) {
- ndirs++;
+ /*
+ * A file is linked to the parent <cf>, a directory
+ * is added to the dirs SIMPLEQ list for later use.
+ */
+ if ((cfp->cf_type != DT_DIR) && !freecf) {
+ SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list);
+ nfiles++;
+ } else if (cfp->cf_type == DT_DIR) {
SIMPLEQ_INSERT_TAIL(&dirs, cfp, cf_list);
- } else {
- /* callback for the file */
- if (cb != NULL) {
- if (cb(cfp, arg) != CVS_EX_OK) {
- closedir(dirp);
- goto done;
- }
- }
+ ndirs++;
}
- if (path != NULL) {
- check_entry = 0;
- break;
+ /*
+ * Now, for a file, pass it to the callback if it was
+ * supplied to us.
+ */
+ if (cfp->cf_type != DT_DIR && cb != NULL) {
+ if ((cvs_error = cb(cfp, arg)) != CVS_EX_OK)
+ goto done;
}
- }
- closedir(dirp);
+ /*
+ * Remove it from the Entries list to make sure it won't
+ * be picked up again when we look at the Entries.
+ */
+ if (entf != NULL)
+ (void)cvs_ent_remove(entf, de->d_name);
- if (entfile != NULL && check_entry) {
- while ((cvsent = cvs_ent_next(entfile)) != NULL) {
- if (path != NULL) {
- if (strcmp(cvsent->ce_name, path))
- continue;
- }
+ /*
+ * If we don't want to keep it, free it
+ */
+ if ((cfp->cf_type != DT_DIR) && freecf)
+ cvs_file_free(cfp);
+ }
- l = snprintf(pbuf, sizeof(pbuf), "%s/%s", fpath,
- cvsent->ce_name);
- if (l == -1 || l >= (int)sizeof(pbuf)) {
- errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", pbuf);
- goto done;
- }
+ closedir(dp);
+ dp = NULL;
- cfp = cvs_file_find(cf, cvsent->ce_name);
- if (cfp == NULL) {
- cfp = cvs_file_lget(pbuf, flags, cf, cvsent);
- if (cfp == NULL)
- continue;
+ /*
+ * Pass over all of the entries now, so we pickup any files
+ * that might have been lost, or are for some reason not on disk.
+ *
+ * (Follows the same procedure as above ... can we merge them?)
+ */
+ while ((entf != NULL) && ((ent = cvs_ent_next(entf)) != NULL)) {
+ if (!(flags & CF_RECURSE) && (ent->ce_type == CVS_ENT_DIR))
+ continue;
+ if ((flags & CF_NOFILES) && (ent->ce_type != CVS_ENT_DIR))
+ continue;
- if (cfp->cf_type != DT_DIR) {
- SIMPLEQ_INSERT_TAIL(&(cf->cf_files),
- cfp, cf_list);
- nfiles++;
- }
- } else {
- cfp->cf_flags |= CVS_GDIR_IGNORE;
- }
+ len = cvs_path_cat(fpath, ent->ce_name, pbuf, sizeof(pbuf));
+ if (len >= sizeof(pbuf))
+ goto done;
- if (cfp->cf_type == DT_DIR) {
- ndirs++;
- SIMPLEQ_INSERT_TAIL(&dirs, cfp,
- cf_list);
- } else {
- /* callback for the file */
- if (cb != NULL) {
- if (cb(cfp, arg) != CVS_EX_OK)
- goto done;
- }
- }
+ cfp = cvs_file_lget(pbuf, flags, cf, ent);
+ if (cfp == NULL) {
+ cvs_log(LP_ERR, "failed to fetch '%s'", pbuf);
+ goto done;
+ }
- if (path != NULL)
- break;
+ if ((cfp->cf_type != DT_DIR) && !freecf) {
+ SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list);
+ nfiles++;
+ } else if (cfp->cf_type == DT_DIR) {
+ SIMPLEQ_INSERT_TAIL(&dirs, cfp, cf_list);
+ ndirs++;
+ }
+
+ if (cfp->cf_type != DT_DIR && cb != NULL) {
+ if ((cvs_error = cb(cfp, arg)) != CVS_EX_OK)
+ goto done;
}
+
+ if ((cfp->cf_type != DT_DIR) && freecf)
+ cvs_file_free(cfp);
}
+ /*
+ * Sort files and dirs if requested.
+ */
if (flags & CF_SORT) {
if (nfiles > 0)
cvs_file_sort(&(cf->cf_files), nfiles);
@@ -876,25 +962,48 @@ cvs_file_getdir(CVSFILE *cf, int flags, char *path, int (*cb)(CVSFILE *, void *)
cvs_file_sort(&dirs, ndirs);
}
+ /*
+ * Finally, run over the directories we have encountered.
+ * Before calling cvs_file_getdir() on them, we pass them
+ * to the callback first.
+ */
while (!SIMPLEQ_EMPTY(&dirs)) {
cfp = SIMPLEQ_FIRST(&dirs);
SIMPLEQ_REMOVE_HEAD(&dirs, cf_list);
- if (!(cfp->cf_flags & CVS_GDIR_IGNORE))
+ if (!freecf)
SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list);
- else
- cfp->cf_flags &= ~CVS_GDIR_IGNORE;
- if (cvs_file_getdir(cfp, flags, np, cb, arg) < 0) {
- cvs_log(LP_ERR, "failed to get %s", cfp->cf_name);
- continue;
+ if (cb != NULL) {
+ if ((cvs_error = cb(cfp, arg)) != CVS_EX_OK)
+ goto done;
}
+
+ if ((cfp->cf_flags & CVS_FILE_ONDISK) &&
+ (cvs_file_getdir(cfp, flags, cb, arg, freecf) < 0))
+ goto done;
+
+ if (freecf)
+ cvs_file_free(cfp);
}
ret = 0;
+ cfp = NULL;
done:
- if (entfile != NULL)
- cvs_ent_close(entfile);
+ if ((cfp != NULL) && freecf)
+ cvs_file_free(cfp);
+
+ while (!SIMPLEQ_EMPTY(&dirs)) {
+ cfp = SIMPLEQ_FIRST(&dirs);
+ SIMPLEQ_REMOVE_HEAD(&dirs, cf_list);
+
+ cvs_file_free(cfp);
+ }
+
+ if (entf != NULL)
+ cvs_ent_close(entf);
+ if (dp != NULL)
+ closedir(dp);
return (ret);
}
@@ -913,6 +1022,9 @@ cvs_file_free(CVSFILE *cf)
if (cf->cf_name != NULL)
cvs_strfree(cf->cf_name);
+ if (cf->cf_dir != NULL)
+ cvs_strfree(cf->cf_dir);
+
if (cf->cf_type == DT_DIR) {
if (cf->cf_root != NULL)
cvsroot_free(cf->cf_root);
@@ -937,9 +1049,7 @@ cvs_file_free(CVSFILE *cf)
/*
* cvs_file_examine()
*
- * Examine the contents of the CVS file structure <cf> with the function
- * <exam>. The function is called for all subdirectories and files of the
- * root file.
+ * Walk through the files, calling the callback as we go.
*/
int
cvs_file_examine(CVSFILE *cf, int (*exam)(CVSFILE *, void *), void *arg)
@@ -947,16 +1057,8 @@ cvs_file_examine(CVSFILE *cf, int (*exam)(CVSFILE *, void *), void *arg)
int ret;
CVSFILE *fp;
- if (cf->cf_type == DT_DIR) {
- ret = (*exam)(cf, arg);
- SIMPLEQ_FOREACH(fp, &(cf->cf_files), cf_list) {
- ret = cvs_file_examine(fp, exam, arg);
- if (ret != 0)
- break;
- }
- } else
- ret = (*exam)(cf, arg);
-
+ fp = NULL;
+ ret = 0;
return (ret);
}
@@ -1033,6 +1135,7 @@ CVSFILE*
cvs_file_alloc(const char *path, u_int type)
{
CVSFILE *cfp;
+ char *p;
cfp = (CVSFILE *)malloc(sizeof(*cfp));
if (cfp == NULL) {
@@ -1055,6 +1158,22 @@ cvs_file_alloc(const char *path, u_int type)
return (NULL);
}
+ if ((p = strrchr(path, '/')) != NULL) {
+ *p = '\0';
+ if (strcmp(path, ".")) {
+ cfp->cf_dir = cvs_strdup(path);
+ if (cfp->cf_dir == NULL) {
+ cvs_log(LP_ERR,
+ "failed to copy directory");
+ cvs_file_free(cfp);
+ return (NULL);
+ }
+ } else
+ cfp->cf_dir = NULL;
+ *p = '/';
+ } else
+ cfp->cf_dir = NULL;
+
return (cfp);
}
@@ -1069,14 +1188,12 @@ cvs_file_alloc(const char *path, u_int type)
static CVSFILE*
cvs_file_lget(const char *path, int flags, CVSFILE *parent, struct cvs_ent *ent)
{
- int ret, cwd;
+ int ret;
u_int type;
struct stat st;
CVSFILE *cfp;
type = DT_UNKNOWN;
- cwd = (strcmp(path, ".") == 0) ? 1 : 0;
-
ret = stat(path, &st);
if (ret == 0)
type = IFTODT(st.st_mode);
@@ -1092,10 +1209,13 @@ cvs_file_lget(const char *path, int flags, CVSFILE *parent, struct cvs_ent *ent)
cfp->cf_mode = st.st_mode & ACCESSPERMS;
if (cfp->cf_type == DT_REG)
cfp->cf_mtime = st.st_mtime;
+ cfp->cf_flags |= CVS_FILE_ONDISK;
if (ent == NULL)
- cfp->cf_cvstat = (cwd == 1) ?
- CVS_FST_UPTODATE : CVS_FST_UNKNOWN;
+ if (cfp->cf_flags & CVS_DIRF_BASE)
+ cfp->cf_cvstat = CVS_FST_UPTODATE;
+ else
+ cfp->cf_cvstat = CVS_FST_UNKNOWN;
else {
/* always show directories as up-to-date */
if (ent->ce_type == CVS_ENT_DIR)
@@ -1171,6 +1291,24 @@ cvs_file_lget(const char *path, int flags, CVSFILE *parent, struct cvs_ent *ent)
!strcmp(cfp->cf_repo, path))
cfp->cf_cvstat = CVS_FST_UPTODATE;
+ /*
+ * In server mode, we do a few extra checks.
+ */
+ if (cvs_cmdop == CVS_OP_SERVER) {
+ /*
+ * If for some reason a file was added,
+ * but does not exist anymore, start complaining.
+ */
+ if (!(cfp->cf_flags & CVS_FILE_ONDISK) &&
+ (cfp->cf_cvstat == CVS_FST_ADDED) &&
+ (cfp->cf_type != DT_DIR))
+ cvs_log(LP_WARN, "new-born %s has disappeared", path);
+
+ /*
+ * Any other needed checks?
+ */
+ }
+
return (cfp);
}
@@ -1183,8 +1321,7 @@ cvs_file_cmpname(const char *name1, const char *name2)
}
/*
- * remove a directory if it does not contain
- * any files other than the CVS/ administrative files.
+ * remove any empty directories.
*/
int
cvs_file_prune(char *path)
diff --git a/usr.bin/cvs/file.h b/usr.bin/cvs/file.h
index adbe72005d8..231519852d7 100644
--- a/usr.bin/cvs/file.h
+++ b/usr.bin/cvs/file.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: file.h,v 1.24 2005/07/22 16:27:29 joris Exp $ */
+/* $OpenBSD: file.h,v 1.25 2005/07/23 11:19:46 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -75,7 +75,15 @@ SIMPLEQ_HEAD(cvs_flist, cvs_file);
typedef struct cvs_file {
struct cvs_file *cf_parent; /* parent directory (NULL if none) */
- const char *cf_name;
+
+ /*
+ * cf_name contains the basename of the fullpath
+ * cf_dir contains the parent directory the file or dir is in.
+ * if cf_dir is NULL the file is in the parent directory.
+ */
+ const char *cf_name;
+ const char *cf_dir;
+
mode_t cf_mode;
u_int8_t cf_cvstat; /* cvs status of the file */
u_int8_t cf_type; /* uses values from dirent.h */
@@ -116,8 +124,8 @@ typedef struct cvs_file {
#define CVS_DIRF_STATIC 0x01
#define CVS_DIRF_STICKY 0x02
#define CVS_DIRF_BASE 0x04
-
#define CVS_GDIR_IGNORE 0x08
+#define CVS_FILE_ONDISK 0x10
#define CVS_DIR_ROOT(f) ((((f)->cf_type == DT_DIR) && \
((f)->cf_root != NULL)) ? (f)->cf_root : \
@@ -130,8 +138,13 @@ typedef struct cvs_file {
int cvs_file_init (void);
int cvs_file_ignore (const char *);
int cvs_file_chkign (const char *);
-CVSFILE* cvs_file_get (const char *, int, int (*)(CVSFILE *, void *), void *);
-CVSFILE* cvs_file_getspec (char **, int, int, int (*)(CVSFILE *, void *), void *);
+int cvs_file_get (const char *, int, int (*)(CVSFILE *, void *),
+ void *, struct cvs_flist *);
+int cvs_file_getspec (char **, int, int, int (*)(CVSFILE *, void *),
+ void *, struct cvs_flist *);
+CVSFILE* cvs_file_loadinfo(char *, int, int (*)(CVSFILE *, void *), void *,
+int);
+
CVSFILE* cvs_file_create (CVSFILE *, const char *, u_int, mode_t);
CVSFILE* cvs_file_copy (CVSFILE *);
int cvs_file_attach (CVSFILE *, CVSFILE *);
diff --git a/usr.bin/cvs/proto.c b/usr.bin/cvs/proto.c
index f08fffee75d..52c49df64d2 100644
--- a/usr.bin/cvs/proto.c
+++ b/usr.bin/cvs/proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: proto.c,v 1.63 2005/07/23 00:44:13 joris Exp $ */
+/* $OpenBSD: proto.c,v 1.64 2005/07/23 11:19:46 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -715,6 +715,7 @@ cvs_sendreq(struct cvsroot *root, u_int rid, const char *arg)
if (req->req_flags & CVS_REQF_RESP)
ret = cvs_getresp(root);
+ printf("cvs_sendreq returning %d\n", ret);
return (ret);
}
@@ -756,6 +757,7 @@ cvs_getresp(struct cvsroot *root)
}
ret = cvs_resp_handle(root, cvs_proto_buf);
+ printf("(%s) (%d)\n", cvs_proto_buf, ret);
nbcmd++;
} while (ret == 0);
diff --git a/usr.bin/cvs/resp.c b/usr.bin/cvs/resp.c
index debc20ff21f..ed645865c54 100644
--- a/usr.bin/cvs/resp.c
+++ b/usr.bin/cvs/resp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: resp.c,v 1.46 2005/07/22 16:27:29 joris Exp $ */
+/* $OpenBSD: resp.c,v 1.47 2005/07/23 11:19:46 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -72,7 +72,7 @@ static int cvs_resp_modxpand (struct cvsroot *, int, char *);
static int cvs_resp_rcsdiff (struct cvsroot *, int, char *);
static int cvs_resp_template (struct cvsroot *, int, char *);
static int cvs_resp_copyfile (struct cvsroot *, int, char *);
-
+static int cvs_resp_createdir (char *);
struct cvs_resphdlr {
int (*hdlr)(struct cvsroot *, int, char *);
@@ -345,7 +345,6 @@ cvs_resp_statdir(struct cvsroot *root, int type, char *line)
{
int fd, len;
char rpath[MAXPATHLEN], statpath[MAXPATHLEN];
- struct stat dst;
/* remote directory line */
if (cvs_getln(root, rpath, sizeof(rpath)) < 0)
@@ -353,13 +352,11 @@ cvs_resp_statdir(struct cvsroot *root, int type, char *line)
STRIP_SLASH(line);
- /* if the directory doesn't exist, first create it */
- if ((stat(line, &dst) == -1) && (errno == ENOENT)) {
- if ((mkdir(line, 0755) == -1) && (errno != ENOENT)) {
- cvs_log(LP_ERRNO, "failed to create %s", line);
- return (-1);
- }
- }
+ /*
+ * Create the directory if it does not exist.
+ */
+ if (cvs_resp_createdir(line) < 0)
+ return (-1);
len = snprintf(statpath, sizeof(statpath), "%s/%s", line,
CVS_PATH_STATICENTRIES);
@@ -395,16 +392,12 @@ cvs_resp_statdir(struct cvsroot *root, int type, char *line)
* cvs_resp_sticky()
*
* Handler for the `Clear-sticky' and `Set-sticky' responses. If the
- * specified directory doesn't exist, we create it and attach it to the
- * global file structure.
+ * specified directory doesn't exist, we create it.
*/
static int
cvs_resp_sticky(struct cvsroot *root, int type, char *line)
{
- char buf[MAXPATHLEN], subdir[MAXPATHLEN], *file;
- struct cvs_ent *ent;
- CVSFILE *cf, *sdir;
- CVSENTRIES *entf;
+ char buf[MAXPATHLEN];
/* get the remote path */
if (cvs_getln(root, buf, sizeof(buf)) < 0)
@@ -412,31 +405,44 @@ cvs_resp_sticky(struct cvsroot *root, int type, char *line)
STRIP_SLASH(line);
+ if (cvs_resp_createdir(line) < 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Shared code for cvs_resp[static, sticky]
+ *
+ * Looks if the directory requested exists, if it doesn't it will
+ * create it plus all administrative files as well.
+ */
+static int
+cvs_resp_createdir(char *line)
+{
+ CVSFILE *base, *cf;
+ CVSENTRIES *entf;
+ struct stat st;
+ struct cvs_ent *ent;
+ char *file, subdir[MAXPATHLEN], buf[MAXPATHLEN];
+
cvs_splitpath(line, subdir, sizeof(subdir), &file);
- sdir = cvs_file_find(cvs_files, subdir);
- if (sdir == NULL) {
- cvs_log(LP_ERR, "failed to find %s", subdir);
+ base = cvs_file_loadinfo(subdir, CF_NOFILES, NULL, NULL, 1);
+ if (base == NULL)
return (-1);
- }
- cf = cvs_file_find(sdir, file);
- if (cf == NULL) {
- /* attempt to create it */
- cf = cvs_file_create(sdir, line, DT_DIR, 0755);
- if (cf == NULL) {
- return (-1);
- }
- cf->cf_repo = strdup(line);
- if (cf->cf_repo == NULL) {
- cvs_log(LP_ERRNO, "failed to duplicate `%s'", line);
- cvs_file_free(cf);
+ /*
+ * If <line> doesn't exist, we create it.
+ */
+ if (stat(line, &st) == -1) {
+ if (errno != ENOENT) {
+ cvs_log(LP_ERRNO, "failed to stat '%s'", line);
return (-1);
}
- cf->cf_root = root;
- root->cr_ref++;
- if (cvs_file_attach(sdir, cf) < 0) {
- cvs_file_free(cf);
+ cf = cvs_file_create(base, line, DT_DIR, 0755);
+ if (cf == NULL) {
+ cvs_file_free(base);
return (-1);
}
@@ -466,13 +472,11 @@ cvs_resp_sticky(struct cvsroot *root, int type, char *line)
if (strcmp(subdir, cvs_resp_lastdir))
cvs_ent_close(entf);
}
- }
- if (type == CVS_RESP_CLRSTICKY)
- cf->cf_flags &= ~CVS_DIRF_STICKY;
- else if (type == CVS_RESP_SETSTICKY)
- cf->cf_flags |= CVS_DIRF_STICKY;
+ cvs_file_free(cf);
+ }
+ cvs_file_free(base);
return (0);
}
diff --git a/usr.bin/cvs/update.c b/usr.bin/cvs/update.c
index 458ccf8133a..9fb6dd78b7e 100644
--- a/usr.bin/cvs/update.c
+++ b/usr.bin/cvs/update.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: update.c,v 1.40 2005/07/21 11:42:24 xsa Exp $ */
+/* $OpenBSD: update.c,v 1.41 2005/07/23 11:19:46 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -189,6 +189,9 @@ cvs_update_remote(CVSFILE *cf, void *arg)
if (cvs_sendentry(root, cf) < 0)
return (CVS_EX_PROTO);
+ if (!(cf->cf_flags & CVS_FILE_ONDISK))
+ return (0);
+
switch (cf->cf_cvstat) {
case CVS_FST_UNKNOWN:
ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);