[libvirt] [PATCH] Create file in virFileWriteStr() if it doesn't exist

This patch adds a virFileWriteStrEx() function with a third parameter to set the created file permissions. virFileWriteStr() calls this new function with a default value for the mode parameter. --- src/util/util.c | 11 ++++++++--- src/util/util.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/util/util.c b/src/util/util.c index a2582aa..82ca9b3 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -1123,14 +1123,19 @@ int virFileReadAll(const char *path, int maxlen, char **buf) return len; } -/* Truncate @path and write @str to it. +int virFileWriteStr(const char *path, const char *str) +{ + return virFileWriteStrEx(path, str, S_IRUSR|S_IWUSR); +} + +/* Truncate or create @path and write @str to it. Return 0 for success, nonzero for failure. Be careful to preserve any errno value upon failure. */ -int virFileWriteStr(const char *path, const char *str) +int virFileWriteStrEx(const char *path, const char *str, mode_t mode) { int fd; - if ((fd = open(path, O_WRONLY|O_TRUNC)) == -1) + if ((fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, mode)) == -1) return -1; if (safewrite(fd, str, strlen(str)) < 0) { diff --git a/src/util/util.h b/src/util/util.h index a240d87..18ef693 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -96,6 +96,7 @@ int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; +int virFileWriteStrEx(const char *path, const char *str, mode_t mode) ATTRIBUTE_RETURN_CHECK; int virFileWriteStr(const char *path, const char *str) ATTRIBUTE_RETURN_CHECK; int virFileMatchesNameSuffix(const char *file, -- 1.7.0.4

On 12/02/2010 06:23 AM, Jean-Baptiste Rouault wrote:
This patch adds a virFileWriteStrEx() function with a third parameter to set the created file permissions.
I'm not a fan of Microsoft's naming conventions (Ex conveys no meaning, and it doesn't scale well to future extensions[1]). Can we come up with a better name, such as virFileWriteStrCreate? [1] http://blogs.msdn.com/b/michkap/archive/2006/01/31/520694.aspx Alternatively, I only counted 16 existing users of virFileWriteStr; and this is an internal API. We could easily rewrite all clients to always pass a third parameter, and change the signature of virFileWriteStr to require a mode_t argument. Hmm; some of those clients are writing to kernel files that should always exist (/proc/sys/net/ipv4/ip_forward, for example), where it's tough to justify what we would pass as a mode_t argument. So maybe pass mode==0 as a sentinel to require a pre-existing file (that is, even though open(,O_CREAT,0) is a valid syscall, it seldom makes sense, since the resulting created file cannot be re-read once closed): int virFileWriteStr(const char *path, const char *str, mode_t mode) { int fd; if (mode == 0) fd = open(path, O_WRONLY|O_TRUNC); else fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode); if (fd == -1) ... -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

Making this change will allow the future patches to use virFileWriteStr to create a file, rather than its current limitation of only working on pre-existing files. * src/util/util.h (virFileWriteStr): Alter signature. * src/util/util.c (virFileWriteStr): Allow file creation. * src/network/bridge_driver.c (networkEnableIpForwarding) (networkDisableIPV6): Adjust clients. * src/node_device/node_device_driver.c (nodeDeviceVportCreateDelete): Likewise. * src/util/cgroup.c (virCgroupSetValueStr): Likewise. * src/util/pci.c (pciBindDeviceToStub, pciUnBindDeviceFromStub): Likewise. Based on a report from Jean-Baptiste Rouault. ---
Alternatively, I only counted 16 existing users of virFileWriteStr; and this is an internal API. We could easily rewrite all clients to always pass a third parameter, and change the signature of virFileWriteStr to require a mode_t argument. Hmm; some of those clients are writing to kernel files that should always exist (/proc/sys/net/ipv4/ip_forward, for example), where it's tough to justify what we would pass as a mode_t argument. So maybe pass mode==0 as a sentinel to require a pre-existing file
How does this look? Admittedly, all existing uses were okay with a mode parameter of 0; and I haven't yet seen your patch that would use a non-zero mode, but this still makes more sense to me. Oh, and VIR_FORCE_CLOSE preserves errno, so I was able to simplify virFileWriteStr in the process. src/network/bridge_driver.c | 8 ++++---- src/node_device/node_device_driver.c | 2 +- src/util/cgroup.c | 2 +- src/util/pci.c | 16 ++++++++-------- src/util/util.c | 13 ++++++++----- src/util/util.h | 3 ++- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 54890f9..62639e4 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1024,7 +1024,7 @@ networkReloadIptablesRules(struct network_driver *driver) static int networkEnableIpForwarding(void) { - return virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n"); + return virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n", 0); } #define SYSCTL_PATH "/proc/sys" @@ -1045,7 +1045,7 @@ static int networkDisableIPV6(virNetworkObjPtr network) goto cleanup; } - if (virFileWriteStr(field, "1") < 0) { + if (virFileWriteStr(field, "1", 0) < 0) { virReportSystemError(errno, _("cannot enable %s"), field); goto cleanup; @@ -1057,7 +1057,7 @@ static int networkDisableIPV6(virNetworkObjPtr network) goto cleanup; } - if (virFileWriteStr(field, "0") < 0) { + if (virFileWriteStr(field, "0", 0) < 0) { virReportSystemError(errno, _("cannot disable %s"), field); goto cleanup; @@ -1069,7 +1069,7 @@ static int networkDisableIPV6(virNetworkObjPtr network) goto cleanup; } - if (virFileWriteStr(field, "1") < 0) { + if (virFileWriteStr(field, "1", 0) < 0) { virReportSystemError(errno, _("cannot enable %s"), field); goto cleanup; diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 448cfd3..a6c6042 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -454,7 +454,7 @@ nodeDeviceVportCreateDelete(const int parent_host, goto cleanup; } - if (virFileWriteStr(operation_path, vport_name) == -1) { + if (virFileWriteStr(operation_path, vport_name, 0) == -1) { virReportSystemError(errno, _("Write of '%s' to '%s' during " "vport create/delete failed"), diff --git a/src/util/cgroup.c b/src/util/cgroup.c index 2758a8f..3ba6325 100644 --- a/src/util/cgroup.c +++ b/src/util/cgroup.c @@ -288,7 +288,7 @@ static int virCgroupSetValueStr(virCgroupPtr group, return rc; VIR_DEBUG("Set value '%s' to '%s'", keypath, value); - rc = virFileWriteStr(keypath, value); + rc = virFileWriteStr(keypath, value, 0); if (rc < 0) { DEBUG("Failed to write value '%s': %m", value); rc = -errno; diff --git a/src/util/pci.c b/src/util/pci.c index d38cefa..095ad3f 100644 --- a/src/util/pci.c +++ b/src/util/pci.c @@ -849,7 +849,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) * bound by the stub. */ pciDriverFile(path, sizeof(path), driver, "new_id"); - if (virFileWriteStr(path, dev->id) < 0) { + if (virFileWriteStr(path, dev->id, 0) < 0) { virReportSystemError(errno, _("Failed to add PCI device ID '%s' to %s"), dev->id, driver); @@ -862,7 +862,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) * your root filesystem. */ pciDeviceFile(path, sizeof(path), dev->name, "driver/unbind"); - if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) { + if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to unbind PCI device '%s'"), dev->name); return -1; @@ -875,7 +875,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) if (!virFileLinkPointsTo(path, drvdir)) { /* Xen's pciback.ko wants you to use new_slot first */ pciDriverFile(path, sizeof(path), driver, "new_slot"); - if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) { + if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to add slot for PCI device '%s' to %s"), dev->name, driver); @@ -883,7 +883,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) } pciDriverFile(path, sizeof(path), driver, "bind"); - if (virFileWriteStr(path, dev->name) < 0) { + if (virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to bind PCI device '%s' to %s"), dev->name, driver); @@ -895,7 +895,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) * ID table so that 'drivers_probe' works below. */ pciDriverFile(path, sizeof(path), driver, "remove_id"); - if (virFileExists(path) && virFileWriteStr(path, dev->id) < 0) { + if (virFileExists(path) && virFileWriteStr(path, dev->id, 0) < 0) { virReportSystemError(errno, _("Failed to remove PCI ID '%s' from %s"), dev->id, driver); @@ -936,7 +936,7 @@ pciUnBindDeviceFromStub(pciDevice *dev, const char *driver) pciDeviceFile(path, sizeof(path), dev->name, "driver"); if (virFileExists(drvdir) && virFileLinkPointsTo(path, drvdir)) { pciDriverFile(path, sizeof(path), driver, "unbind"); - if (virFileWriteStr(path, dev->name) < 0) { + if (virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to bind PCI device '%s' to %s"), dev->name, driver); @@ -946,7 +946,7 @@ pciUnBindDeviceFromStub(pciDevice *dev, const char *driver) /* Xen's pciback.ko wants you to use remove_slot on the specific device */ pciDriverFile(path, sizeof(path), driver, "remove_slot"); - if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) { + if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to remove slot for PCI device '%s' to %s"), dev->name, driver); @@ -961,7 +961,7 @@ pciUnBindDeviceFromStub(pciDevice *dev, const char *driver) */ pciDriverFile(path, sizeof(path), driver, "remove_id"); if (!virFileExists(drvdir) || virFileExists(path)) { - if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name) < 0) { + if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to trigger a re-probe for PCI device '%s'"), dev->name); diff --git a/src/util/util.c b/src/util/util.c index f6050de..79ca5d3 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -1125,20 +1125,23 @@ int virFileReadAll(const char *path, int maxlen, char **buf) return len; } -/* Truncate @path and write @str to it. +/* Truncate @path and write @str to it. If @mode is 0, ensure that + @path exists; otherwise, use @mode if @path must be created. Return 0 for success, nonzero for failure. Be careful to preserve any errno value upon failure. */ -int virFileWriteStr(const char *path, const char *str) +int virFileWriteStr(const char *path, const char *str, mode_t mode) { int fd; - if ((fd = open(path, O_WRONLY|O_TRUNC)) == -1) + if (mode) + fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, mode); + else + fd = open(path, O_WRONLY|O_TRUNC); + if (fd == -1) return -1; if (safewrite(fd, str, strlen(str)) < 0) { - int saved_errno = errno; VIR_FORCE_CLOSE(fd); - errno = saved_errno; return -1; } diff --git a/src/util/util.h b/src/util/util.h index deaf8bb..ef4fc13 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -97,7 +97,8 @@ int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; -int virFileWriteStr(const char *path, const char *str) ATTRIBUTE_RETURN_CHECK; +int virFileWriteStr(const char *path, const char *str, mode_t mode) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; int virFileMatchesNameSuffix(const char *file, const char *name, -- 1.7.3.2

2010/12/3 Eric Blake <eblake@redhat.com>:
Making this change will allow the future patches to use virFileWriteStr to create a file, rather than its current limitation of only working on pre-existing files.
* src/util/util.h (virFileWriteStr): Alter signature. * src/util/util.c (virFileWriteStr): Allow file creation. * src/network/bridge_driver.c (networkEnableIpForwarding) (networkDisableIPV6): Adjust clients. * src/node_device/node_device_driver.c (nodeDeviceVportCreateDelete): Likewise. * src/util/cgroup.c (virCgroupSetValueStr): Likewise. * src/util/pci.c (pciBindDeviceToStub, pciUnBindDeviceFromStub): Likewise. Based on a report from Jean-Baptiste Rouault. ---
Alternatively, I only counted 16 existing users of virFileWriteStr; and this is an internal API. We could easily rewrite all clients to always pass a third parameter, and change the signature of virFileWriteStr to require a mode_t argument. Hmm; some of those clients are writing to kernel files that should always exist (/proc/sys/net/ipv4/ip_forward, for example), where it's tough to justify what we would pass as a mode_t argument. So maybe pass mode==0 as a sentinel to require a pre-existing file
How does this look? Admittedly, all existing uses were okay with a mode parameter of 0; and I haven't yet seen your patch that would use a non-zero mode, but this still makes more sense to me.
Oh, and VIR_FORCE_CLOSE preserves errno, so I was able to simplify virFileWriteStr in the process.
src/network/bridge_driver.c | 8 ++++---- src/node_device/node_device_driver.c | 2 +- src/util/cgroup.c | 2 +- src/util/pci.c | 16 ++++++++-------- src/util/util.c | 13 ++++++++----- src/util/util.h | 3 ++- 6 files changed, 24 insertions(+), 20 deletions(-)
ACK. Matthias

This patch adds a mode_t parameter to virFileWriteStr(). If mode is different from 0, virFileWriteStr() will try to create the file if it doesn't exist. --- src/network/bridge_driver.c | 8 ++++---- src/node_device/node_device_driver.c | 2 +- src/util/cgroup.c | 2 +- src/util/pci.c | 16 ++++++++-------- src/util/util.c | 11 ++++++++--- src/util/util.h | 2 +- 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 54890f9..62639e4 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1024,7 +1024,7 @@ networkReloadIptablesRules(struct network_driver *driver) static int networkEnableIpForwarding(void) { - return virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n"); + return virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n", 0); } #define SYSCTL_PATH "/proc/sys" @@ -1045,7 +1045,7 @@ static int networkDisableIPV6(virNetworkObjPtr network) goto cleanup; } - if (virFileWriteStr(field, "1") < 0) { + if (virFileWriteStr(field, "1", 0) < 0) { virReportSystemError(errno, _("cannot enable %s"), field); goto cleanup; @@ -1057,7 +1057,7 @@ static int networkDisableIPV6(virNetworkObjPtr network) goto cleanup; } - if (virFileWriteStr(field, "0") < 0) { + if (virFileWriteStr(field, "0", 0) < 0) { virReportSystemError(errno, _("cannot disable %s"), field); goto cleanup; @@ -1069,7 +1069,7 @@ static int networkDisableIPV6(virNetworkObjPtr network) goto cleanup; } - if (virFileWriteStr(field, "1") < 0) { + if (virFileWriteStr(field, "1", 0) < 0) { virReportSystemError(errno, _("cannot enable %s"), field); goto cleanup; diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 448cfd3..a6c6042 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -454,7 +454,7 @@ nodeDeviceVportCreateDelete(const int parent_host, goto cleanup; } - if (virFileWriteStr(operation_path, vport_name) == -1) { + if (virFileWriteStr(operation_path, vport_name, 0) == -1) { virReportSystemError(errno, _("Write of '%s' to '%s' during " "vport create/delete failed"), diff --git a/src/util/cgroup.c b/src/util/cgroup.c index 2758a8f..3ba6325 100644 --- a/src/util/cgroup.c +++ b/src/util/cgroup.c @@ -288,7 +288,7 @@ static int virCgroupSetValueStr(virCgroupPtr group, return rc; VIR_DEBUG("Set value '%s' to '%s'", keypath, value); - rc = virFileWriteStr(keypath, value); + rc = virFileWriteStr(keypath, value, 0); if (rc < 0) { DEBUG("Failed to write value '%s': %m", value); rc = -errno; diff --git a/src/util/pci.c b/src/util/pci.c index d38cefa..095ad3f 100644 --- a/src/util/pci.c +++ b/src/util/pci.c @@ -849,7 +849,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) * bound by the stub. */ pciDriverFile(path, sizeof(path), driver, "new_id"); - if (virFileWriteStr(path, dev->id) < 0) { + if (virFileWriteStr(path, dev->id, 0) < 0) { virReportSystemError(errno, _("Failed to add PCI device ID '%s' to %s"), dev->id, driver); @@ -862,7 +862,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) * your root filesystem. */ pciDeviceFile(path, sizeof(path), dev->name, "driver/unbind"); - if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) { + if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to unbind PCI device '%s'"), dev->name); return -1; @@ -875,7 +875,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) if (!virFileLinkPointsTo(path, drvdir)) { /* Xen's pciback.ko wants you to use new_slot first */ pciDriverFile(path, sizeof(path), driver, "new_slot"); - if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) { + if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to add slot for PCI device '%s' to %s"), dev->name, driver); @@ -883,7 +883,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) } pciDriverFile(path, sizeof(path), driver, "bind"); - if (virFileWriteStr(path, dev->name) < 0) { + if (virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to bind PCI device '%s' to %s"), dev->name, driver); @@ -895,7 +895,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) * ID table so that 'drivers_probe' works below. */ pciDriverFile(path, sizeof(path), driver, "remove_id"); - if (virFileExists(path) && virFileWriteStr(path, dev->id) < 0) { + if (virFileExists(path) && virFileWriteStr(path, dev->id, 0) < 0) { virReportSystemError(errno, _("Failed to remove PCI ID '%s' from %s"), dev->id, driver); @@ -936,7 +936,7 @@ pciUnBindDeviceFromStub(pciDevice *dev, const char *driver) pciDeviceFile(path, sizeof(path), dev->name, "driver"); if (virFileExists(drvdir) && virFileLinkPointsTo(path, drvdir)) { pciDriverFile(path, sizeof(path), driver, "unbind"); - if (virFileWriteStr(path, dev->name) < 0) { + if (virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to bind PCI device '%s' to %s"), dev->name, driver); @@ -946,7 +946,7 @@ pciUnBindDeviceFromStub(pciDevice *dev, const char *driver) /* Xen's pciback.ko wants you to use remove_slot on the specific device */ pciDriverFile(path, sizeof(path), driver, "remove_slot"); - if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) { + if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to remove slot for PCI device '%s' to %s"), dev->name, driver); @@ -961,7 +961,7 @@ pciUnBindDeviceFromStub(pciDevice *dev, const char *driver) */ pciDriverFile(path, sizeof(path), driver, "remove_id"); if (!virFileExists(drvdir) || virFileExists(path)) { - if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name) < 0) { + if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to trigger a re-probe for PCI device '%s'"), dev->name); diff --git a/src/util/util.c b/src/util/util.c index f6050de..09f4da6 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -1125,14 +1125,19 @@ int virFileReadAll(const char *path, int maxlen, char **buf) return len; } -/* Truncate @path and write @str to it. +/* Truncate or create @path and write @str to it. Return 0 for success, nonzero for failure. Be careful to preserve any errno value upon failure. */ -int virFileWriteStr(const char *path, const char *str) +int virFileWriteStr(const char *path, const char *str, mode_t mode) { int fd; - if ((fd = open(path, O_WRONLY|O_TRUNC)) == -1) + if (mode == 0) + fd = open(path, O_WRONLY|O_TRUNC); + else + fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, mode); + + if (fd == -1) return -1; if (safewrite(fd, str, strlen(str)) < 0) { diff --git a/src/util/util.h b/src/util/util.h index deaf8bb..90e45cb 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -97,7 +97,7 @@ int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; -int virFileWriteStr(const char *path, const char *str) ATTRIBUTE_RETURN_CHECK; +int virFileWriteStr(const char *path, const char *str, mode_t mode) ATTRIBUTE_RETURN_CHECK; int virFileMatchesNameSuffix(const char *file, const char *name, -- 1.7.0.4

Forget that patch, I didn't receive it by email yet and I saw Eric patch on the list archive after sending it... Regards, -- Jean-Baptiste ROUAULT Ingénieur R&D - Diateam : Architectes de l'information Phone : +33 (0)9 53 16 02 70 Fax : +33 (0)2 98 050 051

On 12/03/2010 02:58 AM, Jean-Baptiste Rouault wrote:
Forget that patch, I didn't receive it by email yet and I saw Eric patch on the list archive after sending it...
Seeing as how your patch is practically identical to mine, I'm taking that as an ACK, and pushing in your name. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org
participants (3)
-
Eric Blake
-
Jean-Baptiste Rouault
-
Matthias Bolte