~ubuntu-branches/ubuntu/trusty/mysql-5.6/trusty

« back to all changes in this revision

Viewing changes to mysys/mf_pack.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-02-12 11:54:27 UTC
  • Revision ID: package-import@ubuntu.com-20140212115427-oq6tfsqxl1wuwehi
Tags: upstream-5.6.15
ImportĀ upstreamĀ versionĀ 5.6.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2000, 2013, 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 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
#include "mysys_priv.h"
 
18
#include <m_string.h>
 
19
#ifdef HAVE_PWD_H
 
20
#include <pwd.h>
 
21
#endif
 
22
 
 
23
static char * expand_tilde(char **path);
 
24
 
 
25
        /* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
 
26
        /* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
 
27
        /* to may be == from */
 
28
 
 
29
void pack_dirname(char * to, const char *from)
 
30
{
 
31
  int cwd_err;
 
32
  size_t d_length,length,UNINIT_VAR(buff_length);
 
33
  char * start;
 
34
  char buff[FN_REFLEN];
 
35
  DBUG_ENTER("pack_dirname");
 
36
 
 
37
  (void) intern_filename(to,from);              /* Change to intern name */
 
38
 
 
39
#ifdef FN_DEVCHAR
 
40
  if ((start=strrchr(to,FN_DEVCHAR)) != 0)      /* Skip device part */
 
41
    start++;
 
42
  else
 
43
#endif
 
44
    start=to;
 
45
 
 
46
  if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
 
47
  {
 
48
    buff_length= strlen(buff);
 
49
    d_length= (size_t) (start-to);
 
50
    if ((start == to ||
 
51
         (buff_length == d_length && !memcmp(buff,start,d_length))) &&
 
52
        *start != FN_LIBCHAR && *start)
 
53
    {                                           /* Put current dir before */
 
54
      bchange((uchar*) to, d_length, (uchar*) buff, buff_length, strlen(to)+1);
 
55
    }
 
56
  }
 
57
 
 
58
  if ((d_length= cleanup_dirname(to,to)) != 0)
 
59
  {
 
60
    length=0;
 
61
    if (home_dir)
 
62
    {
 
63
      length= strlen(home_dir);
 
64
      if (home_dir[length-1] == FN_LIBCHAR)
 
65
        length--;                               /* Don't test last '/' */
 
66
    }
 
67
    if (length > 1 && length < d_length)
 
68
    {                                           /* test if /xx/yy -> ~/yy */
 
69
      if (memcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
 
70
      {
 
71
        to[0]=FN_HOMELIB;                       /* Filename begins with ~ */
 
72
        (void) strmov_overlapp(to+1,to+length);
 
73
      }
 
74
    }
 
75
    if (! cwd_err)
 
76
    {                                           /* Test if cwd is ~/... */
 
77
      if (length > 1 && length < buff_length)
 
78
      {
 
79
        if (memcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
 
80
        {
 
81
          buff[0]=FN_HOMELIB;
 
82
          (void) strmov_overlapp(buff+1,buff+length);
 
83
        }
 
84
      }
 
85
      if (is_prefix(to,buff))
 
86
      {
 
87
        length= strlen(buff);
 
88
        if (to[length])
 
89
          (void) strmov_overlapp(to,to+length); /* Remove everything before */
 
90
        else
 
91
        {
 
92
          to[0]= FN_CURLIB;                     /* Put ./ instead of cwd */
 
93
          to[1]= FN_LIBCHAR;
 
94
          to[2]= '\0';
 
95
        }
 
96
      }
 
97
    }
 
98
  }
 
99
  DBUG_PRINT("exit",("to: '%s'",to));
 
100
  DBUG_VOID_RETURN;
 
101
} /* pack_dirname */
 
102
 
 
103
 
 
104
/*
 
105
  remove unwanted chars from dirname
 
106
 
 
107
  SYNOPSIS
 
108
     cleanup_dirname()
 
109
     to         Store result here
 
110
     from       Dirname to fix.  May be same as to
 
111
 
 
112
  IMPLEMENTATION
 
113
  "/../" removes prev dir
 
114
  "/~/" removes all before ~
 
115
  //" is same as "/", except on Win32 at start of a file
 
116
  "/./" is removed
 
117
  Unpacks home_dir if "~/.." used
 
118
  Unpacks current dir if if "./.." used
 
119
 
 
120
  RETURN
 
121
    #  length of new name   
 
122
*/
 
123
 
 
124
size_t cleanup_dirname(register char *to, const char *from)
 
125
{
 
126
  reg5 size_t length;
 
127
  reg2 char * pos;
 
128
  reg3 char * from_ptr;
 
129
  reg4 char * start;
 
130
  char parent[5],                               /* for "FN_PARENTDIR" */
 
131
       buff[FN_REFLEN+1],*end_parentdir;
 
132
#ifdef BACKSLASH_MBTAIL
 
133
  CHARSET_INFO *fs= fs_character_set();
 
134
#endif
 
135
  DBUG_ENTER("cleanup_dirname");
 
136
  DBUG_PRINT("enter",("from: '%s'",from));
 
137
 
 
138
  start=buff;
 
139
  from_ptr=(char *) from;
 
140
#ifdef FN_DEVCHAR
 
141
  if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
 
142
  {                                             /* Skip device part */
 
143
    length=(size_t) (pos-from_ptr)+1;
 
144
    start=strnmov(buff,from_ptr,length); from_ptr+=length;
 
145
  }
 
146
#endif
 
147
 
 
148
  parent[0]=FN_LIBCHAR;
 
149
  length=(size_t) (strmov(parent+1,FN_PARENTDIR)-parent);
 
150
  for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
 
151
  {
 
152
#ifdef BACKSLASH_MBTAIL
 
153
    uint l;
 
154
    if (use_mb(fs) && (l= my_ismbchar(fs, from_ptr - 1, from_ptr + 2)))
 
155
    {
 
156
      for (l-- ; l ; *++pos= *from_ptr++, l--);
 
157
      start= pos + 1; /* Don't look inside multi-byte char */
 
158
      continue;
 
159
    }
 
160
#endif
 
161
    if (*pos == '/')
 
162
      *pos = FN_LIBCHAR;
 
163
    if (*pos == FN_LIBCHAR)
 
164
    {
 
165
      if ((size_t) (pos-start) > length && memcmp(pos-length,parent,length) == 0)
 
166
      {                                         /* If .../../; skip prev */
 
167
        pos-=length;
 
168
        if (pos != start)
 
169
        {                                        /* not /../ */
 
170
          pos--;
 
171
          if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR))
 
172
          {
 
173
            if (!home_dir)
 
174
            {
 
175
              pos+=length+1;                    /* Don't unpack ~/.. */
 
176
              continue;
 
177
            }
 
178
            pos=strmov(buff,home_dir)-1;        /* Unpacks ~/.. */
 
179
            if (*pos == FN_LIBCHAR)
 
180
              pos--;                            /* home ended with '/' */
 
181
          }
 
182
          if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR))
 
183
          {
 
184
            if (my_getwd(curr_dir,FN_REFLEN,MYF(0)))
 
185
            {
 
186
              pos+=length+1;                    /* Don't unpack ./.. */
 
187
              continue;
 
188
            }
 
189
            pos=strmov(buff,curr_dir)-1;        /* Unpacks ./.. */
 
190
            if (*pos == FN_LIBCHAR)
 
191
              pos--;                            /* home ended with '/' */
 
192
          }
 
193
          end_parentdir=pos;
 
194
          while (pos >= start && *pos != FN_LIBCHAR)    /* remove prev dir */
 
195
            pos--;
 
196
          if (pos[1] == FN_HOMELIB ||
 
197
              (pos >= start && memcmp(pos, parent, length) == 0))
 
198
          {                                     /* Don't remove ~user/ */
 
199
            pos=strmov(end_parentdir+1,parent);
 
200
            *pos=FN_LIBCHAR;
 
201
            continue;
 
202
          }
 
203
        }
 
204
      }
 
205
      else if ((size_t) (pos-start) == length-1 &&
 
206
               !memcmp(start,parent+1,length-1))
 
207
        start=pos;                              /* Starts with "../" */
 
208
      else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
 
209
      {
 
210
#ifdef FN_NETWORK_DRIVES
 
211
        if (pos-start != 1)
 
212
#endif
 
213
          pos--;                        /* Remove dupplicate '/' */
 
214
      }
 
215
      else if (pos-start > 1 && pos[-1] == FN_CURLIB && pos[-2] == FN_LIBCHAR)
 
216
        pos-=2;                                 /* Skip /./ */
 
217
      else if (pos > buff+1 && pos[-1] == FN_HOMELIB && pos[-2] == FN_LIBCHAR)
 
218
      {                                 /* Found ..../~/  */
 
219
        buff[0]=FN_HOMELIB;
 
220
        buff[1]=FN_LIBCHAR;
 
221
        start=buff; pos=buff+1;
 
222
      }
 
223
    }
 
