/*-
* Copyright (c) 2000-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 <stdlib.h>
#include <limits.h>
#include <pthread.h>
#include <string.h>
#include "compat_stdbool.h"
#include "compat_stdint.h"
#include "compat_inttypes.h"
#include "compat_limits.h"
#include "basedef.h"
#include "attribute.h"
#include "collection.h"
#include "cvsync.h"
#include "cvsync_attr.h"
#include "filetypes.h"
#include "list.h"
#include "mux.h"
#include "scanfile.h"
#include "dirscan.h"
#include "dircmp.h"
struct dirscan_scanfile_args {
struct collection *sa_collection;
uint8_t *sa_start, *sa_end;
};
bool dirscan_rcs_scanfile_down(struct dirscan_args *, struct scanfile_attr *);
bool dirscan_rcs_scanfile_up(struct dirscan_args *);
bool dirscan_rcs_scanfile_file(struct dirscan_args *, struct scanfile_attr *);
bool dirscan_rcs_scanfile_read(struct dirscan_scanfile_args *,
struct scanfile_attr *);
bool dirscan_isparent(struct scanfile_attr *, struct scanfile_attr *);
bool
dirscan_rcs_scanfile(struct dirscan_args *dsa)
{
struct dirscan_scanfile_args args;
struct scanfile_args *sa = dsa->dsa_collection->cl_scanfile;
struct scanfile_attr *dirattr = NULL, attr;
struct list *lp;
args.sa_collection = dsa->dsa_collection;
args.sa_start = sa->sa_start;
args.sa_end = sa->sa_end;
if ((lp = list_init()) == NULL)
return (false);
list_set_destructor(lp, free);
while (args.sa_start < args.sa_end) {
if (cvsync_isinterrupted()) {
list_destroy(lp);
if (dirattr != NULL)
free(dirattr);
return (false);
}
if (!dirscan_rcs_scanfile_read(&args, &attr)) {
if (args.sa_start == args.sa_end)
break;
list_destroy(lp);
if (dirattr != NULL)
free(dirattr);
return (false);
}
if (attr.a_namelen > dsa->dsa_namemax) {
list_destroy(lp);
if (dirattr != NULL)
free(dirattr);
return (false);
}
switch (attr.a_type) {
case FILETYPE_DIR:
while (!dirscan_isparent(dirattr, &attr)) {
if (dirattr == NULL)
break;
if (!dirscan_rcs_scanfile_up(dsa)) {
list_destroy(lp);
free(dirattr);
return (false);
}
free(dirattr);
if (list_isempty(lp)) {
dirattr = NULL;
break;
}
if ((dirattr = list_remove_tail(lp)) == NULL) {
list_destroy(lp);
if (dirattr != NULL)
free(dirattr);
return (false);
}
}
if ((dirattr != NULL) &&
!list_insert_tail(lp, dirattr)) {
list_destroy(lp);
if (dirattr != NULL)
free(dirattr);
return (false);
}
if (attr.a_auxlen != RCS_ATTRLEN_DIR) {
list_destroy(lp);
return (false);
}
if (!dirscan_rcs_scanfile_down(dsa, &attr)) {
list_destroy(lp);
return (false);
}
dirattr = cvsync_memdup(&attr, sizeof(attr));
if (dirattr == NULL) {
list_destroy(lp);
return (false);
}
break;
case FILETYPE_FILE:
case FILETYPE_RCS:
case FILETYPE_RCS_ATTIC:
case FILETYPE_SYMLINK:
while (!dirscan_isparent(dirattr, &attr)) {
if ((dirattr != NULL) &&
!dirscan_rcs_scanfile_up(dsa)) {
list_destroy(lp);
free(dirattr);
return (false);
}
if (dirattr != NULL)
free(dirattr);
if (list_isempty(lp)) {
dirattr = NULL;
break;
}
if ((dirattr = list_remove_tail(lp)) == NULL) {
list_destroy(lp);
if (dirattr != NULL)
free(dirattr);
return (false);
}
}
if (!dirscan_rcs_scanfile_file(dsa, &attr)) {
list_destroy(lp);
if (dirattr != NULL)
free(dirattr);
return (false);
}
break;
default:
list_destroy(lp);
if (dirattr != NULL)
free(dirattr);
return (false);
}
args.sa_start += attr.a_size;
}
if (dirattr != NULL) {
if (!dirscan_rcs_scanfile_up(dsa)) {
list_destroy(lp);
free(dirattr);
return (false);
}
free(dirattr);
}
while (!list_isempty(lp)) {
if ((dirattr = list_remove_tail(lp)) == NULL) {
list_destroy(lp);
return (false);
}
if (!dirscan_rcs_scanfile_up(dsa)) {
list_destroy(lp);
free(dirattr);
return (false);
}
free(dirattr);
}
list_destroy(lp);
return (true);
}
bool
dirscan_rcs_scanfile_down(struct dirscan_args *dsa, struct scanfile_attr *attr)
{
const uint8_t *name, *sv_name = attr->a_name;
uint8_t *cmd = dsa->dsa_cmd;
size_t namelen, len;
for (name = &sv_name[attr->a_namelen - 1] ; name >= sv_name ; name--) {
if (*name == '/') {
name++;
break;
}
}
if (name < sv_name)
name = sv_name;
namelen = attr->a_namelen - (name - sv_name);
if (namelen > dsa->dsa_namemax)
return (false);
if ((len = namelen + attr->a_auxlen + 4) > dsa->dsa_cmdmax)
return (false);
SetWord(cmd, len - 2);
cmd[2] = DIRCMP_DOWN;
cmd[3] = namelen;
if (!mux_send(dsa->dsa_mux, MUX_DIRCMP, cmd, 4))
return (false);
if (!mux_send(dsa->dsa_mux, MUX_DIRCMP, name, namelen))
return (false);
if (!mux_send(dsa->dsa_mux, MUX_DIRCMP, attr->a_aux, attr->a_auxlen))
return (false);
return (true);
}
bool
dirscan_rcs_scanfile_up(struct dirscan_args *dsa)
{
static const uint8_t _cmd[3] = { 0x00, 0x01, DIRCMP_UP };
if (!mux_send(dsa->dsa_mux, MUX_DIRCMP, _cmd, sizeof(_cmd)))
return (false);
return (true);
}
bool
dirscan_rcs_scanfile_file(struct dirscan_args *dsa, struct scanfile_attr *attr)
{
uint8_t *cmd = dsa->dsa_cmd;
const uint8_t *name, *sv_name = attr->a_name;
size_t namelen, len;
for (name = &sv_name[attr->a_namelen - 1] ; name >= sv_name ; name--) {
if (*name == '/') {
name++;
break;
}
}
if (name < sv_name)
name = sv_name;
namelen = attr->a_namelen - (name - sv_name);
if (namelen > dsa->dsa_namemax)
return (false);
if ((len = namelen + attr->a_auxlen + 4) > dsa->dsa_cmdmax)
return (false);
SetWord(cmd, len - 2);
switch (attr->a_type) {
case FILETYPE_FILE:
cmd[2] = DIRCMP_FILE;
if (attr->a_auxlen != RCS_ATTRLEN_FILE)
return (false);
break;
case FILETYPE_RCS:
cmd[2] = DIRCMP_RCS;
if (attr->a_auxlen != RCS_ATTRLEN_RCS)
return (false);
break;
case FILETYPE_RCS_ATTIC:
cmd[2] = DIRCMP_RCS_ATTIC;
if (attr->a_auxlen != RCS_ATTRLEN_RCS)
return (false);
break;
case FILETYPE_SYMLINK:
cmd[2] = DIRCMP_SYMLINK;
if (attr->a_auxlen > CVSYNC_MAXAUXLEN)
return (false);
break;
default:
return (false);
}
cmd[3] = namelen;
if (!mux_send(dsa->dsa_mux, MUX_DIRCMP, cmd, 4))
return (false);
if (!mux_send(dsa->dsa_mux, MUX_DIRCMP, name, namelen))
return (false);
if (!mux_send(dsa->dsa_mux, MUX_DIRCMP, attr->a_aux, attr->a_auxlen))
return (false);
return (true);
}
bool
dirscan_rcs_scanfile_read(struct dirscan_scanfile_args *args,
struct scanfile_attr *attr)
{
struct collection *cl = args->sa_collection;
struct scanfile_attr rpref_attr;
char *name;
rpref_attr.a_name = cl->cl_rprefix;
rpref_attr.a_namelen = cl->cl_rprefixlen + 1;
for (;;) {
if (!scanfile_read_attr(args->sa_start, args->sa_end, attr))
return (false);
if (cl->cl_rprefixlen == 0)
break;
if (attr->a_namelen <= cl->cl_rprefixlen) {
if (!dirscan_isparent(attr, &rpref_attr)) {
args->sa_start += attr->a_size;
continue;
}
break;
}
name = attr->a_name;
if ((name[cl->cl_rprefixlen] == '/') &&
(memcmp(name, cl->cl_rprefix, cl->cl_rprefixlen) == 0)) {
break;
}
args->sa_start += attr->a_size;
if (args->sa_start == args->sa_end)
return (false);
}
return (true);
}
bool
dirscan_isparent(struct scanfile_attr *dirattr, struct scanfile_attr *attr)
{
uint8_t *name = attr->a_name;
if (dirattr == NULL)
return (true);
if (dirattr->a_type != FILETYPE_DIR)
return (false);
if (dirattr->a_namelen >= attr->a_namelen)
return (false);
if (name[dirattr->a_namelen] != '/')
return (false);
if (memcmp(dirattr->a_name, name, dirattr->a_namelen) != 0)
return (false);
return (true);
}
syntax highlighted by Code2HTML, v. 0.9.1