1 /* @(#)linkat.c 1.5 19/07/31 Copyright 2011-2019 J. Schilling */
2 /*
3 * Emulate the behavior of linkat(int fd1, const char *name1, int fd2,
4 * const char *name2, int flag)
5 *
6 * Note that emulation methods that do not use the /proc filesystem are
7 * not MT safe. In the non-MT-safe case, we do:
8 *
9 * savewd()/fchdir()/open(name)/restorewd()
10 *
11 * Errors may force us to abort the program as our caller is not expected
12 * to know that we do more than a simple open() here and that the
13 * working directory may be changed by us.
14 *
15 * Copyright (c) 2011-2019 J. Schilling
16 */
17 /*
18 * The contents of this file are subject to the terms of the
19 * Common Development and Distribution License, Version 1.0 only
20 * (the "License"). You may not use this file except in compliance
21 * with the License.
22 *
23 * See the file CDDL.Schily.txt in this distribution for details.
24 * A copy of the CDDL is also available via the Internet at
25 * http://www.opensource.org/licenses/cddl1.txt
26 *
27 * When distributing Covered Code, include this CDDL HEADER in each
28 * file and include the License file CDDL.Schily.txt from this distribution.
29 */
30
31 /*
32 * Since we need to call fstat() and since this is not a predictable call,
33 * we always compile this module in largefile mode.
34 */
35 #define USE_LARGEFILES
36
37 #include <schily/unistd.h>
38 #include <schily/types.h>
39 #include <schily/fcntl.h>
40 #include <schily/maxpath.h>
41 #include <schily/errno.h>
42 #include <schily/standard.h>
43 #include <schily/schily.h>
44 #include "at-defs.h"
45
46 #ifndef HAVE_LINKAT
47
48 #ifndef ENAMETOOLONG
49 #define ENAMETOOLONG EINVAL
50 #endif
51
52 EXPORT int linkfollow __PR((const char *old, const char *new));
53 EXPORT int
linkfollow(old,new)54 linkfollow(old, new)
55 const char *old;
56 const char *new;
57 {
58 char buf[max(8192, PATH_MAX+1)];
59 int blen;
60
61 buf[0] = '\0';
62 if ((blen = resolvepath(old, buf, sizeof (buf))) < 0) {
63 return (-1);
64 } else if (blen >= sizeof (buf)) {
65 seterrno(ENAMETOOLONG);
66 return (-1); /* Path too long */
67 } else {
68 buf[blen] = '\0'; /* Solaris syscall does not null-terminate */
69 }
70 return (link(buf, new));
71 }
72
73 #define KR_DECL int flag;
74 /* CSTYLED */
75 #define KR_ARGS , flag
76 #define FUNC_CALL(n1, n2) (flag & AT_SYMLINK_FOLLOW ? \
77 linkfollow(n1, n2) : link(n1, n2))
78 #define FLAG_CHECK() if (flag & ~(AT_SYMLINK_FOLLOW)) { \
79 seterrno(EINVAL); \
80 return (-1); \
81 }
82 #define FUNC_NAME linkat
83 #define FUNC_RESULT int
84
85 #include "at-base2.c"
86
87 #endif /* HAVE_LINKAT */
88