diff options
author | Joris Vink <joris@cvs.openbsd.org> | 2007-01-19 23:23:22 +0000 |
---|---|---|
committer | Joris Vink <joris@cvs.openbsd.org> | 2007-01-19 23:23:22 +0000 |
commit | 4a71af5c4d11fdae042f2ba1627067246f58fa88 (patch) | |
tree | 9a90929604a6c8676d72aa8a00d480cb4af286d4 /usr.bin | |
parent | dc6e8ac5f69a36e3db19a40d55c2797148813cfb (diff) |
When we hit a DT_UNKNOWN for dirent->d_type in our filelist functions,
stat() the filepath to get the correct type, and therefor
add it to the appropriate list.
This fixes opencvs with CVSROOTs on NFS and AFS, because they
both return D_UNKNOWN for directories (afs even for files too)
in dirent->d_type.
problem found by thib@ and todd@
tested by thib@, todd@,
ok niallo@
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/cvs/file.c | 62 | ||||
-rw-r--r-- | usr.bin/cvs/repository.c | 65 |
2 files changed, 103 insertions, 24 deletions
diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c index e3d3fb7d5e4..a9aa1e3922a 100644 --- a/usr.bin/cvs/file.c +++ b/usr.bin/cvs/file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file.c,v 1.170 2007/01/14 23:10:56 joris Exp $ */ +/* $OpenBSD: file.c,v 1.171 2007/01/19 23:23:21 joris Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> @@ -342,7 +342,7 @@ next: void cvs_file_walkdir(struct cvs_file *cf, struct cvs_recursion *cr) { - int l; + int l, type; FILE *fp; int nbytes; size_t len; @@ -438,27 +438,61 @@ cvs_file_walkdir(struct cvs_file *cf, struct cvs_recursion *cr) continue; } - if (!(cr->flags & CR_RECURSE_DIRS) && - dp->d_type == DT_DIR) { - cp += dp->d_reclen; - continue; - } - l = snprintf(fpath, MAXPATHLEN, "%s/%s", cf->file_path, dp->d_name); if (l == -1 || l >= MAXPATHLEN) fatal("cvs_file_walkdir: overflow"); /* - * Anticipate the file type to sort them, - * note that we do not determine the final - * type until we actually have the fd floating - * around. + * nfs and afs will show d_type as DT_UNKNOWN + * for files and/or directories so when we encounter + * this we call stat() on the path to be sure. */ - if (dp->d_type == DT_DIR) + if (dp->d_type == DT_UNKNOWN) { + if (stat(fpath, &st) == -1) + fatal("'%s': %s", fpath, + strerror(errno)); + + switch (st.st_mode & S_IFMT) { + case S_IFDIR: + type = CVS_DIR; + break; + case S_IFREG: + type = CVS_FILE; + break; + default: + fatal("Unknown file type in copy"); + } + } else { + switch (dp->d_type) { + case DT_DIR: + type = CVS_DIR; + break; + case DT_REG: + type = CVS_FILE; + break; + default: + fatal("Unknown file type in copy"); + } + } + + if (!(cr->flags & CR_RECURSE_DIRS) && + type == CVS_DIR) { + cp += dp->d_reclen; + continue; + } + + switch (type) { + case CVS_DIR: cvs_file_get(fpath, &dl); - else if (dp->d_type == DT_REG) + break; + case CVS_FILE: cvs_file_get(fpath, &fl); + break; + default: + fatal("type %d unknown, shouldn't happen", + type); + } cp += dp->d_reclen; } diff --git a/usr.bin/cvs/repository.c b/usr.bin/cvs/repository.c index d2cd6958903..2ff62dc3434 100644 --- a/usr.bin/cvs/repository.c +++ b/usr.bin/cvs/repository.c @@ -1,4 +1,4 @@ -/* $OpenBSD: repository.c,v 1.7 2006/12/11 07:59:18 xsa Exp $ */ +/* $OpenBSD: repository.c,v 1.8 2007/01/19 23:23:21 joris Exp $ */ /* * Copyright (c) 2006 Joris Vink <joris@openbsd.org> * @@ -89,9 +89,14 @@ void cvs_repository_getdir(const char *dir, const char *wdir, struct cvs_flisthead *fl, struct cvs_flisthead *dl, int dodirs) { + int type; DIR *dirp; + struct stat st; struct dirent *dp; - char *s, fpath[MAXPATHLEN]; + char *s, *fpath, *rpath; + + rpath = xmalloc(MAXPATHLEN); + fpath = xmalloc(MAXPATHLEN); if ((dirp = opendir(dir)) == NULL) fatal("cvs_repository_getdir: failed to open '%s'", dir); @@ -106,25 +111,65 @@ cvs_repository_getdir(const char *dir, const char *wdir, if (cvs_file_chkign(dp->d_name)) continue; - if (dodirs == 0 && dp->d_type == DT_DIR) - continue; - if (cvs_path_cat(wdir, dp->d_name, - fpath, sizeof(fpath)) >= sizeof(fpath)) + fpath, MAXPATHLEN) >= MAXPATHLEN) + fatal("cvs_repository_getdir: truncation"); + + if (cvs_path_cat(dir, dp->d_name, + rpath, MAXPATHLEN) >= MAXPATHLEN) fatal("cvs_repository_getdir: truncation"); /* - * Anticipate the file type for sorting, we do not determine - * the final file type until we have the fd floating around. + * nfs and afs will show d_type as DT_UNKNOWN + * for files and/or directories so when we encounter + * this we call stat() on the path to be sure. */ - if (dp->d_type == DT_DIR) { + if (dp->d_type == DT_UNKNOWN) { + if (stat(rpath, &st) == -1) + fatal("'%s': %s", rpath, strerror(errno)); + + switch (st.st_mode & S_IFMT) { + case S_IFDIR: + type = CVS_DIR; + break; + case S_IFREG: + type = CVS_FILE; + break; + default: + fatal("Unknown file type in repository"); + } + } else { + switch (dp->d_type) { + case DT_DIR: + type = CVS_DIR; + break; + case DT_REG: + type = CVS_FILE; + break; + default: + fatal("Unknown file type in repository"); + } + } + + if (dodirs == 0 && type == CVS_DIR) + continue; + + switch (type) { + case CVS_DIR: cvs_file_get(fpath, dl); - } else if (dp->d_type == DT_REG) { + break; + case CVS_FILE: if ((s = strrchr(fpath, ',')) != NULL) *s = '\0'; cvs_file_get(fpath, fl); + break; + default: + fatal("type %d unknown, shouldn't happen", type); } } + xfree(rpath); + xfree(fpath); + (void)closedir(dirp); } |