2015-08-01 Juan Manuell Guerrero * mktemp.c [__DJGPP__]: Define new macros DIR_EXIST, CANONICALIZE_PATH OPTIONS and STRIP_FULL_PATH_AND_EXTENSION; for other systems these are no-ops. (main) [__DJGPP__]: Use STRIP_FULL_PATH_AND_EXTENSION to strip path and extension from argv[0]. Use CANONICALIZE_PATH to replace DOS-style backslash directory separator with unix-style slash directory separtor in the passed prefix. Change hardcoded template string pattern with TEMPLATE_PATTERN. Change test for hardcoded slash char as dir separator char with IS_DIR_SEPARATOR. For MSDOS this also checks for drive specifier prefix. (main) [__DJGPP__]: Check also for TMP and TEMP. If one of them are set, check that the directory exists, if not default to cwd. Change test for hardcoded slash char as dir separator char with IS_SLASH. Change hardcoded slash char as dir separator char with DIR_SEPARATOR. * priv_mktemp.c (_mktemp): Use macro IS_TEMPLATE_PATTERN_CHAR to detect at runtime what kind of template characters are allowed. For systems with LFN support only 'X' is allowed. For SFN systems like DOS also '.' is allowed. This allows to use the extension as pattern too. * mktemp.man: Add MSDOS/DJGPP specific information. * mktemp.mdoc: Add MSDOS/DJGPP specific information. diff -aprNU5 mktemp-1.7.orig/mktemp.c mktemp-1.7/mktemp.c --- mktemp-1.7.orig/mktemp.c 2010-04-25 13:31:44 +0200 +++ mktemp-1.7/mktemp.c 2015-08-01 10:10:40 +0200 @@ -47,10 +47,57 @@ #endif /* HAVE_GETOPT_LONG */ #include #include +#ifdef __DJGPP__ +# include + +# undef IS_DOS_SLASH +# define IS_DOS_SLASH(c) (IS_SLASH(c) || (c) == ':') + +# define STRIP_FULL_PATH_AND_EXTENSION(file_name) \ + (__gnuc_extension__ \ + ({ \ + char *_dst, *_src; \ + _dst = _src = unconst((file_name), char *); \ + while (*_src++) \ + ; \ + while ((_src - _dst) && (*--_src != '.')) \ + ; \ + for (*_src = '\0'; (_src - _dst); _src--) \ + if (IS_DOS_SLASH(*_src)) \ + break; \ + if (_src - _dst) \ + while ((*_dst++ = *++_src)) \ + ; \ + (file_name); \ + }) \ + ) + +# define CANONICALIZE_PATH(path) \ + (__gnuc_extension__ \ + ({ \ + if ((path)) \ + { \ + char *_p = unconst((path), char *); \ + for (; *_p; _p++) \ + if (*_p == '\\') \ + *_p = '/'; \ + } \ + (path); \ + }) \ + ) +# define DIR_EXISTS(path) (access((path), D_OK) == 0) +# define OPTIONS "dp:qTtuV" +#else +# define STRIP_FULL_PATH_AND_EXTENSION(file_name) (file_name) +# define CANONICALIZE_PATH(path) (path) +# define DIR_EXISTS(path) (1) +# define OPTIONS "dp:qtuV" +#endif + #ifndef _PATH_TMP #define _PATH_TMP "/tmp" #endif #ifdef HAVE_PROGNAME @@ -65,11 +112,15 @@ void usage __P((void)) __attribute__((__ static struct option const longopts[] = { {"directory", no_argument, NULL, 'd'}, {"help", no_argument, NULL, 'h'}, {"quiet", no_argument, NULL, 'q'}, +#ifdef __DJGPP__ + {"tmpdir", no_argument, NULL, 'T'}, +#else {"tmpdir", optional_argument, NULL, 'T'}, +#endif {"dry-run", no_argument, NULL, 'u'}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; #endif @@ -84,34 +135,38 @@ main(argc, argv) size_t plen; extern char *optarg; extern int optind; #ifndef HAVE_PROGNAME - __progname = argv[0]; + __progname = STRIP_FULL_PATH_AND_EXTENSION(argv[0]); #endif #ifdef HAVE_GETOPT_LONG - while ((ch = getopt_long(argc, argv, "dp:qtuV", longopts, NULL)) != -1) + while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) #else - while ((ch = getopt(argc, argv, "dp:qtuV")) != -1) + while ((ch = getopt(argc, argv, OPTIONS)) != -1) #endif switch (ch) { case 'd': makedir = 1; break; case 'p': - prefix = optarg; + prefix = CANONICALIZE_PATH(optarg); tflag = 1; break; case 'q': quiet = 1; break; case 'T': +#ifdef __DJGPP__ + Tflag = 1; +#else if (optarg) { Tflag = 1; prefix = optarg; } +#endif /* FALLTHROUGH */ case 't': tflag = 1; break; case 'u': @@ -125,46 +180,60 @@ main(argc, argv) } /* If no template specified use a default one (implies -t mode) */ switch (argc - optind) { case 1: - template = argv[optind]; + template = CANONICALIZE_PATH(argv[optind]); break; case 0: - template = "tmp.XXXXXXXXXX"; + template = TEMPLATE_PATTERN; tflag = 1; break; default: usage(); } if (tflag) { - if (strchr(template, '/')) { + if (IS_DIR_SEPARATOR(template)) { if (!quiet) (void)fprintf(stderr, "%s: template must not contain directory separators in -t mode\n", __progname); exit(1); } if (!Tflag) { cp = getenv("TMPDIR"); - if (cp != NULL && *cp != '\0') + if (cp != NULL && *cp != '\0' && DIR_EXISTS(cp)) + prefix = cp; + } +#ifdef __DJGPP__ + else + { + cp = getenv("TMPDIR"); + if (cp == NULL || *cp == '\0' || !DIR_EXISTS(cp)) { + cp = getenv("TMP"); + if (cp == NULL || *cp == '\0' || !DIR_EXISTS(cp)) { + cp = getenv("TEMP"); + } + } + if (cp != NULL && *cp != '\0' && DIR_EXISTS(cp)) prefix = cp; } +#endif plen = strlen(prefix); - while (plen != 0 && prefix[plen - 1] == '/') + while (plen != 0 && IS_SLASH(prefix[plen - 1])) plen--; tempfile = (char *)malloc(plen + 1 + strlen(template) + 1); if (tempfile == NULL) { if (!quiet) (void)fprintf(stderr, "%s: cannot allocate memory\n", __progname); exit(1); } (void)memcpy(tempfile, prefix, plen); - tempfile[plen] = '/'; + tempfile[plen] = DIR_SEPARATOR; (void)strcpy(tempfile + plen + 1, template); /* SAFE */ } else { if ((tempfile = strdup(template)) == NULL) { if (!quiet) (void)fprintf(stderr, @@ -209,9 +278,13 @@ main(argc, argv) void usage() { (void)fprintf(stderr, +#ifdef __DJGPP__ + "Usage: %s [-V] | [-dqTtu] [-p prefix] [template]\n", +#else "Usage: %s [-V] | [-dqtu] [-p prefix] [template]\n", +#endif __progname); exit(1); } diff -aprNU5 mktemp-1.7.orig/mktemp.man mktemp-1.7/mktemp.man --- mktemp-1.7.orig/mktemp.man 2010-04-25 13:28:18 +0200 +++ mktemp-1.7/mktemp.man 2015-08-01 10:04:26 +0200 @@ -18,11 +18,11 @@ .\" .TH MKTEMP 1 "30 September 2001" .SH NAME \fBmktemp\fP \- make temporary filename (unique) .SH SYNOPSIS -\fBmktemp\fP [\fB\-V\fP] | [\fB\-dqtu\fP] [\fB\-p\fP \fIdirectory\fP] [\fItemplate\fP] +\fBmktemp\fP [\fB\-V\fP] | [\fB\-dqTtu\fP] [\fB\-p\fP \fIdirectory\fP] [\fItemplate\fP] .SH DESCRIPTION The .B mktemp utility takes the given filename .I template @@ -34,19 +34,27 @@ may be any filename with some number of .I /tmp/tfile.XXXXXXXXXX. If no .I template is specified a default of .I tmp.XXXXXXXXXX +if LFN support is available, and +.I tpXXXXXX.XXX +if LFN support is not available is used and the .B \-t flag is implied (see below). .PP The trailing \(gaXs\(aa are replaced with a combination of the current process number and random letters. The name chosen depends both on the number of \(gaXs\(aa in the .I template and the number of collisions with pre\-existing files. +If LFN support is not available, like on plain DOS, +the number of \(gaXs\(aa in the +.I template +is restricted to 6 in the filename +and 3 more in the extension. The number of unique filenames .B mktemp can return depends on the number of \(gaXs\(aa provided; ten \(gaXs\(aa will result in .B mktemp @@ -89,10 +97,14 @@ as a prefix when generating the temporar The .I directory will be overridden by the user's .SM TMPDIR environment variable if it is set. +If the environment variable has been set, it will be checked if +the directory contained therein can be accessed. +If this is not possible then the current working directory +will be used as prefix when generating the temporary filename. This option implies the .B \-t flag (see below). .TP .B \-q @@ -113,17 +125,48 @@ Otherwise, if the .B \-p flag was given the specified directory is used. .IP \(bu If none of the above apply, .I /tmp +(on MSDOS and clones +.I ./ +) +is used. +.RE +.TP +.B \-T +Generate a path rooted in a temporary directory on MSDOS and clones. +This directory is chosen as follows: +.RS +.IP \(bu +If the user's +.SM TMPDIR +environment variable is set, the directory contained therein is used. +On MSDOS and clones also the environment variables +.SM TMP +and +.SM TEMP +will be checked in that order. +.IP \(bu +Otherwise, if the +.B \-p +flag was given the specified directory is used. +.IP \(bu +If none of the above apply, +.I /tmp +(on MSDOS and clones +.I ./ +) is used. .RE .PP -In this mode, the +In these modes, the .I template (if specified) should be a directory component (as opposed to a full path) and thus should not contain any forward slashes. +On MSDOS and clones also neither backslashes nor drive letter prefix are +allowed. .TP .B \-u Operate in "unsafe" mode. The temp file will be unlinked before .B mktemp @@ -138,10 +181,19 @@ exits with a value of 0 on success or 1 .SH ENVIRONMENT .IP TMPDIR 8 directory in which to place the temporary file when in .B \-t mode +.IP TMPDIR 8 +or +.IP TMP 8 +and +.IP TEMP 8 +on MSDOS and clones +directory in which to place the temporary file when in +.B \-T +mode .SH EXAMPLES The following sh(1) fragment illustrates a simple use of .B mktemp where the script should quit if it cannot get a safe @@ -183,10 +235,15 @@ other than .I /tmp. In this example the temporary file will be created in .I /extra/tmp unless the user's .SM TMPDIR +(or +.SM TMP +and +.SM TEMP +on MSDOS and clones) environment variable specifies otherwise. .RS .nf TMPFILE=\(gamktemp \-p /extra/tmp example.XXXXXXXXXX\(ga || exit 1 diff -aprNU5 mktemp-1.7.orig/mktemp.mdoc mktemp-1.7/mktemp.mdoc --- mktemp-1.7.orig/mktemp.mdoc 2010-04-25 13:28:24 +0200 +++ mktemp-1.7/mktemp.mdoc 2015-08-01 10:04:26 +0200 @@ -44,10 +44,13 @@ to it, for example .Pa /tmp/tfile.XXXXXXXXXX . If no .Ar template is specified a default of .Pa tmp.XXXXXXXXXX +if LFN support is available and +.Pa tpXXXXXX.XXX +if LFN support is not available is used and the .Fl t flag is implied (see below). .Pp The trailing @@ -57,10 +60,17 @@ random letters. The name chosen depends both on the number of .Ql X Ns s in the .Ar template and the number of collisions with pre-existing files. +If LFN support is not available, like on plain DOS, +the number of +.Ql X Ns s +in the +.Ar template +is restricted to 6 in the filename +and 3 more in the extension. The number of unique filenames .Nm can return depends on the number of .Ql X Ns s provided; ten @@ -105,10 +115,21 @@ as a prefix when generating the temporar The .Ar directory will be overridden by the user's .Ev TMPDIR environment variable if it is set. +On MSDOS and clones, if +.Ev TMPDIR +is not set also the environment variables +.Ev TMP +and +.Ev TEMP +will be checked in that order. +If one of the environment variables has been set, +it will be checked if the directory contained therein can be accessed. +If this is not possible then the current working directory +will be used as prefix when generating the temporary filename. This option implies the .Fl t flag (see below). .It Fl q Fail silently if an error occurs. @@ -120,24 +141,33 @@ This directory is chosen as follows: .Bl -bullet .It If the user's .Ev TMPDIR environment variable is set, the directory contained therein is used. +On MSDOS and clones also the environment variables +.Ev TMP +and +.Ev TEMP +will be checked in that order. .It Otherwise, if the .Fl p flag was given the specified directory is used. .It If none of the above apply, .Pa /tmp +(on MSDOS and clones +.Pa ./ +) is used. .El .Pp In this mode, the .Ar template (if specified) should be a directory component (as opposed to a full path) and thus should not contain any forward slashes. +On MSDOS also neither backslashes nor drive letter prefix. .It Fl u Operate in .Dq unsafe mode. The temp file will be unlinked before @@ -154,10 +184,15 @@ The utility exits with a value of 0 on success or 1 on failure. .Sh ENVIRONMENT .Bl -tag -width TMPDIR .It Ev TMPDIR +(or +.Ev TMP +and +.Ev TEMP +on MSDOS and clones) directory in which to place the temporary file when in .Fl t mode .El .Sh EXAMPLES @@ -195,10 +230,15 @@ other than .Pa /tmp . In this example the temporary file will be created in .Pa /extra/tmp unless the user's .Ev TMPDIR +(or +.Ev TMP +and +.Ev TEMP +on MSDOS and clones) environment variable specifies otherwise. .Bd -literal -offset indent TMPFILE=\(gamktemp -p /extra/tmp example.XXXXXXXXXX\(ga || exit 1 echo "program output" >> $TMPFILE .Ed diff -aprNU5 mktemp-1.7.orig/priv_mktemp.c mktemp-1.7/priv_mktemp.c --- mktemp-1.7.orig/priv_mktemp.c 2010-04-25 13:32:12 +0200 +++ mktemp-1.7/priv_mktemp.c 2015-08-01 10:04:26 +0200 @@ -63,11 +63,11 @@ mktemp_internal(path, mode) } for (start = path; *start; start++) ; tries = 1; - for (; start > path && start[-1] == 'X'; start--) { + for (; start > path && IS_TEMPLATE_PATTERN_CHAR(start[-1]); start--) { if (tries < INT_MAX / NUM_CHARS) tries *= NUM_CHARS; } tries *= 2;