version 1.33, 2004/08/31 11:17:02 |
version 1.34, 2004/11/26 16:23:50 |
|
|
|
|
|
|
/* |
/* |
|
* Filename hash table used to avoid duplication of name strings when working |
|
* on large source trees with common parts. |
|
*/ |
|
|
|
SLIST_HEAD(cvs_fhb, cvs_fname); |
|
|
|
static struct cvs_fhb cvs_fnht[CVS_FILE_NBUCKETS]; |
|
|
|
|
|
|
|
/* |
* Entries in the CVS/Entries file with a revision of '0' have only been |
* Entries in the CVS/Entries file with a revision of '0' have only been |
* added. Compare against this revision to see if this is the case |
* added. Compare against this revision to see if this is the case |
*/ |
*/ |
|
|
TAILQ_HEAD(, cvs_ignpat) cvs_ign_pats; |
TAILQ_HEAD(, cvs_ignpat) cvs_ign_pats; |
|
|
|
|
static int cvs_file_getdir (CVSFILE *, 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 *, u_int); |
static int cvs_file_sort (struct cvs_flist *, u_int); |
static int cvs_file_cmp (const void *, const void *); |
static int cvs_file_cmp (const void *, const void *); |
static int cvs_file_cmpname (const char *, const char *); |
static int cvs_file_cmpname (const char *, const char *); |
static CVSFILE* cvs_file_alloc (const char *, u_int); |
static u_int8_t cvs_file_hashname (const char *); |
static CVSFILE* cvs_file_lget (const char *, int, CVSFILE *); |
static struct cvs_fname* cvs_file_getname (const char *); |
|
static CVSFILE* cvs_file_alloc (const char *, u_int); |
|
static CVSFILE* cvs_file_lget (const char *, int, CVSFILE *); |
|
|
|
|
|
|
|
|
FILE *ifp; |
FILE *ifp; |
struct passwd *pwd; |
struct passwd *pwd; |
|
|
|
/* initialize the filename hash table */ |
|
for (i = 0; i < CVS_FILE_NBUCKETS; i++) |
|
SLIST_INIT(&(cvs_fnht[i])); |
|
|
TAILQ_INIT(&cvs_ign_pats); |
TAILQ_INIT(&cvs_ign_pats); |
|
|
cvs_addedrev = rcsnum_alloc(); |
cvs_addedrev = rcsnum_alloc(); |
|
|
ifp = fopen(path, "r"); |
ifp = fopen(path, "r"); |
if (ifp == NULL) { |
if (ifp == NULL) { |
if (errno != ENOENT) |
if (errno != ENOENT) |
cvs_log(LP_ERRNO, "failed to open `%s'", path); |
cvs_log(LP_ERRNO, |
|
"failed to open user's cvsignore", path); |
} |
} |
else { |
else { |
while (fgets(buf, sizeof(buf), ifp) != NULL) { |
while (fgets(buf, sizeof(buf), ifp) != NULL) { |
|
|
*/ |
*/ |
|
|
CVSFILE* |
CVSFILE* |
cvs_file_create(const char *path, u_int type, mode_t mode) |
cvs_file_create(CVSFILE *parent, const char *path, u_int type, mode_t mode) |
{ |
{ |
int fd; |
int fd; |
|
char fp[MAXPATHLEN]; |
CVSFILE *cfp; |
CVSFILE *cfp; |
|
|
|
printf("cvs_file_create(%s)\n", path); |
cfp = cvs_file_alloc(path, type); |
cfp = cvs_file_alloc(path, type); |
if (cfp == NULL) |
if (cfp == NULL) |
return (NULL); |
return (NULL); |
|
|
cfp->cf_type = type; |
cfp->cf_type = type; |
cfp->cf_mode = mode; |
cfp->cf_mode = mode; |
cfp->cf_ddat->cd_root = cvsroot_get(path); |
cfp->cf_parent = parent; |
cfp->cf_ddat->cd_repo = strdup(cfp->cf_path); |
|
|
|
if (cfp->cf_ddat->cd_repo == NULL) { |
|
cvs_file_free(cfp); |
|
return (NULL); |
|
} |
|
|
|
if (type == DT_DIR) { |
if (type == DT_DIR) { |
|
cfp->cf_ddat->cd_root = cvsroot_get(path); |
|
cfp->cf_ddat->cd_repo = strdup(cvs_file_getpath(cfp, |
|
fp, sizeof(fp))); |
|
if (cfp->cf_ddat->cd_repo == NULL) { |
|
cvs_file_free(cfp); |
|
return (NULL); |
|
} |
|
|
if ((mkdir(path, mode) == -1) || (cvs_mkadmin(cfp, mode) < 0)) { |
if ((mkdir(path, mode) == -1) || (cvs_mkadmin(cfp, mode) < 0)) { |
cvs_file_free(cfp); |
cvs_file_free(cfp); |
return (NULL); |
return (NULL); |
|
|
} |
} |
|
|
TAILQ_FOREACH(sf, &(cf->cf_ddat->cd_files), cf_list) |
TAILQ_FOREACH(sf, &(cf->cf_ddat->cd_files), cf_list) |
if (cvs_file_cmpname(pp, sf->cf_name) == 0) |
if (cvs_file_cmpname(pp, CVS_FILE_NAME(sf)) == 0) |
break; |
break; |
if (sf == NULL) |
if (sf == NULL) |
return (NULL); |
return (NULL); |
|
|
|
|
|
|
/* |
/* |
|
* cvs_file_getpath() |
|
* |
|
* 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. |
|
*/ |
|
|
|
char* |
|
cvs_file_getpath(CVSFILE *file, char *buf, size_t len) |
|
{ |
|
u_int i; |
|
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 = CVS_FILE_NAME(top); |
|
|
|
/* 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); |
|
strlcat(buf, "/", len); |
|
} |
|
strlcat(buf, namevec[i], len); |
|
|
|
return (buf); |
|
} |
|
|
|
|
|
/* |
* cvs_file_attach() |
* cvs_file_attach() |
* |
* |
* Attach the file <file> as one of the children of parent <parent>, which |
* Attach the file <file> as one of the children of parent <parent>, which |
|
|
u_int ndirs; |
u_int ndirs; |
long base; |
long base; |
void *dp, *ep; |
void *dp, *ep; |
char fbuf[2048], pbuf[MAXPATHLEN]; |
char fbuf[2048], pbuf[MAXPATHLEN], fpath[MAXPATHLEN]; |
struct dirent *ent; |
struct dirent *ent; |
CVSFILE *cfp; |
CVSFILE *cfp; |
struct stat st; |
struct stat st; |
|
|
TAILQ_INIT(&dirs); |
TAILQ_INIT(&dirs); |
cdp = cf->cf_ddat; |
cdp = cf->cf_ddat; |
|
|
|
cvs_file_getpath(cf, fpath, sizeof(fpath)); |
|
|
if (cf->cf_cvstat != CVS_FST_UNKNOWN) { |
if (cf->cf_cvstat != CVS_FST_UNKNOWN) { |
cdp->cd_root = cvsroot_get(cf->cf_path); |
cdp->cd_root = cvsroot_get(fpath); |
if (cdp->cd_root == NULL) |
if (cdp->cd_root == NULL) |
return (-1); |
return (-1); |
|
|
|
|
cvs_mkadmin(cf, 0755); |
cvs_mkadmin(cf, 0755); |
|
|
/* if the CVS administrative directory exists, load the info */ |
/* if the CVS administrative directory exists, load the info */ |
snprintf(pbuf, sizeof(pbuf), "%s/" CVS_PATH_CVSDIR, |
snprintf(pbuf, sizeof(pbuf), "%s/" CVS_PATH_CVSDIR, fpath); |
cf->cf_path); |
|
if ((stat(pbuf, &st) == 0) && S_ISDIR(st.st_mode)) { |
if ((stat(pbuf, &st) == 0) && S_ISDIR(st.st_mode)) { |
if (cvs_readrepo(cf->cf_path, pbuf, |
if (cvs_readrepo(fpath, pbuf, sizeof(pbuf)) == 0) { |
sizeof(pbuf)) == 0) { |
|
cdp->cd_repo = strdup(pbuf); |
cdp->cd_repo = strdup(pbuf); |
if (cdp->cd_repo == NULL) { |
if (cdp->cd_repo == NULL) { |
cvs_log(LP_ERRNO, |
cvs_log(LP_ERRNO, |
|
|
} |
} |
} |
} |
|
|
cdp->cd_ent = cvs_ent_open(cf->cf_path, O_RDWR); |
cdp->cd_ent = cvs_ent_open(fpath, O_RDWR); |
} |
} |
} |
} |
|
|
if (!(flags & CF_RECURSE) || (cf->cf_cvstat == CVS_FST_UNKNOWN)) |
if (!(flags & CF_RECURSE) || (cf->cf_cvstat == CVS_FST_UNKNOWN)) |
return (0); |
return (0); |
|
|
fd = open(cf->cf_path, O_RDONLY); |
fd = open(fpath, 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'", fpath); |
return (-1); |
return (-1); |
} |
} |
|
|
|
|
if ((flags & CF_NOSYMS) && (ent->d_type == DT_LNK)) |
if ((flags & CF_NOSYMS) && (ent->d_type == DT_LNK)) |
continue; |
continue; |
|
|
snprintf(pbuf, sizeof(pbuf), "%s/%s", |
snprintf(pbuf, sizeof(pbuf), "%s/%s", fpath, |
cf->cf_path, ent->d_name); |
ent->d_name); |
cfp = cvs_file_lget(pbuf, flags, cf); |
cfp = cvs_file_lget(pbuf, flags, cf); |
if (cfp != NULL) { |
if (cfp != NULL) { |
if (cfp->cf_type == DT_DIR) { |
if (cfp->cf_type == DT_DIR) { |
|
|
} |
} |
} while (ret > 0); |
} while (ret > 0); |
|
|
|
#if 1 |
|
cvs_ent_close(cdp->cd_ent); |
|
cdp->cd_ent = NULL; |
|
#endif |
|
|
if (flags & CF_SORT) { |
if (flags & CF_SORT) { |
cvs_file_sort(&(cdp->cd_files), cdp->cd_nfiles); |
cvs_file_sort(&(cdp->cd_files), cdp->cd_nfiles); |
cvs_file_sort(&dirs, ndirs); |
cvs_file_sort(&dirs, ndirs); |
|
|
void |
void |
cvs_file_free(CVSFILE *cf) |
cvs_file_free(CVSFILE *cf) |
{ |
{ |
if (cf->cf_path != NULL) |
|
free(cf->cf_path); |
|
if (cf->cf_ddat != NULL) |
if (cf->cf_ddat != NULL) |
cvs_file_freedir(cf->cf_ddat); |
cvs_file_freedir(cf->cf_ddat); |
free(cf); |
free(cf); |
|
|
CVSFILE *cf1, *cf2; |
CVSFILE *cf1, *cf2; |
cf1 = *(CVSFILE **)f1; |
cf1 = *(CVSFILE **)f1; |
cf2 = *(CVSFILE **)f2; |
cf2 = *(CVSFILE **)f2; |
return cvs_file_cmpname(cf1->cf_name, cf2->cf_name); |
return cvs_file_cmpname(CVS_FILE_NAME(cf1), CVS_FILE_NAME(cf2)); |
} |
} |
|
|
|
|
|
/* |
|
* cvs_file_alloc() |
|
* |
|
* Allocate a CVSFILE structure and initialize its internals. |
|
*/ |
|
|
CVSFILE* |
CVSFILE* |
cvs_file_alloc(const char *path, u_int type) |
cvs_file_alloc(const char *path, u_int type) |
{ |
{ |
size_t len; |
size_t len; |
char pbuf[MAXPATHLEN]; |
char pbuf[MAXPATHLEN]; |
|
const char *fnp; |
CVSFILE *cfp; |
CVSFILE *cfp; |
struct cvs_dir *ddat; |
struct cvs_dir *ddat; |
|
|
|
|
while (pbuf[len - 1] == '/') |
while (pbuf[len - 1] == '/') |
pbuf[--len] = '\0'; |
pbuf[--len] = '\0'; |
|
|
cfp->cf_path = strdup(pbuf); |
fnp = strrchr(path, '/'); |
if (cfp->cf_path == NULL) { |
if (fnp == NULL) |
free(cfp); |
fnp = path; |
return (NULL); |
|
} |
|
|
|
cfp->cf_name = strrchr(cfp->cf_path, '/'); |
|
if (cfp->cf_name == NULL) |
|
cfp->cf_name = cfp->cf_path; |
|
else |
else |
cfp->cf_name++; |
fnp++; |
|
|
|
cfp->cf_name = cvs_file_getname(fnp); |
|
if (cfp->cf_name == NULL) { |
|
cvs_log(LP_ERR, "WTF!?"); |
|
return (NULL); |
|
} |
cfp->cf_type = type; |
cfp->cf_type = type; |
cfp->cf_cvstat = CVS_FST_UNKNOWN; |
cfp->cf_cvstat = CVS_FST_UNKNOWN; |
|
|
|
|
int cwd; |
int cwd; |
struct stat st; |
struct stat st; |
CVSFILE *cfp; |
CVSFILE *cfp; |
struct cvs_ent *ent; |
struct cvs_ent *ent = NULL; |
|
|
ent = NULL; |
|
|
|
if (strcmp(path, ".") == 0) |
if (strcmp(path, ".") == 0) |
cwd = 1; |
cwd = 1; |
else |
else |
|
|
cfp->cf_mtime = st.st_mtime; |
cfp->cf_mtime = st.st_mtime; |
|
|
if ((parent != NULL) && (CVS_DIR_ENTRIES(parent) != NULL)) { |
if ((parent != NULL) && (CVS_DIR_ENTRIES(parent) != NULL)) { |
ent = cvs_ent_get(CVS_DIR_ENTRIES(parent), cfp->cf_name); |
ent = cvs_ent_get(CVS_DIR_ENTRIES(parent), CVS_FILE_NAME(cfp)); |
} |
} |
|
|
if (ent == NULL) { |
if (ent == NULL) { |
|
|
{ |
{ |
return (cvs_nocase == 0) ? (strcmp(name1, name2)) : |
return (cvs_nocase == 0) ? (strcmp(name1, name2)) : |
(strcasecmp(name1, name2)); |
(strcasecmp(name1, name2)); |
|
} |
|
|
|
|
|
/* |
|
* cvs_file_hashname() |
|
* |
|
* Generate an 8 bit hash value from the name of a file. |
|
* XXX Improve my distribution! |
|
*/ |
|
|
|
static u_int8_t |
|
cvs_file_hashname(const char *name) |
|
{ |
|
const char *np; |
|
u_int8_t h; |
|
|
|
h = 0xb5; |
|
for (np = name; *np != '\0'; np++) |
|
h ^= (*np << 3 ^ *np >> 1); |
|
|
|
return (h); |
|
} |
|
|
|
|
|
/* |
|
* cvs_file_getname() |
|
* |
|
* Look for the file name <name> in the filename hash table. |
|
* If no entry is found for that name, a new one is created and inserted into |
|
* the table. The name's reference count is increased. |
|
*/ |
|
|
|
static struct cvs_fname* |
|
cvs_file_getname(const char *name) |
|
{ |
|
u_int8_t h; |
|
struct cvs_fname *fnp; |
|
|
|
h = cvs_file_hashname(name); |
|
|
|
SLIST_FOREACH(fnp, &(cvs_fnht[h]), cf_list) |
|
if (strcmp(name, fnp->cf_name) == 0) { |
|
fnp->cf_ref++; |
|
break; |
|
} |
|
|
|
if (fnp == NULL) { |
|
fnp = (struct cvs_fname *)malloc(sizeof(*fnp)); |
|
if (fnp == NULL) { |
|
cvs_log(LP_ERRNO, |
|
"failed to allocate new file name entry"); |
|
return (NULL); |
|
} |
|
|
|
fnp->cf_name = strdup(name); |
|
fnp->cf_ref = 1; |
|
SLIST_INSERT_HEAD(&(cvs_fnht[h]), fnp, cf_list); |
|
} |
|
|
|
return (fnp); |
} |
} |