Edit

IABSD.fr/src/usr.bin/cvs/remote.c

Branch :

  • Show log

    Commit

  • Author : deraadt
    Date : 2021-11-28 19:28:41
    Hash : 1a0afcde
    Message : Stop using MAXBSIZE to eliminate sys/param.h including (which injects a ton of namespace intrusion). Create local sizes, and refactor some code along the way. ok millert

  • usr.bin/cvs/remote.c
  • /*	$OpenBSD: remote.c,v 1.34 2021/11/28 19:28:42 deraadt Exp $	*/
    /*
     * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #include <errno.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #include "atomicio.h"
    #include "cvs.h"
    #include "remote.h"
    
    #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
    #define _MAXBSIZE	(64 * 1024)
    
    struct cvs_resp *
    cvs_remote_get_response_info(const char *response)
    {
    	int i;
    
    	for (i = 0; cvs_responses[i].supported != -1; i++) {
    		if (!strcmp(cvs_responses[i].name, response))
    			return (&(cvs_responses[i]));
    	}
    
    	return (NULL);
    }
    
    struct cvs_req *
    cvs_remote_get_request_info(const char *request)
    {
    	int i;
    
    	for (i = 0; cvs_requests[i].supported != -1; i++) {
    		if (!strcmp(cvs_requests[i].name, request))
    			return (&(cvs_requests[i]));
    	}
    
    	return (NULL);
    }
    
    void
    cvs_remote_output(char *data)
    {
    	FILE *out;
    	size_t len;
    	char nl = '\n';
    
    	if (cvs_server_active)
    		out = stdout;
    	else
    		out = current_cvsroot->cr_srvin;
    
    	fputs(data, out);
    	fputs("\n", out);
    
    	if (cvs_server_active == 0 && cvs_client_inlog_fd != -1) {
    		len = strlen(data);
    		if (atomicio(vwrite, cvs_client_inlog_fd, data, len) != len ||
    		    atomicio(vwrite, cvs_client_inlog_fd, &nl, 1) != 1)
    			fatal("failed to write to log file");
    	}
    }
    
    char *
    cvs_remote_input(void)
    {
    	FILE *in;
    	size_t len;
    	char nl = '\n';
    	char *data, *ldata;
    
    	if (cvs_server_active)
    		in = stdin;
    	else
    		in = current_cvsroot->cr_srvout;
    
    	data = fgetln(in, &len);
    	if (data == NULL) {
    		if (sig_received != 0)
    			fatal("received signal %d", sig_received);
    
    		if (cvs_server_active) {
    			cvs_cleanup();
    			exit(0);
    		}
    
    		fatal("the connection has been closed by the server");
    	}
    
    	if (data[len - 1] == '\n') {
    		data[len - 1] = '\0';
    		ldata = xstrdup(data);
    	} else {
    		ldata = xmalloc(len + 1);
    		memcpy(ldata, data, len);
    		ldata[len] = '\0';
    	}
    
    	if (cvs_server_active == 0 && cvs_client_outlog_fd != -1) {
    		len = strlen(data);
    		if (atomicio(vwrite, cvs_client_outlog_fd, data, len) != len ||
    		    atomicio(vwrite, cvs_client_outlog_fd, &nl, 1) != 1)
    			fatal("failed to write to log file");
    	}
    
    	return (ldata);
    }
    
    void
    cvs_remote_receive_file(int fd, size_t len)
    {
    	FILE *in;
    	char data[_MAXBSIZE];
    	size_t nread, nleft, toread;
    
    	if (cvs_server_active)
    		in = stdin;
    	else
    		in = current_cvsroot->cr_srvout;
    
    	nleft = len;
    
    	while (nleft > 0) {
    		toread = MINIMUM(nleft, sizeof data);
    
    		nread = fread(data, sizeof(char), toread, in);
    		if (nread == 0)
    			fatal("error receiving file");
    
    		if (atomicio(vwrite, fd, data, nread) != nread)
    			fatal("failed to write %zu bytes", nread);
    
    		if (cvs_server_active == 0 && cvs_client_outlog_fd != -1 &&
    		    atomicio(vwrite, cvs_client_outlog_fd, data, nread)
    		    != nread)
    			fatal("failed to write to log file");
    
    		nleft -= nread;
    	}
    }
    
    void
    cvs_remote_send_file(const char *path, int _fd)
    {
    	int fd;
    	FILE *out, *in;
    	size_t ret, rw;
    	off_t total;
    	struct stat st;
    	char buf[18], data[_MAXBSIZE];
    
    	if (cvs_server_active)
    		out = stdout;
    	else
    		out = current_cvsroot->cr_srvin;
    
    	fd = dup(_fd);
    	if (fd == -1)
    		fatal("cvs_remote_send_file: dup: %s", strerror(errno));
    
    	if (lseek(fd, 0, SEEK_SET) == -1)
    		fatal("cvs_remote_send_file: %s: lseek: %s", path,
    		    strerror(errno));
    
    	if (fstat(fd, &st) == -1)
    		fatal("cvs_remote_send_file: %s: fstat: %s", path,
    		    strerror(errno));
    
    	cvs_modetostr(st.st_mode, buf, sizeof(buf));
    	cvs_remote_output(buf);
    
    	(void)xsnprintf(buf, sizeof(buf), "%lld", st.st_size);
    	cvs_remote_output(buf);
    
    	if ((in = fdopen(fd, "r")) == NULL)
    		fatal("cvs_remote_send_file: fdopen %s", strerror(errno));
    
    	total = 0;
    	while ((ret = fread(data, sizeof(char), sizeof data, in)) != 0) {
    		rw = fwrite(data, sizeof(char), ret, out);
    		if (rw != ret)
    			fatal("failed to write %zu bytes", ret);
    
    		if (cvs_server_active == 0 && cvs_client_inlog_fd != -1 &&
    		    atomicio(vwrite, cvs_client_inlog_fd, data, ret) != ret)
    			fatal("failed to write to log file");
    
    		total += ret;
    	}
    
    	if (total != st.st_size)
    		fatal("length mismatch, %lld vs %lld", total, st.st_size);
    
    	(void)fclose(in);
    }
    
    void
    cvs_remote_send_file_buf(char *file, BUF *bp, mode_t mode)
    {
    	char buf[18];
    	u_char *data;
    	size_t len, ret;
    
    	if (cvs_server_active != 1)
    		fatal("cvs_remote_send_file_buf is server only");
    
    	len = buf_len(bp);
    	data = buf_release(bp);
    
    	cvs_modetostr(mode, buf, sizeof(buf));
    	cvs_remote_output(buf);
    
    	(void)xsnprintf(buf, sizeof(buf), "%ld", len);
    	cvs_remote_output(buf);
    
    	ret = fwrite(data, sizeof(char), len, stdout);
    	if (ret != len)
    		cvs_log(LP_ERR, "warning: sent %s truncated", file);
    
    	if (cvs_server_active == 0 && cvs_client_inlog_fd != -1 &&
    	    atomicio(vwrite, cvs_client_inlog_fd, data, len) != len)
    		fatal("failed to write to log file");
    
    	free(data);
    }
    
    void
    cvs_remote_classify_file(struct cvs_file *cf)
    {
    	struct stat st;
    	CVSENTRIES *entlist;
    
    	entlist = cvs_ent_open(cf->file_wd);
    	cf->file_ent = cvs_ent_get(entlist, cf->file_name);
    
    	if (cf->file_ent != NULL && cf->file_ent->ce_status != CVS_ENT_REG) {
    		if (cf->file_ent->ce_status == CVS_ENT_ADDED) {
    			if (cf->fd != -1)
    				cf->file_status = FILE_ADDED;
    			else
    				cf->file_status = FILE_UNKNOWN;
    		} else {
    			cf->file_status = FILE_REMOVED;
    		}
    
    		return;
    	}
    
    	if (cf->file_ent != NULL) {
    		if (cf->file_ent->ce_type == CVS_ENT_DIR)
    			cf->file_type = CVS_DIR;
    		else
    			cf->file_type = CVS_FILE;
    	}
    
    	if (cf->fd != -1)
    		cf->file_flags |= FILE_ON_DISK;
    
    	if ((cf->file_flags & FILE_ON_DISK) && cf->file_ent != NULL) {
    		if (fstat(cf->fd, &st) == -1)
    			fatal("cvs_remote_classify_file(%s): %s", cf->file_path,
    			    strerror(errno));
    
    		if (st.st_mtime != cf->file_ent->ce_mtime ||
    		    cf->file_ent->ce_conflict != NULL)
    			cf->file_status = FILE_MODIFIED;
    		else
    			cf->file_status = FILE_UPTODATE;
    	} else if (!(cf->file_flags & FILE_ON_DISK)) {
    		cf->file_status = FILE_UNKNOWN;
    	}
    
    	if (cvs_cmdop == CVS_OP_IMPORT && cf->file_type == CVS_FILE)
    		cf->file_status = FILE_MODIFIED;
    }
    
    
    void
    cvs_validate_directory(const char *path)
    {
    	char *dir, *sp, *dp;
    
    	dir = xstrdup(path);
    
    	for (sp = dir; sp != NULL; sp = dp) {
    		dp = strchr(sp, '/');
    		if (dp != NULL)
    			*(dp++) = '\0';
    
    		if (!strcmp(sp, ".."))
    			fatal("path validation failed!");
    	}
    
    	free(dir);
    }