]> arthur.barton.de Git - bup.git/blob - lib/bup/_helpers.c
Merge remote branch 'origin/master' into meta
[bup.git] / lib / bup / _helpers.c
1 #define _LARGEFILE64_SOURCE 1
2
3 #include "bupsplit.h"
4 #include <Python.h>
5 #include <assert.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <arpa/inet.h>
9 #include <stdint.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13
14 #ifdef linux
15 #include <linux/fs.h>
16 #include <sys/ioctl.h>
17 #include <sys/stat.h>
18 #include <sys/time.h>
19 #endif
20
21 static int istty = 0;
22
23 static PyObject *selftest(PyObject *self, PyObject *args)
24 {
25     if (!PyArg_ParseTuple(args, ""))
26         return NULL;
27     
28     return Py_BuildValue("i", !bupsplit_selftest());
29 }
30
31
32 static PyObject *blobbits(PyObject *self, PyObject *args)
33 {
34     if (!PyArg_ParseTuple(args, ""))
35         return NULL;
36     return Py_BuildValue("i", BUP_BLOBBITS);
37 }
38
39
40 static PyObject *splitbuf(PyObject *self, PyObject *args)
41 {
42     unsigned char *buf = NULL;
43     int len = 0, out = 0, bits = -1;
44
45     if (!PyArg_ParseTuple(args, "t#", &buf, &len))
46         return NULL;
47     out = bupsplit_find_ofs(buf, len, &bits);
48     return Py_BuildValue("ii", out, bits);
49 }
50
51
52 static PyObject *bitmatch(PyObject *self, PyObject *args)
53 {
54     unsigned char *buf1 = NULL, *buf2 = NULL;
55     int len1 = 0, len2 = 0;
56     int byte, bit;
57
58     if (!PyArg_ParseTuple(args, "t#t#", &buf1, &len1, &buf2, &len2))
59         return NULL;
60     
61     bit = 0;
62     for (byte = 0; byte < len1 && byte < len2; byte++)
63     {
64         int b1 = buf1[byte], b2 = buf2[byte];
65         if (b1 != b2)
66         {
67             for (bit = 0; bit < 8; bit++)
68                 if ( (b1 & (0x80 >> bit)) != (b2 & (0x80 >> bit)) )
69                     break;
70             break;
71         }
72     }
73     
74     return Py_BuildValue("i", byte*8 + bit);
75 }
76
77
78 static PyObject *firstword(PyObject *self, PyObject *args)
79 {
80     unsigned char *buf = NULL;
81     int len = 0;
82     uint32_t v;
83
84     if (!PyArg_ParseTuple(args, "t#", &buf, &len))
85         return NULL;
86     
87     if (len < 4)
88         return NULL;
89     
90     v = ntohl(*(uint32_t *)buf);
91     return PyLong_FromUnsignedLong(v);
92 }
93
94
95 typedef struct {
96     uint32_t high;
97     unsigned char low;
98 } bits40_t;
99
100
101 static void to_bloom_address_bitmask4(const bits40_t *buf,
102         const int nbits, uint64_t *v, unsigned char *bitmask)
103 {
104     int bit;
105     uint64_t raw, mask;
106
107     mask = (1<<nbits) - 1;
108     raw = (((uint64_t)ntohl(buf->high)) << 8) | buf->low;
109     bit = (raw >> (37-nbits)) & 0x7;
110     *v = (raw >> (40-nbits)) & mask;
111     *bitmask = 1 << bit;
112 }
113
114 static void to_bloom_address_bitmask5(const uint32_t *buf,
115         const int nbits, uint32_t *v, unsigned char *bitmask)
116 {
117     int bit;
118     uint32_t raw, mask;
119
120     mask = (1<<nbits) - 1;
121     raw = ntohl(*buf);
122     bit = (raw >> (29-nbits)) & 0x7;
123     *v = (raw >> (32-nbits)) & mask;
124     *bitmask = 1 << bit;
125 }
126
127
128 #define BLOOM_SET_BIT(name, address, itype, otype) \
129 static void name(unsigned char *bloom, const void *buf, const int nbits)\
130 {\
131     unsigned char bitmask;\
132     otype v;\
133     address((itype *)buf, nbits, &v, &bitmask);\
134     bloom[16+v] |= bitmask;\
135 }
136 BLOOM_SET_BIT(bloom_set_bit4, to_bloom_address_bitmask4, bits40_t, uint64_t)
137 BLOOM_SET_BIT(bloom_set_bit5, to_bloom_address_bitmask5, uint32_t, uint32_t)
138
139
140 #define BLOOM_GET_BIT(name, address, itype, otype) \
141 static int name(const unsigned char *bloom, const void *buf, const int nbits)\
142 {\
143     unsigned char bitmask;\
144     otype v;\
145     address((itype *)buf, nbits, &v, &bitmask);\
146     return bloom[16+v] & bitmask;\
147 }
148 BLOOM_GET_BIT(bloom_get_bit4, to_bloom_address_bitmask4, bits40_t, uint64_t)
149 BLOOM_GET_BIT(bloom_get_bit5, to_bloom_address_bitmask5, uint32_t, uint32_t)
150
151
152 static PyObject *bloom_add(PyObject *self, PyObject *args)
153 {
154     unsigned char *sha = NULL, *bloom = NULL;
155     unsigned char *end;
156     int len = 0, blen = 0, nbits = 0, k = 0;
157
158     if (!PyArg_ParseTuple(args, "w#s#ii", &bloom, &blen, &sha, &len, &nbits, &k))
159         return NULL;
160
161     if (blen < 16+(1<<nbits) || len % 20 != 0)
162         return NULL;
163
164     if (k == 5)
165     {
166         if (nbits > 29)
167             return NULL;
168         for (end = sha + len; sha < end; sha += 20/k)
169             bloom_set_bit5(bloom, sha, nbits);
170     }
171     else if (k == 4)
172     {
173         if (nbits > 37)
174             return NULL;
175         for (end = sha + len; sha < end; sha += 20/k)
176             bloom_set_bit4(bloom, sha, nbits);
177     }
178     else
179         return NULL;
180
181
182     return Py_BuildValue("i", len/20);
183 }
184
185 static PyObject *bloom_contains(PyObject *self, PyObject *args)
186 {
187     unsigned char *sha = NULL, *bloom = NULL;
188     int len = 0, blen = 0, nbits = 0, k = 0;
189     unsigned char *end;
190     int steps;
191
192     if (!PyArg_ParseTuple(args, "t#s#ii", &bloom, &blen, &sha, &len, &nbits, &k))
193         return NULL;
194
195     if (len != 20)
196         return NULL;
197
198     if (k == 5)
199     {
200         if (nbits > 29)
201             return NULL;
202         for (steps = 1, end = sha + 20; sha < end; sha += 20/k, steps++)
203             if (!bloom_get_bit5(bloom, sha, nbits))
204                 return Py_BuildValue("Oi", Py_None, steps);
205     }
206     else if (k == 4)
207     {
208         if (nbits > 37)
209             return NULL;
210         for (steps = 1, end = sha + 20; sha < end; sha += 20/k, steps++)
211             if (!bloom_get_bit4(bloom, sha, nbits))
212                 return Py_BuildValue("Oi", Py_None, steps);
213     }
214     else
215         return NULL;
216
217     return Py_BuildValue("Oi", Py_True, k);
218 }
219
220
221 static uint32_t _extract_bits(unsigned char *buf, int nbits)
222 {
223     uint32_t v, mask;
224
225     mask = (1<<nbits) - 1;
226     v = ntohl(*(uint32_t *)buf);
227     v = (v >> (32-nbits)) & mask;
228     return v;
229 }
230 static PyObject *extract_bits(PyObject *self, PyObject *args)
231 {
232     unsigned char *buf = NULL;
233     int len = 0, nbits = 0;
234
235     if (!PyArg_ParseTuple(args, "t#i", &buf, &len, &nbits))
236         return NULL;
237     
238     if (len < 4)
239         return NULL;
240     
241     return PyLong_FromUnsignedLong(_extract_bits(buf, nbits));
242 }
243
244
245 struct sha {
246     unsigned char bytes[20];
247 };
248 struct idx {
249     unsigned char *map;
250     struct sha *cur;
251     struct sha *end;
252     uint32_t *cur_name;
253     long bytes;
254     int name_base;
255 };
256
257
258 static int _cmp_sha(const struct sha *sha1, const struct sha *sha2)
259 {
260     int i;
261     for (i = 0; i < 20; i++)
262         if (sha1->bytes[i] != sha2->bytes[i])
263             return sha1->bytes[i] - sha2->bytes[i];
264     return 0;
265 }
266
267
268 static void _fix_idx_order(struct idx **idxs, int *last_i)
269 {
270     struct idx *idx;
271     int low, mid, high, c = 0;
272
273     idx = idxs[*last_i];
274     if (idxs[*last_i]->cur >= idxs[*last_i]->end)
275     {
276         idxs[*last_i] = NULL;
277         PyMem_Free(idx);
278         --*last_i;
279         return;
280     }
281     if (*last_i == 0)
282         return;
283
284     low = *last_i-1;
285     mid = *last_i;
286     high = 0;
287     while (low >= high)
288     {
289         mid = (low + high) / 2;
290         c = _cmp_sha(idx->cur, idxs[mid]->cur);
291         if (c < 0)
292             high = mid + 1;
293         else if (c > 0)
294             low = mid - 1;
295         else
296             break;
297     }
298     if (c < 0)
299         ++mid;
300     if (mid == *last_i)
301         return;
302     memmove(&idxs[mid+1], &idxs[mid], (*last_i-mid)*sizeof(struct idx *));
303     idxs[mid] = idx;
304 }
305
306
307 static uint32_t _get_idx_i(struct idx *idx)
308 {
309     if (idx->cur_name == NULL)
310         return idx->name_base;
311     return ntohl(*idx->cur_name) + idx->name_base;
312 }
313
314
315 static PyObject *merge_into(PyObject *self, PyObject *args)
316 {
317     PyObject *ilist = NULL;
318     unsigned char *fmap = NULL;
319     struct sha *sha_ptr, *last = NULL;
320     uint32_t *table_ptr, *name_ptr;
321     struct idx **idxs = NULL;
322     int flen = 0, bits = 0, i;
323     uint32_t total, count, prefix;
324     int num_i;
325     int last_i;
326
327     if (!PyArg_ParseTuple(args, "w#iIO", &fmap, &flen, &bits, &total, &ilist))
328         return NULL;
329
330     num_i = PyList_Size(ilist);
331     idxs = (struct idx **)PyMem_Malloc(num_i * sizeof(struct idx *));
332
333     for (i = 0; i < num_i; i++)
334     {
335         long len, sha_ofs, name_map_ofs;
336         idxs[i] = (struct idx *)PyMem_Malloc(sizeof(struct idx));
337         PyObject *itup = PyList_GetItem(ilist, i);
338         if (!PyArg_ParseTuple(itup, "t#llli", &idxs[i]->map, &idxs[i]->bytes,
339                     &len, &sha_ofs, &name_map_ofs, &idxs[i]->name_base))
340             return NULL;
341         idxs[i]->cur = (struct sha *)&idxs[i]->map[sha_ofs];
342         idxs[i]->end = &idxs[i]->cur[len];
343         if (name_map_ofs)
344             idxs[i]->cur_name = (uint32_t *)&idxs[i]->map[name_map_ofs];
345         else
346             idxs[i]->cur_name = NULL;
347     }
348     table_ptr = (uint32_t *)&fmap[12];
349     sha_ptr = (struct sha *)&table_ptr[1<<bits];
350     name_ptr = (uint32_t *)&sha_ptr[total];
351
352     last_i = num_i-1;
353     count = 0;
354     prefix = 0;
355     while (last_i >= 0)
356     {
357         struct idx *idx;
358         uint32_t new_prefix;
359         if (count % 102424 == 0 && istty)
360             fprintf(stderr, "midx: writing %.2f%% (%d/%d)\r",
361                     count*100.0/total, count, total);
362         idx = idxs[last_i];
363         new_prefix = _extract_bits((unsigned char *)idx->cur, bits);
364         while (prefix < new_prefix)
365             table_ptr[prefix++] = htonl(count);
366         if (last == NULL || _cmp_sha(last, idx->cur) != 0)
367         {
368             memcpy(sha_ptr++, idx->cur, 20);
369             *name_ptr++ = htonl(_get_idx_i(idx));
370             last = idx->cur;
371         }
372         ++idx->cur;
373         if (idx->cur_name != NULL)
374             ++idx->cur_name;
375         _fix_idx_order(idxs, &last_i);
376         ++count;
377     }
378     table_ptr[prefix] = htonl(count);
379
380     PyMem_Free(idxs);
381     return PyLong_FromUnsignedLong(count);
382 }
383
384
385 // I would have made this a lower-level function that just fills in a buffer
386 // with random values, and then written those values from python.  But that's
387 // about 20% slower in my tests, and since we typically generate random
388 // numbers for benchmarking other parts of bup, any slowness in generating
389 // random bytes will make our benchmarks inaccurate.  Plus nobody wants
390 // pseudorandom bytes much except for this anyway.
391 static PyObject *write_random(PyObject *self, PyObject *args)
392 {
393     uint32_t buf[1024/4];
394     int fd = -1, seed = 0, verbose = 0;
395     ssize_t ret;
396     long long len = 0, kbytes = 0, written = 0;
397
398     if (!PyArg_ParseTuple(args, "iLii", &fd, &len, &seed, &verbose))
399         return NULL;
400     
401     srandom(seed);
402     
403     for (kbytes = 0; kbytes < len/1024; kbytes++)
404     {
405         unsigned i;
406         for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++)
407             buf[i] = random();
408         ret = write(fd, buf, sizeof(buf));
409         if (ret < 0)
410             ret = 0;
411         written += ret;
412         if (ret < (int)sizeof(buf))
413             break;
414         if (verbose && kbytes/1024 > 0 && !(kbytes%1024))
415             fprintf(stderr, "Random: %lld Mbytes\r", kbytes/1024);
416     }
417     
418     // handle non-multiples of 1024
419     if (len % 1024)
420     {
421         unsigned i;
422         for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++)
423             buf[i] = random();
424         ret = write(fd, buf, len % 1024);
425         if (ret < 0)
426             ret = 0;
427         written += ret;
428     }
429     
430     if (kbytes/1024 > 0)
431         fprintf(stderr, "Random: %lld Mbytes, done.\n", kbytes/1024);
432     return Py_BuildValue("L", written);
433 }
434
435
436 static PyObject *random_sha(PyObject *self, PyObject *args)
437 {
438     static int seeded = 0;
439     uint32_t shabuf[20/4];
440     int i;
441     
442     if (!seeded)
443     {
444         assert(sizeof(shabuf) == 20);
445         srandom(time(NULL));
446         seeded = 1;
447     }
448     
449     if (!PyArg_ParseTuple(args, ""))
450         return NULL;
451     
452     memset(shabuf, 0, sizeof(shabuf));
453     for (i=0; i < 20/4; i++)
454         shabuf[i] = random();
455     return Py_BuildValue("s#", shabuf, 20);
456 }
457
458
459 static PyObject *open_noatime(PyObject *self, PyObject *args)
460 {
461     char *filename = NULL;
462     int attrs, attrs_noatime, fd;
463     if (!PyArg_ParseTuple(args, "s", &filename))
464         return NULL;
465     attrs = O_RDONLY;
466 #ifdef O_NOFOLLOW
467     attrs |= O_NOFOLLOW;
468 #endif
469 #ifdef O_LARGEFILE
470     attrs |= O_LARGEFILE;
471 #endif
472     attrs_noatime = attrs;
473 #ifdef O_NOATIME
474     attrs_noatime |= O_NOATIME;
475 #endif
476     fd = open(filename, attrs_noatime);
477     if (fd < 0 && errno == EPERM)
478     {
479         // older Linux kernels would return EPERM if you used O_NOATIME
480         // and weren't the file's owner.  This pointless restriction was
481         // relaxed eventually, but we have to handle it anyway.
482         // (VERY old kernels didn't recognized O_NOATIME, but they would
483         // just harmlessly ignore it, so this branch won't trigger)
484         fd = open(filename, attrs);
485     }
486     if (fd < 0)
487         return PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
488     return Py_BuildValue("i", fd);
489 }
490
491
492 static PyObject *fadvise_done(PyObject *self, PyObject *args)
493 {
494     int fd = -1;
495     long long ofs = 0;
496     if (!PyArg_ParseTuple(args, "iL", &fd, &ofs))
497         return NULL;
498 #ifdef POSIX_FADV_DONTNEED
499     posix_fadvise(fd, 0, ofs, POSIX_FADV_DONTNEED);
500 #endif    
501     return Py_BuildValue("");
502 }
503
504
505 #ifdef linux
506 static PyObject *bup_get_linux_file_attr(PyObject *self, PyObject *args)
507 {
508     int rc;
509     unsigned long attr;
510     char *path;
511     int fd;
512
513     if (!PyArg_ParseTuple(args, "s", &path))
514         return NULL;
515
516     fd = open(path, O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_NOFOLLOW);
517     if (fd == -1)
518         return PyErr_SetFromErrnoWithFilename(PyExc_IOError, path);
519
520     attr = 0;
521     rc = ioctl(fd, FS_IOC_GETFLAGS, &attr);
522     if (rc == -1)
523     {
524         close(fd);
525         return PyErr_SetFromErrnoWithFilename(PyExc_IOError, path);
526     }
527
528     close(fd);
529     return Py_BuildValue("k", attr);
530 }
531
532
533 static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args)
534 {
535     int rc;
536     unsigned long attr;
537     char *path;
538     int fd;
539
540     if (!PyArg_ParseTuple(args, "sk", &path, &attr))
541         return NULL;
542
543     fd = open(path, O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_NOFOLLOW);
544     if(fd == -1)
545         return PyErr_SetFromErrnoWithFilename(PyExc_IOError, path);
546
547     rc = ioctl(fd, FS_IOC_SETFLAGS, &attr);
548     if (rc == -1)
549     {
550         close(fd);
551         return PyErr_SetFromErrnoWithFilename(PyExc_IOError, path);
552     }
553
554     close(fd);
555     Py_RETURN_TRUE;
556 }
557 #endif /* def linux */
558
559
560 #if defined(_ATFILE_SOURCE) \
561   || _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
562 #define HAVE_BUP_UTIMENSAT 1
563
564 static PyObject *bup_utimensat(PyObject *self, PyObject *args)
565 {
566     int rc, dirfd, flags;
567     char *path;
568     long access, access_ns, modification, modification_ns;
569     struct timespec ts[2];
570
571     if (!PyArg_ParseTuple(args, "is((ll)(ll))i",
572                           &dirfd,
573                           &path,
574                           &access, &access_ns,
575                           &modification, &modification_ns,
576                           &flags))
577         return NULL;
578
579     if (isnan(access))
580     {
581         PyErr_SetString(PyExc_ValueError, "access time is NaN");
582         return NULL;
583     }
584     else if (isinf(access))
585     {
586         PyErr_SetString(PyExc_ValueError, "access time is infinite");
587         return NULL;
588     }
589     else if (isnan(modification))
590     {
591         PyErr_SetString(PyExc_ValueError, "modification time is NaN");
592         return NULL;
593     }
594     else if (isinf(modification))
595     {
596         PyErr_SetString(PyExc_ValueError, "modification time is infinite");
597         return NULL;
598     }
599
600     if (isnan(access_ns))
601     {
602         PyErr_SetString(PyExc_ValueError, "access time ns is NaN");
603         return NULL;
604     }
605     else if (isinf(access_ns))
606     {
607         PyErr_SetString(PyExc_ValueError, "access time ns is infinite");
608         return NULL;
609     }
610     else if (isnan(modification_ns))
611     {
612         PyErr_SetString(PyExc_ValueError, "modification time ns is NaN");
613         return NULL;
614     }
615     else if (isinf(modification_ns))
616     {
617         PyErr_SetString(PyExc_ValueError, "modification time ns is infinite");
618         return NULL;
619     }
620
621     ts[0].tv_sec = access;
622     ts[0].tv_nsec = access_ns;
623     ts[1].tv_sec = modification;
624     ts[1].tv_nsec = modification_ns;
625
626     rc = utimensat(dirfd, path, ts, flags);
627     if (rc != 0)
628         return PyErr_SetFromErrnoWithFilename(PyExc_IOError, path);
629
630     Py_RETURN_TRUE;
631 }
632
633 #endif /* defined(_ATFILE_SOURCE)
634           || _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L */
635
636
637 #ifdef linux /* and likely others */
638
639 #define HAVE_BUP_STAT 1
640 static PyObject *bup_stat(PyObject *self, PyObject *args)
641 {
642     int rc;
643     char *filename;
644
645     if (!PyArg_ParseTuple(args, "s", &filename))
646         return NULL;
647
648     struct stat st;
649     rc = stat(filename, &st);
650     if (rc != 0)
651         return PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
652
653     return Py_BuildValue("kkkkkkkk"
654                          "(ll)"
655                          "(ll)"
656                          "(ll)",
657                          (unsigned long) st.st_mode,
658                          (unsigned long) st.st_ino,
659                          (unsigned long) st.st_dev,
660                          (unsigned long) st.st_nlink,
661                          (unsigned long) st.st_uid,
662                          (unsigned long) st.st_gid,
663                          (unsigned long) st.st_rdev,
664                          (unsigned long) st.st_size,
665                          (long) st.st_atime,
666                          (long) st.st_atim.tv_nsec,
667                          (long) st.st_mtime,
668                          (long) st.st_mtim.tv_nsec,
669                          (long) st.st_ctime,
670                          (long) st.st_ctim.tv_nsec);
671 }
672
673
674 #define HAVE_BUP_LSTAT 1
675 static PyObject *bup_lstat(PyObject *self, PyObject *args)
676 {
677     int rc;
678     char *filename;
679
680     if (!PyArg_ParseTuple(args, "s", &filename))
681         return NULL;
682
683     struct stat st;
684     rc = lstat(filename, &st);
685     if (rc != 0)
686         return PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
687
688     return Py_BuildValue("kkkkkkkk"
689                          "(ll)"
690                          "(ll)"
691                          "(ll)",
692                          (unsigned long) st.st_mode,
693                          (unsigned long) st.st_ino,
694                          (unsigned long) st.st_dev,
695                          (unsigned long) st.st_nlink,
696                          (unsigned long) st.st_uid,
697                          (unsigned long) st.st_gid,
698                          (unsigned long) st.st_rdev,
699                          (unsigned long) st.st_size,
700                          (long) st.st_atime,
701                          (long) st.st_atim.tv_nsec,
702                          (long) st.st_mtime,
703                          (long) st.st_mtim.tv_nsec,
704                          (long) st.st_ctime,
705                          (long) st.st_ctim.tv_nsec);
706 }
707
708
709 #define HAVE_BUP_FSTAT 1
710 static PyObject *bup_fstat(PyObject *self, PyObject *args)
711 {
712     int rc, fd;
713
714     if (!PyArg_ParseTuple(args, "i", &fd))
715         return NULL;
716
717     struct stat st;
718     rc = fstat(fd, &st);
719     if (rc != 0)
720         return PyErr_SetFromErrno(PyExc_IOError);
721
722     return Py_BuildValue("kkkkkkkk"
723                          "(ll)"
724                          "(ll)"
725                          "(ll)",
726                          (unsigned long) st.st_mode,
727                          (unsigned long) st.st_ino,
728                          (unsigned long) st.st_dev,
729                          (unsigned long) st.st_nlink,
730                          (unsigned long) st.st_uid,
731                          (unsigned long) st.st_gid,
732                          (unsigned long) st.st_rdev,
733                          (unsigned long) st.st_size,
734                          (long) st.st_atime,
735                          (long) st.st_atim.tv_nsec,
736                          (long) st.st_mtime,
737                          (long) st.st_mtim.tv_nsec,
738                          (long) st.st_ctime,
739                          (long) st.st_ctim.tv_nsec);
740 }
741
742 #endif /* def linux */
743
744
745 static PyMethodDef faster_methods[] = {
746     { "selftest", selftest, METH_VARARGS,
747         "Check that the rolling checksum rolls correctly (for unit tests)." },
748     { "blobbits", blobbits, METH_VARARGS,
749         "Return the number of bits in the rolling checksum." },
750     { "splitbuf", splitbuf, METH_VARARGS,
751         "Split a list of strings based on a rolling checksum." },
752     { "bitmatch", bitmatch, METH_VARARGS,
753         "Count the number of matching prefix bits between two strings." },
754     { "firstword", firstword, METH_VARARGS,
755         "Return an int corresponding to the first 32 bits of buf." },
756     { "bloom_contains", bloom_contains, METH_VARARGS,
757         "Check if a bloom filter of 2^nbits bytes contains an object" },
758     { "bloom_add", bloom_add, METH_VARARGS,
759         "Add an object to a bloom filter of 2^nbits bytes" },
760     { "extract_bits", extract_bits, METH_VARARGS,
761         "Take the first 'nbits' bits from 'buf' and return them as an int." },
762     { "merge_into", merge_into, METH_VARARGS,
763         "Merges a bunch of idx and midx files into a single midx." },
764     { "write_random", write_random, METH_VARARGS,
765         "Write random bytes to the given file descriptor" },
766     { "random_sha", random_sha, METH_VARARGS,
767         "Return a random 20-byte string" },
768     { "open_noatime", open_noatime, METH_VARARGS,
769         "open() the given filename for read with O_NOATIME if possible" },
770     { "fadvise_done", fadvise_done, METH_VARARGS,
771         "Inform the kernel that we're finished with earlier parts of a file" },
772 #ifdef linux
773     { "get_linux_file_attr", bup_get_linux_file_attr, METH_VARARGS,
774       "Return the Linux attributes for the given file." },
775     { "set_linux_file_attr", bup_set_linux_file_attr, METH_VARARGS,
776       "Set the Linux attributes for the given file." },
777 #endif
778 #ifdef HAVE_BUP_UTIMENSAT
779     { "utimensat", bup_utimensat, METH_VARARGS,
780       "Change file timestamps with nanosecond precision." },
781 #endif
782 #ifdef HAVE_BUP_STAT
783     { "stat", bup_stat, METH_VARARGS,
784       "Extended version of stat." },
785 #endif
786 #ifdef HAVE_BUP_LSTAT
787     { "lstat", bup_lstat, METH_VARARGS,
788       "Extended version of lstat." },
789 #endif
790 #ifdef HAVE_BUP_FSTAT
791     { "fstat", bup_fstat, METH_VARARGS,
792       "Extended version of fstat." },
793 #endif
794     { NULL, NULL, 0, NULL },  // sentinel
795 };
796
797
798 PyMODINIT_FUNC init_helpers(void)
799 {
800     PyObject *m = Py_InitModule("_helpers", faster_methods);
801     if (m == NULL)
802         return;
803 #ifdef HAVE_BUP_UTIMENSAT
804     PyModule_AddObject(m, "AT_FDCWD", Py_BuildValue("i", AT_FDCWD));
805     PyModule_AddObject(m, "AT_SYMLINK_NOFOLLOW",
806                        Py_BuildValue("i", AT_SYMLINK_NOFOLLOW));
807 #endif
808 #ifdef HAVE_BUP_STAT
809     Py_INCREF(Py_True);
810     PyModule_AddObject(m, "_have_ns_fs_timestamps", Py_True);
811 #else
812     Py_INCREF(Py_False);
813     PyModule_AddObject(m, "_have_ns_fs_timestamps", Py_False);
814 #endif
815     istty = isatty(2) || getenv("BUP_FORCE_TTY");
816 }