224
  }
 
225
  (void) strmov(to,buff);
 
226
  DBUG_PRINT("exit",("to: '%s'",to));
 
227
  DBUG_RETURN((size_t) (pos-buff));
 
228
} /* cleanup_dirname */
 
229
 
 
230
 
 
231
/*
 
232
  On system where you don't have symbolic links, the following
 
233
  code will allow you to create a file: 
 
234
  directory-name.sym that should contain the real path
 
235
  to the directory.  This will be used if the directory name
 
236
  doesn't exists
 
237
*/
 
238
 
 
239
 
 
240
my_bool my_use_symdir=0;        /* Set this if you want to use symdirs */
 
241
 
 
242
#ifdef USE_SYMDIR
 
243
void symdirget(char *dir, my_bool *is_symdir)
 
244
{
 
245
  char buff[FN_REFLEN+1];
 
246
  char *pos=strend(dir);
 
247
  if (dir[0] && pos[-1] != FN_DEVCHAR && my_access(dir, F_OK))
 
248
  {
 
249
    File file;
 
250
    size_t length;
 
251
    char temp= *(--pos);            /* May be "/" or "\" */
 
252
    strmov(pos,".sym");
 
253
    file= my_open(dir, O_RDONLY, MYF(0));
 
254
    *pos++=temp; *pos=0;          /* Restore old filename */
 
255
    if (file >= 0)
 
256
    {
 
257
      if ((length= my_read(file, buff, sizeof(buff) - 1, MYF(0))) > 0)
 
258
      {
 
259
        for (pos= buff + length ;
 
260
             pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ;
 
261
             pos --);
 
262
 
 
263
        /* Ensure that the symlink ends with the directory symbol */
 
264
        if (pos == buff || pos[-1] != FN_LIBCHAR)
 
265
          *pos++=FN_LIBCHAR;
 
266
 
 
267
        strmake(dir,buff, (size_t) (pos-buff));
 
268
 
 
269
        *is_symdir= TRUE;
 
270
      }
 
271
      my_close(file, MYF(0));
 
272
    }
 
273
  }
 
274
}
 
