1 /* Copyright (c) 2001, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
27
28 #include "mysys_priv.h"
29 #include "my_sys.h"
30 #include "mysys_err.h"
31 #include <m_string.h>
32 #include <errno.h>
33 #include "my_thread_local.h"
34 #include "my_dir.h"
35 #ifdef HAVE_REALPATH
36 #include <sys/param.h>
37 #include <sys/stat.h>
38 #endif
39 #include "my_dir.h"
40
41 /*
42 Reads the content of a symbolic link
43 If the file is not a symbolic link, return the original file name in to.
44
45 RETURN
46 0 If filename was a symlink, (to will be set to value of symlink)
47 1 If filename was a normal file (to will be set to filename)
48 -1 on error.
49 */
50
my_readlink(char * to,const char * filename,myf MyFlags)51 int my_readlink(char *to, const char *filename, myf MyFlags)
52 {
53 #ifndef HAVE_READLINK
54 my_stpcpy(to,filename);
55 return 1;
56 #else
57 int result=0;
58 int length;
59 DBUG_ENTER("my_readlink");
60
61 if ((length=readlink(filename, to, FN_REFLEN-1)) < 0)
62 {
63 /* Don't give an error if this wasn't a symlink */
64 set_my_errno(errno);
65 if (my_errno() == EINVAL)
66 {
67 result= 1;
68 my_stpcpy(to,filename);
69 }
70 else
71 {
72 if (MyFlags & MY_WME)
73 {
74 char errbuf[MYSYS_STRERROR_SIZE];
75 my_error(EE_CANT_READLINK, MYF(0), filename,
76 errno, my_strerror(errbuf, sizeof(errbuf), errno));
77 }
78 result= -1;
79 }
80 }
81 else
82 to[length]=0;
83 DBUG_PRINT("exit" ,("result: %d", result));
84 DBUG_RETURN(result);
85 #endif /* HAVE_READLINK */
86 }
87
88
89 /* Create a symbolic link */
90
my_symlink(const char * content,const char * linkname,myf MyFlags)91 int my_symlink(const char *content, const char *linkname, myf MyFlags)
92 {
93 #ifndef HAVE_READLINK
94 return 0;
95 #else
96 int result;
97 DBUG_ENTER("my_symlink");
98 DBUG_PRINT("enter",("content: %s linkname: %s", content, linkname));
99
100 result= 0;
101 if (symlink(content, linkname))
102 {
103 result= -1;
104 set_my_errno(errno);
105 if (MyFlags & MY_WME)
106 {
107 char errbuf[MYSYS_STRERROR_SIZE];
108 my_error(EE_CANT_SYMLINK, MYF(0), linkname, content,
109 errno, my_strerror(errbuf, sizeof(errbuf), errno));
110 }
111 }
112 else if ((MyFlags & MY_SYNC_DIR) && my_sync_dir_by_file(linkname, MyFlags))
113 result= -1;
114 DBUG_RETURN(result);
115 #endif /* HAVE_READLINK */
116 }
117
118 #if defined(MAXPATHLEN)
119 #define BUFF_LEN MAXPATHLEN
120 #else
121 #define BUFF_LEN FN_LEN
122 #endif
123
124
my_is_symlink(const char * filename MY_ATTRIBUTE ((unused)),ST_FILE_ID * file_id)125 int my_is_symlink(const char *filename MY_ATTRIBUTE((unused)),
126 ST_FILE_ID *file_id)
127 {
128 #if defined (HAVE_LSTAT) && defined (S_ISLNK)
129 struct stat stat_buff;
130 int result= !lstat(filename, &stat_buff) && S_ISLNK(stat_buff.st_mode);
131 if (file_id && !result)
132 {
133 file_id->st_dev= stat_buff.st_dev;
134 file_id->st_ino= stat_buff.st_ino;
135 }
136 return result;
137 #elif defined (_WIN32)
138 DWORD dwAttr = GetFileAttributes(filename);
139 return (dwAttr != INVALID_FILE_ATTRIBUTES) &&
140 (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT);
141 #else /* No symlinks */
142 return 0;
143 #endif
144 }
145
146 /*
147 Resolve all symbolic links in path
148 'to' may be equal to 'filename'
149 */
150
my_realpath(char * to,const char * filename,myf MyFlags)151 int my_realpath(char *to, const char *filename, myf MyFlags)
152 {
153 #if defined(HAVE_REALPATH)
154 int result=0;
155 char buff[BUFF_LEN];
156 char *ptr;
157 DBUG_ENTER("my_realpath");
158
159 DBUG_PRINT("info",("executing realpath"));
160 if ((ptr=realpath(filename,buff)))
161 strmake(to,ptr,FN_REFLEN-1);
162 else
163 {
164 /*
165 Realpath didn't work; Use my_load_path() which is a poor substitute
166 original name but will at least be able to resolve paths that starts
167 with '.'.
168 */
169 DBUG_PRINT("error",("realpath failed with errno: %d", errno));
170 set_my_errno(errno);
171 if (MyFlags & MY_WME)
172 {
173 char errbuf[MYSYS_STRERROR_SIZE];
174 my_error(EE_REALPATH, MYF(0), filename,
175 my_errno(), my_strerror(errbuf, sizeof(errbuf), my_errno()));
176 }
177 my_load_path(to, filename, NullS);
178 result= -1;
179 }
180 DBUG_RETURN(result);
181 #elif defined(_WIN32)
182 int ret= GetFullPathName(filename,FN_REFLEN, to, NULL);
183 if (ret == 0 || ret > FN_REFLEN)
184 {
185 set_my_errno((ret > FN_REFLEN) ? ENAMETOOLONG : GetLastError());
186 if (MyFlags & MY_WME)
187 {
188 char errbuf[MYSYS_STRERROR_SIZE];
189 my_error(EE_REALPATH, MYF(0), filename,
190 my_errno(), my_strerror(errbuf, sizeof(errbuf), my_errno()));
191 }
192 /*
193 GetFullPathName didn't work : use my_load_path() which is a poor
194 substitute original name but will at least be able to resolve
195 paths that starts with '.'.
196 */
197 my_load_path(to, filename, NullS);
198 return -1;
199 }
200 #else
201 my_load_path(to, filename, NullS);
202 #endif
203 return 0;
204 }
205
206
207 /**
208 Return non-zero if the file descriptor and a previously lstat-ed file
209 identified by file_id point to the same file
210 */
my_is_same_file(File file,const ST_FILE_ID * file_id)211 int my_is_same_file(File file, const ST_FILE_ID *file_id)
212 {
213 MY_STAT stat_buf;
214 if (my_fstat(file, &stat_buf, MYF(0)) == -1)
215 {
216 set_my_errno(errno);
217 return 0;
218 }
219 return (stat_buf.st_dev == file_id->st_dev)
220 && (stat_buf.st_ino == file_id->st_ino);
221 }
222