1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
27
28 /*
29 Advanced symlink handling.
30 This is used in MyISAM to let users symlinks tables to different disk.
31 The main idea with these functions is to automaticly create, delete and
32 rename files and symlinks like they would be one unit.
33 */
34
35 #include "mysys_priv.h"
36 #include "mysys_err.h"
37 #include <m_string.h>
38
my_create_with_symlink(const char * linkname,const char * filename,int createflags,int access_flags,myf MyFlags)39 File my_create_with_symlink(const char *linkname, const char *filename,
40 int createflags, int access_flags, myf MyFlags)
41 {
42 File file;
43 int tmp_errno;
44 /* Test if we should create a link */
45 int create_link;
46 char abs_linkname[FN_REFLEN];
47 DBUG_ENTER("my_create_with_symlink");
48 DBUG_PRINT("enter", ("linkname: %s filename: %s",
49 linkname ? linkname : "(null)",
50 filename ? filename : "(null)"));
51
52 if (my_disable_symlinks)
53 {
54 DBUG_PRINT("info", ("Symlinks disabled"));
55 /* Create only the file, not the link and file */
56 create_link= 0;
57 if (linkname)
58 filename= linkname;
59 }
60 else
61 {
62 if (linkname)
63 my_realpath(abs_linkname, linkname, MYF(0));
64 create_link= (linkname && strcmp(abs_linkname,filename));
65 }
66
67 if (!(MyFlags & MY_DELETE_OLD))
68 {
69 if (!access(filename,F_OK))
70 {
71 char errbuf[MYSYS_STRERROR_SIZE];
72 my_errno= errno= EEXIST;
73 my_error(EE_CANTCREATEFILE, MYF(0), filename,
74 EEXIST, my_strerror(errbuf, sizeof(errbuf), EEXIST));
75 DBUG_RETURN(-1);
76 }
77 if (create_link && !access(linkname,F_OK))
78 {
79 char errbuf[MYSYS_STRERROR_SIZE];
80 my_errno= errno= EEXIST;
81 my_error(EE_CANTCREATEFILE, MYF(0), linkname,
82 EEXIST, my_strerror(errbuf, sizeof(errbuf), EEXIST));
83 DBUG_RETURN(-1);
84 }
85 }
86
87 if ((file=my_create(filename, createflags, access_flags, MyFlags)) >= 0)
88 {
89 if (create_link)
90 {
91 /* Delete old link/file */
92 if (MyFlags & MY_DELETE_OLD)
93 my_delete(linkname, MYF(0));
94 /* Create link */
95 if (my_symlink(filename, linkname, MyFlags))
96 {
97 /* Fail, remove everything we have done */
98 tmp_errno=my_errno;
99 my_close(file,MYF(0));
100 my_delete(filename, MYF(0));
101 file= -1;
102 my_errno=tmp_errno;
103 }
104 }
105 }
106 DBUG_RETURN(file);
107 }
108
109 /*
110 If the file was a symlink, delete both symlink and the file which the
111 symlink pointed to.
112 */
113
my_delete_with_symlink(const char * name,myf MyFlags)114 int my_delete_with_symlink(const char *name, myf MyFlags)
115 {
116 char link_name[FN_REFLEN];
117 int was_symlink= (!my_disable_symlinks &&
118 !my_readlink(link_name, name, MYF(0)));
119 int result;
120 DBUG_ENTER("my_delete_with_symlink");
121
122 if (!(result=my_delete(name, MyFlags)))
123 {
124 if (was_symlink)
125 result=my_delete(link_name, MyFlags);
126 }
127 DBUG_RETURN(result);
128 }
129
130 /*
131 If the file is a normal file, just rename it.
132 If the file is a symlink:
133 - Create a new file with the name 'to' that points at
134 symlink_dir/basename(to)
135 - Rename the symlinked file to symlink_dir/basename(to)
136 - Delete 'from'
137 If something goes wrong, restore everything.
138 */
139
my_rename_with_symlink(const char * from,const char * to,myf MyFlags)140 int my_rename_with_symlink(const char *from, const char *to, myf MyFlags)
141 {
142 #ifndef HAVE_READLINK
143 return my_rename(from, to, MyFlags);
144 #else
145 char link_name[FN_REFLEN], tmp_name[FN_REFLEN];
146 int was_symlink= (!my_disable_symlinks &&
147 !my_readlink(link_name, from, MYF(0)));
148 int result=0;
149 int name_is_different;
150 DBUG_ENTER("my_rename_with_symlink");
151
152 if (!was_symlink)
153 DBUG_RETURN(my_rename(from, to, MyFlags));
154
155 /* Change filename that symlink pointed to */
156 strmov(tmp_name, to);
157 fn_same(tmp_name,link_name,1); /* Copy dir */
158 name_is_different= strcmp(link_name, tmp_name);
159 if (name_is_different && !access(tmp_name, F_OK))
160 {
161 my_errno= EEXIST;
162 if (MyFlags & MY_WME)
163 {
164 char errbuf[MYSYS_STRERROR_SIZE];
165 my_error(EE_CANTCREATEFILE, MYF(0), tmp_name,
166 EEXIST, my_strerror(errbuf, sizeof(errbuf), EEXIST));
167 }
168 DBUG_RETURN(1);
169 }
170
171 /* Create new symlink */
172 if (my_symlink(tmp_name, to, MyFlags))
173 DBUG_RETURN(1);
174
175 /*
176 Rename symlinked file if the base name didn't change.
177 This can happen if you use this function where 'from' and 'to' has
178 the same basename and different directories.
179 */
180
181 if (name_is_different && my_rename(link_name, tmp_name, MyFlags))
182 {
183 int save_errno=my_errno;
184 my_delete(to, MyFlags); /* Remove created symlink */
185 my_errno=save_errno;
186 DBUG_RETURN(1);
187 }
188
189 /* Remove original symlink */
190 if (my_delete(from, MyFlags))
191 {
192 int save_errno=my_errno;
193 /* Remove created link */
194 my_delete(to, MyFlags);
195 /* Rename file back */
196 if (strcmp(link_name, tmp_name))
197 (void) my_rename(tmp_name, link_name, MyFlags);
198 my_errno=save_errno;
199 result= 1;
200 }
201 DBUG_RETURN(result);
202 #endif /* HAVE_READLINK */
203 }
204