// Documented in header. char *utf8DupFromZstring(zstring string) { zint size = utf8SizeFromZstring(string) + 1; // `+1` for the final `\0`. char *result = utilAlloc(size); utf8FromZstring(size, result, string); return result; }
// Documented in header. char *utilReadLink(const char *path) { struct stat statBuf; if (lstat(path, &statBuf) != 0) { if ((errno == ENOENT) || (errno == ENOTDIR)) { // File not found or invalid component, neither of which are // really errors from the perspective of this function. errno = 0; return NULL; } die("Trouble with `lstat`: %s", strerror(errno)); } else if (!S_ISLNK(statBuf.st_mode)) { // Not a symlink. errno = 0; return NULL; } // If `st_size` is non-zero, then it can safely be used as the size of // the link data. However, on Linux some valid links (particularly, those // in `/proc/`) will have `st_size` reported as `0`. In such cases, we // use an ample but fixed-size buffer, and hope for the best. bool assumeSize = (statBuf.st_size == 0); size_t linkSz = assumeSize ? 500 : statBuf.st_size; char *result = utilAlloc(linkSz + 1); ssize_t resultSz = readlink(path, result, linkSz); if (resultSz < 0) { die("Trouble with `readlink`: %s", strerror(errno)); } else if (assumeSize ? (resultSz > linkSz) : (resultSz != linkSz)) { die("Strange `readlink` result: %d", (zint) resultSz); } result[resultSz] = '\0'; return result; }