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_file.h"
22 : #include "lib/util/debug.h"
23 : #include "lib/util/samba_util.h"
24 : #include "lib/util/sys_rw.h"
25 : #include "lib/util/sys_popen.h"
26 : #include "lib/async_req/async_sock.h"
27 : #include "lib/util/tevent_unix.h"
28 :
29 : struct file_ploadv_state {
30 : struct tevent_context *ev;
31 : struct tevent_req *subreq;
32 : size_t maxsize;
33 : int fd;
34 : uint8_t *buf;
35 : };
36 :
37 : static void file_ploadv_cleanup_fn(
38 : struct tevent_req *req, enum tevent_req_state req_state);
39 : static void file_ploadv_readable(struct tevent_req *subreq);
40 :
41 272 : struct tevent_req *file_ploadv_send(TALLOC_CTX *mem_ctx,
42 : struct tevent_context *ev,
43 : char * const argl[], size_t maxsize)
44 : {
45 272 : struct tevent_req *req = NULL;
46 272 : struct file_ploadv_state *state = NULL;
47 :
48 272 : req = tevent_req_create(mem_ctx, &state, struct file_ploadv_state);
49 272 : if (req == NULL) {
50 0 : return NULL;
51 : }
52 272 : state->ev = ev;
53 272 : state->maxsize = maxsize;
54 :
55 272 : state->fd = sys_popenv(argl);
56 272 : if (state->fd == -1) {
57 0 : tevent_req_error(req, errno);
58 0 : return tevent_req_post(req, ev);
59 : }
60 272 : tevent_req_set_cleanup_fn(req, file_ploadv_cleanup_fn);
61 :
62 272 : state->subreq = wait_for_read_send(state, state->ev, state->fd, false);
63 272 : if (tevent_req_nomem(state->subreq, req)) {
64 0 : return tevent_req_post(req, ev);
65 : }
66 272 : tevent_req_set_callback(state->subreq, file_ploadv_readable, req);
67 272 : return req;
68 : }
69 :
70 544 : static void file_ploadv_cleanup_fn(
71 : struct tevent_req *req, enum tevent_req_state req_state)
72 : {
73 544 : struct file_ploadv_state *state = tevent_req_data(
74 : req, struct file_ploadv_state);
75 :
76 544 : TALLOC_FREE(state->subreq);
77 544 : if (state->fd != -1) {
78 272 : sys_pclose(state->fd);
79 272 : state->fd = -1;
80 : }
81 544 : }
82 :
83 544 : static void file_ploadv_readable(struct tevent_req *subreq)
84 : {
85 544 : struct tevent_req *req = tevent_req_callback_data(
86 : subreq, struct tevent_req);
87 544 : struct file_ploadv_state *state = tevent_req_data(
88 : req, struct file_ploadv_state);
89 : uint8_t buf[1024];
90 : uint8_t *tmp;
91 : ssize_t nread;
92 : size_t bufsize;
93 : int err;
94 : bool ok;
95 :
96 544 : ok = wait_for_read_recv(subreq, &err);
97 544 : TALLOC_FREE(subreq);
98 544 : state->subreq = NULL;
99 544 : if (!ok) {
100 0 : tevent_req_error(req, err);
101 88 : return;
102 : }
103 :
104 544 : nread = sys_read(state->fd, buf, sizeof(buf));
105 544 : if (nread == -1) {
106 0 : tevent_req_error(req, errno);
107 0 : return;
108 : }
109 544 : if (nread == 0) {
110 272 : tevent_req_done(req);
111 272 : return;
112 : }
113 :
114 272 : bufsize = talloc_get_size(state->buf);
115 272 : if (bufsize > 0) {
116 : /*
117 : * Last round we've added the trailing '\0'. Remove it
118 : * for this round.
119 : */
120 0 : bufsize -= 1;
121 : }
122 :
123 456 : if (((bufsize + nread) < bufsize) ||
124 272 : ((bufsize + nread + 1) < bufsize)) {
125 : /* overflow */
126 0 : tevent_req_error(req, EMSGSIZE);
127 0 : return;
128 : }
129 :
130 272 : if ((state->maxsize != 0) && ((bufsize + nread) > state->maxsize)) {
131 0 : tevent_req_error(req, EMSGSIZE);
132 0 : return;
133 : }
134 :
135 272 : tmp = talloc_realloc(state, state->buf, uint8_t, bufsize + nread + 1);
136 272 : if (tevent_req_nomem(tmp, req)) {
137 0 : return;
138 : }
139 272 : state->buf = tmp;
140 :
141 272 : memcpy(state->buf + bufsize, buf, nread);
142 272 : state->buf[bufsize+nread] = '\0';
143 :
144 272 : state->subreq = wait_for_read_send(state, state->ev, state->fd, false);
145 272 : if (tevent_req_nomem(state->subreq, req)) {
146 0 : return;
147 : }
148 272 : tevent_req_set_callback(state->subreq, file_ploadv_readable, req);
149 : }
150 :
151 272 : int file_ploadv_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
152 : uint8_t **buf)
153 : {
154 272 : struct file_ploadv_state *state = tevent_req_data(
155 : req, struct file_ploadv_state);
156 : int err;
157 :
158 272 : if (tevent_req_is_unix_error(req, &err)) {
159 0 : return err;
160 : }
161 272 : *buf = talloc_move(mem_ctx, &state->buf);
162 :
163 272 : tevent_req_received(req);
164 :
165 272 : return 0;
166 : }
167 :
168 :
169 : /**
170 : Load a pipe into memory and return an array of pointers to lines in the data
171 : must be freed with TALLOC_FREE.
172 : **/
173 :
174 2 : char **file_lines_ploadv(TALLOC_CTX *mem_ctx,
175 : char * const argl[],
176 : int *numlines)
177 : {
178 2 : char *p = NULL;
179 : size_t size;
180 :
181 2 : p = file_ploadv(argl, &size);
182 2 : if (!p) {
183 0 : return NULL;
184 : }
185 :
186 2 : return file_lines_parse(p, size, numlines, mem_ctx);
187 : }
|