00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "postgres.h"
00033
00034 #include "px.h"
00035 #include "mbuf.h"
00036
00037 #define STEP (16*1024)
00038
00039 struct MBuf
00040 {
00041 uint8 *data;
00042 uint8 *data_end;
00043 uint8 *read_pos;
00044 uint8 *buf_end;
00045 bool no_write;
00046 bool own_data;
00047 };
00048
00049 int
00050 mbuf_avail(MBuf *mbuf)
00051 {
00052 return mbuf->data_end - mbuf->read_pos;
00053 }
00054
00055 int
00056 mbuf_size(MBuf *mbuf)
00057 {
00058 return mbuf->data_end - mbuf->data;
00059 }
00060
00061 int
00062 mbuf_tell(MBuf *mbuf)
00063 {
00064 return mbuf->read_pos - mbuf->data;
00065 }
00066
00067 int
00068 mbuf_free(MBuf *mbuf)
00069 {
00070 if (mbuf->own_data)
00071 {
00072 memset(mbuf->data, 0, mbuf->buf_end - mbuf->data);
00073 px_free(mbuf->data);
00074 }
00075 px_free(mbuf);
00076 return 0;
00077 }
00078
00079 static void
00080 prepare_room(MBuf *mbuf, int block_len)
00081 {
00082 uint8 *newbuf;
00083 unsigned newlen;
00084
00085 if (mbuf->data_end + block_len <= mbuf->buf_end)
00086 return;
00087
00088 newlen = (mbuf->buf_end - mbuf->data)
00089 + ((block_len + STEP + STEP - 1) & -STEP);
00090
00091 newbuf = px_realloc(mbuf->data, newlen);
00092
00093 mbuf->buf_end = newbuf + newlen;
00094 mbuf->data_end = newbuf + (mbuf->data_end - mbuf->data);
00095 mbuf->read_pos = newbuf + (mbuf->read_pos - mbuf->data);
00096 mbuf->data = newbuf;
00097
00098 return;
00099 }
00100
00101 int
00102 mbuf_append(MBuf *dst, const uint8 *buf, int len)
00103 {
00104 if (dst->no_write)
00105 {
00106 px_debug("mbuf_append: no_write");
00107 return PXE_BUG;
00108 }
00109
00110 prepare_room(dst, len);
00111
00112 memcpy(dst->data_end, buf, len);
00113 dst->data_end += len;
00114
00115 return 0;
00116 }
00117
00118 MBuf *
00119 mbuf_create(int len)
00120 {
00121 MBuf *mbuf;
00122
00123 if (!len)
00124 len = 8192;
00125
00126 mbuf = px_alloc(sizeof *mbuf);
00127 mbuf->data = px_alloc(len);
00128 mbuf->buf_end = mbuf->data + len;
00129 mbuf->data_end = mbuf->data;
00130 mbuf->read_pos = mbuf->data;
00131
00132 mbuf->no_write = false;
00133 mbuf->own_data = true;
00134
00135 return mbuf;
00136 }
00137
00138 MBuf *
00139 mbuf_create_from_data(uint8 *data, int len)
00140 {
00141 MBuf *mbuf;
00142
00143 mbuf = px_alloc(sizeof *mbuf);
00144 mbuf->data = (uint8 *) data;
00145 mbuf->buf_end = mbuf->data + len;
00146 mbuf->data_end = mbuf->data + len;
00147 mbuf->read_pos = mbuf->data;
00148
00149 mbuf->no_write = true;
00150 mbuf->own_data = false;
00151
00152 return mbuf;
00153 }
00154
00155
00156 int
00157 mbuf_grab(MBuf *mbuf, int len, uint8 **data_p)
00158 {
00159 if (len > mbuf_avail(mbuf))
00160 len = mbuf_avail(mbuf);
00161
00162 mbuf->no_write = true;
00163
00164 *data_p = mbuf->read_pos;
00165 mbuf->read_pos += len;
00166 return len;
00167 }
00168
00169 int
00170 mbuf_rewind(MBuf *mbuf)
00171 {
00172 mbuf->read_pos = mbuf->data;
00173 return 0;
00174 }
00175
00176 int
00177 mbuf_steal_data(MBuf *mbuf, uint8 **data_p)
00178 {
00179 int len = mbuf_size(mbuf);
00180
00181 mbuf->no_write = true;
00182 mbuf->own_data = false;
00183
00184 *data_p = mbuf->data;
00185
00186 mbuf->data = mbuf->data_end = mbuf->read_pos = mbuf->buf_end = NULL;
00187
00188 return len;
00189 }
00190
00191
00192
00193
00194
00195 struct PullFilter
00196 {
00197 PullFilter *src;
00198 const PullFilterOps *op;
00199 int buflen;
00200 uint8 *buf;
00201 int pos;
00202 void *priv;
00203 };
00204
00205 int
00206 pullf_create(PullFilter **pf_p, const PullFilterOps *op, void *init_arg, PullFilter *src)
00207 {
00208 PullFilter *pf;
00209 void *priv;
00210 int res;
00211
00212 if (op->init != NULL)
00213 {
00214 res = op->init(&priv, init_arg, src);
00215 if (res < 0)
00216 return res;
00217 }
00218 else
00219 {
00220 priv = init_arg;
00221 res = 0;
00222 }
00223
00224 pf = px_alloc(sizeof(*pf));
00225 memset(pf, 0, sizeof(*pf));
00226 pf->buflen = res;
00227 pf->op = op;
00228 pf->priv = priv;
00229 pf->src = src;
00230 if (pf->buflen > 0)
00231 {
00232 pf->buf = px_alloc(pf->buflen);
00233 pf->pos = 0;
00234 }
00235 else
00236 {
00237 pf->buf = NULL;
00238 pf->pos = 0;
00239 }
00240 *pf_p = pf;
00241 return 0;
00242 }
00243
00244 void
00245 pullf_free(PullFilter *pf)
00246 {
00247 if (pf->op->free)
00248 pf->op->free(pf->priv);
00249
00250 if (pf->buf)
00251 {
00252 memset(pf->buf, 0, pf->buflen);
00253 px_free(pf->buf);
00254 }
00255
00256 memset(pf, 0, sizeof(*pf));
00257 px_free(pf);
00258 }
00259
00260
00261 int
00262 pullf_read(PullFilter *pf, int len, uint8 **data_p)
00263 {
00264 int res;
00265
00266 if (pf->op->pull)
00267 {
00268 if (pf->buflen && len > pf->buflen)
00269 len = pf->buflen;
00270 res = pf->op->pull(pf->priv, pf->src, len, data_p,
00271 pf->buf, pf->buflen);
00272 }
00273 else
00274 res = pullf_read(pf->src, len, data_p);
00275 return res;
00276 }
00277
00278 int
00279 pullf_read_max(PullFilter *pf, int len, uint8 **data_p, uint8 *tmpbuf)
00280 {
00281 int res,
00282 total;
00283 uint8 *tmp;
00284
00285 res = pullf_read(pf, len, data_p);
00286 if (res <= 0 || res == len)
00287 return res;
00288
00289
00290 memcpy(tmpbuf, *data_p, res);
00291 *data_p = tmpbuf;
00292 len -= res;
00293 total = res;
00294
00295 while (len > 0)
00296 {
00297 res = pullf_read(pf, len, &tmp);
00298 if (res < 0)
00299 {
00300
00301 memset(tmpbuf, 0, total);
00302 return res;
00303 }
00304 if (res == 0)
00305 break;
00306 memcpy(tmpbuf + total, tmp, res);
00307 total += res;
00308 }
00309 return total;
00310 }
00311
00312
00313
00314
00315 int
00316 pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
00317 {
00318 int res;
00319 uint8 *p;
00320
00321 res = pullf_read_max(src, len, &p, dst);
00322 if (res < 0)
00323 return res;
00324 if (res != len)
00325 {
00326 px_debug("pullf_read_fixed: need=%d got=%d", len, res);
00327 return PXE_MBUF_SHORT_READ;
00328 }
00329 if (p != dst)
00330 memcpy(dst, p, len);
00331 return 0;
00332 }
00333
00334
00335
00336
00337 static int
00338 pull_from_mbuf(void *arg, PullFilter *src, int len,
00339 uint8 **data_p, uint8 *buf, int buflen)
00340 {
00341 MBuf *mbuf = arg;
00342
00343 return mbuf_grab(mbuf, len, data_p);
00344 }
00345
00346 static const struct PullFilterOps mbuf_reader = {
00347 NULL, pull_from_mbuf, NULL
00348 };
00349
00350 int
00351 pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
00352 {
00353 return pullf_create(mp_p, &mbuf_reader, src, NULL);
00354 }
00355
00356
00357
00358
00359
00360
00361 struct PushFilter
00362 {
00363 PushFilter *next;
00364 const PushFilterOps *op;
00365 int block_size;
00366 uint8 *buf;
00367 int pos;
00368 void *priv;
00369 };
00370
00371 int
00372 pushf_create(PushFilter **mp_p, const PushFilterOps *op, void *init_arg, PushFilter *next)
00373 {
00374 PushFilter *mp;
00375 void *priv;
00376 int res;
00377
00378 if (op->init != NULL)
00379 {
00380 res = op->init(next, init_arg, &priv);
00381 if (res < 0)
00382 return res;
00383 }
00384 else
00385 {
00386 priv = init_arg;
00387 res = 0;
00388 }
00389
00390 mp = px_alloc(sizeof(*mp));
00391 memset(mp, 0, sizeof(*mp));
00392 mp->block_size = res;
00393 mp->op = op;
00394 mp->priv = priv;
00395 mp->next = next;
00396 if (mp->block_size > 0)
00397 {
00398 mp->buf = px_alloc(mp->block_size);
00399 mp->pos = 0;
00400 }
00401 else
00402 {
00403 mp->buf = NULL;
00404 mp->pos = 0;
00405 }
00406 *mp_p = mp;
00407 return 0;
00408 }
00409
00410 void
00411 pushf_free(PushFilter *mp)
00412 {
00413 if (mp->op->free)
00414 mp->op->free(mp->priv);
00415
00416 if (mp->buf)
00417 {
00418 memset(mp->buf, 0, mp->block_size);
00419 px_free(mp->buf);
00420 }
00421
00422 memset(mp, 0, sizeof(*mp));
00423 px_free(mp);
00424 }
00425
00426 void
00427 pushf_free_all(PushFilter *mp)
00428 {
00429 PushFilter *tmp;
00430
00431 while (mp)
00432 {
00433 tmp = mp->next;
00434 pushf_free(mp);
00435 mp = tmp;
00436 }
00437 }
00438
00439 static int
00440 wrap_process(PushFilter *mp, const uint8 *data, int len)
00441 {
00442 int res;
00443
00444 if (mp->op->push != NULL)
00445 res = mp->op->push(mp->next, mp->priv, data, len);
00446 else
00447 res = pushf_write(mp->next, data, len);
00448 if (res > 0)
00449 return PXE_BUG;
00450 return res;
00451 }
00452
00453
00454 int
00455 pushf_write(PushFilter *mp, const uint8 *data, int len)
00456 {
00457 int need,
00458 res;
00459
00460
00461
00462
00463 if (mp->block_size <= 0)
00464 return wrap_process(mp, data, len);
00465
00466
00467
00468
00469 need = mp->block_size - mp->pos;
00470 if (need > 0)
00471 {
00472 if (len < need)
00473 {
00474 memcpy(mp->buf + mp->pos, data, len);
00475 mp->pos += len;
00476 return 0;
00477 }
00478 memcpy(mp->buf + mp->pos, data, need);
00479 len -= need;
00480 data += need;
00481 }
00482
00483
00484
00485
00486 res = wrap_process(mp, mp->buf, mp->block_size);
00487 if (res < 0)
00488 return res;
00489 mp->pos = 0;
00490
00491
00492
00493
00494 while (len > 0)
00495 {
00496 if (len > mp->block_size)
00497 {
00498 res = wrap_process(mp, data, mp->block_size);
00499 if (res < 0)
00500 return res;
00501 data += mp->block_size;
00502 len -= mp->block_size;
00503 }
00504 else
00505 {
00506 memcpy(mp->buf, data, len);
00507 mp->pos += len;
00508 break;
00509 }
00510 }
00511 return 0;
00512 }
00513
00514 int
00515 pushf_flush(PushFilter *mp)
00516 {
00517 int res;
00518
00519 while (mp)
00520 {
00521 if (mp->block_size > 0)
00522 {
00523 res = wrap_process(mp, mp->buf, mp->pos);
00524 if (res < 0)
00525 return res;
00526 }
00527
00528 if (mp->op->flush)
00529 {
00530 res = mp->op->flush(mp->next, mp->priv);
00531 if (res < 0)
00532 return res;
00533 }
00534
00535 mp = mp->next;
00536 }
00537 return 0;
00538 }
00539
00540
00541
00542
00543
00544 static int
00545 push_into_mbuf(PushFilter *next, void *arg, const uint8 *data, int len)
00546 {
00547 int res = 0;
00548 MBuf *mbuf = arg;
00549
00550 if (len > 0)
00551 res = mbuf_append(mbuf, data, len);
00552 return res < 0 ? res : 0;
00553 }
00554
00555 static const struct PushFilterOps mbuf_filter = {
00556 NULL, push_into_mbuf, NULL, NULL
00557 };
00558
00559 int
00560 pushf_create_mbuf_writer(PushFilter **res, MBuf *dst)
00561 {
00562 return pushf_create(res, &mbuf_filter, dst, NULL);
00563 }