1 /*
2  * Unix SMB/CIFS implementation.
3  * Utility functions to transfer files.
4  *
5  * Copyright (C) Jeremy Allison 2001-2002
6  * Copyright (C) Michael Adam 2008
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 
23 #include <includes.h>
24 #include "transfer_file.h"
25 #include "lib/util/sys_rw.h"
26 
27 /****************************************************************************
28  Transfer some data between two fd's.
29 ****************************************************************************/
30 
31 #ifndef TRANSFER_BUF_SIZE
32 #define TRANSFER_BUF_SIZE 65536
33 #endif
34 
35 
transfer_file_internal(void * in_file,void * out_file,size_t n,ssize_t (* pread_fn)(void *,void *,size_t,off_t),ssize_t (* pwrite_fn)(void *,const void *,size_t,off_t))36 ssize_t transfer_file_internal(void *in_file,
37 			       void *out_file,
38 			       size_t n,
39 			       ssize_t (*pread_fn)(void *, void *, size_t, off_t),
40 			       ssize_t (*pwrite_fn)(void *, const void *, size_t, off_t))
41 {
42 	char *buf;
43 	size_t total = 0;
44 	ssize_t read_ret;
45 	ssize_t write_ret;
46 	size_t num_to_read_thistime;
47 	size_t num_written = 0;
48 	off_t offset = 0;
49 
50 	if (n == 0) {
51 		return 0;
52 	}
53 
54 	if ((buf = SMB_MALLOC_ARRAY(char, TRANSFER_BUF_SIZE)) == NULL) {
55 		return -1;
56 	}
57 
58 	do {
59 		num_to_read_thistime = MIN((n - total), TRANSFER_BUF_SIZE);
60 
61 		read_ret = (*pread_fn)(in_file, buf, num_to_read_thistime, offset);
62 		if (read_ret == -1) {
63 			DEBUG(0,("transfer_file_internal: read failure. "
64 				 "Error = %s\n", strerror(errno) ));
65 			SAFE_FREE(buf);
66 			return -1;
67 		}
68 		if (read_ret == 0) {
69 			break;
70 		}
71 
72 		num_written = 0;
73 
74 		while (num_written < read_ret) {
75 			write_ret = (*pwrite_fn)(out_file, buf + num_written,
76 					        read_ret - num_written,
77 						offset + num_written);
78 
79 			if (write_ret == -1) {
80 				DEBUG(0,("transfer_file_internal: "
81 					 "write failure. Error = %s\n",
82 					 strerror(errno) ));
83 				SAFE_FREE(buf);
84 				return -1;
85 			}
86 			if (write_ret == 0) {
87 				return (ssize_t)total;
88 			}
89 
90 			num_written += (size_t)write_ret;
91 		}
92 
93 		total += (size_t)read_ret;
94 		offset += (off_t)read_ret;
95 	} while (total < n);
96 
97 	SAFE_FREE(buf);
98 	return (ssize_t)total;
99 }
100 
sys_pread_fn(void * file,void * buf,size_t len,off_t offset)101 static ssize_t sys_pread_fn(void *file, void *buf, size_t len, off_t offset)
102 {
103 	int *fd = (int *)file;
104 
105 	return sys_pread(*fd, buf, len, offset);
106 }
107 
sys_pwrite_fn(void * file,const void * buf,size_t len,off_t offset)108 static ssize_t sys_pwrite_fn(void *file, const void *buf, size_t len, off_t offset)
109 {
110 	int *fd = (int *)file;
111 
112 	return sys_pwrite(*fd, buf, len, offset);
113 }
114 
transfer_file(int infd,int outfd,off_t n)115 off_t transfer_file(int infd, int outfd, off_t n)
116 {
117 	return (off_t)transfer_file_internal(&infd, &outfd, (size_t)n,
118 						 sys_pread_fn, sys_pwrite_fn);
119 }
120