275
#endif /* USE_SYMDIR */
 
276
 
 
277
 
 
278
/**
 
279
  Convert a directory name to a format which can be compared as strings
 
280
 
 
281
  @param to     result buffer, FN_REFLEN chars in length; may be == from
 
282
  @param from   'packed' directory name, in whatever format
 
283
  @returns      size of the normalized name
 
284
 
 
285
  @details
 
286
  - Ensures that last char is FN_LIBCHAR, unless it is FN_DEVCHAR
 
287
  - Uses cleanup_dirname
 
288
 
 
289
  It does *not* expand ~/ (although, see cleanup_dirname).  Nor does it do
 
290
  any case folding.  All case-insensitive normalization should be done by
 
291
  the caller.
 
292
*/
 
293
 
 
294
size_t normalize_dirname(char *to, const char *from)
 
295
{
 
296
  size_t length;
 
297
  char buff[FN_REFLEN];
 
298
  DBUG_ENTER("normalize_dirname");
 
299
 
 
300
  /*
 
301
    Despite the name, this actually converts the name to the system's
 
302
    format (TODO: name this properly).
 
303
  */
 
304
  (void) intern_filename(buff, from);
 
305
  length= strlen(buff);                 /* Fix that '/' is last */
 
306
  if (length &&
 
307
#ifdef FN_DEVCHAR
 
308
      buff[length - 1] != FN_DEVCHAR &&
 
309
#endif
 
310
      buff[length - 1] != FN_LIBCHAR && buff[length - 1] != '/')
 
311
  {
 
312
    /* we need reserve 2 bytes for the trailing slash and the zero */
 
313
    if (length >= sizeof (buff) - 1)
 
314
      length= sizeof (buff) - 2;
 
315
    buff[length]= FN_LIBCHAR;
 
316
    buff[length + 1]= '\0';
 
317
  }
 
318
 
 
319
  length=cleanup_dirname(to, buff);
 
320
 
 
321
  DBUG_RETURN(length);
 
322
}
 
323
 
 
324
 
 
325
/**
 
326
  Fixes a directory name so that can be used by open()
 
327
 
 
328
  @param to     Result buffer, FN_REFLEN characters. May be == from
 
329
  @param from   'Packed' directory name (may contain ~)
 
330
  @param[out] is_symdir  Indicates that directory in question turned
 
331
                         out to be fake .sym symbolic link, which was
 
332
                         resolved to real directory it points to.
 
333
 
 
334
  @details
 
335
  - Uses normalize_dirname()
 
336
  - Expands ~/... to home_dir/...
 
337
  - Resolves MySQL's fake "foo.sym" symbolic directory names (if USE_SYMDIR)
 
338
  - Changes a UNIX filename to system filename (replaces / with \ on windows)
 
339
 
 
340
  @returns
 
341
   Length of new directory name (= length of to)
 
342
*/
 
343
 
 
344
size_t unpack_dirname(char * to, const char *from, my_bool *is_symdir)
 
