int chacl (int argc, char **argv) { int c; int local = 1; int err = 0; int is_rchacl = !strcmp(command_name,"rchacl"); if (argc == 1 || argc == -1) usage (is_rchacl?rchacl_usage:chacl_usage); memset(&parms,0,sizeof(parms)); optind = 0; while ((c = getopt (argc, argv, "+a:dnRr:u:m:j:p:")) != -1) { switch (c) { case 'a': if(parms.del) error(1,0,"Cannot combine -a and -d"); parms.access = xstrdup(optarg); break; case 'd': if(parms.access) error(1,0,"Cannot combine -a and -d"); parms.del = 1; break; case 'j': parms.merge=xstrdup(optarg); break; case 'm': parms.message=xstrdup(optarg); break; case 'n': parms.noinherit=1; break; case 'p': parms.priority=xstrdup(optarg); break; case 'r': if(parms.branch) error(1,0,"Cannot have multiple -r options"); parms.branch = xstrdup(optarg); break; case 'R': local = 0; break; case 'u': if(parms.user) error(1,0,"Cannot have multiple -u options"); parms.user = xstrdup(optarg); break; case '?': default: usage (chacl_usage); break; } } argc -= optind; argv += optind; if (argc < 0) usage (is_rchacl?rchacl_usage:chacl_usage); if (current_parsed_root->isremote) { if(is_rchacl) { if (!supported_request ("rchacl2")) error (1, 0, "server does not support rchacl"); } else { if (!supported_request ("chacl2")) error (1, 0, "server does not support v2 chacl"); } if(parms.branch) { send_arg("-r"); send_arg(parms.branch); } if(parms.user) { send_arg("-u"); send_arg(parms.user); } if(parms.del) send_arg("-d"); if(parms.noinherit) send_arg("-n"); if(parms.access) { send_arg("-a"); send_arg(parms.access); } if(parms.message) { send_arg("-m"); send_arg(parms.message); } if(parms.merge) { send_arg("-j"); send_arg(parms.merge); } if(parms.priority) { send_arg("-p"); send_arg(parms.priority); } if(!local) { send_arg("-R"); } send_arg("--"); if (is_rchacl) { int i; for (i = 0; i < argc; i++) send_arg (argv[i]); send_to_server ("rchacl2\n", 0); } else { send_file_names (argc, argv, SEND_EXPAND_WILD); send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server ("chacl2\n", 0); } return get_responses_and_close (); } if(!acl_mode) error(1,0,"Access control is disabled on this repository."); if (is_rchacl) { DBM *db; int i; db = open_module (); for (i = 0; i < argc; i++) { err += do_module (db, argv[i], MISC, "Changing", rchacl_proc, (char *) NULL, 0, local, 0, 0, (char *) NULL); } close_module (db); } else { current_date = date_from_time_t(global_session_time_t); err = start_recursion(chacl_fileproc, NULL, (PREDIRENTPROC) NULL, chacl_dirproc, chacl_dirleaveproc, (void*)NULL, argc, argv, local, W_LOCAL, 0, 0, (char*)NULL, NULL, 1, verify_control, parms.branch); xfree(current_date); } return (err); }
/* The purpose of "select_hrec" is to apply the selection criteria based on * the command arguments and defaults and return a flag indicating whether * this record should be remembered for printing. */ static int select_hrec (struct hrec *hr) { char **cpp, *cp, *cp2; struct file_list_str *fl; int count; /* basic validity checking */ if (!hr->type || !hr->user || !hr->dir || !hr->repos || !hr->rev || !hr->file || !hr->end) { error (0, 0, "warning: history line %ld invalid", hr->idx); return 0; } /* "Since" checking: The argument parser guarantees that only one of the * following four choices is set: * * 1. If "since_date" is set, it contains the date specified on the * command line. hr->date fields earlier than "since_date" are ignored. * 2. If "since_rev" is set, it contains either an RCS "dotted" revision * number (which is of limited use) or a symbolic TAG. Each RCS file * is examined and the date on the specified revision (or the revision * corresponding to the TAG) in the RCS file (CVSROOT/repos/file) is * compared against hr->date as in 1. above. * 3. If "since_tag" is set, matching tag records are saved. The field * "last_since_tag" is set to the last one of these. Since we don't * know where the last one will be, all records are saved from the * first occurrence of the TAG. Later, at the end of "select_hrec" * records before the last occurrence of "since_tag" are skipped. * 4. If "backto" is set, all records with a module name or file name * matching "backto" are saved. In addition, all records with a * repository field with a *prefix* matching "backto" are saved. * The field "last_backto" is set to the last one of these. As in * 3. above, "select_hrec" adjusts to include the last one later on. */ if (since_date) { char *ourdate = date_from_time_t (hr->date); count = RCS_datecmp (ourdate, since_date); free (ourdate); if (count < 0) return 0; } else if (*since_rev) { Vers_TS *vers; time_t t; struct file_info finfo; memset (&finfo, 0, sizeof finfo); finfo.file = hr->file; /* Not used, so don't worry about it. */ finfo.update_dir = NULL; finfo.fullname = finfo.file; finfo.repository = hr->repos; finfo.entries = NULL; finfo.rcs = NULL; vers = Version_TS (&finfo, NULL, since_rev, NULL, 1, 0); if (vers->vn_rcs) { if ((t = RCS_getrevtime (vers->srcfile, vers->vn_rcs, NULL, 0)) != (time_t) 0) { if (hr->date < t) { freevers_ts (&vers); return 0; } } } freevers_ts (&vers); } else if (*since_tag) { if (*(hr->type) == 'T') { /* * A 'T'ag record, the "rev" field holds the tag to be set, * while the "repos" field holds "D"elete, "A"dd or a rev. */ if (within (since_tag, hr->rev)) { last_since_tag = hr; return 1; } else return 0; } if (!last_since_tag) return 0; } else if (*backto) { if (within (backto, hr->file) || within (backto, hr->mod) || within (backto, hr->repos)) last_backto = hr; else return 0; } /* User checking: * * Run down "user_list", match username ("" matches anything) * If "" is not there and actual username is not there, return failure. */ if (user_list && hr->user) { for (cpp = user_list, count = user_count; count; cpp++, count--) { if (!**cpp) break; /* null user == accept */ if (!strcmp (hr->user, *cpp)) /* found listed user */ break; } if (!count) return 0; /* Not this user */ } /* Record type checking: * * 1. If Record type is not in rec_types field, skip it. * 2. If mod_list is null, keep everything. Otherwise keep only modules * on mod_list. * 3. If neither a 'T', 'F' nor 'O' record, run through "file_list". If * file_list is null, keep everything. Otherwise, keep only files on * file_list, matched appropriately. */ if (!strchr (rec_types, *(hr->type))) return 0; if (!strchr ("TFOE", *(hr->type))) /* Don't bother with "file" if "TFOE" */ { if (file_list) /* If file_list is null, accept all */ { for (fl = file_list, count = file_count; count; fl++, count--) { /* 1. If file_list entry starts with '*', skip the '*' and * compare it against the repository in the hrec. * 2. If file_list entry has a '/' in it, compare it against * the concatenation of the repository and file from hrec. * 3. Else compare the file_list entry against the hrec file. */ char *cmpfile = NULL; if (*(cp = fl->l_file) == '*') { cp++; /* if argument to -p is a prefix of repository */ if (!strncmp (cp, hr->repos, strlen (cp))) { hr->mod = fl->l_module; break; } } else { if (strchr (cp, '/')) { cmpfile = Xasprintf ("%s/%s", hr->repos, hr->file); cp2 = cmpfile; } else { cp2 = hr->file; } /* if requested file is found within {repos}/file fields */ if (within (cp, cp2)) { hr->mod = fl->l_module; if (cmpfile != NULL) free (cmpfile); break; } if (cmpfile != NULL) free (cmpfile); } } if (!count) return 0; /* String specified and no match */ } } if (mod_list) { for (cpp = mod_list, count = mod_count; count; cpp++, count--) { if (hr->mod && !strcmp (hr->mod, *cpp)) /* found module */ break; } if (!count) return 0; /* Module specified & this record is not one of them. */ } return 1; /* Select this record unless rejected above. */ }
static int rchacl_proc(int argc, char **argv, const char *xwhere, const char *mwhere, const char *mfile, int shorten, int local_specified, const char *mname, const char *msg) { /* Begin section which is identical to patch_proc--should this be abstracted out somehow? */ char *myargv[2]; int err = 0; char *repository, *mapped_repository; char *where; repository = (char*)xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); where = (char*)xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1) + 1); (void) strcpy (where, argv[0]); /* if mfile isn't null, we need to set up to do only part of the module */ if (mfile != NULL) { char *cp; char *path; /* if the portion of the module is a path, put the dir part on repos */ if ((cp = (char*)strrchr (mfile, '/')) != NULL) { *cp = '\0'; (void) strcat (repository, "/"); (void) strcat (repository, mfile); (void) strcat (where, "/"); (void) strcat (where, mfile); mfile = cp + 1; } /* take care of the rest */ path = (char*)xmalloc (strlen (repository) + strlen (mfile) + 5); (void) sprintf (path, "%s/%s", repository, mfile); if (isdir (path)) { /* directory means repository gets the dir tacked on */ (void) strcpy (repository, path); (void) strcat (where, "/"); (void) strcat (where, mfile); } else { myargv[0] = argv[0]; myargv[1] = (char*)mfile; argc = 2; argv = myargv; } xfree (path); } mapped_repository = map_repository(repository); /* cd to the starting repository */ if ( CVS_CHDIR (mapped_repository) < 0) { error (0, errno, "cannot chdir to %s", fn_root(repository)); xfree (repository); xfree (mapped_repository); return (1); } xfree (repository); /* End section which is identical to patch_proc. */ current_date = date_from_time_t(global_session_time_t); err = start_recursion (chacl_fileproc, (FILESDONEPROC) NULL, (PREDIRENTPROC) NULL, chacl_dirproc, (DIRLEAVEPROC) NULL, NULL, argc - 1, argv + 1, local_specified, W_REPOS, 0, 1, where, mapped_repository, 1, verify_control, parms.branch); xfree(current_date); xfree (mapped_repository); return err; }