~drizzle-trunk/drizzle/development

1 by brian
clean slate
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"
212.5.18 by Monty Taylor
Moved m_ctype, m_string and my_bitmap. Removed t_ctype.
17
#include <mystrings/m_string.h>
53.2.7 by Monty Taylor
Changes so that removal of duplicate curr_dir from my_sys.h work.
18
#include "my_static.h"
1 by brian
clean slate
19
#ifdef HAVE_PWD_H
20
#include <pwd.h>
21
#endif
22
#ifdef VMS
23
#include <rms.h>
24
#include <iodef.h>
25
#include <descrip.h>
26
#endif /* VMS */
27
28
static char * expand_tilde(char * *path);
29
30
	/* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
31
	/* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
32
	/* to may be == from */
33
34
void pack_dirname(char * to, const char *from)
35
{
36
  int cwd_err;
37
  size_t d_length,length,buff_length= 0;
38
  char * start;
39
  char buff[FN_REFLEN];
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 ||
212.6.3 by Mats Kindahl
Removing deprecated functions from code and replacing them with C99 equivalents:
55
	 (buff_length == d_length && !memcmp(buff,start,d_length))) &&
1 by brian
clean slate
56
	*start != FN_LIBCHAR && *start)
57
    {						/* Put current dir before */
481 by Brian Aker
Remove all of uchar.
58
      bchange((unsigned char*) to, d_length, (unsigned char*) buff, buff_length, strlen(to)+1);
1 by brian
clean slate
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 */
212.6.3 by Mats Kindahl
Removing deprecated functions from code and replacing them with C99 equivalents:
73
      if (memcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
1 by brian
clean slate
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
      {
212.6.3 by Mats Kindahl
Removing deprecated functions from code and replacing them with C99 equivalents:
83
	if (memcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
1 by brian
clean slate
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
  }
51.3.21 by Jay Pipes
Phase 8 - Remove DBUG from mysys
103
  return;
1 by brian
clean slate
104
} /* pack_dirname */
105
106
107
/*
108
  remove unwanted chars from dirname
109
110
  SYNOPSIS
111
     cleanup_dirname()
112
     to		Store result here
113
     from	Dirname to fix.  May be same as to
114
115
  IMPLEMENTATION
116
  "/../" removes prev dir
117
  "/~/" removes all before ~
118
  //" is same as "/", except on Win32 at start of a file
119
  "/./" is removed
120
  Unpacks home_dir if "~/.." used
121
  Unpacks current dir if if "./.." used
122
123
  RETURN
124
    #  length of new name   
125
*/
126
127
size_t cleanup_dirname(register char *to, const char *from)
128
{
129
  register size_t length;
130
  register char * pos;
266.7.15 by Andy Lester
Added a proper const qualifer.
131
  register const char * from_ptr;
1 by brian
clean slate
132
  register char * start;
133
  char parent[5],				/* for "FN_PARENTDIR" */
134
       buff[FN_REFLEN+1],*end_parentdir;
135
#ifdef BACKSLASH_MBTAIL
136
  CHARSET_INFO *fs= fs_character_set();
137
#endif
138
139
  start=buff;
266.7.15 by Andy Lester
Added a proper const qualifer.
140
  from_ptr= from;
1 by brian
clean slate
141
#ifdef FN_DEVCHAR
142
  if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
143
  {						/* Skip device part */
144
    length=(size_t) (pos-from_ptr)+1;
411.1.1 by Brian Aker
Work on removing GNU specific calls.
145
    start=my_stpncpy(buff,from_ptr,length); from_ptr+=length;
1 by brian
clean slate
146
  }
147
#endif
148
149
  parent[0]=FN_LIBCHAR;
411.1.1 by Brian Aker
Work on removing GNU specific calls.
150
  length=(size_t) (my_stpcpy(parent+1,FN_PARENTDIR)-parent);
1 by brian
clean slate
151
  for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
152
  {
153
#ifdef BACKSLASH_MBTAIL
482 by Brian Aker
Remove uint.
154
    uint32_t l;
1 by brian
clean slate
155
    if (use_mb(fs) && (l= my_ismbchar(fs, from_ptr - 1, from_ptr + 2)))
156
    {
157
      for (l-- ; l ; *++pos= *from_ptr++, l--);
158
      start= pos + 1; /* Don't look inside multi-byte char */
159
      continue;
160
    }
161
#endif
162
    if (*pos == '/')
163
      *pos = FN_LIBCHAR;
164
    if (*pos == FN_LIBCHAR)
165
    {
212.6.3 by Mats Kindahl
Removing deprecated functions from code and replacing them with C99 equivalents:
166
      if ((size_t) (pos-start) > length &&
167
          memcmp(pos-length,parent,length) == 0)
1 by brian
clean slate
168
      {						/* If .../../; skip prev */
169
	pos-=length;
170
	if (pos != start)
171
	{					 /* not /../ */
172
	  pos--;
173
	  if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR))
174
	  {
175
	    if (!home_dir)
176
	    {
177
	      pos+=length+1;			/* Don't unpack ~/.. */
178
	      continue;
179
	    }
411.1.1 by Brian Aker
Work on removing GNU specific calls.
180
	    pos=my_stpcpy(buff,home_dir)-1;	/* Unpacks ~/.. */
1 by brian
clean slate
181
	    if (*pos == FN_LIBCHAR)
182
	      pos--;				/* home ended with '/' */
183
	  }
184
	  if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR))
185
	  {
186
	    if (my_getwd(curr_dir,FN_REFLEN,MYF(0)))
187
	    {
188
	      pos+=length+1;			/* Don't unpack ./.. */
189
	      continue;
190
	    }
411.1.1 by Brian Aker
Work on removing GNU specific calls.
191
	    pos=my_stpcpy(buff,curr_dir)-1;	/* Unpacks ./.. */
1 by brian
clean slate
192
	    if (*pos == FN_LIBCHAR)
193
	      pos--;				/* home ended with '/' */
194
	  }
195
	  end_parentdir=pos;
196
	  while (pos >= start && *pos != FN_LIBCHAR)	/* remove prev dir */
197
	    pos--;
212.6.3 by Mats Kindahl
Removing deprecated functions from code and replacing them with C99 equivalents:
198
	  if (pos[1] == FN_HOMELIB || memcmp(pos,parent,length) == 0)
1 by brian
clean slate
199
	  {					/* Don't remove ~user/ */
411.1.1 by Brian Aker
Work on removing GNU specific calls.
200
	    pos=my_stpcpy(end_parentdir+1,parent);
1 by brian
clean slate
201
	    *pos=FN_LIBCHAR;
202
	    continue;
203
	  }
204
	}
205
      }
206
      else if ((size_t) (pos-start) == length-1 &&
212.6.3 by Mats Kindahl
Removing deprecated functions from code and replacing them with C99 equivalents:
207
	       !memcmp(start,parent+1,length-1))
1 by brian
clean slate
208
	start=pos;				/* Starts with "../" */
209
      else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
210
      {
211
#ifdef FN_NETWORK_DRIVES
212
	if (pos-start != 1)
213
#endif
214
	  pos--;			/* Remove dupplicate '/' */
215
      }
216
      else if (pos-start > 1 && pos[-1] == FN_CURLIB && pos[-2] == FN_LIBCHAR)
217
	pos-=2;					/* Skip /./ */
218
      else if (pos > buff+1 && pos[-1] == FN_HOMELIB && pos[-2] == FN_LIBCHAR)
219
      {					/* Found ..../~/  */
220
	buff[0]=FN_HOMELIB;
221
	buff[1]=FN_LIBCHAR;
222
	start=buff; pos=buff+1;
223
      }
224
    }
225
  }
411.1.1 by Brian Aker
Work on removing GNU specific calls.
226
  (void) my_stpcpy(to,buff);
51.3.21 by Jay Pipes
Phase 8 - Remove DBUG from mysys
227
  return((size_t) (pos-buff));
1 by brian
clean slate
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
146 by Brian Aker
my_bool cleanup.
240
bool my_use_symdir=0;	/* Set this if you want to use symdirs */
1 by brian
clean slate
241
242
#ifdef USE_SYMDIR
243
void symdirget(char *dir)
244
{
245
  char buff[FN_REFLEN];
376 by Brian Aker
strend remove
246
  char *pos= strchr(dir, '\0');
1 by brian
clean slate
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 "\" */
411.1.1 by Brian Aker
Work on removing GNU specific calls.
252
    my_stpcpy(pos,".sym");
1 by brian
clean slate
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), 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
      my_close(file, MYF(0));
270
    }
271
  }
272
}
273
#endif /* USE_SYMDIR */
274
275
276
/*
277
  Fixes a directroy name so that can be used by open()
278
279
  SYNOPSIS
280
    unpack_dirname()
281
    to			result-buffer, FN_REFLEN characters. may be == from
282
    from		'Packed' directory name (may contain ~)
283
284
 IMPLEMENTATION
285
  Make that last char of to is '/' if from not empty and
286
  from doesn't end in FN_DEVCHAR
287
  Uses cleanup_dirname and changes ~/.. to home_dir/..
288
289
  Changes a UNIX filename to system filename (replaces / with \ on windows)
290
291
  RETURN
292
   Length of new directory name (= length of to)
293
*/
294
295
size_t unpack_dirname(char * to, const char *from)
296
{
297
  size_t length, h_length;
298
  char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
299
300
  (void) intern_filename(buff,from);	    /* Change to intern name */
301
  length= strlen(buff);                     /* Fix that '/' is last */
302
  if (length &&
303
#ifdef FN_DEVCHAR
304
      buff[length-1] != FN_DEVCHAR &&
305
#endif
306
      buff[length-1] != FN_LIBCHAR && buff[length-1] != '/')
307
  {
308
    buff[length]=FN_LIBCHAR;
309
    buff[length+1]= '\0';
310
  }
311
312
  length=cleanup_dirname(buff,buff);
313
  if (buff[0] == FN_HOMELIB)
314
  {
315
    suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
316
    if (tilde_expansion)
317
    {
318
      length-= (size_t) (suffix-buff)-1;
319
      if (length+(h_length= strlen(tilde_expansion)) <= FN_REFLEN)
320
      {
321
	if (tilde_expansion[h_length-1] == FN_LIBCHAR)
322
	  h_length--;
323
	if (buff+h_length < suffix)
212.6.3 by Mats Kindahl
Removing deprecated functions from code and replacing them with C99 equivalents:
324
	  memcpy(buff+h_length, suffix, length);
1 by brian
clean slate
325
	else
481 by Brian Aker
Remove all of uchar.
326
	  bmove_upp((unsigned char*) buff+h_length+length, (unsigned char*) suffix+length, length);
212.6.3 by Mats Kindahl
Removing deprecated functions from code and replacing them with C99 equivalents:
327
	memcpy(buff, tilde_expansion, h_length);
1 by brian
clean slate
328
      }
329
    }
330
  }
331
#ifdef USE_SYMDIR
332
  if (my_use_symdir)
333
    symdirget(buff);
334
#endif
51.3.21 by Jay Pipes
Phase 8 - Remove DBUG from mysys
335
  return(system_filename(to,buff));	/* Fix for open */
1 by brian
clean slate
336
} /* unpack_dirname */
337
338
339
	/* Expand tilde to home or user-directory */