345
{
 
346
  size_t length, h_length;
 
347
  char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
 
348
  DBUG_ENTER("unpack_dirname");
 
349
 
 
350
  *is_symdir= FALSE;
 
351
 
 
352
  length= normalize_dirname(buff, from);
 
353
 
 
354
  if (buff[0] == FN_HOMELIB)
 
355
  {
 
356
    suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
 
357
    if (tilde_expansion)
 
358
    {
 
359
      length-= (size_t) (suffix-buff)-1;
 
360
      if (length+(h_length= strlen(tilde_expansion)) <= FN_REFLEN)
 
361
      {
 
362
        if ((h_length > 0) && (tilde_expansion[h_length-1] == FN_LIBCHAR))
 
363
          h_length--;
 
364
        if (buff+h_length < suffix)
 
365
          bmove(buff+h_length,suffix,length);
 
366
        else
 
367
          bmove_upp((uchar*) buff+h_length+length, (uchar*) suffix+length, length);
 
368
        bmove(buff,tilde_expansion,h_length);
 
369
      }
 
370
    }
 
371
  }
 
372
#ifdef USE_SYMDIR
 
373
  if (my_use_symdir)
 
374
    symdirget(buff, is_symdir);
 
375
#endif
 
376
  DBUG_RETURN(system_filename(to,buff));        /* Fix for open */
 
377
} /* unpack_dirname */
 
378
 
 
379
 
 
380
        /* Expand tilde to home or user-directory */
 
381
        /* Path is reset to point at FN_LIBCHAR after ~xxx */
 
382
 
 
383
static char * expand_tilde(char **path)
 
384
{
 
385
  if (path[0][0] == FN_LIBCHAR)
 
386
    return home_dir;                    /* ~/ expanded to home */
 
387
#ifdef HAVE_GETPWNAM
 
388
  {
 
389
    char *str,save;
 
390
    struct passwd *user_entry;
 
391
 
 
392
    if (!(str=strchr(*path,FN_LIBCHAR)))
 
393
      str=strend(*path);
 
394
    save= *str; *str= '\0';
 
395
    user_entry=getpwnam(*path);
 
396
    *str=save;
 
397
    endpwent();
 
398
    if (user_entry)
 
399
    {
 
400
      *path=str;
 
401
      return user_entry->pw_dir;
 
402
    }
 
403
  }
 
404
#endif
 
405
  return (char *) 0;
 
406
}
 
407
 
 
408
 
 
409
/*
 
410
  Fix filename so it can be used by open, create
 
411
 
 
412
  SYNOPSIS
 
413
    unpack_filename()
 
414
    to          Store result here. Must be at least of size FN_REFLEN.
 
415
    from        Filename in unix format (with ~)
 
416
 
 
417
  RETURN
 
418
    # length of to
 
419
 
 
420
  NOTES
 
421
    to may be == from
 
422
    ~ will only be expanded if total length < FN_REFLEN
 
423
*/
 
424
 
 
425
 
 
426
size_t unpack_filename(char * to, const char *from)
 
427
{
 
428
  size_t length, n_length, buff_length;
 
429
  char buff[FN_REFLEN];
 
430
  my_bool not_used;
 
431
  DBUG_ENTER("unpack_filename");
 
432
 
 
433
  length=dirname_part(buff, from, &buff_length);/* copy & convert dirname */
 
434
  n_length=unpack_dirname(buff, buff, &not_used);
 
435
  if (n_length+strlen(from+length) < FN_REFLEN)
 
436
  {
 
437
    (void) strmov(buff+n_length,from+length);
 
438
    length= system_filename(to,buff);           /* Fix to usably filename */
 
439
  }
 
440
  else
 
441
    length= system_filename(to,from);           /* Fix to usably filename */
 
442
  DBUG_RETURN(length);
 
443
} /* unpack_filename */
 
444
 
 
445
 
 
446
        /* Convert filename (unix standard) to system standard */
 
447
        /* Used before system command's like open(), create() .. */
 
448
        /* Returns used length of to; total length should be FN_REFLEN */
 
449
 
 
450
size_t system_filename(char *to, const char *from)
 
451
{
 
452
  return (size_t) (strmake(to,from,FN_REFLEN-1)-to);
 
453
}
 
454
 
 
455
        /* Fix a filename to intern (UNIX format) */
 
456
 
 
457
char *intern_filename(char *to, const char *from)
 
458
{
 
459
  size_t length, to_length;
 
460
  char buff[FN_REFLEN];
 
461
  if (from == to)
 
462
  {                                             /* Dirname may destroy from */
 
463
    (void) strnmov(buff, from, FN_REFLEN);
 
464
    from=buff;
 
465
  }
 
466
  length= dirname_part(to, from, &to_length);   /* Copy dirname & fix chars */
 
467
  (void) strnmov(to + to_length, from + length, FN_REFLEN - to_length);
 
468
  return (to);
 
469
} /* intern_filename */