1/************************************************************************************
2 Copyright (C) 2000, 2011 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
3 Monty Program AB
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not see <http://www.gnu.org/licenses>
17 or write to the Free Software Foundation, Inc.,
18 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
19
20 Part of this code includes code from the PHP project which
21 is freely available from http://www.php.net
22*************************************************************************************/
23/*
24 +----------------------------------------------------------------------+
25 | PHP Version 5 |
26 +----------------------------------------------------------------------+
27 | Copyright (c) 2006-2011 The PHP Group |
28 +----------------------------------------------------------------------+
29 | This source file is subject to version 3.01 of the PHP license, |
30 | that is bundled with this package in the file LICENSE, and is |
31 | available through the world-wide-web at the following url: |
32 | http://www.php.net/license/3_01.txt |
33 | If you did not receive a copy of the PHP license and are unable to |
34 | obtain it through the world-wide-web, please send a note to |
35 | license@php.net so we can mail you a copy immediately. |
36 +----------------------------------------------------------------------+
37 | Authors: Georg Richter <georg@mysql.com> |
38 | Andrey Hristov <andrey@mysql.com> |
39 | Ulf Wendel <uwendel@mysql.com> |
40 +----------------------------------------------------------------------+
41*/
42
43#include "ma_global.h"
44#include <ma_sys.h>
45#include <ma_string.h>
46#include "errmsg.h"
47#include "mysql.h"
48#include <mariadb/ma_io.h>
49#include <string.h>
50#ifdef _WIN32
51#include <share.h>
52#endif
53
54typedef struct st_mysql_infile_info
55{
56 MA_FILE *fp;
57 int error_no;
58 char error_msg[MYSQL_ERRMSG_SIZE + 1];
59 const char *filename;
60} MYSQL_INFILE_INFO;
61
62/* {{{ mysql_local_infile_init */
63static
64int mysql_local_infile_init(void **ptr, const char *filename, void *userdata)
65{
66 MYSQL_INFILE_INFO *info;
67 MYSQL *mysql= (MYSQL *)userdata;
68
69 info = (MYSQL_INFILE_INFO *)malloc(sizeof(MYSQL_INFILE_INFO));
70 if (!info) {
71 return(1);
72 }
73 memset(info, 0, sizeof(MYSQL_INFILE_INFO));
74 *ptr = info;
75
76 info->filename = filename;
77
78 info->fp= ma_open(filename, "rb", mysql);
79
80 if (!info->fp)
81 {
82 /* error handling is done via mysql_local_infile_error function, so we
83 need to copy error to info */
84 if (mysql_errno(mysql) && !info->error_no)
85 {
86 info->error_no= mysql_errno(mysql);
87 ma_strmake(info->error_msg, mysql_error(mysql), MYSQL_ERRMSG_SIZE);
88 }
89 else
90 {
91 info->error_no = errno;
92 snprintf((char *)info->error_msg, sizeof(info->error_msg),
93 CER(CR_FILE_NOT_FOUND), filename, info->error_no);
94 }
95 return(1);
96 }
97
98 return(0);
99}
100/* }}} */
101
102
103/* {{{ mysql_local_infile_read */
104static
105int mysql_local_infile_read(void *ptr, char * buf, unsigned int buf_len)
106{
107 MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
108 size_t count;
109
110 count= ma_read((void *)buf, 1, (size_t)buf_len, info->fp);
111
112 if (count == (size_t)-1)
113 {
114 info->error_no = errno;
115 snprintf((char *)info->error_msg, sizeof(info->error_msg),
116 CER(CR_FILE_READ), info->filename, info->error_no);
117 }
118 return((int)count);
119}
120/* }}} */
121
122
123/* {{{ mysql_local_infile_error */
124static
125int mysql_local_infile_error(void *ptr, char *error_buf, unsigned int error_buf_len)
126{
127 MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
128
129 if (info) {
130 ma_strmake(error_buf, info->error_msg, error_buf_len);
131 return(info->error_no);
132 }
133
134 ma_strmake(error_buf, "Unknown error", error_buf_len);
135 return(CR_UNKNOWN_ERROR);
136}
137/* }}} */
138
139
140/* {{{ mysql_local_infile_end */
141static
142void mysql_local_infile_end(void *ptr)
143{
144 MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
145
146 if (info)
147 {
148 if (info->fp)
149 ma_close(info->fp);
150 free(ptr);
151 }
152 return;
153}
154/* }}} */
155
156
157/* {{{ mysql_local_infile_default */
158void mysql_set_local_infile_default(MYSQL *conn)
159{
160 conn->options.local_infile_init = mysql_local_infile_init;
161 conn->options.local_infile_read = mysql_local_infile_read;
162 conn->options.local_infile_error = mysql_local_infile_error;
163 conn->options.local_infile_end = mysql_local_infile_end;
164 return;
165}
166/* }}} */
167
168/* {{{ mysql_set_local_infile_handler */
169void STDCALL mysql_set_local_infile_handler(MYSQL *conn,
170 int (*local_infile_init)(void **, const char *, void *),
171 int (*local_infile_read)(void *, char *, uint),
172 void (*local_infile_end)(void *),
173 int (*local_infile_error)(void *, char *, uint),
174 void *userdata)
175{
176 conn->options.local_infile_init= local_infile_init;
177 conn->options.local_infile_read= local_infile_read;
178 conn->options.local_infile_end= local_infile_end;
179 conn->options.local_infile_error= local_infile_error;
180 conn->options.local_infile_userdata = userdata;
181 return;
182}
183/* }}} */
184
185/* {{{ mysql_handle_local_infile */
186my_bool mysql_handle_local_infile(MYSQL *conn, const char *filename)
187{
188 unsigned int buflen= 4096;
189 int bufread;
190 unsigned char *buf= NULL;
191 void *info= NULL;
192 my_bool result= 1;
193
194 /* check if all callback functions exist */
195 if (!conn->options.local_infile_init || !conn->options.local_infile_end ||
196 !conn->options.local_infile_read || !conn->options.local_infile_error)
197 {
198 conn->options.local_infile_userdata= conn;
199 mysql_set_local_infile_default(conn);
200 }
201
202 if (!(conn->options.client_flag & CLIENT_LOCAL_FILES)) {
203 my_set_error(conn, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, "Load data local infile forbidden");
204 /* write empty packet to server */
205 ma_net_write(&conn->net, (unsigned char *)"", 0);
206 ma_net_flush(&conn->net);
207 goto infile_error;
208 }
209
210 /* allocate buffer for reading data */
211 buf = (uchar *)malloc(buflen);
212
213 /* init handler: allocate read buffer and open file */
214 if (conn->options.local_infile_init(&info, filename,
215 conn->options.local_infile_userdata))
216 {
217 char tmp_buf[MYSQL_ERRMSG_SIZE];
218 int tmp_errno;
219
220 tmp_errno= conn->options.local_infile_error(info, tmp_buf, sizeof(tmp_buf));
221 my_set_error(conn, tmp_errno, SQLSTATE_UNKNOWN, tmp_buf);
222 ma_net_write(&conn->net, (unsigned char *)"", 0);
223 ma_net_flush(&conn->net);
224 goto infile_error;
225 }
226
227 /* read data */
228 while ((bufread= conn->options.local_infile_read(info, (char *)buf, buflen)) > 0)
229 {
230 if (ma_net_write(&conn->net, (unsigned char *)buf, bufread))
231 {
232 my_set_error(conn, CR_SERVER_LOST, SQLSTATE_UNKNOWN, NULL);
233 goto infile_error;
234 }
235 }
236
237 /* send empty packet for eof */
238 if (ma_net_write(&conn->net, (unsigned char *)"", 0) ||
239 ma_net_flush(&conn->net))
240 {
241 my_set_error(conn, CR_SERVER_LOST, SQLSTATE_UNKNOWN, NULL);
242 goto infile_error;
243 }
244
245 /* error during read occurred */
246 if (bufread < 0)
247 {
248 char tmp_buf[MYSQL_ERRMSG_SIZE];
249 int tmp_errno= conn->options.local_infile_error(info, tmp_buf, sizeof(tmp_buf));
250 my_set_error(conn, tmp_errno, SQLSTATE_UNKNOWN, tmp_buf);
251 goto infile_error;
252 }
253
254 result = 0;
255
256infile_error:
257 conn->options.local_infile_end(info);
258 free(buf);
259 return(result);
260}
261/* }}} */
262
263