Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * An implementation of host to guest copy functionality for Linux.
  3 *
  4 * Copyright (C) 2014, Microsoft, Inc.
  5 *
  6 * Author : K. Y. Srinivasan <kys@microsoft.com>
  7 *
  8 * This program is free software; you can redistribute it and/or modify it
  9 * under the terms of the GNU General Public License version 2 as published
 10 * by the Free Software Foundation.
 11 *
 12 * This program is distributed in the hope that it will be useful, but
 13 * WITHOUT ANY WARRANTY; without even the implied warranty of
 14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
 15 * NON INFRINGEMENT.  See the GNU General Public License for more
 16 * details.
 17 */
 18
 19
 20#include <sys/types.h>
 21#include <sys/socket.h>
 22#include <sys/poll.h>
 23#include <linux/types.h>
 24#include <linux/kdev_t.h>
 25#include <stdio.h>
 26#include <stdlib.h>
 27#include <unistd.h>
 28#include <string.h>
 29#include <ctype.h>
 30#include <errno.h>
 31#include <linux/hyperv.h>
 32#include <syslog.h>
 33#include <sys/stat.h>
 34#include <fcntl.h>
 35#include <dirent.h>
 36
 37static int target_fd;
 38static char target_fname[W_MAX_PATH];
 39
 40static int hv_start_fcopy(struct hv_start_fcopy *smsg)
 41{
 42	int error = HV_E_FAIL;
 43	char *q, *p;
 44
 45	/*
 46	 * If possile append a path seperator to the path.
 47	 */
 48	if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2))
 49		strcat((char *)smsg->path_name, "/");
 50
 51	p = (char *)smsg->path_name;
 52	snprintf(target_fname, sizeof(target_fname), "%s/%s",
 53		(char *)smsg->path_name, smsg->file_name);
 54
 55	syslog(LOG_INFO, "Target file name: %s", target_fname);
 56	/*
 57	 * Check to see if the path is already in place; if not,
 58	 * create if required.
 59	 */
 60	while ((q = strchr(p, '/')) != NULL) {
 61		if (q == p) {
 62			p++;
 63			continue;
 64		}
 65		*q = '\0';
 66		if (access((char *)smsg->path_name, F_OK)) {
 67			if (smsg->copy_flags & CREATE_PATH) {
 68				if (mkdir((char *)smsg->path_name, 0755)) {
 69					syslog(LOG_ERR, "Failed to create %s",
 70						(char *)smsg->path_name);
 71					goto done;
 72				}
 73			} else {
 74				syslog(LOG_ERR, "Invalid path: %s",
 75					(char *)smsg->path_name);
 76				goto done;
 77			}
 78		}
 79		p = q + 1;
 80		*q = '/';
 81	}
 82
 83	if (!access(target_fname, F_OK)) {
 84		syslog(LOG_INFO, "File: %s exists", target_fname);
 85		if (!(smsg->copy_flags & OVER_WRITE)) {
 86			error = HV_ERROR_ALREADY_EXISTS;
 87			goto done;
 88		}
 89	}
 90
 91	target_fd = open(target_fname, O_RDWR | O_CREAT | O_CLOEXEC, 0744);
 92	if (target_fd == -1) {
 93		syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
 94		goto done;
 95	}
 96
 97	error = 0;
 98done:
 99	return error;
100}
101
102static int hv_copy_data(struct hv_do_fcopy *cpmsg)
103{
104	ssize_t bytes_written;
105
106	bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
107				cpmsg->offset);
108
109	if (bytes_written != cpmsg->size)
110		return HV_E_FAIL;
111
112	return 0;
113}
114
115static int hv_copy_finished(void)
116{
117	close(target_fd);
118	return 0;
119}
120static int hv_copy_cancel(void)
121{
122	close(target_fd);
123	unlink(target_fname);
124	return 0;
125
126}
127
128int main(void)
129{
130	int fd, fcopy_fd, len;
131	int error;
132	int version = FCOPY_CURRENT_VERSION;
133	char *buffer[4096 * 2];
134	struct hv_fcopy_hdr *in_msg;
135
136	if (daemon(1, 0)) {
137		syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno));
138		exit(EXIT_FAILURE);
139	}
140
141	openlog("HV_FCOPY", 0, LOG_USER);
142	syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
143
144	fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
145
146	if (fcopy_fd < 0) {
147		syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s",
148			errno, strerror(errno));
149		exit(EXIT_FAILURE);
150	}
151
152	/*
153	 * Register with the kernel.
154	 */
155	if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) {
156		syslog(LOG_ERR, "Registration failed: %s", strerror(errno));
157		exit(EXIT_FAILURE);
158	}
159
160	while (1) {
161		/*
162		 * In this loop we process fcopy messages after the
163		 * handshake is complete.
164		 */
165		len = pread(fcopy_fd, buffer, (4096 * 2), 0);
166		if (len < 0) {
167			syslog(LOG_ERR, "pread failed: %s", strerror(errno));
168			exit(EXIT_FAILURE);
169		}
170		in_msg = (struct hv_fcopy_hdr *)buffer;
171
172		switch (in_msg->operation) {
173		case START_FILE_COPY:
174			error = hv_start_fcopy((struct hv_start_fcopy *)in_msg);
175			break;
176		case WRITE_TO_FILE:
177			error = hv_copy_data((struct hv_do_fcopy *)in_msg);
178			break;
179		case COMPLETE_FCOPY:
180			error = hv_copy_finished();
181			break;
182		case CANCEL_FCOPY:
183			error = hv_copy_cancel();
184			break;
185
186		default:
187			syslog(LOG_ERR, "Unknown operation: %d",
188				in_msg->operation);
189
190		}
191
192		if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
193			syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
194			exit(EXIT_FAILURE);
195		}
196	}
197}