340
	/* Path is reset to point at FN_LIBCHAR after ~xxx */
341
342
static char * expand_tilde(char * *path)
343
{
344
  if (path[0][0] == FN_LIBCHAR)
345
    return home_dir;			/* ~/ expanded to home */
346
#ifdef HAVE_GETPWNAM
347
  {
348
    char *str,save;
349
    struct passwd *user_entry;
350
351
    if (!(str=strchr(*path,FN_LIBCHAR)))
376 by Brian Aker
strend remove
352
      str= strchr(*path, '\0');
1 by brian
clean slate
353
    save= *str; *str= '\0';
354
    user_entry=getpwnam(*path);
355
    *str=save;
356
    endpwent();
357
    if (user_entry)
358
    {
359
      *path=str;
360
      return user_entry->pw_dir;
361
    }
362
  }
363
#endif
266.6.8 by Andy Lester
use NULL, not 0
364
  return NULL;
1 by brian
clean slate
365
}
366
367
368
/*
369
  Fix filename so it can be used by open, create
370
371
  SYNOPSIS
372
    unpack_filename()
373
    to		Store result here. Must be at least of size FN_REFLEN.
374
    from	Filename in unix format (with ~)
375
376
  RETURN
377
    # length of to
378
379
  NOTES
380
    to may be == from
381
    ~ will only be expanded if total length < FN_REFLEN
382
*/
383
384
385
size_t unpack_filename(char * to, const char *from)
386
{
387
  size_t length, n_length, buff_length;
388
  char buff[FN_REFLEN];
389
390
  length=dirname_part(buff, from, &buff_length);/* copy & convert dirname */
391
  n_length=unpack_dirname(buff,buff);
392
  if (n_length+strlen(from+length) < FN_REFLEN)
393
  {
411.1.1 by Brian Aker
Work on removing GNU specific calls.
394
    (void) my_stpcpy(buff+n_length,from+length);
1 by brian
clean slate
395
    length= system_filename(to,buff);		/* Fix to usably filename */
396
  }
397
  else
398
    length= system_filename(to,from);		/* Fix to usably filename */
51.3.21 by Jay Pipes
Phase 8 - Remove DBUG from mysys
399
  return(length);
1 by brian
clean slate
400
} /* unpack_filename */
401
402
403
	/* Convert filename (unix standard) to system standard */
404
	/* Used before system command's like open(), create() .. */
405
	/* Returns used length of to; total length should be FN_REFLEN */
