Skip to content

Commit e8e0d5c

Browse files
author
bar@mysql.com
committed
bug#17870 Table names conflict with Windows device names
It was impossible to create some table names on Windows (e.g. LPT1, AUX, COM1, etc). Fixed to pad dangerous names with thee "at" signs (e.g. LPT1@@@, AUX@@@, COM1@@@, and so on).
1 parent 58ad559 commit e8e0d5c

File tree

6 files changed

+142
-8
lines changed

6 files changed

+142
-8
lines changed

include/my_sys.h

+1
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ extern File my_sopen(const char *path, int oflag, int shflag, int pmode);
608608
#define my_access access
609609
#endif
610610
extern int check_if_legal_filename(const char *path);
611+
extern int check_if_legal_tablename(const char *path);
611612

612613
#ifndef TERMINATE
613614
extern void TERMINATE(FILE *file);

mysql-test/r/ctype_filename.result

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
drop table if exists con, aux, nul, lpt1, com1, `clock$`;
2+
create table con (a int);
3+
drop table con;
4+
create table aux (a int);
5+
drop table aux;
6+
create table nul (a int);
7+
drop table nul;
8+
create table lpt1 (a int);
9+
drop table lpt1;
10+
create table com1 (a int);
11+
drop table com1;
12+
create table `clock$` (a int);
13+
drop table `clock$`;

mysql-test/t/ctype_filename.test

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--disable_warnings
2+
drop table if exists con, aux, nul, lpt1, com1, `clock$`;
3+
--enable_warnings
4+
5+
create table con (a int);
6+
drop table con;
7+
8+
create table aux (a int);
9+
drop table aux;
10+
11+
create table nul (a int);
12+
drop table nul;
13+
14+
create table lpt1 (a int);
15+
drop table lpt1;
16+
17+
create table com1 (a int);
18+
drop table com1;
19+
20+
create table `clock$` (a int);
21+
drop table `clock$`;

mysys/my_access.c

+92-5
Original file line numberDiff line numberDiff line change
@@ -54,24 +54,111 @@ int my_access(const char *path, int amode)
5454

5555
#endif /* __WIN__ */
5656

57-
#if defined(MSDOS) || defined(__WIN__) || defined(__EMX__)
5857

5958
/*
6059
List of file names that causes problem on windows
6160
6261
NOTE that one can also not have file names of type CON.TXT
62+
63+
NOTE: it is important to keep "CLOCK$" on the first place,
64+
we skip it in check_if_legal_tablename.
6365
*/
64-
6566
static const char *reserved_names[]=
6667
{
67-
"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6",
68-
"COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6",
69-
"LPT7", "LPT8", "LPT9", "CLOCK$",
68+
"CLOCK$",
69+
"CON", "PRN", "AUX", "NUL",
70+
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
71+
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
7072
NullS
7173
};
7274

7375
#define MAX_RESERVED_NAME_LENGTH 6
7476

77+
78+
/*
79+
Looks up a null-terminated string in a list,
80+
case insensitively.
81+
82+
SYNOPSIS
83+
str_list_find()
84+
list list of items
85+
str item to find
86+
87+
RETURN
88+
0 ok
89+
1 reserved file name
90+
*/
91+
static int str_list_find(const char **list, const char *str)
92+
{
93+
const char **name;
94+
for (name= list; *name; name++)
95+
{
96+
if (!my_strcasecmp(&my_charset_latin1, *name, str))
97+
return 1;
98+
}
99+
return 0;
100+
}
101+
102+
103+
/*
104+
A map for faster reserved_names lookup,
105+
helps to avoid loops in many cases.
106+
1 - can be the first letter
107+
2 - can be the second letter
108+
4 - can be the third letter
109+
*/
110+
static char reserved_map[256]=
111+
{
112+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
113+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
114+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* !"#$%&'()*+,-./ */
115+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0123456789:;<=>? */
116+
0,1,0,1,0,0,0,0,0,0,0,0,7,4,5,2, /* @ABCDEFGHIJKLMNO */
117+
3,0,2,0,4,2,0,0,4,0,0,0,0,0,0,0, /* PQRSTUVWXYZ[\]^_ */
118+
0,1,0,1,0,0,0,0,0,0,0,0,7,4,5,2, /* bcdefghijklmno */
119+
3,0,2,0,4,2,0,0,4,0,0,0,0,0,0,0, /* pqrstuvwxyz{|}~. */
120+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
121+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
122+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
123+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
124+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
125+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
126+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
127+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* ................ */
128+
};
129+
130+
131+
/*
132+
Check if a table name may cause problems
133+
134+
SYNOPSIS
135+
check_if_legal_tablename
136+
name Table name (without any extensions)
137+
138+
DESCRIPTION
139+
We don't check 'CLOCK$' because dollar sign is encoded as @0024,
140+
making table file name 'CLOCK@0024', which is safe.
141+
This is why we start lookup from the second element
142+
(i.e. &reserver_name[1])
143+
144+
RETURN
145+
0 ok
146+
1 reserved file name
147+
*/
148+
149+
int check_if_legal_tablename(const char *name)
150+
{
151+
DBUG_ENTER("check_if_legal_tablename");
152+
DBUG_RETURN((reserved_map[(uchar) name[0]] & 1) &&
153+
(reserved_map[(uchar) name[1]] & 2) &&
154+
(reserved_map[(uchar) name[2]] & 4) &&
155+
str_list_find(&reserved_names[1], name));
156+
}
157+
158+
159+
#if defined(MSDOS) || defined(__WIN__) || defined(__EMX__)
160+
161+
75162
/*
76163
Check if a path will access a reserverd file name that may cause problems
77164

sql/sql_table.cc

+10-3
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,19 @@ uint filename_to_tablename(const char *from, char *to, uint to_length)
7272

7373
uint tablename_to_filename(const char *from, char *to, uint to_length)
7474
{
75-
uint errors;
75+
uint errors, length;
7676
if (from[0] == '#' && !strncmp(from, MYSQL50_TABLE_NAME_PREFIX,
7777
MYSQL50_TABLE_NAME_PREFIX_LENGTH))
7878
return my_snprintf(to, to_length, "%s", from + 9);
79-
return strconvert(system_charset_info, from,
80-
&my_charset_filename, to, to_length, &errors);
79+
length= strconvert(system_charset_info, from,
80+
&my_charset_filename, to, to_length, &errors);
81+
if (check_if_legal_tablename(to) &&
82+
length + 4 < to_length)
83+
{
84+
memcpy(to + length, "@@@", 4);
85+
length+= 3;
86+
}
87+
return length;
8188
}
8289

8390

strings/ctype-utf8.c

+5
Original file line numberDiff line numberDiff line change
@@ -3943,6 +3943,11 @@ my_mb_wc_filename(CHARSET_INFO *cs __attribute__((unused)),
39433943
*pwc= touni[code];
39443944
return 3;
39453945
}
3946+
if (byte1 == '@' && byte2 == '@')
3947+
{
3948+
*pwc= 0;
3949+
return 3;
3950+
}
39463951
}
39473952

39483953
if (s + 4 > e)

0 commit comments

Comments
 (0)