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 768 : struct tevent_req *file_ploadv_send(TALLOC_CTX *mem_ctx,
43 : struct tevent_context *ev,
44 : char * const argl[], size_t maxsize)
45 : {
46 768 : struct tevent_req *req = NULL;
47 768 : struct file_ploadv_state *state = NULL;
48 :
49 768 : req = tevent_req_create(mem_ctx, &state, struct file_ploadv_state);
50 768 : if (req == NULL) {
51 0 : return NULL;
52 : }
53 768 : state->ev = ev;
54 768 : state->maxsize = maxsize;
55 :
56 768 : state->fd = sys_popenv(argl);
57 768 : if (state->fd == -1) {
58 0 : tevent_req_error(req, errno);
59 0 : return tevent_req_post(req, ev);
60 : }
61 768 : tevent_req_set_cleanup_fn(req, file_ploadv_cleanup_fn);
62 :
63 768 : state->subreq = wait_for_read_send(state, state->ev, state->fd, false);
64 768 : if (tevent_req_nomem(state->subreq, req)) {
65 0 : return tevent_req_post(req, ev);
66 : }
67 768 : tevent_req_set_callback(state->subreq, file_ploadv_readable, req);
68 768 : return req;
69 : }
70 :
71 1536 : static void file_ploadv_cleanup_fn(
72 : struct tevent_req *req, enum tevent_req_state req_state)
73 : {
74 1536 : struct file_ploadv_state *state = tevent_req_data(
75 : req, struct file_ploadv_state);
76 :
77 1536 : TALLOC_FREE(state->subreq);
78 1536 : if (state->fd != -1) {
79 768 : sys_pclose(state->fd);
80 768 : state->fd = -1;
81 : }
82 1536 : }
83 :
84 1536 : static void file_ploadv_readable(struct tevent_req *subreq)
85 : {
86 1536 : struct tevent_req *req = tevent_req_callback_data(
87 : subreq, struct tevent_req);
88 1536 : 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 1536 : ok = wait_for_read_recv(subreq, &err);
98 1536 : TALLOC_FREE(subreq);
99 1536 : state->subreq = NULL;
100 1536 : if (!ok) {
101 0 : tevent_req_error(req, err);
102 768 : return;
103 : }
104 :
105 1536 : nread = sys_read(state->fd, buf, sizeof(buf));
106 1536 : if (nread == -1) {
107 0 : tevent_req_error(req, errno);
108 0 : return;
109 : }
110 1536 : if (nread == 0) {
111 768 : tevent_req_done(req);
112 768 : return;
113 : }
114 :
115 768 : bufsize = talloc_get_size(state->buf);
116 768 : 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 768 : if (((bufsize + nread) < bufsize) ||
125 768 : ((bufsize + nread + 1) < bufsize)) {
126 : /* overflow */
127 0 : tevent_req_error(req, EMSGSIZE);
128 0 : return;
129 : }
130 :
131 768 : if ((state->maxsize != 0) && ((bufsize + nread) > state->maxsize)) {
132 0 : tevent_req_error(req, EMSGSIZE);
133 0 : return;
134 : }
135 :
136 768 : tmp = talloc_realloc(state, state->buf, uint8_t, bufsize + nread + 1);
137 768 : if (tevent_req_nomem(tmp, req)) {
138 0 : return;
139 : }
140 768 : state->buf = tmp;
141 :
142 768 : memcpy(state->buf + bufsize, buf, nread);
143 768 : state->buf[bufsize+nread] = '\0';
144 :
145 768 : state->subreq = wait_for_read_send(state, state->ev, state->fd, false);
146 768 : if (tevent_req_nomem(state->subreq, req)) {
147 0 : return;
148 : }
149 768 : tevent_req_set_callback(state->subreq, file_ploadv_readable, req);
150 : }
151 :
152 768 : int file_ploadv_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
153 : uint8_t **buf)
154 : {
155 768 : struct file_ploadv_state *state = tevent_req_data(
156 : req, struct file_ploadv_state);
157 0 : int err;
158 :
159 768 : if (tevent_req_is_unix_error(req, &err)) {
160 0 : return err;
161 : }
162 768 : *buf = talloc_move(mem_ctx, &state->buf);
163 :
164 768 : tevent_req_received(req);
165 :
166 768 : 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 : }
|