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