summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog29
-rw-r--r--plugins/pychrysa/common/Makefile.am3
-rw-r--r--plugins/pychrysa/common/fnv1a.c2
-rw-r--r--plugins/pychrysa/common/module.c2
-rw-r--r--plugins/pychrysa/common/pathname.c203
-rw-r--r--plugins/pychrysa/common/pathname.h42
-rwxr-xr-xsrc/common/Makefile.am1
-rw-r--r--src/common/extstr.h2
-rw-r--r--src/common/pathname.c173
-rw-r--r--src/common/pathname.h36
-rw-r--r--tests/common/__init__.py0
-rw-r--r--tests/common/pathname.py95
12 files changed, 585 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 57bbdb9..a06eeaf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+15-12-01 Cyrille Bagard <nocbos@gmail.com>
+
+ * plugins/pychrysa/common/Makefile.am:
+ Add the 'pathname.[ch]' files to libpychrysacommon_la_SOURCES.
+
+ * plugins/pychrysa/common/fnv1a.c:
+ Fix comments.
+
+ * plugins/pychrysa/common/module.c:
+ Update code.
+
+ * plugins/pychrysa/common/pathname.c:
+ * plugins/pychrysa/common/pathname.h:
+ New entries: provide bindings for Python.
+
+ * src/common/Makefile.am:
+ Add the 'pathname.[ch]' files to libcommon_la_SOURCES.
+
+ * src/common/extstr.h:
+ Typo.
+
+ * src/common/pathname.c:
+ * src/common/pathname.h:
+ New entries: compute relative and absolute paths.
+
+ * tests/common/__init__.py:
+ * tests/common/pathname.py:
+ New entries: define some new relative test cases.
+
15-11-29 Cyrille Bagard <nocbos@gmail.com>
* configure.ac:
diff --git a/plugins/pychrysa/common/Makefile.am b/plugins/pychrysa/common/Makefile.am
index 38d1697..93d92ac 100644
--- a/plugins/pychrysa/common/Makefile.am
+++ b/plugins/pychrysa/common/Makefile.am
@@ -3,7 +3,8 @@ noinst_LTLIBRARIES = libpychrysacommon.la
libpychrysacommon_la_SOURCES = \
fnv1a.h fnv1a.c \
- module.h module.c
+ module.h module.c \
+ pathname.h pathname.c
libpychrysacommon_la_LDFLAGS =
diff --git a/plugins/pychrysa/common/fnv1a.c b/plugins/pychrysa/common/fnv1a.c
index 2befcbe..99d06fc 100644
--- a/plugins/pychrysa/common/fnv1a.c
+++ b/plugins/pychrysa/common/fnv1a.c
@@ -40,7 +40,7 @@ static PyObject *py_fnv1a_hash(PyObject *, PyObject *);
/******************************************************************************
* *
* Paramètres : self = NULL car méthode statique. *
-* args = non utilisé ici. *
+* args = arguments fournis lors de l'appel à la fonction. *
* *
* Description : Détermine l'empreinte FNV1a d'une chaîne de caractères. *
* *
diff --git a/plugins/pychrysa/common/module.c b/plugins/pychrysa/common/module.c
index bb4d47f..21781b5 100644
--- a/plugins/pychrysa/common/module.c
+++ b/plugins/pychrysa/common/module.c
@@ -26,6 +26,7 @@
#include "fnv1a.h"
+#include "pathname.h"
@@ -76,6 +77,7 @@ bool add_common_module_to_python_module(PyObject *super)
result = true;
result &= register_python_fnv1a(module);
+ result &= register_python_pathname(module);
acmtpm_exit:
diff --git a/plugins/pychrysa/common/pathname.c b/plugins/pychrysa/common/pathname.c
new file mode 100644
index 0000000..4b36675
--- /dev/null
+++ b/plugins/pychrysa/common/pathname.c
@@ -0,0 +1,203 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pathname.c - équivalent Python du fichier "common/pathname.c"
+ *
+ * Copyright (C) 2015 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * OpenIDA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenIDA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "pathname.h"
+
+
+#include <malloc.h>
+#include <pygobject.h>
+
+
+#include <i18n.h>
+
+
+#include <common/pathname.h>
+
+
+
+/* Calcule le chemin relatif entre deux fichiers donnés. */
+static PyObject *py_build_relative_filename(PyObject *, PyObject *);
+
+/* Calcule le chemin absolu d'un fichier par rapport à un autre. */
+static PyObject *py_build_absolute_filename(PyObject *, PyObject *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = NULL car méthode statique. *
+* args = arguments fournis lors de l'appel à la fonction. *
+* *
+* Description : Calcule le chemin relatif entre deux fichiers donnés. *
+* *
+* Retour : Chemin relatif obtenu. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_build_relative_filename(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Instance à retourner */
+ const char *ref; /* Fichier de référence */
+ const char *target; /* Fichier à cibler */
+ int ret; /* Bilan de lecture des args. */
+ char *relative; /* Chemin d'accès construit */
+
+ ret = PyArg_ParseTuple(args, "ss", &ref, &target);
+ if (!ret) Py_RETURN_NONE;
+
+ relative = build_relative_filename(ref, target);
+
+ result = PyUnicode_FromString(relative);
+
+ free(relative);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = NULL car méthode statique. *
+* args = arguments fournis lors de l'appel à la fonction. *
+* *
+* Description : Calcule le chemin absolu d'un fichier par rapport à un autre.*
+* *
+* Retour : Chemin absolu obtenu. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_build_absolute_filename(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Instance à retourner */
+ const char *ref; /* Fichier de référence */
+ const char *target; /* Fichier à cibler */
+ int ret; /* Bilan de lecture des args. */
+ char *relative; /* Chemin d'accès construit */
+
+ ret = PyArg_ParseTuple(args, "ss", &ref, &target);
+ if (!ret) Py_RETURN_NONE;
+
+ relative = build_absolute_filename(ref, target);
+
+ if (relative == NULL)
+ {
+ PyErr_SetString(PyExc_ValueError, _("Relative path is too deep."));
+ result = NULL;
+ }
+ else
+ {
+ result = PyUnicode_FromString(relative);
+
+ free(relative);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_pathname_type(void)
+{
+ static PyMethodDef py_pathname_methods[] = {
+
+ { "build_relative_filename", py_build_relative_filename,
+ METH_VARARGS | METH_STATIC,
+ "build_relative_filename(ref, target, /)\n--\n\nCompute the relative path between two files."
+ },
+ { "build_absolute_filename", py_build_absolute_filename,
+ METH_VARARGS | METH_STATIC,
+ "build_absolute_filename(ref, target, /)\n--\n\nCompute the absolute path for a file."
+ },
+ { NULL }
+
+ };
+
+ static PyTypeObject py_pathname_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.core.pathname",
+ .tp_basicsize = sizeof(PyObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT,
+
+ .tp_doc = "Path manipulations in Python for Chrysalide.",
+
+ .tp_methods = py_pathname_methods
+
+ };
+
+ return &py_pathname_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : module = module dont la définition est à compléter. *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.core.pathname'. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool register_python_pathname(PyObject *module)
+{
+ PyTypeObject *py_pathname_type; /* Type Python pour 'pathname' */
+ int ret; /* Bilan d'un appel */
+
+ py_pathname_type = get_python_pathname_type();
+
+ //py_pathname_type->tp_new = PyType_GenericNew;
+
+ if (PyType_Ready(py_pathname_type) != 0)
+ return false;
+
+ Py_INCREF(py_pathname_type);
+ ret = PyModule_AddObject(module, "pathname", (PyObject *)py_pathname_type);
+
+ return (ret == 0);
+
+}
diff --git a/plugins/pychrysa/common/pathname.h b/plugins/pychrysa/common/pathname.h
new file mode 100644
index 0000000..fe9bc1b
--- /dev/null
+++ b/plugins/pychrysa/common/pathname.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pathname.h - prototypes pour l'équivalent Python du fichier "common/pathname.c"
+ *
+ * Copyright (C) 2015 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * OpenIDA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenIDA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_COMMON_PATHNAME_H
+#define _PLUGINS_PYCHRYSALIDE_COMMON_PATHNAME_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_pathname_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.common.pathname'. */
+bool register_python_pathname(PyObject *);
+
+
+
+#endif /* _PLUGINS_PYCHRYSALIDE_COMMON_PATHNAME_H */
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 7a35813..4c9c2a1 100755
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -15,6 +15,7 @@ libcommon_la_SOURCES = \
leb128.h leb128.c \
macros.h \
net.h net.c \
+ pathname.h pathname.c \
sqlite.h sqlite.c \
xdg.h xdg.c \
xml.h xml.c
diff --git a/src/common/extstr.h b/src/common/extstr.h
index b8bd225..6542d2f 100644
--- a/src/common/extstr.h
+++ b/src/common/extstr.h
@@ -30,7 +30,7 @@
/* Complète une chaîne de caractères avec une autre. */
-char *stradd(char *str1, const char *str2);
+char *stradd(char *, const char *);
/* Complète une chaîne de caractères avec une autre. */
char *strnadd(char *, const char *, size_t);
diff --git a/src/common/pathname.c b/src/common/pathname.c
new file mode 100644
index 0000000..181fd1f
--- /dev/null
+++ b/src/common/pathname.c
@@ -0,0 +1,173 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pathname.c - manipulation de chemins de fichiers
+ *
+ * Copyright (C) 2015 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * OpenIDA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenIDA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "pathname.h"
+
+
+#include <assert.h>
+#include <glib.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include "extstr.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : ref = fichier servant de référence aux calculs. *
+* target = fichier absolu ciblé par la procédure. *
+* *
+* Description : Calcule le chemin relatif entre deux fichiers donnés. *
+* *
+* Retour : Chemin d'accès déterminé. *
+* *
+* Remarques : Les chemins de type 'a//b' ne sont pas supportés. *
+* *
+******************************************************************************/
+
+char *build_relative_filename(const char *ref, const char *target)
+{
+ char *result; /* Chemin à retourner */
+ size_t common; /* Taille de la partie commune */
+ const char *found; /* Séparateur suivant rencontré*/
+ size_t ref_next; /* Prochain séparateur #1 */
+ size_t target_next; /* Prochain séparateur #2 */
+ int ret; /* Bilan d'un appel */
+ unsigned int levels; /* Niveaux de décalage */
+ unsigned int i; /* Boucle de parcours #1 */
+
+ common = 0;
+
+ /* Recherche d'une base commune */
+
+ while (1)
+ {
+ found = strchr(ref + common, G_DIR_SEPARATOR);
+ if (found == NULL) break;
+
+ ref_next = found - ref;
+
+ found = strchr(target + common, G_DIR_SEPARATOR);
+ if (found == NULL) break;
+
+ target_next = found - target;
+
+ /* Comparaison rapide sur la longeur du nom */
+ if (ref_next != target_next) break;
+
+ /* Comparaison sur une portion de chemin */
+ ret = strncmp(ref + common, target + common, ref_next - common);
+ if (ret != 0) break;
+
+ common = ref_next + 1;
+
+ }
+
+ /* Décompte du décalage entre la référence et la cible */
+
+ found = ref + common;
+
+ for (levels = 0; ; levels++)
+ {
+ found = strchr(found, G_DIR_SEPARATOR);
+ if (found == NULL) break;
+
+ found++;
+
+ }
+
+ /* Construction du résultat final */
+
+ result = strdup(target + common);
+
+ for (i = 0; i < levels; i++)
+ {
+ result = strprep(result, G_DIR_SEPARATOR_S);
+ result = strprep(result, "..");
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : ref = fichier servant de référence aux calculs. *
+* target = fichier relatif ciblé par la procédure. *
+* *
+* Description : Calcule le chemin absolu d'un fichier par rapport à un autre.*
+* *
+* Retour : Chemin d'accès déterminé ou NULL en cas d'erreur. *
+* *
+* Remarques : Les chemins de type 'a//b' ne sont pas supportés. *
+* *
+******************************************************************************/
+
+char *build_absolute_filename(const char *ref, const char *target)
+{
+ char *result; /* Chemin à retourner */
+ char *last_sep; /* Dernier séparateur trouvé */
+ const char *target_base; /* Base de la relativité */
+
+ static const char upper[4] = { '.', '.', G_DIR_SEPARATOR, '\0' };
+
+ result = strdup(ref);
+
+ last_sep = strrchr(result, G_DIR_SEPARATOR);
+ assert(last_sep != NULL);
+
+ target_base = target;
+
+ /* Remontée des répertoires */
+ while (1)
+ {
+ if (strncmp(target_base, upper, 3) != 0)
+ break;
+
+ target_base += 3;
+
+ *last_sep = '\0';
+ last_sep = strrchr(result, G_DIR_SEPARATOR);
+
+ /* S'il devient impossible de remonter autant... */
+ if (last_sep == NULL) break;
+
+ }
+
+ if (last_sep == NULL)
+ {
+ free(result);
+ result = NULL;
+ }
+ else
+ {
+ *(last_sep + 1) = '\0';
+ result = stradd(result, target_base);
+ }
+
+ return result;
+
+}
diff --git a/src/common/pathname.h b/src/common/pathname.h
new file mode 100644
index 0000000..744a11b
--- /dev/null
+++ b/src/common/pathname.h
@@ -0,0 +1,36 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pathname.h - prototypes pour la manipulation de chemins de fichiers
+ *
+ * Copyright (C) 2015 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * OpenIDA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenIDA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _COMMON_PATHNAME_H
+#define _COMMON_PATHNAME_H
+
+
+/* Calcule le chemin relatif entre deux fichiers donnés. */
+char *build_relative_filename(const char *, const char *);
+
+/* Calcule le chemin absolu d'un fichier par rapport à un autre. */
+char *build_absolute_filename(const char *, const char *);
+
+
+
+#endif /* _COMMON_PATHNAME_H */
diff --git a/tests/common/__init__.py b/tests/common/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/common/__init__.py
diff --git a/tests/common/pathname.py b/tests/common/pathname.py
new file mode 100644
index 0000000..5cd238c
--- /dev/null
+++ b/tests/common/pathname.py
@@ -0,0 +1,95 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+
+# Tests minimalistes pour valider la construction de chemins relatifs et absolus.
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.common import pathname
+
+
+class TestRestrictedContent(ChrysalideTestCase):
+ """TestCase for common.pathname.build*"""
+
+ @classmethod
+ def setUpClass(cls):
+
+ super(TestRestrictedContent, cls).setUpClass()
+
+ cls._tests = [
+ {
+ 'ref' : '/a/b/d',
+ 'target' : '/a/b/e/f',
+ 'relative' : 'e/f'
+ },
+ {
+ 'ref' : '/a/b/c/d',
+ 'target' : '/a/b/f',
+ 'relative' : '../f'
+ },
+ {
+ 'ref' : '/a/b/c/d',
+ 'target' : '/a/b/c/e',
+ 'relative' : 'e'
+ },
+ {
+ 'ref' : '/a/bb/c/d',
+ 'target' : '/a/b/e/f',
+ 'relative' : '../../b/e/f'
+ },
+ {
+ 'ref' : '/a/b/c/d',
+ 'target' : '/a/bb/e/f',
+ 'relative' : '../../bb/e/f'
+ },
+ {
+ 'ref' : '/a/b/c/d',
+ 'target' : '/f',
+ 'relative' : '../../../f'
+ },
+ {
+ 'ref' : '/z/b/c/d',
+ 'target' : '/a/b/e/f',
+ 'relative' : '../../../a/b/e/f'
+ },
+ {
+ 'ref' : '/a/bbb/c/d',
+ 'target' : '/a/bbc/e/f',
+ 'relative' : '../../bbc/e/f'
+ }
+ ]
+
+
+ def testBuildingRelative(self):
+ """Build valid relative paths."""
+
+ build_relative = pathname.build_relative_filename
+
+ for tst in self._tests:
+
+ got = build_relative(tst['ref'], tst['target'])
+
+ self.assertEqual(got, tst['relative'])
+
+
+ def testBuildingAbsolute(self):
+ """Build valid absolute paths."""
+
+ build_absolute = pathname.build_absolute_filename
+
+ for tst in self._tests:
+
+ got = build_absolute(tst['ref'], tst['relative'])
+
+ self.assertEqual(got, tst['target'])
+
+
+ def testBuildingWrongAbsolute(self):
+ """Build invalid absolute paths."""
+
+ build_absolute = pathname.build_absolute_filename
+
+ with self.assertRaisesRegex(Exception, 'Relative path is too deep.'):
+
+ got = build_absolute('/a/b', '../../c')