How to use readlink with dynamic memory allocation

Problem:

On linux machine, I want to read the link target line. From the documentation, I found the following code example (without error handling):

struct stat sb; ssize_t r; char * linkname; lstat("<some link>", &sb); linkname = malloc(sb.st_size + 1); r = readlink("/proc/self/exe", linkname, sb.st_size + 1); 

The problem is that sb.st_size returns 0 for links on my system.

So, how to allocate memory dynamically for readline on such systems?

Many thanks!


One possible solution:

In future. Using the points made by jilles:

 struct stat sb; ssize_t r = INT_MAX; int linkSize = 0; const int growthRate = 255; char * linkTarget = NULL; // get length of the pathname the link points to if (lstat("/proc/self/exe", &sb) == -1) { // could not lstat: insufficient permissions on directory? perror("lstat"); return; } // read the link target into a string linkSize = sb.st_size + 1 - growthRate; while (r >= linkSize) { // ie symlink increased in size since lstat() or non-POSIX compliant filesystem // allocate sufficient memory to hold the link linkSize += growthRate; free(linkTarget); linkTarget = malloc(linkSize); if (linkTarget == NULL) { // insufficient memory fprintf(stderr, "setProcessName(): insufficient memory\n"); return; } // read the link target into variable linkTarget r = readlink("/proc/self/exe", linkTarget, linkSize); if (r < 0) { // readlink failed: link was deleted? perror("lstat"); return; } } linkTarget[r] = '\0'; // readlink does not null-terminate the string 
+4
source share
6 answers

POSIX says that the st_size field for a symbolic link should be set to the path length in the link (without '\0' ). However, the /proc file system on Linux is not POSIX compatible. (It has more violations than just this, for example, when reading certain files one byte at a time.)

You can allocate a buffer of a certain size, try readlink() and try again with a large buffer if the buffer is not large enough ( readlink() returns as many bytes as it fits in the buffer) until the buffer is large enough.

Alternatively, you can use PATH_MAX and cancel portability on systems where it is not a compile-time constant or where the path may be longer than (POSIX allows either).

+6
source

Other answers don't mention this, but there is a realpath function that does exactly what you want, which is specified by POSIX.1-2001.

 char *realpath(const char *path, char *resolved_path); 

from manpage:

realpath () expands all symbolic links and allows links to /./,/../ and optional '/' characters in a zero-terminated string with a path name to create a canonized absolute path.

realpath also handles dynamic memory allocation for you if you want. Again, an excerpt from the manpage:

If resol_path is specified as NULL, then realpath () uses malloc (3) to buffer up to PATH_MAX bytes to store the resolved path name and returns a pointer to this buffer. The caller must free this buffer using the free (3).

As a simple, complete example:

 #include <limits.h> #include <stdlib.h> #include <stdio.h> int resolve_link (const char *filename) { char *res = realpath(filename, NULL); if (res == NULL) { perror("realpath failed"); return -1; } printf("%s -> %s\n", filename, res); free(res); return 0; } int main (void) { resolve_link("/proc/self/exe"); return 0; } 
+2
source

st_size does not give the correct answer to / proc.

Instead, you can use malloc PATH_MAX or pathconf (_PC_PATH_MAX) bytes. This is enough for most cases. If you want to process paths longer than this, you can call readlink in a loop and reallocate your buffer if the return readlink value indicates that the buffer is too short. Note that many other POSIX functions simply assume that PATH_MAX is sufficient.

+1
source

I am a little puzzled by why st_size is zero. Per POSIX:

For symbolic links, the st_mode member must contain meaningful information when used with file type macros. File mode bits in st_mode are not set. Structural elements st_ino, st_dev, st_uid, st_gid, st_atim, st_ctim and st_mtim must have significant values, and the value of the st_nlink element must be set to the number of (hard) links to a symbolic link. The value of the st_size element must be set to the length of the path name contained in the symbolic link, not including any terminating null byte.

Source: http://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html

If st_size does not work, I think your only option is to dynamically allocate the buffer and keep it larger if the return readlink value is equal to the size of the buffer.

0
source

the manpage for readlink(2) says that it will silently truncate if the buffer is too small. If you really want to be limitless (and do not mind paying a fee for additional work), you can start with a given distribution size and continue to increase it and try to call readlink again. You can stop buffer growth when the next readlink call returns the same line as for the last iteration.

0
source

What exactly are you trying to achieve with lstat?

You can only get the goal with the following

 char buffer[1024]; ssize_t r = readlink ("/proc/self/exe", buffer, 1024); buffer[r] = 0; printf ("%s\n", buffer); 

If you are trying to get the size of the file name, I don’t think st_size is the right variable for this ... But that might be another question.

-one
source

Source: https://habr.com/ru/post/1397676/


All Articles