xref: /openbsd-src/usr.bin/rsync/symlinks.c (revision 173dc8749401a03b492e3d8eaa9358ba3cce4e24)
1*173dc874Sderaadt /*	$OpenBSD: symlinks.c,v 1.7 2021/09/02 21:06:06 deraadt Exp $ */
260a32ee9Sbenno /*
360a32ee9Sbenno  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
460a32ee9Sbenno  *
560a32ee9Sbenno  * Permission to use, copy, modify, and distribute this software for any
660a32ee9Sbenno  * purpose with or without fee is hereby granted, provided that the above
760a32ee9Sbenno  * copyright notice and this permission notice appear in all copies.
860a32ee9Sbenno  *
960a32ee9Sbenno  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1060a32ee9Sbenno  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1160a32ee9Sbenno  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1260a32ee9Sbenno  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1360a32ee9Sbenno  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1460a32ee9Sbenno  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1560a32ee9Sbenno  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1660a32ee9Sbenno  */
1760a32ee9Sbenno 
1860a32ee9Sbenno #include <assert.h>
1960a32ee9Sbenno #include <stdint.h>
2060a32ee9Sbenno #include <stdlib.h>
21*173dc874Sderaadt #include <limits.h>
2260a32ee9Sbenno #include <unistd.h>
2360a32ee9Sbenno 
2460a32ee9Sbenno #include "extern.h"
2560a32ee9Sbenno 
2660a32ee9Sbenno /*
2760a32ee9Sbenno  * Allocate space for a readlink(2) invocation.
2860a32ee9Sbenno  * Returns NULL on failure or a buffer otherwise.
2960a32ee9Sbenno  * The buffer must be passed to free() by the caller.
3060a32ee9Sbenno  */
3160a32ee9Sbenno char *
symlink_read(const char * path)32ba617adaSbenno symlink_read(const char *path)
3360a32ee9Sbenno {
3460a32ee9Sbenno 	char	*buf = NULL;
3560a32ee9Sbenno 	size_t	 sz;
3660a32ee9Sbenno 	ssize_t	 nsz = 0;
3760a32ee9Sbenno 	void	*pp;
3860a32ee9Sbenno 
39*173dc874Sderaadt 	for (sz = PATH_MAX; ; sz *= 2) {
40f1dcb30aSderaadt 		if ((pp = realloc(buf, sz + 1)) == NULL) {
41b2a7eac7Sbenno 			ERR("realloc");
4260a32ee9Sbenno 			free(buf);
4360a32ee9Sbenno 			return NULL;
4460a32ee9Sbenno 		}
4560a32ee9Sbenno 		buf = pp;
4660a32ee9Sbenno 
47f1dcb30aSderaadt 		if ((nsz = readlink(path, buf, sz)) == -1) {
48b2a7eac7Sbenno 			ERR("%s: readlink", path);
4960a32ee9Sbenno 			free(buf);
5060a32ee9Sbenno 			return NULL;
51f1dcb30aSderaadt 		} else if (nsz == 0) {
52b2a7eac7Sbenno 			ERRX("%s: empty link", path);
5360a32ee9Sbenno 			free(buf);
5460a32ee9Sbenno 			return NULL;
5560a32ee9Sbenno 		} else if ((size_t)nsz < sz)
5660a32ee9Sbenno 			break;
5760a32ee9Sbenno 	}
5860a32ee9Sbenno 
59f1dcb30aSderaadt 	assert(buf != NULL);
6060a32ee9Sbenno 	assert(nsz > 0);
6160a32ee9Sbenno 	buf[nsz] = '\0';
6260a32ee9Sbenno 	return buf;
6360a32ee9Sbenno }
6460a32ee9Sbenno 
6560a32ee9Sbenno /*
6660a32ee9Sbenno  * Allocate space for a readlinkat(2) invocation.
6760a32ee9Sbenno  * Returns NULL on failure or a buffer otherwise.
6860a32ee9Sbenno  * The buffer must be passed to free() by the caller.
6960a32ee9Sbenno  */
7060a32ee9Sbenno char *
symlinkat_read(int fd,const char * path)71ba617adaSbenno symlinkat_read(int fd, const char *path)
7260a32ee9Sbenno {
7360a32ee9Sbenno 	char	*buf = NULL;
7460a32ee9Sbenno 	size_t	 sz;
7560a32ee9Sbenno 	ssize_t	 nsz = 0;
7660a32ee9Sbenno 	void	*pp;
7760a32ee9Sbenno 
78*173dc874Sderaadt 	for (sz = PATH_MAX; ; sz *= 2) {
79f1dcb30aSderaadt 		if ((pp = realloc(buf, sz + 1)) == NULL) {
80b2a7eac7Sbenno 			ERR("realloc");
8160a32ee9Sbenno 			free(buf);
8260a32ee9Sbenno 			return NULL;
8360a32ee9Sbenno 		}
8460a32ee9Sbenno 		buf = pp;
8560a32ee9Sbenno 
86f1dcb30aSderaadt 		if ((nsz = readlinkat(fd, path, buf, sz)) == -1) {
87b2a7eac7Sbenno 			ERR("%s: readlinkat", path);
8860a32ee9Sbenno 			free(buf);
8960a32ee9Sbenno 			return NULL;
90f1dcb30aSderaadt 		} else if (nsz == 0) {
91b2a7eac7Sbenno 			ERRX("%s: empty link", path);
9260a32ee9Sbenno 			free(buf);
9360a32ee9Sbenno 			return NULL;
9460a32ee9Sbenno 		} else if ((size_t)nsz < sz)
9560a32ee9Sbenno 			break;
9660a32ee9Sbenno 	}
9760a32ee9Sbenno 
98f1dcb30aSderaadt 	assert(buf != NULL);
9960a32ee9Sbenno 	assert(nsz > 0);
10060a32ee9Sbenno 	buf[nsz] = '\0';
10160a32ee9Sbenno 	return buf;
10260a32ee9Sbenno }
103