Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * SMB parameters and setup
4 : * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
5 : *
6 : * This program is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU General Public License as published by the Free
8 : * Software Foundation; either version 3 of the License, or (at your option)
9 : * any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 : * more details.
15 : *
16 : * You should have received a copy of the GNU General Public License along with
17 : * this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "replace.h"
21 : #include "lib/util/util_file.h"
22 : #include "source3/lib/util_file.h"
23 : #include "lib/util/debug.h"
24 : #include "lib/util/samba_util.h"
25 : #include "lib/util/sys_rw.h"
26 : #include "lib/util/sys_popen.h"
27 : #include "lib/async_req/async_sock.h"
28 : #include "lib/util/tevent_unix.h"
29 :
30 : struct file_ploadv_state {
31 : struct tevent_context *ev;
32 : struct tevent_req *subreq;
33 : size_t maxsize;
34 : int fd;
35 : uint8_t *buf;
36 : };
37 :
38 : static void file_ploadv_cleanup_fn(
39 : struct tevent_req *req, enum tevent_req_state req_state);
40 : static void file_ploadv_readable(struct tevent_req *subreq);
41 :
42 744 : struct tevent_req *file_ploadv_send(TALLOC_CTX *mem_ctx,
43 : struct tevent_context *ev,
44 : char * const argl[], size_t maxsize)
45 : {
46 744 : struct tevent_req *req = NULL;
47 744 : struct file_ploadv_state *state = NULL;
48 :
49 744 : req = tevent_req_create(mem_ctx, &state, struct file_ploadv_state);
50 744 : if (req == NULL) {
51 0 : return NULL;
52 : }
53 744 : state->ev = ev;
54 744 : state->maxsize = maxsize;
55 :
56 744 : state->fd = sys_popenv(argl);
57 744 : if (state->fd == -1) {
58 0 : tevent_req_error(req, errno);
59 0 : return tevent_req_post(req, ev);
60 : }
61 744 : tevent_req_set_cleanup_fn(req, file_ploadv_cleanup_fn);
62 :
63 744 : state->subreq = wait_for_read_send(state, state->ev, state->fd, false);
64 744 : if (tevent_req_nomem(state->subreq, req)) {
65 0 : return tevent_req_post(req, ev);
66 : }
67 744 : tevent_req_set_callback(state->subreq, file_ploadv_readable, req);
68 744 : return req;
69 : }
70 :
71 1488 : static void file_ploadv_cleanup_fn(
72 : struct tevent_req *req, enum tevent_req_state req_state)
73 : {
74 1488 : struct file_ploadv_state *state = tevent_req_data(
75 : req, struct file_ploadv_state);
76 :
77 1488 : TALLOC_FREE(state->subreq);
78 1488 : if (state->fd != -1) {
79 744 : sys_pclose(state->fd);
80 744 : state->fd = -1;
81 : }
82 1488 : }
83 :
84 1488 : static void file_ploadv_readable(struct tevent_req *subreq)
85 : {
86 1488 : struct tevent_req *req = tevent_req_callback_data(
87 : subreq, struct tevent_req);
88 1488 : struct file_ploadv_state *state = tevent_req_data(
89 : req, struct file_ploadv_state);
90 0 : uint8_t buf[1024];
91 0 : uint8_t *tmp;
92 0 : ssize_t nread;
93 0 : size_t bufsize;
94 0 : int err;
95 0 : bool ok;
96 :
97 1488 : ok = wait_for_read_recv(subreq, &err);
98 1488 : TALLOC_FREE(subreq);
99 1488 : state->subreq = NULL;
100 1488 : if (!ok) {
101 0 : tevent_req_error(req, err);
102 744 : return;
103 : }
104 :
105 1488 : nread = sys_read(state->fd, buf, sizeof(buf));
106 1488 : if (nread == -1) {
107 0 : tevent_req_error(req, errno);
108 0 : return;
109 : }
110 1488 : if (nread == 0) {
111 744 : tevent_req_done(req);
112 744 : return;
113 : }
114 :
115 744 : bufsize = talloc_get_size(state->buf);
116 744 : if (bufsize > 0) {
117 : /*
118 : * Last round we've added the trailing '\0'. Remove it
119 : * for this round.
120 : */
121 0 : bufsize -= 1;
122 : }
123 :
124 744 : if (((bufsize + nread) < bufsize) ||
125 744 : ((bufsize + nread + 1) < bufsize)) {
126 : /* overflow */
127 0 : tevent_req_error(req, EMSGSIZE);
128 0 : return;
129 : }
130 :
131 744 : if ((state->maxsize != 0) && ((bufsize + nread) > state->maxsize)) {
132 0 : tevent_req_error(req, EMSGSIZE);
133 0 : return;
134 : }
135 :
136 744 : tmp = talloc_realloc(state, state->buf, uint8_t, bufsize + nread + 1);
137 744 : if (tevent_req_nomem(tmp, req)) {
138 0 : return;
139 : }
140 744 : state->buf = tmp;
141 :
142 744 : memcpy(state->buf + bufsize, buf, nread);
143 744 : state->buf[bufsize+nread] = '\0';
144 :
145 744 : state->subreq = wait_for_read_send(state, state->ev, state->fd, false);
146 744 : if (tevent_req_nomem(state->subreq, req)) {
147 0 : return;
148 : }
149 744 : tevent_req_set_callback(state->subreq, file_ploadv_readable, req);
150 : }
151 :
152 744 : int file_ploadv_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
153 : uint8_t **buf)
154 : {
155 744 : struct file_ploadv_state *state = tevent_req_data(
156 : req, struct file_ploadv_state);
157 0 : int err;
158 :
159 744 : if (tevent_req_is_unix_error(req, &err)) {
160 0 : return err;
161 : }
162 744 : *buf = talloc_move(mem_ctx, &state->buf);
163 :
164 744 : tevent_req_received(req);
165 :
166 744 : return 0;
167 : }
168 :
169 :
170 : /**
171 : Load a pipe into memory and return an array of pointers to lines in the data
172 : must be freed with TALLOC_FREE.
173 : **/
174 :
175 930 : char **file_lines_ploadv(TALLOC_CTX *mem_ctx,
176 : char * const argl[],
177 : int *numlines)
178 : {
179 930 : char *p = NULL;
180 0 : size_t size;
181 :
182 930 : p = file_ploadv(argl, &size);
183 930 : if (!p) {
184 0 : return NULL;
185 : }
186 :
187 930 : return file_lines_parse(p, size, numlines, mem_ctx);
188 : }
|