Drizzled Public API Documentation

my_symlink2.cc
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 St, 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 <config.h>
24 
25 #include <drizzled/internal/my_sys.h>
26 #include <drizzled/error.h>
27 #include <drizzled/internal/m_string.h>
28 
29 namespace drizzled {
30 namespace internal {
31 
32 int my_create_with_symlink(const char *linkname, const char *filename,
33  int createflags, int access_flags, myf MyFlags)
34 {
35  /* Test if we should create a link */
36  bool create_link= false;
37  char rp_buff[PATH_MAX];
38 
39  if (my_disable_symlinks)
40  {
41  /* Create only the file, not the link and file */
42  if (linkname)
43  filename= linkname;
44  }
45  else if (linkname)
46  {
47  if (!realpath(linkname,rp_buff))
48  my_load_path(rp_buff, linkname, NULL);
49  rp_buff[FN_REFLEN-1]= '\0';
50  char abs_linkname[FN_REFLEN];
51  strcpy(abs_linkname, rp_buff);
52  create_link= strcmp(abs_linkname, filename);
53  }
54 
55  if (!(MyFlags & MY_DELETE_OLD))
56  {
57  if (!access(filename,F_OK))
58  {
59  errno= EEXIST;
60  my_error(EE_CANTCREATEFILE, MYF(0), filename, EEXIST);
61  return(-1);
62  }
63  if (create_link && !access(linkname,F_OK))
64  {
65  errno= EEXIST;
66  my_error(EE_CANTCREATEFILE, MYF(0), linkname, EEXIST);
67  return(-1);
68  }
69  }
70 
71  int file= my_create(filename, createflags, access_flags, MyFlags);
72  if (file >= 0 && create_link)
73  {
74  /* Delete old link/file */
75  if (MyFlags & MY_DELETE_OLD)
76  my_delete(linkname, MYF(0));
77  /* Create link */
78  if (symlink(filename,linkname))
79  {
80  /* Fail, remove everything we have done */
81  int tmp_errno= errno;
82  my_close(file, MYF(0));
83  my_delete(filename, MYF(0));
84  file= -1;
85  errno= tmp_errno;
86  }
87  else if (MyFlags & MY_SYNC_DIR)
88  my_sync_dir_by_file(linkname, MyFlags);
89  }
90  return file;
91 }
92 
93 /*
94  If the file was a symlink, delete both symlink and the file which the
95  symlink pointed to.
96 */
97 
98 int my_delete_with_symlink(const char *name, myf MyFlags)
99 {
100  char link_name[FN_REFLEN];
101  ssize_t sym_link_size= readlink(name,link_name,FN_REFLEN-1);
102  int was_symlink= (!my_disable_symlinks && sym_link_size != -1);
103  int result;
104 
105  if (!(result=my_delete(name, MyFlags)))
106  {
107  if (was_symlink)
108  {
109  link_name[sym_link_size]= '\0';
110  result= my_delete(link_name, MyFlags);
111  }
112  }
113  return(result);
114 }
115 
116 /*
117  If the file is a normal file, just rename it.
118  If the file is a symlink:
119  - Create a new file with the name 'to' that points at
120  symlink_dir/basename(to)
121  - Rename the symlinked file to symlink_dir/basename(to)
122  - Delete 'from'
123  If something goes wrong, restore everything.
124 */
125 
126 int my_rename_with_symlink(const char *from, const char *to, myf MyFlags)
127 {
128  char link_name[FN_REFLEN], tmp_name[FN_REFLEN];
129  int sym_link_size= -1;
130  int was_symlink= (!my_disable_symlinks &&
131  (sym_link_size= static_cast<int>(readlink(from,link_name,
132  FN_REFLEN-1))) != -1);
133  int result=0;
134  int name_is_different;
135 
136  if (!was_symlink)
137  return(my_rename(from, to, MyFlags));
138  else
139  link_name[sym_link_size]= '\0';
140 
141  /* Change filename that symlink pointed to */
142  strcpy(tmp_name, to);
143  fn_same(tmp_name,link_name,1); /* Copy dir */
144  name_is_different= strcmp(link_name, tmp_name);
145  if (name_is_different && !access(tmp_name, F_OK))
146  {
147  errno= EEXIST;
148  if (MyFlags & MY_WME)
149  my_error(EE_CANTCREATEFILE, MYF(0), tmp_name, EEXIST);
150  return 1;
151  }
152 
153  /* Create new symlink */
154  if (symlink(tmp_name, to))
155  return 1;
156  else if (MyFlags & MY_SYNC_DIR)
157  my_sync_dir_by_file(to, MyFlags);
158 
159  /*
160  Rename symlinked file if the base name didn't change.
161  This can happen if you use this function where 'from' and 'to' has
162  the same basename and different directories.
163  */
164 
165  if (name_is_different && my_rename(link_name, tmp_name, MyFlags))
166  {
167  int save_errno=errno;
168  my_delete(to, MyFlags); /* Remove created symlink */
169  errno=save_errno;
170  return 1;
171  }
172 
173  /* Remove original symlink */
174  if (my_delete(from, MyFlags))
175  {
176  int save_errno=errno;
177  /* Remove created link */
178  my_delete(to, MyFlags);
179  /* Rename file back */
180  if (strcmp(link_name, tmp_name))
181  (void) my_rename(tmp_name, link_name, MyFlags);
182  errno=save_errno;
183  result= 1;
184  }
185  return(result);
186 }
187 
188 } /* namespace internal */
189 } /* namespace drizzled */