Commit 2164243d 2164243df618ab718f4d30c95174eab12178fb76 by Sergey Poznyakoff

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.
1 parent d3759d84
...@@ -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
......