/src/samba/source3/lib/util_transfer_file.c
Line | Count | Source |
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 | | |
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 | 0 | { |
42 | 0 | char *buf; |
43 | 0 | size_t total = 0; |
44 | 0 | ssize_t read_ret; |
45 | 0 | ssize_t write_ret; |
46 | 0 | size_t num_to_read_thistime; |
47 | 0 | size_t num_written = 0; |
48 | 0 | off_t offset = 0; |
49 | |
|
50 | 0 | if (n == 0) { |
51 | 0 | return 0; |
52 | 0 | } |
53 | | |
54 | 0 | if ((buf = SMB_MALLOC_ARRAY(char, TRANSFER_BUF_SIZE)) == NULL) { |
55 | 0 | return -1; |
56 | 0 | } |
57 | | |
58 | 0 | do { |
59 | 0 | num_to_read_thistime = MIN((n - total), TRANSFER_BUF_SIZE); |
60 | |
|
61 | 0 | read_ret = (*pread_fn)(in_file, buf, num_to_read_thistime, offset); |
62 | 0 | if (read_ret == -1) { |
63 | 0 | DEBUG(0,("transfer_file_internal: read failure. " |
64 | 0 | "Error = %s\n", strerror(errno) )); |
65 | 0 | SAFE_FREE(buf); |
66 | 0 | return -1; |
67 | 0 | } |
68 | 0 | if (read_ret == 0) { |
69 | 0 | break; |
70 | 0 | } |
71 | | |
72 | 0 | num_written = 0; |
73 | |
|
74 | 0 | while (num_written < read_ret) { |
75 | 0 | write_ret = (*pwrite_fn)(out_file, buf + num_written, |
76 | 0 | read_ret - num_written, |
77 | 0 | offset + num_written); |
78 | |
|
79 | 0 | if (write_ret == -1) { |
80 | 0 | DEBUG(0,("transfer_file_internal: " |
81 | 0 | "write failure. Error = %s\n", |
82 | 0 | strerror(errno) )); |
83 | 0 | SAFE_FREE(buf); |
84 | 0 | return -1; |
85 | 0 | } |
86 | 0 | if (write_ret == 0) { |
87 | 0 | return (ssize_t)total; |
88 | 0 | } |
89 | | |
90 | 0 | num_written += (size_t)write_ret; |
91 | 0 | } |
92 | | |
93 | 0 | total += (size_t)read_ret; |
94 | 0 | offset += (off_t)read_ret; |
95 | 0 | } while (total < n); |
96 | | |
97 | 0 | SAFE_FREE(buf); |
98 | 0 | return (ssize_t)total; |
99 | 0 | } |
100 | | |
101 | | static ssize_t sys_pread_fn(void *file, void *buf, size_t len, off_t offset) |
102 | 0 | { |
103 | 0 | int *fd = (int *)file; |
104 | |
|
105 | 0 | return sys_pread(*fd, buf, len, offset); |
106 | 0 | } |
107 | | |
108 | | static ssize_t sys_pwrite_fn(void *file, const void *buf, size_t len, off_t offset) |
109 | 0 | { |
110 | 0 | int *fd = (int *)file; |
111 | |
|
112 | 0 | return sys_pwrite(*fd, buf, len, offset); |
113 | 0 | } |
114 | | |
115 | | off_t transfer_file(int infd, int outfd, off_t n) |
116 | 0 | { |
117 | 0 | return (off_t)transfer_file_internal(&infd, &outfd, (size_t)n, |
118 | 0 | sys_pread_fn, sys_pwrite_fn); |
119 | 0 | } |