406
407
size_t system_filename(char * to, const char *from)
408
{
409
#ifndef FN_C_BEFORE_DIR
410
  return (size_t) (strmake(to,from,FN_REFLEN-1)-to);
411
#else	/* VMS */
412
413
	/* change 'dev:lib/xxx' to 'dev:[lib]xxx' */
414
	/* change 'dev:xxx' to 'dev:xxx' */
415
	/* change './xxx' to 'xxx' */
416
	/* change './lib/' or lib/ to '[.lib]' */
417
	/* change '/x/y/z to '[x.y]x' */
418
	/* change 'dev:/x' to 'dev:[000000]x' */
419
420
  int libchar_found;
421
  size_t length;
422
  char * to_pos,from_pos,pos;
423
  char buff[FN_REFLEN];
424
425
  libchar_found=0;
411.1.1 by Brian Aker
Work on removing GNU specific calls.
426
  (void) my_stpcpy(buff,from);			 /* If to == from */
1 by brian
clean slate
427
  from_pos= buff;
428
  if ((pos=strrchr(from_pos,FN_DEVCHAR)))	/* Skip device part */
429
  {
430
    pos++;
411.1.1 by Brian Aker
Work on removing GNU specific calls.
431
    to_pos=my_stpncpy(to,from_pos,(size_t) (pos-from_pos));
1 by brian
clean slate
432
    from_pos=pos;
433
  }
434
  else
435
    to_pos=to;
436
437
  if (from_pos[0] == FN_CURLIB && from_pos[1] == FN_LIBCHAR)
438
    from_pos+=2;				/* Skip './' */
439
  if (strchr(from_pos,FN_LIBCHAR))
440
  {
441
    *(to_pos++) = FN_C_BEFORE_DIR;
77.1.91 by Monty Taylor
Removed strinstr. It was only used twice in once place in mf_pack... and there
442
    if (strstr(from_pos,FN_ROOTDIR) == from_pos)
1 by brian
clean slate
443
    {
444
      from_pos+=strlen(FN_ROOTDIR);		/* Actually +1 but... */
445
      if (! strchr(from_pos,FN_LIBCHAR))
446
      {						/* No dir, use [000000] */
411.1.1 by Brian Aker
Work on removing GNU specific calls.
447
	to_pos=my_stpcpy(to_pos,FN_C_ROOT_DIR);
1 by brian
clean slate
448
	libchar_found++;
449
      }
450
    }
451
    else
452
      *(to_pos++)=FN_C_DIR_SEP;			/* '.' gives current dir */
453
454
    while ((pos=strchr(from_pos,FN_LIBCHAR)))
455
    {
456
      if (libchar_found++)
457
	*(to_pos++)=FN_C_DIR_SEP;		/* Add '.' between dirs */
77.1.91 by Monty Taylor
Removed strinstr. It was only used twice in once place in mf_pack... and there
458
      if (strstr(from_pos,FN_PARENTDIR) == from_pos &&
1 by brian
clean slate
459
	  from_pos+strlen(FN_PARENTDIR) == pos)
411.1.1 by Brian Aker
Work on removing GNU specific calls.
460
	to_pos=my_stpcpy(to_pos,FN_C_PARENT_DIR);	/* Found '../' */
1 by brian
clean slate
461
      else
411.1.1 by Brian Aker
Work on removing GNU specific calls.
462
	to_pos=my_stpncpy(to_pos,from_pos,(size_t) (pos-from_pos));
1 by brian
clean slate
463
      from_pos=pos+1;
464
    }
465
    *(to_pos++)=FN_C_AFTER_DIR;
466
  }
411.1.1 by Brian Aker
Work on removing GNU specific calls.
467
  length= (size_t) (my_stpcpy(to_pos,from_pos)-to);
51.3.21 by Jay Pipes
Phase 8 - Remove DBUG from mysys
468
  return(length);
1 by brian
clean slate
469
#endif
470
} /* system_filename */
471
472
473
	/* Fix a filename to intern (UNIX format) */
474
475
char *intern_filename(char *to, const char *from)
476
{
477
  size_t length, to_length;
478
  char buff[FN_REFLEN];
479
  if (from == to)
480
  {						/* Dirname may destroy from */
411.1.1 by Brian Aker
Work on removing GNU specific calls.
481
    my_stpcpy(buff,from);
1 by brian
clean slate
482
    from=buff;
483
  }
484
  length= dirname_part(to, from, &to_length);	/* Copy dirname & fix chars */
411.1.1 by Brian Aker
Work on removing GNU specific calls.
485
  (void) my_stpcpy(to + to_length,from+length);
1 by brian
clean slate
486
  return (to);
487
} /* intern_filename */