]> arthur.barton.de Git - bup.git/blob - lib/bup/_helpers.c
04a3bb9ce9a928ac3154a7d95a1f88202143efce
[bup.git] / lib / bup / _helpers.c
1 #define _LARGEFILE64_SOURCE 1
2 #undef NDEBUG
3 #include "../../config/config.h"
4 #include "bupsplit.h"
5 #include <Python.h>
6 #include <assert.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <arpa/inet.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13
14 #ifdef HAVE_SYS_TYPES_H
15 #include <sys/types.h>
16 #endif
17 #ifdef HAVE_SYS_STAT_H
18 #include <sys/stat.h>
19 #endif
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif
23
24 #ifdef HAVE_LINUX_FS_H
25 #include <linux/fs.h>
26 #endif
27 #ifdef HAVE_SYS_IOCTL_H
28 #include <sys/ioctl.h>
29 #endif
30 #ifdef HAVE_EXT2FS_EXT2_FS_H
31 #include <ext2fs/ext2_fs.h>
32 #endif
33
34 #if defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) \
35     && defined(HAVE_EXT2FS_EXT2_FS_H)
36 #define BUP_HAVE_FILE_ATTRS 1
37 #endif
38
39 static int istty2 = 0;
40
41 // Probably we should use autoconf or something and set HAVE_PY_GETARGCARGV...
42 #if __WIN32__ || __CYGWIN__
43
44 // There's no 'ps' on win32 anyway, and Py_GetArgcArgv() isn't available.
45 static void unpythonize_argv(void) { }
46
47 #else // not __WIN32__
48
49 // For some reason this isn't declared in Python.h
50 extern void Py_GetArgcArgv(int *argc, char ***argv);
51
52 static void unpythonize_argv(void)
53 {
54     int argc, i;
55     char **argv, *arge;
56     
57     Py_GetArgcArgv(&argc, &argv);
58     
59     for (i = 0; i < argc-1; i++)
60     {
61         if (argv[i] + strlen(argv[i]) + 1 != argv[i+1])
62         {
63             // The argv block doesn't work the way we expected; it's unsafe
64             // to mess with it.
65             return;
66         }
67     }
68     
69     arge = argv[argc-1] + strlen(argv[argc-1]) + 1;
70     
71     if (strstr(argv[0], "python") && argv[1] == argv[0] + strlen(argv[0]) + 1)
72     {
73         char *p;
74         size_t len, diff;
75         p = strrchr(argv[1], '/');
76         if (p)
77         {
78             p++;
79             diff = p - argv[0];
80             len = arge - p;
81             memmove(argv[0], p, len);
82             memset(arge - diff, 0, diff);
83             for (i = 0; i < argc; i++)
84                 argv[i] = argv[i+1] ? argv[i+1]-diff : NULL;
85         }
86     }
87 }
88
89 #endif // not __WIN32__ or __CYGWIN__
90
91
92 static PyObject *selftest(PyObject *self, PyObject *args)
93 {
94     if (!PyArg_ParseTuple(args, ""))
95         return NULL;
96     
97     return Py_BuildValue("i", !bupsplit_selftest());
98 }
99
100
101 static PyObject *blobbits(PyObject *self, PyObject *args)
102 {
103     if (!PyArg_ParseTuple(args, ""))
104         return NULL;
105     return Py_BuildValue("i", BUP_BLOBBITS);
106 }
107
108
109 static PyObject *splitbuf(PyObject *self, PyObject *args)
110 {
111     unsigned char *buf = NULL;
112     int len = 0, out = 0, bits = -1;
113
114     if (!PyArg_ParseTuple(args, "t#", &buf, &len))
115         return NULL;
116     out = bupsplit_find_ofs(buf, len, &bits);
117     if (out) assert(bits >= BUP_BLOBBITS);
118     return Py_BuildValue("ii", out, bits);
119 }
120
121
122 static PyObject *bitmatch(PyObject *self, PyObject *args)
123 {
124     unsigned char *buf1 = NULL, *buf2 = NULL;
125     int len1 = 0, len2 = 0;
126     int byte, bit;
127
128     if (!PyArg_ParseTuple(args, "t#t#", &buf1, &len1, &buf2, &len2))
129         return NULL;
130     
131     bit = 0;
132     for (byte = 0; byte < len1 && byte < len2; byte++)
133     {
134         int b1 = buf1[byte], b2 = buf2[byte];
135         if (b1 != b2)
136         {
137             for (bit = 0; bit < 8; bit++)
138                 if ( (b1 & (0x80 >> bit)) != (b2 & (0x80 >> bit)) )
139                     break;
140             break;
141         }
142     }
143     
144     return Py_BuildValue("i", byte*8 + bit);
145 }
146
147
148 static PyObject *firstword(PyObject *self, PyObject *args)
149 {
150     unsigned char *buf = NULL;
151     int len = 0;
152     uint32_t v;
153
154     if (!PyArg_ParseTuple(args, "t#", &buf, &len))
155         return NULL;
156     
157     if (len < 4)
158         return NULL;
159     
160     v = ntohl(*(uint32_t *)buf);
161     return PyLong_FromUnsignedLong(v);
162 }
163
164
165 #define BLOOM2_HEADERLEN 16
166
167 typedef struct {
168     uint32_t high;
169     unsigned char low;
170 } bits40_t;
171
172 static void to_bloom_address_bitmask4(const bits40_t *buf,
173         const int nbits, uint64_t *v, unsigned char *bitmask)
174 {
175     int bit;
176     uint64_t raw, mask;
177
178     mask = (1<<nbits) - 1;
179     raw = (((uint64_t)ntohl(buf->high)) << 8) | buf->low;
180     bit = (raw >> (37-nbits)) & 0x7;
181     *v = (raw >> (40-nbits)) & mask;
182     *bitmask = 1 << bit;
183 }
184
185 static void to_bloom_address_bitmask5(const uint32_t *buf,
186         const int nbits, uint32_t *v, unsigned char *bitmask)
187 {
188     int bit;
189     uint32_t raw, mask;
190
191     mask = (1<<nbits) - 1;
192     raw = ntohl(*buf);
193     bit = (raw >> (29-nbits)) & 0x7;
194     *v = (raw >> (32-nbits)) & mask;
195     *bitmask = 1 << bit;
196 }
197
198 #define BLOOM_SET_BIT(name, address, itype, otype) \
199 static void name(unsigned char *bloom, const void *buf, const int nbits)\
200 {\
201     unsigned char bitmask;\
202     otype v;\
203     address((itype *)buf, nbits, &v, &bitmask);\
204     bloom[BLOOM2_HEADERLEN+v] |= bitmask;\
205 }
206 BLOOM_SET_BIT(bloom_set_bit4, to_bloom_address_bitmask4, bits40_t, uint64_t)
207 BLOOM_SET_BIT(bloom_set_bit5, to_bloom_address_bitmask5, uint32_t, uint32_t)
208
209
210 #define BLOOM_GET_BIT(name, address, itype, otype) \
211 static int name(const unsigned char *bloom, const void *buf, const int nbits)\
212 {\
213     unsigned char bitmask;\
214     otype v;\
215     address((itype *)buf, nbits, &v, &bitmask);\
216     return bloom[BLOOM2_HEADERLEN+v] & bitmask;\
217 }
218 BLOOM_GET_BIT(bloom_get_bit4, to_bloom_address_bitmask4, bits40_t, uint64_t)
219 BLOOM_GET_BIT(bloom_get_bit5, to_bloom_address_bitmask5, uint32_t, uint32_t)
220
221
222 static PyObject *bloom_add(PyObject *self, PyObject *args)
223 {
224     unsigned char *sha = NULL, *bloom = NULL;
225     unsigned char *end;
226     int len = 0, blen = 0, nbits = 0, k = 0;
227
228     if (!PyArg_ParseTuple(args, "w#s#ii", &bloom, &blen, &sha, &len, &nbits, &k))
229         return NULL;
230
231     if (blen < 16+(1<<nbits) || len % 20 != 0)
232         return NULL;
233
234     if (k == 5)
235     {
236         if (nbits > 29)
237             return NULL;
238         for (end = sha + len; sha < end; sha += 20/k)
239             bloom_set_bit5(bloom, sha, nbits);
240     }
241     else if (k == 4)
242     {
243         if (nbits > 37)
244             return NULL;
245         for (end = sha + len; sha < end; sha += 20/k)
246             bloom_set_bit4(bloom, sha, nbits);
247     }
248     else
249         return NULL;
250
251
252     return Py_BuildValue("i", len/20);
253 }
254
255 static PyObject *bloom_contains(PyObject *self, PyObject *args)
256 {
257     unsigned char *sha = NULL, *bloom = NULL;
258     int len = 0, blen = 0, nbits = 0, k = 0;
259     unsigned char *end;
260     int steps;
261
262     if (!PyArg_ParseTuple(args, "t#s#ii", &bloom, &blen, &sha, &len, &nbits, &k))
263         return NULL;
264
265     if (len != 20)
266         return NULL;
267
268     if (k == 5)
269     {
270         if (nbits > 29)
271             return NULL;
272         for (steps = 1, end = sha + 20; sha < end; sha += 20/k, steps++)
273             if (!bloom_get_bit5(bloom, sha, nbits))
274                 return Py_BuildValue("Oi", Py_None, steps);
275     }
276     else if (k == 4)
277     {
278         if (nbits > 37)
279             return NULL;
280         for (steps = 1, end = sha + 20; sha < end; sha += 20/k, steps++)
281             if (!bloom_get_bit4(bloom, sha, nbits))
282                 return Py_BuildValue("Oi", Py_None, steps);
283     }
284     else
285         return NULL;
286
287     return Py_BuildValue("ii", 1, k);
288 }
289
290
291 static uint32_t _extract_bits(unsigned char *buf, int nbits)
292 {
293     uint32_t v, mask;
294
295     mask = (1<<nbits) - 1;
296     v = ntohl(*(uint32_t *)buf);
297     v = (v >> (32-nbits)) & mask;
298     return v;
299 }
300 static PyObject *extract_bits(PyObject *self, PyObject *args)
301 {
302     unsigned char *buf = NULL;
303     int len = 0, nbits = 0;
304
305     if (!PyArg_ParseTuple(args, "t#i", &buf, &len, &nbits))
306         return NULL;
307     
308     if (len < 4)
309         return NULL;
310     
311     return PyLong_FromUnsignedLong(_extract_bits(buf, nbits));
312 }
313
314
315 struct sha {
316     unsigned char bytes[20];
317 };
318 struct idx {
319     unsigned char *map;
320     struct sha *cur;
321     struct sha *end;
322     uint32_t *cur_name;
323     long bytes;
324     int name_base;
325 };
326
327
328 static int _cmp_sha(const struct sha *sha1, const struct sha *sha2)
329 {
330     int i;
331     for (i = 0; i < sizeof(struct sha); i++)
332         if (sha1->bytes[i] != sha2->bytes[i])
333             return sha1->bytes[i] - sha2->bytes[i];
334     return 0;
335 }
336
337
338 static void _fix_idx_order(struct idx **idxs, int *last_i)
339 {
340     struct idx *idx;
341     int low, mid, high, c = 0;
342
343     idx = idxs[*last_i];
344     if (idxs[*last_i]->cur >= idxs[*last_i]->end)
345     {
346         idxs[*last_i] = NULL;
347         PyMem_Free(idx);
348         --*last_i;
349         return;
350     }
351     if (*last_i == 0)
352         return;
353
354     low = *last_i-1;
355     mid = *last_i;
356     high = 0;
357     while (low >= high)
358     {
359         mid = (low + high) / 2;
360         c = _cmp_sha(idx->cur, idxs[mid]->cur);
361         if (c < 0)
362             high = mid + 1;
363         else if (c > 0)
364             low = mid - 1;
365         else
366             break;
367     }
368     if (c < 0)
369         ++mid;
370     if (mid == *last_i)
371         return;
372     memmove(&idxs[mid+1], &idxs[mid], (*last_i-mid)*sizeof(struct idx *));
373     idxs[mid] = idx;
374 }
375
376
377 static uint32_t _get_idx_i(struct idx *idx)
378 {
379     if (idx->cur_name == NULL)
380         return idx->name_base;
381     return ntohl(*idx->cur_name) + idx->name_base;
382 }
383
384 #define MIDX4_HEADERLEN 12
385
386 static PyObject *merge_into(PyObject *self, PyObject *args)
387 {
388     PyObject *ilist = NULL;
389     unsigned char *fmap = NULL;
390     struct sha *sha_ptr, *sha_start = NULL;
391     uint32_t *table_ptr, *name_ptr, *name_start;
392     struct idx **idxs = NULL;
393     int flen = 0, bits = 0, i;
394     uint32_t total, count, prefix;
395     int num_i;
396     int last_i;
397
398     if (!PyArg_ParseTuple(args, "w#iIO", &fmap, &flen, &bits, &total, &ilist))
399         return NULL;
400
401     num_i = PyList_Size(ilist);
402     idxs = (struct idx **)PyMem_Malloc(num_i * sizeof(struct idx *));
403
404     for (i = 0; i < num_i; i++)
405     {
406         long len, sha_ofs, name_map_ofs;
407         idxs[i] = (struct idx *)PyMem_Malloc(sizeof(struct idx));
408         PyObject *itup = PyList_GetItem(ilist, i);
409         if (!PyArg_ParseTuple(itup, "t#llli", &idxs[i]->map, &idxs[i]->bytes,
410                     &len, &sha_ofs, &name_map_ofs, &idxs[i]->name_base))
411             return NULL;
412         idxs[i]->cur = (struct sha *)&idxs[i]->map[sha_ofs];
413         idxs[i]->end = &idxs[i]->cur[len];
414         if (name_map_ofs)
415             idxs[i]->cur_name = (uint32_t *)&idxs[i]->map[name_map_ofs];
416         else
417             idxs[i]->cur_name = NULL;
418     }
419     table_ptr = (uint32_t *)&fmap[MIDX4_HEADERLEN];
420     sha_start = sha_ptr = (struct sha *)&table_ptr[1<<bits];
421     name_start = name_ptr = (uint32_t *)&sha_ptr[total];
422
423     last_i = num_i-1;
424     count = 0;
425     prefix = 0;
426     while (last_i >= 0)
427     {
428         struct idx *idx;
429         uint32_t new_prefix;
430         if (count % 102424 == 0 && istty2)
431             fprintf(stderr, "midx: writing %.2f%% (%d/%d)\r",
432                     count*100.0/total, count, total);
433         idx = idxs[last_i];
434         new_prefix = _extract_bits((unsigned char *)idx->cur, bits);
435         while (prefix < new_prefix)
436             table_ptr[prefix++] = htonl(count);
437         memcpy(sha_ptr++, idx->cur, sizeof(struct sha));
438         *name_ptr++ = htonl(_get_idx_i(idx));
439         ++idx->cur;
440         if (idx->cur_name != NULL)
441             ++idx->cur_name;
442         _fix_idx_order(idxs, &last_i);
443         ++count;
444     }
445     while (prefix < (1<<bits))
446         table_ptr[prefix++] = htonl(count);
447     assert(count == total);
448     assert(prefix == (1<<bits));
449     assert(sha_ptr == sha_start+count);
450     assert(name_ptr == name_start+count);
451
452     PyMem_Free(idxs);
453     return PyLong_FromUnsignedLong(count);
454 }
455
456 // This function should technically be macro'd out if it's going to be used
457 // more than ocasionally.  As of this writing, it'll actually never be called
458 // in real world bup scenarios (because our packs are < MAX_INT bytes).
459 static uint64_t htonll(uint64_t value)
460 {
461     static const int endian_test = 42;
462
463     if (*(char *)&endian_test == endian_test) // LSB-MSB
464         return ((uint64_t)htonl(value & 0xFFFFFFFF) << 32) | htonl(value >> 32);
465     return value; // already in network byte order MSB-LSB
466 }
467
468 #define PACK_IDX_V2_HEADERLEN 8
469 #define FAN_ENTRIES 256
470
471 static PyObject *write_idx(PyObject *self, PyObject *args)
472 {
473     PyObject *pf = NULL, *idx = NULL;
474     PyObject *part;
475     FILE *f;
476     unsigned char *fmap = NULL;
477     int flen = 0;
478     uint32_t total = 0;
479     uint32_t count;
480     int i, j, ofs64_count;
481     uint32_t *fan_ptr, *crc_ptr, *ofs_ptr;
482     struct sha *sha_ptr;
483
484     if (!PyArg_ParseTuple(args, "Ow#OI", &pf, &fmap, &flen, &idx, &total))
485         return NULL;
486
487     fan_ptr = (uint32_t *)&fmap[PACK_IDX_V2_HEADERLEN];
488     sha_ptr = (struct sha *)&fan_ptr[FAN_ENTRIES];
489     crc_ptr = (uint32_t *)&sha_ptr[total];
490     ofs_ptr = (uint32_t *)&crc_ptr[total];
491     f = PyFile_AsFile(pf);
492
493     count = 0;
494     ofs64_count = 0;
495     for (i = 0; i < FAN_ENTRIES; ++i)
496     {
497         int plen;
498         part = PyList_GET_ITEM(idx, i);
499         PyList_Sort(part);
500         plen = PyList_GET_SIZE(part);
501         count += plen;
502         *fan_ptr++ = htonl(count);
503         for (j = 0; j < plen; ++j)
504         {
505             unsigned char *sha = NULL;
506             int sha_len = 0;
507             uint32_t crc = 0;
508             uint64_t ofs = 0;
509             if (!PyArg_ParseTuple(PyList_GET_ITEM(part, j), "t#IK",
510                                   &sha, &sha_len, &crc, &ofs))
511                 return NULL;
512             if (sha_len != sizeof(struct sha))
513                 return NULL;
514             memcpy(sha_ptr++, sha, sizeof(struct sha));
515             *crc_ptr++ = htonl(crc);
516             if (ofs > 0x7fffffff)
517             {
518                 uint64_t nofs = htonll(ofs);
519                 if (fwrite(&nofs, sizeof(uint64_t), 1, f) != 1)
520                     return PyErr_SetFromErrno(PyExc_OSError);
521                 ofs = 0x80000000 | ofs64_count++;
522             }
523             *ofs_ptr++ = htonl((uint32_t)ofs);
524         }
525     }
526     return PyLong_FromUnsignedLong(count);
527 }
528
529
530 // I would have made this a lower-level function that just fills in a buffer
531 // with random values, and then written those values from python.  But that's
532 // about 20% slower in my tests, and since we typically generate random
533 // numbers for benchmarking other parts of bup, any slowness in generating
534 // random bytes will make our benchmarks inaccurate.  Plus nobody wants
535 // pseudorandom bytes much except for this anyway.
536 static PyObject *write_random(PyObject *self, PyObject *args)
537 {
538     uint32_t buf[1024/4];
539     int fd = -1, seed = 0, verbose = 0;
540     ssize_t ret;
541     long long len = 0, kbytes = 0, written = 0;
542
543     if (!PyArg_ParseTuple(args, "iLii", &fd, &len, &seed, &verbose))
544         return NULL;
545     
546     srandom(seed);
547     
548     for (kbytes = 0; kbytes < len/1024; kbytes++)
549     {
550         unsigned i;
551         for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++)
552             buf[i] = random();
553         ret = write(fd, buf, sizeof(buf));
554         if (ret < 0)
555             ret = 0;
556         written += ret;
557         if (ret < (int)sizeof(buf))
558             break;
559         if (verbose && kbytes/1024 > 0 && !(kbytes%1024))
560             fprintf(stderr, "Random: %lld Mbytes\r", kbytes/1024);
561     }
562     
563     // handle non-multiples of 1024
564     if (len % 1024)
565     {
566         unsigned i;
567         for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++)
568             buf[i] = random();
569         ret = write(fd, buf, len % 1024);
570         if (ret < 0)
571             ret = 0;
572         written += ret;
573     }
574     
575     if (kbytes/1024 > 0)
576         fprintf(stderr, "Random: %lld Mbytes, done.\n", kbytes/1024);
577     return Py_BuildValue("L", written);
578 }
579
580
581 static PyObject *random_sha(PyObject *self, PyObject *args)
582 {
583     static int seeded = 0;
584     uint32_t shabuf[20/4];
585     int i;
586     
587     if (!seeded)
588     {
589         assert(sizeof(shabuf) == 20);
590         srandom(time(NULL));
591         seeded = 1;
592     }
593     
594     if (!PyArg_ParseTuple(args, ""))
595         return NULL;
596     
597     memset(shabuf, 0, sizeof(shabuf));
598     for (i=0; i < 20/4; i++)
599         shabuf[i] = random();
600     return Py_BuildValue("s#", shabuf, 20);
601 }
602
603
604 static PyObject *open_noatime(PyObject *self, PyObject *args)
605 {
606     char *filename = NULL;
607     int attrs, attrs_noatime, fd;
608     if (!PyArg_ParseTuple(args, "s", &filename))
609         return NULL;
610     attrs = O_RDONLY;
611 #ifdef O_NOFOLLOW
612     attrs |= O_NOFOLLOW;
613 #endif
614 #ifdef O_LARGEFILE
615     attrs |= O_LARGEFILE;
616 #endif
617     attrs_noatime = attrs;
618 #ifdef O_NOATIME
619     attrs_noatime |= O_NOATIME;
620 #endif
621     fd = open(filename, attrs_noatime);
622     if (fd < 0 && errno == EPERM)
623     {
624         // older Linux kernels would return EPERM if you used O_NOATIME
625         // and weren't the file's owner.  This pointless restriction was
626         // relaxed eventually, but we have to handle it anyway.
627         // (VERY old kernels didn't recognized O_NOATIME, but they would
628         // just harmlessly ignore it, so this branch won't trigger)
629         fd = open(filename, attrs);
630     }
631     if (fd < 0)
632         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
633     return Py_BuildValue("i", fd);
634 }
635
636
637 static PyObject *fadvise_done(PyObject *self, PyObject *args)
638 {
639     int fd = -1;
640     long long ofs = 0;
641     if (!PyArg_ParseTuple(args, "iL", &fd, &ofs))
642         return NULL;
643 #ifdef POSIX_FADV_DONTNEED
644     posix_fadvise(fd, 0, ofs, POSIX_FADV_DONTNEED);
645 #endif    
646     return Py_BuildValue("");
647 }
648
649
650 #ifdef BUP_HAVE_FILE_ATTRS
651 static PyObject *bup_get_linux_file_attr(PyObject *self, PyObject *args)
652 {
653     int rc;
654     unsigned long attr;
655     char *path;
656     int fd;
657
658     if (!PyArg_ParseTuple(args, "s", &path))
659         return NULL;
660
661     fd = open(path, O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_NOFOLLOW);
662     if (fd == -1)
663         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
664
665     attr = 0;
666     rc = ioctl(fd, FS_IOC_GETFLAGS, &attr);
667     if (rc == -1)
668     {
669         close(fd);
670         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
671     }
672
673     close(fd);
674     return Py_BuildValue("k", attr);
675 }
676 #endif /* def BUP_HAVE_FILE_ATTRS */
677
678
679 #ifdef BUP_HAVE_FILE_ATTRS
680 static PyObject *bup_set_linux_file_attr(PyObject *self, PyObject *args)
681 {
682     int rc;
683     unsigned long attr;
684     char *path;
685     int fd;
686
687     if (!PyArg_ParseTuple(args, "sk", &path, &attr))
688         return NULL;
689
690     fd = open(path, O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_NOFOLLOW);
691     if (fd == -1)
692         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
693
694     // Restrict attr to modifiable flags acdeijstuADST -- see
695     // chattr(1) and the e2fsprogs source.  Letter to flag mapping is
696     // in pf.c flags_array[].
697     attr &= EXT2_APPEND_FL | EXT2_COMPR_FL | EXT2_NODUMP_FL | EXT4_EXTENTS_FL
698     | EXT2_IMMUTABLE_FL | EXT3_JOURNAL_DATA_FL | EXT2_SECRM_FL | EXT2_NOTAIL_FL
699     | EXT2_UNRM_FL | EXT2_NOATIME_FL | EXT2_DIRSYNC_FL | EXT2_SYNC_FL
700     | EXT2_TOPDIR_FL;
701
702     rc = ioctl(fd, FS_IOC_SETFLAGS, &attr);
703     if (rc == -1)
704     {
705         close(fd);
706         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
707     }
708
709     close(fd);
710     return Py_BuildValue("O", Py_None);
711 }
712 #endif /* def BUP_HAVE_FILE_ATTRS */
713
714
715 #if defined(HAVE_UTIMENSAT) || defined(HAVE_FUTIMES) || defined(HAVE_LUTIMES)
716
717 static int bup_parse_xutime_args(char **path,
718                                  long *access,
719                                  long *access_ns,
720                                  long *modification,
721                                  long *modification_ns,
722                                  PyObject *self, PyObject *args)
723 {
724     if (!PyArg_ParseTuple(args, "s((ll)(ll))",
725                           path,
726                           access, access_ns,
727                           modification, modification_ns))
728         return 0;
729
730     if (isnan(*access))
731     {
732         PyErr_SetString(PyExc_ValueError, "access time is NaN");
733         return 0;
734     }
735     else if (isinf(*access))
736     {
737         PyErr_SetString(PyExc_ValueError, "access time is infinite");
738         return 0;
739     }
740     else if (isnan(*modification))
741     {
742         PyErr_SetString(PyExc_ValueError, "modification time is NaN");
743         return 0;
744     }
745     else if (isinf(*modification))
746     {
747         PyErr_SetString(PyExc_ValueError, "modification time is infinite");
748         return 0;
749     }
750
751     if (isnan(*access_ns))
752     {
753         PyErr_SetString(PyExc_ValueError, "access time ns is NaN");
754         return 0;
755     }
756     else if (isinf(*access_ns))
757     {
758         PyErr_SetString(PyExc_ValueError, "access time ns is infinite");
759         return 0;
760     }
761     else if (isnan(*modification_ns))
762     {
763         PyErr_SetString(PyExc_ValueError, "modification time ns is NaN");
764         return 0;
765     }
766     else if (isinf(*modification_ns))
767     {
768         PyErr_SetString(PyExc_ValueError, "modification time ns is infinite");
769         return 0;
770     }
771
772     return 1;
773 }
774
775 #endif /* defined(HAVE_UTIMENSAT) || defined(HAVE_FUTIMES)
776           || defined(HAVE_LUTIMES) */
777
778
779 #ifdef HAVE_UTIMENSAT
780
781 static PyObject *bup_xutime_ns(PyObject *self, PyObject *args,
782                                int follow_symlinks)
783 {
784     int rc;
785     char *path;
786     long access, access_ns, modification, modification_ns;
787     struct timespec ts[2];
788
789     if (!bup_parse_xutime_args(&path, &access, &access_ns,
790                                &modification, &modification_ns,
791                                self, args))
792        return NULL;
793
794     ts[0].tv_sec = access;
795     ts[0].tv_nsec = access_ns;
796     ts[1].tv_sec = modification;
797     ts[1].tv_nsec = modification_ns;
798     rc = utimensat(AT_FDCWD, path, ts,
799                    follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
800     if (rc != 0)
801         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
802
803     return Py_BuildValue("O", Py_None);
804 }
805
806
807 #define BUP_HAVE_BUP_UTIME_NS 1
808 static PyObject *bup_utime_ns(PyObject *self, PyObject *args)
809 {
810     return bup_xutime_ns(self, args, 1);
811 }
812
813
814 #define BUP_HAVE_BUP_LUTIME_NS 1
815 static PyObject *bup_lutime_ns(PyObject *self, PyObject *args)
816 {
817     return bup_xutime_ns(self, args, 0);
818 }
819
820
821 #else /* not defined(HAVE_UTIMENSAT) */
822
823
824 #ifdef HAVE_UTIMES
825 #define BUP_HAVE_BUP_UTIME_NS 1
826 static PyObject *bup_utime_ns(PyObject *self, PyObject *args)
827 {
828     int rc;
829     char *path;
830     long access, access_ns, modification, modification_ns;
831     struct timeval tv[2];
832
833     if (!bup_parse_xutime_args(&path, &access, &access_ns,
834                                &modification, &modification_ns,
835                                self, args))
836        return NULL;
837
838     tv[0].tv_sec = access;
839     tv[0].tv_usec = access_ns / 1000;
840     tv[1].tv_sec = modification;
841     tv[1].tv_usec = modification_ns / 1000;
842     rc = utimes(path, tv);
843     if (rc != 0)
844         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
845
846     return Py_BuildValue("O", Py_None);
847 }
848 #endif /* def HAVE_UTIMES */
849
850
851 #ifdef HAVE_LUTIMES
852 #define BUP_HAVE_BUP_LUTIME_NS 1
853 static PyObject *bup_lutime_ns(PyObject *self, PyObject *args)
854 {
855     int rc;
856     char *path;
857     long access, access_ns, modification, modification_ns;
858     struct timeval tv[2];
859
860     if (!bup_parse_xutime_args(&path, &access, &access_ns,
861                                &modification, &modification_ns,
862                                self, args))
863        return NULL;
864
865     tv[0].tv_sec = access;
866     tv[0].tv_usec = access_ns / 1000;
867     tv[1].tv_sec = modification;
868     tv[1].tv_usec = modification_ns / 1000;
869     rc = lutimes(path, tv);
870     if (rc != 0)
871         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
872
873     return Py_BuildValue("O", Py_None);
874 }
875 #endif /* def HAVE_LUTIMES */
876
877
878 #endif /* not defined(HAVE_UTIMENSAT) */
879
880
881 #ifdef HAVE_STAT_ST_ATIM
882 # define BUP_STAT_ATIME_NS(st) (st)->st_atim.tv_nsec
883 # define BUP_STAT_MTIME_NS(st) (st)->st_mtim.tv_nsec
884 # define BUP_STAT_CTIME_NS(st) (st)->st_ctim.tv_nsec
885 #elif defined HAVE_STAT_ST_ATIMENSEC
886 # define BUP_STAT_ATIME_NS(st) (st)->st_atimespec.tv_nsec
887 # define BUP_STAT_MTIME_NS(st) (st)->st_mtimespec.tv_nsec
888 # define BUP_STAT_CTIME_NS(st) (st)->st_ctimespec.tv_nsec
889 #else
890 # define BUP_STAT_ATIME_NS(st) 0
891 # define BUP_STAT_MTIME_NS(st) 0
892 # define BUP_STAT_CTIME_NS(st) 0
893 #endif
894
895
896 static PyObject *stat_struct_to_py(const struct stat *st)
897 {
898     long atime_ns = BUP_STAT_ATIME_NS(st);
899     long mtime_ns = BUP_STAT_MTIME_NS(st);
900     long ctime_ns = BUP_STAT_CTIME_NS(st);
901
902     /* Enforce the current timespec nanosecond range expectations. */
903     if (atime_ns < 0 || atime_ns > 999999999)
904     {
905         PyErr_SetString(PyExc_ValueError, "invalid atime timespec nanoseconds");
906         return NULL;
907     }
908     if (mtime_ns < 0 || mtime_ns > 999999999)
909     {
910         PyErr_SetString(PyExc_ValueError, "invalid mtime timespec nanoseconds");
911         return NULL;
912     }
913     if (ctime_ns < 0 || ctime_ns > 999999999)
914     {
915         PyErr_SetString(PyExc_ValueError, "invalid ctime timespec nanoseconds");
916         return NULL;
917     }
918
919     return Py_BuildValue("kkkkkkkk(Ll)(Ll)(Ll)",
920                          (unsigned long) st->st_mode,
921                          (unsigned long) st->st_ino,
922                          (unsigned long) st->st_dev,
923                          (unsigned long) st->st_nlink,
924                          (unsigned long) st->st_uid,
925                          (unsigned long) st->st_gid,
926                          (unsigned long) st->st_rdev,
927                          (unsigned long) st->st_size,
928                          (long long) st->st_atime,
929                          (long) atime_ns,
930                          (long long) st->st_mtime,
931                          (long) mtime_ns,
932                          (long long) st->st_ctime,
933                          (long) ctime_ns);
934 }
935
936
937 static PyObject *bup_stat(PyObject *self, PyObject *args)
938 {
939     int rc;
940     char *filename;
941
942     if (!PyArg_ParseTuple(args, "s", &filename))
943         return NULL;
944
945     struct stat st;
946     rc = stat(filename, &st);
947     if (rc != 0)
948         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
949     return stat_struct_to_py(&st);
950 }
951
952
953 static PyObject *bup_lstat(PyObject *self, PyObject *args)
954 {
955     int rc;
956     char *filename;
957
958     if (!PyArg_ParseTuple(args, "s", &filename))
959         return NULL;
960
961     struct stat st;
962     rc = lstat(filename, &st);
963     if (rc != 0)
964         return PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
965     return stat_struct_to_py(&st);
966 }
967
968
969 static PyObject *bup_fstat(PyObject *self, PyObject *args)
970 {
971     int rc, fd;
972
973     if (!PyArg_ParseTuple(args, "i", &fd))
974         return NULL;
975
976     struct stat st;
977     rc = fstat(fd, &st);
978     if (rc != 0)
979         return PyErr_SetFromErrno(PyExc_OSError);
980     return stat_struct_to_py(&st);
981 }
982
983
984 static PyMethodDef helper_methods[] = {
985     { "selftest", selftest, METH_VARARGS,
986         "Check that the rolling checksum rolls correctly (for unit tests)." },
987     { "blobbits", blobbits, METH_VARARGS,
988         "Return the number of bits in the rolling checksum." },
989     { "splitbuf", splitbuf, METH_VARARGS,
990         "Split a list of strings based on a rolling checksum." },
991     { "bitmatch", bitmatch, METH_VARARGS,
992         "Count the number of matching prefix bits between two strings." },
993     { "firstword", firstword, METH_VARARGS,
994         "Return an int corresponding to the first 32 bits of buf." },
995     { "bloom_contains", bloom_contains, METH_VARARGS,
996         "Check if a bloom filter of 2^nbits bytes contains an object" },
997     { "bloom_add", bloom_add, METH_VARARGS,
998         "Add an object to a bloom filter of 2^nbits bytes" },
999     { "extract_bits", extract_bits, METH_VARARGS,
1000         "Take the first 'nbits' bits from 'buf' and return them as an int." },
1001     { "merge_into", merge_into, METH_VARARGS,
1002         "Merges a bunch of idx and midx files into a single midx." },
1003     { "write_idx", write_idx, METH_VARARGS,
1004         "Write a PackIdxV2 file from an idx list of lists of tuples" },
1005     { "write_random", write_random, METH_VARARGS,
1006         "Write random bytes to the given file descriptor" },
1007     { "random_sha", random_sha, METH_VARARGS,
1008         "Return a random 20-byte string" },
1009     { "open_noatime", open_noatime, METH_VARARGS,
1010         "open() the given filename for read with O_NOATIME if possible" },
1011     { "fadvise_done", fadvise_done, METH_VARARGS,
1012         "Inform the kernel that we're finished with earlier parts of a file" },
1013 #ifdef BUP_HAVE_FILE_ATTRS
1014     { "get_linux_file_attr", bup_get_linux_file_attr, METH_VARARGS,
1015       "Return the Linux attributes for the given file." },
1016 #endif
1017 #ifdef BUP_HAVE_FILE_ATTRS
1018     { "set_linux_file_attr", bup_set_linux_file_attr, METH_VARARGS,
1019       "Set the Linux attributes for the given file." },
1020 #endif
1021 #ifdef BUP_HAVE_BUP_UTIME_NS
1022     { "bup_utime_ns", bup_utime_ns, METH_VARARGS,
1023       "Change path timestamps with up to nanosecond precision." },
1024 #endif
1025 #ifdef BUP_HAVE_BUP_LUTIME_NS
1026     { "bup_lutime_ns", bup_lutime_ns, METH_VARARGS,
1027       "Change path timestamps with up to nanosecond precision;"
1028       " don't follow symlinks." },
1029 #endif
1030     { "stat", bup_stat, METH_VARARGS,
1031       "Extended version of stat." },
1032     { "lstat", bup_lstat, METH_VARARGS,
1033       "Extended version of lstat." },
1034     { "fstat", bup_fstat, METH_VARARGS,
1035       "Extended version of fstat." },
1036     { NULL, NULL, 0, NULL },  // sentinel
1037 };
1038
1039
1040 PyMODINIT_FUNC init_helpers(void)
1041 {
1042     char *e;
1043     PyObject *m = Py_InitModule("_helpers", helper_methods);
1044     if (m == NULL)
1045         return;
1046     e = getenv("BUP_FORCE_TTY");
1047     istty2 = isatty(2) || (atoi(e ? e : "0") & 2);
1048     unpythonize_argv();
1049 }