~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/mf_pack.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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