/*-
* Copyright (c) 2003-2005 MAEKAWA Masahide <maekawa@cvsync.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include "compat_sys_stat.h"
#include "compat_stdbool.h"
#include "compat_stdint.h"
#include "compat_stdio.h"
#include "compat_inttypes.h"
#include "compat_limits.h"
#include "attribute.h"
#include "cvsync.h"
#include "filetypes.h"
#include "list.h"
#include "logmsg.h"
#include "scanfile.h"
#include "defs.h"
bool cvsync2cvsup(struct scanfile_args *, const char *);
bool cvsync2cvsup_chdir(struct scanfile_args *, struct scanfile_attr *, struct scanfile_attr *);
bool cvsync2cvsup_isparent(struct scanfile_attr *, struct scanfile_attr *);
bool cvsync2cvsup_insert_attr(struct scanfile_args *, struct scanfile_attr *);
void cvsync2cvsup_remove_attr(struct scanfile_args *, struct scanfile_attr *);
void usage(void);
int
main(int argc, char *argv[])
{
const char *ifile = NULL, *ofile = NULL;
struct scanfile_args *sa;
char *user = NULL, *group = NULL;
int ch;
bool log_flag = false;
while ((ch = getopt(argc, argv, "g:hi:o:qu:v")) != -1) {
switch (ch) {
case 'g':
group = optarg;
break;
case 'h':
usage();
/* NOTREACHED */
case 'i':
if (ifile != NULL) {
usage();
/* NOTREACHED */
}
ifile = optarg;
break;
case 'o':
if (ofile != NULL) {
usage();
/* NOTREACHED */
}
ofile = optarg;
break;
case 'q':
if (log_flag) {
usage();
/* NOTREACHED */
}
logmsg_quiet = true;
log_flag = true;
break;
case 'u':
user = optarg;
break;
case 'v':
if (log_flag) {
usage();
/* NOTREACHED */
}
logmsg_detail = true;
log_flag = true;
break;
default:
usage();
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
if ((argc != 0) || (ifile == NULL) || (ofile == NULL)) {
usage();
/* NOTREACHED */
}
if (!cvsync_init())
exit(EXIT_FAILURE);
if (!cvsup_init(user, group))
exit(EXIT_FAILURE);
if ((sa = scanfile_open(ifile)) == NULL)
exit(EXIT_FAILURE);
if ((sa->sa_dirlist = list_init()) == NULL) {
logmsg_err("Scanfile Error: list init");
scanfile_close(sa);
exit(EXIT_FAILURE);
}
if (!cvsync2cvsup(sa, ofile)) {
scanfile_close(sa);
exit(EXIT_FAILURE);
}
scanfile_close(sa);
exit(EXIT_SUCCESS);
/* NOTREACHED */
}
bool
cvsync2cvsup(struct scanfile_args *sa, const char *ofile)
{
struct scanfile_attr attr, dirattr;
struct stat st;
char new_ofile[PATH_MAX + CVSYNC_NAME_MAX + 1];
int fd, wn;
if (stat(ofile, &st) != -1) {
st.st_mode &= CVSYNC_ALLPERMS;
} else {
if (errno != ENOENT) {
logmsg_err("%s: %s", ofile, strerror(errno));
return (false);
}
st.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
}
wn = snprintf(new_ofile, sizeof(new_ofile), "%s.XXXXXX", ofile);
if ((wn <= 0) || ((size_t)wn >= sizeof(new_ofile))) {
logmsg_err("%s: %s", ofile, strerror(EINVAL));
return (false);
}
if ((fd = mkstemp(new_ofile)) == -1) {
logmsg_err("%s: %s", ofile, strerror(errno));
return (false);
}
sa->sa_tmp = fd;
if (!cvsup_write_header(sa->sa_tmp, sa->sa_scanfile->cf_mtime))
return (false);
(void)memset(&dirattr, 0, sizeof(dirattr));
while (sa->sa_start < sa->sa_end) {
if (cvsync_isinterrupted()) {
logmsg_intr();
(void)unlink(new_ofile);
return (false);
}
if (!scanfile_read_attr(sa->sa_start, sa->sa_end, &attr)) {
(void)unlink(new_ofile);
return (false);
}
if (!cvsync2cvsup_chdir(sa, &dirattr, &attr)) {
(void)unlink(new_ofile);
return (false);
}
switch (attr.a_type) {
case FILETYPE_DIR:
/* Nothing to do. */
break;
case FILETYPE_FILE:
if (!cvsup_write_file(sa->sa_tmp, &attr))
return (false);
break;
case FILETYPE_RCS:
case FILETYPE_RCS_ATTIC:
if (!cvsup_write_rcs(sa->sa_tmp, &attr))
return (false);
break;
case FILETYPE_SYMLINK:
if (!cvsup_write_symlink(sa->sa_tmp, &attr))
return (false);
break;
default:
logmsg_err("%c: Unknown attr type");
break;
}
sa->sa_start += attr.a_size;
}
if (dirattr.a_type == FILETYPE_DIR) {
if (!cvsup_write_dirup(sa->sa_tmp, &dirattr))
return (false);
}
while (!list_isempty(sa->sa_dirlist)) {
cvsync2cvsup_remove_attr(sa, &dirattr);
if (dirattr.a_type != FILETYPE_DIR)
return (false);
if (!cvsup_write_dirup(sa->sa_tmp, &dirattr))
return (false);
}
fd = sa->sa_tmp;
sa->sa_tmp = -1;
if (fchmod(fd, st.st_mode) == -1) {
logmsg_err("%s: %s", ofile, strerror(errno));
(void)unlink(new_ofile);
return (false);
}
if (close(fd) == -1) {
logmsg_err("%s: %s", ofile, strerror(errno));
(void)unlink(new_ofile);
return (false);
}
if (rename(new_ofile, ofile) == -1) {
logmsg_err("%s: %s", ofile, strerror(errno));
(void)unlink(new_ofile);
return (false);
}
logmsg("Finished successfully");
return (true);
}
bool
cvsync2cvsup_chdir(struct scanfile_args *sa, struct scanfile_attr *dirattr,
struct scanfile_attr *attr)
{
if (dirattr->a_type != FILETYPE_DIR) {
if (attr->a_type == FILETYPE_DIR) {
(void)memcpy(dirattr, attr, sizeof(*dirattr));
if (!cvsup_write_dirdown(sa->sa_tmp, dirattr))
return (false);
}
return (true);
}
if (cvsync2cvsup_isparent(dirattr, attr)) {
if (attr->a_type == FILETYPE_DIR) {
if (!cvsync2cvsup_insert_attr(sa, dirattr))
return (false);
(void)memcpy(dirattr, attr, sizeof(*dirattr));
if (!cvsup_write_dirdown(sa->sa_tmp, dirattr))
return (false);
}
return (true);
}
if (attr->a_type == FILETYPE_DIR) {
for (;;) {
if (!cvsup_write_dirup(sa->sa_tmp, dirattr))
return (false);
cvsync2cvsup_remove_attr(sa, dirattr);
if (dirattr->a_type != FILETYPE_DIR)
break;
if (cvsync2cvsup_isparent(dirattr, attr)) {
if (!cvsync2cvsup_insert_attr(sa, dirattr))
return (false);
break;
}
}
(void)memcpy(dirattr, attr, sizeof(*dirattr));
if (!cvsup_write_dirdown(sa->sa_tmp, dirattr))
return (false);
return (true);
}
for (;;) {
if (list_isempty(sa->sa_dirlist)) {
(void)memset(dirattr, 0, sizeof(*dirattr));
break;
}
if (!cvsup_write_dirup(sa->sa_tmp, dirattr))
return (false);
cvsync2cvsup_remove_attr(sa, dirattr);
if ((dirattr->a_type != FILETYPE_DIR) ||
cvsync2cvsup_isparent(dirattr, attr)) {
break;
}
}
return (true);
}
bool
cvsync2cvsup_isparent(struct scanfile_attr *attr1, struct scanfile_attr *attr2)
{
uint8_t *name2 = (uint8_t *)attr2->a_name;
if ((attr1->a_namelen < attr2->a_namelen) &&
(name2[attr1->a_namelen] == '/') &&
(memcmp(attr1->a_name, name2, attr1->a_namelen) == 0)) {
return (true);
}
return (false);
}
bool
cvsync2cvsup_insert_attr(struct scanfile_args *sa, struct scanfile_attr *attr)
{
struct scanfile_attr *new_attr;
if ((new_attr = malloc(sizeof(*new_attr))) == NULL) {
logmsg_err("%s", strerror(errno));
return (false);
}
(void)memcpy(new_attr, attr, sizeof(*new_attr));
if (!list_insert_tail(sa->sa_dirlist, new_attr)) {
free(new_attr);
return (false);
}
return (true);
}
void
cvsync2cvsup_remove_attr(struct scanfile_args *sa, struct scanfile_attr *attr)
{
struct scanfile_attr *new_attr;
if ((new_attr = list_remove_tail(sa->sa_dirlist)) == NULL) {
(void)memset(attr, 0, sizeof(*attr));
} else {
(void)memcpy(attr, new_attr, sizeof(*attr));
free(new_attr);
}
}
void
usage(void)
{
logmsg_err("Usage: cvsync2cvsup [-hqv] "
"-i <cvsync-scanfile> -o <cvsup-scanfile>");
exit(EXIT_FAILURE);
}
syntax highlighted by Code2HTML, v. 0.9.1