home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / cvs-1.8.7-src.tgz / tar.out / fsf / cvs / src / client.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  122KB  |  4,785 lines

  1. /* CVS client-related stuff.  */
  2.  
  3. #ifdef HAVE_CONFIG_H
  4. #include "config.h"
  5. #endif /* HAVE_CONFIG_H */
  6.  
  7. #include "cvs.h"
  8. #include "getline.h"
  9. #include "edit.h"
  10. #include "buffer.h"
  11.  
  12. #ifdef CLIENT_SUPPORT
  13.  
  14. #include "md5.h"
  15.  
  16. #if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || USE_DIRECT_TCP
  17. #  ifdef HAVE_WINSOCK_H
  18. #    include <winsock.h>
  19. #  else /* No winsock.h */
  20. #    include <sys/socket.h>
  21. #    include <netinet/in.h>
  22. #    include <netdb.h>
  23. #  endif /* No winsock.h */
  24. #endif /* defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || USE_DIRECT_TCP */
  25.  
  26. #if HAVE_KERBEROS || USE_DIRECT_TCP
  27. #define CVS_PORT 1999
  28.  
  29. #if HAVE_KERBEROS
  30. #include <krb.h>
  31.  
  32. extern char *krb_realmofhost ();
  33. #ifndef HAVE_KRB_GET_ERR_TEXT
  34. #define krb_get_err_text(status) krb_err_txt[status]
  35. #endif /* HAVE_KRB_GET_ERR_TEXT */
  36.  
  37. /* Information we need if we are going to use Kerberos encryption.  */
  38. static C_Block kblock;
  39. static Key_schedule sched;
  40.  
  41. #endif /* HAVE_KERBEROS */
  42.  
  43. #endif /* HAVE_KERBEROS || USE_DIRECT_TCP */
  44.  
  45. static void add_prune_candidate PROTO((char *));
  46.  
  47. /* All the commands.  */
  48. int add PROTO((int argc, char **argv));
  49. int admin PROTO((int argc, char **argv));
  50. int checkout PROTO((int argc, char **argv));
  51. int commit PROTO((int argc, char **argv));
  52. int diff PROTO((int argc, char **argv));
  53. int history PROTO((int argc, char **argv));
  54. int import PROTO((int argc, char **argv));
  55. int cvslog PROTO((int argc, char **argv));
  56. int patch PROTO((int argc, char **argv));
  57. int release PROTO((int argc, char **argv));
  58. int cvsremove PROTO((int argc, char **argv));
  59. int rtag PROTO((int argc, char **argv));
  60. int status PROTO((int argc, char **argv));
  61. int tag PROTO((int argc, char **argv));
  62. int update PROTO((int argc, char **argv));
  63.  
  64. /* All the response handling functions.  */
  65. static void handle_ok PROTO((char *, int));
  66. static void handle_error PROTO((char *, int));
  67. static void handle_valid_requests PROTO((char *, int));
  68. static void handle_checked_in PROTO((char *, int));
  69. static void handle_new_entry PROTO((char *, int));
  70. static void handle_checksum PROTO((char *, int));
  71. static void handle_copy_file PROTO((char *, int));
  72. static void handle_updated PROTO((char *, int));
  73. static void handle_merged PROTO((char *, int));
  74. static void handle_patched PROTO((char *, int));
  75. static void handle_removed PROTO((char *, int));
  76. static void handle_remove_entry PROTO((char *, int));
  77. static void handle_set_static_directory PROTO((char *, int));
  78. static void handle_clear_static_directory PROTO((char *, int));
  79. static void handle_set_sticky PROTO((char *, int));
  80. static void handle_clear_sticky PROTO((char *, int));
  81. static void handle_set_checkin_prog PROTO((char *, int));
  82. static void handle_set_update_prog PROTO((char *, int));
  83. static void handle_module_expansion PROTO((char *, int));
  84. static void handle_m PROTO((char *, int));
  85. static void handle_e PROTO((char *, int));
  86. static void handle_f PROTO((char *, int));
  87. static void handle_notified PROTO((char *, int));
  88.  
  89. static void buf_memory_error PROTO((struct buffer *));
  90. static size_t try_read_from_server PROTO ((char *, size_t));
  91. #endif /* CLIENT_SUPPORT */
  92.  
  93. #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
  94.  
  95. /* Shared with server.  */
  96.  
  97. /*
  98.  * Return a malloc'd, '\0'-terminated string
  99.  * corresponding to the mode in SB.
  100.  */
  101. char *
  102. #ifdef __STDC__
  103. mode_to_string (mode_t mode)
  104. #else /* ! __STDC__ */
  105. mode_to_string (mode)
  106.     mode_t mode;
  107. #endif /* __STDC__ */
  108. {
  109.     char buf[18], u[4], g[4], o[4];
  110.     int i;
  111.  
  112.     i = 0;
  113.     if (mode & S_IRUSR) u[i++] = 'r';
  114.     if (mode & S_IWUSR) u[i++] = 'w';
  115.     if (mode & S_IXUSR) u[i++] = 'x';
  116.     u[i] = '\0';
  117.  
  118.     i = 0;
  119.     if (mode & S_IRGRP) g[i++] = 'r';
  120.     if (mode & S_IWGRP) g[i++] = 'w';
  121.     if (mode & S_IXGRP) g[i++] = 'x';
  122.     g[i] = '\0';
  123.  
  124.     i = 0;
  125.     if (mode & S_IROTH) o[i++] = 'r';
  126.     if (mode & S_IWOTH) o[i++] = 'w';
  127.     if (mode & S_IXOTH) o[i++] = 'x';
  128.     o[i] = '\0';
  129.  
  130.     sprintf(buf, "u=%s,g=%s,o=%s", u, g, o);
  131.     return xstrdup(buf);
  132. }
  133.  
  134. /*
  135.  * Change mode of FILENAME to MODE_STRING.
  136.  * Returns 0 for success or errno code.
  137.  */
  138. int
  139. change_mode (filename, mode_string)
  140.     char *filename;
  141.     char *mode_string;
  142. {
  143. #ifdef CHMOD_BROKEN
  144.     char *p;
  145.     int writeable = 0;
  146.  
  147.     /* We can only distinguish between
  148.          1) readable
  149.          2) writeable
  150.          3) Picasso's "Blue Period"
  151.        We handle the first two. */
  152.     p = mode_string;
  153.     while (*p != '\0')
  154.     {
  155.     if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=')
  156.     {
  157.         char *q = p + 2;
  158.         while (*q != ',' && *q != '\0')
  159.         {
  160.         if (*q == 'w')
  161.             writeable = 1;
  162.         ++q;
  163.         }
  164.     }
  165.     /* Skip to the next field.  */
  166.     while (*p != ',' && *p != '\0')
  167.         ++p;
  168.     if (*p == ',')
  169.         ++p;
  170.     }
  171.  
  172.     xchmod (filename, writeable);
  173.     return 0;
  174.  
  175. #else /* ! CHMOD_BROKEN */
  176.  
  177.     char *p;
  178.     mode_t mode = 0;
  179.  
  180.     p = mode_string;
  181.     while (*p != '\0')
  182.     {
  183.     if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=')
  184.     {
  185.         int can_read = 0, can_write = 0, can_execute = 0;
  186.         char *q = p + 2;
  187.         while (*q != ',' && *q != '\0')
  188.         {
  189.         if (*q == 'r')
  190.             can_read = 1;
  191.         else if (*q == 'w')
  192.             can_write = 1;
  193.         else if (*q == 'x')
  194.             can_execute = 1;
  195.         ++q;
  196.         }
  197.         if (p[0] == 'u')
  198.         {
  199.         if (can_read)
  200.             mode |= S_IRUSR;
  201.         if (can_write)
  202.             mode |= S_IWUSR;
  203.         if (can_execute)
  204.             mode |= S_IXUSR;
  205.         }
  206.         else if (p[0] == 'g')
  207.         {
  208.         if (can_read)
  209.             mode |= S_IRGRP;
  210.         if (can_write)
  211.             mode |= S_IWGRP;
  212.         if (can_execute)
  213.             mode |= S_IXGRP;
  214.         }
  215.         else if (p[0] == 'o')
  216.         {
  217.         if (can_read)
  218.             mode |= S_IROTH;
  219.         if (can_write)
  220.             mode |= S_IWOTH;
  221.         if (can_execute)
  222.             mode |= S_IXOTH;
  223.         }
  224.     }
  225.     /* Skip to the next field.  */
  226.     while (*p != ',' && *p != '\0')
  227.         ++p;
  228.     if (*p == ',')
  229.         ++p;
  230.     }
  231.  
  232.     if (chmod (filename, mode) < 0)
  233.     return errno;
  234.     return 0;
  235. #endif /* ! CHMOD_BROKEN */
  236. }
  237.  
  238. #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
  239.  
  240. #ifdef CLIENT_SUPPORT
  241.  
  242. int client_prune_dirs;
  243.  
  244. static List *ignlist = (List *) NULL;
  245.  
  246. /* Buffer to write to the server.  */
  247. static struct buffer *to_server;
  248. /* The stream underlying to_server, if we are using a stream.  */
  249. static FILE *to_server_fp;
  250.  
  251. /* Buffer used to read from the server.  */
  252. static struct buffer *from_server;
  253. /* The stream underlying from_server, if we are using a stream.  */
  254. static FILE *from_server_fp;
  255.  
  256. #if ! RSH_NOT_TRANSPARENT
  257. /* Process ID of rsh subprocess.  */
  258. static int rsh_pid = -1;
  259. #endif /* ! RSH_NOT_TRANSPARENT */
  260.  
  261.  
  262. /* This routine is called when one of the buffer routines runs out of
  263.    memory.  */
  264.  
  265. static void
  266. buf_memory_error (buf)
  267.      struct buffer *buf;
  268. {
  269.     error (1, 0, "out of memory");
  270. }
  271.  
  272. /* We want to be able to log data sent between us and the server.  We
  273.    do it using log buffers.  Each log buffer has another buffer which
  274.    handles the actual I/O, and a file to log information to.
  275.  
  276.    This structure is the closure field of a log buffer.  */
  277.  
  278. struct log_buffer
  279. {
  280.     /* The underlying buffer.  */
  281.     struct buffer *buf;
  282.     /* The file to log information to.  */
  283.     FILE *log;
  284. };
  285.  
  286. static struct buffer *log_buffer_initialize
  287.   PROTO((struct buffer *, FILE *, int, void (*) (struct buffer *)));
  288. static int log_buffer_input PROTO((void *, char *, int, int, int *));
  289. static int log_buffer_output PROTO((void *, const char *, int, int *));
  290. static int log_buffer_flush PROTO((void *));
  291. static int log_buffer_block PROTO((void *, int));
  292. static int log_buffer_shutdown PROTO((void *));
  293.  
  294. /* Create a log buffer.  */
  295.  
  296. static struct buffer *
  297. log_buffer_initialize (buf, fp, input, memory)
  298.      struct buffer *buf;
  299.      FILE *fp;
  300.      int input;
  301.      void (*memory) PROTO((struct buffer *));
  302. {
  303.     struct log_buffer *n;
  304.  
  305.     n = (struct log_buffer *) xmalloc (sizeof *n);
  306.     n->buf = buf;
  307.     n->log = fp;
  308.     return buf_initialize (input ? log_buffer_input : NULL,
  309.                input ? NULL : log_buffer_output,
  310.                input ? NULL : log_buffer_flush,
  311.                log_buffer_block,
  312.                log_buffer_shutdown,
  313.                memory,
  314.                n);
  315. }
  316.  
  317. /* The input function for a log buffer.  */
  318.  
  319. static int
  320. log_buffer_input (closure, data, need, size, got)
  321.      void *closure;
  322.      char *data;
  323.      int need;
  324.      int size;
  325.      int *got;
  326. {
  327.     struct log_buffer *lb = (struct log_buffer *) closure;
  328.     int status;
  329.     size_t n_to_write;
  330.  
  331.     if (lb->buf->input == NULL)
  332.     abort ();
  333.  
  334.     status = (*lb->buf->input) (lb->buf->closure, data, need, size, got);
  335.     if (status != 0)
  336.     return status;
  337.  
  338.     if (*got > 0)
  339.     {
  340.     n_to_write = *got;
  341.     if (fwrite (data, 1, n_to_write, lb->log) != n_to_write)
  342.         error (0, errno, "writing to log file");
  343.     }
  344.  
  345.     return 0;
  346. }
  347.  
  348. /* The output function for a log buffer.  */
  349.  
  350. static int
  351. log_buffer_output (closure, data, have, wrote)
  352.      void *closure;
  353.      const char *data;
  354.      int have;
  355.      int *wrote;
  356. {
  357.     struct log_buffer *lb = (struct log_buffer *) closure;
  358.     int status;
  359.     size_t n_to_write;
  360.  
  361.     if (lb->buf->output == NULL)
  362.     abort ();
  363.  
  364.     status = (*lb->buf->output) (lb->buf->closure, data, have, wrote);
  365.     if (status != 0)
  366.     return status;
  367.  
  368.     if (*wrote > 0)
  369.     {
  370.     n_to_write = *wrote;
  371.     if (fwrite (data, 1, n_to_write, lb->log) != n_to_write)
  372.         error (0, errno, "writing to log file");
  373.     }
  374.  
  375.     return 0;
  376. }
  377.  
  378. /* The flush function for a log buffer.  */
  379.  
  380. static int
  381. log_buffer_flush (closure)
  382.      void *closure;
  383. {
  384.     struct log_buffer *lb = (struct log_buffer *) closure;
  385.  
  386.     if (lb->buf->flush == NULL)
  387.     abort ();
  388.  
  389.     /* We don't really have to flush the log file here, but doing it
  390.        will let tail -f on the log file show what is sent to the
  391.        network as it is sent.  */
  392.     if (fflush (lb->log) != 0)
  393.         error (0, errno, "flushing log file");
  394.  
  395.     return (*lb->buf->flush) (lb->buf->closure);
  396. }
  397.  
  398. /* The block function for a log buffer.  */
  399.  
  400. static int
  401. log_buffer_block (closure, block)
  402.      void *closure;
  403.      int block;
  404. {
  405.     struct log_buffer *lb = (struct log_buffer *) closure;
  406.  
  407.     if (block)
  408.     return set_block (lb->buf);
  409.     else
  410.     return set_nonblock (lb->buf);
  411. }
  412.  
  413. /* The shutdown function for a log buffer.  */
  414.  
  415. static int
  416. log_buffer_shutdown (closure)
  417.      void *closure;
  418. {
  419.     struct log_buffer *lb = (struct log_buffer *) closure;
  420.  
  421.     return buf_shutdown (lb->buf);
  422. }
  423.  
  424. #ifdef NO_SOCKET_TO_FD
  425.  
  426. /* Under certain circumstances, we must communicate with the server
  427.    via a socket using send() and recv().  This is because under some
  428.    operating systems (OS/2 and Windows 95 come to mind), a socket
  429.    cannot be converted to a file descriptor -- it must be treated as a
  430.    socket and nothing else.  */
  431.  
  432. static int use_socket_style = 0;
  433. static int server_sock;
  434.  
  435. /* These routines implement a buffer structure which uses send and
  436.    recv.  We don't need the block routine, so we don't implement it.  */
  437.  
  438. /* We use an instance of this structure as the closure field.  */
  439.  
  440. struct socket_buffer
  441. {
  442.     /* The socket number.  */
  443.     int socket;
  444. };
  445.  
  446. static struct buffer *socket_buffer_initialize
  447.   PROTO ((int, int, void (*) (struct buffer *)));
  448. static int socket_buffer_input PROTO((void *, char *, int, int, int *));
  449. static int socket_buffer_output PROTO((void *, const char *, int, int *));
  450. static int socket_buffer_flush PROTO((void *));
  451.  
  452. /* Create a buffer based on a socket.  */
  453.  
  454. static struct buffer *
  455. socket_buffer_initialize (socket, input, memory)
  456.      int socket;
  457.      int input;
  458.      void (*memory) PROTO((struct buffer *));
  459. {
  460.     struct socket_buffer *n;
  461.  
  462.     n = (struct socket_buffer *) xmalloc (sizeof *n);
  463.     n->socket = socket;
  464.     return buf_initialize (input ? socket_buffer_input : NULL,
  465.                input ? NULL : socket_buffer_output,
  466.                input ? NULL : socket_buffer_flush,
  467.                (int (*) PROTO((void *, int))) NULL,
  468.                (int (*) PROTO((void *))) NULL,
  469.                memory,
  470.                n);
  471. }
  472.  
  473. /* The buffer input function for a buffer built on a socket.  */
  474.  
  475. static int
  476. socket_buffer_input (closure, data, need, size, got)
  477.      void *closure;
  478.      char *data;
  479.      int need;
  480.      int size;
  481.      int *got;
  482. {
  483.     struct socket_buffer *sb = (struct socket_buffer *) closure;
  484.     int nbytes;
  485.  
  486.     /* I believe that the recv function gives us exactly the semantics
  487.        we want.  If there is a message, it returns immediately with
  488.        whatever it could get.  If there is no message, it waits until
  489.        one comes in.  In other words, it is not like read, which in
  490.        blocking mode normally waits until all the requested data is
  491.        available.  */
  492.  
  493.     *got = 0;
  494.  
  495.     while (need > 0)
  496.     {
  497.     nbytes = recv (sb->socket, data, size, 0);
  498.     if (nbytes < 0)
  499.         error (1, errno, "reading from server");
  500.     need -= nbytes;
  501.     size -= nbytes;
  502.     data += nbytes;
  503.     *got += nbytes;
  504.     }
  505.  
  506.     return 0;
  507. }
  508.  
  509. /* The buffer output function for a buffer built on a socket.  */
  510.  
  511. static int
  512. socket_buffer_output (closure, data, have, wrote)
  513.      void *closure;
  514.      const char *data;
  515.      int have;
  516.      int *wrote;
  517. {
  518.     struct socket_buffer *sb = (struct socket_buffer *) closure;
  519.  
  520.     *wrote = have;
  521.  
  522. #ifdef VMS
  523.     /* send() blocks under VMS */
  524.     if (send (sb->socket, data, have, 0) < 0)
  525.     error (1, errno, "writing to server socket");
  526. #else /* VMS */
  527.     while (have > 0)
  528.     {
  529.     int nbytes;
  530.  
  531.     nbytes = send (sb->socket, data, have, 0);
  532.     if (nbytes < 0)
  533.         error (1, errno, "writing to server socket");
  534.  
  535.     have -= nbytes;
  536.     data += nbytes;
  537.     }
  538. #endif  /* VMS */
  539.  
  540.     return 0;
  541. }
  542.  
  543. /* The buffer flush function for a buffer built on a socket.  */
  544.  
  545. /*ARGSUSED*/
  546. static int
  547. socket_buffer_flush (closure)
  548.      void *closure;
  549. {
  550.     /* Nothing to do.  Sockets are always flushed.  */
  551.     return 0;
  552. }
  553.  
  554. #endif /* NO_SOCKET_TO_FD */
  555.  
  556. /*
  557.  * Read a line from the server.  Result does not include the terminating \n.
  558.  *
  559.  * Space for the result is malloc'd and should be freed by the caller.
  560.  *
  561.  * Returns number of bytes read.
  562.  */
  563. static int
  564. read_line (resultp)
  565.     char **resultp;
  566. {
  567.     int status;
  568.     char *result;
  569.     int len;
  570.  
  571.     status = buf_flush (to_server, 1);
  572.     if (status != 0)
  573.     error (1, status, "writing to server");
  574.  
  575.     status = buf_read_line (from_server, &result, &len);
  576.     if (status != 0)
  577.     {
  578.     if (status == -1)
  579.         error (1, 0, "end of file from server (consult above messages if any)");
  580.     else if (status == -2)
  581.         error (1, 0, "out of memory");
  582.     else
  583.         error (1, status, "reading from server");
  584.     }
  585.  
  586.     if (resultp != NULL)
  587.     *resultp = result;
  588.     else
  589.     free (result);
  590.  
  591.     return len;
  592. }
  593.  
  594. #endif /* CLIENT_SUPPORT */
  595.  
  596.  
  597. #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
  598.  
  599. /*
  600.  * Zero if compression isn't supported or requested; non-zero to indicate
  601.  * a compression level to request from gzip.
  602.  */
  603. int gzip_level;
  604.  
  605. /*
  606.  * Level of compression to use when running gzip on a single file.
  607.  */
  608. int file_gzip_level;
  609.  
  610. int filter_through_gzip (fd, dir, level, pidp)
  611.     int fd, dir, level;
  612.     pid_t *pidp;
  613. {
  614.     static char buf[5] = "-";
  615.     static char *gzip_argv[3] = { "gzip", buf };
  616.  
  617.     sprintf (buf+1, "%d", level);
  618.     return filter_stream_through_program (fd, dir, &gzip_argv[0], pidp);
  619. }
  620.  
  621. int filter_through_gunzip (fd, dir, pidp)
  622.     int fd, dir;
  623.     pid_t *pidp;
  624. {
  625.     static char *gunzip_argv[3] = { "gzip", "-d" };
  626.     return filter_stream_through_program (fd, dir, &gunzip_argv[0], pidp);
  627. }
  628.  
  629. #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
  630.  
  631. #ifdef CLIENT_SUPPORT
  632.  
  633. /*
  634.  * The Repository for the top level of this command (not necessarily
  635.  * the CVSROOT, just the current directory at the time we do it).
  636.  */
  637. static char *toplevel_repos;
  638.  
  639. /* Working directory when we first started.  */
  640. char toplevel_wd[PATH_MAX];
  641.  
  642. static void
  643. handle_ok (args, len)
  644.     char *args;
  645.     int len;
  646. {
  647.     return;
  648. }
  649.  
  650. static void
  651. handle_error (args, len)
  652.     char *args;
  653.     int len;
  654. {
  655.     int something_printed;
  656.     
  657.     /*
  658.      * First there is a symbolic error code followed by a space, which
  659.      * we ignore.
  660.      */
  661.     char *p = strchr (args, ' ');
  662.     if (p == NULL)
  663.     {
  664.     error (0, 0, "invalid data from cvs server");
  665.     return;
  666.     }
  667.     ++p;
  668.     len -= p - args;
  669.     something_printed = 0;
  670.     for (; len > 0; --len)
  671.     {
  672.     something_printed = 1;
  673.     putc (*p++, stderr);
  674.     }
  675.     if (something_printed)
  676.     putc ('\n', stderr);
  677. }
  678.  
  679. static void
  680. handle_valid_requests (args, len)
  681.     char *args;
  682.     int len;
  683. {
  684.     char *p = args;
  685.     char *q;
  686.     struct request *rq;
  687.     do
  688.     {
  689.     q = strchr (p, ' ');
  690.     if (q != NULL)
  691.         *q++ = '\0';
  692.     for (rq = requests; rq->name != NULL; ++rq)
  693.     {
  694.         if (strcmp (rq->name, p) == 0)
  695.         break;
  696.     }
  697.     if (rq->name == NULL)
  698.         /*
  699.          * It is a request we have never heard of (and thus never
  700.          * will want to use).  So don't worry about it.
  701.          */
  702.         ;
  703.     else
  704.     {
  705.         if (rq->status == rq_enableme)
  706.         {
  707.         /*
  708.          * Server wants to know if we have this, to enable the
  709.          * feature.
  710.          */
  711.         send_to_server (rq->name, 0);
  712.                 send_to_server ("\012", 0);
  713.  
  714.         if (!strcmp("UseUnchanged",rq->name))
  715.             use_unchanged = 1;
  716.         }
  717.         else
  718.         rq->status = rq_supported;
  719.     }
  720.     p = q;
  721.     } while (q != NULL);
  722.     for (rq = requests; rq->name != NULL; ++rq)
  723.     {
  724.     if (rq->status == rq_essential)
  725.         error (1, 0, "request `%s' not supported by server", rq->name);
  726.     else if (rq->status == rq_optional)
  727.         rq->status = rq_not_supported;
  728.     }
  729. }
  730.  
  731. static int use_directory = -1;
  732.  
  733. static char *get_short_pathname PROTO((const char *));
  734.  
  735. static char *
  736. get_short_pathname (name)
  737.     const char *name;
  738. {
  739.     const char *retval;
  740.     if (use_directory)
  741.     return (char *) name;
  742.     if (strncmp (name, toplevel_repos, strlen (toplevel_repos)) != 0)
  743.     error (1, 0, "server bug: name `%s' doesn't specify file in `%s'",
  744.            name, toplevel_repos);
  745.     retval = name + strlen (toplevel_repos) + 1;
  746.     if (retval[-1] != '/')
  747.     error (1, 0, "server bug: name `%s' doesn't specify file in `%s'",
  748.            name, toplevel_repos);
  749.     return (char *) retval;
  750. }
  751.  
  752. /* This variable holds the result of Entries_Open, so that we can
  753.    close Entries_Close on it when we move on to a new directory, or
  754.    when we finish.  */
  755. static List *last_entries;
  756.  
  757. /*
  758.  * Do all the processing for PATHNAME, where pathname consists of the
  759.  * repository and the filename.  The parameters we pass to FUNC are:
  760.  * DATA is just the DATA parameter which was passed to
  761.  * call_in_directory; ENT_LIST is a pointer to an entries list (which
  762.  * we manage the storage for); SHORT_PATHNAME is the pathname of the
  763.  * file relative to the (overall) directory in which the command is
  764.  * taking place; and FILENAME is the filename portion only of
  765.  * SHORT_PATHNAME.  When we call FUNC, the curent directory points to
  766.  * the directory portion of SHORT_PATHNAME.  */
  767.  
  768. static char *last_dir_name;
  769.  
  770. static void
  771. call_in_directory (pathname, func, data)
  772.     char *pathname;
  773.     void (*func) PROTO((char *data, List *ent_list, char *short_pathname,
  774.               char *filename));
  775.     char *data;
  776. {
  777.     char *dir_name;
  778.     char *filename;
  779.     /* Just the part of pathname relative to toplevel_repos.  */
  780.     char *short_pathname = get_short_pathname (pathname);
  781.     char *p;
  782.  
  783.     /*
  784.      * Do the whole descent in parallel for the repositories, so we
  785.      * know what to put in CVS/Repository files.  I'm not sure the
  786.      * full hair is necessary since the server does a similar
  787.      * computation; I suspect that we only end up creating one
  788.      * directory at a time anyway.
  789.      *
  790.      * Also note that we must *only* worry about this stuff when we
  791.      * are creating directories; `cvs co foo/bar; cd foo/bar; cvs co
  792.      * CVSROOT; cvs update' is legitimate, but in this case
  793.      * foo/bar/CVSROOT/CVS/Repository is not a subdirectory of
  794.      * foo/bar/CVS/Repository.
  795.      */
  796.     char *reposname;
  797.     char *short_repos;
  798.     char *reposdirname;
  799.     char *rdirp;
  800.     int reposdirname_absolute;
  801.  
  802.     reposname = NULL;
  803.     if (use_directory)
  804.     read_line (&reposname);
  805.  
  806.     reposdirname_absolute = 0;
  807.     if (reposname != NULL)
  808.     {
  809.     if (strncmp (reposname, toplevel_repos, strlen (toplevel_repos)) != 0)
  810.     {
  811.         reposdirname_absolute = 1;
  812.         short_repos = reposname;
  813.     }
  814.     else
  815.     {
  816.         short_repos = reposname + strlen (toplevel_repos) + 1;
  817.         if (short_repos[-1] != '/')
  818.         {
  819.         reposdirname_absolute = 1;
  820.         short_repos = reposname;
  821.         }
  822.     }
  823.     }
  824.     else
  825.     {
  826.     short_repos = short_pathname;
  827.     }
  828.     reposdirname = xstrdup (short_repos);
  829.     p = strrchr (reposdirname, '/');
  830.     if (p == NULL)
  831.     {
  832.     reposdirname = xrealloc (reposdirname, 2);
  833.     reposdirname[0] = '.'; reposdirname[1] = '\0';
  834.     }
  835.     else
  836.     *p = '\0';
  837.  
  838.     dir_name = xstrdup (short_pathname);
  839.     p = strrchr (dir_name, '/');
  840.     if (p == NULL)
  841.     {
  842.     dir_name = xrealloc (dir_name, 2);
  843.     dir_name[0] = '.'; dir_name[1] = '\0';
  844.     }
  845.     else
  846.     *p = '\0';
  847.     if (client_prune_dirs)
  848.     add_prune_candidate (dir_name);
  849.  
  850.     filename = strrchr (short_repos, '/');
  851.     if (filename == NULL)
  852.     filename = short_repos;
  853.     else
  854.     ++filename;
  855.  
  856.     if (reposname != NULL)
  857.     {
  858.     /* This is the use_directory case.  */
  859.  
  860.     short_pathname = xmalloc (strlen (pathname) + strlen (filename) + 5);
  861.     strcpy (short_pathname, pathname);
  862.     strcat (short_pathname, filename);
  863.     }
  864.  
  865.     if (last_dir_name == NULL
  866.     || strcmp (last_dir_name, dir_name) != 0)
  867.     {
  868.     int newdir;
  869.  
  870.     if (strcmp (command_name, "export") != 0)
  871.         if (last_entries)
  872.         Entries_Close (last_entries);
  873.  
  874.     if (last_dir_name)
  875.         free (last_dir_name);
  876.     last_dir_name = dir_name;
  877.  
  878.     if (toplevel_wd[0] == '\0')
  879.         if (getwd (toplevel_wd) == NULL)
  880.         error (1, 0,
  881.                "could not get working directory: %s", toplevel_wd);
  882.  
  883.     if ( CVS_CHDIR (toplevel_wd) < 0)
  884.         error (1, errno, "could not chdir to %s", toplevel_wd);
  885.     newdir = 0;
  886.     if ( CVS_CHDIR (dir_name) < 0)
  887.     {
  888.         char *dir;
  889.         char *dirp;
  890.         
  891.         if (! existence_error (errno))
  892.         error (1, errno, "could not chdir to %s", dir_name);
  893.         
  894.         /* Directory does not exist, we need to create it.  */
  895.         newdir = 1;
  896.         dir = xmalloc (strlen (dir_name) + 1);
  897.         dirp = dir_name;
  898.         rdirp = reposdirname;
  899.  
  900.         /* This algorithm makes nested directories one at a time
  901.                and create CVS administration files in them.  For
  902.                example, we're checking out foo/bar/baz from the
  903.                repository:
  904.  
  905.            1) create foo, point CVS/Repository to <root>/foo
  906.            2)     .. foo/bar                   .. <root>/foo/bar
  907.            3)     .. foo/bar/baz               .. <root>/foo/bar/baz
  908.            
  909.            As you can see, we're just stepping along DIR_NAME (with
  910.            DIRP) and REPOSDIRNAME (with RDIRP) respectively.
  911.  
  912.            We need to be careful when we are checking out a
  913.            module, however, since DIR_NAME and REPOSDIRNAME are not
  914.            going to be the same.  Since modules will not have any
  915.            slashes in their names, we should watch the output of
  916.            STRCHR to decide whether or not we should use STRCHR on
  917.            the RDIRP.  That is, if we're down to a module name,
  918.            don't keep picking apart the repository directory name.  */
  919.  
  920.         do
  921.         {
  922.         dirp = strchr (dirp, '/');
  923.         if (dirp)
  924.         {
  925.             strncpy (dir, dir_name, dirp - dir_name);
  926.             dir[dirp - dir_name] = '\0';
  927.             /* Skip the slash.  */
  928.             ++dirp;
  929.             if (rdirp == NULL)
  930.             error (0, 0,
  931.                    "internal error: repository string too short.");
  932.             else
  933.             rdirp = strchr (rdirp, '/');
  934.         }
  935.         else
  936.         {
  937.             /* If there are no more slashes in the dir name,
  938.                        we're down to the most nested directory -OR- to
  939.                        the name of a module.  In the first case, we
  940.                        should be down to a DIRP that has no slashes,
  941.                        so it won't help/hurt to do another STRCHR call
  942.                        on DIRP.  It will definitely hurt, however, if
  943.                        we're down to a module name, since a module
  944.                        name can point to a nested directory (that is,
  945.                        DIRP will still have slashes in it.  Therefore,
  946.                        we should set it to NULL so the routine below
  947.                        copies the contents of REMOTEDIRNAME onto the
  948.                        root repository directory (does this if rdirp
  949.                        is set to NULL, because we used to do an extra
  950.                        STRCHR call here). */
  951.  
  952.             rdirp = NULL;
  953.             strcpy (dir, dir_name);
  954.         }
  955.  
  956.         if (mkdir_if_needed (dir))
  957.         {
  958.             /* It already existed, fine.  Just keep going.  */
  959.         }
  960.         else if (strcmp (command_name, "export") == 0)
  961.             /* Don't create CVSADM directories if this is export.  */
  962.             ;
  963.         else
  964.         {
  965.             /*
  966.              * Put repository in CVS/Repository.  For historical
  967.              * (pre-CVS/Root) reasons, this is an absolute pathname,
  968.              * but what really matters is the part of it which is
  969.              * relative to cvsroot.
  970.              */
  971.             char *repo;
  972.             char *r, *b;
  973.  
  974.             repo = xmalloc (strlen (reposdirname)
  975.                     + strlen (toplevel_repos)
  976.                     + 80);
  977.             if (reposdirname_absolute)
  978.             r = repo;
  979.             else
  980.             {
  981.             strcpy (repo, toplevel_repos);
  982.             strcat (repo, "/");
  983.             r = repo + strlen (repo);
  984.             }
  985.  
  986.             if (rdirp)
  987.             {
  988.             strncpy (r, reposdirname, rdirp - reposdirname);
  989.             r[rdirp - reposdirname] = '\0';
  990.             }
  991.             else
  992.             strcpy (r, reposdirname);
  993.  
  994.             Create_Admin (dir, dir, repo,
  995.                   (char *)NULL, (char *)NULL);
  996.             free (repo);
  997.  
  998.             b = strrchr (dir, '/');
  999.             if (b == NULL)
  1000.             Subdir_Register ((List *) NULL, (char *) NULL, dir);
  1001.             else
  1002.             {
  1003.             *b = '\0';
  1004.             Subdir_Register ((List *) NULL, dir, b + 1);
  1005.             *b = '/';
  1006.             }
  1007.         }
  1008.  
  1009.         if (rdirp != NULL)
  1010.         {
  1011.             /* Skip the slash.  */
  1012.             ++rdirp;
  1013.         }
  1014.  
  1015.         } while (dirp != NULL);
  1016.         free (dir);
  1017.         /* Now it better work.  */
  1018.         if ( CVS_CHDIR (dir_name) < 0)
  1019.         error (1, errno, "could not chdir to %s", dir_name);
  1020.     }
  1021.  
  1022.     /* If the modules file has an entry for the entire tree (e.g.,
  1023.            ``world -a .''), we may need to create the CVS directory
  1024.            specially in this working directory.  */
  1025.     if (strcmp (dir_name, ".") == 0
  1026.         && ! isdir (CVSADM))
  1027.     {
  1028.         char *repo;
  1029.         char *r;
  1030.  
  1031.         newdir = 1;
  1032.  
  1033.         repo = xmalloc (strlen (reposdirname)
  1034.                 + strlen (toplevel_repos)
  1035.                 + 10);
  1036.         if (reposdirname_absolute)
  1037.             r = repo;
  1038.         else
  1039.         {
  1040.             strcpy (repo, toplevel_repos);
  1041.         r = repo + strlen (repo);
  1042.         *r++ = '/';
  1043.         }
  1044.  
  1045.         strcpy (r, reposdirname);
  1046.  
  1047.         r += strlen (r);
  1048.         if (r[-1] != '.' || r[-2] != '/')
  1049.             strcpy (r, "/.");
  1050.  
  1051.         Create_Admin (dir_name, dir_name, repo, (char *) NULL,
  1052.               (char *) NULL);
  1053.  
  1054.         free (repo);
  1055.     }
  1056.  
  1057.     if (strcmp (command_name, "export") != 0)
  1058.     {
  1059.         last_entries = Entries_Open (0);
  1060.  
  1061.         /* If this is a newly created directory, we will record
  1062.            all subdirectory information, so call Subdirs_Known in
  1063.            case there are no subdirectories.  If this is not a
  1064.            newly created directory, it may be an old working
  1065.            directory from before we recorded subdirectory
  1066.            information in the Entries file.  We force a search for
  1067.            all subdirectories now, to make sure our subdirectory
  1068.            information is up to date.  If the Entries file does
  1069.            record subdirectory information, then this call only
  1070.            does list manipulation.  */
  1071.         if (newdir)
  1072.         Subdirs_Known (last_entries);
  1073.         else
  1074.         {
  1075.         List *dirlist;
  1076.  
  1077.         dirlist = Find_Directories ((char *) NULL, W_LOCAL,
  1078.                         last_entries);
  1079.         dellist (&dirlist);
  1080.         }
  1081.     }
  1082.     }
  1083.     else
  1084.     free (dir_name);
  1085.     free (reposdirname);
  1086.     (*func) (data, last_entries, short_pathname, filename);
  1087.     if (reposname != NULL)
  1088.     {
  1089.     free (short_pathname);
  1090.     free (reposname);
  1091.     }
  1092. }
  1093.  
  1094. static void
  1095. copy_a_file (data, ent_list, short_pathname, filename)
  1096.     char *data;
  1097.     List *ent_list;
  1098.     char *short_pathname;
  1099.     char *filename;
  1100. {
  1101.     char *newname;
  1102. #ifdef USE_VMS_FILENAMES
  1103.     char *p;
  1104. #endif
  1105.  
  1106.     read_line (&newname);
  1107.  
  1108. #ifdef USE_VMS_FILENAMES
  1109.     /* Mogrify the filename so VMS is happy with it. */
  1110.     for(p = newname; *p; p++)
  1111.        if(*p == '.' || *p == '#') *p = '_';
  1112. #endif
  1113.  
  1114.     copy_file (filename, newname);
  1115.     free (newname);
  1116. }
  1117.  
  1118. static void
  1119. handle_copy_file (args, len)
  1120.     char *args;
  1121.     int len;
  1122. {
  1123.     call_in_directory (args, copy_a_file, (char *)NULL);
  1124. }
  1125.  
  1126.  
  1127. static void read_counted_file PROTO ((char *, char *));
  1128.  
  1129. /* Read from the server the count for the length of a file, then read
  1130.    the contents of that file and write them to FILENAME.  FULLNAME is
  1131.    the name of the file for use in error messages.  FIXME-someday:
  1132.    extend this to deal with compressed files and make update_entries
  1133.    use it.  On error, gives a fatal error.  */
  1134. static void
  1135. read_counted_file (filename, fullname)
  1136.     char *filename;
  1137.     char *fullname;
  1138. {
  1139.     char *size_string;
  1140.     size_t size;
  1141.     char *buf;
  1142.  
  1143.     /* Pointers in buf to the place to put data which will be read,
  1144.        and the data which needs to be written, respectively.  */
  1145.     char *pread;
  1146.     char *pwrite;
  1147.     /* Number of bytes left to read and number of bytes in buf waiting to
  1148.        be written, respectively.  */
  1149.     size_t nread;
  1150.     size_t nwrite;
  1151.  
  1152.     FILE *fp;
  1153.  
  1154.     read_line (&size_string);
  1155.     if (size_string[0] == 'z')
  1156.     error (1, 0, "\
  1157. protocol error: compressed files not supported for that operation");
  1158.     /* FIXME: should be doing more error checking, probably.  Like using
  1159.        strtoul and making sure we used up the whole line.  */
  1160.     size = atoi (size_string);
  1161.     free (size_string);
  1162.  
  1163.     /* A more sophisticated implementation would use only a limited amount
  1164.        of buffer space (8K perhaps), and read that much at a time.  We allocate
  1165.        a buffer for the whole file only to make it easy to keep track what
  1166.        needs to be read and written.  */
  1167.     buf = xmalloc (size);
  1168.  
  1169.     /* FIXME-someday: caller should pass in a flag saying whether it
  1170.        is binary or not.  I haven't carefully looked into whether
  1171.        CVS/Template files should use local text file conventions or
  1172.        not.  */
  1173.     fp = CVS_FOPEN (filename, "wb");
  1174.     if (fp == NULL)
  1175.     error (1, errno, "cannot write %s", fullname);
  1176.     nread = size;
  1177.     nwrite = 0;
  1178.     pread = buf;
  1179.     pwrite = buf;
  1180.     while (nread > 0 || nwrite > 0)
  1181.     {
  1182.     size_t n;
  1183.  
  1184.     if (nread > 0)
  1185.     {
  1186.         n = try_read_from_server (pread, nread);
  1187.         nread -= n;
  1188.         pread += n;
  1189.         nwrite += n;
  1190.     }
  1191.  
  1192.     if (nwrite > 0)
  1193.     {
  1194.         n = fwrite (pwrite, 1, nwrite, fp);
  1195.         if (ferror (fp))
  1196.         error (1, errno, "cannot write %s", fullname);
  1197.         nwrite -= n;
  1198.         pwrite += n;
  1199.     }
  1200.     }
  1201.     free (buf);
  1202.     if (fclose (fp) < 0)
  1203.     error (1, errno, "cannot close %s", fullname);
  1204. }
  1205.  
  1206. /*
  1207.  * The time stamp of the last file we registered.
  1208.  */
  1209. static time_t last_register_time;
  1210.  
  1211. /*
  1212.  * The Checksum response gives the checksum for the file transferred
  1213.  * over by the next Updated, Merged or Patch response.  We just store
  1214.  * it here, and then check it in update_entries.
  1215.  */
  1216.  
  1217. static int stored_checksum_valid;
  1218. static unsigned char stored_checksum[16];
  1219.  
  1220. static void
  1221. handle_checksum (args, len)
  1222.     char *args;
  1223.     int len;
  1224. {
  1225.     char *s;
  1226.     char buf[3];
  1227.     int i;
  1228.  
  1229.     if (stored_checksum_valid)
  1230.         error (1, 0, "Checksum received before last one was used");
  1231.  
  1232.     s = args;
  1233.     buf[2] = '\0';
  1234.     for (i = 0; i < 16; i++)
  1235.     {
  1236.         char *bufend;
  1237.  
  1238.     buf[0] = *s++;
  1239.     buf[1] = *s++;
  1240.     stored_checksum[i] = (char) strtol (buf, &bufend, 16);
  1241.     if (bufend != buf + 2)
  1242.         break;
  1243.     }
  1244.  
  1245.     if (i < 16 || *s != '\0')
  1246.         error (1, 0, "Invalid Checksum response: `%s'", args);
  1247.  
  1248.     stored_checksum_valid = 1;
  1249. }
  1250.  
  1251. static int stored_mode_valid;
  1252. static char *stored_mode;
  1253.  
  1254. static void handle_mode PROTO ((char *, int));
  1255.  
  1256. static void
  1257. handle_mode (args, len)
  1258.     char *args;
  1259.     int len;
  1260. {
  1261.     if (stored_mode_valid)
  1262.     error (1, 0, "protocol error: duplicate Mode");
  1263.     if (stored_mode != NULL)
  1264.     free (stored_mode);
  1265.     stored_mode = xstrdup (args);
  1266.     stored_mode_valid = 1;
  1267. }
  1268.  
  1269. /*
  1270.  * If we receive a patch, but the patch program fails to apply it, we
  1271.  * want to request the original file.  We keep a list of files whose
  1272.  * patches have failed.
  1273.  */
  1274.  
  1275. char **failed_patches;
  1276. int failed_patches_count;
  1277.  
  1278. struct update_entries_data
  1279. {
  1280.     enum {
  1281.       /*
  1282.        * We are just getting an Entries line; the local file is
  1283.        * correct.
  1284.        */
  1285.       UPDATE_ENTRIES_CHECKIN,
  1286.       /* We are getting the file contents as well.  */
  1287.       UPDATE_ENTRIES_UPDATE,
  1288.       /*
  1289.        * We are getting a patch against the existing local file, not
  1290.        * an entire new file.
  1291.        */
  1292.       UPDATE_ENTRIES_PATCH
  1293.     } contents;
  1294.  
  1295.     enum {
  1296.     /* We are replacing an existing file.  */
  1297.     UPDATE_ENTRIES_EXISTING,
  1298.     /* We are creating a new file.  */
  1299.     UPDATE_ENTRIES_NEW,
  1300.     /* We don't know whether it is existing or new.  */
  1301.     UPDATE_ENTRIES_EXISTING_OR_NEW
  1302.     } existp;
  1303.  
  1304.     /*
  1305.      * String to put in the timestamp field or NULL to use the timestamp
  1306.      * of the file.
  1307.      */
  1308.     char *timestamp;
  1309. };
  1310.  
  1311. /* Update the Entries line for this file.  */
  1312. static void
  1313. update_entries (data_arg, ent_list, short_pathname, filename)
  1314.     char *data_arg;
  1315.     List *ent_list;
  1316.     char *short_pathname;
  1317.     char *filename;
  1318. {
  1319.     char *entries_line;
  1320.     struct update_entries_data *data = (struct update_entries_data *)data_arg;
  1321.  
  1322.     char *cp;
  1323.     char *user;
  1324.     char *vn;
  1325.     /* Timestamp field.  Always empty according to the protocol.  */
  1326.     char *ts;
  1327.     char *options;
  1328.     char *tag;
  1329.     char *date;
  1330.     char *tag_or_date;
  1331.     char *scratch_entries;
  1332.     int bin;
  1333.  
  1334.     read_line (&entries_line);
  1335.  
  1336.     /*
  1337.      * Parse the entries line.
  1338.      */
  1339.     if (strcmp (command_name, "export") != 0)
  1340.     {
  1341.     scratch_entries = xstrdup (entries_line);
  1342.  
  1343.     if (scratch_entries[0] != '/')
  1344.         error (1, 0, "bad entries line `%s' from server", entries_line);
  1345.     user = scratch_entries + 1;
  1346.     if ((cp = strchr (user, '/')) == NULL)
  1347.         error (1, 0, "bad entries line `%s' from server", entries_line);
  1348.     *cp++ = '\0';
  1349.     vn = cp;
  1350.     if ((cp = strchr (vn, '/')) == NULL)
  1351.         error (1, 0, "bad entries line `%s' from server", entries_line);
  1352.     *cp++ = '\0';
  1353.     
  1354.     ts = cp;
  1355.     if ((cp = strchr (ts, '/')) == NULL)
  1356.         error (1, 0, "bad entries line `%s' from server", entries_line);
  1357.     *cp++ = '\0';
  1358.     options = cp;
  1359.     if ((cp = strchr (options, '/')) == NULL)
  1360.         error (1, 0, "bad entries line `%s' from server", entries_line);
  1361.     *cp++ = '\0';
  1362.     tag_or_date = cp;
  1363.  
  1364.     /* If a slash ends the tag_or_date, ignore everything after it.  */
  1365.     cp = strchr (tag_or_date, '/');
  1366.     if (cp != NULL)
  1367.         *cp = '\0';
  1368.     tag = (char *) NULL;
  1369.     date = (char *) NULL;
  1370.     if (*tag_or_date == 'T')
  1371.         tag = tag_or_date + 1;
  1372.     else if (*tag_or_date == 'D')
  1373.         date = tag_or_date + 1;
  1374.     }
  1375.     else
  1376.     /* For cvs export, assume it is a text file.  FIXME: This is
  1377.        broken behavior--we should be having the server tell us
  1378.        whether it is text or binary and dealing accordingly.  I
  1379.        think maybe we can parse the entries line, get the options,
  1380.        and then ignore the entries line otherwise, but I haven't
  1381.        checked to see whether the server sends the entries line
  1382.        correctly in this case.  */
  1383.     options = NULL;
  1384.  
  1385.     if (data->contents == UPDATE_ENTRIES_UPDATE
  1386.     || data->contents == UPDATE_ENTRIES_PATCH)
  1387.     {
  1388.     char *size_string;
  1389.     char *mode_string;
  1390.     int size;
  1391.     int fd;
  1392.     char *buf;
  1393.     char *temp_filename;
  1394.     int use_gzip, gzip_status;
  1395.     pid_t gzip_pid = 0;
  1396.  
  1397.     read_line (&mode_string);
  1398.     
  1399.     read_line (&size_string);
  1400.     if (size_string[0] == 'z')
  1401.     {
  1402.         use_gzip = 1;
  1403.         size = atoi (size_string+1);
  1404.     }
  1405.     else
  1406.     {
  1407.         use_gzip = 0;
  1408.         size = atoi (size_string);
  1409.     }
  1410.     free (size_string);
  1411.  
  1412.     /* Note that checking this separately from writing the file is
  1413.        a race condition: if the existing or lack thereof of the
  1414.        file changes between now and the actually calls which
  1415.        operate on it, we lose.  However (a) there are so many
  1416.        cases, I'm reluctant to try to fix them all, (b) in some
  1417.        cases the system might not even have a system call which
  1418.        does the right thing, and (c) it isn't clear this needs to
  1419.        work.  */
  1420.     if (data->existp == UPDATE_ENTRIES_EXISTING
  1421.         && !isfile (filename))
  1422.         /* Emit a warning and update the file anyway.  */
  1423.         error (0, 0, "warning: %s unexpectedly disappeared",
  1424.            short_pathname);
  1425.  
  1426.     if (data->existp == UPDATE_ENTRIES_NEW
  1427.         && isfile (filename))
  1428.     {
  1429.         /* Emit a warning and refuse to update the file; we don't want
  1430.            to clobber a user's file.  */
  1431.         size_t nread;
  1432.         size_t toread;
  1433.  
  1434.         /* size should be unsigned, but until we get around to fixing that, work around
  1435.            it.  */
  1436.         size_t usize = size;
  1437.  
  1438.         char buf[8192];
  1439.  
  1440.         error (0, 0, "move away %s; it is in the way", short_pathname);
  1441.  
  1442.         /* Now read and discard the file contents.  */
  1443.         nread = 0;
  1444.         while (nread < usize)
  1445.         {
  1446.         toread = usize - nread;
  1447.         if (toread > sizeof buf)
  1448.             toread = sizeof buf;
  1449.  
  1450.         nread += try_read_from_server (buf, toread);
  1451.         if (nread == usize)
  1452.             break;
  1453.         }
  1454.  
  1455.         free (mode_string);
  1456.         free (entries_line);
  1457.         return;
  1458.     }
  1459.  
  1460.     temp_filename = xmalloc (strlen (filename) + 80);
  1461. #ifdef USE_VMS_FILENAMES
  1462.         /* A VMS rename of "blah.dat" to "foo" to implies a
  1463.            destination of "foo.dat" which is unfortinate for CVS */
  1464.        sprintf (temp_filename, "%s_new_", filename);
  1465. #else
  1466. #ifdef _POSIX_NO_TRUNC
  1467.     sprintf (temp_filename, ".new.%.9s", filename);
  1468. #else /* _POSIX_NO_TRUNC */
  1469.     sprintf (temp_filename, ".new.%s", filename);
  1470. #endif /* _POSIX_NO_TRUNC */
  1471. #endif /* USE_VMS_FILENAMES */
  1472.     buf = xmalloc (size);
  1473.  
  1474.         /* Some systems, like OS/2 and Windows NT, end lines with CRLF
  1475.            instead of just LF.  Format translation is done in the C
  1476.            library I/O funtions.  Here we tell them whether or not to
  1477.            convert -- if this file is marked "binary" with the RCS -kb
  1478.            flag, then we don't want to convert, else we do (because
  1479.            CVS assumes text files by default). */
  1480.  
  1481.     if (options)
  1482.         bin = !(strcmp (options, "-kb"));
  1483.     else
  1484.         bin = 0;
  1485.  
  1486.         fd = CVS_OPEN (temp_filename,
  1487.                    O_WRONLY | O_CREAT | O_TRUNC | (bin ? OPEN_BINARY : 0),
  1488.                    0777);
  1489.  
  1490.     if (fd < 0)
  1491.         error (1, errno, "writing %s", short_pathname);
  1492.  
  1493.     if (use_gzip)
  1494.         fd = filter_through_gunzip (fd, 0, &gzip_pid);
  1495.  
  1496.     if (size > 0)
  1497.     {
  1498.           read_from_server (buf, size);
  1499.         
  1500.           if (write (fd, buf, size) != size)
  1501.             error (1, errno, "writing %s", short_pathname);
  1502.     }
  1503.  
  1504.     if (close (fd) < 0)
  1505.         error (1, errno, "writing %s", short_pathname);
  1506.     if (gzip_pid > 0)
  1507.     {
  1508.         if (waitpid (gzip_pid, &gzip_status, 0) == -1)
  1509.         error (1, errno, "waiting for gzip process %ld",
  1510.                (long) gzip_pid);
  1511.         else if (gzip_status != 0)
  1512.         error (1, 0, "gzip process exited %d", gzip_status);
  1513.     }
  1514.  
  1515.     gzip_pid = -1;
  1516.  
  1517.     /* Since gunzip writes files without converting LF to CRLF
  1518.        (a reasonable behavior), we now have a patch file in LF
  1519.        format.  Leave the file as is if we're just going to feed
  1520.        it to patch; patch can handle it.  However, if it's the
  1521.        final source file, convert it.  */
  1522.  
  1523.     if (data->contents == UPDATE_ENTRIES_UPDATE)
  1524.     {
  1525. #ifdef LINES_CRLF_TERMINATED
  1526.  
  1527.             /* `bin' is non-zero iff `options' contains "-kb", meaning
  1528.                 treat this file as binary. */
  1529.  
  1530.         if (use_gzip && (! bin))
  1531.         {
  1532.             convert_file (temp_filename, O_RDONLY | OPEN_BINARY,
  1533.                       filename, O_WRONLY | O_CREAT | O_TRUNC);
  1534.             if ( CVS_UNLINK (temp_filename) < 0)
  1535.                 error (0, errno, "warning: couldn't delete %s",
  1536.                            temp_filename);
  1537.         }
  1538.         else
  1539. #ifdef BROKEN_READWRITE_CONVERSION
  1540.         {
  1541.         /* If only stdio, not open/write/etc., do text/binary
  1542.            conversion, use convert_file which can compensate
  1543.            (FIXME: we could just use stdio instead which would
  1544.            avoid the whole problem).  */
  1545.         if (!bin)
  1546.         {
  1547.             convert_file (temp_filename, O_RDONLY | OPEN_BINARY,
  1548.                   filename, O_WRONLY | O_CREAT | O_TRUNC);
  1549.             if (CVS_UNLINK (temp_filename) < 0)
  1550.             error (0, errno, "warning: couldn't delete %s",
  1551.                    temp_filename);
  1552.         }
  1553.         else
  1554.             rename_file (temp_filename, filename);
  1555.         }
  1556. #else
  1557.         rename_file (temp_filename, filename);
  1558. #endif
  1559.             
  1560. #else /* ! LINES_CRLF_TERMINATED */
  1561.         rename_file (temp_filename, filename);
  1562. #endif /* LINES_CRLF_TERMINATED */
  1563.     }
  1564.     else
  1565.     {
  1566.         int retcode;
  1567.         char backup[PATH_MAX];
  1568.         struct stat s;
  1569.  
  1570.         (void) sprintf (backup, "%s~", filename);
  1571.         (void) unlink_file (backup);
  1572.         if (!isfile (filename))
  1573.             error (1, 0, "patch original file %s does not exist",
  1574.                short_pathname);
  1575.         if ( CVS_STAT (temp_filename, &s) < 0)
  1576.             error (1, 1, "can't stat patch file %s", temp_filename);
  1577.         if (s.st_size == 0)
  1578.             retcode = 0;
  1579.         else
  1580.         {
  1581.             run_setup ("%s -f -s -b ~ %s %s", PATCH_PROGRAM,
  1582.                filename, temp_filename);
  1583.         retcode = run_exec (DEVNULL, RUN_TTY, RUN_TTY, RUN_NORMAL);
  1584.         }
  1585.         /* FIXME: should we really be silently ignoring errors?  */
  1586.         (void) unlink_file (temp_filename);
  1587.         if (retcode == 0)
  1588.         {
  1589.         /* FIXME: should we really be silently ignoring errors?  */
  1590.         (void) unlink_file (backup);
  1591.         }
  1592.         else
  1593.         {
  1594.             int old_errno = errno;
  1595.         char *path_tmp;
  1596.  
  1597.             if (isfile (backup))
  1598.             rename_file (backup, filename);
  1599.        
  1600.         /* Get rid of the patch reject file.  */
  1601.         path_tmp = xmalloc (strlen (filename) + 10);
  1602.         strcpy (path_tmp, filename);
  1603.         strcat (path_tmp, ".rej");
  1604.         /* FIXME: should we really be silently ignoring errors?  */
  1605.         (void) unlink_file (path_tmp);
  1606.         free (path_tmp);
  1607.  
  1608.         /* Save this file to retrieve later.  */
  1609.         failed_patches =
  1610.             (char **) xrealloc ((char *) failed_patches,
  1611.                     ((failed_patches_count + 1)
  1612.                      * sizeof (char *)));
  1613.         failed_patches[failed_patches_count] =
  1614.             xstrdup (short_pathname);
  1615.         ++failed_patches_count;
  1616.  
  1617.         error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
  1618.                "could not patch %s%s", filename,
  1619.                retcode == -1 ? "" : "; will refetch");
  1620.  
  1621.         stored_checksum_valid = 0;
  1622.  
  1623.         return;
  1624.         }
  1625.     }
  1626.     free (temp_filename);
  1627.  
  1628.     if (stored_checksum_valid)
  1629.     {
  1630.         FILE *e;
  1631.         struct MD5Context context;
  1632.         unsigned char buf[8192];
  1633.         unsigned len;
  1634.         unsigned char checksum[16];
  1635.  
  1636.         /*
  1637.          * Compute the MD5 checksum.  This will normally only be
  1638.          * used when receiving a patch, so we always compute it
  1639.          * here on the final file, rather than on the received
  1640.          * data.
  1641.          *
  1642.          * Note that if the file is a text file, we should read it
  1643.          * here using text mode, so its lines will be terminated the same
  1644.          * way they were transmitted.
  1645.          */
  1646.         e = CVS_FOPEN (filename, "r");
  1647.         if (e == NULL)
  1648.             error (1, errno, "could not open %s", short_pathname);
  1649.  
  1650.         MD5Init (&context);
  1651.         while ((len = fread (buf, 1, sizeof buf, e)) != 0)
  1652.         MD5Update (&context, buf, len);
  1653.         if (ferror (e))
  1654.         error (1, errno, "could not read %s", short_pathname);
  1655.         MD5Final (checksum, &context);
  1656.  
  1657.         fclose (e);
  1658.  
  1659.         stored_checksum_valid = 0;
  1660.  
  1661.         if (memcmp (checksum, stored_checksum, 16) != 0)
  1662.         {
  1663.             if (data->contents != UPDATE_ENTRIES_PATCH)
  1664.             error (1, 0, "checksum failure on %s",
  1665.                short_pathname);
  1666.  
  1667.         error (0, 0,
  1668.                "checksum failure after patch to %s; will refetch",
  1669.                short_pathname);
  1670.  
  1671.         /* Save this file to retrieve later.  */
  1672.         failed_patches =
  1673.             (char **) xrealloc ((char *) failed_patches,
  1674.                     ((failed_patches_count + 1)
  1675.                      * sizeof (char *)));
  1676.         failed_patches[failed_patches_count] =
  1677.             xstrdup (short_pathname);
  1678.         ++failed_patches_count;
  1679.  
  1680.         return;
  1681.         }
  1682.     }
  1683.  
  1684.         {
  1685.         /* FIXME: we should be respecting the umask.  */
  1686.         int status = change_mode (filename, mode_string);
  1687.         if (status != 0)
  1688.         error (0, status, "cannot change mode of %s", short_pathname);
  1689.     }
  1690.  
  1691.     free (mode_string);
  1692.     free (buf);
  1693.     }
  1694.  
  1695.     if (stored_mode_valid)
  1696.     change_mode (filename, stored_mode);
  1697.     stored_mode_valid = 0;
  1698.  
  1699.     /*
  1700.      * Process the entries line.  Do this after we've written the file,
  1701.      * since we need the timestamp.
  1702.      */
  1703.     if (strcmp (command_name, "export") != 0)
  1704.     {
  1705.     char *local_timestamp;
  1706.     char *file_timestamp;
  1707.  
  1708.     (void) time (&last_register_time);
  1709.  
  1710.     local_timestamp = data->timestamp;
  1711.     if (local_timestamp == NULL || ts[0] == '+')
  1712.         file_timestamp = time_stamp (filename);
  1713.     else
  1714.         file_timestamp = NULL;
  1715.  
  1716.     /*
  1717.      * These special version numbers signify that it is not up to
  1718.      * date.  Create a dummy timestamp which will never compare
  1719.      * equal to the timestamp of the file.
  1720.      */
  1721.     if (vn[0] == '\0' || vn[0] == '0' || vn[0] == '-')
  1722.         local_timestamp = "dummy timestamp";
  1723.     else if (local_timestamp == NULL)
  1724.     {
  1725.         local_timestamp = file_timestamp;
  1726.         mark_up_to_date (filename);
  1727.     }
  1728.  
  1729.     Register (ent_list, filename, vn, local_timestamp,
  1730.           options, tag, date, ts[0] == '+' ? file_timestamp : NULL);
  1731.  
  1732.     if (file_timestamp)
  1733.         free (file_timestamp);
  1734.  
  1735.     free (scratch_entries);
  1736.     }
  1737.     free (entries_line);
  1738. }
  1739.  
  1740. static void
  1741. handle_checked_in (args, len)
  1742.     char *args;
  1743.     int len;
  1744. {
  1745.     struct update_entries_data dat;
  1746.     dat.contents = UPDATE_ENTRIES_CHECKIN;
  1747.     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
  1748.     dat.timestamp = NULL;
  1749.     call_in_directory (args, update_entries, (char *)&dat);
  1750. }
  1751.  
  1752. static void
  1753. handle_new_entry (args, len)
  1754.     char *args;
  1755.     int len;
  1756. {
  1757.     struct update_entries_data dat;
  1758.     dat.contents = UPDATE_ENTRIES_CHECKIN;
  1759.     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
  1760.     dat.timestamp = "dummy timestamp from new-entry";
  1761.     call_in_directory (args, update_entries, (char *)&dat);
  1762. }
  1763.  
  1764. static void
  1765. handle_updated (args, len)
  1766.     char *args;
  1767.     int len;
  1768. {
  1769.     struct update_entries_data dat;
  1770.     dat.contents = UPDATE_ENTRIES_UPDATE;
  1771.     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
  1772.     dat.timestamp = NULL;
  1773.     call_in_directory (args, update_entries, (char *)&dat);
  1774. }
  1775.  
  1776. static void handle_created PROTO((char *, int));
  1777.  
  1778. static void
  1779. handle_created (args, len)
  1780.     char *args;
  1781.     int len;
  1782. {
  1783.     struct update_entries_data dat;
  1784.     dat.contents = UPDATE_ENTRIES_UPDATE;
  1785.     dat.existp = UPDATE_ENTRIES_NEW;
  1786.     dat.timestamp = NULL;
  1787.     call_in_directory (args, update_entries, (char *)&dat);
  1788. }
  1789.  
  1790. static void handle_update_existing PROTO((char *, int));
  1791.  
  1792. static void
  1793. handle_update_existing (args, len)
  1794.     char *args;
  1795.     int len;
  1796. {
  1797.     struct update_entries_data dat;
  1798.     dat.contents = UPDATE_ENTRIES_UPDATE;
  1799.     dat.existp = UPDATE_ENTRIES_EXISTING;
  1800.     dat.timestamp = NULL;
  1801.     call_in_directory (args, update_entries, (char *)&dat);
  1802. }
  1803.  
  1804. static void
  1805. handle_merged (args, len)
  1806.     char *args;
  1807.     int len;
  1808. {
  1809.     struct update_entries_data dat;
  1810.     dat.contents = UPDATE_ENTRIES_UPDATE;
  1811.     /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
  1812.     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
  1813.     dat.timestamp = "Result of merge";
  1814.     call_in_directory (args, update_entries, (char *)&dat);
  1815. }
  1816.  
  1817. static void
  1818. handle_patched (args, len)
  1819.      char *args;
  1820.      int len;
  1821. {
  1822.     struct update_entries_data dat;
  1823.     dat.contents = UPDATE_ENTRIES_PATCH;
  1824.     /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
  1825.     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
  1826.     dat.timestamp = NULL;
  1827.     call_in_directory (args, update_entries, (char *)&dat);
  1828. }
  1829.  
  1830. static void
  1831. remove_entry (data, ent_list, short_pathname, filename)
  1832.     char *data;
  1833.     List *ent_list;
  1834.     char *short_pathname;
  1835.     char *filename;
  1836. {
  1837.     Scratch_Entry (ent_list, filename);
  1838. }
  1839.  
  1840. static void
  1841. handle_remove_entry (args, len)
  1842.     char *args;
  1843.     int len;
  1844. {
  1845.     call_in_directory (args, remove_entry, (char *)NULL);
  1846. }
  1847.  
  1848. static void
  1849. remove_entry_and_file (data, ent_list, short_pathname, filename)
  1850.     char *data;
  1851.     List *ent_list;
  1852.     char *short_pathname;
  1853.     char *filename;
  1854. {
  1855.     Scratch_Entry (ent_list, filename);
  1856.     /* Note that we don't ignore existence_error's here.  The server
  1857.        should be sending Remove-entry rather than Removed in cases
  1858.        where the file does not exist.  And if the user removes the
  1859.        file halfway through a cvs command, we should be printing an
  1860.        error.  */
  1861.     if (unlink_file (filename) < 0)
  1862.     error (0, errno, "unable to remove %s", short_pathname);
  1863. }
  1864.  
  1865. static void
  1866. handle_removed (args, len)
  1867.     char *args;
  1868.     int len;
  1869. {
  1870.     call_in_directory (args, remove_entry_and_file, (char *)NULL);
  1871. }
  1872.  
  1873. /* Is this the top level (directory containing CVSROOT)?  */
  1874. static int
  1875. is_cvsroot_level (pathname)
  1876.     char *pathname;
  1877. {
  1878.     char *short_pathname;
  1879.  
  1880.     if (strcmp (toplevel_repos, CVSroot_directory) != 0)
  1881.     return 0;
  1882.  
  1883.     if (!use_directory)
  1884.     {
  1885.     if (strncmp (pathname, CVSroot_directory, strlen (CVSroot_directory)) != 0)
  1886.         error (1, 0,
  1887.            "server bug: pathname `%s' doesn't specify file in `%s'",
  1888.            pathname, CVSroot_directory);
  1889.     short_pathname = pathname + strlen (CVSroot_directory) + 1;
  1890.     if (short_pathname[-1] != '/')
  1891.         error (1, 0,
  1892.            "server bug: pathname `%s' doesn't specify file in `%s'",
  1893.            pathname, CVSroot_directory);
  1894.     return strchr (short_pathname, '/') == NULL;
  1895.     }
  1896.     else
  1897.     {
  1898.     return strchr (pathname, '/') == NULL;
  1899.     }
  1900. }
  1901.  
  1902. static void
  1903. set_static (data, ent_list, short_pathname, filename)
  1904.     char *data;
  1905.     List *ent_list;
  1906.     char *short_pathname;
  1907.     char *filename;
  1908. {
  1909.     FILE *fp;
  1910.     fp = open_file (CVSADM_ENTSTAT, "w+");
  1911.     if (fclose (fp) == EOF)
  1912.         error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
  1913. }
  1914.  
  1915. static void
  1916. handle_set_static_directory (args, len)
  1917.     char *args;
  1918.     int len;
  1919. {
  1920.     if (strcmp (command_name, "export") == 0)
  1921.     {
  1922.     /* Swallow the repository.  */
  1923.     read_line (NULL);
  1924.     return;
  1925.     }
  1926.     call_in_directory (args, set_static, (char *)NULL);
  1927. }
  1928.  
  1929. static void
  1930. clear_static (data, ent_list, short_pathname, filename)
  1931.     char *data;
  1932.     List *ent_list;
  1933.     char *short_pathname;
  1934.     char *filename;
  1935. {
  1936.     if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
  1937.         error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
  1938. }
  1939.  
  1940. static void
  1941. handle_clear_static_directory (pathname, len)
  1942.     char *pathname;
  1943.     int len;
  1944. {
  1945.     if (strcmp (command_name, "export") == 0)
  1946.     {
  1947.     /* Swallow the repository.  */
  1948.     read_line (NULL);
  1949.     return;
  1950.     }
  1951.  
  1952.     if (is_cvsroot_level (pathname))
  1953.     {
  1954.         /*
  1955.      * Top level (directory containing CVSROOT).  This seems to normally
  1956.      * lack a CVS directory, so don't try to create files in it.
  1957.      */
  1958.     return;
  1959.     }
  1960.     call_in_directory (pathname, clear_static, (char *)NULL);
  1961. }
  1962.  
  1963. static void
  1964. set_sticky (data, ent_list, short_pathname, filename)
  1965.     char *data;
  1966.     List *ent_list;
  1967.     char *short_pathname;
  1968.     char *filename;
  1969. {
  1970.     char *tagspec;
  1971.     FILE *f;
  1972.  
  1973.     read_line (&tagspec);
  1974.     f = open_file (CVSADM_TAG, "w+");
  1975.     if (fprintf (f, "%s\n", tagspec) < 0)
  1976.     error (1, errno, "writing %s", CVSADM_TAG);
  1977.     if (fclose (f) == EOF)
  1978.     error (1, errno, "closing %s", CVSADM_TAG);
  1979.     free (tagspec);
  1980. }
  1981.  
  1982. static void
  1983. handle_set_sticky (pathname, len)
  1984.     char *pathname;
  1985.     int len;
  1986. {
  1987.     if (strcmp (command_name, "export") == 0)
  1988.     {
  1989.     /* Swallow the repository.  */
  1990.     read_line (NULL);
  1991.         /* Swallow the tag line.  */
  1992.     read_line (NULL);
  1993.     return;
  1994.     }
  1995.     if (is_cvsroot_level (pathname))
  1996.     {
  1997.         /*
  1998.      * Top level (directory containing CVSROOT).  This seems to normally
  1999.      * lack a CVS directory, so don't try to create files in it.
  2000.      */
  2001.  
  2002.     /* Swallow the repository.  */
  2003.     read_line (NULL);
  2004.         /* Swallow the tag line.  */
  2005.     read_line (NULL);
  2006.     return;
  2007.     }
  2008.  
  2009.     call_in_directory (pathname, set_sticky, (char *)NULL);
  2010. }
  2011.  
  2012. static void
  2013. clear_sticky (data, ent_list, short_pathname, filename)
  2014.     char *data;
  2015.     List *ent_list;
  2016.     char *short_pathname;
  2017.     char *filename;
  2018. {
  2019.     if (unlink_file (CVSADM_TAG) < 0 && ! existence_error (errno))
  2020.     error (1, errno, "cannot remove %s", CVSADM_TAG);
  2021. }
  2022.  
  2023. static void
  2024. handle_clear_sticky (pathname, len)
  2025.     char *pathname;
  2026.     int len;
  2027. {
  2028.     if (strcmp (command_name, "export") == 0)
  2029.     {
  2030.     /* Swallow the repository.  */
  2031.     read_line (NULL);
  2032.     return;
  2033.     }
  2034.  
  2035.     if (is_cvsroot_level (pathname))
  2036.     {
  2037.         /*
  2038.      * Top level (directory containing CVSROOT).  This seems to normally
  2039.      * lack a CVS directory, so don't try to create files in it.
  2040.      */
  2041.     return;
  2042.     }
  2043.  
  2044.     call_in_directory (pathname, clear_sticky, (char *)NULL);
  2045. }
  2046.  
  2047.  
  2048. static void template PROTO ((char *, List *, char *, char *));
  2049.  
  2050. static void
  2051. template (data, ent_list, short_pathname, filename)
  2052.     char *data;
  2053.     List *ent_list;
  2054.     char *short_pathname;
  2055.     char *filename;
  2056. {
  2057.     /* FIXME: should be computing second argument from CVSADM_TEMPLATE
  2058.        and short_pathname.  */
  2059.     read_counted_file (CVSADM_TEMPLATE, "<CVS/Template file>");
  2060. }
  2061.  
  2062. static void handle_template PROTO ((char *, int));
  2063.  
  2064. static void
  2065. handle_template (pathname, len)
  2066.     char *pathname;
  2067.     int len;
  2068. {
  2069.     call_in_directory (pathname, template, NULL);
  2070. }
  2071.  
  2072.  
  2073. struct save_prog {
  2074.     char *name;
  2075.     char *dir;
  2076.     struct save_prog *next;
  2077. };
  2078.  
  2079. static struct save_prog *checkin_progs;
  2080. static struct save_prog *update_progs;
  2081.  
  2082. /*
  2083.  * Unlike some responses this doesn't include the repository.  So we can't
  2084.  * just call call_in_directory and have the right thing happen; we save up
  2085.  * the requests and do them at the end.
  2086.  */
  2087. static void
  2088. handle_set_checkin_prog (args, len)
  2089.     char *args;
  2090.     int len;
  2091. {
  2092.     char *prog;
  2093.     struct save_prog *p;
  2094.     read_line (&prog);
  2095.     p = (struct save_prog *) xmalloc (sizeof (struct save_prog));
  2096.     p->next = checkin_progs;
  2097.     p->dir = xstrdup (args);
  2098.     p->name = prog;
  2099.     checkin_progs = p;
  2100. }
  2101.     
  2102. static void
  2103. handle_set_update_prog (args, len)
  2104.     char *args;
  2105.     int len;
  2106. {
  2107.     char *prog;
  2108.     struct save_prog *p;
  2109.     read_line (&prog);
  2110.     p = (struct save_prog *) xmalloc (sizeof (struct save_prog));
  2111.     p->next = update_progs;
  2112.     p->dir = xstrdup (args);
  2113.     p->name = prog;
  2114.     update_progs = p;
  2115. }
  2116.  
  2117. static void do_deferred_progs PROTO((void));
  2118.  
  2119. static void
  2120. do_deferred_progs ()
  2121. {
  2122.     struct save_prog *p;
  2123.     struct save_prog *q;
  2124.  
  2125.     char fname[PATH_MAX];
  2126.     FILE *f;
  2127.     if (toplevel_wd[0] != '\0')
  2128.       {
  2129.     if ( CVS_CHDIR (toplevel_wd) < 0)
  2130.       error (1, errno, "could not chdir to %s", toplevel_wd);
  2131.       }
  2132.     for (p = checkin_progs; p != NULL; )
  2133.     {
  2134.     sprintf (fname, "%s/%s", p->dir, CVSADM_CIPROG);
  2135.     f = open_file (fname, "w");
  2136.     if (fprintf (f, "%s\n", p->name) < 0)
  2137.         error (1, errno, "writing %s", fname);
  2138.     if (fclose (f) == EOF)
  2139.         error (1, errno, "closing %s", fname);
  2140.     free (p->name);
  2141.     free (p->dir);
  2142.     q = p->next;
  2143.     free (p);
  2144.     p = q;
  2145.     }
  2146.     checkin_progs = NULL;
  2147.     for (p = update_progs; p != NULL; p = p->next)
  2148.     {
  2149.     sprintf (fname, "%s/%s", p->dir, CVSADM_UPROG);
  2150.     f = open_file (fname, "w");
  2151.     if (fprintf (f, "%s\n", p->name) < 0)
  2152.         error (1, errno, "writing %s", fname);
  2153.     if (fclose (f) == EOF)
  2154.         error (1, errno, "closing %s", fname);
  2155.     free (p->name);
  2156.     free (p->dir);
  2157.     free (p);
  2158.     }
  2159.     update_progs = NULL;
  2160. }
  2161.  
  2162. static int client_isemptydir PROTO((char *));
  2163.  
  2164. /*
  2165.  * Returns 1 if the argument directory exists and is completely empty,
  2166.  * other than the existence of the CVS directory entry.  Zero otherwise.
  2167.  */
  2168. static int
  2169. client_isemptydir (dir)
  2170.     char *dir;
  2171. {
  2172.     DIR *dirp;
  2173.     struct dirent *dp;
  2174.  
  2175.     if ((dirp = CVS_OPENDIR (dir)) == NULL)
  2176.     {
  2177.     if (! existence_error (errno))
  2178.         error (0, errno, "cannot open directory %s for empty check", dir);
  2179.     return (0);
  2180.     }
  2181.     errno = 0;
  2182.     while ((dp = readdir (dirp)) != NULL)
  2183.     {
  2184.     if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0 &&
  2185.         strcmp (dp->d_name, CVSADM) != 0)
  2186.     {
  2187.         (void) closedir (dirp);
  2188.         return (0);
  2189.     }
  2190.     }
  2191.     if (errno != 0)
  2192.     {
  2193.     error (0, errno, "cannot read directory %s", dir);
  2194.     (void) closedir (dirp);
  2195.     return (0);
  2196.     }
  2197.     (void) closedir (dirp);
  2198.     return (1);
  2199. }
  2200.  
  2201. struct save_dir {
  2202.     char *dir;
  2203.     struct save_dir *next;
  2204. };
  2205.  
  2206. struct save_dir *prune_candidates;
  2207.  
  2208. static void
  2209. add_prune_candidate (dir)
  2210.     char *dir;
  2211. {
  2212.     struct save_dir *p;
  2213.  
  2214.     if (dir[0] == '.' && dir[1] == '\0')
  2215.     return;
  2216.     p = (struct save_dir *) xmalloc (sizeof (struct save_dir));
  2217.     p->dir = xstrdup (dir);
  2218.     p->next = prune_candidates;
  2219.     prune_candidates = p;
  2220. }
  2221.  
  2222. static void process_prune_candidates PROTO((void));
  2223.  
  2224. static void
  2225. process_prune_candidates ()
  2226. {
  2227.     struct save_dir *p;
  2228.     struct save_dir *q;
  2229.  
  2230.     if (toplevel_wd[0] != '\0')
  2231.     {
  2232.     if ( CVS_CHDIR (toplevel_wd) < 0)
  2233.       error (1, errno, "could not chdir to %s", toplevel_wd);
  2234.     }
  2235.     for (p = prune_candidates; p != NULL; )
  2236.     {
  2237.     if (client_isemptydir (p->dir))
  2238.     {
  2239.         char *b;
  2240.  
  2241.         unlink_file_dir (p->dir);
  2242.         b = strrchr (p->dir, '/');
  2243.         if (b == NULL)
  2244.         Subdir_Deregister ((List *) NULL, (char *) NULL, p->dir);
  2245.         else
  2246.         {
  2247.         *b = '\0';
  2248.         Subdir_Deregister ((List *) NULL, p->dir, b + 1);
  2249.         }
  2250.     }
  2251.     free (p->dir);
  2252.     q = p->next;
  2253.     free (p);
  2254.     p = q;
  2255.     }
  2256.     prune_candidates = NULL;
  2257. }
  2258.  
  2259. /* Send a Repository line.  */
  2260.  
  2261. static char *last_repos;
  2262. static char *last_update_dir;
  2263.  
  2264. static void send_repository PROTO((char *, char *, char *));
  2265.  
  2266. static void
  2267. send_repository (dir, repos, update_dir)
  2268.     char *dir;
  2269.     char *repos;
  2270.     char *update_dir;
  2271. {
  2272.     char *adm_name;
  2273.  
  2274.     /* FIXME: this is probably not the best place to check; I wish I
  2275.      * knew where in here's callers to really trap this bug.  To
  2276.      * reproduce the bug, just do this:
  2277.      * 
  2278.      *       mkdir junk
  2279.      *       cd junk
  2280.      *       cvs -d some_repos update foo
  2281.      *
  2282.      * Poof, CVS seg faults and dies!  It's because it's trying to
  2283.      * send a NULL string to the server but dies in send_to_server.
  2284.      * That string was supposed to be the repository, but it doesn't
  2285.      * get set because there's no CVSADM dir, and somehow it's not
  2286.      * getting set from the -d argument either... ?
  2287.      */
  2288.     if (repos == NULL)
  2289.     {
  2290.         /* Lame error.  I want a real fix but can't stay up to track
  2291.            this down right now. */
  2292.         error (1, 0, "no repository");
  2293.     }
  2294.  
  2295.     if (update_dir == NULL || update_dir[0] == '\0')
  2296.     update_dir = ".";
  2297.  
  2298.     if (last_repos != NULL
  2299.     && strcmp (repos, last_repos) == 0
  2300.     && last_update_dir != NULL
  2301.     && strcmp (update_dir, last_update_dir) == 0)
  2302.     /* We've already sent it.  */
  2303.     return;
  2304.  
  2305.     if (client_prune_dirs)
  2306.     add_prune_candidate (update_dir);
  2307.  
  2308.     /* 80 is large enough for any of CVSADM_*.  */
  2309.     adm_name = xmalloc (strlen (dir) + 80);
  2310.  
  2311.     if (use_directory == -1)
  2312.     use_directory = supported_request ("Directory");
  2313.  
  2314.     if (use_directory)
  2315.     {
  2316.     send_to_server ("Directory ", 0);
  2317.     send_to_server (update_dir, 0);
  2318.     send_to_server ("\012", 1);
  2319.     send_to_server (repos, 0);
  2320.     send_to_server ("\012", 1);
  2321.     }
  2322.     else
  2323.     {
  2324.     send_to_server ("Repository ", 0);
  2325.     send_to_server (repos, 0);
  2326.     send_to_server ("\012", 1);
  2327.     }
  2328.     if (supported_request ("Static-directory"))
  2329.     {
  2330.     adm_name[0] = '\0';
  2331.     if (dir[0] != '\0')
  2332.     {
  2333.         strcat (adm_name, dir);
  2334.         strcat (adm_name, "/");
  2335.     }
  2336.     strcat (adm_name, CVSADM_ENTSTAT);
  2337.     if (isreadable (adm_name))
  2338.     {
  2339.         send_to_server ("Static-directory\012", 0);
  2340.     }
  2341.     }
  2342.     if (supported_request ("Sticky"))
  2343.     {
  2344.     FILE *f;
  2345.     if (dir[0] == '\0')
  2346.         strcpy (adm_name, CVSADM_TAG);
  2347.     else
  2348.         sprintf (adm_name, "%s/%s", dir, CVSADM_TAG);
  2349.  
  2350.     f = CVS_FOPEN (adm_name, "r");
  2351.     if (f == NULL)
  2352.     {
  2353.         if (! existence_error (errno))
  2354.         error (1, errno, "reading %s", adm_name);
  2355.     }
  2356.     else
  2357.     {
  2358.         char line[80];
  2359.         char *nl;
  2360.         send_to_server ("Sticky ", 0);
  2361.         while (fgets (line, sizeof (line), f) != NULL)
  2362.         {
  2363.         send_to_server (line, 0);
  2364.         nl = strchr (line, '\n');
  2365.         if (nl != NULL)
  2366.             break;
  2367.         }
  2368.         if (nl == NULL)
  2369.                 send_to_server ("\012", 1);
  2370.         if (fclose (f) == EOF)
  2371.         error (0, errno, "closing %s", adm_name);
  2372.     }
  2373.     }
  2374.     if (supported_request ("Checkin-prog"))
  2375.     {
  2376.     FILE *f;
  2377.     if (dir[0] == '\0')
  2378.         strcpy (adm_name, CVSADM_CIPROG);
  2379.     else
  2380.         sprintf (adm_name, "%s/%s", dir, CVSADM_CIPROG);
  2381.  
  2382.     f = CVS_FOPEN (adm_name, "r");
  2383.     if (f == NULL)
  2384.     {
  2385.         if (! existence_error (errno))
  2386.         error (1, errno, "reading %s", adm_name);
  2387.     }
  2388.     else
  2389.     {
  2390.         char line[80];
  2391.         char *nl;
  2392.  
  2393.         send_to_server ("Checkin-prog ", 0);
  2394.  
  2395.         while (fgets (line, sizeof (line), f) != NULL)
  2396.         {
  2397.         send_to_server (line, 0);
  2398.  
  2399.         nl = strchr (line, '\n');
  2400.         if (nl != NULL)
  2401.             break;
  2402.         }
  2403.         if (nl == NULL)
  2404.         send_to_server ("\012", 1);
  2405.         if (fclose (f) == EOF)
  2406.         error (0, errno, "closing %s", adm_name);
  2407.     }
  2408.     }
  2409.     if (supported_request ("Update-prog"))
  2410.     {
  2411.     FILE *f;
  2412.     if (dir[0] == '\0')
  2413.         strcpy (adm_name, CVSADM_UPROG);
  2414.     else
  2415.         sprintf (adm_name, "%s/%s", dir, CVSADM_UPROG);
  2416.  
  2417.     f = CVS_FOPEN (adm_name, "r");
  2418.     if (f == NULL)
  2419.     {
  2420.         if (! existence_error (errno))
  2421.         error (1, errno, "reading %s", adm_name);
  2422.     }
  2423.     else
  2424.     {
  2425.         char line[80];
  2426.         char *nl;
  2427.  
  2428.         send_to_server ("Update-prog ", 0);
  2429.  
  2430.         while (fgets (line, sizeof (line), f) != NULL)
  2431.         {
  2432.         send_to_server (line, 0);
  2433.  
  2434.         nl = strchr (line, '\n');
  2435.         if (nl != NULL)
  2436.             break;
  2437.         }
  2438.         if (nl == NULL)
  2439.         send_to_server ("\012", 1);
  2440.         if (fclose (f) == EOF)
  2441.         error (0, errno, "closing %s", adm_name);
  2442.     }
  2443.     }
  2444.     free (adm_name);
  2445.     if (last_repos != NULL)
  2446.     free (last_repos);
  2447.     if (last_update_dir != NULL)
  2448.     free (last_update_dir);
  2449.     last_repos = xstrdup (repos);
  2450.     last_update_dir = xstrdup (update_dir);
  2451. }
  2452.  
  2453. /* Send a Repository line and set toplevel_repos.  */
  2454. static void send_a_repository PROTO((char *, char *, char *));
  2455.  
  2456. static void
  2457. send_a_repository (dir, repository, update_dir)
  2458.     char *dir;
  2459.     char *repository;
  2460.     char *update_dir;
  2461. {
  2462.     if (toplevel_repos == NULL && repository != NULL)
  2463.     {
  2464.     if (update_dir[0] == '\0'
  2465.         || (update_dir[0] == '.' && update_dir[1] == '\0'))
  2466.         toplevel_repos = xstrdup (repository);
  2467.     else
  2468.     {
  2469.         /*
  2470.          * Get the repository from a CVS/Repository file if update_dir
  2471.          * is absolute.  This is not correct in general, because
  2472.          * the CVS/Repository file might not be the top-level one.
  2473.          * This is for cases like "cvs update /foo/bar" (I'm not
  2474.          * sure it matters what toplevel_repos we get, but it does
  2475.          * matter that we don't hit the "internal error" code below).
  2476.          */
  2477.         if (update_dir[0] == '/')
  2478.         toplevel_repos = Name_Repository (update_dir, update_dir);
  2479.         else
  2480.         {
  2481.         /*
  2482.          * Guess the repository of that directory by looking at a
  2483.          * subdirectory and removing as many pathname components
  2484.          * as are in update_dir.  I think that will always (or at
  2485.          * least almost always) be 1.
  2486.          *
  2487.          * So this deals with directories which have been
  2488.          * renamed, though it doesn't necessarily deal with
  2489.          * directories which have been put inside other
  2490.          * directories (and cvs invoked on the containing
  2491.          * directory).  I'm not sure the latter case needs to
  2492.          * work.
  2493.          */
  2494.         /*
  2495.          * This gets toplevel_repos wrong for "cvs update ../foo"
  2496.          * but I'm not sure toplevel_repos matters in that case.
  2497.          */
  2498.         int slashes_in_update_dir;
  2499.         int slashes_skipped;
  2500.         char *p;
  2501.  
  2502.         slashes_in_update_dir = 0;
  2503.         for (p = update_dir; *p != '\0'; ++p)
  2504.             if (*p == '/')
  2505.             ++slashes_in_update_dir;
  2506.  
  2507.         slashes_skipped = 0;
  2508.         p = repository + strlen (repository);
  2509.         while (1)
  2510.         {
  2511.             if (p == repository)
  2512.             error (1, 0,
  2513.                    "internal error: not enough slashes in %s",
  2514.                    repository);
  2515.             if (*p == '/')
  2516.             ++slashes_skipped;
  2517.             if (slashes_skipped < slashes_in_update_dir + 1)
  2518.             --p;
  2519.             else
  2520.             break;
  2521.         }
  2522.         toplevel_repos = xmalloc (p - repository + 1);
  2523.         /* Note that we don't copy the trailing '/'.  */
  2524.         strncpy (toplevel_repos, repository, p - repository);
  2525.         toplevel_repos[p - repository] = '\0';
  2526.         }
  2527.     }
  2528.     }
  2529.  
  2530.     send_repository (dir, repository, update_dir);
  2531. }
  2532.  
  2533. /* The "expanded" modules.  */
  2534. static int modules_count;
  2535. static int modules_allocated;
  2536. static char **modules_vector;
  2537.  
  2538. static void
  2539. handle_module_expansion (args, len)
  2540.     char *args;
  2541.     int len;
  2542. {
  2543.     if (modules_vector == NULL)
  2544.     {
  2545.     modules_allocated = 1; /* Small for testing */
  2546.     modules_vector = (char **) xmalloc
  2547.       (modules_allocated * sizeof (modules_vector[0]));
  2548.     }
  2549.     else if (modules_count >= modules_allocated)
  2550.     {
  2551.     modules_allocated *= 2;
  2552.     modules_vector = (char **) xrealloc
  2553.       ((char *) modules_vector,
  2554.        modules_allocated * sizeof (modules_vector[0]));
  2555.     }
  2556.     modules_vector[modules_count] = xmalloc (strlen (args) + 1);
  2557.     strcpy (modules_vector[modules_count], args);
  2558.     ++modules_count;
  2559. }
  2560.  
  2561. /* Original, not "expanded" modules.  */
  2562. static int module_argc;
  2563. static char **module_argv;
  2564.  
  2565. void
  2566. client_expand_modules (argc, argv, local)
  2567.     int argc;
  2568.     char **argv;
  2569.     int local;
  2570. {
  2571.     int errs;
  2572.     int i;
  2573.  
  2574.     module_argc = argc;
  2575.     module_argv = (char **) xmalloc ((argc + 1) * sizeof (module_argv[0]));
  2576.     for (i = 0; i < argc; ++i)
  2577.     module_argv[i] = xstrdup (argv[i]);
  2578.     module_argv[argc] = NULL;
  2579.  
  2580.     for (i = 0; i < argc; ++i)
  2581.     send_arg (argv[i]);
  2582.     send_a_repository ("", CVSroot_directory, "");
  2583.  
  2584.     send_to_server ("expand-modules\012", 0);
  2585.  
  2586.     errs = get_server_responses ();
  2587.     if (last_repos != NULL)
  2588.         free (last_repos);
  2589.     last_repos = NULL;
  2590.     if (last_update_dir != NULL)
  2591.         free (last_update_dir);
  2592.     last_update_dir = NULL;
  2593.     if (errs)
  2594.     error (errs, 0, "cannot expand modules");
  2595. }
  2596.  
  2597. void
  2598. client_send_expansions (local, where)
  2599.     int local;
  2600.     char *where;
  2601. {
  2602.     int i;
  2603.     char *argv[1];
  2604.  
  2605.     /* Send the original module names.  The "expanded" module name might
  2606.        not be suitable as an argument to a co request (e.g. it might be
  2607.        the result of a -d argument in the modules file).  It might be
  2608.        cleaner if we genuinely expanded module names, all the way to a
  2609.        local directory and repository, but that isn't the way it works
  2610.        now.  */
  2611.     send_file_names (module_argc, module_argv, 0);
  2612.  
  2613.     for (i = 0; i < modules_count; ++i)
  2614.     {
  2615.     argv[0] = where ? where : modules_vector[i];
  2616.     if (isfile (argv[0]))
  2617.         send_files (1, argv, local, 0);
  2618.     }
  2619.     send_a_repository ("", CVSroot_directory, "");
  2620. }
  2621.  
  2622. void
  2623. client_nonexpanded_setup ()
  2624. {
  2625.     send_a_repository ("", CVSroot_directory, "");
  2626. }
  2627.  
  2628. static void
  2629. handle_m (args, len)
  2630.     char *args;
  2631.     int len;
  2632. {
  2633.     /* In the case where stdout and stderr point to the same place,
  2634.        fflushing stderr will make output happen in the correct order.
  2635.        Often stderr will be line-buffered and this won't be needed,
  2636.        but not always.  */
  2637.     fflush (stderr);
  2638.     fwrite (args, len, sizeof (*args), stdout);
  2639.     putc ('\n', stdout);
  2640. }
  2641.  
  2642. static void
  2643. handle_e (args, len)
  2644.     char *args;
  2645.     int len;
  2646. {
  2647.     /* In the case where stdout and stderr point to the same place,
  2648.        fflushing stdout will make output happen in the correct order.  */
  2649.     fflush (stdout);
  2650.     fwrite (args, len, sizeof (*args), stderr);
  2651.     putc ('\n', stderr);
  2652. }
  2653.  
  2654. /*ARGSUSED*/
  2655. static void
  2656. handle_f (args, len)
  2657.     char *args;
  2658.     int len;
  2659. {
  2660.     fflush (stderr);
  2661. }
  2662.  
  2663. #endif /* CLIENT_SUPPORT */
  2664. #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
  2665.  
  2666. /* This table must be writeable if the server code is included.  */
  2667. struct response responses[] =
  2668. {
  2669. #ifdef CLIENT_SUPPORT
  2670. #define RSP_LINE(n, f, t, s) {n, f, t, s}
  2671. #else /* ! CLIENT_SUPPORT */
  2672. #define RSP_LINE(n, f, t, s) {n, s}
  2673. #endif /* CLIENT_SUPPORT */
  2674.  
  2675.     RSP_LINE("ok", handle_ok, response_type_ok, rs_essential),
  2676.     RSP_LINE("error", handle_error, response_type_error, rs_essential),
  2677.     RSP_LINE("Valid-requests", handle_valid_requests, response_type_normal,
  2678.        rs_essential),
  2679.     RSP_LINE("Checked-in", handle_checked_in, response_type_normal,
  2680.        rs_essential),
  2681.     RSP_LINE("New-entry", handle_new_entry, response_type_normal, rs_optional),
  2682.     RSP_LINE("Checksum", handle_checksum, response_type_normal, rs_optional),
  2683.     RSP_LINE("Copy-file", handle_copy_file, response_type_normal, rs_optional),
  2684.     RSP_LINE("Updated", handle_updated, response_type_normal, rs_essential),
  2685.     RSP_LINE("Created", handle_created, response_type_normal, rs_optional),
  2686.     RSP_LINE("Update-existing", handle_update_existing, response_type_normal,
  2687.        rs_optional),
  2688.     RSP_LINE("Merged", handle_merged, response_type_normal, rs_essential),
  2689.     RSP_LINE("Patched", handle_patched, response_type_normal, rs_optional),
  2690.     RSP_LINE("Mode", handle_mode, response_type_normal, rs_optional),
  2691.     RSP_LINE("Removed", handle_removed, response_type_normal, rs_essential),
  2692.     RSP_LINE("Remove-entry", handle_remove_entry, response_type_normal,
  2693.        rs_optional),
  2694.     RSP_LINE("Set-static-directory", handle_set_static_directory,
  2695.        response_type_normal,
  2696.        rs_optional),
  2697.     RSP_LINE("Clear-static-directory", handle_clear_static_directory,
  2698.        response_type_normal,
  2699.        rs_optional),
  2700.     RSP_LINE("Set-sticky", handle_set_sticky, response_type_normal,
  2701.        rs_optional),
  2702.     RSP_LINE("Clear-sticky", handle_clear_sticky, response_type_normal,
  2703.        rs_optional),
  2704.     RSP_LINE("Template", handle_template, response_type_normal,
  2705.        rs_optional),
  2706.     RSP_LINE("Set-checkin-prog", handle_set_checkin_prog, response_type_normal,
  2707.        rs_optional),
  2708.     RSP_LINE("Set-update-prog", handle_set_update_prog, response_type_normal,
  2709.        rs_optional),
  2710.     RSP_LINE("Notified", handle_notified, response_type_normal, rs_optional),
  2711.     RSP_LINE("Module-expansion", handle_module_expansion, response_type_normal,
  2712.        rs_optional),
  2713.     RSP_LINE("M", handle_m, response_type_normal, rs_essential),
  2714.     RSP_LINE("E", handle_e, response_type_normal, rs_essential),
  2715.     RSP_LINE("F", handle_f, response_type_normal, rs_optional),
  2716.     /* Possibly should be response_type_error.  */
  2717.     RSP_LINE(NULL, NULL, response_type_normal, rs_essential)
  2718.  
  2719. #undef RSP_LINE
  2720. };
  2721.  
  2722. #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */
  2723. #ifdef CLIENT_SUPPORT
  2724.  
  2725. /* 
  2726.  * If LEN is 0, then send_to_server() computes string's length itself.
  2727.  *
  2728.  * Therefore, pass the real length when transmitting data that might
  2729.  * contain 0's.
  2730.  */
  2731. void
  2732. send_to_server (str, len)
  2733.      char *str;
  2734.      size_t len;
  2735. {
  2736.     static int nbytes;
  2737.  
  2738.     if (len == 0)
  2739.     len = strlen (str);
  2740.  
  2741.     buf_output (to_server, str, len);
  2742.       
  2743.     /* There is no reason not to send data to the server, so do it
  2744.        whenever we've accumulated enough information in the buffer to
  2745.        make it worth sending.  */
  2746.     nbytes += len;
  2747.     if (nbytes >= 2 * BUFFER_DATA_SIZE)
  2748.     {
  2749.     int status;
  2750.  
  2751.         status = buf_send_output (to_server);
  2752.     if (status != 0)
  2753.         error (1, status, "error writing to server");
  2754.     nbytes = 0;
  2755.     }
  2756. }
  2757.  
  2758. /* Read up to LEN bytes from the server.  Returns actual number of
  2759.    bytes read, which will always be at least one; blocks if there is
  2760.    no data available at all.  Gives a fatal error on EOF or error.  */
  2761. static size_t
  2762. try_read_from_server (buf, len)
  2763.     char *buf;
  2764.     size_t len;
  2765. {
  2766.     int status, nread;
  2767.     char *data;
  2768.  
  2769.     status = buf_read_data (from_server, len, &data, &nread);
  2770.     if (status != 0)
  2771.     {
  2772.     if (status == -1)
  2773.         error (1, 0,
  2774.            "end of file from server (consult above messages if any)");
  2775.     else if (status == -2)
  2776.         error (1, 0, "out of memory");
  2777.     else
  2778.         error (1, status, "reading from server");
  2779.     }
  2780.  
  2781.     memcpy (buf, data, nread);
  2782.  
  2783.     return nread;
  2784. }
  2785.  
  2786. /*
  2787.  * Read LEN bytes from the server or die trying.
  2788.  */
  2789. void
  2790. read_from_server (buf, len)
  2791.     char *buf;
  2792.     size_t len;
  2793. {
  2794.     size_t red = 0;
  2795.     while (red < len)
  2796.     {
  2797.     red += try_read_from_server (buf + red, len - red);
  2798.     if (red == len)
  2799.         break;
  2800.     }
  2801. }
  2802.  
  2803. /*
  2804.  * Get some server responses and process them.  Returns nonzero for
  2805.  * error, 0 for success.  */
  2806. int
  2807. get_server_responses ()
  2808. {
  2809.     struct response *rs;
  2810.     do
  2811.     {
  2812.     char *cmd;
  2813.     int len;
  2814.     
  2815.     len = read_line (&cmd);
  2816.     for (rs = responses; rs->name != NULL; ++rs)
  2817.         if (strncmp (cmd, rs->name, strlen (rs->name)) == 0)
  2818.         {
  2819.         int cmdlen = strlen (rs->name);
  2820.         if (cmd[cmdlen] == '\0')
  2821.             ;
  2822.         else if (cmd[cmdlen] == ' ')
  2823.             ++cmdlen;
  2824.         else
  2825.             /*
  2826.              * The first len characters match, but it's a different
  2827.              * response.  e.g. the response is "oklahoma" but we
  2828.              * matched "ok".
  2829.              */
  2830.             continue;
  2831.         (*rs->func) (cmd + cmdlen, len - cmdlen);
  2832.         break;
  2833.         }
  2834.     if (rs->name == NULL)
  2835.         /* It's OK to print just to the first '\0'.  */
  2836.         error (0, 0,
  2837.            "warning: unrecognized response `%s' from cvs server",
  2838.            cmd);
  2839.     free (cmd);
  2840.     } while (rs->type == response_type_normal);
  2841.     return rs->type == response_type_error ? 1 : 0;
  2842. }
  2843.  
  2844. /* Get the responses and then close the connection.  */
  2845. int server_fd = -1;
  2846.  
  2847. /*
  2848.  * Flag var; we'll set it in start_server() and not one of its
  2849.  * callees, such as start_rsh_server().  This means that there might
  2850.  * be a small window between the starting of the server and the
  2851.  * setting of this var, but all the code in that window shouldn't care
  2852.  * because it's busy checking return values to see if the server got
  2853.  * started successfully anyway.
  2854.  */
  2855. int server_started = 0;
  2856.  
  2857. int
  2858. get_responses_and_close ()
  2859. {
  2860.     int errs = get_server_responses ();
  2861.     int status;
  2862.  
  2863.     if (last_entries != NULL)
  2864.     {
  2865.     Entries_Close (last_entries);
  2866.     last_entries = NULL;
  2867.     }
  2868.  
  2869.     do_deferred_progs ();
  2870.  
  2871.     if (client_prune_dirs)
  2872.     process_prune_candidates ();
  2873.  
  2874.     /* The calls to buf_shutdown are currently only meaningful when we
  2875.        are using compression.  First we shut down TO_SERVER.  That
  2876.        tells the server that its input is finished.  It then shuts
  2877.        down the buffer it is sending to us, at which point our shut
  2878.        down of FROM_SERVER will complete.  */
  2879.  
  2880.     status = buf_shutdown (to_server);
  2881.     if (status != 0)
  2882.         error (0, status, "shutting down buffer to server");
  2883.     status = buf_shutdown (from_server);
  2884.     if (status != 0)
  2885.     error (0, status, "shutting down buffer from server");
  2886.  
  2887. #ifdef NO_SOCKET_TO_FD
  2888.     if (use_socket_style)
  2889.     {
  2890.     if (shutdown (server_sock, 2) < 0)
  2891.         error (1, errno, "shutting down server socket");
  2892.     }
  2893.     else
  2894. #endif /* NO_SOCKET_TO_FD */
  2895.     {
  2896. #if defined(HAVE_KERBEROS) || defined(USE_DIRECT_TCP) || defined(AUTH_CLIENT_SUPPORT)
  2897.     if (server_fd != -1)
  2898.     {
  2899.         if (shutdown (server_fd, 1) < 0)
  2900.         error (1, errno, "shutting down connection to %s",
  2901.                CVSroot_hostname);
  2902.             /*
  2903.              * This test will always be true because we dup the descriptor
  2904.              */
  2905.         if (fileno (from_server_fp) != fileno (to_server_fp))
  2906.         {
  2907.         if (fclose (to_server_fp) != 0)
  2908.             error (1, errno,
  2909.                "closing down connection to %s",
  2910.                CVSroot_hostname);
  2911.         }
  2912.     }
  2913.         else
  2914. #endif /* HAVE_KERBEROS || USE_DIRECT_TCP || AUTH_CLIENT_SUPPORT */
  2915.           
  2916. #ifdef SHUTDOWN_SERVER
  2917.         SHUTDOWN_SERVER (fileno (to_server_fp));
  2918. #else /* ! SHUTDOWN_SERVER */
  2919.     {
  2920.  
  2921. #ifdef START_RSH_WITH_POPEN_RW
  2922.         if (pclose (to_server_fp) == EOF)
  2923. #else /* ! START_RSH_WITH_POPEN_RW */
  2924.         if (fclose (to_server_fp) == EOF)
  2925. #endif /* START_RSH_WITH_POPEN_RW */
  2926.         {
  2927.             error (1, errno, "closing connection to %s",
  2928.                CVSroot_hostname);
  2929.         }
  2930.         }
  2931.  
  2932.     if (! buf_empty_p (from_server)
  2933.         || getc (from_server_fp) != EOF)
  2934.         error (0, 0, "dying gasps from %s unexpected", CVSroot_hostname);
  2935.     else if (ferror (from_server_fp))
  2936.         error (0, errno, "reading from %s", CVSroot_hostname);
  2937.  
  2938.     fclose (from_server_fp);
  2939. #endif /* SHUTDOWN_SERVER */
  2940.     }
  2941.  
  2942. #if ! RSH_NOT_TRANSPARENT
  2943.     if (rsh_pid != -1
  2944.     && waitpid (rsh_pid, (int *) 0, 0) == -1)
  2945.     error (1, errno, "waiting for process %d", rsh_pid);
  2946. #endif /* ! RSH_NOT_TRANSPARENT */
  2947.  
  2948.     server_started = 0;
  2949.  
  2950.     /* see if we need to sleep before returning */
  2951.     if (last_register_time)
  2952.     {
  2953.     time_t now;
  2954.  
  2955.     (void) time (&now);
  2956.     if (now == last_register_time)
  2957.         sleep (1);            /* to avoid time-stamp races */
  2958.     }
  2959.  
  2960.     return errs;
  2961. }
  2962.     
  2963. #ifndef RSH_NOT_TRANSPARENT
  2964. static void start_rsh_server PROTO((int *, int *));
  2965. #endif /* RSH_NOT_TRANSPARENT */
  2966.  
  2967. int
  2968. supported_request (name)
  2969.     char *name;
  2970. {
  2971.     struct request *rq;
  2972.  
  2973.     for (rq = requests; rq->name; rq++)
  2974.     if (!strcmp (rq->name, name))
  2975.         return rq->status == rq_supported;
  2976.     error (1, 0, "internal error: testing support for unknown option?");
  2977.     /* NOTREACHED */
  2978.     return 0;
  2979. }
  2980.  
  2981.  
  2982. #ifdef AUTH_CLIENT_SUPPORT
  2983. void
  2984. init_sockaddr (name, hostname, port)
  2985.     struct sockaddr_in *name;
  2986.     const char *hostname;
  2987.     unsigned short int port;
  2988. {
  2989.     struct hostent *hostinfo;
  2990.  
  2991.     memset (name, 0, sizeof (*name));
  2992.     name->sin_family = AF_INET;
  2993.     name->sin_port = htons (port);
  2994.     hostinfo = gethostbyname (hostname);
  2995.     if (hostinfo == NULL)
  2996.     {
  2997.     fprintf (stderr, "Unknown host %s.\n", hostname);
  2998.     exit (EXIT_FAILURE);
  2999.     }
  3000.     name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
  3001. }
  3002.  
  3003.  
  3004. int
  3005. auth_server_port_number ()
  3006. {
  3007.     return CVS_AUTH_PORT;
  3008. }
  3009.  
  3010.  
  3011. /*
  3012.  * Connect to the authenticating server.
  3013.  *
  3014.  * If VERIFY_ONLY is non-zero, then just verify that the password is
  3015.  * correct and then shutdown the connection.  In this case, the return
  3016.  * values is 1 if the password was correct, 0 if not.
  3017.  *
  3018.  * If VERIFY_ONLY is 0, then really connect to the server.  In this
  3019.  * case the return value is 1 on succees, but is probably ignored.  If
  3020.  * fail to connect, then die with error.
  3021.  */
  3022. int
  3023. connect_to_pserver (tofdp, fromfdp, verify_only)
  3024.      int *tofdp, *fromfdp;
  3025.      int verify_only;
  3026. {
  3027.     int sock;
  3028. #ifndef NO_SOCKET_TO_FD
  3029.     int tofd, fromfd;
  3030. #endif
  3031.     int port_number;
  3032.     struct sockaddr_in client_sai;
  3033.  
  3034.     sock = socket (AF_INET, SOCK_STREAM, 0);
  3035.     if (sock == -1)
  3036.     {
  3037.     fprintf (stderr, "socket() failed\n");
  3038.     exit (EXIT_FAILURE);
  3039.     }
  3040.     port_number = auth_server_port_number ();
  3041.     init_sockaddr (&client_sai, CVSroot_hostname, port_number);
  3042.     if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai))
  3043.     < 0)
  3044.     error (1, errno, "connect to %s:%d failed", CVSroot_hostname,
  3045.            CVS_AUTH_PORT);
  3046.  
  3047.     /* Run the authorization mini-protocol before anything else. */
  3048.     {
  3049.     int i;
  3050.     char ch, read_buf[PATH_MAX];
  3051.     char *begin      = NULL;
  3052.     char *repository = CVSroot_directory;
  3053.     char *username   = CVSroot_username;
  3054.     char *password   = NULL;
  3055.     char *end        = NULL;
  3056.  
  3057.     if (verify_only)
  3058.     {
  3059.         begin = "BEGIN VERIFICATION REQUEST\n";
  3060.         end   = "END VERIFICATION REQUEST\n";
  3061.     }
  3062.     else
  3063.     {
  3064.         begin = "BEGIN AUTH REQUEST\n";
  3065.         end   = "END AUTH REQUEST\n";
  3066.     }
  3067.  
  3068.     /* Get the password, probably from ~/.cvspass. */
  3069.     password = get_cvs_password ();
  3070.  
  3071.     /* Announce that we're starting the authorization protocol. */
  3072.     send (sock, begin, strlen (begin), 0);
  3073.  
  3074.     /* Send the data the server needs. */
  3075.     send (sock, repository, strlen (repository), 0);
  3076.     send (sock, "\n", 1, 0);
  3077.     send (sock, username, strlen (username), 0);
  3078.     send (sock, "\n", 1, 0);
  3079.     send (sock, password, strlen (password), 0);
  3080.     send (sock, "\n", 1, 0);
  3081.  
  3082.     /* Announce that we're ending the authorization protocol. */
  3083.     send (sock, end, strlen (end), 0);
  3084.  
  3085.     /* Paranoia. */
  3086.     memset (password, 0, strlen (password));
  3087.  
  3088.     /* Get ACK or NACK from the server. 
  3089.      * 
  3090.      * We could avoid this careful read-char loop by having the ACK
  3091.      * and NACK cookies be of the same length, so we'd simply read
  3092.      * that length and see what we got.  But then there'd be Yet
  3093.      * Another Protocol Requirement floating around, and someday
  3094.      * someone would make a change that breaks it and spend a hellish
  3095.      * day tracking it down.  Therefore, we use "\n" to mark off the
  3096.      * end of both ACK and NACK, and we loop, reading until "\n".
  3097.      */
  3098.     ch = 0;
  3099.     memset (read_buf, 0, PATH_MAX);
  3100.     for (i = 0; (i < (PATH_MAX - 1)) && (ch != '\n'); i++)
  3101.     {
  3102.         if (recv (sock, &ch, 1, 0) < 0)
  3103.                 error (1, errno, "recv() from server %s", CVSroot_hostname);
  3104.  
  3105.             read_buf[i] = ch;
  3106.     }
  3107.  
  3108.     if (strcmp (read_buf, "I HATE YOU\n") == 0)
  3109.     {
  3110.         /* Authorization not granted. */
  3111.         if (shutdown (sock, 2) < 0)
  3112.         {
  3113.         error (0, 0, 
  3114.                "authorization failed: server %s rejected access", 
  3115.                CVSroot_hostname);
  3116.         error (1, errno,
  3117.                "shutdown() failed (server %s)", CVSroot_hostname);
  3118.         }
  3119.  
  3120.         if (verify_only)
  3121.         return 0;
  3122.         else
  3123.         error (1, 0, 
  3124.                "authorization failed: server %s rejected access", 
  3125.                CVSroot_hostname);
  3126.     }
  3127.     else if (strcmp (read_buf, "I LOVE YOU\n") != 0)
  3128.     {
  3129.         /* Unrecognized response from server. */
  3130.         if (shutdown (sock, 2) < 0)
  3131.         {
  3132.         error (0, 0,
  3133.                "unrecognized auth response from %s: %s", 
  3134.                CVSroot_hostname, read_buf);
  3135.         error (1, errno, "shutdown() failed, server %s", CVSroot_hostname);
  3136.         }
  3137.         error (1, 0, 
  3138.            "unrecognized auth response from %s: %s", 
  3139.            CVSroot_hostname, read_buf);
  3140.     }
  3141.     }
  3142.  
  3143.     if (verify_only)
  3144.     {
  3145.     if (shutdown (sock, 2) < 0)
  3146.         error (0, errno, "shutdown() failed, server %s", CVSroot_hostname);
  3147.     return 1;
  3148.     }
  3149.     else
  3150.     {
  3151. #ifdef NO_SOCKET_TO_FD
  3152.     use_socket_style = 1;
  3153.     server_sock = sock;
  3154.     /* Try to break mistaken callers: */
  3155.     *tofdp = 0;
  3156.     *fromfdp = 0;
  3157. #else /* ! NO_SOCKET_TO_FD */
  3158.     server_fd = sock;
  3159.     close_on_exec (server_fd);
  3160.     tofd = fromfd = sock;
  3161.     /* Hand them back to the caller. */
  3162.     *tofdp   = tofd;
  3163.     *fromfdp = fromfd;
  3164. #endif /* NO_SOCKET_TO_FD */
  3165.     }
  3166.  
  3167.     return 1;
  3168. }
  3169. #endif /* AUTH_CLIENT_SUPPORT */
  3170.  
  3171.  
  3172. #if HAVE_KERBEROS || USE_DIRECT_TCP
  3173.  
  3174. /*
  3175.  * FIXME: this function has not been changed to deal with
  3176.  * NO_SOCKET_TO_FD (i.e., systems on which sockets cannot be converted
  3177.  * to file descriptors.  The first person to try building a kerberos
  3178.  * client on such a system (OS/2, Windows 95, and maybe others) will
  3179.  * have to make take care of this.
  3180.  */
  3181. void
  3182. start_tcp_server (tofdp, fromfdp)
  3183.     int *tofdp, *fromfdp;
  3184. {
  3185.     int tofd = -1, fromfd;
  3186.  
  3187.     struct hostent *hp;
  3188.     char *hname;
  3189.     const char *portenv;
  3190.     int port;
  3191.     struct sockaddr_in sin;
  3192.     int s;
  3193.  
  3194. #if HAVE_KERBEROS
  3195.     KTEXT_ST ticket;
  3196.     const char *realm;
  3197. #endif /* HAVE_KERBEROS */
  3198.  
  3199.     int status;
  3200.  
  3201.     /*
  3202.      * We look up the host to give a better error message if it
  3203.      * does not exist.  However, we then pass CVSroot_hostname to
  3204.      * krb_sendauth, rather than the canonical name, because
  3205.      * krb_sendauth is going to do its own canonicalization anyhow
  3206.      * and that lets us not worry about the static storage used by
  3207.      * gethostbyname.
  3208.      */
  3209.     hp = gethostbyname (CVSroot_hostname);
  3210.     if (hp == NULL)
  3211.     error (1, 0, "%s: unknown host", CVSroot_hostname);
  3212.     hname = xmalloc (strlen (hp->h_name) + 1);
  3213.     strcpy (hname, hp->h_name);
  3214.   
  3215. #if HAVE_KERBEROS
  3216.     realm = krb_realmofhost (hname);
  3217. #endif /* HAVE_KERBEROS */
  3218.  
  3219.     /* Get CVS_CLIENT_PORT or look up cvs/tcp with CVS_PORT as default */
  3220.     portenv = getenv ("CVS_CLIENT_PORT");
  3221.     if (portenv != NULL)
  3222.     {
  3223.     port = atoi (portenv);
  3224.     if (port <= 0)
  3225.     {
  3226.         error (0, 0, "CVS_CLIENT_PORT must be a positive number!  If you");
  3227.         error (0, 0, "are trying to force a connection via rsh, please");
  3228.         error (0, 0, "put \":server:\" at the beginning of your CVSROOT");
  3229.         error (1, 0, "variable.");
  3230.     }
  3231.     if (trace)
  3232.         fprintf(stderr, "Using TCP port %d to contact server.\n", port);
  3233.     port = htons (port);
  3234.     }
  3235.     else
  3236.     {
  3237.     struct servent *sp;
  3238.  
  3239.     sp = getservbyname ("cvs", "tcp");
  3240.     if (sp == NULL)
  3241.         port = htons (CVS_PORT);
  3242.     else
  3243.         port = sp->s_port;
  3244.     }
  3245.  
  3246.     s = socket (AF_INET, SOCK_STREAM, 0);
  3247.     if (s < 0)
  3248.     error (1, errno, "socket");
  3249.  
  3250.     memset (&sin, 0, sizeof sin);
  3251.     sin.sin_family = AF_INET;
  3252.     sin.sin_addr.s_addr = INADDR_ANY;
  3253.     sin.sin_port = 0;
  3254.  
  3255.     if (bind (s, (struct sockaddr *) &sin, sizeof sin) < 0)
  3256.     error (1, errno, "bind");
  3257.  
  3258.     memcpy (&sin.sin_addr, hp->h_addr, hp->h_length);
  3259.     sin.sin_port = port;
  3260.  
  3261.     if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0)
  3262.     {
  3263.     error (0, errno, "connect");
  3264.     close (s);
  3265.     }
  3266.     else
  3267.     {
  3268. #ifdef HAVE_KERBEROS
  3269.     struct sockaddr_in laddr;
  3270.     int laddrlen;
  3271.     MSG_DAT msg_data;
  3272.     CREDENTIALS cred;
  3273.  
  3274.     laddrlen = sizeof (laddr);
  3275.     if (getsockname (s, (struct sockaddr *) &laddr, &laddrlen) < 0)
  3276.         error (1, errno, "getsockname");
  3277.  
  3278.     /* We don't care about the checksum, and pass it as zero.  */
  3279.     status = krb_sendauth (KOPT_DO_MUTUAL, s, &ticket, "rcmd",
  3280.                    hname, realm, (unsigned long) 0, &msg_data,
  3281.                    &cred, sched, &laddr, &sin, "KCVSV1.0");
  3282.     if (status != KSUCCESS)
  3283.         {
  3284.         error (0, 0, "kerberos: %s", krb_get_err_text(status));
  3285.         close (s);
  3286.         }
  3287.     else
  3288.         {
  3289.         memcpy (kblock, cred.session, sizeof (C_Block));
  3290.  
  3291. #endif /* HAVE_KERBEROS */
  3292.  
  3293.         server_fd = s;
  3294.         close_on_exec (server_fd);
  3295.         tofd = fromfd = s;
  3296.  
  3297. #ifdef HAVE_KERBEROS
  3298.         }
  3299. #endif /* HAVE_KERBEROS */
  3300.     }
  3301.   
  3302.     if (tofd == -1)
  3303.     {
  3304. #ifdef HAVE_KERBEROS
  3305.     error (0, 0, "Kerberos connect failed");
  3306. #else
  3307.     error (0, 0, "Direct TCP connect failed");
  3308. #endif
  3309.     error (1, 0, "couldn't connect to remote host %s", CVSroot_hostname);
  3310.     }
  3311.  
  3312.     free (hname);
  3313.  
  3314.     /* Give caller the values it wants. */
  3315.     *tofdp   = tofd;
  3316.     *fromfdp = fromfd;
  3317. }
  3318.  
  3319. #endif /* HAVE_KERBEROS || USE_DIRECT_TCP */
  3320.  
  3321. static int send_variable_proc PROTO ((Node *, void *));
  3322.  
  3323. static int
  3324. send_variable_proc (node, closure)
  3325.     Node *node;
  3326.     void *closure;
  3327. {
  3328.     send_to_server ("Set ", 0);
  3329.     send_to_server (node->key, 0);
  3330.     send_to_server ("=", 1);
  3331.     send_to_server (node->data, 0);
  3332.     send_to_server ("\012", 1);
  3333.     return 0;
  3334. }
  3335.  
  3336. /* Contact the server.  */
  3337. void
  3338. start_server ()
  3339. {
  3340.     int tofd, fromfd;
  3341.     char *log = getenv ("CVS_CLIENT_LOG");
  3342.  
  3343.     /* Note that generally speaking we do *not* fall back to a different
  3344.        way of connecting if the first one does not work.  This is slow
  3345.        (*really* slow on a 14.4kbps link); the clean way to have a CVS
  3346.        which supports several ways of connecting is with access methods.  */
  3347.  
  3348.     switch (CVSroot_method)
  3349.     {
  3350.  
  3351. #ifdef AUTH_CLIENT_SUPPORT
  3352.     case pserver_method:
  3353.         /* Toss the return value.  It will die with error if anything
  3354.            goes wrong anyway. */
  3355.         connect_to_pserver (&tofd, &fromfd, 0);
  3356.         break;
  3357. #endif
  3358.  
  3359. #if HAVE_KERBEROS || USE_DIRECT_TCP
  3360.     case kserver_method:
  3361.         start_tcp_server (&tofd, &fromfd);
  3362.         break;
  3363. #endif
  3364.  
  3365.     case server_method:
  3366. #if ! RSH_NOT_TRANSPARENT
  3367.         start_rsh_server (&tofd, &fromfd);
  3368. #else
  3369.  
  3370. #  if defined(START_SERVER)
  3371.         START_SERVER (&tofd, &fromfd, getcaller (),
  3372.               CVSroot_username, CVSroot_hostname,
  3373.               CVSroot_directory);
  3374. #  endif
  3375. #endif
  3376.         break;
  3377.  
  3378.     default:
  3379.         error (1, 0, "\
  3380. (start_server internal error): unknown access method");
  3381.         break;
  3382.     }
  3383.  
  3384. #if defined(VMS) && defined(NO_SOCKET_TO_FD)
  3385.     /* Avoid mixing sockets with stdio */
  3386.     use_socket_style = 1;
  3387.     server_sock = tofd;
  3388. #endif /* VMS && NO_SOCKET_TO_FD */
  3389.  
  3390.     /* "Hi, I'm Darlene and I'll be your server tonight..." */
  3391.     server_started = 1;
  3392.  
  3393. #ifdef NO_SOCKET_TO_FD
  3394.     if (use_socket_style)
  3395.     {
  3396.     to_server = socket_buffer_initialize (server_sock, 0,
  3397.                           buf_memory_error);
  3398.     from_server = socket_buffer_initialize (server_sock, 1,
  3399.                         buf_memory_error);
  3400.     }
  3401.     else
  3402. #endif /* NO_SOCKET_TO_FD */
  3403.     {
  3404.         /* todo: some OS's don't need these calls... */
  3405.         close_on_exec (tofd);
  3406.         close_on_exec (fromfd);
  3407.  
  3408.     /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes
  3409.        fdopening the same file descriptor twice, so dup it if it is the
  3410.        same.  */
  3411.     if (tofd == fromfd)
  3412.     {
  3413.         fromfd = dup (tofd);
  3414.         if (fromfd < 0)
  3415.         error (1, errno, "cannot dup net connection");
  3416.     }
  3417.  
  3418.         /* These will use binary mode on systems which have it.  */
  3419.         to_server_fp = fdopen (tofd, FOPEN_BINARY_WRITE);
  3420.         if (to_server_fp == NULL)
  3421.         error (1, errno, "cannot fdopen %d for write", tofd);
  3422.     to_server = stdio_buffer_initialize (to_server_fp, 0,
  3423.                          buf_memory_error);
  3424.  
  3425.         from_server_fp = fdopen (fromfd, FOPEN_BINARY_READ);
  3426.         if (from_server_fp == NULL)
  3427.         error (1, errno, "cannot fdopen %d for read", fromfd);
  3428.     from_server = stdio_buffer_initialize (from_server_fp, 1,
  3429.                            buf_memory_error);
  3430.     }
  3431.  
  3432.     /* Set up logfiles, if any. */
  3433.     if (log)
  3434.     {
  3435.     int len = strlen (log);
  3436.     char *buf = xmalloc (len + 5);
  3437.     char *p;
  3438.     FILE *fp;
  3439.  
  3440.     strcpy (buf, log);
  3441.     p = buf + len;
  3442.  
  3443.     /* Open logfiles in binary mode so that they reflect
  3444.        exactly what was transmitted and received (that is
  3445.        more important than that they be maximally
  3446.        convenient to view).  */
  3447.     strcpy (p, ".in");
  3448.     fp = open_file (buf, "wb");
  3449.         if (fp == NULL)
  3450.         error (0, errno, "opening to-server logfile %s", buf);
  3451.     else
  3452.         to_server = log_buffer_initialize (to_server, fp, 0,
  3453.                            buf_memory_error);
  3454.  
  3455.     strcpy (p, ".out");
  3456.     fp = open_file (buf, "wb");
  3457.         if (fp == NULL)
  3458.         error (0, errno, "opening from-server logfile %s", buf);
  3459.     else
  3460.         from_server = log_buffer_initialize (from_server, fp, 1,
  3461.                          buf_memory_error);
  3462.  
  3463.     free (buf);
  3464.     }
  3465.  
  3466.     /* Clear static variables.  */
  3467.     if (toplevel_repos != NULL)
  3468.     free (toplevel_repos);
  3469.     toplevel_repos = NULL;
  3470.     if (last_dir_name != NULL)
  3471.     free (last_dir_name);
  3472.     last_dir_name = NULL;
  3473.     if (last_repos != NULL)
  3474.     free (last_repos);
  3475.     last_repos = NULL;
  3476.     if (last_update_dir != NULL)
  3477.     free (last_update_dir);
  3478.     last_update_dir = NULL;
  3479.     stored_checksum_valid = 0;
  3480.     stored_mode_valid = 0;
  3481.  
  3482.     if (strcmp (command_name, "init") != 0)
  3483.     {
  3484.     send_to_server ("Root ", 0);
  3485.     send_to_server (CVSroot_directory, 0);
  3486.     send_to_server ("\012", 1);
  3487.     }
  3488.  
  3489.     {
  3490.     struct response *rs;
  3491.  
  3492.     send_to_server ("Valid-responses", 0);
  3493.  
  3494.     for (rs = responses; rs->name != NULL; ++rs)
  3495.     {
  3496.         send_to_server (" ", 0);
  3497.         send_to_server (rs->name, 0);
  3498.     }
  3499.     send_to_server ("\012", 1);
  3500.     }
  3501.     send_to_server ("valid-requests\012", 0);
  3502.  
  3503.     if (get_server_responses ())
  3504.     exit (EXIT_FAILURE);
  3505.  
  3506.     /*
  3507.      * Now handle global options.
  3508.      *
  3509.      * -H, -f, -d, -e should be handled OK locally.
  3510.      *
  3511.      * -b we ignore (treating it as a server installation issue).
  3512.      * FIXME: should be an error message.
  3513.      *
  3514.      * -v we print local version info; FIXME: Add a protocol request to get
  3515.      * the version from the server so we can print that too.
  3516.      *
  3517.      * -l -t -r -w -q -n and -Q need to go to the server.
  3518.      */
  3519.  
  3520.     {
  3521.     int have_global = supported_request ("Global_option");
  3522.  
  3523.     if (noexec)
  3524.     {
  3525.         if (have_global)
  3526.         {
  3527.         send_to_server ("Global_option -n\012", 0);
  3528.         }
  3529.         else
  3530.         error (1, 0,
  3531.                "This server does not support the global -n option.");
  3532.     }
  3533.     if (quiet)
  3534.     {
  3535.         if (have_global)
  3536.         {
  3537.         send_to_server ("Global_option -q\012", 0);
  3538.         }
  3539.         else
  3540.         error (1, 0,
  3541.                "This server does not support the global -q option.");
  3542.     }
  3543.     if (really_quiet)
  3544.     {
  3545.         if (have_global)
  3546.         {
  3547.         send_to_server ("Global_option -Q\012", 0);
  3548.         }
  3549.         else
  3550.         error (1, 0,
  3551.                "This server does not support the global -Q option.");
  3552.     }
  3553.     if (!cvswrite)
  3554.     {
  3555.         if (have_global)
  3556.         {
  3557.         send_to_server ("Global_option -r\012", 0);
  3558.         }
  3559.         else
  3560.         error (1, 0,
  3561.                "This server does not support the global -r option.");
  3562.     }
  3563.     if (trace)
  3564.     {
  3565.         if (have_global)
  3566.         {
  3567.         send_to_server ("Global_option -t\012", 0);
  3568.         }
  3569.         else
  3570.         error (1, 0,
  3571.                "This server does not support the global -t option.");
  3572.     }
  3573.     if (logoff)
  3574.     {
  3575.         if (have_global)
  3576.         {
  3577.         send_to_server ("Global_option -l\012", 0);
  3578.         }
  3579.         else
  3580.         error (1, 0,
  3581.                "This server does not support the global -l option.");
  3582.     }
  3583.     }
  3584.     if (cvsencrypt)
  3585.     {
  3586.     /* Turn on encryption before turning on compression.  We do
  3587.            not want to try to compress the encrypted stream.  Instead,
  3588.            we want to encrypt the compressed stream.  If we can't turn
  3589.            on encryption, bomb out; don't let the user think the data
  3590.            is being encrypted when it is not.  */
  3591. #ifdef HAVE_KERBEROS
  3592.     if (CVSroot_method == kserver_method)
  3593.     {
  3594.         if (! supported_request ("Kerberos-encrypt"))
  3595.         error (1, 0, "This server does not support encryption");
  3596.         send_to_server ("Kerberos-encrypt\012", 0);
  3597.         to_server = krb_encrypt_buffer_initialize (to_server, 0, sched,
  3598.                                kblock,
  3599.                                buf_memory_error);
  3600.         from_server = krb_encrypt_buffer_initialize (from_server, 1,
  3601.                              sched, kblock,
  3602.                              buf_memory_error);
  3603.     }
  3604.     else
  3605. #endif
  3606.         error (1, 0, "Encryption is only supported when using Kerberos");
  3607.     }
  3608.     if (gzip_level)
  3609.     {
  3610.     if (supported_request ("Gzip-stream"))
  3611.     {
  3612.         char gzip_level_buf[5];
  3613.         send_to_server ("Gzip-stream ", 0);
  3614.         sprintf (gzip_level_buf, "%d", gzip_level);
  3615.         send_to_server (gzip_level_buf, 0);
  3616.         send_to_server ("\012", 1);
  3617.  
  3618.         /* All further communication with the server will be
  3619.                compressed.  */
  3620.  
  3621.         to_server = compress_buffer_initialize (to_server, 0, gzip_level,
  3622.                             buf_memory_error);
  3623.         from_server = compress_buffer_initialize (from_server, 1,
  3624.                               gzip_level,
  3625.                               buf_memory_error);
  3626.     }
  3627. #ifndef NO_CLIENT_GZIP_PROCESS
  3628.     else if (supported_request ("gzip-file-contents"))
  3629.     {
  3630.             char gzip_level_buf[5];
  3631.         send_to_server ("gzip-file-contents ", 0);
  3632.             sprintf (gzip_level_buf, "%d", gzip_level);
  3633.         send_to_server (gzip_level_buf, 0);
  3634.  
  3635.         send_to_server ("\012", 1);
  3636.  
  3637.         file_gzip_level = gzip_level;
  3638.     }
  3639. #endif
  3640.     else
  3641.     {
  3642.         fprintf (stderr, "server doesn't support gzip-file-contents\n");
  3643.         /* Setting gzip_level to 0 prevents us from giving the
  3644.                error twice if update has to contact the server again
  3645.                to fetch unpatchable files.  */
  3646.         gzip_level = 0;
  3647.     }
  3648.     }
  3649.  
  3650. #ifdef FILENAMES_CASE_INSENSITIVE
  3651.     if (supported_request ("Case"))
  3652.     send_to_server ("Case\012", 0);
  3653. #endif
  3654.  
  3655.     /* If "Set" is not supported, just silently fail to send the variables.
  3656.        Users with an old server should get a useful error message when it
  3657.        fails to recognize the ${=foo} syntax.  This way if someone uses
  3658.        several servers, some of which are new and some old, they can still
  3659.        set user variables in their .cvsrc without trouble.  */
  3660.     if (supported_request ("Set"))
  3661.     walklist (variable_list, send_variable_proc, NULL);
  3662. }
  3663.  
  3664. #ifndef RSH_NOT_TRANSPARENT
  3665. /* Contact the server by starting it with rsh.  */
  3666.  
  3667. /* Right now, we have two different definitions for this function,
  3668.    depending on whether we start the rsh server using popenRW or not.
  3669.    This isn't ideal, and the best thing would probably be to change
  3670.    the OS/2 port to be more like the regular Unix client (i.e., by
  3671.    implementing piped_child)... but I'm doing something else at the
  3672.    moment, and wish to make only one change at a time.  -Karl */
  3673.  
  3674. #ifdef START_RSH_WITH_POPEN_RW
  3675.  
  3676. /* This is actually a crock -- it's OS/2-specific, for no one else
  3677.    uses it.  If I get time, I want to make piped_child and all the
  3678.    other stuff in os2/run.c work right.  In the meantime, this gets us
  3679.    up and running, and that's most important. */
  3680.  
  3681. static void
  3682. start_rsh_server (tofdp, fromfdp)
  3683.     int *tofdp, *fromfdp;
  3684. {
  3685.     int pipes[2];
  3686.  
  3687.     /* If you're working through firewalls, you can set the
  3688.        CVS_RSH environment variable to a script which uses rsh to
  3689.        invoke another rsh on a proxy machine.  */
  3690.     char *cvs_rsh = getenv ("CVS_RSH");
  3691.     char *cvs_server = getenv ("CVS_SERVER");
  3692.     char command[PATH_MAX];
  3693.     int i = 0;
  3694.     /* This needs to fit "rsh", "-b", "-l", "USER", "host",
  3695.        "cmd (w/ args)", and NULL.  We leave some room to grow. */
  3696.     char *rsh_argv[10];
  3697.  
  3698.     if (!cvs_rsh)
  3699.     cvs_rsh = "rsh";
  3700.     if (!cvs_server)
  3701.     cvs_server = "cvs";
  3702.  
  3703.     /* If you are running a very old (Nov 3, 1994, before 1.5)
  3704.      * version of the server, you need to make sure that your .bashrc
  3705.      * on the server machine does not set CVSROOT to something
  3706.      * containing a colon (or better yet, upgrade the server).  */
  3707.  
  3708.     /* The command line starts out with rsh. */
  3709.     rsh_argv[i++] = cvs_rsh;
  3710.  
  3711. #ifdef RSH_NEEDS_BINARY_FLAG
  3712.     /* "-b" for binary, under OS/2. */
  3713.     rsh_argv[i++] = "-b";
  3714. #endif /* RSH_NEEDS_BINARY_FLAG */
  3715.  
  3716.     /* Then we strcat more things on the end one by one. */
  3717.     if (CVSroot_username != NULL)
  3718.     {
  3719.     rsh_argv[i++] = "-l";
  3720.     rsh_argv[i++] = CVSroot_username;
  3721.     }
  3722.  
  3723.     rsh_argv[i++] = CVSroot_hostname;
  3724.     rsh_argv[i++] = cvs_server;
  3725.     rsh_argv[i++] = "server";
  3726.  
  3727.     /* Mark the end of the arg list. */
  3728.     rsh_argv[i]   = (char *) NULL;
  3729.  
  3730.     if (trace)
  3731.     {
  3732.     fprintf (stderr, " -> Starting server: ");
  3733.     fprintf (stderr, "%s", command);
  3734.     putc ('\n', stderr);
  3735.     }
  3736.  
  3737.     /* Do the deed. */
  3738.     rsh_pid = popenRW (rsh_argv, pipes);
  3739.     if (rsh_pid < 0)
  3740.     error (1, errno, "cannot start server via rsh");
  3741.  
  3742.     /* Give caller the file descriptors. */
  3743.     *tofdp   = pipes[0];
  3744.     *fromfdp = pipes[1];
  3745. }
  3746.  
  3747. #else /* ! START_RSH_WITH_POPEN_RW */
  3748.  
  3749. static void
  3750. start_rsh_server (tofdp, fromfdp)
  3751.      int *tofdp;
  3752.      int *fromfdp;
  3753. {
  3754.     /* If you're working through firewalls, you can set the
  3755.        CVS_RSH environment variable to a script which uses rsh to
  3756.        invoke another rsh on a proxy machine.  */
  3757.     char *cvs_rsh = getenv ("CVS_RSH");
  3758.     char *cvs_server = getenv ("CVS_SERVER");
  3759.     char *command;
  3760.  
  3761.     if (!cvs_rsh)
  3762.     cvs_rsh = "rsh";
  3763.     if (!cvs_server)
  3764.     cvs_server = "cvs";
  3765.  
  3766.     /* Pass the command to rsh as a single string.  This shouldn't
  3767.        affect most rsh servers at all, and will pacify some buggy
  3768.        versions of rsh that grab switches out of the middle of the
  3769.        command (they're calling the GNU getopt routines incorrectly).  */
  3770.     command = xmalloc (strlen (cvs_server)
  3771.                + strlen (CVSroot_directory)
  3772.                + 50);
  3773.  
  3774.     /* If you are running a very old (Nov 3, 1994, before 1.5)
  3775.      * version of the server, you need to make sure that your .bashrc
  3776.      * on the server machine does not set CVSROOT to something
  3777.      * containing a colon (or better yet, upgrade the server).  */
  3778.     sprintf (command, "%s server", cvs_server);
  3779.  
  3780.     {
  3781.         char *argv[10];
  3782.     char **p = argv;
  3783.  
  3784.     *p++ = cvs_rsh;
  3785.     *p++ = CVSroot_hostname;
  3786.  
  3787.     /* If the login names differ between client and server
  3788.      * pass it on to rsh.
  3789.      */
  3790.     if (CVSroot_username != NULL)
  3791.     {
  3792.         *p++ = "-l";
  3793.         *p++ = CVSroot_username;
  3794.     }
  3795.  
  3796.     *p++ = command;
  3797.     *p++ = NULL;
  3798.  
  3799.     if (trace)
  3800.         {
  3801.         int i;
  3802.  
  3803.             fprintf (stderr, " -> Starting server: ");
  3804.         for (i = 0; argv[i]; i++)
  3805.             fprintf (stderr, "%s ", argv[i]);
  3806.         putc ('\n', stderr);
  3807.     }
  3808.     rsh_pid = piped_child (argv, tofdp, fromfdp);
  3809.  
  3810.     if (rsh_pid < 0)
  3811.         error (1, errno, "cannot start server via rsh");
  3812.     }
  3813. }
  3814.  
  3815. #endif /* START_RSH_WITH_POPEN_RW */
  3816. #endif /* ! RSH_NOT_TRANSPARENT */
  3817.  
  3818.  
  3819.  
  3820. /* Send an argument STRING.  */
  3821. void
  3822. send_arg (string)
  3823.     char *string;
  3824. {
  3825.     char buf[1];
  3826.     char *p = string;
  3827.  
  3828.     send_to_server ("Argument ", 0);
  3829.  
  3830.     while (*p)
  3831.     {
  3832.     if (*p == '\n')
  3833.     {
  3834.         send_to_server ("\012Argumentx ", 0);
  3835.     }
  3836.     else
  3837.         {
  3838.         buf[0] = *p;
  3839.         send_to_server (buf, 1);
  3840.         }
  3841.     ++p;
  3842.     }
  3843.     send_to_server ("\012", 1);
  3844. }
  3845.  
  3846. static void send_modified PROTO ((char *, char *, Vers_TS *));
  3847.  
  3848. static void
  3849. send_modified (file, short_pathname, vers)
  3850.     char *file;
  3851.     char *short_pathname;
  3852.     Vers_TS *vers;
  3853. {
  3854.     /* File was modified, send it.  */
  3855.     struct stat sb;
  3856.     int fd;
  3857.     char *buf;
  3858.     char *mode_string;
  3859.     int bufsize;
  3860.     int bin;
  3861.  
  3862.     if (trace)
  3863.     (void) fprintf (stderr, " -> Sending file `%s' to server\n", file);
  3864.  
  3865.     /* Don't think we can assume fstat exists.  */
  3866.     if ( CVS_STAT (file, &sb) < 0)
  3867.     error (1, errno, "reading %s", short_pathname);
  3868.  
  3869.     mode_string = mode_to_string (sb.st_mode);
  3870.  
  3871.     /* Beware: on systems using CRLF line termination conventions,
  3872.        the read and write functions will convert CRLF to LF, so the
  3873.        number of characters read is not the same as sb.st_size.  Text
  3874.        files should always be transmitted using the LF convention, so
  3875.        we don't want to disable this conversion.  */
  3876.     bufsize = sb.st_size;
  3877.     buf = xmalloc (bufsize);
  3878.  
  3879.     /* Is the file marked as containing binary data by the "-kb" flag?
  3880.        If so, make sure to open it in binary mode: */
  3881.  
  3882.     if (vers && vers->options)
  3883.       bin = !(strcmp (vers->options, "-kb"));
  3884.     else
  3885.       bin = 0;
  3886.  
  3887. #ifdef BROKEN_READWRITE_CONVERSION
  3888.     if (!bin)
  3889.     {
  3890.     /* If only stdio, not open/write/etc., do text/binary
  3891.        conversion, use convert_file which can compensate
  3892.        (FIXME: we could just use stdio instead which would
  3893.        avoid the whole problem).  */
  3894.     char tfile[1024]; strcpy(tfile, file); strcat(tfile, ".CVSBFCTMP");
  3895.     convert_file (file, O_RDONLY,
  3896.               tfile, O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY);
  3897.     fd = CVS_OPEN (tfile, O_RDONLY | OPEN_BINARY);
  3898.     if (fd < 0)
  3899.         error (1, errno, "reading %s", short_pathname);
  3900.     }
  3901.     else
  3902.     fd = CVS_OPEN (file, O_RDONLY | OPEN_BINARY);
  3903. #else
  3904.     fd = CVS_OPEN (file, O_RDONLY | (bin ? OPEN_BINARY : 0));
  3905. #endif
  3906.  
  3907.     if (fd < 0)
  3908.     error (1, errno, "reading %s", short_pathname);
  3909.  
  3910.     if (file_gzip_level && sb.st_size > 100)
  3911.     {
  3912.     int nread, newsize = 0, gzip_status;
  3913.     pid_t gzip_pid;
  3914.     char *bufp = buf;
  3915.     int readsize = 8192;
  3916. #ifdef LINES_CRLF_TERMINATED
  3917.     char *tempfile;
  3918.     int converting;
  3919. #endif /* LINES_CRLF_TERMINATED */
  3920.  
  3921. #ifdef LINES_CRLF_TERMINATED
  3922.     /* Assume everything in a "cvs import" is text.  */
  3923.     if (vers == NULL)
  3924.         converting = 1;
  3925.     else
  3926.             /* Otherwise, we convert things unless they're binary. */
  3927.         converting = (! bin);
  3928.  
  3929.     if (converting)
  3930.     {
  3931.         /* gzip reads and writes files without munging CRLF
  3932.            sequences, as it should, but files should be
  3933.            transmitted in LF form.  Convert CRLF to LF before
  3934.            gzipping, on systems where this is necessary.
  3935.  
  3936.            If Windows NT supported fork, we could do this by
  3937.            pushing another filter on in front of gzip.  But it
  3938.            doesn't.  I'd have to write a trivial little program to
  3939.            do the conversion and have CVS spawn it off.  But
  3940.            little executables like that always get lost.
  3941.  
  3942.            Alternatively, this cruft could go away if we switched
  3943.            to a gzip library instead of a subprocess; then we
  3944.            could tell gzip to open the file with CRLF translation
  3945.            enabled.  */
  3946.         if (close (fd) < 0)
  3947.         error (0, errno, "warning: can't close %s", short_pathname);
  3948.  
  3949.         tempfile = cvs_temp_name ();
  3950.         convert_file (file, O_RDONLY,
  3951.               tempfile,
  3952.               O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY);
  3953.  
  3954.         /* This OPEN_BINARY doesn't make any difference, I think, because
  3955.            gzip will deal with the inherited handle as it pleases.  But I
  3956.            do remember something obscure in the manuals about propagating
  3957.            the translation mode to created processes via environment
  3958.            variables, ick.  */
  3959.         fd = CVS_OPEN (tempfile, O_RDONLY | OPEN_BINARY);
  3960.         if (fd < 0)
  3961.         error (1, errno, "reading %s", short_pathname);
  3962.     }
  3963. #endif /* LINES_CRLF_TERMINATED */
  3964.  
  3965.     fd = filter_through_gzip (fd, 1, file_gzip_level, &gzip_pid);
  3966.  
  3967.     /* FIXME: is there any reason to go through all this realloc'ing
  3968.        when we could just be writing the data to the network as we read
  3969.        it from gzip?  */
  3970.     while (1)
  3971.     {
  3972.         if ((bufp - buf) + readsize >= bufsize)
  3973.         {
  3974.         /*
  3975.          * We need to expand the buffer if gzip ends up expanding
  3976.          * the file.
  3977.          */
  3978.         newsize = bufp - buf;
  3979.         while (newsize + readsize >= bufsize)
  3980.           bufsize *= 2;
  3981.         buf = xrealloc (buf, bufsize);
  3982.         bufp = buf + newsize;
  3983.         }
  3984.         nread = read (fd, bufp, readsize);
  3985.         if (nread < 0)
  3986.         error (1, errno, "reading from gzip pipe");
  3987.         else if (nread == 0)
  3988.         /* eof */
  3989.         break;
  3990.         bufp += nread;
  3991.     }
  3992.     newsize = bufp - buf;
  3993.     if (close (fd) < 0)
  3994.         error (0, errno, "warning: can't close %s", short_pathname);
  3995.  
  3996.     if (waitpid (gzip_pid, &gzip_status, 0) != gzip_pid)
  3997.         error (1, errno, "waiting for gzip proc %ld", (long) gzip_pid);
  3998.     else if (gzip_status != 0)
  3999.         error (1, errno, "gzip exited %d", gzip_status);
  4000.  
  4001. #if LINES_CRLF_TERMINATED
  4002.     if (converting)
  4003.     {
  4004.         if ( CVS_UNLINK (tempfile) < 0)
  4005.         error (0, errno,
  4006.                "warning: can't remove temp file %s", tempfile);
  4007.         free (tempfile);
  4008.         tempfile = NULL;
  4009.     }
  4010. #endif /* LINES_CRLF_TERMINATED */
  4011.  
  4012.         {
  4013.           char tmp[80];
  4014.  
  4015.       send_to_server ("Modified ", 0);
  4016.       send_to_server (file, 0);
  4017.       send_to_server ("\012", 1);
  4018.       send_to_server (mode_string, 0);
  4019.       send_to_server ("\012z", 2);
  4020.       sprintf (tmp, "%lu\n", (unsigned long) newsize);
  4021.       send_to_server (tmp, 0);
  4022.  
  4023.           send_to_server (buf, newsize);
  4024.         }
  4025.     }
  4026.     else
  4027.     {
  4028.         int newsize;
  4029.  
  4030.         {
  4031.         char *bufp = buf;
  4032.         int len;
  4033.  
  4034.         /* FIXME: This is gross.  It assumes that we might read
  4035.            less than st_size bytes (true on NT), but not more.
  4036.            Instead of this we should just be reading a block of
  4037.            data (e.g. 8192 bytes), writing it to the network, and
  4038.            so on until EOF.  */
  4039.         while ((len = read (fd, bufp, (buf + sb.st_size) - bufp)) > 0)
  4040.             bufp += len;
  4041.  
  4042.         if (len < 0)
  4043.             error (1, errno, "reading %s", short_pathname);
  4044.  
  4045.         newsize = bufp - buf;
  4046.     }
  4047.     if (close (fd) < 0)
  4048.         error (0, errno, "warning: can't close %s", short_pathname);
  4049.  
  4050.         {
  4051.           char tmp[80];
  4052.  
  4053.       send_to_server ("Modified ", 0);
  4054.       send_to_server (file, 0);
  4055.       send_to_server ("\012", 1);
  4056.       send_to_server (mode_string, 0);
  4057.       send_to_server ("\012", 1);
  4058.           sprintf (tmp, "%lu\012", (unsigned long) newsize);
  4059.           send_to_server (tmp, 0);
  4060.         }
  4061. #ifdef BROKEN_READWRITE_CONVERSION
  4062.     if (!bin)
  4063.     {
  4064.         char tfile[1024]; strcpy(tfile, file); strcat(tfile, ".CVSBFCTMP");
  4065.         if (CVS_UNLINK (tfile) < 0)
  4066.         error (0, errno, "warning: can't remove temp file %s", tfile);
  4067.     }
  4068. #endif
  4069.  
  4070.     /*
  4071.      * Note that this only ends with a newline if the file ended with
  4072.      * one.
  4073.      */
  4074.     if (newsize > 0)
  4075.           send_to_server (buf, newsize);
  4076.     }
  4077.     free (buf);
  4078.     free (mode_string);
  4079. }
  4080.  
  4081. static int send_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  4082.  
  4083. /* Deal with one file.  */
  4084. static int
  4085. send_fileproc (callerdat, finfo)
  4086.     void *callerdat;
  4087.     struct file_info *finfo;
  4088. {
  4089.     Vers_TS *vers;
  4090.     struct file_info xfinfo;
  4091.     /* File name to actually use.  Might differ in case from
  4092.        finfo->file.  */
  4093.     char *filename;
  4094.  
  4095.     send_a_repository ("", finfo->repository, finfo->update_dir);
  4096.  
  4097.     xfinfo = *finfo;
  4098.     xfinfo.repository = NULL;
  4099.     xfinfo.rcs = NULL;
  4100.     vers = Version_TS (&xfinfo, NULL, NULL, NULL, 0, 0);
  4101.  
  4102.     if (vers->entdata != NULL)
  4103.     filename = vers->entdata->user;
  4104.     else
  4105.     filename = finfo->file;
  4106.  
  4107.     if (vers->vn_user != NULL)
  4108.     {
  4109.       char *tmp;
  4110.  
  4111.       tmp = xmalloc (strlen (filename) + strlen (vers->vn_user)
  4112.              + strlen (vers->options) + 200);
  4113.       sprintf (tmp, "Entry /%s/%s/%s%s/%s/", 
  4114.                filename, vers->vn_user,
  4115.                vers->ts_conflict == NULL ? "" : "+",
  4116.                (vers->ts_conflict == NULL ? ""
  4117.                 : (vers->ts_user != NULL &&
  4118.                    strcmp (vers->ts_conflict, vers->ts_user) == 0
  4119.                    ? "="
  4120.                    : "modified")),
  4121.                vers->options);
  4122.  
  4123.     /* The Entries request.  */
  4124.     /* Not sure about whether this deals with -k and stuff right.  */
  4125.     send_to_server (tmp, 0);
  4126.         free (tmp);
  4127.     if (vers->entdata != NULL && vers->entdata->tag)
  4128.     {
  4129.         send_to_server ("T", 0);
  4130.         send_to_server (vers->entdata->tag, 0);
  4131.     }
  4132.     else if (vers->entdata != NULL && vers->entdata->date)
  4133.           {
  4134.         send_to_server ("D", 0);
  4135.         send_to_server (vers->entdata->date, 0);
  4136.           }
  4137.     send_to_server ("\012", 1);
  4138.     }
  4139.  
  4140.     if (vers->ts_user == NULL)
  4141.     {
  4142.     /*
  4143.      * Do we want to print "file was lost" like normal CVS?
  4144.      * Would it always be appropriate?
  4145.      */
  4146.     /* File no longer exists.  */
  4147.     if (!use_unchanged)
  4148.     {
  4149.         /* if the server is old, use the old request... */
  4150.         send_to_server ("Lost ", 0);
  4151.         send_to_server (filename, 0);
  4152.         send_to_server ("\012", 1);
  4153.         /*
  4154.          * Otherwise, don't do anything for missing files,
  4155.          * they just happen.
  4156.          */
  4157.     }
  4158.     }
  4159.     else if (vers->ts_rcs == NULL
  4160.          || strcmp (vers->ts_user, vers->ts_rcs) != 0)
  4161.     {
  4162.     send_modified (filename, finfo->fullname, vers);
  4163.     }
  4164.     else
  4165.     {
  4166.     /* Only use this request if the server supports it... */
  4167.     if (use_unchanged)
  4168.           {
  4169.         send_to_server ("Unchanged ", 0);
  4170.         send_to_server (filename, 0);
  4171.         send_to_server ("\012", 1);
  4172.           }
  4173.     }
  4174.  
  4175.     /* if this directory has an ignore list, add this file to it */
  4176.     if (ignlist)
  4177.     {
  4178.     Node *p;
  4179.  
  4180.     p = getnode ();
  4181.     p->type = FILES;
  4182.     p->key = xstrdup (finfo->file);
  4183.     (void) addnode (ignlist, p);
  4184.     }
  4185.  
  4186.     freevers_ts (&vers);
  4187.     return 0;
  4188. }
  4189.  
  4190. static void send_ignproc PROTO ((char *, char *));
  4191.  
  4192. static void
  4193. send_ignproc (file, dir)
  4194.     char *file;
  4195.     char *dir;
  4196. {
  4197.     if (ign_inhibit_server || !supported_request ("Questionable"))
  4198.     {
  4199.     if (dir[0] != '\0')
  4200.         (void) printf ("? %s/%s\n", dir, file);
  4201.     else
  4202.         (void) printf ("? %s\n", file);
  4203.     }
  4204.     else
  4205.     {
  4206.     send_to_server ("Questionable ", 0);
  4207.     send_to_server (file, 0);
  4208.     send_to_server ("\012", 1);
  4209.     }
  4210. }
  4211.  
  4212. static int send_filesdoneproc PROTO ((void *, int, char *, char *, List *));
  4213.  
  4214. static int
  4215. send_filesdoneproc (callerdat, err, repository, update_dir, entries)
  4216.     void *callerdat;
  4217.     int err;
  4218.     char *repository;
  4219.     char *update_dir;
  4220.     List *entries;
  4221. {
  4222.     /* if this directory has an ignore list, process it then free it */
  4223.     if (ignlist)
  4224.     {
  4225.     ignore_files (ignlist, entries, update_dir, send_ignproc);
  4226.     dellist (&ignlist);
  4227.     }
  4228.  
  4229.     return (err);
  4230. }
  4231.  
  4232. static Dtype send_dirent_proc PROTO ((void *, char *, char *, char *, List *));
  4233.  
  4234. /*
  4235.  * send_dirent_proc () is called back by the recursion processor before a
  4236.  * sub-directory is processed for update.
  4237.  * A return code of 0 indicates the directory should be
  4238.  * processed by the recursion code.  A return of non-zero indicates the
  4239.  * recursion code should skip this directory.
  4240.  *
  4241.  */
  4242. static Dtype
  4243. send_dirent_proc (callerdat, dir, repository, update_dir, entries)
  4244.     void *callerdat;
  4245.     char *dir;
  4246.     char *repository;
  4247.     char *update_dir;
  4248.     List *entries;
  4249. {
  4250.     int dir_exists;
  4251.     char *cvsadm_name;
  4252.     char *cvsadm_repos_name;
  4253.  
  4254.     if (ignore_directory (update_dir))
  4255.     {
  4256.     /* print the warm fuzzy message */
  4257.     if (!quiet)
  4258.         error (0, 0, "Ignoring %s", update_dir);
  4259.         return (R_SKIP_ALL);
  4260.     }
  4261.  
  4262.     /*
  4263.      * If the directory does not exist yet (e.g. "cvs update -d foo"),
  4264.      * no need to send any files from it.  If the directory does not
  4265.      * have a CVS directory, then we pretend that it does not exist.
  4266.      * Otherwise, we will fail when trying to open the Entries file.
  4267.      * This case will happen when checking out a module defined as
  4268.      * ``-a .''.
  4269.      */
  4270.     cvsadm_name = xmalloc (strlen (dir) + sizeof (CVSADM) + 10);
  4271.     sprintf (cvsadm_name, "%s/%s", dir, CVSADM);
  4272.     dir_exists = isdir (cvsadm_name);
  4273.     free (cvsadm_name);
  4274.  
  4275.     /* initialize the ignore list for this directory */
  4276.     ignlist = getlist ();
  4277.  
  4278.     /*
  4279.      * If there is an empty directory (e.g. we are doing `cvs add' on a
  4280.      * newly-created directory), the server still needs to know about it.
  4281.      */
  4282.  
  4283.     cvsadm_repos_name = xmalloc (strlen (dir) + sizeof (CVSADM_REP) + 80);
  4284.     sprintf (cvsadm_repos_name, "%s/%s", dir, CVSADM_REP);
  4285.     if (dir_exists && isreadable (cvsadm_repos_name))
  4286.     {
  4287.     /*
  4288.      * Get the repository from a CVS/Repository file whenever possible.
  4289.      * The repository variable is wrong if the names in the local
  4290.      * directory don't match the names in the repository.
  4291.      */
  4292.     char *repos = Name_Repository (dir, update_dir);
  4293.     send_a_repository (dir, repos, update_dir);
  4294.     free (repos);
  4295.     }
  4296.     else
  4297.     send_a_repository (dir, repository, update_dir);
  4298.     free (cvsadm_repos_name);
  4299.  
  4300.     return (dir_exists ? R_PROCESS : R_SKIP_ALL);
  4301. }
  4302.  
  4303. /*
  4304.  * Send each option in a string to the server, one by one.
  4305.  * This assumes that the options are separated by spaces, for example
  4306.  * STRING might be "--foo -C5 -y".
  4307.  */
  4308.  
  4309. void
  4310. send_option_string (string)
  4311.     char *string;
  4312. {
  4313.     char *copy;
  4314.     char *p;
  4315.  
  4316.     copy = xstrdup (string);
  4317.     p = copy;
  4318.     while (1)
  4319.     {
  4320.         char *s;
  4321.     char l;
  4322.  
  4323.     for (s = p; *s != ' ' && *s != '\0'; s++)
  4324.         ;
  4325.     l = *s;
  4326.     *s = '\0';
  4327.     if (s != p)
  4328.         send_arg (p);
  4329.     if (l == '\0')
  4330.         break;
  4331.     p = s + 1;
  4332.     }
  4333.     free (copy);
  4334. }
  4335.  
  4336.  
  4337. /* Send the names of all the argument files to the server.  */
  4338.  
  4339. void
  4340. send_file_names (argc, argv, flags)
  4341.     int argc;
  4342.     char **argv;
  4343.     unsigned int flags;
  4344. {
  4345.     int i;
  4346.     char *p;
  4347.     char *q;
  4348.     int level;
  4349.     int max_level;
  4350.     char *line;
  4351.     size_t line_allocated;
  4352.  
  4353.     line = NULL;
  4354.     line_allocated = 0;
  4355.  
  4356.     /* The fact that we do this here as well as start_recursion is a bit 
  4357.        of a performance hit.  Perhaps worth cleaning up someday.  */
  4358.     if (flags & SEND_EXPAND_WILD)
  4359.     expand_wild (argc, argv, &argc, &argv);
  4360.  
  4361.     /* Send Max-dotdot if needed.  */
  4362.     max_level = 0;
  4363.     for (i = 0; i < argc; ++i)
  4364.     {
  4365.     p = argv[i];
  4366.     level = 0;
  4367.     do
  4368.     {
  4369.         q = strchr (p, '/');
  4370.         if (q != NULL)
  4371.         ++q;
  4372.         if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || p[2] == '/'))
  4373.         {
  4374.         --level;
  4375.         if (-level > max_level)
  4376.             max_level = -level;
  4377.         }
  4378.         else if (p[0] == '.' && (p[1] == '\0' || p[1] == '/'))
  4379.         ;
  4380.         else
  4381.         ++level;
  4382.         p = q;
  4383.     } while (p != NULL);
  4384.     }
  4385.     if (max_level > 0)
  4386.     {
  4387.     if (supported_request ("Max-dotdot"))
  4388.     {
  4389.             char buf[10];
  4390.             sprintf (buf, "%d", max_level);
  4391.  
  4392.         send_to_server ("Max-dotdot ", 0);
  4393.         send_to_server (buf, 0);
  4394.         send_to_server ("\012", 1);
  4395.     }
  4396.     else
  4397.         /*
  4398.          * "leading .." is not strictly correct, as this also includes
  4399.          * cases like "foo/../..".  But trying to explain that in the
  4400.          * error message would probably just confuse users.
  4401.          */
  4402.         error (1, 0,
  4403.            "leading .. not supported by old (pre-Max-dotdot) servers");
  4404.     }
  4405.  
  4406.     for (i = 0; i < argc; ++i)
  4407.     {
  4408.     char buf[1];
  4409.     char *p = argv[i];
  4410.  
  4411. #ifdef FILENAMES_CASE_INSENSITIVE
  4412.     /* We want to send the file name as it appears
  4413.        in CVS/Entries.  We put this inside an ifdef
  4414.        to avoid doing all these system calls in
  4415.        cases where fncmp is just strcmp anyway.  */
  4416.     /* For now just do this for files in the local
  4417.        directory.  Would be nice to handle the
  4418.        non-local case too, though.  */
  4419.     if (p == last_component (p))
  4420.     {
  4421.         FILE *ent;
  4422.  
  4423.         ent = CVS_FOPEN (CVSADM_ENT, "r");
  4424.         if (ent == NULL)
  4425.         {
  4426.         if (!existence_error (errno))
  4427.             error (0, errno, "cannot read %s", CVSADM_ENT);
  4428.         }
  4429.         else
  4430.         {
  4431.         while (getline (&line, &line_allocated, ent) > 0)
  4432.         {
  4433.             char *cp;
  4434.  
  4435.             if (line[0] != '/')
  4436.             continue;
  4437.             cp = strchr (line + 1, '/');
  4438.             if (cp == NULL)
  4439.             continue;
  4440.             *cp = '\0';
  4441.             if (fncmp (p, line + 1) == 0)
  4442.             {
  4443.             p = line + 1;
  4444.             break;
  4445.             }
  4446.         }
  4447.         if (ferror (ent))
  4448.             error (0, errno, "cannot read %s", CVSADM_ENT);
  4449.         if (fclose (ent) < 0)
  4450.             error (0, errno, "cannot close %s", CVSADM_ENT);
  4451.         /* We don't attempt to look at CVS/Entries.Log.  In a few cases that might
  4452.            lead to strange behaviors, but they should be fairly obscure.  */
  4453.         }
  4454.     }
  4455. #endif /* FILENAMES_CASE_INSENSITIVE */
  4456.  
  4457.     send_to_server ("Argument ", 0);
  4458.  
  4459.     while (*p)
  4460.     {
  4461.         if (*p == '\n')
  4462.         {
  4463.         send_to_server ("\012Argumentx ", 0);
  4464.         }
  4465.         else if (ISDIRSEP (*p))
  4466.         {
  4467.         buf[0] = '/';
  4468.         send_to_server (buf, 1);
  4469.         }
  4470.         else
  4471.         {
  4472.         buf[0] = *p;
  4473.         send_to_server (buf, 1);
  4474.         }
  4475.         ++p;
  4476.     }
  4477.     send_to_server ("\012", 1);
  4478.     }
  4479.  
  4480.     if (line != NULL)
  4481.     free (line);
  4482.  
  4483.     if (flags & SEND_EXPAND_WILD)
  4484.     {
  4485.     int i;
  4486.     for (i = 0; i < argc; ++i)
  4487.         free (argv[i]);
  4488.     free (argv);
  4489.     }
  4490. }
  4491.  
  4492.  
  4493. /*
  4494.  * Send Repository, Modified and Entry.  argc and argv contain only
  4495.  * the files to operate on (or empty for everything), not options.
  4496.  * local is nonzero if we should not recurse (-l option).  Also sends
  4497.  * Argument lines for argc and argv, so should be called after options
  4498.  * are sent.
  4499.  */
  4500. void
  4501. send_files (argc, argv, local, aflag)
  4502.     int argc;
  4503.     char **argv;
  4504.     int local;
  4505.     int aflag;
  4506. {
  4507.     int err;
  4508.  
  4509.     /*
  4510.      * aflag controls whether the tag/date is copied into the vers_ts.
  4511.      * But we don't actually use it, so I don't think it matters what we pass
  4512.      * for aflag here.
  4513.      */
  4514.     err = start_recursion
  4515.     (send_fileproc, send_filesdoneproc,
  4516.      send_dirent_proc, (DIRLEAVEPROC)NULL, NULL,
  4517.      argc, argv, local, W_LOCAL, aflag, 0, (char *)NULL, 0);
  4518.     if (err)
  4519.     exit (EXIT_FAILURE);
  4520.     if (toplevel_repos == NULL)
  4521.     /*
  4522.      * This happens if we are not processing any files,
  4523.      * or for checkouts in directories without any existing stuff
  4524.      * checked out.  The following assignment is correct for the
  4525.      * latter case; I don't think toplevel_repos matters for the
  4526.      * former.
  4527.      */
  4528.     toplevel_repos = xstrdup (CVSroot_directory);
  4529.     send_repository ("", toplevel_repos, ".");
  4530. }
  4531.  
  4532. void
  4533. client_import_setup (repository)
  4534.     char *repository;
  4535. {
  4536.     if (toplevel_repos == NULL)        /* should always be true */
  4537.         send_a_repository ("", repository, "");
  4538. }
  4539.  
  4540. /*
  4541.  * Process the argument import file.
  4542.  */
  4543. int
  4544. client_process_import_file (message, vfile, vtag, targc, targv, repository)
  4545.     char *message;
  4546.     char *vfile;
  4547.     char *vtag;
  4548.     int targc;
  4549.     char *targv[];
  4550.     char *repository;
  4551. {
  4552.     char *short_pathname;
  4553.     int first_time;
  4554.  
  4555.     /* FIXME: I think this is always false now that we call
  4556.        client_import_setup at the start.  */
  4557.  
  4558.     first_time = toplevel_repos == NULL;
  4559.  
  4560.     if (first_time)
  4561.     send_a_repository ("", repository, "");
  4562.  
  4563.     if (strncmp (repository, toplevel_repos, strlen (toplevel_repos)) != 0)
  4564.     error (1, 0,
  4565.            "internal error: pathname `%s' doesn't specify file in `%s'",
  4566.            repository, toplevel_repos);
  4567.     short_pathname = repository + strlen (toplevel_repos) + 1;
  4568.  
  4569.     if (!first_time)
  4570.     {
  4571.     send_a_repository ("", repository, short_pathname);
  4572.     }
  4573.     send_modified (vfile, short_pathname, NULL);
  4574.     return 0;
  4575. }
  4576.  
  4577. void
  4578. client_import_done ()
  4579. {
  4580.     if (toplevel_repos == NULL)
  4581.     /*
  4582.      * This happens if we are not processing any files,
  4583.      * or for checkouts in directories without any existing stuff
  4584.      * checked out.  The following assignment is correct for the
  4585.      * latter case; I don't think toplevel_repos matters for the
  4586.      * former.
  4587.      */
  4588.         /* FIXME: "can't happen" now that we call client_import_setup
  4589.        at the beginning.  */
  4590.     toplevel_repos = xstrdup (CVSroot_directory);
  4591.     send_repository ("", toplevel_repos, ".");
  4592. }
  4593.  
  4594. static void
  4595. notified_a_file (data, ent_list, short_pathname, filename)
  4596.     char *data;
  4597.     List *ent_list;
  4598.     char *short_pathname;
  4599.     char *filename;
  4600. {
  4601.     FILE *fp;
  4602.     FILE *newf;
  4603.     size_t line_len = 8192;
  4604.     char *line = xmalloc (line_len);
  4605.     char *cp;
  4606.     int nread;
  4607.     int nwritten;
  4608.     char *p;
  4609.  
  4610.     fp = open_file (CVSADM_NOTIFY, "r");
  4611.     if (getline (&line, &line_len, fp) < 0)
  4612.     {
  4613.     error (0, errno, "cannot read %s", CVSADM_NOTIFY);
  4614.     goto error_exit;
  4615.     }
  4616.     cp = strchr (line, '\t');
  4617.     if (cp == NULL)
  4618.     {
  4619.     error (0, 0, "malformed %s file", CVSADM_NOTIFY);
  4620.     goto error_exit;
  4621.     }
  4622.     *cp = '\0';
  4623.     if (strcmp (filename, line + 1) != 0)
  4624.     {
  4625.     error (0, 0, "protocol error: notified %s, expected %s", filename,
  4626.            line + 1);
  4627.     }
  4628.  
  4629.     if (getline (&line, &line_len, fp) < 0)
  4630.     {
  4631.     if (feof (fp))
  4632.     {
  4633.         if (fclose (fp) < 0)
  4634.         error (0, errno, "cannot close %s", CVSADM_NOTIFY);
  4635.         if ( CVS_UNLINK (CVSADM_NOTIFY) < 0)
  4636.         error (0, errno, "cannot remove %s", CVSADM_NOTIFY);
  4637.         return;
  4638.     }
  4639.     else
  4640.     {
  4641.         error (0, errno, "cannot read %s", CVSADM_NOTIFY);
  4642.         goto error_exit;
  4643.     }
  4644.     }
  4645.     newf = open_file (CVSADM_NOTIFYTMP, "w");
  4646.     if (fputs (line, newf) < 0)
  4647.     {
  4648.     error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP);
  4649.     goto error2;
  4650.     }
  4651.     while ((nread = fread (line, 1, line_len, fp)) > 0)
  4652.     {
  4653.     p = line;
  4654.     while ((nwritten = fwrite (p, 1, nread, newf)) > 0)
  4655.     {
  4656.         nread -= nwritten;
  4657.         p += nwritten;
  4658.     }
  4659.     if (ferror (newf))
  4660.     {
  4661.         error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP);
  4662.         goto error2;
  4663.     }
  4664.     }
  4665.     if (ferror (fp))
  4666.     {
  4667.     error (0, errno, "cannot read %s", CVSADM_NOTIFY);
  4668.     goto error2;
  4669.     }
  4670.     if (fclose (newf) < 0)
  4671.     {
  4672.     error (0, errno, "cannot close %s", CVSADM_NOTIFYTMP);
  4673.     goto error_exit;
  4674.     }
  4675.     if (fclose (fp) < 0)
  4676.     {
  4677.     error (0, errno, "cannot close %s", CVSADM_NOTIFY);
  4678.     return;
  4679.     }
  4680.  
  4681.     {
  4682.         /* In this case, we want rename_file() to ignore noexec. */
  4683.         int saved_noexec = noexec;
  4684.         noexec = 0;
  4685.         rename_file (CVSADM_NOTIFYTMP, CVSADM_NOTIFY);
  4686.         noexec = saved_noexec;
  4687.     }
  4688.  
  4689.     return;
  4690.   error2:
  4691.     (void) fclose (newf);
  4692.   error_exit:
  4693.     (void) fclose (fp);
  4694. }
  4695.  
  4696. static void
  4697. handle_notified (args, len)
  4698.     char *args;
  4699.     int len;
  4700. {
  4701.     call_in_directory (args, notified_a_file, NULL);
  4702. }
  4703.  
  4704. void
  4705. client_notify (repository, update_dir, filename, notif_type, val)
  4706.     char *repository;
  4707.     char *update_dir;
  4708.     char *filename;
  4709.     int notif_type;
  4710.     char *val;
  4711. {
  4712.     char buf[2];
  4713.  
  4714.     send_a_repository ("", repository, update_dir);
  4715.     send_to_server ("Notify ", 0);
  4716.     send_to_server (filename, 0);
  4717.     send_to_server ("\012", 1);
  4718.     buf[0] = notif_type;
  4719.     buf[1] = '\0';
  4720.     send_to_server (buf, 1);
  4721.     send_to_server ("\t", 1);
  4722.     send_to_server (val, 0);
  4723. }
  4724.  
  4725. /*
  4726.  * Send an option with an argument, dealing correctly with newlines in
  4727.  * the argument.  If ARG is NULL, forget the whole thing.
  4728.  */
  4729. void
  4730. option_with_arg (option, arg)
  4731.     char *option;
  4732.     char *arg;
  4733. {
  4734.     if (arg == NULL)
  4735.     return;
  4736.  
  4737.     send_to_server ("Argument ", 0);
  4738.     send_to_server (option, 0);
  4739.     send_to_server ("\012", 1);
  4740.  
  4741.     send_arg (arg);
  4742. }
  4743.  
  4744. /*
  4745.  * Send a date to the server.  This will passed a string which is the
  4746.  * result of Make_Date, and looks like YY.MM.DD.HH.MM.SS, where all
  4747.  * the letters are single digits.  The time will be GMT.  getdate on
  4748.  * the server can't parse that, so we turn it back into something
  4749.  * which it can parse.
  4750.  */
  4751.  
  4752. void
  4753. client_senddate (date)
  4754.     const char *date;
  4755. {
  4756.     int year, month, day, hour, minute, second;
  4757.     char buf[100];
  4758.  
  4759.     if (sscanf (date, DATEFORM, &year, &month, &day, &hour, &minute, &second)
  4760.     != 6)
  4761.     {
  4762.         error (1, 0, "diff_client_senddate: sscanf failed on date");
  4763.     }
  4764.  
  4765. #ifndef HAVE_RCS5
  4766.     /* We need to fix the timezone in this case; see Make_Date.  */
  4767.     abort ();
  4768. #endif /* HAVE_RCS5 */
  4769.  
  4770.     sprintf (buf, "%d/%d/%d %d:%d:%d GMT", month, day, year,
  4771.          hour, minute, second);
  4772.     option_with_arg ("-D", buf);
  4773. }
  4774.  
  4775. void
  4776. send_init_command ()
  4777. {
  4778.     /* This is here because we need the CVSroot_directory variable.  */
  4779.     send_to_server ("init ", 0);
  4780.     send_to_server (CVSroot_directory, 0);
  4781.     send_to_server ("\012", 0);
  4782. }
  4783.  
  4784. #endif /* CLIENT_SUPPORT */
  4785.