libs/libc/stdio: correct the prototype of mktemp(3)
From: int mktemp(FAR char *path_template); To: FAR char *mktemp(FAR char *path_template); See the reference here: https://pubs.opengroup.org/onlinepubs/009695399/functions/mktemp.html Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
parent
7816b5ec8c
commit
4067a9f057
5 changed files with 226 additions and 227 deletions
|
@ -235,7 +235,7 @@ lldiv_t lldiv(long long number, long long denom);
|
||||||
|
|
||||||
/* Temporary files */
|
/* Temporary files */
|
||||||
|
|
||||||
int mktemp(FAR char *path_template);
|
FAR char *mktemp(FAR char *path_template);
|
||||||
int mkstemp(FAR char *path_template);
|
int mkstemp(FAR char *path_template);
|
||||||
|
|
||||||
/* Sorting */
|
/* Sorting */
|
||||||
|
|
|
@ -87,21 +87,24 @@
|
||||||
|
|
||||||
FAR char *tempnam(FAR const char *dir, FAR const char *pfx)
|
FAR char *tempnam(FAR const char *dir, FAR const char *pfx)
|
||||||
{
|
{
|
||||||
|
FAR char *template;
|
||||||
FAR char *path;
|
FAR char *path;
|
||||||
int ret;
|
|
||||||
|
|
||||||
asprintf(&path, "%s/%s-XXXXXX.tmp", dir, pfx);
|
asprintf(&template, "%s/%s-XXXXXX", dir, pfx);
|
||||||
if (path)
|
if (template)
|
||||||
{
|
{
|
||||||
ret = mktemp(path);
|
path = mktemp(template);
|
||||||
if (ret == OK)
|
if (path != NULL)
|
||||||
{
|
{
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
lib_free(path);
|
lib_free(template);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_errno(ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_errno(ENOMEM);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,14 +82,12 @@
|
||||||
FAR char *tmpnam(FAR char *s)
|
FAR char *tmpnam(FAR char *s)
|
||||||
{
|
{
|
||||||
static char path[L_tmpnam];
|
static char path[L_tmpnam];
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
{
|
{
|
||||||
s = path;
|
s = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(s, L_tmpnam, "%s/XXXXXX.tmp", P_tmpdir);
|
snprintf(s, L_tmpnam, "%s/XXXXXX", P_tmpdir);
|
||||||
ret = mktemp(s);
|
return mktemp(s);
|
||||||
return (ret == OK) ? s : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,143 +25,9 @@
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
#include <nuttx/compiler.h>
|
#include <nuttx/compiler.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <nuttx/semaphore.h>
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Pre-processor definitions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#define MAX_XS 6
|
|
||||||
#define MIN_NUMERIC 0 /* 0-9: Numeric */
|
|
||||||
#define MAX_NUMERIC 9
|
|
||||||
#define MIN_UPPERCASE 10 /* 10-35: Upper case */
|
|
||||||
#define MAX_UPPERCASE 35
|
|
||||||
#define MIN_LOWERCASE 36 /* 36-61: Lower case */
|
|
||||||
#define MAX_LOWERCASE 61
|
|
||||||
#define MAX_BASE62 MAX_LOWERCASE
|
|
||||||
|
|
||||||
/* 62**1 = 62
|
|
||||||
* 62**2 = 3844
|
|
||||||
* 62**3 = 238328
|
|
||||||
* 62**4 = 14776336
|
|
||||||
* 62**5 = 916132832
|
|
||||||
* 62**6 = 56800235584 > UINT32_MAX
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define BIG_XS 5
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Data
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static uint8_t g_base62[MAX_XS];
|
|
||||||
static sem_t g_b62sem = SEM_INITIALIZER(1);
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Functions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: base62_to_char
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Convert a base62 value to a printable character.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static char base62_to_char(uint8_t base62)
|
|
||||||
{
|
|
||||||
if (base62 <= MAX_NUMERIC)
|
|
||||||
{
|
|
||||||
return '0' + base62;
|
|
||||||
}
|
|
||||||
else if (base62 <= MAX_UPPERCASE)
|
|
||||||
{
|
|
||||||
return 'A' + base62 - MIN_UPPERCASE;
|
|
||||||
}
|
|
||||||
else /* if (base62 <= MAX_LOWERCASE) */
|
|
||||||
{
|
|
||||||
DEBUGASSERT(base62 <= MAX_LOWERCASE);
|
|
||||||
return 'a' + base62 - MIN_LOWERCASE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: incr_base62
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* increment the base62 value array.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void incr_base62(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = MAX_XS - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (g_base62[i] < MAX_LOWERCASE)
|
|
||||||
{
|
|
||||||
g_base62[i]++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_base62[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: get_base62
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Atomically copy and increment the base62 array.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void get_base62(FAR uint8_t *ptr)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
while ((ret = _SEM_WAIT(&g_b62sem)) < 0)
|
|
||||||
{
|
|
||||||
DEBUGASSERT(_SEM_ERRNO(ret) == EINTR || _SEM_ERRNO(ret) == ECANCELED);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(ptr, g_base62, MAX_XS);
|
|
||||||
incr_base62();
|
|
||||||
_SEM_POST(&g_b62sem);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: copy_base62
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Copy the base62 array into the template filename, converting each
|
|
||||||
* base62 value to a printable character.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void copy_base62(FAR const uint8_t *src, FAR char *dest, int len)
|
|
||||||
{
|
|
||||||
if (len < MAX_XS)
|
|
||||||
{
|
|
||||||
src += MAX_XS - len;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; len > 0; len--)
|
|
||||||
{
|
|
||||||
*dest++ = base62_to_char(*src++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
|
@ -195,78 +61,13 @@ static void copy_base62(FAR const uint8_t *src, FAR char *dest, int len)
|
||||||
|
|
||||||
int mkstemp(FAR char *path_template)
|
int mkstemp(FAR char *path_template)
|
||||||
{
|
{
|
||||||
uint8_t base62[MAX_XS];
|
FAR char *path = mktemp(path_template);
|
||||||
uint32_t retries;
|
int ret = ERROR;
|
||||||
FAR char *xptr;
|
|
||||||
int xlen;
|
|
||||||
int fd;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Count the number of X's at the end of the template */
|
if (path)
|
||||||
|
|
||||||
xptr = &path_template[strlen(path_template)];
|
|
||||||
for (xlen = 0; xlen < MAX_XS && path_template < xptr && *(xptr - 1) == 'X';
|
|
||||||
xlen++, xptr--);
|
|
||||||
|
|
||||||
if (xlen == 0)
|
|
||||||
{
|
{
|
||||||
/* No Xs? There should always really be 6 */
|
ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0666);
|
||||||
|
|
||||||
return open(path_template, O_RDWR | O_CREAT | O_EXCL, 0666);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore any X's after the sixth */
|
return ret;
|
||||||
|
|
||||||
if (xlen > MAX_XS)
|
|
||||||
{
|
|
||||||
xptr += xlen - MAX_XS;
|
|
||||||
xlen = MAX_XS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If xlen is small, then we need to determine the maximum number of
|
|
||||||
* retries before the values will repeat.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (xlen >= BIG_XS)
|
|
||||||
{
|
|
||||||
retries = UINT32_MAX;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = 1, retries = 62; i < xlen; i++, retries *= 62);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Then loop until we find a unique file name */
|
|
||||||
|
|
||||||
while (retries > 0)
|
|
||||||
{
|
|
||||||
/* Sample and increment the base62 counter */
|
|
||||||
|
|
||||||
get_base62(base62);
|
|
||||||
|
|
||||||
/* Form the candidate file name */
|
|
||||||
|
|
||||||
copy_base62(base62, xptr, xlen);
|
|
||||||
|
|
||||||
/* Attempt to open the candidate file -- creating it exclusively
|
|
||||||
*
|
|
||||||
* REVISIT: This prohibits the use of this function to create unique
|
|
||||||
* directories
|
|
||||||
*/
|
|
||||||
|
|
||||||
fd = open(path_template, O_RDWR | O_CREAT | O_EXCL, 0666);
|
|
||||||
if (fd >= 0)
|
|
||||||
{
|
|
||||||
/* We have it... return the file descriptor */
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
retries--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We could not find an unique filename */
|
|
||||||
|
|
||||||
return ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,17 +25,146 @@
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
#include <nuttx/compiler.h>
|
#include <nuttx/compiler.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <nuttx/semaphore.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor definitions
|
* Pre-processor definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define MAX_XS 6
|
||||||
|
#define MIN_NUMERIC 0 /* 0-9: Numeric */
|
||||||
|
#define MAX_NUMERIC 9
|
||||||
|
#define MIN_UPPERCASE 10 /* 10-35: Upper case */
|
||||||
|
#define MAX_UPPERCASE 35
|
||||||
|
#define MIN_LOWERCASE 36 /* 36-61: Lower case */
|
||||||
|
#define MAX_LOWERCASE 61
|
||||||
|
#define MAX_BASE62 MAX_LOWERCASE
|
||||||
|
|
||||||
|
/* 62**1 = 62
|
||||||
|
* 62**2 = 3844
|
||||||
|
* 62**3 = 238328
|
||||||
|
* 62**4 = 14776336
|
||||||
|
* 62**5 = 916132832
|
||||||
|
* 62**6 = 56800235584 > UINT32_MAX
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BIG_XS 5
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static uint8_t g_base62[MAX_XS];
|
||||||
|
static sem_t g_b62sem = SEM_INITIALIZER(1);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: base62_to_char
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Convert a base62 value to a printable character.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static char base62_to_char(uint8_t base62)
|
||||||
|
{
|
||||||
|
if (base62 <= MAX_NUMERIC)
|
||||||
|
{
|
||||||
|
return '0' + base62;
|
||||||
|
}
|
||||||
|
else if (base62 <= MAX_UPPERCASE)
|
||||||
|
{
|
||||||
|
return 'A' + base62 - MIN_UPPERCASE;
|
||||||
|
}
|
||||||
|
else /* if (base62 <= MAX_LOWERCASE) */
|
||||||
|
{
|
||||||
|
DEBUGASSERT(base62 <= MAX_LOWERCASE);
|
||||||
|
return 'a' + base62 - MIN_LOWERCASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: incr_base62
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* increment the base62 value array.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void incr_base62(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = MAX_XS - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (g_base62[i] < MAX_LOWERCASE)
|
||||||
|
{
|
||||||
|
g_base62[i]++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_base62[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: get_base62
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Atomically copy and increment the base62 array.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void get_base62(FAR uint8_t *ptr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while ((ret = _SEM_WAIT(&g_b62sem)) < 0)
|
||||||
|
{
|
||||||
|
DEBUGASSERT(_SEM_ERRNO(ret) == EINTR || _SEM_ERRNO(ret) == ECANCELED);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ptr, g_base62, MAX_XS);
|
||||||
|
incr_base62();
|
||||||
|
_SEM_POST(&g_b62sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: copy_base62
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Copy the base62 array into the template filename, converting each
|
||||||
|
* base62 value to a printable character.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void copy_base62(FAR const uint8_t *src, FAR char *dest, int len)
|
||||||
|
{
|
||||||
|
if (len < MAX_XS)
|
||||||
|
{
|
||||||
|
src += MAX_XS - len;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; len > 0; len--)
|
||||||
|
{
|
||||||
|
*dest++ = base62_to_char(*src++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -44,19 +173,87 @@
|
||||||
* Name: mktemp
|
* Name: mktemp
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* The use of mktemp is dangerous; use mkstemp instead.
|
* The mktemp() function generates a unique temporary filename from
|
||||||
|
* template. The last six characters of template must be XXXXXX and these
|
||||||
|
* are replaced with a string that makes the filename unique. Since it
|
||||||
|
* will be modified, template must not be a string constant, but should be
|
||||||
|
* declared as a character array.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
int mktemp(FAR char *path_template)
|
FAR char *mktemp(FAR char *path_template)
|
||||||
{
|
{
|
||||||
int fd = mkstemp(path_template);
|
uint8_t base62[MAX_XS];
|
||||||
if (fd < 0)
|
uint32_t retries;
|
||||||
|
struct stat buf;
|
||||||
|
FAR char *xptr;
|
||||||
|
int xlen;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Count the number of X's at the end of the template */
|
||||||
|
|
||||||
|
xptr = &path_template[strlen(path_template)];
|
||||||
|
for (xlen = 0; xlen < MAX_XS && path_template < xptr && *(xptr - 1) == 'X';
|
||||||
|
xlen++, xptr--);
|
||||||
|
|
||||||
|
if (xlen == 0)
|
||||||
{
|
{
|
||||||
return ERROR;
|
/* No Xs? There should always really be 6 */
|
||||||
|
|
||||||
|
return path_template;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
/* Ignore any X's after the sixth */
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (xlen > MAX_XS)
|
||||||
|
{
|
||||||
|
xptr += xlen - MAX_XS;
|
||||||
|
xlen = MAX_XS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If xlen is small, then we need to determine the maximum number of
|
||||||
|
* retries before the values will repeat.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (xlen >= BIG_XS)
|
||||||
|
{
|
||||||
|
retries = UINT32_MAX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 1, retries = 62; i < xlen; i++, retries *= 62);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then loop until we find a unique file name */
|
||||||
|
|
||||||
|
while (retries > 0)
|
||||||
|
{
|
||||||
|
/* Sample and increment the base62 counter */
|
||||||
|
|
||||||
|
get_base62(base62);
|
||||||
|
|
||||||
|
/* Form the candidate file name */
|
||||||
|
|
||||||
|
copy_base62(base62, xptr, xlen);
|
||||||
|
|
||||||
|
/* Attempt to stat the candidate file */
|
||||||
|
|
||||||
|
ret = stat(path_template, &buf);
|
||||||
|
if (ret < 0 && errno == ENOENT)
|
||||||
|
{
|
||||||
|
/* We have it... Clear the errno and return the template */
|
||||||
|
|
||||||
|
set_errno(0);
|
||||||
|
return path_template;
|
||||||
|
}
|
||||||
|
|
||||||
|
retries--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We could not find an unique filename */
|
||||||
|
|
||||||
|
set_errno(EINVAL);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue