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