version 1.5, 2006/04/26 02:55:13 |
version 1.6, 2006/04/26 21:55:22 |
|
|
* Returns last modified time on success, or -1 on failure. |
* Returns last modified time on success, or -1 on failure. |
*/ |
*/ |
time_t |
time_t |
rcs_get_mtime(const char *filename) |
rcs_get_mtime(RCSFILE *file) |
{ |
{ |
struct stat st; |
struct stat st; |
time_t mtime; |
time_t mtime; |
|
|
if (stat(filename, &st) == -1) { |
if (fstat(file->fd, &st) == -1) { |
warn("%s", filename); |
warn("%s", file->rf_path); |
return (-1); |
return (-1); |
} |
} |
|
|
mtime = (time_t)st.st_mtimespec.tv_sec; |
mtime = (time_t)st.st_mtimespec.tv_sec; |
|
|
return (mtime); |
return (mtime); |
|
|
* Set <filename> last modified time to <mtime> if it's not set to -1. |
* Set <filename> last modified time to <mtime> if it's not set to -1. |
*/ |
*/ |
void |
void |
rcs_set_mtime(const char *filename, time_t mtime) |
rcs_set_mtime(RCSFILE *file, time_t mtime) |
{ |
{ |
static struct timeval tv[2]; |
static struct timeval tv[2]; |
|
|
|
|
tv[0].tv_sec = mtime; |
tv[0].tv_sec = mtime; |
tv[1].tv_sec = tv[0].tv_sec; |
tv[1].tv_sec = tv[0].tv_sec; |
|
|
if (utimes(filename, tv) == -1) |
if (futimes(file->fd, tv) == -1) |
err(1, "utimes"); |
err(1, "utimes"); |
} |
} |
|
|
|
|
* |
* |
* Returns pointer to a char array on success, NULL on failure. |
* Returns pointer to a char array on success, NULL on failure. |
*/ |
*/ |
char * |
int |
rcs_choosefile(const char *filename) |
rcs_choosefile(const char *filename, char *out, size_t len) |
{ |
{ |
|
int fd; |
struct stat sb; |
struct stat sb; |
char *p, *ext, name[MAXPATHLEN], *next, *ptr, rcsdir[MAXPATHLEN], |
char *p, *ext, name[MAXPATHLEN], *next, *ptr, rcsdir[MAXPATHLEN], |
*ret, *suffixes, rcspath[MAXPATHLEN]; |
*ret, *suffixes, rcspath[MAXPATHLEN]; |
|
|
if (rcs_suffixes == NULL) |
if (rcs_suffixes == NULL) |
rcs_suffixes = RCS_DEFAULT_SUFFIX; |
rcs_suffixes = RCS_DEFAULT_SUFFIX; |
|
|
|
fd = -1; |
|
|
/* |
/* |
* If `filename' contains a directory, `rcspath' contains that |
* If `filename' contains a directory, `rcspath' contains that |
* directory, including a trailing slash. Otherwise `rcspath' |
* directory, including a trailing slash. Otherwise `rcspath' |
* contains an empty string. |
* contains an empty string. |
*/ |
*/ |
if (strlcpy(rcspath, filename, sizeof(rcspath)) >= sizeof(rcspath)) |
if (strlcpy(rcspath, filename, sizeof(rcspath)) >= sizeof(rcspath)) |
return (NULL); |
errx(1, "rcs_choosefile: truncation"); |
|
|
/* If `/' is found, end string after `/'. */ |
/* If `/' is found, end string after `/'. */ |
if ((ptr = strrchr(rcspath, '/')) != NULL) |
if ((ptr = strrchr(rcspath, '/')) != NULL) |
*(++ptr) = '\0'; |
*(++ptr) = '\0'; |
|
|
/* Append RCS/ to `rcspath' if it exists. */ |
/* Append RCS/ to `rcspath' if it exists. */ |
if (strlcpy(rcsdir, rcspath, sizeof(rcsdir)) >= sizeof(rcsdir) || |
if (strlcpy(rcsdir, rcspath, sizeof(rcsdir)) >= sizeof(rcsdir) || |
strlcat(rcsdir, RCSDIR, sizeof(rcsdir)) >= sizeof(rcsdir)) |
strlcat(rcsdir, RCSDIR, sizeof(rcsdir)) >= sizeof(rcsdir)) |
return (NULL); |
errx(1, "rcs_choosefile: truncation"); |
|
|
if (stat(rcsdir, &sb) == 0 && (sb.st_mode & S_IFDIR)) |
if (stat(rcsdir, &sb) == 0 && (sb.st_mode & S_IFDIR)) |
if (strlcpy(rcspath, rcsdir, sizeof(rcspath)) >= sizeof(rcspath) || |
if (strlcpy(rcspath, rcsdir, sizeof(rcspath)) |
|
>= sizeof(rcspath) || |
strlcat(rcspath, "/", sizeof(rcspath)) >= sizeof(rcspath)) |
strlcat(rcspath, "/", sizeof(rcspath)) >= sizeof(rcspath)) |
return (NULL); |
errx(1, "rcs_choosefile: truncation"); |
|
|
/* Name of file without path. */ |
/* Name of file without path. */ |
if ((ptr = strrchr(filename, '/')) == NULL) { |
if ((ptr = strrchr(filename, '/')) == NULL) { |
if (strlcpy(name, filename, sizeof(name)) >= sizeof(name)) |
if (strlcpy(name, filename, sizeof(name)) >= sizeof(name)) |
return (NULL); |
errx(1, "rcs_choosefile: truncation"); |
} else { |
} else { |
/* Skip `/'. */ |
/* Skip `/'. */ |
if (strlcpy(name, ptr + 1, sizeof(name)) >= sizeof(name)) |
if (strlcpy(name, ptr + 1, sizeof(name)) >= sizeof(name)) |
return (NULL); |
errx(1, "rcs_choosefile: truncation"); |
} |
} |
|
|
/* Name of RCS file without an extension. */ |
/* Name of RCS file without an extension. */ |
if (strlcat(rcspath, name, sizeof(rcspath)) >= sizeof(rcspath)) |
if (strlcat(rcspath, name, sizeof(rcspath)) >= sizeof(rcspath)) |
return (NULL); |
errx(1, "rcs_choosefile: truncation"); |
|
|
/* |
/* |
* If only the empty suffix was given, use existing rcspath. |
* If only the empty suffix was given, use existing rcspath. |
* This ensures that there is at least one suffix for strsep(). |
* This ensures that there is at least one suffix for strsep(). |
*/ |
*/ |
if (strcmp(rcs_suffixes, "") == 0) { |
if (strcmp(rcs_suffixes, "") == 0) { |
ret = xstrdup(rcspath); |
fd = open(rcspath, O_RDONLY); |
return (ret); |
strlcpy(out, rcspath, len); |
|
return (fd); |
} |
} |
|
|
/* |
/* |
|
|
|
|
if ((p = strrchr(rcspath, ',')) != NULL) { |
if ((p = strrchr(rcspath, ',')) != NULL) { |
if (!strcmp(p, ext)) { |
if (!strcmp(p, ext)) { |
if (stat(rcspath, &sb) == 0) { |
if ((fd = open(rcspath, O_RDONLY)) == -1) |
ret = xstrdup(rcspath); |
continue; |
goto out; |
|
} |
if (fstat(fd, &sb) == -1) |
|
err(1, "%s", rcspath); |
|
|
|
if (strlcpy(out, rcspath, len) >= len) |
|
errx(1, "rcs_choosefile; truncation"); |
|
|
|
return (fd); |
} |
} |
|
|
continue; |
continue; |
|
|
/* Construct RCS file path. */ |
/* Construct RCS file path. */ |
if (strlcpy(fpath, rcspath, sizeof(fpath)) >= sizeof(fpath) || |
if (strlcpy(fpath, rcspath, sizeof(fpath)) >= sizeof(fpath) || |
strlcat(fpath, ext, sizeof(fpath)) >= sizeof(fpath)) |
strlcat(fpath, ext, sizeof(fpath)) >= sizeof(fpath)) |
goto out; |
errx(1, "rcs_choosefile: truncation"); |
|
|
/* Don't use `filename' as RCS file. */ |
/* Don't use `filename' as RCS file. */ |
if (strcmp(fpath, filename) == 0) |
if (strcmp(fpath, filename) == 0) |
continue; |
continue; |
|
|
if (stat(fpath, &sb) == 0) { |
if ((fd = open(fpath, O_RDONLY)) == -1) |
ret = xstrdup(fpath); |
continue; |
goto out; |
|
} |
if (fstat(fd, &sb) == -1) |
|
err(1, "%s", fpath); |
|
|
|
if (strlcpy(out, fpath, len) >= len) |
|
errx(1, "rcs_choosefile: truncation"); |
|
|
|
return (fd); |
} |
} |
|
|
/* |
/* |
|
|
*/ |
*/ |
if (strlcat(rcspath, suffixes, sizeof(rcspath)) >= |
if (strlcat(rcspath, suffixes, sizeof(rcspath)) >= |
sizeof(rcspath)) |
sizeof(rcspath)) |
goto out; |
errx(1, "rcs_choosefile: truncation"); |
ret = xstrdup(rcspath); |
|
|
|
out: |
|
/* `ret' may be NULL, which indicates an error. */ |
|
xfree(suffixes); |
xfree(suffixes); |
return (ret); |
|
|
fd = open(rcspath, O_RDONLY); |
|
strlcpy(out, rcspath, len); |
|
|
|
return (fd); |
} |
} |
|
|
/* |
/* |
|
|
int |
int |
rcs_statfile(char *fname, char *out, size_t len, int flags) |
rcs_statfile(char *fname, char *out, size_t len, int flags) |
{ |
{ |
struct stat st; |
int fd; |
char *rcspath; |
|
|
|
if ((rcspath = rcs_choosefile(fname)) == NULL) |
fd = rcs_choosefile(fname, out, len); |
errx(1, "rcs_statfile: path truncation"); |
if (fd == -1 && !(flags & RCS_CREATE)) { |
|
|
/* Error out if file not found and we are not creating one. */ |
|
if (stat(rcspath, &st) == -1 && !(flags & RCS_CREATE)) { |
|
if (strcmp(__progname, "rcsclean") != 0 && |
if (strcmp(__progname, "rcsclean") != 0 && |
strcmp(__progname, "ci") != 0) |
strcmp(__progname, "ci") != 0) |
warn("%s", rcspath); |
warn("%s", out); |
xfree(rcspath); |
|
return (-1); |
return (-1); |
} |
} |
|
|
if (strlcpy(out, rcspath, len) >= len) |
return (fd); |
errx(1, "rcs_statfile: path truncation"); |
|
|
|
xfree(rcspath); |
|
|
|
return (0); |
|
} |
} |
|
|
/* |
/* |