mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
81d01a1add
We have to first TALLOC_FREE() the waiting event before closing the pipe. Otherwise EPOLL_CTL_DEL is unhappy and might remove an unrelated file descriptor. Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
188 lines
4.5 KiB
C
188 lines
4.5 KiB
C
/*
|
|
* Unix SMB/CIFS implementation.
|
|
* SMB parameters and setup
|
|
* Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 3 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "replace.h"
|
|
#include "lib/util_file.h"
|
|
#include "lib/util/debug.h"
|
|
#include "lib/util/samba_util.h"
|
|
#include "lib/util/sys_rw.h"
|
|
#include "lib/util/sys_popen.h"
|
|
#include "lib/async_req/async_sock.h"
|
|
#include "lib/util/tevent_unix.h"
|
|
|
|
struct file_ploadv_state {
|
|
struct tevent_context *ev;
|
|
struct tevent_req *subreq;
|
|
size_t maxsize;
|
|
int fd;
|
|
uint8_t *buf;
|
|
};
|
|
|
|
static void file_ploadv_cleanup_fn(
|
|
struct tevent_req *req, enum tevent_req_state req_state);
|
|
static void file_ploadv_readable(struct tevent_req *subreq);
|
|
|
|
struct tevent_req *file_ploadv_send(TALLOC_CTX *mem_ctx,
|
|
struct tevent_context *ev,
|
|
char * const argl[], size_t maxsize)
|
|
{
|
|
struct tevent_req *req = NULL;
|
|
struct file_ploadv_state *state = NULL;
|
|
|
|
req = tevent_req_create(mem_ctx, &state, struct file_ploadv_state);
|
|
if (req == NULL) {
|
|
return NULL;
|
|
}
|
|
state->ev = ev;
|
|
state->maxsize = maxsize;
|
|
|
|
state->fd = sys_popenv(argl);
|
|
if (state->fd == -1) {
|
|
tevent_req_error(req, errno);
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
tevent_req_set_cleanup_fn(req, file_ploadv_cleanup_fn);
|
|
|
|
state->subreq = wait_for_read_send(state, state->ev, state->fd, false);
|
|
if (tevent_req_nomem(state->subreq, req)) {
|
|
return tevent_req_post(req, ev);
|
|
}
|
|
tevent_req_set_callback(state->subreq, file_ploadv_readable, req);
|
|
return req;
|
|
}
|
|
|
|
static void file_ploadv_cleanup_fn(
|
|
struct tevent_req *req, enum tevent_req_state req_state)
|
|
{
|
|
struct file_ploadv_state *state = tevent_req_data(
|
|
req, struct file_ploadv_state);
|
|
|
|
TALLOC_FREE(state->subreq);
|
|
if (state->fd != -1) {
|
|
sys_pclose(state->fd);
|
|
state->fd = -1;
|
|
}
|
|
}
|
|
|
|
static void file_ploadv_readable(struct tevent_req *subreq)
|
|
{
|
|
struct tevent_req *req = tevent_req_callback_data(
|
|
subreq, struct tevent_req);
|
|
struct file_ploadv_state *state = tevent_req_data(
|
|
req, struct file_ploadv_state);
|
|
uint8_t buf[1024];
|
|
uint8_t *tmp;
|
|
ssize_t nread;
|
|
size_t bufsize;
|
|
int err;
|
|
bool ok;
|
|
|
|
ok = wait_for_read_recv(subreq, &err);
|
|
TALLOC_FREE(subreq);
|
|
state->subreq = NULL;
|
|
if (!ok) {
|
|
tevent_req_error(req, err);
|
|
return;
|
|
}
|
|
|
|
nread = sys_read(state->fd, buf, sizeof(buf));
|
|
if (nread == -1) {
|
|
tevent_req_error(req, errno);
|
|
return;
|
|
}
|
|
if (nread == 0) {
|
|
tevent_req_done(req);
|
|
return;
|
|
}
|
|
|
|
bufsize = talloc_get_size(state->buf);
|
|
if (bufsize > 0) {
|
|
/*
|
|
* Last round we've added the trailing '\0'. Remove it
|
|
* for this round.
|
|
*/
|
|
bufsize -= 1;
|
|
}
|
|
|
|
if (((bufsize + nread) < bufsize) ||
|
|
((bufsize + nread + 1) < bufsize)) {
|
|
/* overflow */
|
|
tevent_req_error(req, EMSGSIZE);
|
|
return;
|
|
}
|
|
|
|
if ((state->maxsize != 0) && ((bufsize + nread) > state->maxsize)) {
|
|
tevent_req_error(req, EMSGSIZE);
|
|
return;
|
|
}
|
|
|
|
tmp = talloc_realloc(state, state->buf, uint8_t, bufsize + nread + 1);
|
|
if (tevent_req_nomem(tmp, req)) {
|
|
return;
|
|
}
|
|
state->buf = tmp;
|
|
|
|
memcpy(state->buf + bufsize, buf, nread);
|
|
state->buf[bufsize+nread] = '\0';
|
|
|
|
state->subreq = wait_for_read_send(state, state->ev, state->fd, false);
|
|
if (tevent_req_nomem(state->subreq, req)) {
|
|
return;
|
|
}
|
|
tevent_req_set_callback(state->subreq, file_ploadv_readable, req);
|
|
}
|
|
|
|
int file_ploadv_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
|
|
uint8_t **buf)
|
|
{
|
|
struct file_ploadv_state *state = tevent_req_data(
|
|
req, struct file_ploadv_state);
|
|
int err;
|
|
|
|
if (tevent_req_is_unix_error(req, &err)) {
|
|
return err;
|
|
}
|
|
*buf = talloc_move(mem_ctx, &state->buf);
|
|
|
|
tevent_req_received(req);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
Load a pipe into memory and return an array of pointers to lines in the data
|
|
must be freed with TALLOC_FREE.
|
|
**/
|
|
|
|
char **file_lines_ploadv(TALLOC_CTX *mem_ctx,
|
|
char * const argl[],
|
|
int *numlines)
|
|
{
|
|
char *p = NULL;
|
|
size_t size;
|
|
|
|
p = file_ploadv(argl, &size);
|
|
if (!p) {
|
|
return NULL;
|
|
}
|
|
|
|
return file_lines_parse(p, size, numlines, mem_ctx);
|
|
}
|