Blame


1 56e7a15f 2021-03-10 stsp /*
2 56e7a15f 2021-03-10 stsp * Copyright (c) 2020 Ori Bernstein
3 2a0e67f7 2021-03-10 stsp *
4 2a0e67f7 2021-03-10 stsp * Permission to use, copy, modify, and distribute this software for any
5 2a0e67f7 2021-03-10 stsp * purpose with or without fee is hereby granted, provided that the above
6 2a0e67f7 2021-03-10 stsp * copyright notice and this permission notice appear in all copies.
7 2a0e67f7 2021-03-10 stsp *
8 2a0e67f7 2021-03-10 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 2a0e67f7 2021-03-10 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 2a0e67f7 2021-03-10 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 2a0e67f7 2021-03-10 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 2a0e67f7 2021-03-10 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 2a0e67f7 2021-03-10 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 2a0e67f7 2021-03-10 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 56e7a15f 2021-03-10 stsp */
16 56e7a15f 2021-03-10 stsp
17 f364801d 2021-03-10 stsp #include <sys/types.h>
18 f364801d 2021-03-10 stsp #include <sys/queue.h>
19 56e7a15f 2021-03-10 stsp
20 f364801d 2021-03-10 stsp #include <assert.h>
21 f364801d 2021-03-10 stsp #include <limits.h>
22 f364801d 2021-03-10 stsp #include <stdint.h>
23 f364801d 2021-03-10 stsp #include <stdio.h>
24 f364801d 2021-03-10 stsp #include <stdlib.h>
25 f364801d 2021-03-10 stsp #include <string.h>
26 f364801d 2021-03-10 stsp #include <sha1.h>
27 56e7a15f 2021-03-10 stsp
28 f364801d 2021-03-10 stsp #include "got_error.h"
29 f364801d 2021-03-10 stsp #include "got_object.h"
30 f364801d 2021-03-10 stsp
31 f364801d 2021-03-10 stsp #include "got_lib_delta.h"
32 f364801d 2021-03-10 stsp #include "got_lib_object.h"
33 f364801d 2021-03-10 stsp
34 f364801d 2021-03-10 stsp struct Dblock {
35 f364801d 2021-03-10 stsp unsigned char *buf;
36 f364801d 2021-03-10 stsp int len;
37 f364801d 2021-03-10 stsp int off;
38 f364801d 2021-03-10 stsp uint64_t hash;
39 f364801d 2021-03-10 stsp };
40 f364801d 2021-03-10 stsp
41 f364801d 2021-03-10 stsp struct Dtab {
42 f364801d 2021-03-10 stsp unsigned char *base;
43 f364801d 2021-03-10 stsp int nbase;
44 f364801d 2021-03-10 stsp struct Dblock *b;
45 f364801d 2021-03-10 stsp int nb;
46 f364801d 2021-03-10 stsp int sz;
47 f364801d 2021-03-10 stsp };
48 f364801d 2021-03-10 stsp
49 f364801d 2021-03-10 stsp struct Delta {
50 f364801d 2021-03-10 stsp int cpy;
51 f364801d 2021-03-10 stsp int off;
52 f364801d 2021-03-10 stsp int len;
53 f364801d 2021-03-10 stsp };
54 f364801d 2021-03-10 stsp
55 56e7a15f 2021-03-10 stsp enum {
56 56e7a15f 2021-03-10 stsp Minchunk = 128,
57 56e7a15f 2021-03-10 stsp Maxchunk = 8192,
58 f364801d 2021-03-10 stsp Splitmask = (1 << 8) - 1,
59 56e7a15f 2021-03-10 stsp
60 56e7a15f 2021-03-10 stsp };
61 56e7a15f 2021-03-10 stsp
62 f364801d 2021-03-10 stsp static uint32_t geartab[] = {
63 56e7a15f 2021-03-10 stsp 0x67ed26b7, 0x32da500c, 0x53d0fee0, 0xce387dc7, 0xcd406d90, 0x2e83a4d4, 0x9fc9a38d, 0xb67259dc,
64 56e7a15f 2021-03-10 stsp 0xca6b1722, 0x6d2ea08c, 0x235cea2e, 0x3149bb5f, 0x1beda787, 0x2a6b77d5, 0x2f22d9ac, 0x91fc0544,
65 56e7a15f 2021-03-10 stsp 0xe413acfa, 0x5a30ff7a, 0xad6fdde0, 0x444fd0f5, 0x7ad87864, 0x58c5ff05, 0x8d2ec336, 0x2371f853,
66 56e7a15f 2021-03-10 stsp 0x550f8572, 0x6aa448dd, 0x7c9ddbcf, 0x95221e14, 0x2a82ec33, 0xcbec5a78, 0xc6795a0d, 0x243995b7,
67 56e7a15f 2021-03-10 stsp 0x1c909a2f, 0x4fded51c, 0x635d334b, 0x0e2b9999, 0x2702968d, 0x856de1d5, 0x3325d60e, 0xeb6a7502,
68 56e7a15f 2021-03-10 stsp 0xec2a9844, 0x0905835a, 0xa1820375, 0xa4be5cab, 0x96a6c058, 0x2c2ccd70, 0xba40fce3, 0xd794c46b,
69 56e7a15f 2021-03-10 stsp 0x8fbae83e, 0xc3aa7899, 0x3d3ff8ed, 0xa0d42b5b, 0x571c0c97, 0xd2811516, 0xf7e7b96c, 0x4fd2fcbd,
70 56e7a15f 2021-03-10 stsp 0xe2fdec94, 0x282cc436, 0x78e8e95c, 0x80a3b613, 0xcfbee20c, 0xd4a32d1c, 0x2a12ff13, 0x6af82936,
71 56e7a15f 2021-03-10 stsp 0xe5630258, 0x8efa6a98, 0x294fb2d1, 0xdeb57086, 0x5f0fddb3, 0xeceda7ce, 0x4c87305f, 0x3a6d3307,
72 56e7a15f 2021-03-10 stsp 0xe22d2942, 0x9d060217, 0x1e42ed02, 0xb6f63b52, 0x4367f39f, 0x055cf262, 0x03a461b2, 0x5ef9e382,
73 56e7a15f 2021-03-10 stsp 0x386bc03a, 0x2a1e79c7, 0xf1a0058b, 0xd4d2dea9, 0x56baf37d, 0x5daff6cc, 0xf03a951d, 0xaef7de45,
74 56e7a15f 2021-03-10 stsp 0xa8f4581e, 0x3960b555, 0xffbfff6d, 0xbe702a23, 0x8f5b6d6f, 0x061739fb, 0x98696f47, 0x3fd596d4,
75 56e7a15f 2021-03-10 stsp 0x151eac6b, 0xa9fcc4f5, 0x69181a12, 0x3ac5a107, 0xb5198fe7, 0x96bcb1da, 0x1b5ddf8e, 0xc757d650,
76 56e7a15f 2021-03-10 stsp 0x65865c3a, 0x8fc0a41a, 0x87435536, 0x99eda6f2, 0x41874794, 0x29cff4e8, 0xb70efd9a, 0x3103f6e7,
77 56e7a15f 2021-03-10 stsp 0x84d2453b, 0x15a450bd, 0x74f49af1, 0x60f664b1, 0xa1c86935, 0xfdafbce1, 0xe36353e3, 0x5d9ba739,
78 56e7a15f 2021-03-10 stsp 0xbc0559ba, 0x708b0054, 0xd41d808c, 0xb2f31723, 0x9027c41f, 0xf136d165, 0xb5374b12, 0x9420a6ac,
79 56e7a15f 2021-03-10 stsp 0x273958b6, 0xe6c2fad0, 0xebdc1f21, 0xfb33af8b, 0xc71c25cd, 0xe9a2d8e5, 0xbeb38a50, 0xbceb7cc2,
80 56e7a15f 2021-03-10 stsp 0x4e4e73f0, 0xcd6c251d, 0xde4c032c, 0x4b04ac30, 0x725b8b21, 0x4eb8c33b, 0x20d07b75, 0x0567aa63,
81 56e7a15f 2021-03-10 stsp 0xb56b2bb7, 0xc1f5fd3a, 0xcafd35ca, 0x470dd4da, 0xfe4f94cd, 0xfb8de424, 0xe8dbcf40, 0xfe50a37a,
82 56e7a15f 2021-03-10 stsp 0x62db5b5d, 0xf32f4ab6, 0x2c4a8a51, 0x18473dc0, 0xfe0cbb6e, 0xfe399efd, 0xdf34ecc9, 0x6ccd5055,
83 56e7a15f 2021-03-10 stsp 0x46097073, 0x139135c2, 0x721c76f6, 0x1c6a94b4, 0x6eee014d, 0x8a508e02, 0x3da538f5, 0x280d394f,
84 56e7a15f 2021-03-10 stsp 0x5248a0c4, 0x3ce94c6c, 0x9a71ad3a, 0x8493dd05, 0xe43f0ab6, 0x18e4ed42, 0x6c5c0e09, 0x42b06ec9,
85 56e7a15f 2021-03-10 stsp 0x8d330343, 0xa45b6f59, 0x2a573c0c, 0xd7fd3de6, 0xeedeab68, 0x5c84dafc, 0xbbd1b1a8, 0xa3ce1ad1,
86 56e7a15f 2021-03-10 stsp 0x85b70bed, 0xb6add07f, 0xa531309c, 0x8f8ab852, 0x564de332, 0xeac9ed0c, 0x73da402c, 0x3ec52761,
87 56e7a15f 2021-03-10 stsp 0x43af2f4d, 0xd6ff45c8, 0x4c367462, 0xd553bd6a, 0x44724855, 0x3b2aa728, 0x56e5eb65, 0xeaf16173,
88 56e7a15f 2021-03-10 stsp 0x33fa42ff, 0xd714bb5d, 0xfbd0a3b9, 0xaf517134, 0x9416c8cd, 0x534cf94f, 0x548947c2, 0x34193569,
89 56e7a15f 2021-03-10 stsp 0x32f4389a, 0xfe7028bc, 0xed73b1ed, 0x9db95770, 0x468e3922, 0x0440c3cd, 0x60059a62, 0x33504562,
90 56e7a15f 2021-03-10 stsp 0x2b229fbd, 0x5174dca5, 0xf7028752, 0xd63c6aa8, 0x31276f38, 0x0646721c, 0xb0191da8, 0xe00e6de0,
91 56e7a15f 2021-03-10 stsp 0x9eac1a6e, 0x9f7628a5, 0xed6c06ea, 0x0bb8af15, 0xf119fb12, 0x38693c1c, 0x732bc0fe, 0x84953275,
92 56e7a15f 2021-03-10 stsp 0xb82ec888, 0x33a4f1b3, 0x3099835e, 0x028a8782, 0x5fdd51d7, 0xc6c717b3, 0xb06caf71, 0x17c8c111,
93 56e7a15f 2021-03-10 stsp 0x61bad754, 0x9fd03061, 0xe09df1af, 0x3bc9eb73, 0x85878413, 0x9889aaf2, 0x3f5a9e46, 0x42c9f01f,
94 56e7a15f 2021-03-10 stsp 0x9984a4f4, 0xd5de43cc, 0xd294daed, 0xbecba2d2, 0xf1f6e72c, 0x5551128a, 0x83af87e2, 0x6f0342ba,
95 56e7a15f 2021-03-10 stsp };
96 56e7a15f 2021-03-10 stsp
97 f364801d 2021-03-10 stsp static uint64_t
98 f364801d 2021-03-10 stsp hash(unsigned char *p, int n)
99 56e7a15f 2021-03-10 stsp {
100 f364801d 2021-03-10 stsp unsigned char buf[SHA1_DIGEST_LENGTH];
101 f364801d 2021-03-10 stsp uint64_t h;
102 f364801d 2021-03-10 stsp SHA1Data(p, n, buf);
103 f364801d 2021-03-10 stsp memcpy(&h, buf, sizeof(h));
104 f364801d 2021-03-10 stsp return be64toh(h);
105 56e7a15f 2021-03-10 stsp }
106 56e7a15f 2021-03-10 stsp
107 f364801d 2021-03-10 stsp static const struct got_error *
108 f364801d 2021-03-10 stsp addblk(struct Dtab *dt, void *buf, int len, int off, uint64_t h)
109 56e7a15f 2021-03-10 stsp {
110 56e7a15f 2021-03-10 stsp int i, sz, probe;
111 f364801d 2021-03-10 stsp struct Dblock *db;
112 56e7a15f 2021-03-10 stsp
113 56e7a15f 2021-03-10 stsp probe = h % dt->sz;
114 f364801d 2021-03-10 stsp while (dt->b[probe].buf != NULL) {
115 f364801d 2021-03-10 stsp if (len == dt->b[probe].len &&
116 f364801d 2021-03-10 stsp memcmp(buf, dt->b[probe].buf, len) == 0)
117 f364801d 2021-03-10 stsp return NULL;
118 56e7a15f 2021-03-10 stsp probe = (probe + 1) % dt->sz;
119 56e7a15f 2021-03-10 stsp }
120 f364801d 2021-03-10 stsp assert(dt->b[probe].buf == NULL);
121 56e7a15f 2021-03-10 stsp dt->b[probe].buf = buf;
122 56e7a15f 2021-03-10 stsp dt->b[probe].len = len;
123 56e7a15f 2021-03-10 stsp dt->b[probe].off = off;
124 56e7a15f 2021-03-10 stsp dt->b[probe].hash = h;
125 56e7a15f 2021-03-10 stsp dt->nb++;
126 f364801d 2021-03-10 stsp if (dt->sz < 2 * dt->nb) {
127 56e7a15f 2021-03-10 stsp sz = dt->sz;
128 56e7a15f 2021-03-10 stsp db = dt->b;
129 56e7a15f 2021-03-10 stsp dt->sz *= 2;
130 56e7a15f 2021-03-10 stsp dt->nb = 0;
131 f364801d 2021-03-10 stsp dt->b = calloc(dt->sz, sizeof(struct Dblock));
132 f364801d 2021-03-10 stsp if (dt->b == NULL)
133 f364801d 2021-03-10 stsp return got_error_from_errno("calloc");
134 f364801d 2021-03-10 stsp for (i = 0; i < sz; i++) {
135 f364801d 2021-03-10 stsp if (db[i].buf != NULL)
136 f364801d 2021-03-10 stsp return addblk(dt, db[i].buf, db[i].len,
137 f364801d 2021-03-10 stsp db[i].off, db[i].hash);
138 f364801d 2021-03-10 stsp }
139 56e7a15f 2021-03-10 stsp free(db);
140 f364801d 2021-03-10 stsp }
141 f364801d 2021-03-10 stsp
142 f364801d 2021-03-10 stsp return NULL;
143 56e7a15f 2021-03-10 stsp }
144 56e7a15f 2021-03-10 stsp
145 f364801d 2021-03-10 stsp static struct Dblock *
146 f364801d 2021-03-10 stsp lookup(struct Dtab *dt, unsigned char *p, int n)
147 56e7a15f 2021-03-10 stsp {
148 56e7a15f 2021-03-10 stsp int probe;
149 f364801d 2021-03-10 stsp uint64_t h;
150 56e7a15f 2021-03-10 stsp
151 56e7a15f 2021-03-10 stsp h = hash(p, n);
152 f364801d 2021-03-10 stsp for (probe = h % dt->sz; dt->b[probe].buf != NULL;
153 f364801d 2021-03-10 stsp probe = (probe + 1) % dt->sz) {
154 f364801d 2021-03-10 stsp if (dt->b[probe].hash != h)
155 56e7a15f 2021-03-10 stsp continue;
156 f364801d 2021-03-10 stsp if (n != dt->b[probe].len)
157 56e7a15f 2021-03-10 stsp continue;
158 f364801d 2021-03-10 stsp if (memcmp(p, dt->b[probe].buf, n) != 0)
159 56e7a15f 2021-03-10 stsp continue;
160 56e7a15f 2021-03-10 stsp return &dt->b[probe];
161 56e7a15f 2021-03-10 stsp }
162 f364801d 2021-03-10 stsp return NULL;
163 56e7a15f 2021-03-10 stsp }
164 56e7a15f 2021-03-10 stsp
165 56e7a15f 2021-03-10 stsp static int
166 f364801d 2021-03-10 stsp nextblk(unsigned char *s, unsigned char *e)
167 56e7a15f 2021-03-10 stsp {
168 f364801d 2021-03-10 stsp uint32_t gh;
169 f364801d 2021-03-10 stsp unsigned char *p;
170 56e7a15f 2021-03-10 stsp
171 f364801d 2021-03-10 stsp if ((e - s) < Minchunk)
172 56e7a15f 2021-03-10 stsp return e - s;
173 56e7a15f 2021-03-10 stsp p = s + Minchunk;
174 f364801d 2021-03-10 stsp if ((e - s) > Maxchunk)
175 56e7a15f 2021-03-10 stsp e = s + Maxchunk;
176 56e7a15f 2021-03-10 stsp gh = 0;
177 f364801d 2021-03-10 stsp while (p != e) {
178 f364801d 2021-03-10 stsp gh = (gh << 1) + geartab[*p++];
179 f364801d 2021-03-10 stsp if ((gh & Splitmask) == 0)
180 56e7a15f 2021-03-10 stsp break;
181 56e7a15f 2021-03-10 stsp }
182 56e7a15f 2021-03-10 stsp return p - s;
183 56e7a15f 2021-03-10 stsp }
184 56e7a15f 2021-03-10 stsp
185 f364801d 2021-03-10 stsp const struct got_error *
186 f364801d 2021-03-10 stsp dtinit(struct Dtab *dt, struct got_object *obj)
187 56e7a15f 2021-03-10 stsp {
188 f364801d 2021-03-10 stsp unsigned char *s = NULL, *e;
189 f364801d 2021-03-10 stsp uint64_t h;
190 f364801d 2021-03-10 stsp long n, o;
191 56e7a15f 2021-03-10 stsp
192 56e7a15f 2021-03-10 stsp o = 0;
193 f364801d 2021-03-10 stsp #ifdef notyet
194 f364801d 2021-03-10 stsp s = (unsigned char *)obj->data;
195 f364801d 2021-03-10 stsp #endif
196 56e7a15f 2021-03-10 stsp e = s + obj->size;
197 56e7a15f 2021-03-10 stsp dt->nb = 0;
198 56e7a15f 2021-03-10 stsp dt->sz = 128;
199 f364801d 2021-03-10 stsp dt->b = calloc(dt->sz, sizeof(struct Dblock));
200 f364801d 2021-03-10 stsp if (dt->b == NULL)
201 f364801d 2021-03-10 stsp return got_error_from_errno("calloc");
202 f364801d 2021-03-10 stsp #ifdef notyet
203 f364801d 2021-03-10 stsp dt->base = (unsigned char *)obj->data;
204 f364801d 2021-03-10 stsp #endif
205 56e7a15f 2021-03-10 stsp dt->nbase = obj->size;
206 f364801d 2021-03-10 stsp while (s != e) {
207 56e7a15f 2021-03-10 stsp n = nextblk(s, e);
208 56e7a15f 2021-03-10 stsp h = hash(s, n);
209 56e7a15f 2021-03-10 stsp addblk(dt, s, n, o, h);
210 56e7a15f 2021-03-10 stsp s += n;
211 56e7a15f 2021-03-10 stsp o += n;
212 56e7a15f 2021-03-10 stsp }
213 f364801d 2021-03-10 stsp
214 f364801d 2021-03-10 stsp return NULL;
215 56e7a15f 2021-03-10 stsp }
216 56e7a15f 2021-03-10 stsp
217 56e7a15f 2021-03-10 stsp void
218 f364801d 2021-03-10 stsp dtclear(struct Dtab *dt)
219 56e7a15f 2021-03-10 stsp {
220 56e7a15f 2021-03-10 stsp free(dt->b);
221 56e7a15f 2021-03-10 stsp }
222 56e7a15f 2021-03-10 stsp
223 f364801d 2021-03-10 stsp static const struct got_error *
224 f364801d 2021-03-10 stsp emitdelta(struct Delta **pd, int *nd, int cpy, int off, int len)
225 56e7a15f 2021-03-10 stsp {
226 f364801d 2021-03-10 stsp struct Delta *d, *p;
227 56e7a15f 2021-03-10 stsp
228 56e7a15f 2021-03-10 stsp *nd += 1;
229 f364801d 2021-03-10 stsp p = reallocarray(*pd, *nd, sizeof(struct Delta));
230 f364801d 2021-03-10 stsp if (p == NULL)
231 f364801d 2021-03-10 stsp return got_error_from_errno("realloc");
232 f364801d 2021-03-10 stsp *pd = p;
233 56e7a15f 2021-03-10 stsp d = &(*pd)[*nd - 1];
234 56e7a15f 2021-03-10 stsp d->cpy = cpy;
235 56e7a15f 2021-03-10 stsp d->off = off;
236 56e7a15f 2021-03-10 stsp d->len = len;
237 f364801d 2021-03-10 stsp return NULL;
238 56e7a15f 2021-03-10 stsp }
239 56e7a15f 2021-03-10 stsp
240 56e7a15f 2021-03-10 stsp static int
241 f364801d 2021-03-10 stsp stretch(struct Dtab *dt, struct Dblock *b, unsigned char *s,
242 f364801d 2021-03-10 stsp unsigned char *e, int n)
243 56e7a15f 2021-03-10 stsp {
244 f364801d 2021-03-10 stsp unsigned char *p, *q, *eb;
245 56e7a15f 2021-03-10 stsp
246 f364801d 2021-03-10 stsp if (b == NULL)
247 56e7a15f 2021-03-10 stsp return n;
248 56e7a15f 2021-03-10 stsp p = s + n;
249 56e7a15f 2021-03-10 stsp q = dt->base + b->off + n;
250 56e7a15f 2021-03-10 stsp eb = dt->base + dt->nbase;
251 f364801d 2021-03-10 stsp while (n < (1 << 24)) {
252 f364801d 2021-03-10 stsp if (p == e || q == eb)
253 56e7a15f 2021-03-10 stsp break;
254 f364801d 2021-03-10 stsp if (*p != *q)
255 56e7a15f 2021-03-10 stsp break;
256 56e7a15f 2021-03-10 stsp p++;
257 56e7a15f 2021-03-10 stsp q++;
258 56e7a15f 2021-03-10 stsp n++;
259 56e7a15f 2021-03-10 stsp }
260 56e7a15f 2021-03-10 stsp return n;
261 56e7a15f 2021-03-10 stsp }
262 56e7a15f 2021-03-10 stsp
263 f364801d 2021-03-10 stsp struct Delta *
264 f364801d 2021-03-10 stsp deltify(struct got_object *obj, struct Dtab *dt, int *pnd)
265 56e7a15f 2021-03-10 stsp {
266 f364801d 2021-03-10 stsp struct Delta *d;
267 f364801d 2021-03-10 stsp struct Dblock *b;
268 f364801d 2021-03-10 stsp unsigned char *s = NULL, *e;
269 f364801d 2021-03-10 stsp long n, o;
270 56e7a15f 2021-03-10 stsp
271 56e7a15f 2021-03-10 stsp o = 0;
272 f364801d 2021-03-10 stsp d = NULL;
273 f364801d 2021-03-10 stsp #ifdef notyet
274 f364801d 2021-03-10 stsp s = (unsigned char *)obj->data;
275 f364801d 2021-03-10 stsp #endif
276 56e7a15f 2021-03-10 stsp e = s + obj->size;
277 56e7a15f 2021-03-10 stsp *pnd = 0;
278 f364801d 2021-03-10 stsp while (s != e) {
279 56e7a15f 2021-03-10 stsp n = nextblk(s, e);
280 56e7a15f 2021-03-10 stsp b = lookup(dt, s, n);
281 56e7a15f 2021-03-10 stsp n = stretch(dt, b, s, e, n);
282 f364801d 2021-03-10 stsp if (b != NULL)
283 56e7a15f 2021-03-10 stsp emitdelta(&d, pnd, 1, b->off, n);
284 56e7a15f 2021-03-10 stsp else
285 56e7a15f 2021-03-10 stsp emitdelta(&d, pnd, 0, o, n);
286 56e7a15f 2021-03-10 stsp s += n;
287 56e7a15f 2021-03-10 stsp o += n;
288 56e7a15f 2021-03-10 stsp }
289 56e7a15f 2021-03-10 stsp return d;
290 56e7a15f 2021-03-10 stsp }