1 /*
2 * socket2buffer.c
3 * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
4 * All rights reserved.
5 *
6 * $Id: socket2buffer.c,v 1.14 2015/03/14 06:11:27 marc Exp marc $
7 *
8 */
9
10 #include "headers.h"
11
12 static const char rcsid[] __attribute__ ((used)) = "$Id: socket2buffer.c,v 1.14 2015/03/14 06:11:27 marc Exp marc $";
13
buffer2file(struct context * ctx,int cur)14 void buffer2file(struct context *ctx, int cur __attribute__ ((unused)))
15 {
16 ssize_t l = 0, len = 0;
17
18 DebugIn(DEBUG_BUFFER);
19
20 if (ctx->dbuf) {
21 do {
22 struct iovec v[10];
23 int count = 10;
24
25 buffer_setv(ctx->dbuf, v, &count, 0);
26 l = writev(ctx->ffn, v, count);
27 if (l > 0) {
28 off_t l2 = (off_t) l;
29 len += l;
30 ctx->dbuf = buffer_release(ctx->dbuf, &l2);
31 }
32 }
33 while (l > 0 && ctx->dbuf);
34
35 if (l <= 0 && errno == EDQUOT) {
36 reply(ctx, MSG_451_Transfer_incomplete_quota);
37 logmsg("%s: quota limit reached", ctx->user);
38
39 ftp_log(ctx, LOG_TRANSFER, "i");
40 cleanup_file(ctx, ctx->ffn);
41 cleanup_data(ctx, ctx->dfn);
42 Debug((DEBUG_PROC, "- %s: quota exceeded\n", __func__));
43 return;
44 }
45 if (l < 0) {
46 if (errno != EAGAIN) {
47 reply(ctx, MSG_451_Transfer_incomplete);
48
49 ftp_log(ctx, LOG_TRANSFER, "i");
50 cleanup_file(ctx, ctx->ffn);
51 cleanup_data(ctx, ctx->dfn);
52 }
53 Debug((DEBUG_BUFFER, "- %s FAILURE transfer incomplete\n", __func__));
54 return;
55 }
56 ctx->bytecount += len;
57 }
58 if (ctx->dfn < 0) { /* socket is closed */
59 if (ctx->cfn < 0) { /* control connection not available */
60 ftp_log(ctx, LOG_TRANSFER, "I");
61 cleanup_file(ctx, ctx->ffn);
62 } else {
63 if (!cleanup_file(ctx, ctx->ffn)) {
64 if (ctx->mode != 'z' || ctx->bytecount == 0)
65 reply(ctx, MSG_226_Transfer_complete);
66 else
67 replyf(ctx, MSG_226_Transfer_completeZ, (int) (100 * ctx->filesize / ctx->bytecount), ctx->bytecount - ctx->filesize);
68 ftp_log(ctx, LOG_TRANSFER, "I");
69 } else {
70 ftp_log(ctx, LOG_TRANSFER, "i");
71 if (errno == EDQUOT) {
72 reply(ctx, MSG_451_Transfer_incomplete_quota);
73 logmsg("%s: quota limit reached", ctx->user);
74 } else
75 reply(ctx, MSG_451_Transfer_incomplete);
76 }
77 ctx->bytecount = 0;
78 }
79 }
80 DebugOut(DEBUG_BUFFER);
81 }
82
socket2buffer(struct context * ctx,int cur)83 void socket2buffer(struct context *ctx, int cur __attribute__ ((unused)))
84 {
85 int thats_all = 0;
86 ssize_t l;
87 struct buffer *b = NULL;
88
89 DebugIn(DEBUG_NET);
90
91 io_sched_renew_proc(ctx->io, ctx, (void *) cleanup);
92
93 if (ctx->dbuf == NULL)
94 ctx->dbuf = buffer_get();
95
96 #ifdef WITH_ZLIB
97 if (ctx->mode == 'z')
98 b = buffer_get();
99 else
100 #endif
101 b = ctx->dbuf;
102
103 #ifdef WITH_SSL
104 if (ctx->ssl_d)
105 l = io_SSL_read(ctx->ssl_d, b->buf + b->length, b->size - b->length, ctx->io, ctx->dfn, (void *) socket2buffer);
106 else
107 #endif
108 l = read(ctx->dfn, b->buf + b->length, b->size - b->length);
109
110 if (l > 0)
111 ctx->traffic_total += l, ctx->traffic_files += l;
112
113 thats_all = (l <= 0);
114
115 if (!(l == -1 && errno == EAGAIN)) {
116 #ifdef WITH_ZLIB
117 if (ctx->mode == 'z') {
118 struct buffer *out = ctx->dbuf;
119 b->length = l;
120 b->offset = 0;
121 l = 0;
122
123 if (!ctx->zstream) {
124 ctx->zstream = Xcalloc(1, sizeof(z_stream));
125 ctx->zstream->next_in = (u_char *) b->buf + b->offset;
126 ctx->zstream->avail_in = b->length - b->offset;
127 if (Z_OK != inflateInit(ctx->zstream)) {
128 Xfree(&ctx->zstream);
129
130 reply(ctx, MSG_451_Internal_error);
131 logmsg("%s: inflateInit failed", ctx->user);
132 ftp_log(ctx, LOG_TRANSFER, "i");
133 cleanup_file(ctx, ctx->ffn);
134 cleanup_data(ctx, ctx->dfn);
135 Debug((DEBUG_PROC, "- %s: inflateEnd\n", __func__));
136 return;
137 }
138 ctx->filesize = 0;
139 }
140 do {
141 int res;
142 off_t decomp;
143
144 if (out->length == out->size) {
145 out->next = buffer_get();
146 out = out->next;
147 }
148 ctx->zstream->next_in = (u_char *) b->buf + b->offset;
149 ctx->zstream->avail_in = b->length - b->offset;
150 ctx->zstream->next_out = (u_char *) out->buf + out->length;
151 ctx->zstream->avail_out = out->size - out->length;
152
153 res = inflate(ctx->zstream, Z_NO_FLUSH);
154 decomp = (char *) ctx->zstream->next_in - b->buf - b->offset;
155 ctx->filesize += decomp;
156 Debug((DEBUG_PROC, "inflate returns %d\n", res));
157 switch (res) {
158 case Z_OK:
159 Debug((DEBUG_PROC, "Z_OK\n"));
160 l += decomp;
161 b = buffer_release(b, &decomp);
162 out->length = out->size - ctx->zstream->avail_out;
163 break;
164 case Z_STREAM_END:
165 Debug((DEBUG_PROC, "Z_STREAM_END\n"));
166 b = buffer_free(b);
167 ctx->dbuf->length = ctx->dbuf->size - ctx->zstream->avail_out;
168 if (Z_OK != inflateEnd(ctx->zstream)) {
169 logmsg("%s: inflateEnd", ctx->user);
170 bye:
171 buffer_free(b);
172 Xfree(&ctx->zstream);
173 reply(ctx, MSG_451_Internal_error);
174 ftp_log(ctx, LOG_TRANSFER, "i");
175 cleanup_file(ctx, ctx->ffn);
176 cleanup_data(ctx, ctx->dfn);
177 Debug((DEBUG_PROC, "- %s: inflateEnd\n", __func__));
178 return;
179 }
180 Xfree(&ctx->zstream);
181 thats_all = 1;
182 break;
183 default:
184 inflateEnd(ctx->zstream);
185 logmsg("%s: inflate returned %d", ctx->user, res);
186 goto bye;
187 }
188 }
189 while (b);
190 } else
191 #endif /* WITH_ZLIB */
192 {
193 if (l > 0)
194 ctx->dbuf->length += l;
195 l = ctx->dbuf->length;
196 }
197
198 while (ctx->dbuf && (thats_all || (ctx->dbuf->length >= (ctx->dbuf->size >> 2) * 3))) {
199 if (l > 0 && ctx->use_ascii) {
200 char lastchar = ctx->lastchar;
201 char *t = (char *) ctx->dbuf->buf + ctx->dbuf->offset;
202 char *u = t;
203 char *ul = u + ctx->dbuf->length;
204
205 for (; u < ul; u++)
206 if (*u == '\r') {
207 lastchar = '\r';
208 *t++ = '\n';
209 } else {
210 if (*u != '\n' || lastchar != '\r')
211 *t++ = *u;
212 lastchar = *u;
213 }
214
215 ctx->lastchar = lastchar;
216 ctx->dbuf->length = (size_t) (t - ctx->dbuf->buf);
217 }
218 if (thats_all)
219 cleanup_data(ctx, ctx->dfn);
220 else
221 buffer2file(ctx, ctx->ffn);
222
223 thats_all = 0;
224 }
225 }
226 DebugOut(DEBUG_NET);
227 }
228