Exemple #1
0
inline static
const char *GetInvalidChars(const char *fileName)
{
    // SET: Added a check for LFNs, in LFN drives ;,[]=+ are valid
    if (_use_lfn(fileName))
    return IllegalChars2;
    return IllegalChars1;
}
Exemple #2
0
/// \brief      Appends suffix to src_name
///
/// In contrast to uncompressed_name(), we check only suffixes that are valid
/// for the specified file format.
static char *
compressed_name(const char *src_name, size_t src_len)
{
	// The order of these must match the order in args.h.
	static const char *const all_suffixes[][4] = {
		{
			".xz",
			".txz",
			NULL
		}, {
			".lzma",
#ifdef __DJGPP__
			".lzm",
#endif
			".tlz",
			NULL
/*
		}, {
			".gz",
			".tgz",
			NULL
*/
		}, {
			// --format=raw requires specifying the suffix
			// manually or using stdout.
			NULL
		}
	};

	// args.c ensures this.
	assert(opt_format != FORMAT_AUTO);

	const size_t format = opt_format - 1;
	const char *const *suffixes = all_suffixes[format];

	// Look for known filename suffixes and refuse to compress them.
	for (size_t i = 0; suffixes[i] != NULL; ++i) {
		if (test_suffix(suffixes[i], src_name, src_len) != 0) {
			msg_suffix(src_name, suffixes[i]);
			return NULL;
		}
	}

#ifdef __DJGPP__
	// Recognize also the special suffix that is used when long
	// filename (LFN) support isn't available. This suffix is
	// recognized on LFN systems too.
	if (opt_format == FORMAT_XZ && has_sfn_suffix(src_name, src_len)) {
		msg_suffix(src_name, "-");
		return NULL;
	}
#endif

	if (custom_suffix != NULL) {
		if (test_suffix(custom_suffix, src_name, src_len) != 0) {
			msg_suffix(src_name, custom_suffix);
			return NULL;
		}
	}

	// TODO: Hmm, maybe it would be better to validate this in args.c,
	// since the suffix handling when decoding is weird now.
	if (opt_format == FORMAT_RAW && custom_suffix == NULL) {
		message_error(_("%s: With --format=raw, "
				"--suffix=.SUF is required unless "
				"writing to stdout"), src_name);
		return NULL;
	}

	const char *suffix = custom_suffix != NULL
			? custom_suffix : suffixes[0];
	size_t suffix_len = strlen(suffix);

#ifdef __DJGPP__
	if (!_use_lfn(src_name)) {
		// Long filename (LFN) support isn't available and we are
		// limited to 8.3 short filenames (SFN).
		//
		// Look for suffix separator from the filename, and make sure
		// that it is in the filename, not in a directory name.
		const char *sufsep = strrchr(src_name, '.');
		if (sufsep == NULL || sufsep[1] == '\0'
				|| has_dir_sep(sufsep)) {
			// src_name has no filename extension.
			//
			// Examples:
			// xz foo         -> foo.xz
			// xz -F lzma foo -> foo.lzm
			// xz -S x foo    -> foox
			// xz -S x foo.   -> foo.x
			// xz -S x.y foo  -> foox.y
			// xz -S .x foo   -> foo.x
			// xz -S .x foo.  -> foo.x
			//
			// Avoid double dots:
			if (sufsep != NULL && sufsep[1] == '\0'
					&& suffix[0] == '.')
				--src_len;

		} else if (custom_suffix == NULL
				&& strcasecmp(sufsep, ".tar") == 0) {
			// ".tar" is handled specially.
			//
			// Examples:
			// xz foo.tar          -> foo.txz
			// xz -F lzma foo.tar  -> foo.tlz
			static const char *const tar_suffixes[] = {
				".txz",
				".tlz",
				// ".tgz",
			};
			suffix = tar_suffixes[format];
			suffix_len = 4;
			src_len -= 4;

		} else {
			if (custom_suffix == NULL && opt_format == FORMAT_XZ) {
				// Instead of the .xz suffix, use a single
				// character at the end of the filename
				// extension. This is to minimize name
				// conflicts when compressing multiple files
				// with the same basename. E.g. foo.txt and
				// foo.exe become foo.tx- and foo.ex-. Dash
				// is rare as the last character of the
				// filename extension, so it seems to be
				// quite safe choice and it stands out better
				// in directory listings than e.g. x. For
				// comparison, gzip uses z.
				suffix = "-";
				suffix_len = 1;
			}

			if (suffix[0] == '.') {
				// The first character of the suffix is a dot.
				// Throw away the original filename extension
				// and replace it with the new suffix.
				//
				// Examples:
				// xz -F lzma foo.txt  -> foo.lzm
				// xz -S .x  foo.txt   -> foo.x
				src_len = sufsep - src_name;

			} else {
				// The first character of the suffix is not
				// a dot. Preserve the first 0-2 characters
				// of the original filename extension.
				//
				// Examples:
				// xz foo.txt         -> foo.tx-
				// xz -S x  foo.c     -> foo.cx
				// xz -S ab foo.c     -> foo.cab
				// xz -S ab foo.txt   -> foo.tab
				// xz -S abc foo.txt  -> foo.abc
				//
				// Truncate the suffix to three chars:
				if (suffix_len > 3)
					suffix_len = 3;

				// If needed, overwrite 1-3 characters.
				if (strlen(sufsep) > 4 - suffix_len)
					src_len = sufsep - src_name
							+ 4 - suffix_len;
			}
		}
	}
#endif

	char *dest_name = xmalloc(src_len + suffix_len + 1);

	memcpy(dest_name, src_name, src_len);
	memcpy(dest_name + src_len, suffix, suffix_len);
	dest_name[src_len + suffix_len] = '\0';

	return dest_name;
}
static const char *msdosify (const char *file_name)
{
  static char dos_name[PATH_MAX];
  static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
    "|<>\\\":?*"; /* illegal in DOS & W95 */
  static const char *illegal_chars_w95 = &illegal_chars_dos[8];
  int idx, dot_idx;
  const char *s = file_name;
  char *d = dos_name;
  const char *const dlimit = dos_name + sizeof(dos_name) - 1;
  const char *illegal_aliens = illegal_chars_dos;
  size_t len = sizeof(illegal_chars_dos) - 1;

  /* Support for Windows 9X VFAT systems, when available. */
  if(_use_lfn(file_name)) {
    illegal_aliens = illegal_chars_w95;
    len -= (illegal_chars_w95 - illegal_chars_dos);
  }

  /* Get past the drive letter, if any. */
  if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
    *d++ = *s++;
    *d++ = *s++;
  }

  for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
    if(memchr(illegal_aliens, *s, len)) {
      /* Dots are special: DOS doesn't allow them as the leading character,
         and a file name cannot have more than a single dot.  We leave the
         first non-leading dot alone, unless it comes too close to the
         beginning of the name: we want sh.lex.c to become sh_lex.c, not
         sh.lex-c.  */
      if(*s == '.') {
        if(idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) {
          /* Copy "./" and "../" verbatim.  */
          *d++ = *s++;
          if(*s == '.')
            *d++ = *s++;
          *d = *s;
        }
        else if(idx == 0)
          *d = '_';
        else if(dot_idx >= 0) {
          if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
            d[dot_idx - idx] = '_'; /* replace previous dot */
            *d = '.';
          }
          else
            *d = '-';
        }
        else
          *d = '.';

        if(*s == '.')
          dot_idx = idx;
      }
      else if(*s == '+' && s[1] == '+') {
        if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */
          *d++ = 'x';
          *d   = 'x';
        }
        else {
          /* libg++ etc.  */
          memcpy (d, "plus", 4);
          d += 3;
        }
        s++;
        idx++;
      }
      else
        *d = '_';
    }
    else
      *d = *s;
    if(*s == '/') {
      idx = 0;
      dot_idx = -1;
    }
    else
      idx++;
  }

  *d = '\0';
  return dos_name;
}
Exemple #4
0
char *maybe_rename_file(const char *original_name)
{
    static char dosified_name[PATH_MAX+1];
    static const char illegal_chars_dos[] = ".+, ;=[]|<>\":?*";
    const char *illegal_chars = illegal_chars_dos;
    int idx, dot_idx;
    const char *s = original_name;
    char *d = dosified_name;

    /* Support for Win32 VFAT systems, when available.  */
#if defined(__DJGPP__)
    if (_use_lfn(original_name))
        illegal_chars = illegal_chars_dos + 8;
#elif (ACC_OS_WIN32 || ACC_OS_WIN64 || ACC_OS_CYGWIN)
    illegal_chars = illegal_chars_dos + 8;
#endif

    /* Get past the drive letter, if any. */
    if (fn_is_drive(s))
    {
        *d++ = *s++;
        *d++ = *s++;
    }

    for (idx = 0, dot_idx = -1; *s; s++, d++)
    {
        if (strchr(illegal_chars, *s))
        {
            /* Dots are special on DOS: it doesn't allow them as the leading
             character, and a file name cannot have more than a single dot.
             We leave the first non-leading dot alone, unless it comes too
             close to the beginning of the name: we want sh.lex.c to become
             sh_lex.c, not sh.lex-c.  */
            if (*s == '.')
            {
                if (idx == 0
                    && (is_slash(s[1]) || s[1] == '\0'
                        || (s[1] == '.' && (is_slash(s[2]) || s[2] == '\0'))))
                {
                    /* Copy "./" and "../" verbatim.  */
                    *d++ = *s++;
                    if (*s == '.')
                        *d++ = *s++;
                    *d = *s;
                }
                else if (idx == 0)
                    *d = '_';
                else if (dot_idx >= 0)
                {
                    if (dot_idx < 5) /* 5 is merely a heuristic ad-hoc'ery */
                    {
                        d[dot_idx - idx] = '_'; /* replace previous dot */
                        *d = '.';
                    }
                    else
                        *d = '-';
                }
                else
                    *d = '.';

                if (*s == '.')
                    dot_idx = idx;
            }
            else if (*s == '+' && s[1] == '+')
            {
                if (idx - 2 == dot_idx) /* .c++, .h++ etc. */
                {
                    *d++ = 'x';
                    *d   = 'x';
                }
                else
                {
                    /* libg++ etc.  */
                    memcpy (d, "plus", 4);
                    d += 3;
                }
                s++;
                idx++;
            }
            else
                *d = '_';
        }
        else
            *d = *s;
        if (is_slash(*s))
        {
            idx = 0;
            dot_idx = -1;
        }
        else
            idx++;
    }

    *d = '\0';

#if defined(S_ISCHR)
    /* We could have a file in an archive whose name is reserved
     on MS-DOS by a device driver.  Trying to extract such a
     file would fail at best and wedge us at worst.  We need to
     rename such files.  */

    if (idx > 0)
    {
        struct stat st_buf;
        char *base = d - idx;
        int i = 0;

        /* The list of character devices is not constant: it depends on
         what device drivers did they install in their CONFIG.SYS.
         `stat' will tell us if the basename of the file name is a
         characer device.  */
        while (stat(base, &st_buf) == 0 && S_ISCHR(st_buf.st_mode))
        {
            size_t blen = strlen(base);

            /* I don't believe any DOS character device names begin with a
             `_'.  But in case they invent such a device, let us try twice.  */
            if (++i > 2)
                return (char *)0;

            /* Prepend a '_'.  */
            memmove(base + 1, base, blen + 1);
            base[0] = '_';
        }
    }
#endif

    return dosified_name;
}