Back to index

obnam  1.1
_obnammodule.c
Go to the documentation of this file.
00001 /*
00002  * _obnammodule.c -- Python extensions for Obna
00003  *
00004  * Copyright (C) 2008, 2009  Lars Wirzenius <liw@liw.fi>
00005  * 
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 3 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License along
00017  * with this program; if not, write to the Free Software Foundation, Inc.,
00018  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00019  */
00020 
00021 
00022 /*
00023  * This is a Python extension module written for Obnam, the backup
00024  * software. 
00025  *
00026  * This module provides a way to call the posix_fadvise function from
00027  * Python. Obnam uses this to use set the POSIX_FADV_SEQUENTIAL and
00028  * POSIX_FADV_DONTNEED flags, to make sure the kernel knows that it will
00029  * read files sequentially and that the data does not need to be cached.
00030  * This makes Obnam not trash the disk buffer cache, which is nice.
00031  */
00032 
00033 
00034 #include <Python.h>
00035 
00036 
00037 #ifndef _XOPEN_SOURCE
00038 #define _XOPEN_SOURCE 600
00039 #endif
00040 #define _POSIX_C_SOURCE 200809L
00041 #include <errno.h>
00042 #include <fcntl.h>
00043 #include <stdio.h>
00044 #include <sys/types.h>
00045 #include <sys/stat.h>
00046 #include <sys/xattr.h>
00047 #include <unistd.h>
00048 #include <stdlib.h>
00049 
00050 
00051 static PyObject *
00052 fadvise_dontneed(PyObject *self, PyObject *args)
00053 {
00054 #if POSIX_FADV_DONTNEED
00055     int fd;
00056     /* Can't use off_t for offset and len, since PyArg_ParseTuple
00057        doesn't know it. */
00058     unsigned long long offset;
00059     unsigned long long len;
00060     int ret;
00061 
00062     if (!PyArg_ParseTuple(args, "iLL", &fd, &offset, &len))
00063         return NULL;
00064     ret = posix_fadvise(fd, offset, len, POSIX_FADV_DONTNEED);
00065     return Py_BuildValue("i", ret);
00066 #else
00067     return Py_BuildValue("i", 0);
00068 #endif
00069 }
00070 
00071 
00072 static PyObject *
00073 utimensat_wrapper(PyObject *self, PyObject *args)
00074 {
00075     int ret;
00076     const char *filename;
00077     long atime_sec, atime_nsec;
00078     long mtime_sec, mtime_nsec;
00079     struct timespec tv[2];
00080 
00081     if (!PyArg_ParseTuple(args, "sllll", 
00082                           &filename, 
00083                           &atime_sec,
00084                           &atime_nsec,
00085                           &mtime_sec,
00086                           &mtime_nsec))
00087         return NULL;
00088 
00089     tv[0].tv_sec = atime_sec;
00090     tv[0].tv_nsec = atime_nsec;
00091     tv[1].tv_sec = mtime_sec;
00092     tv[1].tv_nsec = mtime_nsec;
00093     ret = utimensat(AT_FDCWD, filename, tv, AT_SYMLINK_NOFOLLOW);
00094     if (ret == -1)
00095         ret = errno;
00096     return Py_BuildValue("i", ret);
00097 }
00098 
00099 
00100 static PyObject *
00101 lstat_wrapper(PyObject *self, PyObject *args)
00102 {
00103     int ret;
00104     const char *filename;
00105     struct stat st = {0};
00106 
00107     if (!PyArg_ParseTuple(args, "s", &filename))
00108         return NULL;
00109 
00110     ret = lstat(filename, &st);
00111     if (ret == -1)
00112         ret = errno;
00113     return Py_BuildValue("iLLLLLLLLLLLLLLLL", 
00114                          ret,
00115                          (long long) st.st_dev,
00116                          (long long) st.st_ino,
00117                          (long long) st.st_mode,
00118                          (long long) st.st_nlink,
00119                          (long long) st.st_uid,
00120                          (long long) st.st_gid,
00121                          (long long) st.st_rdev,
00122                          (long long) st.st_size,
00123                          (long long) st.st_blksize,
00124                          (long long) st.st_blocks,
00125                          (long long) st.st_atim.tv_sec,
00126                          (long long) st.st_atim.tv_nsec,
00127                          (long long) st.st_mtim.tv_sec,
00128                          (long long) st.st_mtim.tv_nsec,
00129                          (long long) st.st_ctim.tv_sec,
00130                          (long long) st.st_ctim.tv_nsec);
00131 }
00132 
00133 
00134 static PyObject *
00135 llistxattr_wrapper(PyObject *self, PyObject *args)
00136 {
00137     const char *filename;
00138     size_t bufsize;
00139     PyObject *o;
00140 
00141     if (!PyArg_ParseTuple(args, "s", &filename))
00142         return NULL;
00143 
00144     bufsize = 0;
00145     o = NULL;
00146     do {
00147         bufsize += 1024;
00148         char *buf = malloc(bufsize);
00149         ssize_t n = llistxattr(filename, buf, bufsize);
00150 
00151         if (n >= 0)
00152             o = Py_BuildValue("s#", buf, (int) n);
00153         else if (n == -1 && errno != ERANGE)
00154             o = Py_BuildValue("i", errno);
00155         free(buf);
00156     } while (o == NULL);
00157     
00158     return o;
00159 }
00160 
00161 
00162 static PyObject *
00163 lgetxattr_wrapper(PyObject *self, PyObject *args)
00164 {
00165     const char *filename;
00166     const char *attrname;
00167     size_t bufsize;
00168     PyObject *o;
00169 
00170     if (!PyArg_ParseTuple(args, "ss", &filename, &attrname))
00171         return NULL;
00172 
00173     bufsize = 0;
00174     o = NULL;
00175     do {
00176         bufsize += 1024;
00177         char *buf = malloc(bufsize);
00178         ssize_t n = lgetxattr(filename, attrname, buf, bufsize);
00179 
00180         if (n > 0)
00181             o = Py_BuildValue("s#", buf, (int) n);
00182         else if (n == -1 && errno != ERANGE)
00183             o = Py_BuildValue("i", errno);
00184         free(buf);
00185     } while (o == NULL);
00186     
00187     return o;
00188 }
00189 
00190 
00191 static PyObject *
00192 lsetxattr_wrapper(PyObject *self, PyObject *args)
00193 {
00194     const char *filename;
00195     const char *name;
00196     const char *value;
00197     int size;
00198     int ret;
00199 
00200     if (!PyArg_ParseTuple(args, "sss#", &filename, &name, &value, &size))
00201         return NULL;
00202 
00203     ret = lsetxattr(filename, name, value, size, 0);
00204     if (ret == -1)
00205         ret = errno;
00206     return Py_BuildValue("i", ret);
00207 }
00208 
00209 
00210 static PyMethodDef methods[] = {
00211     {"fadvise_dontneed",  fadvise_dontneed, METH_VARARGS, 
00212      "Call posix_fadvise(2) with POSIX_FADV_DONTNEED argument."},
00213     {"utimensat", utimensat_wrapper, METH_VARARGS,
00214      "utimensat(2) wrapper."},
00215     {"lstat", lstat_wrapper, METH_VARARGS,
00216      "lstat(2) wrapper; arg is filename, returns tuple."},
00217     {"llistxattr", llistxattr_wrapper, METH_VARARGS,
00218      "llistxattr(2) wrapper; arg is filename, returns tuple."},
00219     {"lgetxattr", lgetxattr_wrapper, METH_VARARGS,
00220      "lgetxattr(2) wrapper; arg is filename, returns tuple."},
00221     {"lsetxattr", lsetxattr_wrapper, METH_VARARGS,
00222      "lsetxattr(2) wrapper; arg is filename, returns errno."},
00223     {NULL, NULL, 0, NULL}        /* Sentinel */
00224 };
00225 
00226 
00227 PyMODINIT_FUNC
00228 init_obnam(void)
00229 {
00230     (void) Py_InitModule("_obnam", methods);
00231 }