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