/* * 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. */ #include "config.h" #include "mkisofs.h" #include 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((unsigned char)*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((unsigned char)*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); }