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