1 /* $OpenBSD: remote.c,v 1.12 2007/01/26 11:19:44 joris Exp $ */ 2 /* 3 * Copyright (c) 2006 Joris Vink <joris@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include "includes.h" 19 20 #include "cvs.h" 21 #include "log.h" 22 #include "diff.h" 23 #include "remote.h" 24 25 struct cvs_resp * 26 cvs_remote_get_response_info(const char *response) 27 { 28 int i; 29 30 for (i = 0; cvs_responses[i].supported != -1; i++) { 31 if (!strcmp(cvs_responses[i].name, response)) 32 return (&(cvs_responses[i])); 33 } 34 35 return (NULL); 36 } 37 38 struct cvs_req * 39 cvs_remote_get_request_info(const char *request) 40 { 41 int i; 42 43 for (i = 0; cvs_requests[i].supported != -1; i++) { 44 if (!strcmp(cvs_requests[i].name, request)) 45 return (&(cvs_requests[i])); 46 } 47 48 return (NULL); 49 } 50 51 void 52 cvs_remote_output(const char *data) 53 { 54 FILE *out; 55 56 if (cvs_server_active) 57 out = stdout; 58 else 59 out = current_cvsroot->cr_srvin; 60 61 fputs(data, out); 62 fputs("\n", out); 63 } 64 65 char * 66 cvs_remote_input(void) 67 { 68 FILE *in; 69 size_t len; 70 char *data, *ldata; 71 72 if (cvs_server_active) 73 in = stdin; 74 else 75 in = current_cvsroot->cr_srvout; 76 77 data = fgetln(in, &len); 78 if (data == NULL) { 79 if (sig_received != 0) 80 fatal("received signal %d", sig_received); 81 82 if (cvs_server_active) { 83 cvs_cleanup(); 84 exit(0); 85 } 86 87 fatal("the connection has been closed by the server"); 88 } 89 90 if (data[len - 1] == '\n') { 91 data[len - 1] = '\0'; 92 ldata = xstrdup(data); 93 } else { 94 ldata = xmalloc(len + 1); 95 memcpy(ldata, data, len); 96 ldata[len] = '\0'; 97 } 98 99 if (cvs_server_active == 0 && cvs_client_outlog_fd != -1) { 100 BUF *bp; 101 102 bp = cvs_buf_alloc(strlen(ldata), BUF_AUTOEXT); 103 104 if (cvs_buf_append(bp, ldata, strlen(ldata)) < 0) 105 fatal("cvs_remote_input: cvs_buf_append"); 106 107 cvs_buf_putc(bp, '\n'); 108 109 if (cvs_buf_write_fd(bp, cvs_client_outlog_fd) < 0) 110 fatal("cvs_remote_input: cvs_buf_write_fd"); 111 112 cvs_buf_free(bp); 113 } 114 115 return (ldata); 116 } 117 118 void 119 cvs_remote_receive_file(int fd, size_t len) 120 { 121 FILE *in; 122 char data[MAXBSIZE]; 123 size_t nread, nwrite, nleft, toread; 124 125 if (cvs_server_active) 126 in = stdin; 127 else 128 in = current_cvsroot->cr_srvout; 129 130 nleft = len; 131 132 while (nleft > 0) { 133 toread = MIN(nleft, MAXBSIZE); 134 135 nread = fread(data, sizeof(char), toread, in); 136 if (nread == 0) 137 fatal("error receiving file"); 138 139 nwrite = write(fd, data, nread); 140 if (nwrite != nread) 141 fatal("failed to write %zu bytes", nread); 142 143 if (cvs_server_active == 0 && 144 cvs_client_outlog_fd != -1) 145 (void)write(cvs_client_outlog_fd, data, nread); 146 147 nleft -= nread; 148 } 149 } 150 151 void 152 cvs_remote_send_file(const char *path) 153 { 154 int l, fd; 155 FILE *out, *in; 156 size_t ret, rw; 157 off_t total; 158 struct stat st; 159 char buf[18], data[MAXBSIZE]; 160 161 if (cvs_server_active) 162 out = stdout; 163 else 164 out = current_cvsroot->cr_srvin; 165 166 if ((fd = open(path, O_RDONLY)) == -1) 167 fatal("cvs_remote_send_file: %s: %s", path, strerror(errno)); 168 169 if (fstat(fd, &st) == -1) 170 fatal("cvs_remote_send_file: %s: %s", path, strerror(errno)); 171 172 cvs_modetostr(st.st_mode, buf, sizeof(buf)); 173 cvs_remote_output(buf); 174 175 l = snprintf(buf, sizeof(buf), "%lld", st.st_size); 176 if (l == -1 || l >= (int)sizeof(buf)) 177 fatal("cvs_remote_send_file: overflow"); 178 cvs_remote_output(buf); 179 180 if ((in = fdopen(fd, "r")) == NULL) 181 fatal("cvs_remote_send_file: fdopen %s", strerror(errno)); 182 183 total = 0; 184 while ((ret = fread(data, sizeof(char), MAXBSIZE, in)) != 0) { 185 rw = fwrite(data, sizeof(char), ret, out); 186 if (rw != ret) 187 fatal("failed to write %zu bytes", ret); 188 189 if (cvs_server_active == 0 && 190 cvs_client_outlog_fd != -1) 191 (void)write(cvs_client_outlog_fd, data, ret); 192 193 total += ret; 194 } 195 196 if (total != st.st_size) 197 fatal("length mismatch, %lld vs %lld", total, st.st_size); 198 199 (void)fclose(in); 200 } 201 202 void 203 cvs_remote_classify_file(struct cvs_file *cf) 204 { 205 struct stat st; 206 CVSENTRIES *entlist; 207 208 entlist = cvs_ent_open(cf->file_wd); 209 cf->file_ent = cvs_ent_get(entlist, cf->file_name); 210 cvs_ent_close(entlist, ENT_NOSYNC); 211 212 if (cf->file_ent != NULL && cf->file_ent->ce_status != CVS_ENT_REG) { 213 if (cf->file_ent->ce_status == CVS_ENT_ADDED) 214 cf->file_status = FILE_ADDED; 215 else 216 cf->file_status = FILE_REMOVED; 217 return; 218 } 219 220 if (cf->file_ent != NULL) { 221 if (cf->file_ent->ce_type == CVS_ENT_DIR) 222 cf->file_type = CVS_DIR; 223 else 224 cf->file_type = CVS_FILE; 225 } 226 227 if (cf->fd != -1 && cf->file_ent != NULL) { 228 if (fstat(cf->fd, &st) == -1) 229 fatal("cvs_remote_classify_file(%s): %s", cf->file_path, 230 strerror(errno)); 231 232 if (st.st_mtime != cf->file_ent->ce_mtime) 233 cf->file_status = FILE_MODIFIED; 234 else 235 cf->file_status = FILE_UPTODATE; 236 } else if (cf->fd == -1) { 237 cf->file_status = FILE_UNKNOWN; 238 } 239 240 if (cvs_cmdop == CVS_OP_IMPORT && cf->file_type == CVS_FILE) 241 cf->file_status = FILE_MODIFIED; 242 } 243 244