mariadb/mysys/mf_pack.c
monty@mysql.com/narttu.mysql.fi 088e2395f1 WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:

- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t

Removed declaration of byte, gptr, my_string, my_size_t and size_s. 

Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
  instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
  as this requires fewer casts in the code and is more in line with how the
  standard functions work.
- Added extra length argument to dirname_part() to return the length of the
  created string.
- Changed (at least) following functions to take uchar* as argument:
  - db_dump()
  - my_net_write()
  - net_write_command()
  - net_store_data()
  - DBUG_DUMP()
  - decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
  argument to my_uncompress() from a pointer to a value as we only return
  one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
  the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
  casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.

Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
  needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
  explicitely as this conflict was often hided by casting the function to
  hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
  get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
  size_t. This was needed to properly detect errors (which are
  returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
  (portability fix)
- Removed windows specific code to restore cursor position as this
  causes slowdown on windows and we should not mix read() and pread()
  calls anyway as this is not thread safe. Updated function comment to
  reflect this. Changed function that depended on original behavior of
  my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
  m_size is the number of elements in the array, not a string/memory
  length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
  Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
  - Replaced some calls to alloc_root + memcpy to use
    strmake_root()/strdup_root().
  - Changed some calls from memdup() to strmake() (Safety fix)
  - Simpler loops in client-simple.c
2007-05-10 12:59:39 +03:00

495 lines
13 KiB
C

/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysys_priv.h"
#include <m_string.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#ifdef VMS
#include <rms.h>
#include <iodef.h>
#include <descrip.h>
#endif /* VMS */
static char * NEAR_F expand_tilde(char * *path);
/* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
/* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
/* to may be == from */
void pack_dirname(char * to, const char *from)
{
int cwd_err;
size_t d_length,length,buff_length;
char * start;
char buff[FN_REFLEN];
DBUG_ENTER("pack_dirname");
LINT_INIT(buff_length);
(void) intern_filename(to,from); /* Change to intern name */
#ifdef FN_DEVCHAR
if ((start=strrchr(to,FN_DEVCHAR)) != 0) /* Skip device part */
start++;
else
#endif
start=to;
if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
{
buff_length= strlen(buff);
d_length= (size_t) (start-to);
if ((start == to ||
(buff_length == d_length && !bcmp(buff,start,d_length))) &&
*start != FN_LIBCHAR && *start)
{ /* Put current dir before */
bchange(to,d_length,buff,buff_length,strlen(to)+1);
}
}
if ((d_length= cleanup_dirname(to,to)) != 0)
{
length=0;
if (home_dir)
{
length= strlen(home_dir);
if (home_dir[length-1] == FN_LIBCHAR)
length--; /* Don't test last '/' */
}
if (length > 1 && length < d_length)
{ /* test if /xx/yy -> ~/yy */
if (bcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
{
to[0]=FN_HOMELIB; /* Filename begins with ~ */
(void) strmov_overlapp(to+1,to+length);
}
}
if (! cwd_err)
{ /* Test if cwd is ~/... */
if (length > 1 && length < buff_length)
{
if (bcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
{
buff[0]=FN_HOMELIB;
(void) strmov_overlapp(buff+1,buff+length);
}
}
if (is_prefix(to,buff))
{
length= strlen(buff);
if (to[length])
(void) strmov_overlapp(to,to+length); /* Remove everything before */
else
{
to[0]= FN_CURLIB; /* Put ./ instead of cwd */
to[1]= FN_LIBCHAR;
to[2]= '\0';
}
}
}
}
DBUG_PRINT("exit",("to: '%s'",to));
DBUG_VOID_RETURN;
} /* pack_dirname */
/*
remove unwanted chars from dirname
SYNOPSIS
cleanup_dirname()
to Store result here
from Dirname to fix. May be same as to
IMPLEMENTATION
"/../" removes prev dir
"/~/" removes all before ~
//" is same as "/", except on Win32 at start of a file
"/./" is removed
Unpacks home_dir if "~/.." used
Unpacks current dir if if "./.." used
RETURN
# length of new name
*/
size_t cleanup_dirname(register char *to, const char *from)
{
reg5 size_t length;
reg2 char * pos;
reg3 char * from_ptr;
reg4 char * start;
char parent[5], /* for "FN_PARENTDIR" */
buff[FN_REFLEN+1],*end_parentdir;
#ifdef BACKSLASH_MBTAIL
CHARSET_INFO *fs= fs_character_set();
#endif
DBUG_ENTER("cleanup_dirname");
DBUG_PRINT("enter",("from: '%s'",from));
start=buff;
from_ptr=(char *) from;
#ifdef FN_DEVCHAR
if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
{ /* Skip device part */
length=(size_t) (pos-from_ptr)+1;
start=strnmov(buff,from_ptr,length); from_ptr+=length;
}
#endif
parent[0]=FN_LIBCHAR;
length=(size_t) (strmov(parent+1,FN_PARENTDIR)-parent);
for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
{
#ifdef BACKSLASH_MBTAIL
uint l;
if (use_mb(fs) && (l= my_ismbchar(fs, from_ptr - 1, from_ptr + 2)))
{
for (l-- ; l ; *++pos= *from_ptr++, l--);
start= pos + 1; /* Don't look inside multi-byte char */
continue;
}
#endif
if (*pos == '/')
*pos = FN_LIBCHAR;
if (*pos == FN_LIBCHAR)
{
if ((size_t) (pos-start) > length && bcmp(pos-length,parent,length) == 0)
{ /* If .../../; skip prev */
pos-=length;
if (pos != start)
{ /* not /../ */
pos--;
if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR))
{
if (!home_dir)
{
pos+=length+1; /* Don't unpack ~/.. */
continue;
}
pos=strmov(buff,home_dir)-1; /* Unpacks ~/.. */
if (*pos == FN_LIBCHAR)
pos--; /* home ended with '/' */
}
if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR))
{
if (my_getwd(curr_dir,FN_REFLEN,MYF(0)))
{
pos+=length+1; /* Don't unpack ./.. */
continue;
}
pos=strmov(buff,curr_dir)-1; /* Unpacks ./.. */
if (*pos == FN_LIBCHAR)
pos--; /* home ended with '/' */
}
end_parentdir=pos;
while (pos >= start && *pos != FN_LIBCHAR) /* remove prev dir */
pos--;
if (pos[1] == FN_HOMELIB || bcmp(pos,parent,length) == 0)
{ /* Don't remove ~user/ */
pos=strmov(end_parentdir+1,parent);
*pos=FN_LIBCHAR;
continue;
}
}
}
else if ((size_t) (pos-start) == length-1 &&
!bcmp(start,parent+1,length-1))
start=pos; /* Starts with "../" */
else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
{
#ifdef FN_NETWORK_DRIVES
if (pos-start != 1)
#endif
pos--; /* Remove dupplicate '/' */
}
else if (pos-start > 1 && pos[-1] == FN_CURLIB && pos[-2] == FN_LIBCHAR)
pos-=2; /* Skip /./ */
else if (pos > buff+1 && pos[-1] == FN_HOMELIB && pos[-2] == FN_LIBCHAR)
{ /* Found ..../~/ */
buff[0]=FN_HOMELIB;
buff[1]=FN_LIBCHAR;
start=buff; pos=buff+1;
}
}
}
(void) strmov(to,buff);
DBUG_PRINT("exit",("to: '%s'",to));
DBUG_RETURN((size_t) (pos-buff));
} /* cleanup_dirname */
/*
On system where you don't have symbolic links, the following
code will allow you to create a file:
directory-name.sym that should contain the real path
to the directory. This will be used if the directory name
doesn't exists
*/
my_bool my_use_symdir=0; /* Set this if you want to use symdirs */
#ifdef USE_SYMDIR
void symdirget(char *dir)
{
char buff[FN_REFLEN];
char *pos=strend(dir);
if (dir[0] && pos[-1] != FN_DEVCHAR && my_access(dir, F_OK))
{
File file;
size_t length;
char temp= *(--pos); /* May be "/" or "\" */
strmov(pos,".sym");
file= my_open(dir, O_RDONLY, MYF(0));
*pos++=temp; *pos=0; /* Restore old filename */
if (file >= 0)
{
if ((length= my_read(file, buff, sizeof(buff), MYF(0))) > 0)
{
for (pos= buff + length ;
pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ;
pos --);
/* Ensure that the symlink ends with the directory symbol */
if (pos == buff || pos[-1] != FN_LIBCHAR)
*pos++=FN_LIBCHAR;
strmake(dir,buff, (size_t) (pos-buff));
}
my_close(file, MYF(0));
}
}
}
#endif /* USE_SYMDIR */
/*
Fixes a directroy name so that can be used by open()
SYNOPSIS
unpack_dirname()
to Store result here. May be = from
from 'Packed' directory name (may contain ~)
IMPLEMENTATION
Make that last char of to is '/' if from not empty and
from doesn't end in FN_DEVCHAR
Uses cleanup_dirname and changes ~/.. to home_dir/..
Changes a UNIX filename to system filename (replaces / with \ on windows)
RETURN
Length of new directory name (= length of to)
*/
size_t unpack_dirname(char * to, const char *from)
{
size_t length, h_length;
char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
DBUG_ENTER("unpack_dirname");
(void) intern_filename(buff,from); /* Change to intern name */
length= strlen(buff); /* Fix that '/' is last */
if (length &&
#ifdef FN_DEVCHAR
buff[length-1] != FN_DEVCHAR &&
#endif
buff[length-1] != FN_LIBCHAR && buff[length-1] != '/')
{
buff[length]=FN_LIBCHAR;
buff[length+1]= '\0';
}
length=cleanup_dirname(buff,buff);
if (buff[0] == FN_HOMELIB)
{
suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
if (tilde_expansion)
{
length-= (size_t) (suffix-buff)-1;
if (length+(h_length= strlen(tilde_expansion)) <= FN_REFLEN)
{
if (tilde_expansion[h_length-1] == FN_LIBCHAR)
h_length--;
if (buff+h_length < suffix)
bmove(buff+h_length,suffix,length);
else
bmove_upp(buff+h_length+length,suffix+length,length);
bmove(buff,tilde_expansion,h_length);
}
}
}
#ifdef USE_SYMDIR
if (my_use_symdir)
symdirget(buff);
#endif
DBUG_RETURN(system_filename(to,buff)); /* Fix for open */
} /* unpack_dirname */
/* Expand tilde to home or user-directory */
/* Path is reset to point at FN_LIBCHAR after ~xxx */
static char * NEAR_F expand_tilde(char * *path)
{
if (path[0][0] == FN_LIBCHAR)
return home_dir; /* ~/ expanded to home */
#ifdef HAVE_GETPWNAM
{
char *str,save;
struct passwd *user_entry;
if (!(str=strchr(*path,FN_LIBCHAR)))
str=strend(*path);
save= *str; *str= '\0';
user_entry=getpwnam(*path);
*str=save;
endpwent();
if (user_entry)
{
*path=str;
return user_entry->pw_dir;
}
}
#endif
return (char *) 0;
}
/*
Fix filename so it can be used by open, create
SYNOPSIS
unpack_filename()
to Store result here. Must be at least of size FN_REFLEN.
from Filename in unix format (with ~)
RETURN
# length of to
NOTES
to may be == from
~ will only be expanded if total length < FN_REFLEN
*/
size_t unpack_filename(char * to, const char *from)
{
size_t length, n_length, buff_length;
char buff[FN_REFLEN];
DBUG_ENTER("unpack_filename");
length=dirname_part(buff, from, &buff_length);/* copy & convert dirname */
n_length=unpack_dirname(buff,buff);
if (n_length+strlen(from+length) < FN_REFLEN)
{
(void) strmov(buff+n_length,from+length);
length= system_filename(to,buff); /* Fix to usably filename */
}
else
length= system_filename(to,from); /* Fix to usably filename */
DBUG_RETURN(length);
} /* unpack_filename */
/* Convert filename (unix standard) to system standard */
/* Used before system command's like open(), create() .. */
/* Returns length of to */
size_t system_filename(char * to, const char *from)
{
#ifndef FN_C_BEFORE_DIR
return (size_t) (strmake(to,from,FN_REFLEN-1)-to);
#else /* VMS */
/* change 'dev:lib/xxx' to 'dev:[lib]xxx' */
/* change 'dev:xxx' to 'dev:xxx' */
/* change './xxx' to 'xxx' */
/* change './lib/' or lib/ to '[.lib]' */
/* change '/x/y/z to '[x.y]x' */
/* change 'dev:/x' to 'dev:[000000]x' */
int libchar_found;
size_t length;
char * to_pos,from_pos,pos;
char buff[FN_REFLEN];
DBUG_ENTER("system_filename");
libchar_found=0;
(void) strmov(buff,from); /* If to == from */
from_pos= buff;
if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skip device part */
{
pos++;
to_pos=strnmov(to,from_pos,(size_t) (pos-from_pos));
from_pos=pos;
}
else
to_pos=to;
if (from_pos[0] == FN_CURLIB && from_pos[1] == FN_LIBCHAR)
from_pos+=2; /* Skip './' */
if (strchr(from_pos,FN_LIBCHAR))
{
*(to_pos++) = FN_C_BEFORE_DIR;
if (strinstr(from_pos,FN_ROOTDIR) == 1)
{
from_pos+=strlen(FN_ROOTDIR); /* Actually +1 but... */
if (! strchr(from_pos,FN_LIBCHAR))
{ /* No dir, use [000000] */
to_pos=strmov(to_pos,FN_C_ROOT_DIR);
libchar_found++;
}
}
else
*(to_pos++)=FN_C_DIR_SEP; /* '.' gives current dir */
while ((pos=strchr(from_pos,FN_LIBCHAR)))
{
if (libchar_found++)
*(to_pos++)=FN_C_DIR_SEP; /* Add '.' between dirs */
if (strinstr(from_pos,FN_PARENTDIR) == 1 &&
from_pos+strlen(FN_PARENTDIR) == pos)
to_pos=strmov(to_pos,FN_C_PARENT_DIR); /* Found '../' */
else
to_pos=strnmov(to_pos,from_pos,(size_t) (pos-from_pos));
from_pos=pos+1;
}
*(to_pos++)=FN_C_AFTER_DIR;
}
length= (size_t) (strmov(to_pos,from_pos)-to);
DBUG_PRINT("exit",("name: '%s'",to));
DBUG_RETURN(length);
#endif
} /* system_filename */
/* Fix a filename to intern (UNIX format) */
char *intern_filename(char *to, const char *from)
{
size_t length, to_length;
char buff[FN_REFLEN];
if (from == to)
{ /* Dirname may destroy from */
strmov(buff,from);
from=buff;
}
length= dirname_part(to, from, &to_length); /* Copy dirname & fix chars */
(void) strmov(to + to_length,from+length);
return (to);
} /* intern_filename */