Pufferüberlauf-sicheres readlink() in C++
Problem:
Du möchtest readlink() verwenden, um die Datei oder das Verzeichnis zu ermitteln, auf das ein symbolischer Link zeigt, aber du kennst nicht die Puffergröße, die zum Speichern des Symlink-Ziels erforderlich ist. Du möchtest keine unglaublich große Speichermenge allozieren (egal welche Menge man wählt, sie könnte immer unzureichend sein), aber du möchtest auch keine Pufferüberläufe riskieren.
Lösung:
readlink() gibt -1 mit errno == EINVAL zurück, wenn der Puffer zu klein ist. Daher kann man readlink einfach iterativ mit zunehmenden Puffergrößen aufrufen.
Diese Implementierung verwendet std::string und gibt im Fehlerfall einen leeren String zurück (errno ist in diesem Fall weiterhin gesetzt). Wenn die Datei kein Symlink ist, wird das Argument filename zurückgegeben.
//Copyright (c) 2013 Uli Köhler
//Lizenz: Apache2.0
#include <unistd.h>
/**
* Ein pufferüberlauf-sicherer readlink()-Wrapper für C++.
* @return Ein String mit dem readlink()-ed Dateinamen, oder
* ein leerer String mit errno, das auf den entsprechenden Fehler gesetzt ist.
* Siehe die readlink() man(2) für errno-Details.
*/
static std::string safeReadlink(const std::string& filename) {
size_t bufferSize = 255;
//Puffergröße erhöhen, bis der Puffer groß genug ist
while (1) {
char* buffer = new char[bufferSize];
size_t rc = readlink (filename.c_str(), buffer, bufferSize);
if (rc == -1) {
delete[] buffer;
if(errno == EINVAL) {
//Wir wissen, dass bufsize positiv ist, also
// ist die Datei kein Symlink.
errno = 0;
return filename;
} else if(errno == ENAMETOOLONG) {
bufferSize += 255;
} else {
//errno enthält noch den Fehlercode
return "";
}
} else {
//Erfolg! rc == Anzahl gültiger Zeichen im Puffer
errno = 0;
return string(buffer, rc);
}
}
}