Improve mu_unroll_symlink interface.
* include/mailutils/util.h (mu_readlink): New function. (mu_unroll_symlink): Change prototype. * libmailutils/base/symlink.c (mu_qualify_link): Remove. (mu_readlink): New function. (mu_unroll_symlink): Rewrite. Don't use statically allocated buffers. * libmailutils/base/locker.c (mu_locker_create): Update calls to mu_unroll_symlink.
Showing
3 changed files
with
105 additions
and
49 deletions
... | @@ -78,7 +78,8 @@ char *mu_normalize_path (char *path); | ... | @@ -78,7 +78,8 @@ char *mu_normalize_path (char *path); |
78 | char *mu_expand_path_pattern (const char *pattern, const char *username); | 78 | char *mu_expand_path_pattern (const char *pattern, const char *username); |
79 | char *mu_tilde_expansion (const char *ref, const char *delim, | 79 | char *mu_tilde_expansion (const char *ref, const char *delim, |
80 | const char *homedir); | 80 | const char *homedir); |
81 | int mu_unroll_symlink (char *out, size_t outsz, const char *in); | 81 | int mu_readlink (const char *name, char **pbuf, size_t *psize, size_t *plen); |
82 | int mu_unroll_symlink (const char *name, char **pout); | ||
82 | char *mu_getcwd (void); | 83 | char *mu_getcwd (void); |
83 | int mu_tempfile (const char *tmpdir, char **namep); | 84 | int mu_tempfile (const char *tmpdir, char **namep); |
84 | char *mu_tempname (const char *tmpdir); | 85 | char *mu_tempname (const char *tmpdir); | ... | ... |
... | @@ -437,7 +437,7 @@ mu_locker_create (mu_locker_t *plocker, const char *fname, int flags) | ... | @@ -437,7 +437,7 @@ mu_locker_create (mu_locker_t *plocker, const char *fname, int flags) |
437 | { | 437 | { |
438 | unsigned type; | 438 | unsigned type; |
439 | mu_locker_t l; | 439 | mu_locker_t l; |
440 | char filename[_POSIX_PATH_MAX]; | 440 | char *filename; |
441 | int err = 0; | 441 | int err = 0; |
442 | 442 | ||
443 | if (plocker == NULL) | 443 | if (plocker == NULL) |
... | @@ -446,15 +446,18 @@ mu_locker_create (mu_locker_t *plocker, const char *fname, int flags) | ... | @@ -446,15 +446,18 @@ mu_locker_create (mu_locker_t *plocker, const char *fname, int flags) |
446 | if (fname == NULL) | 446 | if (fname == NULL) |
447 | return EINVAL; | 447 | return EINVAL; |
448 | 448 | ||
449 | if ((err = mu_unroll_symlink (filename, sizeof (filename), fname))) | 449 | if ((err = mu_unroll_symlink (fname, &filename))) |
450 | return err; | 450 | return err; |
451 | 451 | ||
452 | l = calloc (1, sizeof (*l)); | 452 | l = calloc (1, sizeof (*l)); |
453 | 453 | ||
454 | if (l == NULL) | 454 | if (l == NULL) |
455 | return ENOMEM; | 455 | { |
456 | 456 | free (filename); | |
457 | l->file = strdup (filename); | 457 | return ENOMEM; |
458 | } | ||
459 | |||
460 | l->file = filename; | ||
458 | 461 | ||
459 | if (l->file == NULL) | 462 | if (l->file == NULL) |
460 | { | 463 | { | ... | ... |
... | @@ -30,32 +30,73 @@ | ... | @@ -30,32 +30,73 @@ |
30 | #include <mailutils/types.h> | 30 | #include <mailutils/types.h> |
31 | #include <mailutils/util.h> | 31 | #include <mailutils/util.h> |
32 | 32 | ||
33 | /* The result of readlink() may be a path relative to that link, | 33 | #define INITIAL_READLINK_SIZE 128 |
34 | * qualify it if necessary. | 34 | |
35 | */ | 35 | int |
36 | static void | 36 | mu_readlink (const char *name, char **pbuf, size_t *psize, size_t *plen) |
37 | mu_qualify_link (const char *path, const char *link, char *qualified) | ||
38 | { | 37 | { |
39 | const char *lb = NULL; | 38 | size_t status = 0; |
40 | size_t len; | 39 | char *buf = *pbuf; |
40 | size_t size = *plen; | ||
41 | ssize_t linklen; | ||
41 | 42 | ||
42 | /* link is full path */ | 43 | while (1) |
43 | if (*link == '/') | ||
44 | { | 44 | { |
45 | mu_cpystr (qualified, link, _POSIX_PATH_MAX); | 45 | if (!buf) |
46 | return; | 46 | { |
47 | size = INITIAL_READLINK_SIZE; | ||
48 | buf = malloc (size); | ||
49 | } | ||
50 | else | ||
51 | { | ||
52 | char *p; | ||
53 | size_t newsize = size << 1; | ||
54 | if (newsize < size) | ||
55 | { | ||
56 | status = ENAMETOOLONG; | ||
57 | break; | ||
58 | } | ||
59 | size = newsize; | ||
60 | p = realloc (buf, size); | ||
61 | if (!p) | ||
62 | free (buf); | ||
63 | buf = p; | ||
64 | } | ||
65 | if (!buf) | ||
66 | { | ||
67 | status = ENOMEM; | ||
68 | break; | ||
69 | } | ||
70 | |||
71 | linklen = readlink (name, buf, size); | ||
72 | if (linklen < 0 && errno != ERANGE) | ||
73 | { | ||
74 | status = errno; | ||
75 | break; | ||
76 | } | ||
77 | |||
78 | if ((size_t) linklen < size) | ||
79 | { | ||
80 | buf[linklen++] = '\0'; | ||
81 | status = 0; | ||
82 | break; | ||
83 | } | ||
47 | } | 84 | } |
48 | 85 | ||
49 | if ((lb = strrchr (path, '/')) == NULL) | 86 | if (status) |
50 | { | 87 | { |
51 | /* no path in link */ | 88 | if (buf) |
52 | mu_cpystr (qualified, link, _POSIX_PATH_MAX); | 89 | { |
53 | return; | 90 | free (buf); |
91 | buf = NULL; | ||
92 | } | ||
93 | size = 0; | ||
54 | } | 94 | } |
55 | 95 | *pbuf = buf; | |
56 | len = lb - path + 1; | 96 | *psize = size; |
57 | memcpy (qualified, path, len); | 97 | if (plen) |
58 | mu_cpystr (qualified + len, link, _POSIX_PATH_MAX - len); | 98 | *plen = linklen; |
99 | return status; | ||
59 | } | 100 | } |
60 | 101 | ||
61 | #ifndef _POSIX_SYMLOOP_MAX | 102 | #ifndef _POSIX_SYMLOOP_MAX |
... | @@ -63,41 +104,52 @@ mu_qualify_link (const char *path, const char *link, char *qualified) | ... | @@ -63,41 +104,52 @@ mu_qualify_link (const char *path, const char *link, char *qualified) |
63 | #endif | 104 | #endif |
64 | 105 | ||
65 | int | 106 | int |
66 | mu_unroll_symlink (char *out, size_t outsz, const char *in) | 107 | mu_unroll_symlink (const char *name, char **pout) |
67 | { | 108 | { |
68 | char path[_POSIX_PATH_MAX]; | 109 | size_t symloops = 0; |
69 | int symloops = 0; | 110 | struct slbuf { char *base; size_t size; } buf[2]; |
111 | int idx = 0; | ||
112 | int status; | ||
113 | |||
114 | buf[0].base = buf[1].base = NULL; | ||
115 | buf[0].size = buf[1].size = 0; | ||
70 | 116 | ||
71 | while (symloops++ < _POSIX_SYMLOOP_MAX) | 117 | while (symloops++ < _POSIX_SYMLOOP_MAX) |
72 | { | 118 | { |
73 | struct stat s; | 119 | struct stat st; |
74 | char link[_POSIX_PATH_MAX]; | 120 | size_t len; |
75 | char qualified[_POSIX_PATH_MAX]; | ||
76 | int len; | ||
77 | 121 | ||
78 | if (lstat (in, &s) == -1) | 122 | if (lstat (name, &st) == -1) |
79 | return errno; | 123 | return errno; |
80 | 124 | ||
81 | if (!S_ISLNK (s.st_mode)) | 125 | if (!S_ISLNK (st.st_mode)) |
82 | { | 126 | { |
83 | mu_cpystr (path, in, sizeof (path)); | 127 | if (!buf[idx].base) |
128 | { | ||
129 | buf[idx].base = strdup (name); | ||
130 | if (!buf[idx].base) | ||
131 | return ENOMEM; | ||
132 | } | ||
133 | status = 0; | ||
84 | break; | 134 | break; |
85 | } | 135 | } |
86 | 136 | ||
87 | if ((len = readlink (in, link, sizeof (link))) == -1) | 137 | idx = !idx; |
88 | return errno; | 138 | status = mu_readlink (name, &buf[idx].base, &buf[idx].size, &len); |
89 | 139 | if (status) | |
90 | link[(len >= sizeof (link)) ? (sizeof (link) - 1) : len] = '\0'; | 140 | break; |
91 | 141 | name = mu_normalize_path (buf[idx].base); | |
92 | mu_qualify_link (in, link, qualified); | ||
93 | |||
94 | mu_cpystr (path, qualified, sizeof (path)); | ||
95 | |||
96 | in = path; | ||
97 | } | 142 | } |
98 | 143 | ||
99 | mu_cpystr (out, path, outsz); | 144 | if (status) |
100 | 145 | { | |
101 | return 0; | 146 | free (buf[0].base); |
147 | free (buf[1].base); | ||
148 | } | ||
149 | else | ||
150 | { | ||
151 | *pout = buf[idx].base; | ||
152 | free (buf[!idx].base); | ||
153 | } | ||
154 | return status; | ||
102 | } | 155 | } |
103 | ... | ... |
-
Please register or sign in to post a comment