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