73fb3dd5f0
* util/mkisofs/name.c (FDECL3): Use isascii macro instead of relying that char is signed.
396 lines
8.5 KiB
C
396 lines
8.5 KiB
C
/*
|
|
* File name.c - map full Unix file names to unique 8.3 names that
|
|
* would be valid on DOS.
|
|
*
|
|
|
|
Written by Eric Youngdale (1993).
|
|
|
|
Copyright 1993 Yggdrasil Computing, Incorporated
|
|
|
|
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; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
static char rcsid[] ="$Id: name.c,v 1.11 1999/03/02 03:41:26 eric Exp $";
|
|
|
|
#include "config.h"
|
|
#include "mkisofs.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
extern int allow_leading_dots;
|
|
|
|
/*
|
|
* Function: iso9660_file_length
|
|
*
|
|
* Purpose: Map file name to 8.3 format, return length
|
|
* of result.
|
|
*
|
|
* Arguments: name file name we need to map.
|
|
* sresult directory entry structure to contain mapped name.
|
|
* dirflag flag indicating whether this is a directory or not.
|
|
*
|
|
* Notes: This procedure probably needs to be rationalized somehow.
|
|
* New options to affect the behavior of this function
|
|
* would also be nice to have.
|
|
*/
|
|
int FDECL3(iso9660_file_length,
|
|
const char*, name,
|
|
struct directory_entry *, sresult,
|
|
int, dirflag)
|
|
{
|
|
char * c;
|
|
int chars_after_dot = 0;
|
|
int chars_before_dot = 0;
|
|
int current_length = 0;
|
|
int extra = 0;
|
|
int ignore = 0;
|
|
char * last_dot;
|
|
const char * pnt;
|
|
int priority = 32767;
|
|
char * result;
|
|
int seen_dot = 0;
|
|
int seen_semic = 0;
|
|
int tildes = 0;
|
|
|
|
result = sresult->isorec.name;
|
|
|
|
/*
|
|
* For the '.' entry, generate the correct record, and return
|
|
* 1 for the length.
|
|
*/
|
|
if(strcmp(name,".") == 0)
|
|
{
|
|
if(result)
|
|
{
|
|
*result = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* For the '..' entry, generate the correct record, and return
|
|
* 1 for the length.
|
|
*/
|
|
if(strcmp(name,"..") == 0)
|
|
{
|
|
if(result)
|
|
{
|
|
*result++ = 1;
|
|
*result++ = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Now scan the directory one character at a time, and figure out
|
|
* what to do.
|
|
*/
|
|
pnt = name;
|
|
|
|
/*
|
|
* Find the '.' that we intend to use for the extension. Usually this
|
|
* is the last dot, but if we have . followed by nothing or a ~, we
|
|
* would consider this to be unsatisfactory, and we keep searching.
|
|
*/
|
|
last_dot = strrchr (pnt,'.');
|
|
if( (last_dot != NULL)
|
|
&& ( (last_dot[1] == '~')
|
|
|| (last_dot[1] == '\0')) )
|
|
{
|
|
c = last_dot;
|
|
*c = '\0';
|
|
last_dot = strrchr (pnt,'.');
|
|
*c = '.';
|
|
}
|
|
|
|
while(*pnt)
|
|
{
|
|
#ifdef VMS
|
|
if( strcmp(pnt,".DIR;1") == 0 )
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* This character indicates a Unix style of backup file
|
|
* generated by some editors. Lower the priority of
|
|
* the file.
|
|
*/
|
|
if(*pnt == '#')
|
|
{
|
|
priority = 1;
|
|
pnt++;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* This character indicates a Unix style of backup file
|
|
* generated by some editors. Lower the priority of
|
|
* the file.
|
|
*/
|
|
if(*pnt == '~')
|
|
{
|
|
priority = 1;
|
|
tildes++;
|
|
pnt++;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* This might come up if we had some joker already try and put
|
|
* iso9660 version numbers into the file names. This would be
|
|
* a silly thing to do on a Unix box, but we check for it
|
|
* anyways. If we see this, then we don't have to add our
|
|
* own version number at the end.
|
|
* UNLESS the ';' is part of the filename and no version
|
|
* number is following. [VK]
|
|
*/
|
|
if(*pnt == ';')
|
|
{
|
|
/* [VK] */
|
|
if (pnt[1] != '\0' && (pnt[1] < '0' || pnt[1] > '9'))
|
|
{
|
|
pnt++;
|
|
ignore++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we have a name with multiple '.' characters, we ignore everything
|
|
* after we have gotten the extension.
|
|
*/
|
|
if(ignore)
|
|
{
|
|
pnt++;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Spin past any iso9660 version number we might have.
|
|
*/
|
|
if(seen_semic)
|
|
{
|
|
if(*pnt >= '0' && *pnt <= '9')
|
|
{
|
|
*result++ = *pnt;
|
|
}
|
|
extra++;
|
|
pnt++;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* If we have full names, the names we generate will not
|
|
* work on a DOS machine, since they are not guaranteed
|
|
* to be 8.3. Nonetheless, in many cases this is a useful
|
|
* option. We still only allow one '.' character in the
|
|
* name, however.
|
|
*/
|
|
if(full_iso9660_filenames)
|
|
{
|
|
/* Here we allow a more relaxed syntax. */
|
|
if(*pnt == '.')
|
|
{
|
|
if (seen_dot)
|
|
{
|
|
ignore++;
|
|
continue;
|
|
}
|
|
seen_dot++;
|
|
}
|
|
if(current_length < 30)
|
|
{
|
|
if( !isascii (*pnt))
|
|
{
|
|
*result++ = '_';
|
|
}
|
|
else
|
|
{
|
|
*result++ = (islower((unsigned char)*pnt) ? toupper((unsigned char)*pnt) : *pnt);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Dos style filenames. We really restrict the
|
|
* names here.
|
|
*/
|
|
/* It would be nice to have .tar.gz transform to .tgz,
|
|
* .ps.gz to .psz, ...
|
|
*/
|
|
if(*pnt == '.')
|
|
{
|
|
if (!chars_before_dot && !allow_leading_dots)
|
|
{
|
|
/* DOS can't read files with dot first */
|
|
chars_before_dot++;
|
|
if (result)
|
|
{
|
|
*result++ = '_'; /* Substitute underscore */
|
|
}
|
|
}
|
|
else if( pnt != last_dot )
|
|
{
|
|
/*
|
|
* If this isn't the dot that we use for the extension,
|
|
* then change the character into a '_' instead.
|
|
*/
|
|
if(chars_before_dot < 8)
|
|
{
|
|
chars_before_dot++;
|
|
if(result)
|
|
{
|
|
*result++ = '_';
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (seen_dot)
|
|
{
|
|
ignore++; continue;
|
|
}
|
|
if(result)
|
|
{
|
|
*result++ = '.';
|
|
}
|
|
seen_dot++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (seen_dot && (chars_after_dot < 3) && ++chars_after_dot)
|
|
|| (!seen_dot && (chars_before_dot < 8) && ++chars_before_dot) )
|
|
{
|
|
if(result)
|
|
{
|
|
switch (*pnt)
|
|
{
|
|
default:
|
|
if( !isascii (*pnt) )
|
|
{
|
|
*result++ = '_';
|
|
}
|
|
else
|
|
{
|
|
*result++ = islower((unsigned char)*pnt) ? toupper((unsigned char)*pnt) : *pnt;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* Descriptions of DOS's 'Parse Filename'
|
|
* (function 29H) describes V1 and V2.0+
|
|
* separator and terminator characters.
|
|
* These characters in a DOS name make
|
|
* the file visible but un-manipulable
|
|
* (all useful operations error off.
|
|
*/
|
|
/* separators */
|
|
case '+':
|
|
case '=':
|
|
case '%': /* not legal DOS filename */
|
|
case ':':
|
|
case ';': /* already handled */
|
|
case '.': /* already handled */
|
|
case ',': /* already handled */
|
|
case '\t':
|
|
case ' ':
|
|
/* V1 only separators */
|
|
case '/':
|
|
case '"':
|
|
case '[':
|
|
case ']':
|
|
/* terminators */
|
|
case '>':
|
|
case '<':
|
|
case '|':
|
|
/* Hmm - what to do here? Skip?
|
|
* Win95 looks like it substitutes '_'
|
|
*/
|
|
*result++ = '_';
|
|
break;
|
|
} /* switch (*pnt) */
|
|
} /* if (result) */
|
|
} /* if (chars_{after,before}_dot) ... */
|
|
} /* else *pnt == '.' */
|
|
} /* else DOS file names */
|
|
current_length++;
|
|
pnt++;
|
|
} /* while (*pnt) */
|
|
|
|
/*
|
|
* OK, that wraps up the scan of the name. Now tidy up a few other
|
|
* things.
|
|
*/
|
|
|
|
/*
|
|
* Look for emacs style of numbered backups, like foo.c.~3~. If
|
|
* we see this, convert the version number into the priority
|
|
* number. In case of name conflicts, this is what would end
|
|
* up being used as the 'extension'.
|
|
*/
|
|
if(tildes == 2)
|
|
{
|
|
int prio1 = 0;
|
|
pnt = name;
|
|
while (*pnt && *pnt != '~')
|
|
{
|
|
pnt++;
|
|
}
|
|
if (*pnt)
|
|
{
|
|
pnt++;
|
|
}
|
|
while(*pnt && *pnt != '~')
|
|
{
|
|
prio1 = 10*prio1 + *pnt - '0';
|
|
pnt++;
|
|
}
|
|
priority = prio1;
|
|
}
|
|
|
|
/*
|
|
* If this is not a directory, force a '.' in case we haven't
|
|
* seen one, and add a version number if we haven't seen one
|
|
* of those either.
|
|
*/
|
|
if (!dirflag)
|
|
{
|
|
if (!seen_dot && !omit_period)
|
|
{
|
|
if (result) *result++ = '.';
|
|
extra++;
|
|
}
|
|
if(!omit_version_number && !seen_semic)
|
|
{
|
|
if(result)
|
|
{
|
|
*result++ = ';';
|
|
*result++ = '1';
|
|
};
|
|
extra += 2;
|
|
}
|
|
}
|
|
|
|
if(result)
|
|
{
|
|
*result++ = 0;
|
|
}
|
|
sresult->priority = priority;
|
|
|
|
return (chars_before_dot + chars_after_dot + seen_dot + extra);
|
|
}
|