1 /* CVS client-related stuff.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.  */
12 #include <sys/cdefs.h>
13 __RCSID("$NetBSD: client.c,v 1.6 2024/02/04 21:42:24 christos Exp $");
14 
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif /* HAVE_CONFIG_H */
18 
19 #include "cvs.h"
20 #include "getline.h"
21 #include "edit.h"
22 #include "buffer.h"
23 #include "save-cwd.h"
24 
25 #ifdef CLIENT_SUPPORT
26 
27 # include "log-buffer.h"
28 # include "md5.h"
29 
30 #include "socket-client.h"
31 #include "rsh-client.h"
32 
33 # ifdef HAVE_GSSAPI
34 #   include "gssapi-client.h"
35 # endif
36 
37 # ifdef HAVE_KERBEROS
38 #   include "kerberos4-client.h"
39 # endif
40 
41 
42 
43 /* Keep track of any paths we are sending for Max-dotdot so that we can verify
44  * that uplevel paths coming back form the server are valid.
45  *
46  * FIXME: The correct way to do this is probably provide some sort of virtual
47  * path map on the client side.  This would be generic enough to be applied to
48  * absolute paths supplied by the user too.
49  */
50 static List *uppaths;
51 
52 
53 
54 static void add_prune_candidate (const char *);
55 
56 /* All the commands.  */
57 int add (int argc, char **argv);
58 int admin (int argc, char **argv);
59 int checkout (int argc, char **argv);
60 int commit (int argc, char **argv);
61 int diff (int argc, char **argv);
62 int history (int argc, char **argv);
63 int import (int argc, char **argv);
64 int cvslog (int argc, char **argv);
65 int patch (int argc, char **argv);
66 int release (int argc, char **argv);
67 int cvsremove (int argc, char **argv);
68 int rtag (int argc, char **argv);
69 int status (int argc, char **argv);
70 int tag (int argc, char **argv);
71 int update (int argc, char **argv);
72 
73 #if defined AUTH_CLIENT_SUPPORT || defined HAVE_KERBEROS || defined HAVE_GSSAPI
74 static int connect_to(char *, unsigned int);
75 #endif
76 
77 static size_t try_read_from_server (char *, size_t);
78 
79 static void auth_server (cvsroot_t *, struct buffer *, struct buffer *,
80                                int, int);
81 
82 
83 
84 /* This is the referrer who referred us to a primary, or write server, using
85  * the "Redirect" request.
86  */
87 static cvsroot_t *client_referrer;
88 
89 /* We need to keep track of the list of directories we've sent to the
90    server.  This list, along with the current CVSROOT, will help us
91    decide which command-line arguments to send.  */
92 List *dirs_sent_to_server;
93 static int
is_arg_a_parent_or_listed_dir(Node * n,void * d)94 is_arg_a_parent_or_listed_dir (Node *n, void *d)
95 {
96     char *directory = n->key; /* name of the dir sent to server */
97     char *this_argv_elem = d; /* this argv element */
98 
99     /* Say we should send this argument if the argument matches the
100        beginning of a directory name sent to the server.  This way,
101        the server will know to start at the top of that directory
102        hierarchy and descend. */
103 
104     if (!strncmp (directory, this_argv_elem, strlen (this_argv_elem)))
105           return 1;
106 
107     return 0;
108 }
109 
110 
111 
112 /* Return nonzero if this argument should not be sent to the
113    server. */
114 static int
arg_should_not_be_sent_to_server(char * arg)115 arg_should_not_be_sent_to_server (char *arg)
116 {
117     /* Decide if we should send this directory name to the server.  We
118        should always send argv[i] if:
119 
120        1) the list of directories sent to the server is empty (as it
121        will be for checkout, etc.).
122 
123        2) the argument is "."
124 
125        3) the argument is a file in the cwd and the cwd is checked out
126        from the current root
127 
128        4) the argument lies within one of the paths in
129        dirs_sent_to_server.
130 
131        */
132 
133     if (list_isempty (dirs_sent_to_server))
134           return 0;           /* always send it */
135 
136     if (!strcmp (arg, "."))
137           return 0;           /* always send it */
138 
139     /* We should send arg if it is one of the directories sent to the
140        server or the parent of one; this tells the server to descend
141        the hierarchy starting at this level. */
142     if (isdir (arg))
143     {
144           if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir, arg))
145               return 0;
146 
147           /* If arg wasn't a parent, we don't know anything about it (we
148              would have seen something related to it during the
149              send_files phase).  Don't send it.  */
150           return 1;
151     }
152 
153     /* Try to decide whether we should send arg to the server by
154        checking the contents of the corresponding CVSADM directory. */
155     {
156           char *t, *root_string;
157           cvsroot_t *this_root = NULL;
158 
159           /* Calculate "dirname arg" */
160           for (t = arg + strlen (arg) - 1; t >= arg; t--)
161           {
162               if (ISSLASH (*t))
163                     break;
164           }
165 
166           /* Now we're either poiting to the beginning of the
167              string, or we found a path separator. */
168           if (t >= arg)
169           {
170               /* Found a path separator.  */
171               char c = *t;
172               *t = '\0';
173 
174               /* First, check to see if we sent this directory to the
175                server, because it takes less time than actually
176                opening the stuff in the CVSADM directory.  */
177               if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir,
178                                 arg))
179               {
180                     *t = c;             /* make sure to un-truncate the arg */
181                     return 0;
182               }
183 
184               /* Since we didn't find it in the list, check the CVSADM
185                files on disk.  */
186               this_root = Name_Root (arg, NULL);
187               root_string = this_root->original;
188               *t = c;
189           }
190           else
191           {
192               /* We're at the beginning of the string.  Look at the
193                CVSADM files in cwd.  */
194               if (CVSroot_cmdline)
195                     root_string = CVSroot_cmdline;
196               else
197               {
198                     this_root = Name_Root (NULL, NULL);
199                     root_string = this_root->original;
200               }
201           }
202 
203           /* Now check the value for root. */
204           if (root_string && current_parsed_root
205               && strcmp (root_string, original_parsed_root->original))
206           {
207               /* Don't send this, since the CVSROOTs don't match. */
208               return 1;
209           }
210     }
211 
212     /* OK, let's send it. */
213     return 0;
214 }
215 #endif /* CLIENT_SUPPORT */
216 
217 
218 
219 #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
220 
221 /* Shared with server.  */
222 
223 /*
224  * Return a malloc'd, '\0'-terminated string
225  * corresponding to the mode in SB.
226  */
227 char *
mode_to_string(mode_t mode)228 mode_to_string (mode_t mode)
229 {
230     char u[4], g[4], o[4];
231     int i;
232 
233     i = 0;
234     if (mode & S_IRUSR) u[i++] = 'r';
235     if (mode & S_IWUSR) u[i++] = 'w';
236     if (mode & S_IXUSR) u[i++] = 'x';
237     u[i] = '\0';
238 
239     i = 0;
240     if (mode & S_IRGRP) g[i++] = 'r';
241     if (mode & S_IWGRP) g[i++] = 'w';
242     if (mode & S_IXGRP) g[i++] = 'x';
243     g[i] = '\0';
244 
245     i = 0;
246     if (mode & S_IROTH) o[i++] = 'r';
247     if (mode & S_IWOTH) o[i++] = 'w';
248     if (mode & S_IXOTH) o[i++] = 'x';
249     o[i] = '\0';
250 
251     return Xasprintf ("u=%s,g=%s,o=%s", u, g, o);
252 }
253 
254 
255 
256 /*
257  * Change mode of FILENAME to MODE_STRING.
258  * Returns 0 for success or errno code.
259  * If RESPECT_UMASK is set, then honor the umask.
260  */
261 int
change_mode(const char * filename,const char * mode_string,int respect_umask)262 change_mode (const char *filename, const char *mode_string, int respect_umask)
263 {
264 #ifdef CHMOD_BROKEN
265     char *p;
266     int writeable = 0;
267 
268     /* We can only distinguish between
269          1) readable
270          2) writeable
271          3) Picasso's "Blue Period"
272        We handle the first two. */
273     p = mode_string;
274     while (*p != '\0')
275     {
276           if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=')
277           {
278               char *q = p + 2;
279               while (*q != ',' && *q != '\0')
280               {
281                     if (*q == 'w')
282                         writeable = 1;
283                     ++q;
284               }
285           }
286           /* Skip to the next field.  */
287           while (*p != ',' && *p != '\0')
288               ++p;
289           if (*p == ',')
290               ++p;
291     }
292 
293     /* xchmod honors the umask for us.  In the !respect_umask case, we
294        don't try to cope with it (probably to handle that well, the server
295        needs to deal with modes in data structures, rather than via the
296        modes in temporary files).  */
297     xchmod (filename, writeable);
298           return 0;
299 
300 #else /* ! CHMOD_BROKEN */
301 
302     const char *p;
303     mode_t mode = 0;
304     mode_t oumask;
305 
306     p = mode_string;
307     while (*p != '\0')
308     {
309           if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=')
310           {
311               int can_read = 0, can_write = 0, can_execute = 0;
312               const char *q = p + 2;
313               while (*q != ',' && *q != '\0')
314               {
315                     if (*q == 'r')
316                         can_read = 1;
317                     else if (*q == 'w')
318                         can_write = 1;
319                     else if (*q == 'x')
320                         can_execute = 1;
321                     ++q;
322               }
323               if (p[0] == 'u')
324               {
325                     if (can_read)
326                         mode |= S_IRUSR;
327                     if (can_write)
328                         mode |= S_IWUSR;
329                     if (can_execute)
330                         mode |= S_IXUSR;
331               }
332               else if (p[0] == 'g')
333               {
334                     if (can_read)
335                         mode |= S_IRGRP;
336                     if (can_write)
337                         mode |= S_IWGRP;
338                     if (can_execute)
339                         mode |= S_IXGRP;
340               }
341               else if (p[0] == 'o')
342               {
343                     if (can_read)
344                         mode |= S_IROTH;
345                     if (can_write)
346                         mode |= S_IWOTH;
347                     if (can_execute)
348                         mode |= S_IXOTH;
349               }
350           }
351           /* Skip to the next field.  */
352           while (*p != ',' && *p != '\0')
353               ++p;
354           if (*p == ',')
355               ++p;
356     }
357 
358     if (respect_umask)
359     {
360           oumask = umask (0);
361           (void) umask (oumask);
362           mode &= ~oumask;
363     }
364 
365     if (chmod (filename, mode) < 0)
366           return errno;
367     return 0;
368 #endif /* ! CHMOD_BROKEN */
369 }
370 #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
371 
372 
373 
374 #ifdef CLIENT_SUPPORT
375 int client_prune_dirs;
376 
377 static List *ignlist = NULL;
378 
379 /* Buffer to write to the server.  */
380 static struct buffer *global_to_server;
381 
382 /* Buffer used to read from the server.  */
383 static struct buffer *global_from_server;
384 
385 
386 
387 /*
388  * Read a line from the server.  Result does not include the terminating \n.
389  *
390  * Space for the result is malloc'd and should be freed by the caller.
391  *
392  * Returns number of bytes read.
393  */
394 static size_t
read_line_via(struct buffer * via_from_buffer,struct buffer * via_to_buffer,char ** resultp)395 read_line_via (struct buffer *via_from_buffer, struct buffer *via_to_buffer,
396                char **resultp)
397 {
398     int status;
399     char *result;
400     size_t len;
401 
402     status = buf_flush (via_to_buffer, 1);
403     if (status != 0)
404           error (1, status, "writing to server");
405 
406     status = buf_read_line (via_from_buffer, &result, &len);
407     if (status != 0)
408     {
409           if (status == -1)
410               error (1, 0,
411                    "end of file from server (consult above messages if any)");
412           else if (status == -2)
413               error (1, 0, "out of memory");
414           else
415               error (1, status, "reading from server");
416     }
417 
418     if (resultp)
419           *resultp = result;
420     else
421           free (result);
422 
423     return len;
424 }
425 
426 
427 
428 static size_t
read_line(char ** resultp)429 read_line (char **resultp)
430 {
431   return read_line_via (global_from_server, global_to_server, resultp);
432 }
433 #endif /* CLIENT_SUPPORT */
434 
435 
436 
437 #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
438 /*
439  * Zero if compression isn't supported or requested; non-zero to indicate
440  * a compression level to request from gzip.
441  */
442 int gzip_level;
443 
444 /*
445  * Level of compression to use when running gzip on a single file.
446  */
447 int file_gzip_level;
448 
449 #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
450 
451 #ifdef CLIENT_SUPPORT
452 
453 /* Whether the server asked us to force compression.  */
454 static bool force_gzip;
455 
456 /*
457  * The Repository for the top level of this command (not necessarily
458  * the CVSROOT, just the current directory at the time we do it).
459  */
460 static char *toplevel_repos;
461 
462 /* Working directory when we first started.  Note: we could speed things
463    up on some systems by using savecwd.h here instead of just always
464    storing a name.  */
465 char *toplevel_wd;
466 
467 
468 
469 static void
handle_ok(char * args,size_t len)470 handle_ok (char *args, size_t len)
471 {
472     return;
473 }
474 
475 
476 
477 static void
handle_error(char * args,size_t len)478 handle_error (char *args, size_t len)
479 {
480     int something_printed;
481 
482     /*
483      * First there is a symbolic error code followed by a space, which
484      * we ignore.
485      */
486     char *p = strchr (args, ' ');
487     if (!p)
488     {
489           error (0, 0, "invalid data from cvs server");
490           return;
491     }
492     ++p;
493 
494     /* Next we print the text of the message from the server.  We
495        probably should be prefixing it with "server error" or some
496        such, because if it is something like "Out of memory", the
497        current behavior doesn't say which machine is out of
498        memory.  */
499 
500     len -= p - args;
501     something_printed = 0;
502     for (; len > 0; --len)
503     {
504           something_printed = 1;
505           putc (*p++, stderr);
506     }
507     if (something_printed)
508           putc ('\n', stderr);
509 }
510 
511 
512 
513 static void
handle_valid_requests(char * args,size_t len)514 handle_valid_requests (char *args, size_t len)
515 {
516     char *p = args;
517     char *q;
518     struct request *rq;
519     do
520     {
521           q = strchr (p, ' ');
522           if (q)
523               *q++ = '\0';
524           for (rq = requests; rq->name; ++rq)
525           {
526               if (!strcmp (rq->name, p))
527                     break;
528           }
529           if (!rq->name)
530               /*
531                * It is a request we have never heard of (and thus never
532                * will want to use).  So don't worry about it.
533                */
534               ;
535           else
536           {
537               if (rq->flags & RQ_ENABLEME)
538               {
539                     /*
540                      * Server wants to know if we have this, to enable the
541                      * feature.
542                      */
543                     send_to_server (rq->name, 0);
544                 send_to_server ("\012", 0);
545               }
546               else
547                     rq->flags |= RQ_SUPPORTED;
548           }
549           p = q;
550     } while (q);
551     for (rq = requests; rq->name; ++rq)
552     {
553           if ((rq->flags & RQ_SUPPORTED)
554               || (rq->flags & RQ_ENABLEME))
555               continue;
556           if (rq->flags & RQ_ESSENTIAL)
557               error (1, 0, "request `%s' not supported by server", rq->name);
558     }
559 }
560 
561 static void
handle_force_gzip(char * args,size_t len)562 handle_force_gzip (char *args, size_t len)
563 {
564     force_gzip = true;
565 }
566 
567 
568 
569 /* Has the server told us its name since the last redirect?
570  */
571 static bool referred_since_last_redirect = false;
572 static bool free_client_referrer = false;
573 
574 
575 
576 static void
handle_referrer(char * args,size_t len)577 handle_referrer (char *args, size_t len)
578 {
579     TRACE (TRACE_FUNCTION, "handle_referrer (%s)", args);
580     client_referrer = parse_cvsroot (args);
581     referred_since_last_redirect = true;
582     free_client_referrer = true;
583 }
584 
585 
586 
587 /* Redirect our connection to a different server and start over.
588  *
589  * GLOBALS
590  *   current_parsed_root      The CVSROOT being accessed.
591  *   client_referrer                    Used to track the server which referred us to a
592  *                                      new server.  Can be supplied by the referring
593  *                                      server.
594  *   free_client_referrer     Used to track whether the client_referrer needs
595  *                                      to be freed before changing it.
596  *   referred_since_last_redirect
597  *                                      Tracks whether the currect server told us how
598  *                                      to refer to it.
599  *
600  * OUTPUTS
601  *   current_parsed_root      Updated to point to the new CVSROOT.
602  *   referred_since_last_redirect
603  *                                      Always cleared.
604  *   client_referrer                    Set automatically to current_parsed_root if
605  *                                      the current server did not give us a name to
606  *                                      refer to it by.
607  *   free_client_referrer     Reset when necessary.
608  */
609 static void
handle_redirect(char * args,size_t len)610 handle_redirect (char *args, size_t len)
611 {
612     static List *redirects = NULL;
613 
614     TRACE (TRACE_FUNCTION, "handle_redirect (%s)", args);
615 
616     if (redirects && findnode (redirects, args))
617           error (1, 0, "`Redirect' loop detected.  Server misconfiguration?");
618     else
619     {
620           if (!redirects) redirects = getlist();
621           push_string (redirects, args);
622     }
623 
624     if (referred_since_last_redirect)
625           referred_since_last_redirect = false;
626     else
627     {
628           if (free_client_referrer) free (client_referrer);
629           client_referrer = current_parsed_root;
630           free_client_referrer = false;
631     }
632 
633     current_parsed_root = parse_cvsroot (args);
634 
635     /* We deliberately do not set ORIGINAL_PARSED_ROOT here.
636      * ORIGINAL_PARSED_ROOT is used by the client to determine the current root
637      * being processed for the purpose of looking it up in lists and such, even
638      * after a redirect.
639      *
640      * FIXME
641      *   CURRENT_PARSED_ROOT should not be reset by this function.  Redirects
642      *   should be "added" to it.  The REDIRECTS list should also be replaced
643      *   by this new CURRENT_PARSED_ROOT element.  This way, if, for instance,
644      *   a multi-root workspace had two secondaries pointing to the same
645      *   primary, then the client would not report a looping error.
646      *
647      *   There is also a potential memory leak above and storing new roots as
648      *   part of the original could help avoid it fairly elegantly.
649      */
650     if (!current_parsed_root)
651           error (1, 0, "Server requested redirect to invalid root: `%s'",
652                  args);
653 }
654 
655 
656 
657 /*
658  * This is a proc for walklist().  It inverts the error return premise of
659  * walklist.
660  *
661  * RETURNS
662  *   True       If this path is prefixed by one of the paths in walklist and
663  *              does not step above the prefix path.
664  *   False      Otherwise.
665  */
666 static
path_list_prefixed(Node * p,void * closure)667 int path_list_prefixed (Node *p, void *closure)
668 {
669     const char *questionable = closure;
670     const char *prefix = p->key;
671     if (strncmp (prefix, questionable, strlen (prefix))) return 0;
672     questionable += strlen (prefix);
673     while (ISSLASH (*questionable)) questionable++;
674     if (*questionable == '\0') return 1;
675     return pathname_levels (questionable);
676 }
677 
678 
679 
680 /*
681  * Need to validate the client pathname.  Disallowed paths include:
682  *
683  *   1. Absolute paths.
684  *   2. Pathnames that do not reference a specifically requested update
685  *      directory.
686  *
687  * In case 2, we actually only check that the directory is under the uppermost
688  * directories mentioned on the command line.
689  *
690  * RETURNS
691  *   True       If the path is valid.
692  *   False      Otherwise.
693  */
694 static
is_valid_client_path(const char * pathname)695 int is_valid_client_path (const char *pathname)
696 {
697     /* 1. Absolute paths. */
698     if (ISABSOLUTE (pathname)) return 0;
699     /* 2. No up-references in path.  */
700     if (pathname_levels (pathname) == 0) return 1;
701     /* 2. No Max-dotdot paths registered.  */
702     if (!uppaths) return 0;
703 
704     return walklist (uppaths, path_list_prefixed, (void *)pathname);
705 }
706 
707 
708 
709 /*
710  * Do all the processing for PATHNAME, where pathname consists of the
711  * repository and the filename.  The parameters we pass to FUNC are:
712  * DATA is just the DATA parameter which was passed to
713  * call_in_directory; ENT_LIST is a pointer to an entries list (which
714  * we manage the storage for); SHORT_PATHNAME is the pathname of the
715  * file relative to the (overall) directory in which the command is
716  * taking place; and FILENAME is the filename portion only of
717  * SHORT_PATHNAME.  When we call FUNC, the curent directory points to
718  * the directory portion of SHORT_PATHNAME.  */
719 static void
call_in_directory(const char * pathname,void (* func)(void *,List *,const char *,const char *),void * data)720 call_in_directory (const char *pathname,
721                    void (*func) (void *, List *, const char *, const char *),
722                    void *data)
723 {
724     /* This variable holds the result of Entries_Open. */
725     List *last_entries = NULL;
726     char *dir_name;
727     char *filename;
728     /* This is what we get when we hook up the directory (working directory
729        name) from PATHNAME with the filename from REPOSNAME.  For example:
730        pathname: ccvs/src/
731        reposname: /u/src/master/ccvs/foo/ChangeLog
732        short_pathname: ccvs/src/ChangeLog
733        */
734     char *short_pathname;
735     char *p;
736 
737     /*
738      * Do the whole descent in parallel for the repositories, so we
739      * know what to put in CVS/Repository files.  I'm not sure the
740      * full hair is necessary since the server does a similar
741      * computation; I suspect that we only end up creating one
742      * directory at a time anyway.
743      *
744      * Also note that we must *only* worry about this stuff when we
745      * are creating directories; `cvs co foo/bar; cd foo/bar; cvs co
746      * CVSROOT; cvs update' is legitimate, but in this case
747      * foo/bar/CVSROOT/CVS/Repository is not a subdirectory of
748      * foo/bar/CVS/Repository.
749      */
750     char *reposname;
751     char *short_repos;
752     char *reposdirname;
753     char *rdirp;
754     int reposdirname_absolute;
755     int newdir = 0;
756 
757     assert (pathname);
758 
759     reposname = NULL;
760     read_line (&reposname);
761     assert (reposname);
762 
763     reposdirname_absolute = 0;
764     if (strncmp (reposname, toplevel_repos, strlen (toplevel_repos)))
765     {
766           reposdirname_absolute = 1;
767           short_repos = reposname;
768     }
769     else
770     {
771           short_repos = reposname + strlen (toplevel_repos) + 1;
772           if (short_repos[-1] != '/')
773           {
774               reposdirname_absolute = 1;
775               short_repos = reposname;
776           }
777     }
778 
779    /* Now that we have SHORT_REPOS, we can calculate the path to the file we
780     * are being requested to operate on.
781     */
782     filename = strrchr (short_repos, '/');
783     if (!filename)
784           filename = short_repos;
785     else
786           ++filename;
787 
788     short_pathname = xmalloc (strlen (pathname) + strlen (filename) + 5);
789     strcpy (short_pathname, pathname);
790     strcat (short_pathname, filename);
791 
792     /* Now that we know the path to the file we were requested to operate on,
793      * we can verify that it is valid.
794      *
795      * For security reasons, if SHORT_PATHNAME is absolute or attempts to
796      * ascend outside of the current sanbbox, we abort.  The server should not
797      * send us anything but relative paths which remain inside the sandbox
798      * here.  Anything less means a trojan CVS server could create and edit
799      * arbitrary files on the client.
800      */
801     if (!is_valid_client_path (short_pathname))
802     {
803           error (0, 0,
804                "Server attempted to update a file via an invalid pathname:");
805         error (1, 0, "`%s'.", short_pathname);
806     }
807 
808     reposdirname = xstrdup (short_repos);
809     p = strrchr (reposdirname, '/');
810     if (!p)
811     {
812           reposdirname = xrealloc (reposdirname, 2);
813           reposdirname[0] = '.'; reposdirname[1] = '\0';
814     }
815     else
816           *p = '\0';
817 
818     dir_name = xstrdup (pathname);
819     p = strrchr (dir_name, '/');
820     if (!p)
821     {
822           dir_name = xrealloc (dir_name, 2);
823           dir_name[0] = '.'; dir_name[1] = '\0';
824     }
825     else
826           *p = '\0';
827     if (client_prune_dirs)
828           add_prune_candidate (dir_name);
829 
830     if (!toplevel_wd)
831     {
832           toplevel_wd = xgetcwd ();
833           if (!toplevel_wd)
834               error (1, errno, "could not get working directory");
835     }
836 
837     if (CVS_CHDIR (toplevel_wd) < 0)
838           error (1, errno, "could not chdir to %s", toplevel_wd);
839 
840     /* Create the CVS directory at the top level if needed.  The
841        isdir seems like an unneeded system call, but it *does*
842        need to be called both if the CVS_CHDIR below succeeds
843        (e.g.  "cvs co .") or if it fails (e.g. basicb-1a in
844        testsuite).  We only need to do this for the "." case,
845        since the server takes care of forcing this directory to be
846        created in all other cases.  If we don't create CVSADM
847        here, the call to Entries_Open below will fail.  FIXME:
848        perhaps this means that we should change our algorithm
849        below that calls Create_Admin instead of having this code
850        here? */
851     if (/* I think the reposdirname_absolute case has to do with
852              things like "cvs update /foo/bar".  In any event, the
853              code below which tries to put toplevel_repos into
854              CVS/Repository is almost surely unsuited to
855              the reposdirname_absolute case.  */
856           !reposdirname_absolute
857           && !strcmp (dir_name, ".")
858           && ! isdir (CVSADM))
859     {
860           char *repo;
861           char *r;
862 
863           newdir = 1;
864 
865           /* If toplevel_repos doesn't have at least one character, then the
866            * reference to r[-1] below could be out of bounds.
867            */
868           assert (*toplevel_repos);
869 
870           repo = xmalloc (strlen (toplevel_repos)
871                               + 10);
872           strcpy (repo, toplevel_repos);
873           r = repo + strlen (repo);
874           if (r[-1] != '.' || r[-2] != '/')
875               strcpy (r, "/.");
876 
877           Create_Admin (".", ".", repo, NULL, NULL, 0, 1, 1);
878 
879           free (repo);
880     }
881 
882     if (CVS_CHDIR (dir_name) < 0)
883     {
884           char *dir;
885           char *dirp;
886 
887           if (! existence_error (errno))
888               error (1, errno, "could not chdir to %s", dir_name);
889 
890           /* Directory does not exist, we need to create it.  */
891           newdir = 1;
892 
893           /* Provided we are willing to assume that directories get
894              created one at a time, we could simplify this a lot.
895              Do note that one aspect still would need to walk the
896              dir_name path: the checking for "fncmp (dir, CVSADM)".  */
897 
898           dir = xmalloc (strlen (dir_name) + 1);
899           dirp = dir_name;
900           rdirp = reposdirname;
901 
902           /* This algorithm makes nested directories one at a time
903              and create CVS administration files in them.  For
904              example, we're checking out foo/bar/baz from the
905              repository:
906 
907              1) create foo, point CVS/Repository to <root>/foo
908              2)     .. foo/bar                   .. <root>/foo/bar
909              3)     .. foo/bar/baz               .. <root>/foo/bar/baz
910 
911              As you can see, we're just stepping along DIR_NAME (with
912              DIRP) and REPOSDIRNAME (with RDIRP) respectively.
913 
914              We need to be careful when we are checking out a
915              module, however, since DIR_NAME and REPOSDIRNAME are not
916              going to be the same.  Since modules will not have any
917              slashes in their names, we should watch the output of
918              STRCHR to decide whether or not we should use STRCHR on
919              the RDIRP.  That is, if we're down to a module name,
920              don't keep picking apart the repository directory name.  */
921 
922           do
923           {
924               dirp = strchr (dirp, '/');
925               if (dirp)
926               {
927                     strncpy (dir, dir_name, dirp - dir_name);
928                     dir[dirp - dir_name] = '\0';
929                     /* Skip the slash.  */
930                     ++dirp;
931                     if (!rdirp)
932                         /* This just means that the repository string has
933                            fewer components than the dir_name string.  But
934                            that is OK (e.g. see modules3-8 in testsuite).  */
935                         ;
936                     else
937                         rdirp = strchr (rdirp, '/');
938               }
939               else
940               {
941                     /* If there are no more slashes in the dir name,
942                        we're down to the most nested directory -OR- to
943                        the name of a module.  In the first case, we
944                        should be down to a DIRP that has no slashes,
945                        so it won't help/hurt to do another STRCHR call
946                        on DIRP.  It will definitely hurt, however, if
947                        we're down to a module name, since a module
948                        name can point to a nested directory (that is,
949                        DIRP will still have slashes in it.  Therefore,
950                        we should set it to NULL so the routine below
951                        copies the contents of REMOTEDIRNAME onto the
952                        root repository directory (does this if rdirp
953                        is set to NULL, because we used to do an extra
954                        STRCHR call here). */
955 
956                     rdirp = NULL;
957                     strcpy (dir, dir_name);
958               }
959 
960               if (fncmp (dir, CVSADM) == 0)
961               {
962                     error (0, 0, "cannot create a directory named %s", dir);
963                     error (0, 0, "because CVS uses \"%s\" for its own uses",
964                            CVSADM);
965                     error (1, 0, "rename the directory and try again");
966               }
967 
968               if (mkdir_if_needed (dir))
969               {
970                     /* It already existed, fine.  Just keep going.  */
971               }
972               else if (!strcmp (cvs_cmd_name, "export"))
973                     /* Don't create CVSADM directories if this is export.  */
974                     ;
975               else
976               {
977                     /*
978                      * Put repository in CVS/Repository.  For historical
979                      * (pre-CVS/Root) reasons, this is an absolute pathname,
980                      * but what really matters is the part of it which is
981                      * relative to cvsroot.
982                      */
983                     char *repo;
984                     char *r, *b;
985 
986                     repo = xmalloc (strlen (reposdirname)
987                                         + strlen (toplevel_repos)
988                                         + 80);
989                     if (reposdirname_absolute)
990                         r = repo;
991                     else
992                     {
993                         strcpy (repo, toplevel_repos);
994                         strcat (repo, "/");
995                         r = repo + strlen (repo);
996                     }
997 
998                     if (rdirp)
999                     {
1000                         /* See comment near start of function; the only
1001                            way that the server can put the right thing
1002                            in each CVS/Repository file is to create the
1003                            directories one at a time.  I think that the
1004                            CVS server has been doing this all along.  */
1005                         error (0, 0, "\
1006 warning: server is not creating directories one at a time");
1007                         strncpy (r, reposdirname, rdirp - reposdirname);
1008                         r[rdirp - reposdirname] = '\0';
1009                     }
1010                     else
1011                         strcpy (r, reposdirname);
1012 
1013                     Create_Admin (dir, dir, repo, NULL, NULL, 0, 0, 1);
1014                     free (repo);
1015 
1016                     b = strrchr (dir, '/');
1017                     if (!b)
1018                         Subdir_Register (NULL, NULL, dir);
1019                     else
1020                     {
1021                         *b = '\0';
1022                         Subdir_Register (NULL, dir, b + 1);
1023                         *b = '/';
1024                     }
1025               }
1026 
1027               if (rdirp)
1028               {
1029                     /* Skip the slash.  */
1030                     ++rdirp;
1031               }
1032 
1033           } while (dirp);
1034           free (dir);
1035           /* Now it better work.  */
1036           if (CVS_CHDIR (dir_name) < 0)
1037               error (1, errno, "could not chdir to %s", dir_name);
1038     }
1039     else if (!strcmp (cvs_cmd_name, "export"))
1040           /* Don't create CVSADM directories if this is export.  */
1041           ;
1042     else if (!isdir (CVSADM))
1043     {
1044           /*
1045            * Put repository in CVS/Repository.  For historical
1046            * (pre-CVS/Root) reasons, this is an absolute pathname,
1047            * but what really matters is the part of it which is
1048            * relative to cvsroot.
1049            */
1050           char *repo;
1051 
1052           if (reposdirname_absolute)
1053               repo = reposdirname;
1054           else
1055               repo = Xasprintf ("%s/%s", toplevel_repos, reposdirname);
1056 
1057           Create_Admin (".", ".", repo, NULL, NULL, 0, 1, 1);
1058           if (repo != reposdirname)
1059               free (repo);
1060     }
1061 
1062     if (strcmp (cvs_cmd_name, "export"))
1063     {
1064           last_entries = Entries_Open (0, dir_name);
1065 
1066           /* If this is a newly created directory, we will record
1067              all subdirectory information, so call Subdirs_Known in
1068              case there are no subdirectories.  If this is not a
1069              newly created directory, it may be an old working
1070              directory from before we recorded subdirectory
1071              information in the Entries file.  We force a search for
1072              all subdirectories now, to make sure our subdirectory
1073              information is up to date.  If the Entries file does
1074              record subdirectory information, then this call only
1075              does list manipulation.  */
1076           if (newdir)
1077               Subdirs_Known (last_entries);
1078           else
1079           {
1080               List *dirlist;
1081 
1082               dirlist = Find_Directories (NULL, W_LOCAL, last_entries);
1083               dellist (&dirlist);
1084           }
1085     }
1086     free (reposdirname);
1087     (*func) (data, last_entries, short_pathname, filename);
1088     if (last_entries)
1089           Entries_Close (last_entries);
1090     free (dir_name);
1091     free (short_pathname);
1092     free (reposname);
1093 }
1094 
1095 
1096 
1097 static void
copy_a_file(void * data,List * ent_list,const char * short_pathname,const char * filename)1098 copy_a_file (void *data, List *ent_list, const char *short_pathname,
1099                const char *filename)
1100 {
1101     char *newname;
1102 
1103     read_line (&newname);
1104 
1105 #ifdef USE_VMS_FILENAMES
1106     {
1107           /* Mogrify the filename so VMS is happy with it. */
1108           char *p;
1109           for(p = newname; *p; p++)
1110              if(*p == '.' || *p == '#') *p = '_';
1111     }
1112 #endif
1113     /* cvsclient.texi has said for a long time that newname must be in the
1114        same directory.  Wouldn't want a malicious or buggy server overwriting
1115        ~/.profile, /etc/passwd, or anything like that.  */
1116     if (last_component (newname) != newname)
1117           error (1, 0, "protocol error: Copy-file tried to specify directory");
1118 
1119     if (unlink_file (newname) && !existence_error (errno))
1120           error (0, errno, "unable to remove %s", newname);
1121     copy_file (filename, newname);
1122     free (newname);
1123 }
1124 
1125 
1126 
1127 static void
handle_copy_file(char * args,size_t len)1128 handle_copy_file (char *args, size_t len)
1129 {
1130     call_in_directory (args, copy_a_file, NULL);
1131 }
1132 
1133 
1134 
1135 /* Read from the server the count for the length of a file, then read
1136    the contents of that file and write them to FILENAME.  FULLNAME is
1137    the name of the file for use in error messages.  FIXME-someday:
1138    extend this to deal with compressed files and make update_entries
1139    use it.  On error, gives a fatal error.  */
1140 static void
read_counted_file(const char * filename,const char * fullname)1141 read_counted_file (const char *filename, const char *fullname)
1142 {
1143     char *size_string;
1144     size_t size;
1145     char *buf;
1146 
1147     /* Pointers in buf to the place to put data which will be read,
1148        and the data which needs to be written, respectively.  */
1149     char *pread;
1150     char *pwrite;
1151     /* Number of bytes left to read and number of bytes in buf waiting to
1152        be written, respectively.  */
1153     size_t nread;
1154     size_t nwrite;
1155 
1156     FILE *fp;
1157 
1158     read_line (&size_string);
1159     if (size_string[0] == 'z')
1160           error (1, 0, "\
1161 protocol error: compressed files not supported for that operation");
1162     /* FIXME: should be doing more error checking, probably.  Like using
1163        strtoul and making sure we used up the whole line.  */
1164     size = atoi (size_string);
1165     free (size_string);
1166 
1167     /* A more sophisticated implementation would use only a limited amount
1168        of buffer space (8K perhaps), and read that much at a time.  We allocate
1169        a buffer for the whole file only to make it easy to keep track what
1170        needs to be read and written.  */
1171     buf = xmalloc (size);
1172 
1173     /* FIXME-someday: caller should pass in a flag saying whether it
1174        is binary or not.  I haven't carefully looked into whether
1175        CVS/Template files should use local text file conventions or
1176        not.  */
1177     fp = CVS_FOPEN (filename, "wb");
1178     if (!fp)
1179           error (1, errno, "cannot write %s", fullname);
1180     nread = size;
1181     nwrite = 0;
1182     pread = buf;
1183     pwrite = buf;
1184     while (nread > 0 || nwrite > 0)
1185     {
1186           size_t n;
1187 
1188           if (nread > 0)
1189           {
1190               n = try_read_from_server (pread, nread);
1191               nread -= n;
1192               pread += n;
1193               nwrite += n;
1194           }
1195 
1196           if (nwrite > 0)
1197           {
1198               n = fwrite (pwrite, sizeof *pwrite, nwrite, fp);
1199               if (ferror (fp))
1200                     error (1, errno, "cannot write %s", fullname);
1201               nwrite -= n;
1202               pwrite += n;
1203           }
1204     }
1205     free (buf);
1206     if (fclose (fp) < 0)
1207           error (1, errno, "cannot close %s", fullname);
1208 }
1209 
1210 
1211 
1212 /* OK, we want to swallow the "U foo.c" response and then output it only
1213    if we can update the file.  In the future we probably want some more
1214    systematic approach to parsing tagged text, but for now we keep it
1215    ad hoc.  "Why," I hear you cry, "do we not just look at the
1216    Update-existing and Created responses?"  That is an excellent question,
1217    and the answer is roughly conservatism/laziness--I haven't read through
1218    update.c enough to figure out the exact correspondence or lack thereof
1219    between those responses and a "U foo.c" line (note that Merged, from
1220    join_file, can be either "C foo" or "U foo" depending on the context).  */
1221 /* Nonzero if we have seen +updated and not -updated.  */
1222 static int updated_seen;
1223 /* Filename from an "fname" tagged response within +updated/-updated.  */
1224 static char *updated_fname;
1225 
1226 /* This struct is used to hold data when reading the +importmergecmd
1227    and -importmergecmd tags.  We put the variables in a struct only
1228    for namespace issues.  FIXME: As noted above, we need to develop a
1229    more systematic approach.  */
1230 static struct
1231 {
1232     /* Nonzero if we have seen +importmergecmd and not -importmergecmd.  */
1233     int seen;
1234     /* Number of conflicts, from a "conflicts" tagged response.  */
1235     int conflicts;
1236     /* First merge tag, from a "mergetag1" tagged response.  */
1237     char *mergetag1;
1238     /* Second merge tag, from a "mergetag2" tagged response.  */
1239     char *mergetag2;
1240     /* Repository, from a "repository" tagged response.  */
1241     char *repository;
1242 } importmergecmd;
1243 
1244 /* Nonzero if we should arrange to return with a failure exit status.  */
1245 static bool failure_exit;
1246 
1247 
1248 /*
1249  * The time stamp of the last file we registered.
1250  */
1251 static time_t last_register_time;
1252 
1253 
1254 
1255 /*
1256  * The Checksum response gives the checksum for the file transferred
1257  * over by the next Updated, Merged or Patch response.  We just store
1258  * it here, and then check it in update_entries.
1259  */
1260 static int stored_checksum_valid;
1261 static unsigned char stored_checksum[16];
1262 static void
handle_checksum(char * args,size_t len)1263 handle_checksum (char *args, size_t len)
1264 {
1265     char *s;
1266     char buf[3];
1267     int i;
1268 
1269     if (stored_checksum_valid)
1270         error (1, 0, "Checksum received before last one was used");
1271 
1272     s = args;
1273     buf[2] = '\0';
1274     for (i = 0; i < 16; i++)
1275     {
1276         char *bufend;
1277 
1278           buf[0] = *s++;
1279           buf[1] = *s++;
1280           stored_checksum[i] = (char) strtol (buf, &bufend, 16);
1281           if (bufend != buf + 2)
1282               break;
1283     }
1284 
1285     if (i < 16 || *s != '\0')
1286         error (1, 0, "Invalid Checksum response: `%s'", args);
1287 
1288     stored_checksum_valid = 1;
1289 }
1290 
1291 
1292 
1293 /* Mode that we got in a "Mode" response (malloc'd), or NULL if none.  */
1294 static char *stored_mode;
1295 static void
handle_mode(char * args,size_t len)1296 handle_mode (char *args, size_t len)
1297 {
1298     if (stored_mode)
1299           error (1, 0, "protocol error: duplicate Mode");
1300     stored_mode = xstrdup (args);
1301 }
1302 
1303 
1304 
1305 /* Nonzero if time was specified in Mod-time.  */
1306 static int stored_modtime_valid;
1307 /* Time specified in Mod-time.  */
1308 static time_t stored_modtime;
1309 static void
handle_mod_time(char * args,size_t len)1310 handle_mod_time (char *args, size_t len)
1311 {
1312     struct timespec newtime;
1313     if (stored_modtime_valid)
1314           error (0, 0, "protocol error: duplicate Mod-time");
1315     if (get_date (&newtime, args, NULL))
1316     {
1317           /* Truncate nanoseconds.  */
1318           stored_modtime = newtime.tv_sec;
1319           stored_modtime_valid = 1;
1320     }
1321     else
1322           error (0, 0, "protocol error: cannot parse date %s", args);
1323 }
1324 
1325 
1326 
1327 /*
1328  * If we receive a patch, but the patch program fails to apply it, we
1329  * want to request the original file.  We keep a list of files whose
1330  * patches have failed.
1331  */
1332 
1333 char **failed_patches;
1334 int failed_patches_count;
1335 
1336 struct update_entries_data
1337 {
1338     enum {
1339       /*
1340        * We are just getting an Entries line; the local file is
1341        * correct.
1342        */
1343       UPDATE_ENTRIES_CHECKIN,
1344       /* We are getting the file contents as well.  */
1345       UPDATE_ENTRIES_UPDATE,
1346       /*
1347        * We are getting a patch against the existing local file, not
1348        * an entire new file.
1349        */
1350       UPDATE_ENTRIES_PATCH,
1351       /*
1352        * We are getting an RCS change text (diff -n output) against
1353        * the existing local file, not an entire new file.
1354        */
1355       UPDATE_ENTRIES_RCS_DIFF
1356     } contents;
1357 
1358     enum {
1359           /* We are replacing an existing file.  */
1360           UPDATE_ENTRIES_EXISTING,
1361           /* We are creating a new file.  */
1362           UPDATE_ENTRIES_NEW,
1363           /* We don't know whether it is existing or new.  */
1364           UPDATE_ENTRIES_EXISTING_OR_NEW
1365     } existp;
1366 
1367     /*
1368      * String to put in the timestamp field or NULL to use the timestamp
1369      * of the file.
1370      */
1371     char *timestamp;
1372 };
1373 
1374 
1375 
1376 /* Update the Entries line for this file.  */
1377 static void
update_entries(void * data_arg,List * ent_list,const char * short_pathname,const char * filename)1378 update_entries (void *data_arg, List *ent_list, const char *short_pathname,
1379                 const char *filename)
1380 {
1381     char *entries_line;
1382     struct update_entries_data *data = data_arg;
1383 
1384     char *cp;
1385     char *user;
1386     char *vn;
1387     /* Timestamp field.  Always empty according to the protocol.  */
1388     char *ts;
1389     char *options = NULL;
1390     char *tag = NULL;
1391     char *date = NULL;
1392     char *tag_or_date;
1393     char *scratch_entries = NULL;
1394     int bin;
1395 
1396 #ifdef UTIME_EXPECTS_WRITABLE
1397     int change_it_back = 0;
1398 #endif
1399 
1400     read_line (&entries_line);
1401 
1402     /*
1403      * Parse the entries line.
1404      */
1405     scratch_entries = xstrdup (entries_line);
1406 
1407     if (scratch_entries[0] != '/')
1408         error (1, 0, "bad entries line `%s' from server", entries_line);
1409     user = scratch_entries + 1;
1410     if (!(cp = strchr (user, '/')))
1411         error (1, 0, "bad entries line `%s' from server", entries_line);
1412     *cp++ = '\0';
1413     vn = cp;
1414     if (!(cp = strchr (vn, '/')))
1415         error (1, 0, "bad entries line `%s' from server", entries_line);
1416     *cp++ = '\0';
1417 
1418     ts = cp;
1419     if (!(cp = strchr (ts, '/')))
1420         error (1, 0, "bad entries line `%s' from server", entries_line);
1421     *cp++ = '\0';
1422     options = cp;
1423     if (!(cp = strchr (options, '/')))
1424         error (1, 0, "bad entries line `%s' from server", entries_line);
1425     *cp++ = '\0';
1426     tag_or_date = cp;
1427 
1428     /* If a slash ends the tag_or_date, ignore everything after it.  */
1429     cp = strchr (tag_or_date, '/');
1430     if (cp)
1431         *cp = '\0';
1432     if (*tag_or_date == 'T')
1433         tag = tag_or_date + 1;
1434     else if (*tag_or_date == 'D')
1435         date = tag_or_date + 1;
1436 
1437     /* Done parsing the entries line. */
1438 
1439     if (data->contents == UPDATE_ENTRIES_UPDATE
1440           || data->contents == UPDATE_ENTRIES_PATCH
1441           || data->contents == UPDATE_ENTRIES_RCS_DIFF)
1442     {
1443           char *size_string;
1444           char *mode_string;
1445           int size;
1446           char *buf;
1447           char *temp_filename;
1448           int use_gzip;
1449           int patch_failed;
1450 
1451           read_line (&mode_string);
1452 
1453           read_line (&size_string);
1454           if (size_string[0] == 'z')
1455           {
1456               use_gzip = 1;
1457               size = atoi (size_string+1);
1458           }
1459           else
1460           {
1461               use_gzip = 0;
1462               size = atoi (size_string);
1463           }
1464           free (size_string);
1465 
1466           /* Note that checking this separately from writing the file is
1467              a race condition: if the existence or lack thereof of the
1468              file changes between now and the actual calls which
1469              operate on it, we lose.  However (a) there are so many
1470              cases, I'm reluctant to try to fix them all, (b) in some
1471              cases the system might not even have a system call which
1472              does the right thing, and (c) it isn't clear this needs to
1473              work.  */
1474           if (data->existp == UPDATE_ENTRIES_EXISTING
1475               && !isfile (filename))
1476               /* Emit a warning and update the file anyway.  */
1477               error (0, 0, "warning: %s unexpectedly disappeared",
1478                        short_pathname);
1479 
1480           if (data->existp == UPDATE_ENTRIES_NEW
1481               && isfile (filename))
1482           {
1483               /* Emit a warning and refuse to update the file; we don't want
1484                  to clobber a user's file.  */
1485               size_t nread;
1486               size_t toread;
1487 
1488               /* size should be unsigned, but until we get around to fixing
1489                  that, work around it.  */
1490               size_t usize;
1491 
1492               char buf[8192];
1493 
1494               /* This error might be confusing; it isn't really clear to
1495                  the user what to do about it.  Keep in mind that it has
1496                  several causes: (1) something/someone creates the file
1497                  during the time that CVS is running, (2) the repository
1498                  has two files whose names clash for the client because
1499                  of case-insensitivity or similar causes, See 3 for
1500                  additional notes.  (3) a special case of this is that a
1501                  file gets renamed for example from a.c to A.C.  A
1502                  "cvs update" on a case-insensitive client will get this
1503                  error.  In this case and in case 2, the filename
1504                  (short_pathname) printed in the error message will likely _not_
1505                  have the same case as seen by the user in a directory listing.
1506                  (4) the client has a file which the server doesn't know
1507                  about (e.g. "? foo" file), and that name clashes with a file
1508                  the server does know about, (5) classify.c will print the same
1509                  message for other reasons.
1510 
1511                  I hope the above paragraph makes it clear that making this
1512                  clearer is not a one-line fix.  */
1513               error (0, 0, "move away `%s'; it is in the way", short_pathname);
1514               if (updated_fname)
1515               {
1516                     cvs_output ("C ", 0);
1517                     cvs_output (updated_fname, 0);
1518                     cvs_output ("\n", 1);
1519               }
1520               failure_exit = true;
1521 
1522           discard_file_and_return:
1523               /* Now read and discard the file contents.  */
1524               usize = size;
1525               nread = 0;
1526               while (nread < usize)
1527               {
1528                     toread = usize - nread;
1529                     if (toread > sizeof buf)
1530                         toread = sizeof buf;
1531 
1532                     nread += try_read_from_server (buf, toread);
1533                     if (nread == usize)
1534                         break;
1535               }
1536 
1537               free (mode_string);
1538               free (scratch_entries);
1539               free (entries_line);
1540 
1541               /* The Mode, Mod-time, and Checksum responses should not carry
1542                  over to a subsequent Created (or whatever) response, even
1543                  in the error case.  */
1544               if (stored_mode)
1545               {
1546                     free (stored_mode);
1547                     stored_mode = NULL;
1548               }
1549               stored_modtime_valid = 0;
1550               stored_checksum_valid = 0;
1551 
1552               if (updated_fname)
1553               {
1554                     free (updated_fname);
1555                     updated_fname = NULL;
1556               }
1557               return;
1558           }
1559 
1560           temp_filename = xmalloc (strlen (filename) + 80);
1561 #ifdef USE_VMS_FILENAMES
1562         /* A VMS rename of "blah.dat" to "foo" to implies a
1563            destination of "foo.dat" which is unfortinate for CVS */
1564           sprintf (temp_filename, "%s_new_", filename);
1565 #else
1566 #ifdef _POSIX_NO_TRUNC
1567           sprintf (temp_filename, ".new.%.9s", filename);
1568 #else /* _POSIX_NO_TRUNC */
1569           sprintf (temp_filename, ".new.%s", filename);
1570 #endif /* _POSIX_NO_TRUNC */
1571 #endif /* USE_VMS_FILENAMES */
1572 
1573           buf = xmalloc (size);
1574 
1575         /* Some systems, like OS/2 and Windows NT, end lines with CRLF
1576            instead of just LF.  Format translation is done in the C
1577            library I/O funtions.  Here we tell them whether or not to
1578            convert -- if this file is marked "binary" with the RCS -kb
1579            flag, then we don't want to convert, else we do (because
1580            CVS assumes text files by default). */
1581 
1582           if (options)
1583               bin = !strcmp (options, "-kb");
1584           else
1585               bin = 0;
1586 
1587           if (data->contents == UPDATE_ENTRIES_RCS_DIFF)
1588           {
1589               /* This is an RCS change text.  We just hold the change
1590                  text in memory.  */
1591 
1592               if (use_gzip)
1593                     error (1, 0,
1594                            "server error: gzip invalid with RCS change text");
1595 
1596               read_from_server (buf, size);
1597           }
1598           else
1599           {
1600               int fd;
1601 
1602               fd = CVS_OPEN (temp_filename,
1603                                  (O_WRONLY | O_CREAT | O_TRUNC
1604                                   | (bin ? OPEN_BINARY : 0)),
1605                                  0777);
1606 
1607               if (fd < 0)
1608               {
1609                     /* I can see a case for making this a fatal error; for
1610                        a condition like disk full or network unreachable
1611                        (for a file server), carrying on and giving an
1612                        error on each file seems unnecessary.  But if it is
1613                        a permission problem, or some such, then it is
1614                        entirely possible that future files will not have
1615                        the same problem.  */
1616                     error (0, errno, "cannot write %s", short_pathname);
1617                     free (temp_filename);
1618                     free (buf);
1619                     goto discard_file_and_return;
1620               }
1621 
1622               if (size > 0)
1623               {
1624                     read_from_server (buf, size);
1625 
1626                     if (use_gzip)
1627                     {
1628                         if (gunzip_and_write (fd, short_pathname,
1629                                                     (unsigned char *) buf, size))
1630                               error (1, 0, "aborting due to compression error");
1631                     }
1632                     else if (write (fd, buf, size) != size)
1633                         error (1, errno, "writing %s", short_pathname);
1634               }
1635 
1636               if (close (fd) < 0)
1637                     error (1, errno, "writing %s", short_pathname);
1638           }
1639 
1640           /* This is after we have read the file from the net (a change
1641              from previous versions, where the server would send us
1642              "M U foo.c" before Update-existing or whatever), but before
1643              we finish writing the file (arguably a bug).  The timing
1644              affects a user who wants status info about how far we have
1645              gotten, and also affects whether "U foo.c" appears in addition
1646              to various error messages.  */
1647           if (updated_fname)
1648           {
1649               cvs_output ("U ", 0);
1650               cvs_output (updated_fname, 0);
1651               cvs_output ("\n", 1);
1652               free (updated_fname);
1653               updated_fname = 0;
1654           }
1655 
1656           patch_failed = 0;
1657 
1658           if (data->contents == UPDATE_ENTRIES_UPDATE)
1659           {
1660               rename_file (temp_filename, filename);
1661           }
1662           else if (data->contents == UPDATE_ENTRIES_PATCH)
1663           {
1664               /* You might think we could just leave Patched out of
1665                  Valid-responses and not get this response.  However, if
1666                  memory serves, the CVS 1.9 server bases this on -u
1667                  (update-patches), and there is no way for us to send -u
1668                  or not based on whether the server supports "Rcs-diff".
1669 
1670                  Fall back to transmitting entire files.  */
1671               patch_failed = 1;
1672           }
1673           else
1674           {
1675               char *filebuf;
1676               size_t filebufsize;
1677               size_t nread;
1678               char *patchedbuf;
1679               size_t patchedlen;
1680 
1681               /* Handle UPDATE_ENTRIES_RCS_DIFF.  */
1682 
1683               if (!isfile (filename))
1684                   error (1, 0, "patch original file %s does not exist",
1685                            short_pathname);
1686               filebuf = NULL;
1687               filebufsize = 0;
1688               nread = 0;
1689 
1690               get_file (filename, short_pathname, bin ? FOPEN_BINARY_READ : "r",
1691                           &filebuf, &filebufsize, &nread);
1692               /* At this point the contents of the existing file are in
1693                FILEBUF, and the length of the contents is in NREAD.
1694                The contents of the patch from the network are in BUF,
1695                and the length of the patch is in SIZE.  */
1696 
1697               if (! rcs_change_text (short_pathname, filebuf, nread, buf, size,
1698                                            &patchedbuf, &patchedlen))
1699                     patch_failed = 1;
1700               else
1701               {
1702                     if (stored_checksum_valid)
1703                     {
1704                         unsigned char checksum[16];
1705 
1706                         /* We have a checksum.  Check it before writing
1707                            the file out, so that we don't have to read it
1708                            back in again.  */
1709                         md5_buffer (patchedbuf, patchedlen, checksum);
1710                         if (memcmp (checksum, stored_checksum, 16) != 0)
1711                         {
1712                               error (0, 0,
1713 "checksum failure after patch to %s; will refetch",
1714                                      short_pathname);
1715 
1716                               patch_failed = 1;
1717                         }
1718 
1719                         stored_checksum_valid = 0;
1720                     }
1721 
1722                     if (! patch_failed)
1723                     {
1724                         FILE *e;
1725 
1726                         e = xfopen (temp_filename,
1727                                         bin ? FOPEN_BINARY_WRITE : "w");
1728                         if (fwrite (patchedbuf, sizeof *patchedbuf, patchedlen, e)
1729                               != patchedlen)
1730                               error (1, errno, "cannot write %s", temp_filename);
1731                         if (fclose (e) == EOF)
1732                               error (1, errno, "cannot close %s", temp_filename);
1733                         rename_file (temp_filename, filename);
1734                     }
1735 
1736                     free (patchedbuf);
1737               }
1738 
1739               free (filebuf);
1740           }
1741 
1742           free (temp_filename);
1743 
1744           if (stored_checksum_valid && ! patch_failed)
1745           {
1746               FILE *e;
1747               struct md5_ctx context;
1748               unsigned char buf[8192];
1749               unsigned len;
1750               unsigned char checksum[16];
1751 
1752               /*
1753                * Compute the MD5 checksum.  This will normally only be
1754                * used when receiving a patch, so we always compute it
1755                * here on the final file, rather than on the received
1756                * data.
1757                *
1758                * Note that if the file is a text file, we should read it
1759                * here using text mode, so its lines will be terminated the same
1760                * way they were transmitted.
1761                */
1762               e = CVS_FOPEN (filename, "r");
1763               if (!e)
1764                   error (1, errno, "could not open %s", short_pathname);
1765 
1766               md5_init_ctx (&context);
1767               while ((len = fread (buf, 1, sizeof buf, e)) != 0)
1768                     md5_process_bytes (buf, len, &context);
1769               if (ferror (e))
1770                     error (1, errno, "could not read %s", short_pathname);
1771               md5_finish_ctx (&context, checksum);
1772 
1773               fclose (e);
1774 
1775               stored_checksum_valid = 0;
1776 
1777               if (memcmp (checksum, stored_checksum, 16) != 0)
1778               {
1779                   if (data->contents != UPDATE_ENTRIES_PATCH)
1780                         error (1, 0, "checksum failure on %s",
1781                                  short_pathname);
1782 
1783                     error (0, 0,
1784                            "checksum failure after patch to %s; will refetch",
1785                            short_pathname);
1786 
1787                     patch_failed = 1;
1788               }
1789           }
1790 
1791           if (patch_failed)
1792           {
1793               /* Save this file to retrieve later.  */
1794               failed_patches = xnrealloc (failed_patches,
1795                                                   failed_patches_count + 1,
1796                                                   sizeof (char *));
1797               failed_patches[failed_patches_count] = xstrdup (short_pathname);
1798               ++failed_patches_count;
1799 
1800               stored_checksum_valid = 0;
1801 
1802               free (mode_string);
1803               free (buf);
1804               free (scratch_entries);
1805               free (entries_line);
1806 
1807               return;
1808           }
1809 
1810         {
1811               int status = change_mode (filename, mode_string, 1);
1812               if (status != 0)
1813                     error (0, status, "cannot change mode of %s", short_pathname);
1814           }
1815 
1816           free (mode_string);
1817           free (buf);
1818     }
1819 
1820     if (stored_mode)
1821     {
1822           change_mode (filename, stored_mode, 1);
1823           free (stored_mode);
1824           stored_mode = NULL;
1825     }
1826 
1827     if (stored_modtime_valid)
1828     {
1829           struct utimbuf t;
1830 
1831           memset (&t, 0, sizeof (t));
1832           t.modtime = stored_modtime;
1833           (void) time (&t.actime);
1834 
1835 #ifdef UTIME_EXPECTS_WRITABLE
1836           if (!iswritable (filename))
1837           {
1838               xchmod (filename, 1);
1839               change_it_back = 1;
1840           }
1841 #endif  /* UTIME_EXPECTS_WRITABLE  */
1842 
1843           if (utime (filename, &t) < 0)
1844               error (0, errno, "cannot set time on %s", filename);
1845 
1846 #ifdef UTIME_EXPECTS_WRITABLE
1847           if (change_it_back)
1848           {
1849               xchmod (filename, 0);
1850               change_it_back = 0;
1851           }
1852 #endif  /*  UTIME_EXPECTS_WRITABLE  */
1853 
1854           stored_modtime_valid = 0;
1855     }
1856 
1857     /*
1858      * Process the entries line.  Do this after we've written the file,
1859      * since we need the timestamp.
1860      */
1861     if (strcmp (cvs_cmd_name, "export"))
1862     {
1863           char *local_timestamp;
1864           char *file_timestamp;
1865 
1866           (void) time (&last_register_time);
1867 
1868           local_timestamp = data->timestamp;
1869           if (!local_timestamp || ts[0] == '+')
1870               file_timestamp = time_stamp (filename);
1871           else
1872               file_timestamp = NULL;
1873 
1874           /*
1875            * These special version numbers signify that it is not up to
1876            * date.  Create a dummy timestamp which will never compare
1877            * equal to the timestamp of the file.
1878            */
1879           if (vn[0] == '\0' || !strcmp (vn, "0") || vn[0] == '-')
1880               local_timestamp = "dummy timestamp";
1881           else if (!local_timestamp)
1882           {
1883               local_timestamp = file_timestamp;
1884 
1885               /* Checking for cvs_cmd_name of "commit" doesn't seem like
1886                  the cleanest way to handle this, but it seem to roughly
1887                  parallel what the :local: code which calls
1888                  mark_up_to_date ends up amounting to.  Some day, should
1889                  think more about what the Checked-in response means
1890                  vis-a-vis both Entries and Base and clarify
1891                  cvsclient.texi accordingly.  */
1892 
1893               if (!strcmp (cvs_cmd_name, "commit"))
1894                     mark_up_to_date (filename);
1895           }
1896 
1897           Register (ent_list, filename, vn, local_timestamp,
1898                       options, tag, date, ts[0] == '+' ? file_timestamp : NULL);
1899 
1900           if (file_timestamp)
1901               free (file_timestamp);
1902 
1903     }
1904     free (scratch_entries);
1905     free (entries_line);
1906 }
1907 
1908 
1909 
1910 static void
handle_checked_in(char * args,size_t len)1911 handle_checked_in (char *args, size_t len)
1912 {
1913     struct update_entries_data dat;
1914     dat.contents = UPDATE_ENTRIES_CHECKIN;
1915     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
1916     dat.timestamp = NULL;
1917     call_in_directory (args, update_entries, &dat);
1918 }
1919 
1920 
1921 
1922 static void
handle_new_entry(char * args,size_t len)1923 handle_new_entry (char *args, size_t len)
1924 {
1925     struct update_entries_data dat;
1926     dat.contents = UPDATE_ENTRIES_CHECKIN;
1927     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
1928     dat.timestamp = "dummy timestamp from new-entry";
1929     call_in_directory (args, update_entries, &dat);
1930 }
1931 
1932 
1933 
1934 static void
handle_updated(char * args,size_t len)1935 handle_updated (char *args, size_t len)
1936 {
1937     struct update_entries_data dat;
1938     dat.contents = UPDATE_ENTRIES_UPDATE;
1939     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
1940     dat.timestamp = NULL;
1941     call_in_directory (args, update_entries, &dat);
1942 }
1943 
1944 
1945 
1946 static void
handle_created(char * args,size_t len)1947 handle_created (char *args, size_t len)
1948 {
1949     struct update_entries_data dat;
1950     dat.contents = UPDATE_ENTRIES_UPDATE;
1951     dat.existp = UPDATE_ENTRIES_NEW;
1952     dat.timestamp = NULL;
1953     call_in_directory (args, update_entries, &dat);
1954 }
1955 
1956 
1957 
1958 static void
handle_update_existing(char * args,size_t len)1959 handle_update_existing (char *args, size_t len)
1960 {
1961     struct update_entries_data dat;
1962     dat.contents = UPDATE_ENTRIES_UPDATE;
1963     dat.existp = UPDATE_ENTRIES_EXISTING;
1964     dat.timestamp = NULL;
1965     call_in_directory (args, update_entries, &dat);
1966 }
1967 
1968 
1969 
1970 static void
handle_merged(char * args,size_t len)1971 handle_merged (char *args, size_t len)
1972 {
1973     struct update_entries_data dat;
1974     dat.contents = UPDATE_ENTRIES_UPDATE;
1975     /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
1976     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
1977     dat.timestamp = "Result of merge";
1978     call_in_directory (args, update_entries, &dat);
1979 }
1980 
1981 
1982 
1983 static void
handle_patched(char * args,size_t len)1984 handle_patched (char *args, size_t len)
1985 {
1986     struct update_entries_data dat;
1987     dat.contents = UPDATE_ENTRIES_PATCH;
1988     /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
1989     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
1990     dat.timestamp = NULL;
1991     call_in_directory (args, update_entries, &dat);
1992 }
1993 
1994 
1995 
1996 static void
handle_rcs_diff(char * args,size_t len)1997 handle_rcs_diff (char *args, size_t len)
1998 {
1999     struct update_entries_data dat;
2000     dat.contents = UPDATE_ENTRIES_RCS_DIFF;
2001     /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
2002     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
2003     dat.timestamp = NULL;
2004     call_in_directory (args, update_entries, &dat);
2005 }
2006 
2007 
2008 
2009 static void
remove_entry(void * data,List * ent_list,const char * short_pathname,const char * filename)2010 remove_entry (void *data, List *ent_list, const char *short_pathname,
2011               const char *filename)
2012 {
2013     Scratch_Entry (ent_list, filename);
2014 }
2015 
2016 
2017 
2018 static void
handle_remove_entry(char * args,size_t len)2019 handle_remove_entry (char *args, size_t len)
2020 {
2021     call_in_directory (args, remove_entry, NULL);
2022 }
2023 
2024 
2025 
2026 static void
remove_entry_and_file(void * data,List * ent_list,const char * short_pathname,const char * filename)2027 remove_entry_and_file (void *data, List *ent_list, const char *short_pathname,
2028                        const char *filename)
2029 {
2030     Scratch_Entry (ent_list, filename);
2031     /* Note that we don't ignore existence_error's here.  The server
2032        should be sending Remove-entry rather than Removed in cases
2033        where the file does not exist.  And if the user removes the
2034        file halfway through a cvs command, we should be printing an
2035        error.  */
2036     if (unlink_file (filename) < 0)
2037           error (0, errno, "unable to remove %s", short_pathname);
2038 }
2039 
2040 
2041 
2042 static void
handle_removed(char * args,size_t len)2043 handle_removed (char *args, size_t len)
2044 {
2045     call_in_directory (args, remove_entry_and_file, NULL);
2046 }
2047 
2048 
2049 
2050 /* Is this the top level (directory containing CVSROOT)?  */
2051 static int
is_cvsroot_level(char * pathname)2052 is_cvsroot_level (char *pathname)
2053 {
2054     if (strcmp (toplevel_repos, current_parsed_root->directory))
2055           return 0;
2056 
2057     return !strchr (pathname, '/');
2058 }
2059 
2060 
2061 
2062 static void
set_static(void * data,List * ent_list,const char * short_pathname,const char * filename)2063 set_static (void *data, List *ent_list, const char *short_pathname,
2064               const char *filename)
2065 {
2066     FILE *fp;
2067     fp = xfopen (CVSADM_ENTSTAT, "w+");
2068     if (fclose (fp) == EOF)
2069         error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
2070 }
2071 
2072 
2073 
2074 static void
handle_set_static_directory(char * args,size_t len)2075 handle_set_static_directory (char *args, size_t len)
2076 {
2077     if (!strcmp (cvs_cmd_name, "export"))
2078     {
2079           /* Swallow the repository.  */
2080           read_line (NULL);
2081           return;
2082     }
2083     call_in_directory (args, set_static, NULL);
2084 }
2085 
2086 
2087 
2088 static void
clear_static(void * data,List * ent_list,const char * short_pathname,const char * filename)2089 clear_static (void *data, List *ent_list, const char *short_pathname,
2090               const char *filename)
2091 {
2092     if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
2093         error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
2094 }
2095 
2096 
2097 
2098 static void
handle_clear_static_directory(char * pathname,size_t len)2099 handle_clear_static_directory (char *pathname, size_t len)
2100 {
2101     if (!strcmp (cvs_cmd_name, "export"))
2102     {
2103           /* Swallow the repository.  */
2104           read_line (NULL);
2105           return;
2106     }
2107 
2108     if (is_cvsroot_level (pathname))
2109     {
2110         /*
2111            * Top level (directory containing CVSROOT).  This seems to normally
2112            * lack a CVS directory, so don't try to create files in it.
2113            */
2114           return;
2115     }
2116     call_in_directory (pathname, clear_static, NULL);
2117 }
2118 
2119 
2120 
2121 static void
set_sticky(void * data,List * ent_list,const char * short_pathname,const char * filename)2122 set_sticky (void *data, List *ent_list, const char *short_pathname,
2123               const char *filename)
2124 {
2125     char *tagspec;
2126     FILE *f;
2127 
2128     read_line (&tagspec);
2129 
2130     /* FIXME-update-dir: error messages should include the directory.  */
2131     f = CVS_FOPEN (CVSADM_TAG, "w+");
2132     if (!f)
2133     {
2134           /* Making this non-fatal is a bit of a kludge (see dirs2
2135              in testsuite).  A better solution would be to avoid having
2136              the server tell us about a directory we shouldn't be doing
2137              anything with anyway (e.g. by handling directory
2138              addition/removal better).  */
2139           error (0, errno, "cannot open %s", CVSADM_TAG);
2140           free (tagspec);
2141           return;
2142     }
2143     if (fprintf (f, "%s\n", tagspec) < 0)
2144           error (1, errno, "writing %s", CVSADM_TAG);
2145     if (fclose (f) == EOF)
2146           error (1, errno, "closing %s", CVSADM_TAG);
2147     free (tagspec);
2148 }
2149 
2150 
2151 
2152 static void
handle_set_sticky(char * pathname,size_t len)2153 handle_set_sticky (char *pathname, size_t len)
2154 {
2155     if (!strcmp (cvs_cmd_name, "export"))
2156     {
2157           /* Swallow the repository.  */
2158           read_line (NULL);
2159         /* Swallow the tag line.  */
2160           read_line (NULL);
2161           return;
2162     }
2163     if (is_cvsroot_level (pathname))
2164     {
2165         /*
2166            * Top level (directory containing CVSROOT).  This seems to normally
2167            * lack a CVS directory, so don't try to create files in it.
2168            */
2169 
2170           /* Swallow the repository.  */
2171           read_line (NULL);
2172         /* Swallow the tag line.  */
2173           read_line (NULL);
2174           return;
2175     }
2176 
2177     call_in_directory (pathname, set_sticky, NULL);
2178 }
2179 
2180 
2181 
2182 static void
clear_sticky(void * data,List * ent_list,const char * short_pathname,const char * filename)2183 clear_sticky (void *data, List *ent_list, const char *short_pathname,
2184               const char *filename)
2185 {
2186     if (unlink_file (CVSADM_TAG) < 0 && ! existence_error (errno))
2187           error (1, errno, "cannot remove %s", CVSADM_TAG);
2188 }
2189 
2190 
2191 
2192 static void
handle_clear_sticky(char * pathname,size_t len)2193 handle_clear_sticky (char *pathname, size_t len)
2194 {
2195     if (!strcmp (cvs_cmd_name, "export"))
2196     {
2197           /* Swallow the repository.  */
2198           read_line (NULL);
2199           return;
2200     }
2201 
2202     if (is_cvsroot_level (pathname))
2203     {
2204         /*
2205            * Top level (directory containing CVSROOT).  This seems to normally
2206            * lack a CVS directory, so don't try to create files in it.
2207            */
2208           return;
2209     }
2210 
2211     call_in_directory (pathname, clear_sticky, NULL);
2212 }
2213 
2214 
2215 
2216 /* Handle the client-side support for a successful edit.
2217  */
2218 static void
handle_edit_file(char * pathname,size_t len)2219 handle_edit_file (char *pathname, size_t len)
2220 {
2221     call_in_directory (pathname, edit_file, NULL);
2222 }
2223 
2224 
2225 
2226 static void
template(void * data,List * ent_list,const char * short_pathname,const char * filename)2227 template (void *data, List *ent_list, const char *short_pathname,
2228             const char *filename)
2229 {
2230     char *buf = Xasprintf ("%s/%s", short_pathname, CVSADM_TEMPLATE);
2231     read_counted_file (CVSADM_TEMPLATE, buf);
2232     free (buf);
2233 }
2234 
2235 
2236 
2237 static void
handle_template(char * pathname,size_t len)2238 handle_template (char *pathname, size_t len)
2239 {
2240     call_in_directory (pathname, template, NULL);
2241 }
2242 
2243 
2244 
2245 static void
clear_template(void * data,List * ent_list,const char * short_pathname,const char * filename)2246 clear_template (void *data, List *ent_list, const char *short_pathname,
2247                 const char *filename)
2248 {
2249     if (unlink_file (CVSADM_TEMPLATE) < 0 && ! existence_error (errno))
2250           error (1, errno, "cannot remove %s", CVSADM_TEMPLATE);
2251 }
2252 
2253 
2254 
2255 static void
handle_clear_template(char * pathname,size_t len)2256 handle_clear_template (char *pathname, size_t len)
2257 {
2258     call_in_directory (pathname, clear_template, NULL);
2259 }
2260 
2261 
2262 
2263 struct save_dir {
2264     char *dir;
2265     struct save_dir *next;
2266 };
2267 
2268 struct save_dir *prune_candidates;
2269 
2270 static void
add_prune_candidate(const char * dir)2271 add_prune_candidate (const char *dir)
2272 {
2273     struct save_dir *p;
2274 
2275     if ((dir[0] == '.' && dir[1] == '\0')
2276           || (prune_candidates && !strcmp (dir, prune_candidates->dir)))
2277           return;
2278     p = xmalloc (sizeof (struct save_dir));
2279     p->dir = xstrdup (dir);
2280     p->next = prune_candidates;
2281     prune_candidates = p;
2282 }
2283 
2284 
2285 
2286 static void
process_prune_candidates(void)2287 process_prune_candidates (void)
2288 {
2289     struct save_dir *p;
2290     struct save_dir *q;
2291 
2292     processing = "prune";
2293     if (toplevel_wd)
2294     {
2295           if (CVS_CHDIR (toplevel_wd) < 0)
2296               error (1, errno, "could not chdir to %s", toplevel_wd);
2297     }
2298     for (p = prune_candidates; p; )
2299     {
2300           if (isemptydir (p->dir, 1))
2301           {
2302               char *b;
2303 
2304               if (unlink_file_dir (p->dir) < 0)
2305                     error (0, errno, "cannot remove %s", p->dir);
2306               b = strrchr (p->dir, '/');
2307               if (!b)
2308                     Subdir_Deregister (NULL, NULL, p->dir);
2309               else
2310               {
2311                     *b = '\0';
2312                     Subdir_Deregister (NULL, p->dir, b + 1);
2313               }
2314           }
2315           free (p->dir);
2316           q = p->next;
2317           free (p);
2318           p = q;
2319     }
2320     prune_candidates = NULL;
2321 }
2322 
2323 
2324 
2325 /* Send a Repository line.  */
2326 static char *last_repos;
2327 static char *last_update_dir;
2328 static void
send_repository(const char * dir,const char * repos,const char * update_dir)2329 send_repository (const char *dir, const char *repos, const char *update_dir)
2330 {
2331     char *adm_name;
2332 
2333     /* FIXME: this is probably not the best place to check; I wish I
2334      * knew where in here's callers to really trap this bug.  To
2335      * reproduce the bug, just do this:
2336      *
2337      *       mkdir junk
2338      *       cd junk
2339      *       cvs -d some_repos update foo
2340      *
2341      * Poof, CVS seg faults and dies!  It's because it's trying to
2342      * send a NULL string to the server but dies in send_to_server.
2343      * That string was supposed to be the repository, but it doesn't
2344      * get set because there's no CVSADM dir, and somehow it's not
2345      * getting set from the -d argument either... ?
2346      */
2347     if (!repos)
2348     {
2349         /* Lame error.  I want a real fix but can't stay up to track
2350            this down right now. */
2351         error (1, 0, "no repository");
2352     }
2353 
2354     if (!update_dir || update_dir[0] == '\0')
2355           update_dir = ".";
2356 
2357     if (last_repos && !strcmp (repos, last_repos)
2358           && last_update_dir && !strcmp (update_dir, last_update_dir))
2359           /* We've already sent it.  */
2360           return;
2361 
2362     if (client_prune_dirs)
2363           add_prune_candidate (update_dir);
2364 
2365     /* Add a directory name to the list of those sent to the
2366        server. */
2367     if (update_dir && *update_dir != '\0' && strcmp (update_dir, ".")
2368           && !findnode (dirs_sent_to_server, update_dir))
2369     {
2370           Node *n;
2371           n = getnode ();
2372           n->type = NT_UNKNOWN;
2373           n->key = xstrdup (update_dir);
2374           n->data = NULL;
2375 
2376           if (addnode (dirs_sent_to_server, n))
2377               error (1, 0, "cannot add directory %s to list", n->key);
2378     }
2379 
2380     /* 80 is large enough for any of CVSADM_*.  */
2381     adm_name = xmalloc (strlen (dir) + 80);
2382 
2383     send_to_server ("Directory ", 0);
2384     {
2385           /* Send the directory name.  I know that this
2386              sort of duplicates code elsewhere, but each
2387              case seems slightly different...  */
2388           char buf[1];
2389           const char *p = update_dir;
2390           while (*p != '\0')
2391           {
2392               assert (*p != '\012');
2393               if (ISSLASH (*p))
2394               {
2395                     buf[0] = '/';
2396                     send_to_server (buf, 1);
2397               }
2398               else
2399               {
2400                     buf[0] = *p;
2401                     send_to_server (buf, 1);
2402               }
2403               ++p;
2404           }
2405     }
2406     send_to_server ("\012", 1);
2407     if (supported_request ("Relative-directory"))
2408     {
2409           const char *short_repos = Short_Repository (repos);
2410           send_to_server (short_repos, 0);
2411     }
2412     else
2413           send_to_server (repos, 0);
2414     send_to_server ("\012", 1);
2415 
2416     if (supported_request ("Static-directory"))
2417     {
2418           adm_name[0] = '\0';
2419           if (dir[0] != '\0')
2420           {
2421               strcat (adm_name, dir);
2422               strcat (adm_name, "/");
2423           }
2424           strcat (adm_name, CVSADM_ENTSTAT);
2425           if (isreadable (adm_name))
2426           {
2427               send_to_server ("Static-directory\012", 0);
2428           }
2429     }
2430     if (supported_request ("Sticky"))
2431     {
2432           FILE *f;
2433           if (dir[0] == '\0')
2434               strcpy (adm_name, CVSADM_TAG);
2435           else
2436               sprintf (adm_name, "%s/%s", dir, CVSADM_TAG);
2437 
2438           f = CVS_FOPEN (adm_name, "r");
2439           if (!f)
2440           {
2441               if (! existence_error (errno))
2442                     error (1, errno, "reading %s", adm_name);
2443           }
2444           else
2445           {
2446               char line[80];
2447               char *nl = NULL;
2448               send_to_server ("Sticky ", 0);
2449               while (fgets (line, sizeof (line), f))
2450               {
2451                     send_to_server (line, 0);
2452                     nl = strchr (line, '\n');
2453                     if (nl)
2454                         break;
2455               }
2456               if (!nl)
2457                 send_to_server ("\012", 1);
2458               if (fclose (f) == EOF)
2459                     error (0, errno, "closing %s", adm_name);
2460           }
2461     }
2462     free (adm_name);
2463     if (last_repos) free (last_repos);
2464     if (last_update_dir) free (last_update_dir);
2465     last_repos = xstrdup (repos);
2466     last_update_dir = xstrdup (update_dir);
2467 }
2468 
2469 
2470 
2471 /* Send a Repository line and set toplevel_repos.  */
2472 void
send_a_repository(const char * dir,const char * repository,const char * update_dir_in)2473 send_a_repository (const char *dir, const char *repository,
2474                    const char *update_dir_in)
2475 {
2476     char *update_dir = xstrdup (update_dir_in);
2477 
2478     if (!toplevel_repos && repository)
2479     {
2480           if (update_dir[0] == '\0'
2481               || (update_dir[0] == '.' && update_dir[1] == '\0'))
2482               toplevel_repos = xstrdup (repository);
2483           else
2484           {
2485               /*
2486                * Get the repository from a CVS/Repository file if update_dir
2487                * is absolute.  This is not correct in general, because
2488                * the CVS/Repository file might not be the top-level one.
2489                * This is for cases like "cvs update /foo/bar" (I'm not
2490                * sure it matters what toplevel_repos we get, but it does
2491                * matter that we don't hit the "internal error" code below).
2492                */
2493               if (update_dir[0] == '/')
2494                     toplevel_repos = Name_Repository (update_dir, update_dir);
2495               else
2496               {
2497                     /*
2498                      * Guess the repository of that directory by looking at a
2499                      * subdirectory and removing as many pathname components
2500                      * as are in update_dir.  I think that will always (or at
2501                      * least almost always) be 1.
2502                      *
2503                      * So this deals with directories which have been
2504                      * renamed, though it doesn't necessarily deal with
2505                      * directories which have been put inside other
2506                      * directories (and cvs invoked on the containing
2507                      * directory).  I'm not sure the latter case needs to
2508                      * work.
2509                      *
2510                      * 21 Aug 1998: Well, Mr. Above-Comment-Writer, it
2511                      * does need to work after all.  When we are using the
2512                      * client in a multi-cvsroot environment, it will be
2513                      * fairly common that we have the above case (e.g.,
2514                      * cwd checked out from one repository but
2515                      * subdirectory checked out from another).  We can't
2516                      * assume that by walking up a directory in our wd we
2517                      * necessarily walk up a directory in the repository.
2518                      */
2519                     /*
2520                      * This gets toplevel_repos wrong for "cvs update ../foo"
2521                      * but I'm not sure toplevel_repos matters in that case.
2522                      */
2523 
2524                     int repository_len, update_dir_len;
2525 
2526                     strip_trailing_slashes (update_dir);
2527 
2528                     repository_len = strlen (repository);
2529                     update_dir_len = strlen (update_dir);
2530 
2531                     /* Try to remove the path components in UPDATE_DIR
2532                    from REPOSITORY.  If the path elements don't exist
2533                    in REPOSITORY, or the removal of those path
2534                    elements mean that we "step above"
2535                    current_parsed_root->directory, set toplevel_repos to
2536                    current_parsed_root->directory. */
2537                     if (repository_len > update_dir_len
2538                         && !strcmp (repository + repository_len - update_dir_len,
2539                                         update_dir)
2540                         /* TOPLEVEL_REPOS shouldn't be above current_parsed_root->directory */
2541                         && ((size_t)(repository_len - update_dir_len)
2542                               > strlen (current_parsed_root->directory)))
2543                     {
2544                         /* The repository name contains UPDATE_DIR.  Set
2545                        toplevel_repos to the repository name without
2546                        UPDATE_DIR. */
2547 
2548                         toplevel_repos = xmalloc (repository_len - update_dir_len);
2549                         /* Note that we don't copy the trailing '/'.  */
2550                         strncpy (toplevel_repos, repository,
2551                                    repository_len - update_dir_len - 1);
2552                         toplevel_repos[repository_len - update_dir_len - 1] = '\0';
2553                     }
2554                     else
2555                     {
2556                         toplevel_repos = xstrdup (current_parsed_root->directory);
2557                     }
2558               }
2559           }
2560     }
2561 
2562     send_repository (dir, repository, update_dir);
2563     free (update_dir);
2564 }
2565 
2566 
2567 
2568 static void
notified_a_file(void * data,List * ent_list,const char * short_pathname,const char * filename)2569 notified_a_file (void *data, List *ent_list, const char *short_pathname,
2570                  const char *filename)
2571 {
2572     FILE *fp;
2573     FILE *newf;
2574     size_t line_len = 8192;
2575     char *line = xmalloc (line_len);
2576     char *cp;
2577     int nread;
2578     int nwritten;
2579     char *p;
2580 
2581     fp = xfopen (CVSADM_NOTIFY, "r");
2582     if (getline (&line, &line_len, fp) < 0)
2583     {
2584           if (feof (fp))
2585               error (0, 0, "cannot read %s: end of file", CVSADM_NOTIFY);
2586           else
2587               error (0, errno, "cannot read %s", CVSADM_NOTIFY);
2588           goto error_exit;
2589     }
2590     cp = strchr (line, '\t');
2591     if (!cp)
2592     {
2593           error (0, 0, "malformed %s file", CVSADM_NOTIFY);
2594           goto error_exit;
2595     }
2596     *cp = '\0';
2597     if (strcmp (filename, line + 1))
2598           error (0, 0, "protocol error: notified %s, expected %s", filename,
2599                  line + 1);
2600 
2601     if (getline (&line, &line_len, fp) < 0)
2602     {
2603           if (feof (fp))
2604           {
2605               free (line);
2606               if (fclose (fp) < 0)
2607                     error (0, errno, "cannot close %s", CVSADM_NOTIFY);
2608               if ( CVS_UNLINK (CVSADM_NOTIFY) < 0)
2609                     error (0, errno, "cannot remove %s", CVSADM_NOTIFY);
2610               return;
2611           }
2612           else
2613           {
2614               error (0, errno, "cannot read %s", CVSADM_NOTIFY);
2615               goto error_exit;
2616           }
2617     }
2618     newf = xfopen (CVSADM_NOTIFYTMP, "w");
2619     if (fputs (line, newf) < 0)
2620     {
2621           error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP);
2622           goto error2;
2623     }
2624     while ((nread = fread (line, 1, line_len, fp)) > 0)
2625     {
2626           p = line;
2627           while ((nwritten = fwrite (p, sizeof *p, nread, newf)) > 0)
2628           {
2629               nread -= nwritten;
2630               p += nwritten;
2631           }
2632           if (ferror (newf))
2633           {
2634               error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP);
2635               goto error2;
2636           }
2637     }
2638     if (ferror (fp))
2639     {
2640           error (0, errno, "cannot read %s", CVSADM_NOTIFY);
2641           goto error2;
2642     }
2643     if (fclose (newf) < 0)
2644     {
2645           error (0, errno, "cannot close %s", CVSADM_NOTIFYTMP);
2646           goto error_exit;
2647     }
2648     free (line);
2649     if (fclose (fp) < 0)
2650     {
2651           error (0, errno, "cannot close %s", CVSADM_NOTIFY);
2652           return;
2653     }
2654 
2655     {
2656         /* In this case, we want rename_file() to ignore noexec. */
2657         int saved_noexec = noexec;
2658         noexec = 0;
2659         rename_file (CVSADM_NOTIFYTMP, CVSADM_NOTIFY);
2660         noexec = saved_noexec;
2661     }
2662 
2663     return;
2664   error2:
2665     (void)fclose (newf);
2666   error_exit:
2667     free (line);
2668     (void)fclose (fp);
2669 }
2670 
2671 
2672 
2673 static void
handle_notified(char * args,size_t len)2674 handle_notified (char *args, size_t len)
2675 {
2676     call_in_directory (args, notified_a_file, NULL);
2677 }
2678 
2679 
2680 
2681 /* The "expanded" modules.  */
2682 static int modules_count;
2683 static int modules_allocated;
2684 static char **modules_vector;
2685 
2686 static void
handle_module_expansion(char * args,size_t len)2687 handle_module_expansion (char *args, size_t len)
2688 {
2689     if (!modules_vector)
2690     {
2691           modules_allocated = 1; /* Small for testing */
2692           modules_vector = xnmalloc (modules_allocated,
2693                                            sizeof (modules_vector[0]));
2694     }
2695     else if (modules_count >= modules_allocated)
2696     {
2697           modules_allocated *= 2;
2698           modules_vector = xnrealloc (modules_vector,
2699                                             modules_allocated,
2700                                             sizeof (modules_vector[0]));
2701     }
2702     modules_vector[modules_count] = xstrdup (args);
2703     ++modules_count;
2704 }
2705 
2706 
2707 
2708 /* Original, not "expanded" modules.  */
2709 static int module_argc;
2710 static char **module_argv;
2711 
2712 void
client_expand_modules(int argc,char ** argv,int local)2713 client_expand_modules (int argc, char **argv, int local)
2714 {
2715     int errs;
2716     int i;
2717 
2718     module_argc = argc;
2719     module_argv = xnmalloc (argc + 1, sizeof (module_argv[0]));
2720     for (i = 0; i < argc; ++i)
2721           module_argv[i] = xstrdup (argv[i]);
2722     module_argv[argc] = NULL;
2723 
2724     for (i = 0; i < argc; ++i)
2725           send_arg (argv[i]);
2726     send_a_repository ("", current_parsed_root->directory, "");
2727 
2728     send_to_server ("expand-modules\012", 0);
2729 
2730     errs = get_server_responses ();
2731 
2732     if (last_repos) free (last_repos);
2733     last_repos = NULL;
2734 
2735     if (last_update_dir) free (last_update_dir);
2736     last_update_dir = NULL;
2737 
2738     if (errs)
2739           error (errs, 0, "cannot expand modules");
2740 }
2741 
2742 
2743 
2744 void
client_send_expansions(int local,char * where,int build_dirs)2745 client_send_expansions (int local, char *where, int build_dirs)
2746 {
2747     int i;
2748     char *argv[1];
2749 
2750     /* Send the original module names.  The "expanded" module name might
2751        not be suitable as an argument to a co request (e.g. it might be
2752        the result of a -d argument in the modules file).  It might be
2753        cleaner if we genuinely expanded module names, all the way to a
2754        local directory and repository, but that isn't the way it works
2755        now.  */
2756     send_file_names (module_argc, module_argv, 0);
2757 
2758     for (i = 0; i < modules_count; ++i)
2759     {
2760           argv[0] = where ? where : modules_vector[i];
2761           if (isfile (argv[0]))
2762               send_files (1, argv, local, 0, build_dirs ? SEND_BUILD_DIRS : 0);
2763     }
2764     send_a_repository ("", current_parsed_root->directory, "");
2765 }
2766 
2767 
2768 
2769 void
client_nonexpanded_setup(void)2770 client_nonexpanded_setup (void)
2771 {
2772     send_a_repository ("", current_parsed_root->directory, "");
2773 }
2774 
2775 
2776 
2777 /* Receive a cvswrappers line from the server; it must be a line
2778    containing an RCS option (e.g., "*.exe   -k 'b'").
2779 
2780    Note that this doesn't try to handle -t/-f options (which are a
2781    whole separate issue which noone has thought much about, as far
2782    as I know).
2783 
2784    We need to know the keyword expansion mode so we know whether to
2785    read the file in text or binary mode.  */
2786 static void
handle_wrapper_rcs_option(char * args,size_t len)2787 handle_wrapper_rcs_option (char *args, size_t len)
2788 {
2789     char *p;
2790 
2791     /* Enforce the notes in cvsclient.texi about how the response is not
2792        as free-form as it looks.  */
2793     p = strchr (args, ' ');
2794     if (!p)
2795           goto handle_error;
2796     if (*++p != '-'
2797           || *++p != 'k'
2798           || *++p != ' '
2799           || *++p != '\'')
2800           goto handle_error;
2801     if (!strchr (p, '\''))
2802           goto handle_error;
2803 
2804     /* Add server-side cvswrappers line to our wrapper list. */
2805     wrap_add (args, 0);
2806     return;
2807  handle_error:
2808     error (0, errno, "protocol error: ignoring invalid wrappers %s", args);
2809 }
2810 
2811 
2812 
2813 
2814 static void
handle_m(char * args,size_t len)2815 handle_m (char *args, size_t len)
2816 {
2817     /* In the case where stdout and stderr point to the same place,
2818        fflushing stderr will make output happen in the correct order.
2819        Often stderr will be line-buffered and this won't be needed,
2820        but not always (is that true?  I think the comment is probably
2821        based on being confused between default buffering between
2822        stdout and stderr.  But I'm not sure).  */
2823     fflush (stderr);
2824     fwrite (args, sizeof *args, len, stdout);
2825     putc ('\n', stdout);
2826 }
2827 
2828 
2829 
2830 static void
handle_mbinary(char * args,size_t len)2831 handle_mbinary (char *args, size_t len)
2832 {
2833     char *size_string;
2834     size_t size;
2835     size_t totalread;
2836     size_t nread;
2837     size_t toread;
2838     char buf[8192];
2839 
2840     /* See comment at handle_m about (non)flush of stderr.  */
2841 
2842     /* Get the size.  */
2843     read_line (&size_string);
2844     size = atoi (size_string);
2845     free (size_string);
2846 
2847     /* OK, now get all the data.  The algorithm here is that we read
2848        as much as the network wants to give us in
2849        try_read_from_server, and then we output it all, and then
2850        repeat, until we get all the data.  */
2851     totalread = 0;
2852     while (totalread < size)
2853     {
2854           toread = size - totalread;
2855           if (toread > sizeof buf)
2856               toread = sizeof buf;
2857 
2858           nread = try_read_from_server (buf, toread);
2859           cvs_output_binary (buf, nread);
2860           totalread += nread;
2861     }
2862 }
2863 
2864 
2865 
2866 static void
handle_e(char * args,size_t len)2867 handle_e (char *args, size_t len)
2868 {
2869     /* In the case where stdout and stderr point to the same place,
2870        fflushing stdout will make output happen in the correct order.  */
2871     fflush (stdout);
2872     fwrite (args, sizeof *args, len, stderr);
2873     putc ('\n', stderr);
2874 }
2875 
2876 
2877 
2878 /*ARGSUSED*/
2879 static void
handle_f(char * args,size_t len)2880 handle_f  (char *args, size_t len)
2881 {
2882     fflush (stderr);
2883 }
2884 
2885 
2886 
2887 static void
handle_mt(char * args,size_t len)2888 handle_mt (char *args, size_t len)
2889 {
2890     char *p;
2891     char *tag = args;
2892     char *text;
2893 
2894     /* See comment at handle_m for more details.  */
2895     fflush (stderr);
2896 
2897     p = strchr (args, ' ');
2898     if (!p)
2899           text = NULL;
2900     else
2901     {
2902           *p++ = '\0';
2903           text = p;
2904     }
2905 
2906     switch (tag[0])
2907     {
2908           case '+':
2909               if (!strcmp (tag, "+updated"))
2910                     updated_seen = 1;
2911               else if (!strcmp (tag, "+importmergecmd"))
2912                     importmergecmd.seen = 1;
2913               break;
2914           case '-':
2915               if (!strcmp (tag, "-updated"))
2916                     updated_seen = 0;
2917               else if (!strcmp (tag, "-importmergecmd"))
2918               {
2919                     char buf[80];
2920 
2921                     /* Now that we have gathered the information, we can
2922                    output the suggested merge command.  */
2923 
2924                     if (importmergecmd.conflicts == 0
2925                         || !importmergecmd.mergetag1
2926                         || !importmergecmd.mergetag2
2927                         || !importmergecmd.repository)
2928                     {
2929                         error (0, 0,
2930                                  "invalid server: incomplete importmergecmd tags");
2931                         break;
2932                     }
2933 
2934                     if (importmergecmd.conflicts == -1)
2935                         sprintf (buf, "\nNo conflicts created by this import.\n");
2936                     else
2937                         sprintf (buf, "\n%d conflicts created by this import.\n",
2938                                    importmergecmd.conflicts);
2939                     cvs_output (buf, 0);
2940                     cvs_output ("Use the following command to help the merge:\n\n",
2941                                   0);
2942                     cvs_output ("\t", 1);
2943                     cvs_output (program_name, 0);
2944                     if (CVSroot_cmdline)
2945                     {
2946                         cvs_output (" -d ", 0);
2947                         cvs_output (CVSroot_cmdline, 0);
2948                     }
2949                     cvs_output (" checkout -j", 0);
2950                     cvs_output (importmergecmd.mergetag1, 0);
2951                     cvs_output (" -j", 0);
2952                     cvs_output (importmergecmd.mergetag2, 0);
2953                     cvs_output (" ", 1);
2954                     cvs_output (importmergecmd.repository, 0);
2955                     cvs_output ("\n\n", 0);
2956 
2957                     /* Clear the static variables so that everything is
2958                    ready for any subsequent importmergecmd tag.  */
2959                     importmergecmd.conflicts = 0;
2960                     free (importmergecmd.mergetag1);
2961                     importmergecmd.mergetag1 = NULL;
2962                     free (importmergecmd.mergetag2);
2963                     importmergecmd.mergetag2 = NULL;
2964                     free (importmergecmd.repository);
2965                     importmergecmd.repository = NULL;
2966 
2967                     importmergecmd.seen = 0;
2968               }
2969               break;
2970           default:
2971               if (updated_seen)
2972               {
2973                     if (!strcmp (tag, "fname"))
2974                     {
2975                         if (updated_fname)
2976                         {
2977                               /* Output the previous message now.  This can happen
2978                                  if there was no Update-existing or other such
2979                                  response, due to the -n global option.  */
2980                               cvs_output ("U ", 0);
2981                               cvs_output (updated_fname, 0);
2982                               cvs_output ("\n", 1);
2983                               free (updated_fname);
2984                         }
2985                         updated_fname = xstrdup (text);
2986                     }
2987                     /* Swallow all other tags.  Either they are extraneous
2988                        or they reflect future extensions that we can
2989                        safely ignore.  */
2990               }
2991               else if (importmergecmd.seen)
2992               {
2993                     if (!strcmp (tag, "conflicts"))
2994                     {
2995                         if (!strcmp (text, "No"))
2996                               importmergecmd.conflicts = -1;
2997                         else
2998                               importmergecmd.conflicts = atoi (text);
2999                     }
3000                     else if (!strcmp (tag, "mergetag1"))
3001                         importmergecmd.mergetag1 = xstrdup (text);
3002                     else if (!strcmp (tag, "mergetag2"))
3003                         importmergecmd.mergetag2 = xstrdup (text);
3004                     else if (!strcmp (tag, "repository"))
3005                         importmergecmd.repository = xstrdup (text);
3006                     /* Swallow all other tags.  Either they are text for
3007                    which we are going to print our own version when we
3008                    see -importmergecmd, or they are future extensions
3009                    we can safely ignore.  */
3010               }
3011               else if (!strcmp (tag, "newline"))
3012                     printf ("\n");
3013               else if (!strcmp (tag, "date"))
3014               {
3015                     char *date = format_date_alloc (text);
3016                     printf ("%s", date);
3017                     free (date);
3018               }
3019               else if (text)
3020                     printf ("%s", text);
3021     }
3022 }
3023 
3024 
3025 
3026 #endif /* CLIENT_SUPPORT */
3027 #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
3028 
3029 /* This table must be writeable if the server code is included.  */
3030 struct response responses[] =
3031 {
3032 #ifdef CLIENT_SUPPORT
3033 #define RSP_LINE(n, f, t, s) {n, f, t, s}
3034 #else /* ! CLIENT_SUPPORT */
3035 #define RSP_LINE(n, f, t, s) {n, s}
3036 #endif /* CLIENT_SUPPORT */
3037 
3038     RSP_LINE("ok", handle_ok, response_type_ok, rs_essential),
3039     RSP_LINE("error", handle_error, response_type_error, rs_essential),
3040     RSP_LINE("Valid-requests", handle_valid_requests, response_type_normal,
3041        rs_essential),
3042     RSP_LINE("Force-gzip", handle_force_gzip, response_type_normal,
3043        rs_optional),
3044     RSP_LINE("Referrer", handle_referrer, response_type_normal, rs_optional),
3045     RSP_LINE("Redirect", handle_redirect, response_type_redirect, rs_optional),
3046     RSP_LINE("Checked-in", handle_checked_in, response_type_normal,
3047        rs_essential),
3048     RSP_LINE("New-entry", handle_new_entry, response_type_normal, rs_optional),
3049     RSP_LINE("Checksum", handle_checksum, response_type_normal, rs_optional),
3050     RSP_LINE("Copy-file", handle_copy_file, response_type_normal, rs_optional),
3051     RSP_LINE("Updated", handle_updated, response_type_normal, rs_essential),
3052     RSP_LINE("Created", handle_created, response_type_normal, rs_optional),
3053     RSP_LINE("Update-existing", handle_update_existing, response_type_normal,
3054        rs_optional),
3055     RSP_LINE("Merged", handle_merged, response_type_normal, rs_essential),
3056     RSP_LINE("Patched", handle_patched, response_type_normal, rs_optional),
3057     RSP_LINE("Rcs-diff", handle_rcs_diff, response_type_normal, rs_optional),
3058     RSP_LINE("Mode", handle_mode, response_type_normal, rs_optional),
3059     RSP_LINE("Mod-time", handle_mod_time, response_type_normal, rs_optional),
3060     RSP_LINE("Removed", handle_removed, response_type_normal, rs_essential),
3061     RSP_LINE("Remove-entry", handle_remove_entry, response_type_normal,
3062        rs_optional),
3063     RSP_LINE("Set-static-directory", handle_set_static_directory,
3064        response_type_normal,
3065        rs_optional),
3066     RSP_LINE("Clear-static-directory", handle_clear_static_directory,
3067        response_type_normal,
3068        rs_optional),
3069     RSP_LINE("Set-sticky", handle_set_sticky, response_type_normal,
3070        rs_optional),
3071     RSP_LINE("Clear-sticky", handle_clear_sticky, response_type_normal,
3072        rs_optional),
3073     RSP_LINE("Edit-file", handle_edit_file, response_type_normal,
3074        rs_optional),
3075     RSP_LINE("Template", handle_template, response_type_normal,
3076        rs_optional),
3077     RSP_LINE("Clear-template", handle_clear_template, response_type_normal,
3078        rs_optional),
3079     RSP_LINE("Notified", handle_notified, response_type_normal, rs_optional),
3080     RSP_LINE("Module-expansion", handle_module_expansion, response_type_normal,
3081        rs_optional),
3082     RSP_LINE("Wrapper-rcsOption", handle_wrapper_rcs_option,
3083        response_type_normal,
3084        rs_optional),
3085     RSP_LINE("M", handle_m, response_type_normal, rs_essential),
3086     RSP_LINE("Mbinary", handle_mbinary, response_type_normal, rs_optional),
3087     RSP_LINE("E", handle_e, response_type_normal, rs_essential),
3088     RSP_LINE("F", handle_f, response_type_normal, rs_optional),
3089     RSP_LINE("MT", handle_mt, response_type_normal, rs_optional),
3090     /* Possibly should be response_type_error.  */
3091     RSP_LINE(NULL, NULL, response_type_normal, rs_essential)
3092 
3093 #undef RSP_LINE
3094 };
3095 
3096 #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
3097 #ifdef CLIENT_SUPPORT
3098 
3099 
3100 
3101 /*
3102  * If LEN is 0, then send_to_server_via() computes string's length itself.
3103  *
3104  * Therefore, pass the real length when transmitting data that might
3105  * contain 0's.
3106  */
3107 void
send_to_server_via(struct buffer * via_buffer,const char * str,size_t len)3108 send_to_server_via (struct buffer *via_buffer, const char *str, size_t len)
3109 {
3110     static int nbytes;
3111 
3112     if (len == 0)
3113           len = strlen (str);
3114 
3115     buf_output (via_buffer, str, len);
3116 
3117     /* There is no reason not to send data to the server, so do it
3118        whenever we've accumulated enough information in the buffer to
3119        make it worth sending.  */
3120     nbytes += len;
3121     if (nbytes >= 2 * BUFFER_DATA_SIZE)
3122     {
3123           int status;
3124 
3125         status = buf_send_output (via_buffer);
3126           if (status != 0)
3127               error (1, status, "error writing to server");
3128           nbytes = 0;
3129     }
3130 }
3131 
3132 
3133 
3134 void
send_to_server(const char * str,size_t len)3135 send_to_server (const char *str, size_t len)
3136 {
3137   send_to_server_via (global_to_server, str, len);
3138 }
3139 
3140 
3141 
3142 /* Read up to LEN bytes from the server.  Returns actual number of
3143    bytes read, which will always be at least one; blocks if there is
3144    no data available at all.  Gives a fatal error on EOF or error.  */
3145 static size_t
try_read_from_server(char * buf,size_t len)3146 try_read_from_server( char *buf, size_t len )
3147 {
3148     int status;
3149     size_t nread;
3150     char *data;
3151 
3152     status = buf_read_data (global_from_server, len, &data, &nread);
3153     if (status != 0)
3154     {
3155           if (status == -1)
3156               error (1, 0,
3157                        "end of file from server (consult above messages if any)");
3158           else if (status == -2)
3159               error (1, 0, "out of memory");
3160           else
3161               error (1, status, "reading from server");
3162     }
3163 
3164     memcpy (buf, data, nread);
3165 
3166     return nread;
3167 }
3168 
3169 
3170 
3171 /*
3172  * Read LEN bytes from the server or die trying.
3173  */
3174 void
read_from_server(char * buf,size_t len)3175 read_from_server (char *buf, size_t len)
3176 {
3177     size_t red = 0;
3178     while (red < len)
3179     {
3180           red += try_read_from_server (buf + red, len - red);
3181           if (red == len)
3182               break;
3183     }
3184 }
3185 
3186 
3187 
3188 /* Get some server responses and process them.
3189  *
3190  * RETURNS
3191  *   0              Success
3192  *   1              Error
3193  *   2              Redirect
3194  */
3195 int
get_server_responses(void)3196 get_server_responses (void)
3197 {
3198     struct response *rs;
3199     do
3200     {
3201           char *cmd;
3202           size_t len;
3203 
3204           len = read_line (&cmd);
3205           for (rs = responses; rs->name; ++rs)
3206               if (!strncmp (cmd, rs->name, strlen (rs->name)))
3207               {
3208                     size_t cmdlen = strlen (rs->name);
3209                     if (cmd[cmdlen] == '\0')
3210                         ;
3211                     else if (cmd[cmdlen] == ' ')
3212                         ++cmdlen;
3213                     else
3214                         /*
3215                          * The first len characters match, but it's a different
3216                          * response.  e.g. the response is "oklahoma" but we
3217                          * matched "ok".
3218                          */
3219                         continue;
3220                     (*rs->func) (cmd + cmdlen, len - cmdlen);
3221                     break;
3222               }
3223           if (!rs->name)
3224               /* It's OK to print just to the first '\0'.  */
3225               /* We might want to handle control characters and the like
3226                  in some other way other than just sending them to stdout.
3227                  One common reason for this error is if people use :ext:
3228                  with a version of rsh which is doing CRLF translation or
3229                  something, and so the client gets "ok^M" instead of "ok".
3230                  Right now that will tend to print part of this error
3231                  message over the other part of it.  It seems like we could
3232                  do better (either in general, by quoting or omitting all
3233                  control characters, and/or specifically, by detecting the CRLF
3234                  case and printing a specific error message).  */
3235               error (0, 0,
3236                        "warning: unrecognized response `%s' from cvs server",
3237                        cmd);
3238           free (cmd);
3239     } while (rs->type == response_type_normal);
3240 
3241     if (updated_fname)
3242     {
3243           /* Output the previous message now.  This can happen
3244              if there was no Update-existing or other such
3245              response, due to the -n global option.  */
3246           cvs_output ("U ", 0);
3247           cvs_output (updated_fname, 0);
3248           cvs_output ("\n", 1);
3249           free (updated_fname);
3250           updated_fname = NULL;
3251     }
3252 
3253     if (rs->type == response_type_redirect) return 2;
3254     if (rs->type == response_type_error) return 1;
3255     if (failure_exit) return 1;
3256     return 0;
3257 }
3258 
3259 
3260 
3261 static inline void
close_connection_to_server(struct buffer ** to,struct buffer ** from)3262 close_connection_to_server (struct buffer **to, struct buffer **from)
3263 {
3264     int status;
3265 
3266     /* First we shut down GLOBAL_TO_SERVER.  That tells the server that its
3267      * input is finished.  It then shuts down the buffer it is sending to us,
3268      * at which point our shut down of GLOBAL_FROM_SERVER will complete.
3269      */
3270 
3271     TRACE (TRACE_FUNCTION, "close_connection_to_server ()");
3272 
3273     status = buf_shutdown (*to);
3274     if (status != 0)
3275           error (0, status, "shutting down buffer to server");
3276     buf_free (*to);
3277     *to = NULL;
3278 
3279     status = buf_shutdown (*from);
3280     if (status != 0)
3281           error (0, status, "shutting down buffer from server");
3282     buf_free (*from);
3283     *from = NULL;
3284 }
3285 
3286 
3287 
3288 /* Get the responses and then close the connection.  */
3289 
3290 /*
3291  * Flag var; we'll set it in start_server() and not one of its
3292  * callees, such as start_rsh_server().  This means that there might
3293  * be a small window between the starting of the server and the
3294  * setting of this var, but all the code in that window shouldn't care
3295  * because it's busy checking return values to see if the server got
3296  * started successfully anyway.
3297  */
3298 int server_started = 0;
3299 
3300 int
get_responses_and_close(void)3301 get_responses_and_close (void)
3302 {
3303     int errs = get_server_responses ();
3304 
3305     /* The following is necessary when working with multiple cvsroots, at least
3306      * with commit.  It used to be buried nicely in do_deferred_progs() before
3307      * that function was removed.  I suspect it wouldn't be necessary if
3308      * call_in_directory() saved its working directory via save_cwd() before
3309      * changing its directory and restored the saved working directory via
3310      * restore_cwd() before exiting.  Of course, calling CVS_CHDIR only once,
3311      * here, may be more efficient.
3312      */
3313     if (toplevel_wd)
3314     {
3315           if (CVS_CHDIR (toplevel_wd) < 0)
3316               error (1, errno, "could not chdir to %s", toplevel_wd);
3317     }
3318 
3319     if (client_prune_dirs)
3320           process_prune_candidates ();
3321 
3322     close_connection_to_server (&global_to_server, &global_from_server);
3323     server_started = 0;
3324 
3325     /* see if we need to sleep before returning to avoid time-stamp races */
3326     if (last_register_time)
3327           sleep_past (last_register_time);
3328 
3329     return errs;
3330 }
3331 
3332 
3333 
3334 bool
supported_request(const char * name)3335 supported_request (const char *name)
3336 {
3337     struct request *rq;
3338 
3339     for (rq = requests; rq->name; rq++)
3340           if (!strcmp (rq->name, name))
3341               return (rq->flags & RQ_SUPPORTED) != 0;
3342     error (1, 0, "internal error: testing support for unknown request?");
3343     /* NOTREACHED */
3344     return 0;
3345 }
3346 
3347 
3348 
3349 #if defined (AUTH_CLIENT_SUPPORT) || defined (SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI)
3350 
3351 
3352 /* Generic function to do port number lookup tasks.
3353  *
3354  * In order of precedence, will return:
3355  *        getenv (envname), if defined
3356  *        getservbyname (portname), if defined
3357  *        defaultport
3358  */
3359 static int
get_port_number(const char * envname,const char * portname,int defaultport)3360 get_port_number (const char *envname, const char *portname, int defaultport)
3361 {
3362     struct servent *s;
3363     char *port_s;
3364 
3365     if (envname && (port_s = getenv (envname)))
3366     {
3367           int port = atoi (port_s);
3368           if (port <= 0)
3369           {
3370               error (0, 0, "%s must be a positive integer!  If you", envname);
3371               error (0, 0, "are trying to force a connection via rsh, please");
3372               error (0, 0, "put \":server:\" at the beginning of your CVSROOT");
3373               error (1, 0, "variable.");
3374           }
3375           return port;
3376     }
3377     else if (portname && (s = getservbyname (portname, "tcp")))
3378           return ntohs (s->s_port);
3379     else
3380           return defaultport;
3381 }
3382 
3383 
3384 
3385 /* get the port number for a client to connect to based on the port
3386  * and method of a cvsroot_t.
3387  *
3388  * we do this here instead of in parse_cvsroot so that we can keep network
3389  * code confined to a localized area and also to delay the lookup until the
3390  * last possible moment so it remains possible to run cvs client commands that
3391  * skip opening connections to the server (i.e. skip network operations
3392  * entirely)
3393  *
3394  * and yes, I know none of the commands do that now, but here's to planning
3395  * for the future, eh?  cheers.
3396  */
3397 int
get_cvs_port_number(const cvsroot_t * root)3398 get_cvs_port_number (const cvsroot_t *root)
3399 {
3400 
3401     if (root->port) return root->port;
3402 
3403     switch (root->method)
3404     {
3405 # ifdef HAVE_GSSAPI
3406           case gserver_method:
3407 # endif /* HAVE_GSSAPI */
3408 # ifdef AUTH_CLIENT_SUPPORT
3409           case pserver_method:
3410 # endif /* AUTH_CLIENT_SUPPORT */
3411 # if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI)
3412               return get_port_number ("CVS_CLIENT_PORT", "cvspserver",
3413                                     CVS_AUTH_PORT);
3414 # endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) */
3415 # ifdef HAVE_KERBEROS
3416           case kserver_method:
3417               return get_port_number ("CVS_CLIENT_PORT", "cvs", CVS_PORT);
3418 # endif /* HAVE_KERBEROS */
3419           default:
3420               error(1, EINVAL,
3421 "internal error: get_cvs_port_number called for invalid connection method (%s)",
3422                       method_names[root->method]);
3423               break;
3424     }
3425     /* NOTREACHED */
3426     return -1;
3427 }
3428 
3429 
3430 
3431 /* get the port number for a client to connect to based on the proxy port
3432  * of a cvsroot_t.
3433  */
3434 static int
get_proxy_port_number(const cvsroot_t * root)3435 get_proxy_port_number (const cvsroot_t *root)
3436 {
3437 
3438     if (root->proxy_port) return root->proxy_port;
3439 
3440     return get_port_number ("CVS_PROXY_PORT", NULL, CVS_PROXY_PORT);
3441 }
3442 
3443 
3444 
3445 void
make_bufs_from_fds(int tofd,int fromfd,int child_pid,cvsroot_t * root,struct buffer ** to_server_p,struct buffer ** from_server_p,int is_sock)3446 make_bufs_from_fds(int tofd, int fromfd, int child_pid, cvsroot_t *root,
3447                    struct buffer **to_server_p,
3448                    struct buffer **from_server_p, int is_sock)
3449 {
3450 # ifdef NO_SOCKET_TO_FD
3451     if (is_sock)
3452     {
3453           assert (tofd == fromfd);
3454           *to_server_p = socket_buffer_initialize (tofd, 0, NULL);
3455           *from_server_p = socket_buffer_initialize (tofd, 1, NULL);
3456     }
3457     else
3458 # endif /* NO_SOCKET_TO_FD */
3459     {
3460           /* todo: some OS's don't need these calls... */
3461           close_on_exec (tofd);
3462           close_on_exec (fromfd);
3463 
3464           /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes
3465              fdopening the same file descriptor twice, so dup it if it is the
3466              same.  */
3467           if (tofd == fromfd)
3468           {
3469               fromfd = dup (tofd);
3470               if (fromfd < 0)
3471                     error (1, errno, "cannot dup net connection");
3472           }
3473 
3474           /* These will use binary mode on systems which have it.  */
3475           /*
3476            * Also, we know that from_server is shut down second, so we pass
3477            * child_pid in there.  In theory, it should be stored in both
3478            * buffers with a ref count...
3479            */
3480           *to_server_p = fd_buffer_initialize (tofd, 0, root, false, NULL);
3481           *from_server_p = fd_buffer_initialize (fromfd, child_pid, root,
3482                                                true, NULL);
3483     }
3484 }
3485 #endif /* defined (AUTH_CLIENT_SUPPORT) || defined (SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined(HAVE_GSSAPI) */
3486 
3487 
3488 
3489 #if defined (AUTH_CLIENT_SUPPORT) || defined(HAVE_GSSAPI)
3490 /* Connect to the authenticating server.
3491 
3492    If VERIFY_ONLY is non-zero, then just verify that the password is
3493    correct and then shutdown the connection.
3494 
3495    If VERIFY_ONLY is 0, then really connect to the server.
3496 
3497    If DO_GSSAPI is non-zero, then we use GSSAPI authentication rather
3498    than the pserver password authentication.
3499 
3500    If we fail to connect or if access is denied, then die with fatal
3501    error.  */
3502 void
connect_to_pserver(cvsroot_t * root,struct buffer ** to_server_p,struct buffer ** from_server_p,int verify_only,int do_gssapi)3503 connect_to_pserver (cvsroot_t *root, struct buffer **to_server_p,
3504                     struct buffer **from_server_p, int verify_only,
3505                     int do_gssapi)
3506 {
3507     int sock;
3508     int port_number,
3509           proxy_port_number = 0; /* Initialize to silence -Wall.  Dumb.  */
3510     char no_passwd = 0;   /* gets set if no password found */
3511     struct buffer *to_server, *from_server;
3512 
3513     port_number = get_cvs_port_number (root);
3514 
3515     /* if we have a proxy connect to that instead */
3516     if (root->proxy_hostname)
3517     {
3518         TRACE (TRACE_FUNCTION, "Connecting to %s:%d via proxy %s:%d.",
3519                root->hostname, port_number, root->proxy_hostname,
3520                  proxy_port_number);
3521         proxy_port_number = get_proxy_port_number (root);
3522           sock = connect_to(root->proxy_hostname, proxy_port_number);
3523     }
3524     else
3525     {
3526         TRACE (TRACE_FUNCTION, "Connecting to %s:%d.",
3527                root->hostname, port_number);
3528           sock = connect_to(root->hostname, port_number);
3529     }
3530 
3531     if (sock == -1)
3532           error (1, 0, "connect to %s:%d failed: %s",
3533                  root->proxy_hostname ? root->proxy_hostname : root->hostname,
3534                  root->proxy_hostname ? proxy_port_number : port_number,
3535                SOCK_STRERROR (SOCK_ERRNO));
3536 
3537     make_bufs_from_fds (sock, sock, 0, root, &to_server, &from_server, 1);
3538 
3539     /* if we have proxy then connect to the proxy first */
3540     if (root->proxy_hostname)
3541     {
3542 #define CONNECT_STRING "CONNECT %s:%d HTTP/1.0\r\n\r\n"
3543           /* Send a "CONNECT" command to proxy: */
3544           char* read_buf;
3545           int codenum;
3546           size_t count;
3547           /* 4 characters for port covered by the length of %s & %d */
3548           char* write_buf = Xasnprintf (NULL, &count, CONNECT_STRING,
3549                                       root->hostname, port_number);
3550           send_to_server_via (to_server, write_buf, count);
3551 
3552           /* Wait for HTTP status code, bail out if you don't get back a 2xx
3553          * code.
3554          */
3555           read_line_via (from_server, to_server, &read_buf);
3556           count = sscanf (read_buf, "%*s %d", &codenum);
3557 
3558           if (count != 1 || (codenum / 100) != 2)
3559               error (1, 0, "proxy server %s:%d does not support http tunnelling",
3560                        root->proxy_hostname, proxy_port_number);
3561           free (read_buf);
3562           free (write_buf);
3563 
3564           /* Skip through remaining part of MIME header, recv_line
3565            consumes the trailing \n */
3566           while (read_line_via (from_server, to_server, &read_buf) > 0)
3567           {
3568               if (read_buf[0] == '\r' || read_buf[0] == 0)
3569               {
3570                     free (read_buf);
3571                     break;
3572               }
3573               free (read_buf);
3574           }
3575     }
3576 
3577     auth_server (root, to_server, from_server, verify_only, do_gssapi);
3578 
3579     if (verify_only)
3580     {
3581           int status;
3582 
3583           status = buf_shutdown (to_server);
3584           if (status != 0)
3585               error (0, status, "shutting down buffer to server");
3586           buf_free (to_server);
3587           to_server = NULL;
3588 
3589           status = buf_shutdown (from_server);
3590           if (status != 0)
3591               error (0, status, "shutting down buffer from server");
3592           buf_free (from_server);
3593           from_server = NULL;
3594 
3595           /* Don't need to set server_started = 0 since we don't set it to 1
3596            * until returning from this call.
3597            */
3598     }
3599     else
3600     {
3601           *to_server_p = to_server;
3602           *from_server_p = from_server;
3603     }
3604 
3605     return;
3606 }
3607 
3608 
3609 
3610 static void
auth_server(cvsroot_t * root,struct buffer * to_server,struct buffer * from_server,int verify_only,int do_gssapi)3611 auth_server (cvsroot_t *root, struct buffer *to_server,
3612              struct buffer *from_server, int verify_only, int do_gssapi)
3613 {
3614     char *username = NULL;              /* the username we use to connect */
3615     char no_passwd = 0;                           /* gets set if no password found */
3616 
3617     /* Run the authorization mini-protocol before anything else. */
3618     if (do_gssapi)
3619     {
3620 # ifdef HAVE_GSSAPI
3621           int fd = buf_get_fd (to_server);
3622           struct stat s;
3623 
3624           if ((fd < 0) || (fstat (fd, &s) < 0) || !S_ISSOCK(s.st_mode))
3625           {
3626               error (1, 0,
3627                    "gserver currently only enabled for socket connections");
3628           }
3629 
3630           if (! connect_to_gserver (root, fd, root->hostname))
3631           {
3632               error (1, 0,
3633                         "authorization failed: server %s rejected access to %s",
3634                         root->hostname, root->directory);
3635           }
3636 # else /* ! HAVE_GSSAPI */
3637           error (1, 0,
3638 "INTERNAL ERROR: This client does not support GSSAPI authentication");
3639 # endif /* HAVE_GSSAPI */
3640     }
3641     else /* ! do_gssapi */
3642     {
3643 # ifdef AUTH_CLIENT_SUPPORT
3644           char *begin      = NULL;
3645           char *password   = NULL;
3646           char *end        = NULL;
3647 
3648           if (verify_only)
3649           {
3650               begin = "BEGIN VERIFICATION REQUEST";
3651               end   = "END VERIFICATION REQUEST";
3652           }
3653           else
3654           {
3655               begin = "BEGIN AUTH REQUEST";
3656               end   = "END AUTH REQUEST";
3657           }
3658 
3659           /* Get the password, probably from ~/.cvspass. */
3660           password = get_cvs_password ();
3661           username = root->username ? root->username : getcaller();
3662 
3663           /* Send the empty string by default.  This is so anonymous CVS
3664              access doesn't require client to have done "cvs login". */
3665           if (!password)
3666           {
3667               no_passwd = 1;
3668               password = scramble ("");
3669           }
3670 
3671           /* Announce that we're starting the authorization protocol. */
3672           send_to_server_via(to_server, begin, 0);
3673           send_to_server_via(to_server, "\012", 1);
3674 
3675           /* Send the data the server needs. */
3676           send_to_server_via(to_server, root->directory, 0);
3677           send_to_server_via(to_server, "\012", 1);
3678           send_to_server_via(to_server, username, 0);
3679           send_to_server_via(to_server, "\012", 1);
3680           send_to_server_via(to_server, password, 0);
3681           send_to_server_via(to_server, "\012", 1);
3682 
3683           /* Announce that we're ending the authorization protocol. */
3684           send_to_server_via(to_server, end, 0);
3685           send_to_server_via(to_server, "\012", 1);
3686 
3687         /* Paranoia. */
3688         free_cvs_password (password);
3689           password = NULL;
3690 # else /* ! AUTH_CLIENT_SUPPORT */
3691           error (1, 0, "INTERNAL ERROR: This client does not support pserver authentication");
3692 # endif /* AUTH_CLIENT_SUPPORT */
3693     } /* if (do_gssapi) */
3694 
3695     {
3696           char *read_buf;
3697 
3698           /* Loop, getting responses from the server.  */
3699           while (1)
3700           {
3701               read_line_via (from_server, to_server, &read_buf);
3702 
3703               if (!strcmp (read_buf, "I HATE YOU"))
3704               {
3705                     /* Authorization not granted.
3706                      *
3707                      * This is a little confusing since we can reach this while
3708                      * loop in GSSAPI mode, but if GSSAPI authentication failed,
3709                      * we already jumped to the rejected label (there is no case
3710                      * where the connect_to_gserver function can return 1 and we
3711                      * will not receive "I LOVE YOU" from the server, barring
3712                      * broken connections and garbled messages, of course).  The
3713                      * GSSAPI case is also the case where username can be NULL
3714                      * since username is initialized in the !gssapi section.
3715                      *
3716                      * i.e. This is a pserver specific error message and should be
3717                      * since GSSAPI doesn't use username.
3718                      */
3719                     error (0, 0,
3720 "authorization failed: server %s rejected access to %s for user %s",
3721                            root->hostname, root->directory,
3722                            username ? username : "(null)");
3723 
3724                     /* Output a special error message if authentication was attempted
3725                     with no password -- the user should be made aware that they may
3726                     have missed a step. */
3727                     if (no_passwd)
3728                     {
3729                         error (0, 0,
3730 "used empty password; try \"cvs login\" with a real password");
3731                     }
3732                     exit (EXIT_FAILURE);
3733               }
3734               else if (!strncmp (read_buf, "E ", 2))
3735               {
3736                     fprintf (stderr, "%s\n", read_buf + 2);
3737 
3738                     /* Continue with the authentication protocol.  */
3739               }
3740               else if (!strncmp (read_buf, "error ", 6))
3741               {
3742                     char *p;
3743 
3744                     /* First skip the code.  */
3745                     p = read_buf + 6;
3746                     while (*p != ' ' && *p != '\0')
3747                         ++p;
3748 
3749                     /* Skip the space that follows the code.  */
3750                     if (*p == ' ')
3751                         ++p;
3752 
3753                     /* Now output the text.  */
3754                     fprintf (stderr, "%s\n", p);
3755                     exit (EXIT_FAILURE);
3756               }
3757               else if (!strcmp (read_buf, "I LOVE YOU"))
3758               {
3759                     free (read_buf);
3760                     break;
3761               }
3762               else
3763               {
3764                     error (1, 0,
3765                            "unrecognized auth response from %s: %s",
3766                            root->hostname, read_buf);
3767               }
3768               free (read_buf);
3769           }
3770     }
3771 }
3772 #endif /* defined (AUTH_CLIENT_SUPPORT) || defined(HAVE_GSSAPI) */
3773 
3774 
3775 
3776 #if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
3777 /*
3778  * Connect to a forked server process.
3779  */
3780 static void
connect_to_forked_server(cvsroot_t * root,struct buffer ** to_server_p,struct buffer ** from_server_p)3781 connect_to_forked_server (cvsroot_t *root, struct buffer **to_server_p,
3782                           struct buffer **from_server_p)
3783 {
3784     int tofd, fromfd;
3785     int child_pid;
3786 
3787     /* This is pretty simple.  All we need to do is choose the correct
3788        cvs binary and call piped_child. */
3789 
3790      char *command[3];
3791 
3792     command[0] = (root->cvs_server
3793                       ? root->cvs_server : getenv ("CVS_SERVER"));
3794     if (!command[0])
3795 # ifdef SERVER_SUPPORT
3796         /* FIXME:
3797          * I'm casting out the const below because I know that piped_child, the
3798          * only function we pass COMMAND to, accepts COMMAND as a
3799          * (char *const *) and won't alter it, and we don't alter it in this
3800          * function.  This is yucky, there should be a way to declare COMMAND
3801          * such that this casting isn't needed, but I don't know how.  If I
3802          * declare it as (const char *command[]), the compiler complains about
3803          * an incompatible arg 1 being passed to piped_child and if I declare
3804          * it as (char *const command[3]), then the compiler complains when I
3805          * assign values to command[i].
3806          */
3807           command[0] = (char *)program_path;
3808 # else /* SERVER_SUPPORT */
3809     {
3810           error( 0, 0, "You must set the CVS_SERVER environment variable when" );
3811           error( 0, 0, "using the :fork: access method." );
3812           error( 1, 0, "This CVS was not compiled with server support." );
3813     }
3814 # endif /* SERVER_SUPPORT */
3815 
3816     command[1] = "server";
3817     command[2] = NULL;
3818 
3819     TRACE (TRACE_FUNCTION, "Forking server: %s %s",
3820              command[0] ? command[0] : "(null)", command[1]);
3821 
3822     child_pid = piped_child (command, &tofd, &fromfd, false);
3823     if (child_pid < 0)
3824           error (1, 0, "could not fork server process");
3825 
3826     make_bufs_from_fds (tofd, fromfd, child_pid, root, to_server_p,
3827                         from_server_p, 0);
3828 }
3829 #endif /* CLIENT_SUPPORT || SERVER_SUPPORT */
3830 
3831 
3832 
3833 static int
send_variable_proc(Node * node,void * closure)3834 send_variable_proc (Node *node, void *closure)
3835 {
3836     send_to_server ("Set ", 0);
3837     send_to_server (node->key, 0);
3838     send_to_server ("=", 1);
3839     send_to_server (node->data, 0);
3840     send_to_server ("\012", 1);
3841     return 0;
3842 }
3843 
3844 
3845 
3846 /* Open up the connection to the server and perform any necessary
3847  * authentication.
3848  */
3849 void
open_connection_to_server(cvsroot_t * root,struct buffer ** to_server_p,struct buffer ** from_server_p)3850 open_connection_to_server (cvsroot_t *root, struct buffer **to_server_p,
3851                            struct buffer **from_server_p)
3852 {
3853     /* Note that generally speaking we do *not* fall back to a different
3854        way of connecting if the first one does not work.  This is slow
3855        (*really* slow on a 14.4kbps link); the clean way to have a CVS
3856        which supports several ways of connecting is with access methods.  */
3857 
3858     TRACE (TRACE_FUNCTION, "open_connection_to_server (%s)", root->original);
3859 
3860     switch (root->method)
3861     {
3862           case pserver_method:
3863 #ifdef AUTH_CLIENT_SUPPORT
3864               /* Toss the return value.  It will die with an error message if
3865                * anything goes wrong anyway.
3866                */
3867               connect_to_pserver (root, to_server_p, from_server_p, 0, 0);
3868 #else /* AUTH_CLIENT_SUPPORT */
3869               error (0, 0, "CVSROOT is set for a pserver access method but your");
3870               error (1, 0, "CVS executable doesn't support it.");
3871 #endif /* AUTH_CLIENT_SUPPORT */
3872               break;
3873 
3874           case kserver_method:
3875 #if HAVE_KERBEROS
3876               start_kerberos4_server (root, to_server_p,
3877                                     from_server_p);
3878 #else /* !HAVE_KERBEROS */
3879               error (0, 0,
3880                      "CVSROOT is set for a kerberos access method but your");
3881               error (1, 0, "CVS executable doesn't support it.");
3882 #endif /* HAVE_KERBEROS */
3883               break;
3884 
3885           case gserver_method:
3886 #ifdef HAVE_GSSAPI
3887               /* GSSAPI authentication is handled by the pserver.  */
3888               connect_to_pserver (root, to_server_p, from_server_p, 0, 1);
3889 #else /* !HAVE_GSSAPI */
3890               error (0, 0, "CVSROOT is set for a GSSAPI access method but your");
3891               error (1, 0, "CVS executable doesn't support it.");
3892 #endif /* HAVE_GSSAPI */
3893               break;
3894 
3895           case ext_method:
3896 #ifdef NO_EXT_METHOD
3897               error (0, 0, ":ext: method not supported by this port of CVS");
3898               error (1, 0, "try :server: instead");
3899 #else /* ! NO_EXT_METHOD */
3900               start_rsh_server (root, to_server_p,
3901                               from_server_p);
3902 #endif /* NO_EXT_METHOD */
3903               break;
3904 
3905           case server_method:
3906 #ifdef START_SERVER
3907               {
3908               int tofd, fromfd;
3909               START_SERVER (&tofd, &fromfd, getcaller (),
3910                                 root->username,
3911                           root->hostname,
3912                                 root->directory);
3913 # ifdef START_SERVER_RETURNS_SOCKET
3914               make_bufs_from_fds (tofd, fromfd, 0, root, to_server_p,
3915                                 from_server_p, 1);
3916 # else /* ! START_SERVER_RETURNS_SOCKET */
3917               make_bufs_from_fds (tofd, fromfd, 0, root, to_server_p,
3918                                 from_server_p, 0);
3919 # endif /* START_SERVER_RETURNS_SOCKET */
3920               }
3921 #else /* ! START_SERVER */
3922               /* FIXME: It should be possible to implement this portably,
3923                  like pserver, which would get rid of the duplicated code
3924                  in {vms,windows-NT,...}/startserver.c.  */
3925               error (1, 0,
3926 "the :server: access method is not supported by this port of CVS");
3927 #endif /* START_SERVER */
3928               break;
3929 
3930         case fork_method:
3931               connect_to_forked_server (root, to_server_p, from_server_p);
3932               break;
3933 
3934           default:
3935               error (1, 0,
3936                    "(start_server internal error): unknown access method");
3937               break;
3938     }
3939 
3940     /* "Hi, I'm Darlene and I'll be your server tonight..." */
3941     server_started = 1;
3942 }
3943 
3944 
3945 
3946 /* Contact the server.  */
3947 void
start_server(void)3948 start_server (void)
3949 {
3950     bool rootless;
3951     int status;
3952     bool have_global;
3953 
3954     do
3955     {
3956           /* Clear our static variables for this invocation. */
3957           if (toplevel_repos)
3958               free (toplevel_repos);
3959           toplevel_repos = NULL;
3960 
3961           open_connection_to_server (current_parsed_root, &global_to_server,
3962                                            &global_from_server);
3963           setup_logfiles ("CVS_CLIENT_LOG", &global_to_server,
3964                               &global_from_server);
3965 
3966           /* Clear static variables.  */
3967           if (toplevel_repos)
3968           {
3969               free (toplevel_repos);
3970               toplevel_repos = NULL;
3971           }
3972           if (last_repos)
3973           {
3974               free (last_repos);
3975               last_repos = NULL;
3976           }
3977           if (last_update_dir)
3978           {
3979               free (last_update_dir);
3980               last_update_dir = NULL;
3981           }
3982           stored_checksum_valid = 0;
3983           if (stored_mode)
3984           {
3985               free (stored_mode);
3986               stored_mode = NULL;
3987           }
3988 
3989           rootless = !strcmp (cvs_cmd_name, "init");
3990           if (!rootless)
3991           {
3992               send_to_server ("Root ", 0);
3993               send_to_server (current_parsed_root->directory, 0);
3994               send_to_server ("\012", 1);
3995           }
3996 
3997           {
3998               struct response *rs;
3999               bool suppress_redirect = !current_parsed_root->redirect;
4000 
4001               send_to_server ("Valid-responses", 0);
4002 
4003               for (rs = responses; rs->name; ++rs)
4004               {
4005                     if (suppress_redirect && !strcmp (rs->name, "Redirect"))
4006                         continue;
4007 
4008                     send_to_server (" ", 0);
4009                     send_to_server (rs->name, 0);
4010               }
4011               send_to_server ("\012", 1);
4012           }
4013           send_to_server ("valid-requests\012", 0);
4014 
4015           if (get_server_responses ())
4016               exit (EXIT_FAILURE);
4017 
4018           have_global = supported_request ("Global_option");
4019 
4020           /* Encryption needs to come before compression.  Good encryption can
4021            * render compression useless in the other direction.
4022            */
4023           if (cvsencrypt && !rootless)
4024           {
4025 #ifdef ENCRYPTION
4026               /* Turn on encryption before turning on compression.  We do
4027                * not want to try to compress the encrypted stream.  Instead,
4028                * we want to encrypt the compressed stream.  If we can't turn
4029                * on encryption, bomb out; don't let the user think the data
4030                * is being encrypted when it is not.
4031                */
4032 #  ifdef HAVE_KERBEROS
4033               if (current_parsed_root->method == kserver_method)
4034               {
4035                     if (!supported_request ("Kerberos-encrypt"))
4036                         error (1, 0, "This server does not support encryption");
4037                     send_to_server ("Kerberos-encrypt\012", 0);
4038                  initialize_kerberos4_encryption_buffers (&global_to_server,
4039                                                                       &global_from_server);
4040               }
4041               else
4042 #  endif /* HAVE_KERBEROS */
4043 #  ifdef HAVE_GSSAPI
4044               if (current_parsed_root->method == gserver_method)
4045               {
4046                     if (!supported_request ("Gssapi-encrypt"))
4047                         error (1, 0, "This server does not support encryption");
4048                     send_to_server ("Gssapi-encrypt\012", 0);
4049                     initialize_gssapi_buffers (&global_to_server,
4050                                                      &global_from_server);
4051                     cvs_gssapi_encrypt = 1;
4052               }
4053               else
4054 #  endif /* HAVE_GSSAPI */
4055                     error (1, 0,
4056 "Encryption is only supported when using GSSAPI or Kerberos");
4057 #else /* ! ENCRYPTION */
4058               error (1, 0, "This client does not support encryption");
4059 #endif /* ! ENCRYPTION */
4060           }
4061 
4062           if (nolock && !noexec)
4063           {
4064               if (have_global)
4065               {
4066                     send_to_server ("Global_option -u\012", 0);
4067               }
4068               else
4069                     error (1, 0,
4070                            "This server does not support the global -u option.");
4071           }
4072           /* Send this before compression to enable supression of the
4073            * "Forcing compression level Z" messages.
4074            */
4075           if (quiet)
4076           {
4077               if (have_global)
4078               {
4079                     send_to_server ("Global_option -q\012", 0);
4080               }
4081               else
4082                     error (1, 0,
4083                            "This server does not support the global -q option.");
4084           }
4085           if (really_quiet)
4086           {
4087               if (have_global)
4088               {
4089                     send_to_server ("Global_option -Q\012", 0);
4090               }
4091               else
4092                     error (1, 0,
4093                            "This server does not support the global -Q option.");
4094           }
4095 
4096           /* Compression needs to come before any of the rooted requests to
4097            * work with compression limits.
4098            */
4099           if (!rootless && (gzip_level || force_gzip))
4100           {
4101               if (supported_request ("Gzip-stream"))
4102               {
4103                     char *gzip_level_buf = Xasprintf ("%d", gzip_level);
4104                     send_to_server ("Gzip-stream ", 0);
4105                     send_to_server (gzip_level_buf, 0);
4106                     free (gzip_level_buf);
4107                     send_to_server ("\012", 1);
4108 
4109                     /* All further communication with the server will be
4110                        compressed.  */
4111 
4112                     global_to_server =
4113                         compress_buffer_initialize (global_to_server, 0,
4114                                                           gzip_level, NULL);
4115                     global_from_server =
4116                         compress_buffer_initialize (global_from_server, 1,
4117                                                             gzip_level, NULL);
4118               }
4119 #ifndef NO_CLIENT_GZIP_PROCESS
4120               else if (supported_request ("gzip-file-contents"))
4121               {
4122                     char *gzip_level_buf = Xasprintf ("%d", gzip_level);
4123                     send_to_server ("gzip-file-contents ", 0);
4124                     send_to_server (gzip_level_buf, 0);
4125                     free (gzip_level_buf);
4126                     send_to_server ("\012", 1);
4127 
4128                     file_gzip_level = gzip_level;
4129               }
4130 #endif
4131               else
4132               {
4133                     fprintf (stderr, "server doesn't support gzip-file-contents\n");
4134                     /* Setting gzip_level to 0 prevents us from giving the
4135                        error twice if update has to contact the server again
4136                        to fetch unpatchable files.  */
4137                     gzip_level = 0;
4138               }
4139           }
4140 
4141           if (client_referrer && supported_request ("Referrer"))
4142           {
4143               send_to_server ("Referrer ", 0);
4144               send_to_server (client_referrer->original, 0);
4145               send_to_server ("\012", 0);
4146           }
4147 
4148           /* FIXME: I think we should still be sending this for init.  */
4149           if (!rootless && supported_request ("Command-prep"))
4150           {
4151               send_to_server ("Command-prep ", 0);
4152               send_to_server (cvs_cmd_name, 0);
4153               send_to_server ("\012", 0);
4154               status = get_server_responses ();
4155               if (status == 1) exit (EXIT_FAILURE);
4156               if (status == 2) close_connection_to_server (&global_to_server,
4157                                                                        &global_from_server);
4158           }
4159           else status = 0;
4160     } while (status == 2);
4161 
4162 
4163     /*
4164      * Now handle global options.
4165      *
4166      * -H, -f, -d, -e should be handled OK locally.
4167      *
4168      * -b we ignore (treating it as a server installation issue).
4169      * FIXME: should be an error message.
4170      *
4171      * -v we print local version info; FIXME: Add a protocol request to get
4172      * the version from the server so we can print that too.
4173      *
4174      * -l -t -r -w -q -n and -Q need to go to the server.
4175      */
4176     if (noexec)
4177     {
4178           if (have_global)
4179           {
4180               send_to_server ("Global_option -n\012", 0);
4181           }
4182           else
4183               error (1, 0,
4184                        "This server does not support the global -n option.");
4185     }
4186     if (!cvswrite)
4187     {
4188           if (have_global)
4189           {
4190               send_to_server ("Global_option -r\012", 0);
4191           }
4192           else
4193               error (1, 0,
4194                        "This server does not support the global -r option.");
4195     }
4196     if (trace)
4197     {
4198           if (have_global)
4199           {
4200               int count = trace;
4201               while (count--) send_to_server ("Global_option -t\012", 0);
4202           }
4203           else
4204               error (1, 0,
4205                        "This server does not support the global -t option.");
4206     }
4207 
4208     /* Find out about server-side cvswrappers.  An extra network
4209        turnaround for cvs import seems to be unavoidable, unless we
4210        want to add some kind of client-side place to configure which
4211        filenames imply binary.  For cvs add, we could avoid the
4212        problem by keeping a copy of the wrappers in CVSADM (the main
4213        reason to bother would be so we could make add work without
4214        contacting the server, I suspect).  */
4215 
4216     if (!strcmp (cvs_cmd_name, "import") || !strcmp (cvs_cmd_name, "add"))
4217     {
4218           if (supported_request ("wrapper-sendme-rcsOptions"))
4219           {
4220               int err;
4221               send_to_server ("wrapper-sendme-rcsOptions\012", 0);
4222               err = get_server_responses ();
4223               if (err != 0)
4224                     error (err, 0, "error reading from server");
4225           }
4226     }
4227 
4228     if (cvsauthenticate && ! cvsencrypt && !rootless)
4229     {
4230           /* Turn on authentication after turning on compression, so
4231              that we can compress the authentication information.  We
4232              assume that encrypted data is always authenticated--the
4233              ability to decrypt the data stream is itself a form of
4234              authentication.  */
4235 #ifdef HAVE_GSSAPI
4236           if (current_parsed_root->method == gserver_method)
4237           {
4238               if (! supported_request ("Gssapi-authenticate"))
4239                     error (1, 0,
4240                            "This server does not support stream authentication");
4241               send_to_server ("Gssapi-authenticate\012", 0);
4242               initialize_gssapi_buffers(&global_to_server, &global_from_server);
4243 
4244           }
4245           else
4246               error (1, 0, "Stream authentication is only supported when using GSSAPI");
4247 #else /* ! HAVE_GSSAPI */
4248           error (1, 0, "This client does not support stream authentication");
4249 #endif /* ! HAVE_GSSAPI */
4250     }
4251 
4252     /* If "Set" is not supported, just silently fail to send the variables.
4253        Users with an old server should get a useful error message when it
4254        fails to recognize the ${=foo} syntax.  This way if someone uses
4255        several servers, some of which are new and some old, they can still
4256        set user variables in their .cvsrc without trouble.  */
4257     if (supported_request ("Set"))
4258           walklist (variable_list, send_variable_proc, NULL);
4259 }
4260 
4261 
4262 
4263 /* Send an argument STRING.  */
4264 void
send_arg(const char * string)4265 send_arg (const char *string)
4266 {
4267     const char *p = string;
4268 
4269     send_to_server ("Argument ", 0);
4270 
4271     while (*p)
4272     {
4273           if (*p == '\n')
4274               send_to_server ("\012Argumentx ", 0);
4275           else
4276               send_to_server (p, 1);
4277           ++p;
4278     }
4279     send_to_server ("\012", 1);
4280 }
4281 
4282 
4283 
4284 /* VERS->OPTIONS specifies whether the file is binary or not.  NOTE: BEFORE
4285    using any other fields of the struct vers, we would need to fix
4286    client_process_import_file to set them up.  */
4287 static void
send_modified(const char * file,const char * short_pathname,Vers_TS * vers)4288 send_modified (const char *file, const char *short_pathname, Vers_TS *vers)
4289 {
4290     /* File was modified, send it.  */
4291     struct stat sb;
4292     int fd;
4293     unsigned char *buf;
4294     char *mode_string;
4295     size_t bufsize;
4296     int bin;
4297 
4298     TRACE (TRACE_FUNCTION, "Sending file `%s' to server", file);
4299 
4300     /* Don't think we can assume fstat exists.  */
4301     if (stat (file, &sb) < 0)
4302           error (1, errno, "reading %s", short_pathname);
4303 
4304     mode_string = mode_to_string (sb.st_mode);
4305 
4306     /* Beware: on systems using CRLF line termination conventions,
4307        the read and write functions will convert CRLF to LF, so the
4308        number of characters read is not the same as sb.st_size.  Text
4309        files should always be transmitted using the LF convention, so
4310        we don't want to disable this conversion.  */
4311     bufsize = sb.st_size;
4312     buf = xmalloc (bufsize);
4313 
4314     /* Is the file marked as containing binary data by the "-kb" flag?
4315        If so, make sure to open it in binary mode: */
4316 
4317     if (vers && vers->options)
4318       bin = !strcmp (vers->options, "-kb");
4319     else
4320       bin = 0;
4321 
4322 #ifdef BROKEN_READWRITE_CONVERSION
4323     if (!bin)
4324     {
4325           /* If only stdio, not open/write/etc., do text/binary
4326              conversion, use convert_file which can compensate
4327              (FIXME: we could just use stdio instead which would
4328              avoid the whole problem).  */
4329           char *tfile = Xasprintf ("%s.CVSBFCTMP", file);
4330           convert_file (file, O_RDONLY,
4331                           tfile, O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY);
4332           fd = CVS_OPEN (tfile, O_RDONLY | OPEN_BINARY);
4333           if (fd < 0)
4334               error (1, errno, "reading %s", short_pathname);
4335           free (tfile);
4336     }
4337     else
4338           fd = CVS_OPEN (file, O_RDONLY | OPEN_BINARY);
4339 #else
4340     fd = CVS_OPEN (file, O_RDONLY | (bin ? OPEN_BINARY : 0));
4341 #endif
4342 
4343     if (fd < 0)
4344           error (1, errno, "reading %s", short_pathname);
4345 
4346     if (file_gzip_level && sb.st_size > 100)
4347     {
4348           size_t newsize = 0;
4349 
4350           if (read_and_gzip (fd, short_pathname, &buf,
4351                                  &bufsize, &newsize,
4352                                  file_gzip_level))
4353               error (1, 0, "aborting due to compression error");
4354 
4355           if (close (fd) < 0)
4356               error (0, errno, "warning: can't close %s", short_pathname);
4357 
4358         {
4359           char tmp[80];
4360 
4361             send_to_server ("Modified ", 0);
4362             send_to_server (file, 0);
4363             send_to_server ("\012", 1);
4364             send_to_server (mode_string, 0);
4365             send_to_server ("\012z", 2);
4366             sprintf (tmp, "%lu\n", (unsigned long) newsize);
4367             send_to_server (tmp, 0);
4368 
4369           send_to_server (buf, newsize);
4370         }
4371     }
4372     else
4373     {
4374           int newsize;
4375 
4376         {
4377               unsigned char *bufp = buf;
4378               int len;
4379 
4380               /* FIXME: This is gross.  It assumes that we might read
4381                  less than st_size bytes (true on NT), but not more.
4382                  Instead of this we should just be reading a block of
4383                  data (e.g. 8192 bytes), writing it to the network, and
4384                  so on until EOF.  */
4385               while ((len = read (fd, bufp, (buf + sb.st_size) - bufp)) > 0)
4386                   bufp += len;
4387 
4388               if (len < 0)
4389                   error (1, errno, "reading %s", short_pathname);
4390 
4391               newsize = bufp - buf;
4392           }
4393           if (close (fd) < 0)
4394               error (0, errno, "warning: can't close %s", short_pathname);
4395 
4396         {
4397           char tmp[80];
4398 
4399             send_to_server ("Modified ", 0);
4400             send_to_server (file, 0);
4401             send_to_server ("\012", 1);
4402             send_to_server (mode_string, 0);
4403             send_to_server ("\012", 1);
4404           sprintf (tmp, "%lu\012", (unsigned long) newsize);
4405           send_to_server (tmp, 0);
4406         }
4407 #ifdef BROKEN_READWRITE_CONVERSION
4408           if (!bin)
4409           {
4410               char *tfile = Xasprintf ("%s.CVSBFCTMP", file);
4411               if (CVS_UNLINK (tfile) < 0)
4412                     error (0, errno, "warning: can't remove temp file %s", tfile);
4413               free (tfile);
4414           }
4415 #endif
4416 
4417           /*
4418            * Note that this only ends with a newline if the file ended with
4419            * one.
4420            */
4421           if (newsize > 0)
4422               send_to_server (buf, newsize);
4423     }
4424     free (buf);
4425     free (mode_string);
4426 }
4427 
4428 
4429 
4430 /* The address of an instance of this structure is passed to
4431    send_fileproc, send_filesdoneproc, and send_direntproc, as the
4432    callerdat parameter.  */
4433 struct send_data
4434 {
4435     /* Each of the following flags are zero for clear or nonzero for set.  */
4436     int build_dirs;
4437     int force;
4438     int no_contents;
4439     int backup_modified;
4440 };
4441 
4442 /* Deal with one file.  */
4443 static int
send_fileproc(void * callerdat,struct file_info * finfo)4444 send_fileproc (void *callerdat, struct file_info *finfo)
4445 {
4446     struct send_data *args = callerdat;
4447     Vers_TS *vers;
4448     struct file_info xfinfo;
4449     /* File name to actually use.  Might differ in case from
4450        finfo->file.  */
4451     const char *filename;
4452 
4453     send_a_repository ("", finfo->repository, finfo->update_dir);
4454 
4455     xfinfo = *finfo;
4456     xfinfo.repository = NULL;
4457     xfinfo.rcs = NULL;
4458     vers = Version_TS (&xfinfo, NULL, NULL, NULL, 0, 0);
4459 
4460     if (vers->entdata)
4461           filename = vers->entdata->user;
4462     else
4463           filename = finfo->file;
4464 
4465     if (vers->vn_user)
4466     {
4467           /* The Entries request.  */
4468           send_to_server ("Entry /", 0);
4469           send_to_server (filename, 0);
4470           send_to_server ("/", 0);
4471           send_to_server (vers->vn_user, 0);
4472           send_to_server ("/", 0);
4473           if (vers->ts_conflict)
4474           {
4475               if (vers->ts_user && !strcmp (vers->ts_conflict, vers->ts_user))
4476                     send_to_server ("+=", 0);
4477               else
4478                     send_to_server ("+modified", 0);
4479           }
4480           send_to_server ("/", 0);
4481           send_to_server (vers->entdata ? vers->entdata->options : vers->options,
4482                               0);
4483           send_to_server ("/", 0);
4484           if (vers->entdata && vers->entdata->tag)
4485           {
4486               send_to_server ("T", 0);
4487               send_to_server (vers->entdata->tag, 0);
4488           }
4489           else if (vers->entdata && vers->entdata->date)
4490           {
4491               send_to_server ("D", 0);
4492               send_to_server (vers->entdata->date, 0);
4493           }
4494           send_to_server ("\012", 1);
4495     }
4496     else
4497     {
4498           /* It seems a little silly to re-read this on each file, but
4499              send_dirent_proc doesn't get called if filenames are specified
4500              explicitly on the command line.  */
4501           wrap_add_file (CVSDOTWRAPPER, 1);
4502 
4503           if (wrap_name_has (filename, WRAP_RCSOPTION))
4504           {
4505               /* No "Entry", but the wrappers did give us a kopt so we better
4506                  send it with "Kopt".  As far as I know this only happens
4507                  for "cvs add".  Question: is there any reason why checking
4508                  for options from wrappers isn't done in Version_TS?
4509 
4510                  Note: it might have been better to just remember all the
4511                  kopts on the client side, rather than send them to the server,
4512                  and have it send us back the same kopts.  But that seemed like
4513                  a bigger change than I had in mind making now.  */
4514 
4515               if (supported_request ("Kopt"))
4516               {
4517                     char *opt;
4518 
4519                     send_to_server ("Kopt ", 0);
4520                     opt = wrap_rcsoption (filename, 1);
4521                     send_to_server (opt, 0);
4522                     send_to_server ("\012", 1);
4523                     free (opt);
4524               }
4525               else
4526                     error (0, 0, "\
4527 warning: ignoring -k options due to server limitations");
4528           }
4529     }
4530 
4531     if (!vers->ts_user)
4532     {
4533           /*
4534            * Do we want to print "file was lost" like normal CVS?
4535            * Would it always be appropriate?
4536            */
4537           /* File no longer exists.  Don't do anything, missing files
4538              just happen.  */
4539     }
4540     else if (!vers->ts_rcs || args->force
4541                || strcmp (vers->ts_conflict
4542                             ? vers->ts_conflict : vers->ts_rcs, vers->ts_user)
4543                || (vers->ts_conflict && !strcmp (cvs_cmd_name, "diff")))
4544     {
4545           if (args->no_contents
4546               && supported_request ("Is-modified"))
4547           {
4548               send_to_server ("Is-modified ", 0);
4549               send_to_server (filename, 0);
4550               send_to_server ("\012", 1);
4551           }
4552           else
4553               send_modified (filename, finfo->fullname, vers);
4554 
4555         if (args->backup_modified)
4556         {
4557             char *bakname;
4558             bakname = backup_file (filename, vers->vn_user);
4559             /* This behavior is sufficiently unexpected to
4560                justify overinformativeness, I think. */
4561             if (! really_quiet)
4562                 printf ("(Locally modified %s moved to %s)\n",
4563                         filename, bakname);
4564             free (bakname);
4565         }
4566     }
4567     else
4568     {
4569           send_to_server ("Unchanged ", 0);
4570           send_to_server (filename, 0);
4571           send_to_server ("\012", 1);
4572     }
4573 
4574     /* if this directory has an ignore list, add this file to it */
4575     if (ignlist)
4576     {
4577           Node *p;
4578 
4579           p = getnode ();
4580           p->type = FILES;
4581           p->key = xstrdup (finfo->file);
4582           (void) addnode (ignlist, p);
4583     }
4584 
4585     freevers_ts (&vers);
4586     return 0;
4587 }
4588 
4589 
4590 
4591 static void
send_ignproc(const char * file,const char * dir)4592 send_ignproc (const char *file, const char *dir)
4593 {
4594     if (ign_inhibit_server || !supported_request ("Questionable"))
4595     {
4596           if (dir[0] != '\0')
4597               (void) printf ("? %s/%s\n", dir, file);
4598           else
4599               (void) printf ("? %s\n", file);
4600     }
4601     else
4602     {
4603           send_to_server ("Questionable ", 0);
4604           send_to_server (file, 0);
4605           send_to_server ("\012", 1);
4606     }
4607 }
4608 
4609 
4610 
4611 static int
send_filesdoneproc(void * callerdat,int err,const char * repository,const char * update_dir,List * entries)4612 send_filesdoneproc (void *callerdat, int err, const char *repository,
4613                     const char *update_dir, List *entries)
4614 {
4615     /* if this directory has an ignore list, process it then free it */
4616     if (ignlist)
4617     {
4618           ignore_files (ignlist, entries, update_dir, send_ignproc);
4619           dellist (&ignlist);
4620     }
4621 
4622     return err;
4623 }
4624 
4625 
4626 
4627 /*
4628  * send_dirent_proc () is called back by the recursion processor before a
4629  * sub-directory is processed for update.
4630  * A return code of 0 indicates the directory should be
4631  * processed by the recursion code.  A return of non-zero indicates the
4632  * recursion code should skip this directory.
4633  *
4634  */
4635 static Dtype
send_dirent_proc(void * callerdat,const char * dir,const char * repository,const char * update_dir,List * entries)4636 send_dirent_proc (void *callerdat, const char *dir, const char *repository,
4637                   const char *update_dir, List *entries)
4638 {
4639     struct send_data *args = callerdat;
4640     int dir_exists;
4641     char *cvsadm_name;
4642 
4643     if (ignore_directory (update_dir))
4644     {
4645           /* print the warm fuzzy message */
4646           if (!quiet)
4647               error (0, 0, "Ignoring %s", update_dir);
4648         return R_SKIP_ALL;
4649     }
4650 
4651     /*
4652      * If the directory does not exist yet (e.g. "cvs update -d foo"),
4653      * no need to send any files from it.  If the directory does not
4654      * have a CVS directory, then we pretend that it does not exist.
4655      * Otherwise, we will fail when trying to open the Entries file.
4656      * This case will happen when checking out a module defined as
4657      * ``-a .''.
4658      */
4659     cvsadm_name = Xasprintf ("%s/%s", dir, CVSADM);
4660     dir_exists = isdir (cvsadm_name);
4661     free (cvsadm_name);
4662 
4663     /*
4664      * If there is an empty directory (e.g. we are doing `cvs add' on a
4665      * newly-created directory), the server still needs to know about it.
4666      */
4667 
4668     if (dir_exists)
4669     {
4670           /*
4671            * Get the repository from a CVS/Repository file whenever possible.
4672            * The repository variable is wrong if the names in the local
4673            * directory don't match the names in the repository.
4674            */
4675           char *repos = Name_Repository (dir, update_dir);
4676           send_a_repository (dir, repos, update_dir);
4677           free (repos);
4678 
4679           /* initialize the ignore list for this directory */
4680           ignlist = getlist ();
4681     }
4682     else
4683     {
4684           /* It doesn't make sense to send a non-existent directory,
4685              because there is no way to get the correct value for
4686              the repository (I suppose maybe via the expand-modules
4687              request).  In the case where the "obvious" choice for
4688              repository is correct, the server can figure out whether
4689              to recreate the directory; in the case where it is wrong
4690              (that is, does not match what modules give us), we might as
4691              well just fail to recreate it.
4692 
4693              Checking for noexec is a kludge for "cvs -n add dir".  */
4694           /* Don't send a non-existent directory unless we are building
4695            new directories (build_dirs is true).  Otherwise, CVS may
4696            see a D line in an Entries file, and recreate a directory
4697            which the user removed by hand.  */
4698           if (args->build_dirs && noexec)
4699               send_a_repository (dir, repository, update_dir);
4700     }
4701 
4702     return dir_exists ? R_PROCESS : R_SKIP_ALL;
4703 }
4704 
4705 
4706 
4707 /*
4708  * send_dirleave_proc () is called back by the recursion code upon leaving
4709  * a directory.  All it does is delete the ignore list if it hasn't already
4710  * been done (by send_filesdone_proc).
4711  */
4712 /* ARGSUSED */
4713 static int
send_dirleave_proc(void * callerdat,const char * dir,int err,const char * update_dir,List * entries)4714 send_dirleave_proc (void *callerdat, const char *dir, int err,
4715                     const char *update_dir, List *entries )
4716 {
4717 
4718     /* Delete the ignore list if it hasn't already been done.  */
4719     if (ignlist)
4720           dellist (&ignlist);
4721     return err;
4722 }
4723 
4724 
4725 
4726 /*
4727  * Send each option in an array to the server, one by one.
4728  * argv might be "--foo=bar",  "-C", "5", "-y".
4729  */
4730 
4731 void
send_options(int argc,char * const * argv)4732 send_options (int argc, char * const *argv)
4733 {
4734     int i;
4735     for (i = 0; i < argc; i++)
4736           send_arg (argv[i]);
4737 }
4738 
4739 
4740 
4741 /* Send the names of all the argument files to the server.  */
4742 void
send_file_names(int argc,char ** argv,unsigned int flags)4743 send_file_names (int argc, char **argv, unsigned int flags)
4744 {
4745     int i;
4746 
4747     /* The fact that we do this here as well as start_recursion is a bit
4748        of a performance hit.  Perhaps worth cleaning up someday.  */
4749     if (flags & SEND_EXPAND_WILD)
4750           expand_wild (argc, argv, &argc, &argv);
4751 
4752     for (i = 0; i < argc; ++i)
4753     {
4754           char buf[1];
4755           char *p;
4756 #ifdef FILENAMES_CASE_INSENSITIVE
4757           char *line = NULL;
4758 #endif /* FILENAMES_CASE_INSENSITIVE */
4759 
4760           if (arg_should_not_be_sent_to_server (argv[i]))
4761               continue;
4762 
4763 #ifdef FILENAMES_CASE_INSENSITIVE
4764           /* We want to send the path as it appears in the
4765              CVS/Entries files.  We put this inside an ifdef
4766              to avoid doing all these system calls in
4767              cases where fncmp is just strcmp anyway.  */
4768           /* The isdir (CVSADM) check could more gracefully be replaced
4769              with a way of having Entries_Open report back the
4770              error to us and letting us ignore existence_error.
4771              Or some such.  */
4772           {
4773               List *stack;
4774               size_t line_len = 0;
4775               char *q, *r;
4776               struct saved_cwd sdir;
4777 
4778               /* Split the argument onto the stack.  */
4779               stack = getlist();
4780               r = xstrdup (argv[i]);
4781             /* It's okay to discard the const from the last_component return
4782              * below since we know we passed in an arg that was not const.
4783              */
4784               while ((q = (char *)last_component (r)) != r)
4785               {
4786                     push (stack, xstrdup (q));
4787                     *--q = '\0';
4788               }
4789               push (stack, r);
4790 
4791               /* Normalize the path into outstr. */
4792               save_cwd (&sdir);
4793               while (q = pop (stack))
4794               {
4795                     Node *node = NULL;
4796                   if (isdir (CVSADM))
4797                     {
4798                         List *entries;
4799 
4800                         /* Note that if we are adding a directory,
4801                            the following will read the entry
4802                            that we just wrote there, that is, we
4803                            will get the case specified on the
4804                            command line, not the case of the
4805                            directory in the filesystem.  This
4806                            is correct behavior.  */
4807                         entries = Entries_Open (0, NULL);
4808                         node = findnode_fn (entries, q);
4809                         if (node)
4810                         {
4811                               /* Add the slash unless this is our first element. */
4812                               if (line_len)
4813                                   xrealloc_and_strcat (&line, &line_len, "/");
4814                               xrealloc_and_strcat (&line, &line_len, node->key);
4815                               delnode (node);
4816                         }
4817                         Entries_Close (entries);
4818                     }
4819 
4820                     /* If node is still NULL then we either didn't find CVSADM or
4821                      * we didn't find an entry there.
4822                      */
4823                     if (!node)
4824                     {
4825                         /* Add the slash unless this is our first element. */
4826                         if (line_len)
4827                               xrealloc_and_strcat (&line, &line_len, "/");
4828                         xrealloc_and_strcat (&line, &line_len, q);
4829                         break;
4830                     }
4831 
4832                     /* And descend the tree. */
4833                     if (isdir (q))
4834                         CVS_CHDIR (q);
4835                     free (q);
4836               }
4837               restore_cwd (&sdir);
4838               free_cwd (&sdir);
4839 
4840               /* Now put everything we didn't find entries for back on. */
4841               while (q = pop (stack))
4842               {
4843                     if (line_len)
4844                         xrealloc_and_strcat (&line, &line_len, "/");
4845                     xrealloc_and_strcat (&line, &line_len, q);
4846                     free (q);
4847               }
4848 
4849               p = line;
4850 
4851               dellist (&stack);
4852           }
4853 #else /* !FILENAMES_CASE_INSENSITIVE */
4854           p = argv[i];
4855 #endif /* FILENAMES_CASE_INSENSITIVE */
4856 
4857           send_to_server ("Argument ", 0);
4858 
4859           while (*p)
4860           {
4861               if (*p == '\n')
4862               {
4863                     send_to_server ("\012Argumentx ", 0);
4864               }
4865               else if (ISSLASH (*p))
4866               {
4867                     buf[0] = '/';
4868                     send_to_server (buf, 1);
4869               }
4870               else
4871               {
4872                     buf[0] = *p;
4873                     send_to_server (buf, 1);
4874               }
4875               ++p;
4876           }
4877           send_to_server ("\012", 1);
4878 #ifdef FILENAMES_CASE_INSENSITIVE
4879           free (line);
4880 #endif /* FILENAMES_CASE_INSENSITIVE */
4881     }
4882 
4883     if (flags & SEND_EXPAND_WILD)
4884     {
4885           int i;
4886           for (i = 0; i < argc; ++i)
4887               free (argv[i]);
4888           free (argv);
4889     }
4890 }
4891 
4892 
4893 
4894 /* Calculate and send max-dotdot to the server */
4895 static void
send_max_dotdot(argc,argv)4896 send_max_dotdot (argc, argv)
4897     int argc;
4898     char **argv;
4899 {
4900     int i;
4901     int level = 0;
4902     int max_level = 0;
4903 
4904     /* Send Max-dotdot if needed.  */
4905     for (i = 0; i < argc; ++i)
4906     {
4907         level = pathname_levels (argv[i]);
4908           if (level > 0)
4909           {
4910             if (!uppaths) uppaths = getlist();
4911               push_string (uppaths, xstrdup (argv[i]));
4912           }
4913         if (level > max_level)
4914             max_level = level;
4915     }
4916 
4917     if (max_level > 0)
4918     {
4919         if (supported_request ("Max-dotdot"))
4920         {
4921             char buf[10];
4922             sprintf (buf, "%d", max_level);
4923 
4924             send_to_server ("Max-dotdot ", 0);
4925             send_to_server (buf, 0);
4926             send_to_server ("\012", 1);
4927         }
4928         else
4929         {
4930             error (1, 0,
4931 "backreference in path (`..') not supported by old (pre-Max-dotdot) servers");
4932         }
4933     }
4934 }
4935 
4936 
4937 
4938 /* Send Repository, Modified and Entry.  argc and argv contain only
4939   the files to operate on (or empty for everything), not options.
4940   local is nonzero if we should not recurse (-l option).  flags &
4941   SEND_BUILD_DIRS is nonzero if nonexistent directories should be
4942   sent.  flags & SEND_FORCE is nonzero if we should send unmodified
4943   files to the server as though they were modified.  flags &
4944   SEND_NO_CONTENTS means that this command only needs to know
4945   _whether_ a file is modified, not the contents.  Also sends Argument
4946   lines for argc and argv, so should be called after options are sent.  */
4947 void
send_files(int argc,char ** argv,int local,int aflag,unsigned int flags)4948 send_files (int argc, char **argv, int local, int aflag, unsigned int flags)
4949 {
4950     struct send_data args;
4951     int err;
4952 
4953     send_max_dotdot (argc, argv);
4954 
4955     /*
4956      * aflag controls whether the tag/date is copied into the vers_ts.
4957      * But we don't actually use it, so I don't think it matters what we pass
4958      * for aflag here.
4959      */
4960     args.build_dirs = flags & SEND_BUILD_DIRS;
4961     args.force = flags & SEND_FORCE;
4962     args.no_contents = flags & SEND_NO_CONTENTS;
4963     args.backup_modified = flags & BACKUP_MODIFIED_FILES;
4964     err = start_recursion
4965           (send_fileproc, send_filesdoneproc, send_dirent_proc,
4966          send_dirleave_proc, &args, argc, argv, local, W_LOCAL, aflag,
4967          CVS_LOCK_NONE, NULL, 0, NULL);
4968     if (err)
4969           exit (EXIT_FAILURE);
4970     if (!toplevel_repos)
4971           /*
4972            * This happens if we are not processing any files,
4973            * or for checkouts in directories without any existing stuff
4974            * checked out.  The following assignment is correct for the
4975            * latter case; I don't think toplevel_repos matters for the
4976            * former.
4977            */
4978           toplevel_repos = xstrdup (current_parsed_root->directory);
4979     send_repository ("", toplevel_repos, ".");
4980 }
4981 
4982 
4983 
4984 void
client_import_setup(char * repository)4985 client_import_setup (char *repository)
4986 {
4987     if (!toplevel_repos)                /* should always be true */
4988         send_a_repository ("", repository, "");
4989 }
4990 
4991 
4992 
4993 /*
4994  * Process the argument import file.
4995  */
4996 int
client_process_import_file(char * message,char * vfile,char * vtag,int targc,char * targv[],char * repository,int all_files_binary,int modtime)4997 client_process_import_file (char *message, char *vfile, char *vtag, int targc,
4998                             char *targv[], char *repository,
4999                             int all_files_binary,
5000                             int modtime /* Nonzero for "import -d".  */ )
5001 {
5002     char *update_dir;
5003     char *fullname;
5004     Vers_TS vers;
5005 
5006     assert (toplevel_repos);
5007 
5008     if (strncmp (repository, toplevel_repos, strlen (toplevel_repos)))
5009           error (1, 0,
5010                  "internal error: pathname `%s' doesn't specify file in `%s'",
5011                  repository, toplevel_repos);
5012 
5013     if (!strcmp (repository, toplevel_repos))
5014     {
5015           update_dir = "";
5016           fullname = xstrdup (vfile);
5017     }
5018     else
5019     {
5020           update_dir = repository + strlen (toplevel_repos) + 1;
5021 
5022           fullname = Xasprintf ("%s/%s", update_dir, vfile);
5023     }
5024 
5025     send_a_repository ("", repository, update_dir);
5026     if (all_files_binary)
5027           vers.options = xstrdup ("-kb");
5028     else
5029           vers.options = wrap_rcsoption (vfile, 1);
5030 
5031     if (vers.options)
5032     {
5033           if (supported_request ("Kopt"))
5034           {
5035               send_to_server ("Kopt ", 0);
5036               send_to_server (vers.options, 0);
5037               send_to_server ("\012", 1);
5038           }
5039           else
5040               error (0, 0,
5041                        "warning: ignoring -k options due to server limitations");
5042     }
5043     if (modtime)
5044     {
5045           if (supported_request ("Checkin-time"))
5046           {
5047               struct stat sb;
5048               char *rcsdate;
5049               char netdate[MAXDATELEN];
5050 
5051               if (stat (vfile, &sb) < 0)
5052                     error (1, errno, "cannot stat %s", fullname);
5053               rcsdate = date_from_time_t (sb.st_mtime);
5054               date_to_internet (netdate, rcsdate);
5055               free (rcsdate);
5056 
5057               send_to_server ("Checkin-time ", 0);
5058               send_to_server (netdate, 0);
5059               send_to_server ("\012", 1);
5060           }
5061           else
5062               error (0, 0,
5063                        "warning: ignoring -d option due to server limitations");
5064     }
5065     send_modified (vfile, fullname, &vers);
5066     if (vers.options)
5067           free (vers.options);
5068     free (fullname);
5069     return 0;
5070 }
5071 
5072 
5073 
5074 void
client_import_done(void)5075 client_import_done (void)
5076 {
5077     if (!toplevel_repos)
5078           /*
5079            * This happens if we are not processing any files,
5080            * or for checkouts in directories without any existing stuff
5081            * checked out.  The following assignment is correct for the
5082            * latter case; I don't think toplevel_repos matters for the
5083            * former.
5084            */
5085         /* FIXME: "can't happen" now that we call client_import_setup
5086              at the beginning.  */
5087           toplevel_repos = xstrdup (current_parsed_root->directory);
5088     send_repository ("", toplevel_repos, ".");
5089 }
5090 
5091 
5092 
5093 void
client_notify(const char * repository,const char * update_dir,const char * filename,int notif_type,const char * val)5094 client_notify (const char *repository, const char *update_dir,
5095                const char *filename, int notif_type, const char *val)
5096 {
5097     char buf[2];
5098 
5099     send_a_repository ("", repository, update_dir);
5100     send_to_server ("Notify ", 0);
5101     send_to_server (filename, 0);
5102     send_to_server ("\012", 1);
5103     buf[0] = notif_type;
5104     buf[1] = '\0';
5105     send_to_server (buf, 1);
5106     send_to_server ("\t", 1);
5107     send_to_server (val, 0);
5108 }
5109 
5110 
5111 
5112 /*
5113  * Send an option with an argument, dealing correctly with newlines in
5114  * the argument.  If ARG is NULL, forget the whole thing.
5115  */
5116 void
option_with_arg(const char * option,const char * arg)5117 option_with_arg (const char *option, const char *arg)
5118 {
5119     if (!arg)
5120           return;
5121 
5122     send_to_server ("Argument ", 0);
5123     send_to_server (option, 0);
5124     send_to_server ("\012", 1);
5125 
5126     send_arg (arg);
5127 }
5128 
5129 
5130 
5131 /* Send a date to the server.  The input DATE is in RCS format.
5132    The time will be GMT.
5133 
5134    We then convert that to the format required in the protocol
5135    (including the "-D" option) and send it.  According to
5136    cvsclient.texi, RFC 822/1123 format is preferred.  */
5137 void
client_senddate(const char * date)5138 client_senddate (const char *date)
5139 {
5140     char buf[MAXDATELEN];
5141 
5142     date_to_internet (buf, date);
5143     option_with_arg ("-D", buf);
5144 }
5145 
5146 
5147 
5148 void
send_init_command(void)5149 send_init_command (void)
5150 {
5151     /* This is here because we need the current_parsed_root->directory variable.  */
5152     send_to_server ("init ", 0);
5153     send_to_server (current_parsed_root->directory, 0);
5154     send_to_server ("\012", 0);
5155 }
5156 
5157 
5158 
5159 #if defined AUTH_CLIENT_SUPPORT || defined HAVE_KERBEROS || defined HAVE_GSSAPI
5160 
5161 static int
connect_to(char * hostname,unsigned int port)5162 connect_to(char *hostname, unsigned int port)
5163 {
5164     struct addrinfo hints, *res, *res0 = NULL;
5165     char pbuf[10];
5166     int e, sock;
5167 
5168     memset(&hints, 0, sizeof(hints));
5169     hints.ai_family = PF_UNSPEC;
5170     hints.ai_socktype = SOCK_STREAM;
5171     hints.ai_flags = AI_CANONNAME;
5172 
5173     snprintf(pbuf, sizeof(pbuf), "%d", port);
5174     e = getaddrinfo(hostname, pbuf, &hints, &res0);
5175     if (e)
5176     {
5177           error (1, 0, "%s", gai_strerror(e));
5178     }
5179     sock = -1;
5180     for (res = res0; res; res = res->ai_next) {
5181           sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
5182           if (sock < 0)
5183               continue;
5184 
5185           TRACE (TRACE_FUNCTION, " -> Connecting to %s\n", hostname);
5186           if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
5187               close(sock);
5188               sock = -1;
5189               continue;
5190           }
5191           break;
5192     }
5193     freeaddrinfo(res0);
5194     return sock;
5195 }
5196 
5197 #endif /* defined AUTH_CLIENT_SUPPORT || defined HAVE_KERBEROS
5198           * || defined HAVE_GSSAPI
5199           */
5200 
5201 #endif /* CLIENT_SUPPORT */
5202