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