MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_symlink2.c
1 /* Copyright (C) 2000 MySQL AB
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 as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15 
16 /*
17  Advanced symlink handling.
18  This is used in MyISAM to let users symlinks tables to different disk.
19  The main idea with these functions is to automaticly create, delete and
20  rename files and symlinks like they would be one unit.
21 */
22 
23 #include "mysys_priv.h"
24 #include "mysys_err.h"
25 #include <m_string.h>
26 
27 File my_create_with_symlink(const char *linkname, const char *filename,
28  int createflags, int access_flags, myf MyFlags)
29 {
30  File file;
31  int tmp_errno;
32  /* Test if we should create a link */
33  int create_link;
34  char abs_linkname[FN_REFLEN];
35  DBUG_ENTER("my_create_with_symlink");
36  DBUG_PRINT("enter", ("linkname: %s filename: %s",
37  linkname ? linkname : "(null)",
38  filename ? filename : "(null)"));
39 
40  if (my_disable_symlinks)
41  {
42  DBUG_PRINT("info", ("Symlinks disabled"));
43  /* Create only the file, not the link and file */
44  create_link= 0;
45  if (linkname)
46  filename= linkname;
47  }
48  else
49  {
50  if (linkname)
51  my_realpath(abs_linkname, linkname, MYF(0));
52  create_link= (linkname && strcmp(abs_linkname,filename));
53  }
54 
55  if (!(MyFlags & MY_DELETE_OLD))
56  {
57  if (!access(filename,F_OK))
58  {
59  char errbuf[MYSYS_STRERROR_SIZE];
60  my_errno= errno= EEXIST;
61  my_error(EE_CANTCREATEFILE, MYF(0), filename,
62  EEXIST, my_strerror(errbuf, sizeof(errbuf), EEXIST));
63  DBUG_RETURN(-1);
64  }
65  if (create_link && !access(linkname,F_OK))
66  {
67  char errbuf[MYSYS_STRERROR_SIZE];
68  my_errno= errno= EEXIST;
69  my_error(EE_CANTCREATEFILE, MYF(0), linkname,
70  EEXIST, my_strerror(errbuf, sizeof(errbuf), EEXIST));
71  DBUG_RETURN(-1);
72  }
73  }
74 
75  if ((file=my_create(filename, createflags, access_flags, MyFlags)) >= 0)
76  {
77  if (create_link)
78  {
79  /* Delete old link/file */
80  if (MyFlags & MY_DELETE_OLD)
81  my_delete(linkname, MYF(0));
82  /* Create link */
83  if (my_symlink(filename, linkname, MyFlags))
84  {
85  /* Fail, remove everything we have done */
86  tmp_errno=my_errno;
87  my_close(file,MYF(0));
88  my_delete(filename, MYF(0));
89  file= -1;
90  my_errno=tmp_errno;
91  }
92  }
93  }
94  DBUG_RETURN(file);
95 }
96 
97 /*
98  If the file was a symlink, delete both symlink and the file which the
99  symlink pointed to.
100 */
101 
102 int my_delete_with_symlink(const char *name, myf MyFlags)
103 {
104  char link_name[FN_REFLEN];
105  int was_symlink= (!my_disable_symlinks &&
106  !my_readlink(link_name, name, MYF(0)));
107  int result;
108  DBUG_ENTER("my_delete_with_symlink");
109 
110  if (!(result=my_delete(name, MyFlags)))
111  {
112  if (was_symlink)
113  result=my_delete(link_name, MyFlags);
114  }
115  DBUG_RETURN(result);
116 }
117 
118 /*
119  If the file is a normal file, just rename it.
120  If the file is a symlink:
121  - Create a new file with the name 'to' that points at
122  symlink_dir/basename(to)
123  - Rename the symlinked file to symlink_dir/basename(to)
124  - Delete 'from'
125  If something goes wrong, restore everything.
126 */
127 
128 int my_rename_with_symlink(const char *from, const char *to, myf MyFlags)
129 {
130 #ifndef HAVE_READLINK
131  return my_rename(from, to, MyFlags);
132 #else
133  char link_name[FN_REFLEN], tmp_name[FN_REFLEN];
134  int was_symlink= (!my_disable_symlinks &&
135  !my_readlink(link_name, from, MYF(0)));
136  int result=0;
137  int name_is_different;
138  DBUG_ENTER("my_rename_with_symlink");
139 
140  if (!was_symlink)
141  DBUG_RETURN(my_rename(from, to, MyFlags));
142 
143  /* Change filename that symlink pointed to */
144  strmov(tmp_name, to);
145  fn_same(tmp_name,link_name,1); /* Copy dir */
146  name_is_different= strcmp(link_name, tmp_name);
147  if (name_is_different && !access(tmp_name, F_OK))
148  {
149  my_errno= EEXIST;
150  if (MyFlags & MY_WME)
151  {
152  char errbuf[MYSYS_STRERROR_SIZE];
153  my_error(EE_CANTCREATEFILE, MYF(0), tmp_name,
154  EEXIST, my_strerror(errbuf, sizeof(errbuf), EEXIST));
155  }
156  DBUG_RETURN(1);
157  }
158 
159  /* Create new symlink */
160  if (my_symlink(tmp_name, to, MyFlags))
161  DBUG_RETURN(1);
162 
163  /*
164  Rename symlinked file if the base name didn't change.
165  This can happen if you use this function where 'from' and 'to' has
166  the same basename and different directories.
167  */
168 
169  if (name_is_different && my_rename(link_name, tmp_name, MyFlags))
170  {
171  int save_errno=my_errno;
172  my_delete(to, MyFlags); /* Remove created symlink */
173  my_errno=save_errno;
174  DBUG_RETURN(1);
175  }
176 
177  /* Remove original symlink */
178  if (my_delete(from, MyFlags))
179  {
180  int save_errno=my_errno;
181  /* Remove created link */
182  my_delete(to, MyFlags);
183  /* Rename file back */
184  if (strcmp(link_name, tmp_name))
185  (void) my_rename(tmp_name, link_name, MyFlags);
186  my_errno=save_errno;
187  result= 1;
188  }
189  DBUG_RETURN(result);
190 #endif /* HAVE_READLINK */
191 }