Coverage Report

Created: 2026-09-03 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/lib/util_file.c
Line
Count
Source
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/util_file.h"
22
#include "source3/lib/util_file.h"
23
#include "lib/util/debug.h"
24
#include "lib/util/samba_util.h"
25
#include "lib/util/sys_rw.h"
26
#include "lib/util/sys_popen.h"
27
#include "lib/async_req/async_sock.h"
28
#include "lib/util/tevent_unix.h"
29
30
struct file_ploadv_state {
31
  struct tevent_context *ev;
32
  struct tevent_req *subreq;
33
  size_t maxsize;
34
  int fd;
35
  uint8_t *buf;
36
};
37
38
static void file_ploadv_cleanup_fn(
39
  struct tevent_req *req, enum tevent_req_state req_state);
40
static void file_ploadv_readable(struct tevent_req *subreq);
41
42
struct tevent_req *file_ploadv_send(TALLOC_CTX *mem_ctx,
43
           struct tevent_context *ev,
44
           char * const argl[], size_t maxsize)
45
0
{
46
0
  struct tevent_req *req = NULL;
47
0
  struct file_ploadv_state *state = NULL;
48
49
0
  req = tevent_req_create(mem_ctx, &state, struct file_ploadv_state);
50
0
  if (req == NULL) {
51
0
    return NULL;
52
0
  }
53
0
  state->ev = ev;
54
0
  state->maxsize = maxsize;
55
56
0
  state->fd = sys_popenv(argl);
57
0
  if (state->fd == -1) {
58
0
    tevent_req_error(req, errno);
59
0
    return tevent_req_post(req, ev);
60
0
  }
61
0
  tevent_req_set_cleanup_fn(req, file_ploadv_cleanup_fn);
62
63
0
  state->subreq = wait_for_read_send(state, state->ev, state->fd, false);
64
0
  if (tevent_req_nomem(state->subreq, req)) {
65
0
    return tevent_req_post(req, ev);
66
0
  }
67
0
  tevent_req_set_callback(state->subreq, file_ploadv_readable, req);
68
0
  return req;
69
0
}
70
71
static void file_ploadv_cleanup_fn(
72
  struct tevent_req *req, enum tevent_req_state req_state)
73
0
{
74
0
  struct file_ploadv_state *state = tevent_req_data(
75
0
    req, struct file_ploadv_state);
76
77
0
  TALLOC_FREE(state->subreq);
78
0
  if (state->fd != -1) {
79
0
    sys_pclose(state->fd);
80
0
    state->fd = -1;
81
0
  }
82
0
}
83
84
static void file_ploadv_readable(struct tevent_req *subreq)
85
0
{
86
0
  struct tevent_req *req = tevent_req_callback_data(
87
0
    subreq, struct tevent_req);
88
0
  struct file_ploadv_state *state = tevent_req_data(
89
0
    req, struct file_ploadv_state);
90
0
  uint8_t buf[1024];
91
0
  uint8_t *tmp;
92
0
  ssize_t nread;
93
0
  size_t bufsize;
94
0
  int err;
95
0
  bool ok;
96
97
0
  ok = wait_for_read_recv(subreq, &err);
98
0
  TALLOC_FREE(subreq);
99
0
  state->subreq = NULL;
100
0
  if (!ok) {
101
0
    tevent_req_error(req, err);
102
0
    return;
103
0
  }
104
105
0
  nread = sys_read(state->fd, buf, sizeof(buf));
106
0
  if (nread == -1) {
107
0
    tevent_req_error(req, errno);
108
0
    return;
109
0
  }
110
0
  if (nread == 0) {
111
0
    tevent_req_done(req);
112
0
    return;
113
0
  }
114
115
0
  bufsize = talloc_get_size(state->buf);
116
0
  if (bufsize > 0) {
117
    /*
118
     * Last round we've added the trailing '\0'. Remove it
119
     * for this round.
120
     */
121
0
    bufsize -= 1;
122
0
  }
123
124
0
  if (((bufsize + nread) < bufsize) ||
125
0
      ((bufsize + nread + 1) < bufsize)) {
126
    /* overflow */
127
0
    tevent_req_error(req, EMSGSIZE);
128
0
    return;
129
0
  }
130
131
0
  if ((state->maxsize != 0) && ((bufsize + nread) > state->maxsize)) {
132
0
    tevent_req_error(req, EMSGSIZE);
133
0
    return;
134
0
  }
135
136
0
  tmp = talloc_realloc(state, state->buf, uint8_t, bufsize + nread + 1);
137
0
  if (tevent_req_nomem(tmp, req)) {
138
0
    return;
139
0
  }
140
0
  state->buf = tmp;
141
142
0
  memcpy(state->buf + bufsize, buf, nread);
143
0
  state->buf[bufsize+nread] = '\0';
144
145
0
  state->subreq = wait_for_read_send(state, state->ev, state->fd, false);
146
0
  if (tevent_req_nomem(state->subreq, req)) {
147
0
    return;
148
0
  }
149
0
  tevent_req_set_callback(state->subreq, file_ploadv_readable, req);
150
0
}
151
152
int file_ploadv_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
153
        uint8_t **buf)
154
0
{
155
0
  struct file_ploadv_state *state = tevent_req_data(
156
0
    req, struct file_ploadv_state);
157
0
  int err;
158
159
0
  if (tevent_req_is_unix_error(req, &err)) {
160
0
    return err;
161
0
  }
162
0
  *buf = talloc_move(mem_ctx, &state->buf);
163
164
0
  tevent_req_received(req);
165
166
0
  return 0;
167
0
}