version 1.13, 2004/07/30 11:50:33 |
version 1.14, 2004/07/30 17:39:27 |
|
|
|
|
#include "cvs.h" |
#include "cvs.h" |
#include "log.h" |
#include "log.h" |
|
#include "file.h" |
|
|
|
|
#define CVS_IGN_STATIC 0x01 /* pattern is static, no need to glob */ |
#define CVS_IGN_STATIC 0x01 /* pattern is static, no need to glob */ |
|
|
|
|
|
|
#define CVS_CHAR_ISMETA(c) ((c == '*') || (c == '?') || (c == '[')) |
#define CVS_CHAR_ISMETA(c) ((c == '*') || (c == '?') || (c == '[')) |
|
|
|
|
|
|
/* ignore pattern */ |
/* ignore pattern */ |
struct cvs_ignpat { |
struct cvs_ignpat { |
char ip_pat[MAXNAMLEN]; |
char ip_pat[MAXNAMLEN]; |
|
|
TAILQ_HEAD(, cvs_ignpat) cvs_ign_pats; |
TAILQ_HEAD(, cvs_ignpat) cvs_ign_pats; |
|
|
|
|
static int cvs_file_getdir (struct cvs_file *, int); |
static int cvs_file_getdir (CVSFILE *, int); |
static void cvs_file_freedir (struct cvs_dir *); |
static void cvs_file_freedir (struct cvs_dir *); |
static int cvs_file_sort (struct cvs_flist *); |
static int cvs_file_sort (struct cvs_flist *); |
static int cvs_file_cmp (const void *, const void *); |
static int cvs_file_cmp (const void *, const void *); |
static CVSFILE* cvs_file_alloc (const char *, u_int); |
static CVSFILE* cvs_file_alloc (const char *, u_int); |
|
static CVSFILE* cvs_file_lget (const char *, int, CVSFILE *); |
|
|
|
|
|
|
|
|
* with cvs_file_free(). |
* with cvs_file_free(). |
*/ |
*/ |
|
|
struct cvs_file* |
CVSFILE* |
cvs_file_get(const char *path, int flags) |
cvs_file_get(const char *path, int flags) |
{ |
{ |
int cwd; |
return cvs_file_lget(path, flags, NULL); |
size_t len; |
|
char buf[32]; |
|
struct stat st; |
|
struct tm lmtm; |
|
struct cvs_file *cfp; |
|
struct cvs_ent *ent; |
|
|
|
if (strcmp(path, ".") == 0) |
|
cwd = 1; |
|
else |
|
cwd = 0; |
|
|
|
if (stat(path, &st) == -1) { |
|
cvs_log(LP_ERRNO, "failed to stat %s", path); |
|
return (NULL); |
|
} |
|
|
|
cfp = cvs_file_alloc(path, IFTODT(st.st_mode)); |
|
if (cfp == NULL) { |
|
cvs_log(LP_ERRNO, "failed to allocate CVS file data"); |
|
return (NULL); |
|
} |
|
|
|
ent = cvs_ent_getent(path); |
|
if (ent == NULL) |
|
cfp->cf_cvstat = (cwd == 1) ? |
|
CVS_FST_UPTODATE : CVS_FST_UNKNOWN; |
|
else { |
|
/* always show directories as up-to-date */ |
|
if (ent->ce_type == CVS_ENT_DIR) |
|
cfp->cf_cvstat = CVS_FST_UPTODATE; |
|
else if (rcsnum_cmp(ent->ce_rev, cvs_addedrev, 2) == 0) |
|
cfp->cf_cvstat = CVS_FST_ADDED; |
|
else { |
|
/* check last modified time */ |
|
if ((gmtime_r((time_t *)&(st.st_mtime), &lmtm) == NULL) || |
|
(asctime_r(&lmtm, buf) == NULL)) { |
|
cvs_log(LP_ERR, |
|
"failed to generate file timestamp"); |
|
/* fake an up to date file */ |
|
strlcpy(buf, ent->ce_timestamp, sizeof(buf)); |
|
} |
|
len = strlen(buf); |
|
if ((len > 0) && (buf[len - 1] == '\n')) |
|
buf[--len] = '\0'; |
|
|
|
if (strcmp(buf, ent->ce_timestamp) == 0) |
|
cfp->cf_cvstat = CVS_FST_UPTODATE; |
|
else |
|
cfp->cf_cvstat = CVS_FST_MODIFIED; |
|
} |
|
|
|
cvs_ent_free(ent); |
|
} |
|
|
|
/* convert from stat mode to dirent values */ |
|
cfp->cf_type = IFTODT(st.st_mode); |
|
if ((cfp->cf_type == DT_DIR) && ((flags & CF_RECURSE) || cwd)) { |
|
if ((flags & CF_KNOWN) && (cfp->cf_cvstat == CVS_FST_UNKNOWN)) { |
|
free(cfp->cf_ddat); |
|
cfp->cf_ddat = NULL; |
|
} |
|
else if (cvs_file_getdir(cfp, flags) < 0) { |
|
cvs_file_free(cfp); |
|
return (NULL); |
|
} |
|
} |
|
|
|
if (flags & CF_STAT) { |
|
cfp->cf_stat = (struct stat *)malloc(sizeof(struct stat)); |
|
if (cfp->cf_stat == NULL) { |
|
cvs_log(LP_ERRNO, "failed to allocate stat structure"); |
|
cvs_file_free(cfp); |
|
return (NULL); |
|
} |
|
|
|
memcpy(cfp->cf_stat, &st, sizeof(struct stat)); |
|
} |
|
|
|
return (cfp); |
|
} |
} |
|
|
|
|
|
|
{ |
{ |
int i, c; |
int i, c; |
char common[MAXPATHLEN]; |
char common[MAXPATHLEN]; |
struct cvs_file *cfp; |
CVSFILE *cfp; |
|
|
/* first find the common subdir */ |
/* first find the common subdir */ |
strlcpy(common, fspec[0], sizeof(common)); |
strlcpy(common, fspec[0], sizeof(common)); |
|
|
*/ |
*/ |
|
|
static int |
static int |
cvs_file_getdir(struct cvs_file *cf, int flags) |
cvs_file_getdir(CVSFILE *cf, int flags) |
{ |
{ |
int ret, fd; |
int ret, fd; |
long base; |
long base; |
void *dp, *ep; |
void *dp, *ep; |
char fbuf[2048], pbuf[MAXPATHLEN]; |
char fbuf[2048], pbuf[MAXPATHLEN]; |
struct dirent *ent; |
struct dirent *ent; |
struct cvs_file *cfp; |
CVSFILE *cfp; |
struct cvs_dir *cdp; |
struct cvs_dir *cdp; |
struct cvs_flist dirs; |
struct cvs_flist dirs; |
|
|
|
|
} |
} |
|
|
cdp->cd_root = cvsroot_get(cf->cf_path); |
cdp->cd_root = cvsroot_get(cf->cf_path); |
|
printf("cvsroot = %s\n", cdp->cd_root->cr_str); |
if (cdp->cd_root == NULL) { |
if (cdp->cd_root == NULL) { |
cvs_file_freedir(cdp); |
cvs_file_freedir(cdp); |
return (-1); |
return (-1); |
} |
} |
|
|
|
if (flags & CF_MKADMIN) |
|
cvs_mkadmin(cf, 0755); |
|
|
|
cdp->cd_ent = cvs_ent_open(cf->cf_path, O_RDONLY); |
|
|
fd = open(cf->cf_path, O_RDONLY); |
fd = open(cf->cf_path, O_RDONLY); |
if (fd == -1) { |
if (fd == -1) { |
cvs_log(LP_ERRNO, "failed to open `%s'", cf->cf_path); |
cvs_log(LP_ERRNO, "failed to open `%s'", cf->cf_path); |
|
|
|
|
snprintf(pbuf, sizeof(pbuf), "%s/%s", |
snprintf(pbuf, sizeof(pbuf), "%s/%s", |
cf->cf_path, ent->d_name); |
cf->cf_path, ent->d_name); |
cfp = cvs_file_get(pbuf, flags); |
cfp = cvs_file_lget(pbuf, flags, cf); |
if (cfp != NULL) { |
if (cfp != NULL) { |
cfp->cf_parent = cf; |
cfp->cf_parent = cf; |
if (cfp->cf_type == DT_DIR) |
if (cfp->cf_type == DT_DIR) |
|
|
} |
} |
} while (ret > 0); |
} while (ret > 0); |
|
|
|
/* we can now close our Entries file */ |
|
if (cdp->cd_ent != NULL) { |
|
cvs_ent_close(cdp->cd_ent); |
|
cdp->cd_ent = NULL; |
|
} |
|
|
if (flags & CF_SORT) { |
if (flags & CF_SORT) { |
cvs_file_sort(&(cdp->cd_files)); |
cvs_file_sort(&(cdp->cd_files)); |
cvs_file_sort(&dirs); |
cvs_file_sort(&dirs); |
|
|
*/ |
*/ |
|
|
void |
void |
cvs_file_free(struct cvs_file *cf) |
cvs_file_free(CVSFILE *cf) |
{ |
{ |
if (cf->cf_path != NULL) |
if (cf->cf_path != NULL) |
free(cf->cf_path); |
free(cf->cf_path); |
|
|
cvs_file_examine(CVSFILE *cf, int (*exam)(CVSFILE *, void *), void *arg) |
cvs_file_examine(CVSFILE *cf, int (*exam)(CVSFILE *, void *), void *arg) |
{ |
{ |
int ret; |
int ret; |
struct cvs_file *fp; |
CVSFILE *fp; |
|
|
if (cf->cf_type == DT_DIR) { |
if (cf->cf_type == DT_DIR) { |
ret = (*exam)(cf, arg); |
ret = (*exam)(cf, arg); |
|
|
static void |
static void |
cvs_file_freedir(struct cvs_dir *cd) |
cvs_file_freedir(struct cvs_dir *cd) |
{ |
{ |
struct cvs_file *cfp; |
CVSFILE *cfp; |
|
|
if (cd->cd_root != NULL) |
if (cd->cd_root != NULL) |
cvsroot_free(cd->cd_root); |
cvsroot_free(cd->cd_root); |
if (cd->cd_repo != NULL) |
if (cd->cd_repo != NULL) |
free(cd->cd_repo); |
free(cd->cd_repo); |
|
|
|
if (cd->cd_ent != NULL) |
|
cvs_ent_close(cd->cd_ent); |
|
|
while (!TAILQ_EMPTY(&(cd->cd_files))) { |
while (!TAILQ_EMPTY(&(cd->cd_files))) { |
cfp = TAILQ_FIRST(&(cd->cd_files)); |
cfp = TAILQ_FIRST(&(cd->cd_files)); |
TAILQ_REMOVE(&(cd->cd_files), cfp, cf_list); |
TAILQ_REMOVE(&(cd->cd_files), cfp, cf_list); |
|
|
{ |
{ |
int i; |
int i; |
size_t nb; |
size_t nb; |
struct cvs_file *cf, *cfvec[256]; |
CVSFILE *cf, *cfvec[256]; |
|
|
i = 0; |
i = 0; |
TAILQ_FOREACH(cf, flp, cf_list) { |
TAILQ_FOREACH(cf, flp, cf_list) { |
cfvec[i++] = cf; |
cfvec[i++] = cf; |
if (i == sizeof(cfvec)/sizeof(struct cvs_file *)) { |
if (i == sizeof(cfvec)/sizeof(CVSFILE *)) { |
cvs_log(LP_WARN, "too many files to sort"); |
cvs_log(LP_WARN, "too many files to sort"); |
return (-1); |
return (-1); |
} |
} |
|
|
static int |
static int |
cvs_file_cmp(const void *f1, const void *f2) |
cvs_file_cmp(const void *f1, const void *f2) |
{ |
{ |
struct cvs_file *cf1, *cf2; |
CVSFILE *cf1, *cf2; |
cf1 = *(struct cvs_file **)f1; |
cf1 = *(CVSFILE **)f1; |
cf2 = *(struct cvs_file **)f2; |
cf2 = *(CVSFILE **)f2; |
return strcmp(cf1->cf_name, cf2->cf_name); |
return strcmp(cf1->cf_name, cf2->cf_name); |
} |
} |
|
|
|
|
CVSFILE *cfp; |
CVSFILE *cfp; |
struct cvs_dir *ddat; |
struct cvs_dir *ddat; |
|
|
cfp = (struct cvs_file *)malloc(sizeof(*cfp)); |
cfp = (CVSFILE *)malloc(sizeof(*cfp)); |
if (cfp == NULL) { |
if (cfp == NULL) { |
cvs_log(LP_ERRNO, "failed to allocate CVS file data"); |
cvs_log(LP_ERRNO, "failed to allocate CVS file data"); |
return (NULL); |
return (NULL); |
|
|
} |
} |
return (cfp); |
return (cfp); |
} |
} |
|
|
|
|
|
/* |
|
* cvs_file_lget() |
|
* |
|
* Get the file and link it with the parent right away. |
|
*/ |
|
|
|
static CVSFILE* |
|
cvs_file_lget(const char *path, int flags, CVSFILE *parent) |
|
{ |
|
int cwd; |
|
size_t len; |
|
char buf[32]; |
|
struct stat st; |
|
struct tm lmtm; |
|
CVSFILE *cfp; |
|
struct cvs_ent *ent; |
|
|
|
ent = NULL; |
|
|
|
if (strcmp(path, ".") == 0) |
|
cwd = 1; |
|
else |
|
cwd = 0; |
|
|
|
if (stat(path, &st) == -1) { |
|
cvs_log(LP_ERRNO, "failed to stat %s", path); |
|
return (NULL); |
|
} |
|
|
|
cfp = cvs_file_alloc(path, IFTODT(st.st_mode)); |
|
if (cfp == NULL) { |
|
cvs_log(LP_ERRNO, "failed to allocate CVS file data"); |
|
return (NULL); |
|
} |
|
cfp->cf_parent = parent; |
|
|
|
if ((parent != NULL) && (CVS_DIR_ENTRIES(parent) != NULL)) { |
|
ent = cvs_ent_get(CVS_DIR_ENTRIES(parent), path); |
|
} |
|
|
|
if (ent == NULL) |
|
cfp->cf_cvstat = (cwd == 1) ? |
|
CVS_FST_UPTODATE : CVS_FST_UNKNOWN; |
|
else { |
|
/* always show directories as up-to-date */ |
|
if (ent->ce_type == CVS_ENT_DIR) |
|
cfp->cf_cvstat = CVS_FST_UPTODATE; |
|
else if (rcsnum_cmp(ent->ce_rev, cvs_addedrev, 2) == 0) |
|
cfp->cf_cvstat = CVS_FST_ADDED; |
|
else { |
|
/* check last modified time */ |
|
if ((gmtime_r((time_t *)&(st.st_mtime), |
|
&lmtm) == NULL) || |
|
(asctime_r(&lmtm, buf) == NULL)) { |
|
cvs_log(LP_ERR, |
|
"failed to generate file timestamp"); |
|
/* fake an up to date file */ |
|
strlcpy(buf, ent->ce_timestamp, sizeof(buf)); |
|
} |
|
len = strlen(buf); |
|
if ((len > 0) && (buf[len - 1] == '\n')) |
|
buf[--len] = '\0'; |
|
|
|
if (strcmp(buf, ent->ce_timestamp) == 0) |
|
cfp->cf_cvstat = CVS_FST_UPTODATE; |
|
else |
|
cfp->cf_cvstat = CVS_FST_MODIFIED; |
|
} |
|
|
|
cvs_ent_free(ent); |
|
} |
|
|
|
if ((cfp->cf_type == DT_DIR) && ((flags & CF_RECURSE) || cwd)) { |
|
if ((flags & CF_KNOWN) && (cfp->cf_cvstat == CVS_FST_UNKNOWN)) { |
|
free(cfp->cf_ddat); |
|
cfp->cf_ddat = NULL; |
|
} |
|
else if (cvs_file_getdir(cfp, flags) < 0) { |
|
cvs_file_free(cfp); |
|
return (NULL); |
|
} |
|
} |
|
|
|
if (flags & CF_STAT) { |
|
cfp->cf_stat = (struct stat *)malloc(sizeof(struct stat)); |
|
if (cfp->cf_stat == NULL) { |
|
cvs_log(LP_ERRNO, "failed to allocate stat structure"); |
|
cvs_file_free(cfp); |
|
return (NULL); |
|
} |
|
|
|
memcpy(cfp->cf_stat, &st, sizeof(struct stat)); |
|
} |
|
|
|
return (cfp); |
|
} |
|
|
|
|