Create temp directory
Steve Terry

I need a way to create a temporary directory name. I've used tempnam(NULL) and it only seems to return 4 digit names with something like "\aer2." which is not exactly what I'm looking for. Anyone know of a better (no .NET) way of creating a unique temporary name consisting of 8-10 characters?

Rampage

What I do when I need to create temp files is get the current time in milliseconds. That nomber is converted to a string and used as the name for my temp file/dir.

bamccaig

Yeah, date/time would have to be the only reliable way to generate a unique filename.

Even then, because computers operate so fast it's possible for more than one to be created in the same milisecond (or whatever measure your method of getting time is)(depending on your application, of course) so you'll probably want a way to query the filesystem to make sure that the directory doesn't already exist.

Besides, for all you know there was already a directory named 20070409103029.ext or the like from a separate application or user. :P

Now that I think of it you might get away with hashing a random value, for example with SHA1 or MD5 or something, but I don't know how unique those are.

Okay, generate a random value and hash that, salted with a numeric datetime!

...And then query the filesystem to make sure the file doesn't already exist (if it does start the process over). :P

tobing

What's wrong with a name like "/aer2"? As long as the name refers to a directory that doesn't already exist...

bamccaig
tobing said:

What's wrong with a name like "/aer2"? As long as the name refers to a directory that doesn't already exist...

True, there's nothing wrong with that directory name. What was the problem with it?

The only potential problem is the decreased probability of a 4-character string being unique; especially if the directory it's working in is used often or by numerous people at a time.

The time is a better tactic anyway. In any case, you'll always have to check if the file exists or not before writing to make sure you don't damage another file.

tempnam - Manual said:

Creates a file with a unique filename, with access permission set to 0600, in the specified directory. If the directory does not exist, tempnam() may generate a file in the system's temporary directory, and return the name of that.

-Source

In PHP it sounds like it actually returns a unique name, as in PHP checks that it doesn't exist yet (and might even create it for you). What language are you developing with??

CGamesPlay
Quote:

tempnam(NULL)

tempnam accepts two arguments:

Quote:

SYNOPSIS
#include <stdio.h>

char *tempnam(const char *dir, const char *pfx);

DESCRIPTION
The tempnam() function returns a pointer to a string that is a valid file-
name, and such that a file with this name did not exist when tempnam()
checked. The filename suffix of the pathname generated will start with pfx
in case pfx is a non-NULL string of at most five bytes. The directory pre-
fix part of the pathname generated is required to be `appropriate' (often
that at least implies writable).

Attempts to find an appropriate directory go through the following steps:

a) In case the environment variable TMPDIR exists and contains the name
of an appropriate directory, that is used.

b) Otherwise, if the dir argument is non-NULL and appropriate, it is
used.

c) Otherwise, P_tmpdir (as defined in <stdio.h>) is used when appropri-
ate.

d) Finally an implementation-defined directory may be used.

The string returned by tempnam() is allocated using malloc(3) and hence
should be freed by free(3).

[append]
If I were you, I'd do tempnam(getenv("TEMP"), "MyProgram").

Steve Terry

Ahh the documentation I was looking at only had tmpnam taking in one argument, not two. At any rate I just friggin used abs and rand to generate me a nice number (between 10000 and 99999) and used that for the directory name and checked if it existed first.

Thomas Fjellstrom

I wrote a new tmpfile method for allegro 4.3 to handle all this. it atm, returns a file descriptor, so its just for files, but its not hard to make one for dirs either. It handles "anonymous" temp files (ones that are unlinked immediately), and can auto delete upon file close.

I hadn't considered making a temp dir version. Maybe if people request it enough.

code: (for the stdio handler, windows code will likely use one of the Win32 functions, if its deemed necessary)

1#define MAX_MKTEMP_TRIES 1000
2const char mktemp_ok_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
3 
4void _al_fs_mktemp_replace_XX(char *template, char *dst)
5{
6 size_t len = strlen(template);
7 uint32_t i = 0;
8 
9 for(i=0; i<len; ++i) {
10 if(template<i> != 'X') {
11 dst<i> = template<i>;
12 }
13 else {
14 dst<i> = mktemp_ok_chars[ _al_rand() % (sizeof(mktemp_ok_chars)-1) ];
15 }
16 }
17}
18 
19/* FIXME: provide the filename created. */
20/* might have to make AL_FS_ENTRY a strust to provide the filename, and unlink hint. */
21/* by default, temp file is NOT unlink'ed automatically */
22 
23AL_FS_ENTRY *al_fs_stdio_mktemp(const char *template, uint32_t ulink)
24{
25 int32_t fd = -1, tries = 0;
26 int32_t template_len = 0, tmpdir_len = 0;
27 AL_FS_ENTRY *fh = NULL;
28 char *dest = NULL;
29 char tmpdir[PATH_MAX];
30 
31 template_len = strlen( template );
32 
33 if(al_get_path(AL_TEMP_PATH, tmpdir, PATH_MAX) != 0) {
34 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Failed to find temp directory"));
35 return NULL;
36 }
37 
38 tmpdir_len = strlen( tmpdir_len );
39 
40 dest = AL_MALLOC( template_len + tmpdir_len + 2 );
41 if(!dest) {
42 *allegro_errno = errno;
43 return NULL;
44 }
45 
46 memset(dest, 0, template_len + tmpdir_len + 2);
47 memcpy(dest, tmpdir, strlen( tmpdir ) );
48 
49 /* doing this check makes the path prettier, no extra / laying around */
50 if(dest[tmpdir_len-1] != '/') {
51 dest[tmpdir_len] = '/';
52 tmpdir_len++;
53 }
54 
55 memcpy(dest + tmpdir_len, template, template_len);
56 
57 for(i=0; i<MAX_MKTEMP_TRIES; ++i) {
58 _al_fs_mktemp_replace_XX(template, dest + tmpdir_len);
59 fd = open( dest, O_EXCL | O_CREAT | O_RDWR );
60 if(fd == -1)
61 continue;
62 
63 // changing the hook for create handle in a separate thread will cause some nice errors here,
64 // if you expect it to return a stdio handle ;)
65 fh = al_fs_create_handle( dest );
66 if(!fh) {
67 close(fd);
68 free(dest);
69 return NULL;
70 }
71 
72 fh->handle = fdopen( fd, "r+" );
73 if(!fh->handle) {
74 al_fs_stdio_destroy_handle(fh);
75 close(fd);
76 free(dest);
77 return NULL;
78 }
79 
80 if(ulink == AL_FS_MKTEMP_UNLINK_NOW)
81 unlink( dest );
82 else if(ulink == AL_FS_MKTEMP_UNLINK_ON_CLOSE)
83 fh->ulink = 1;
84 
85 fh->free_on_fclose = 1;
86 fh->path = dest;
87 
88 return fh;
89 }
90 
91 free(dest);
92 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Failed to create a uniqe temporary file"));
93 return NULL;
94}

It shouldn't be hard to make that do a dir at all. Or turn into code that doesn't rely on my Allegro 4.3 stuff.

Thread #590936. Printed from Allegro.cc