version 1.78, 2006/04/14 02:45:35 |
version 1.79, 2006/05/27 03:30:31 |
|
|
#include "log.h" |
#include "log.h" |
#include "util.h" |
#include "util.h" |
|
|
#if !defined(RCSPROG) |
|
/* letter -> mode type map */ |
/* letter -> mode type map */ |
static const int cvs_modetypes[26] = { |
static const int cvs_modetypes[26] = { |
-1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, |
|
|
"", "x", "w", "wx", "r", "rx", "rw", "rwx" |
"", "x", "w", "wx", "r", "rx", "rw", "rwx" |
}; |
}; |
|
|
|
|
|
|
/* |
/* |
* cvs_readrepo() |
|
* |
|
* Read the path stored in the `Repository' CVS file for a given directory |
|
* <dir>, and store that path into the buffer pointed to by <dst>, whose size |
|
* is <len>. |
|
*/ |
|
int |
|
cvs_readrepo(const char *dir, char *dst, size_t len) |
|
{ |
|
size_t dlen, l; |
|
FILE *fp; |
|
char repo_path[MAXPATHLEN]; |
|
|
|
l = cvs_path_cat(dir, "CVS/Repository", repo_path, sizeof(repo_path)); |
|
if (l >= sizeof(repo_path)) |
|
return (-1); |
|
|
|
fp = fopen(repo_path, "r"); |
|
if (fp == NULL) |
|
return (-1); |
|
|
|
if (fgets(dst, (int)len, fp) == NULL) { |
|
if (ferror(fp)) { |
|
cvs_log(LP_ERRNO, "failed to read from `%s'", |
|
repo_path); |
|
} |
|
(void)fclose(fp); |
|
return (-1); |
|
} |
|
dlen = strlen(dst); |
|
if (dlen > 0 && dst[dlen - 1] == '\n') |
|
dst[--dlen] = '\0'; |
|
|
|
(void)fclose(fp); |
|
return (0); |
|
} |
|
|
|
|
|
/* |
|
* cvs_strtomode() |
* cvs_strtomode() |
* |
* |
* Read the contents of the string <str> and generate a permission mode from |
* Read the contents of the string <str> and generate a permission mode from |
|
|
memset(ms, 0, sizeof ms); |
memset(ms, 0, sizeof ms); |
if (sscanf(sp, "%c=%3s", &type, ms) != 2 && |
if (sscanf(sp, "%c=%3s", &type, ms) != 2 && |
sscanf(sp, "%c=", &type) != 1) { |
sscanf(sp, "%c=", &type) != 1) { |
cvs_log(LP_WARN, "failed to scan mode string `%s'", sp); |
cvs_log(LP_ERR, "failed to scan mode string `%s'", sp); |
continue; |
continue; |
} |
} |
|
|
if (type <= 'a' || type >= 'z' || |
if (type <= 'a' || type >= 'z' || |
cvs_modetypes[type - 'a'] == -1) { |
cvs_modetypes[type - 'a'] == -1) { |
cvs_log(LP_WARN, |
cvs_log(LP_ERR, |
"invalid mode type `%c'" |
"invalid mode type `%c'" |
" (`u', `g' or `o' expected), ignoring", type); |
" (`u', `g' or `o' expected), ignoring", type); |
continue; |
continue; |
|
|
for (sp = ms; *sp != '\0'; sp++) { |
for (sp = ms; *sp != '\0'; sp++) { |
if (*sp <= 'a' || *sp >= 'z' || |
if (*sp <= 'a' || *sp >= 'z' || |
cvs_modes[(int)type][*sp - 'a'] == 0) { |
cvs_modes[(int)type][*sp - 'a'] == 0) { |
cvs_log(LP_WARN, |
cvs_log(LP_ERR, |
"invalid permission bit `%c'", *sp); |
"invalid permission bit `%c'", *sp); |
} else |
} else |
m |= cvs_modes[(int)type][*sp - 'a']; |
m |= cvs_modes[(int)type][*sp - 'a']; |
|
|
*mode = m; |
*mode = m; |
} |
} |
|
|
|
|
/* |
/* |
* cvs_modetostr() |
* cvs_modetostr() |
* |
* |
|
|
cvs_cksum(const char *file, char *dst, size_t len) |
cvs_cksum(const char *file, char *dst, size_t len) |
{ |
{ |
if (len < CVS_CKSUM_LEN) { |
if (len < CVS_CKSUM_LEN) { |
cvs_log(LP_WARN, "buffer too small for checksum"); |
cvs_log(LP_ERR, "buffer too small for checksum"); |
return (-1); |
return (-1); |
} |
} |
if (MD5File(file, dst) == NULL) { |
if (MD5File(file, dst) == NULL) { |
cvs_log(LP_ERRNO, "failed to generate checksum for %s", file); |
cvs_log(LP_ERR, "failed to generate checksum for %s", file); |
return (-1); |
return (-1); |
} |
} |
|
|
|
|
return (argc); |
return (argc); |
} |
} |
|
|
|
|
/* |
/* |
* cvs_makeargv() |
* cvs_makeargv() |
* |
* |
|
|
return (copy); |
return (copy); |
} |
} |
|
|
|
|
/* |
/* |
* cvs_freeargv() |
* cvs_freeargv() |
* |
* |
|
|
xfree(argv[i]); |
xfree(argv[i]); |
} |
} |
|
|
|
|
/* |
/* |
* cvs_mkadmin() |
|
* |
|
* Create the CVS administrative files within the directory <cdir>. If the |
|
* files already exist, they are kept as is. |
|
* Returns 0 on success, or -1 on failure. |
|
*/ |
|
int |
|
cvs_mkadmin(const char *dpath, const char *rootpath, const char *repopath, |
|
char *tag, char *date, int nb) |
|
{ |
|
size_t l; |
|
char path[MAXPATHLEN]; |
|
FILE *fp; |
|
CVSENTRIES *ef; |
|
struct stat st; |
|
|
|
cvs_log(LP_TRACE, "cvs_mkadmin(%s, %s, %s, %s, %s, %d)", |
|
dpath, rootpath, repopath, tag ? tag : "", date ? date : "", nb); |
|
|
|
l = cvs_path_cat(dpath, CVS_PATH_CVSDIR, path, sizeof(path)); |
|
if (l >= sizeof(path)) |
|
fatal("cvs_mkadmin: path truncation"); |
|
|
|
if (mkdir(path, 0755) == -1 && errno != EEXIST) |
|
fatal("cvs_mkadmin: mkdir: `%s': %s", path, strerror(errno)); |
|
|
|
/* just create an empty Entries file */ |
|
ef = cvs_ent_open(dpath, O_WRONLY); |
|
if (ef != NULL) |
|
cvs_ent_close(ef); |
|
|
|
l = cvs_path_cat(dpath, CVS_PATH_ROOTSPEC, path, sizeof(path)); |
|
if (l >= sizeof(path)) |
|
fatal("cvs_mkadmin: path truncation"); |
|
|
|
if (stat(path, &st) == -1 && errno == ENOENT) { |
|
if ((fp = fopen(path, "w")) == NULL) |
|
fatal("cvs_mkadmin: fopen: `%s': %s", |
|
path, strerror(errno)); |
|
|
|
if (rootpath != NULL) |
|
fprintf(fp, "%s\n", rootpath); |
|
(void)fclose(fp); |
|
} |
|
|
|
l = cvs_path_cat(dpath, CVS_PATH_REPOSITORY, path, sizeof(path)); |
|
if (l >= sizeof(path)) |
|
fatal("cvs_mkadmin: path truncation"); |
|
|
|
if (stat(path, &st) == -1 && errno == ENOENT) { |
|
if ((fp = fopen(path, "w")) == NULL) |
|
fatal("cvs_mkadmin: fopen: `%s': %s", |
|
path, strerror(errno)); |
|
|
|
if (repopath != NULL) |
|
fprintf(fp, "%s\n", repopath); |
|
(void)fclose(fp); |
|
} |
|
|
|
/* create CVS/Tag file (if needed) */ |
|
/* XXX correct? */ |
|
if (tag != NULL || date != NULL) |
|
(void)cvs_write_tagfile(tag, date, nb); |
|
|
|
return (0); |
|
} |
|
|
|
|
|
/* |
|
* cvs_exec() |
* cvs_exec() |
*/ |
*/ |
int |
int |
|
|
pid_t pid; |
pid_t pid; |
|
|
if ((pid = fork()) == -1) { |
if ((pid = fork()) == -1) { |
cvs_log(LP_ERRNO, "failed to fork"); |
cvs_log(LP_ERR, "failed to fork"); |
return (-1); |
return (-1); |
} else if (pid == 0) { |
} else if (pid == 0) { |
execvp(argv[0], argv); |
execvp(argv[0], argv); |
cvs_log(LP_ERRNO, "failed to exec %s", argv[0]); |
cvs_log(LP_ERR, "failed to exec %s", argv[0]); |
exit(1); |
exit(1); |
} |
} |
|
|
if (waitpid(pid, &ret, 0) == -1) |
if (waitpid(pid, &ret, 0) == -1) |
cvs_log(LP_ERRNO, "failed to waitpid"); |
cvs_log(LP_ERR, "failed to waitpid"); |
|
|
return (ret); |
return (ret); |
} |
} |
|
|
return (0); |
return (0); |
|
|
if (unlink(path) == -1 && errno != ENOENT) { |
if (unlink(path) == -1 && errno != ENOENT) { |
cvs_log(LP_ERRNO, "cannot remove `%s'", path); |
cvs_log(LP_ERR, "cannot remove `%s'", path); |
return (-1); |
return (-1); |
} |
} |
|
|
|
|
return (0); |
return (0); |
|
|
if ((dirp = opendir(path)) == NULL) { |
if ((dirp = opendir(path)) == NULL) { |
cvs_log(LP_ERRNO, "failed to open '%s'", path); |
cvs_log(LP_ERR, "failed to open '%s'", path); |
return (-1); |
return (-1); |
} |
} |
|
|
|
|
|
|
|
|
if (rmdir(path) == -1 && errno != ENOENT) { |
if (rmdir(path) == -1 && errno != ENOENT) { |
cvs_log(LP_ERRNO, "failed to remove '%s'", path); |
cvs_log(LP_ERR, "failed to remove '%s'", path); |
goto done; |
goto 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) |
|
{ |
|
int ret; |
|
char *d, *s; |
|
struct stat sb; |
|
char rpath[MAXPATHLEN], entry[MAXPATHLEN]; |
|
CVSENTRIES *entf; |
|
struct cvs_ent *ent; |
|
|
|
if (create_adm == 1 && root == NULL) |
|
fatal("cvs_create_dir failed"); |
|
|
|
s = xstrdup(path); |
|
rpath[0] = '\0'; |
|
if (repo != NULL) { |
|
if (strlcpy(rpath, repo, sizeof(rpath)) >= sizeof(rpath)) |
|
fatal("cvs_create_dir: path truncation"); |
|
|
|
if (strlcat(rpath, "/", sizeof(rpath)) >= sizeof(rpath)) |
|
fatal("cvs_create_dir: path truncation"); |
|
} |
|
|
|
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 == 1) { |
|
if (strlcat(rpath, d, sizeof(rpath)) >= sizeof(rpath)) |
|
fatal("cvs_create_dir: path truncation"); |
|
|
|
if (strlcat(rpath, "/", sizeof(rpath)) >= sizeof(rpath)) |
|
fatal("cvs_create_dir: path truncation"); |
|
|
|
cvs_mkadmin(d, root, rpath, NULL, NULL, 0); |
|
} |
|
|
|
/* |
|
* Add it to the parent directory entry file. |
|
* (if any). |
|
*/ |
|
entf = cvs_ent_open(".", O_RDWR); |
|
if (entf != NULL && strcmp(d, ".")) { |
|
if (strlcpy(entry, "D/", sizeof(entry)) >= |
|
sizeof(entry) || |
|
strlcat(entry, d, sizeof(entry)) >= sizeof(entry) || |
|
strlcat(entry, "////", sizeof(entry)) >= |
|
sizeof(entry)) |
|
fatal("cvs_create_dir: overflow in entry buf"); |
|
|
|
if ((ent = cvs_ent_parse(entry)) == NULL) { |
|
cvs_log(LP_ERR, "failed to parse entry"); |
|
goto done; |
|
} |
|
|
|
cvs_ent_remove(entf, d, 0); |
|
|
|
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. */ |
|
cvs_chdir(d, 0); |
|
|
|
d = strtok(NULL, "/"); |
|
} |
|
|
|
ret = 0; |
|
done: |
|
if (entf != NULL) |
|
cvs_ent_close(entf); |
|
xfree(s); |
|
return (ret); |
|
} |
|
|
|
/* |
|
* cvs_path_cat() |
* cvs_path_cat() |
* |
* |
* Concatenate the two paths <base> and <end> and store the generated path |
* Concatenate the two paths <base> and <end> and store the generated path |
|
|
len = strlcpy(dst, base, dlen); |
len = strlcpy(dst, base, dlen); |
if (len >= dlen - 1) { |
if (len >= dlen - 1) { |
errno = ENAMETOOLONG; |
errno = ENAMETOOLONG; |
cvs_log(LP_ERRNO, "%s", dst); |
fatal("overflow in cvs_path_cat"); |
} else { |
} else { |
dst[len] = '/'; |
dst[len] = '/'; |
dst[len + 1] = '\0'; |
dst[len + 1] = '\0'; |
len = strlcat(dst, end, dlen); |
len = strlcat(dst, end, dlen); |
if (len >= dlen) { |
if (len >= dlen) { |
errno = ENAMETOOLONG; |
errno = ENAMETOOLONG; |
cvs_log(LP_ERRNO, "%s", dst); |
cvs_log(LP_ERR, "%s", dst); |
} |
} |
} |
} |
|
|
|
|
} |
} |
|
|
/* |
/* |
* cvs_rcs_getpath() |
* a hack to mimic and thus match gnu cvs behaviour. |
* |
|
* Get the RCS 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. |
|
*/ |
*/ |
char * |
time_t |
cvs_rcs_getpath(CVSFILE *file, char *buf, size_t len) |
cvs_hack_time(time_t oldtime, int togmt) |
{ |
{ |
char *repo; |
int l; |
struct cvsroot *root; |
struct tm *t; |
|
char tbuf[32]; |
|
|
root = CVS_DIR_ROOT(file); |
if (togmt == 1) { |
repo = CVS_DIR_REPO(file); |
t = gmtime(&oldtime); |
|
if (t == NULL) |
|
return (0); |
|
|
if (strlcpy(buf, root->cr_dir, len) >= len || |
return (mktime(t)); |
strlcat(buf, "/", len) >= len || |
} |
strlcat(buf, repo, len) >= len || |
|
strlcat(buf, "/", len) >= len || |
|
strlcat(buf, file->cf_name, len) >= len || |
|
strlcat(buf, RCS_FILE_EXT, len) >= len) |
|
fatal("cvs_rcs_getpath: path truncation"); |
|
|
|
return (buf); |
t = localtime(&oldtime); |
|
|
|
l = snprintf(tbuf, sizeof(tbuf), "%d/%d/%d GMT %d:%d:%d", |
|
t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, |
|
t->tm_min, t->tm_sec); |
|
if (l == -1 || l >= (int)sizeof(tbuf)) |
|
return (0); |
|
|
|
return (cvs_date_parse(tbuf)); |
} |
} |
|
|
/* |
|
* cvs_write_tagfile() |
|
* |
|
* Write the CVS/Tag file for current directory. |
|
*/ |
|
void |
void |
cvs_write_tagfile(char *tag, char *date, int nb) |
cvs_get_repo(const char *dir, char *dst, size_t len) |
{ |
{ |
|
int l; |
FILE *fp; |
FILE *fp; |
char tagpath[MAXPATHLEN]; |
char *s, buf[MAXPATHLEN], fpath[MAXPATHLEN]; |
|
|
if (cvs_noexec == 1) |
if (strlcpy(buf, dir, sizeof(buf)) >= sizeof(buf)) |
return; |
fatal("cvs_get_repo: truncation"); |
|
|
if (strlcpy(tagpath, CVS_PATH_TAG, sizeof(tagpath)) >= sizeof(tagpath)) |
l = snprintf(fpath, sizeof(fpath), "%s/%s", dir, CVS_PATH_REPOSITORY); |
return; |
if (l == -1 || l >= (int)sizeof(fpath)) |
|
fatal("cvs_get_repo: overflow"); |
|
|
if (tag != NULL || date != NULL) { |
if ((fp = fopen(fpath, "r")) != NULL) { |
fp = fopen(tagpath, "w+"); |
fgets(buf, sizeof(buf), fp); |
if (fp == NULL) { |
|
if (errno != ENOENT) |
if ((s = strrchr(buf, '\n')) != NULL) |
cvs_log(LP_NOTICE, |
*s = '\0'; |
"failed to open `%s' : %s", tagpath, |
|
strerror(errno)); |
|
return; |
|
} |
|
if (tag != NULL) { |
|
if (nb != 0) |
|
fprintf(fp, "N%s\n", tag); |
|
else |
|
fprintf(fp, "T%s\n", tag); |
|
} else { |
|
fprintf(fp, "D%s\n", date); |
|
} |
|
(void)fclose(fp); |
(void)fclose(fp); |
} else { |
|
cvs_unlink(tagpath); |
|
return; |
|
} |
} |
|
|
|
l = snprintf(dst, len, "%s/%s", current_cvsroot->cr_dir, buf); |
|
if (l == -1 || l >= (int)len) |
|
fatal("cvs_get_repo: overflow"); |
} |
} |
|
|
/* |
|
* cvs_parse_tagfile() |
|
* |
|
* Parse the CVS/Tag file for current directory. |
|
* |
|
* If it contains a branch tag, sets <tagp>. |
|
* If it contains a date, sets <datep>. |
|
* If it contains a non-branch tag, sets <nbp>. |
|
* |
|
* Returns nothing but an error message, and sets <tagp>, <datep> to NULL |
|
* and <nbp> to 0. |
|
*/ |
|
void |
void |
cvs_parse_tagfile(char **tagp, char **datep, int *nbp) |
cvs_mkadmin(const char *path, const char *root, const char *repo) |
{ |
{ |
FILE *fp; |
FILE *fp; |
int linenum; |
|
size_t len; |
size_t len; |
char linebuf[128], tagpath[MAXPATHLEN]; |
struct stat st; |
|
char buf[MAXPATHLEN]; |
|
|
if (tagp != NULL) |
cvs_log(LP_TRACE, "cvs_mkadmin(%s, %s, %s)", path, root, repo); |
*tagp = (char *)NULL; |
|
|
|
if (datep != NULL) |
len = cvs_path_cat(path, CVS_PATH_CVSDIR, buf, sizeof(buf)); |
*datep = (char *)NULL; |
if (len >= sizeof(buf)) |
|
fatal("cvs_mkadmin: truncation"); |
|
|
if (nbp != NULL) |
if (stat(buf, &st) != -1) |
*nbp = 0; |
|
|
|
if (strlcpy(tagpath, CVS_PATH_TAG, sizeof(tagpath)) >= sizeof(tagpath)) |
|
return; |
return; |
|
|
fp = fopen(tagpath, "r"); |
if (mkdir(buf, 0755) == -1 && errno != EEXIST) |
if (fp == NULL) { |
fatal("cvs_mkadmin: %s: %s", buf, strerror(errno)); |
if (errno != ENOENT) |
|
cvs_log(LP_NOTICE, "failed to open `%s' : %s", tagpath, |
|
strerror(errno)); |
|
return; |
|
} |
|
|
|
linenum = 0; |
len = cvs_path_cat(path, CVS_PATH_ROOTSPEC, buf, sizeof(buf)); |
|
if (len >= sizeof(buf)) |
|
fatal("cvs_mkadmin: truncation"); |
|
|
while (fgets(linebuf, (int)sizeof(linebuf), fp) != NULL) { |
if ((fp = fopen(buf, "w")) == NULL) |
linenum++; |
fatal("cvs_mkadmin: %s: %s", buf, strerror(errno)); |
if ((len = strlen(linebuf)) == 0) |
|
continue; |
|
if (linebuf[len -1] != '\n') { |
|
cvs_log(LP_WARN, "line too long in `%s:%d'", tagpath, |
|
linenum); |
|
break; |
|
} |
|
linebuf[--len] = '\0'; |
|
|
|
switch (*linebuf) { |
fprintf(fp, "%s\n", root); |
case 'T': |
(void)fclose(fp); |
if (tagp != NULL) |
|
*tagp = xstrdup(linebuf); |
|
break; |
|
case 'D': |
|
if (datep != NULL) |
|
*datep = xstrdup(linebuf); |
|
break; |
|
case 'N': |
|
if (tagp != NULL) |
|
*tagp = xstrdup(linebuf); |
|
if (nbp != NULL) |
|
*nbp = 1; |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
if (ferror(fp)) |
|
cvs_log(LP_NOTICE, "failed to read line from `%s'", tagpath); |
|
|
|
|
len = cvs_path_cat(path, CVS_PATH_REPOSITORY, buf, sizeof(buf)); |
|
if (len >= sizeof(buf)) |
|
fatal("cvs_mkadmin: truncation"); |
|
|
|
if ((fp = fopen(buf, "w")) == NULL) |
|
fatal("cvs_mkadmin: %s: %s", buf, strerror(errno)); |
|
|
|
fprintf(fp, "%s\n", repo); |
(void)fclose(fp); |
(void)fclose(fp); |
|
|
|
len = cvs_path_cat(path, CVS_PATH_ENTRIES, buf, sizeof(buf)); |
|
if (len >= sizeof(buf)) |
|
fatal("cvs_mkadmin: truncation"); |
|
|
|
if ((fp = fopen(buf, "w")) == NULL) |
|
fatal("cvs_mkadmin: %s: %s", buf, strerror(errno)); |
|
(void)fclose(fp); |
} |
} |
|
|
/* |
void |
* a hack to mimic and thus match gnu cvs behaviour. |
cvs_mkpath(const char *path) |
*/ |
|
time_t |
|
cvs_hack_time(time_t oldtime, int togmt) |
|
{ |
{ |
int l; |
FILE *fp; |
struct tm *t; |
size_t len; |
char tbuf[32]; |
struct stat st; |
|
char *sp, *dp, *dir, rpath[MAXPATHLEN], repo[MAXPATHLEN]; |
|
|
if (togmt == 1) { |
dir = xstrdup(path); |
t = gmtime(&oldtime); |
|
if (t == NULL) |
|
return (0); |
|
|
|
return (mktime(t)); |
STRIP_SLASH(dir); |
|
cvs_log(LP_TRACE, "cvs_mkpath(%s)", dir); |
|
|
|
repo[0] = '\0'; |
|
rpath[0] = '\0'; |
|
|
|
if (cvs_cmdop == CVS_OP_UPDATE) { |
|
if ((fp = fopen(CVS_PATH_REPOSITORY, "r")) != NULL) { |
|
fgets(repo, sizeof(repo), fp); |
|
if (repo[strlen(repo) - 1] == '\n') |
|
repo[strlen(repo) - 1] = '\0'; |
|
(void)fclose(fp); |
|
} |
} |
} |
|
|
t = localtime(&oldtime); |
for (sp = dir; sp != NULL; sp = dp) { |
|
dp = strchr(sp, '/'); |
|
if (dp != NULL) |
|
*(dp++) = '\0'; |
|
|
l = snprintf(tbuf, sizeof(tbuf), "%d/%d/%d GMT %d:%d:%d", |
if (repo[0] != '\0') { |
t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, |
len = strlcat(repo, "/", sizeof(repo)); |
t->tm_min, t->tm_sec); |
if (len >= (int)sizeof(repo)) |
if (l == -1 || l >= (int)sizeof(tbuf)) |
fatal("cvs_mkpath: overflow"); |
return (0); |
} |
|
|
return (cvs_date_parse(tbuf)); |
len = strlcat(repo, sp, sizeof(repo)); |
} |
if (len >= (int)sizeof(repo)) |
|
fatal("cvs_mkpath: overflow"); |
|
|
#endif /* !RCSPROG */ |
if (rpath[0] != '\0') { |
|
len = strlcat(rpath, "/", sizeof(rpath)); |
|
if (len >= (int)sizeof(rpath)) |
|
fatal("cvs_mkpath: overflow"); |
|
} |
|
|
|
len = strlcat(rpath, sp, sizeof(rpath)); |
|
if (len >= (int)sizeof(rpath)) |
|
fatal("cvs_mkpath: overflow"); |
|
|
|
if (stat(repo, &st) != -1) |
|
continue; |
|
|
|
if (mkdir(rpath, 0755) == -1 && errno != EEXIST) |
|
fatal("cvs_mkpath: %s: %s", rpath, strerror(errno)); |
|
|
|
cvs_mkadmin(rpath, current_cvsroot->cr_dir, repo); |
|
} |
|
|
|
xfree(dir); |
|
} |
|
|
/* |
/* |
* Split the contents of a file into a list of lines. |
* Split the contents of a file into a list of lines. |