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