mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[sys] Add a function to safely create a unique file
QF currently uses unique file names for screenshots and server-side demos (and remote snapshots), but they're generally useful. QFS_NextFilename has been filling this role, but it is highly insecure in its current implementation. This is the first step to taking care of that.
This commit is contained in:
parent
14ad364e17
commit
a35bfef24c
2 changed files with 60 additions and 0 deletions
|
@ -38,6 +38,8 @@
|
|||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
struct dstring_s;
|
||||
|
||||
extern struct cvar_s *sys_nostdout;
|
||||
extern struct cvar_s *sys_extrasleep;
|
||||
extern struct cvar_s *sys_dead_sleep;
|
||||
|
@ -166,6 +168,37 @@ int Sys_CreatePath (const char *path);
|
|||
*/
|
||||
char *Sys_ExpandSquiggle (const char *path);
|
||||
|
||||
/** Open a newly created file with a guaranteed unique name.
|
||||
|
||||
Uniqueness is guaranteed by adding a numeric sequence between the \a
|
||||
prefix and \a suffix, with a minium of \a mindigits numeric characters
|
||||
(with any required leading 0s to expand the number to \a mindigits).
|
||||
|
||||
The created file has read and write permissions as modified by the OS,
|
||||
and the handle can be bothe written and read.
|
||||
|
||||
\param name dstring into which the name will be generated. Any
|
||||
existing contents will be lost. If an error occurs,
|
||||
\a name will be set to the error string.
|
||||
\param prefix This includes the path to the file and any file name
|
||||
prefix. The numeric sequence will be appended directly
|
||||
to the prefix with no directory separator.
|
||||
\param suffix Optional tail to be appended after the numeric sequence,
|
||||
usually the file extension. A dot is not added
|
||||
automatically, it is up to the caller to supply one. NULL
|
||||
and an empty string are equivalent.
|
||||
\param mindigits The minimum number of digits to include in the
|
||||
generated file name. The sequence number will be padded
|
||||
with 0s in order to meet this menimum. Overflow will
|
||||
simply produce longer numeric sequence sub-strings.
|
||||
\return File handle to the newly created file, or a negative
|
||||
value if an error occured (the negative error code).
|
||||
Suitable for use with read, write, fdopen, Qdopen, etc.
|
||||
\note It is the caller's responsibility to close the file.
|
||||
*/
|
||||
int Sys_UniqueFile (struct dstring_s *name, const char *prefix,
|
||||
const char *suffix, int mindigits);
|
||||
|
||||
///@}
|
||||
|
||||
#endif//__QF_sys_h
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
# include <pwd.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#include <errno.h>
|
||||
|
@ -1155,3 +1156,29 @@ Sys_ExpandSquiggle (const char *path)
|
|||
home = ".";
|
||||
return nva ("%s%s", home, path + 1); // skip leading ~
|
||||
}
|
||||
|
||||
VISIBLE int
|
||||
Sys_UniqueFile (dstring_t *name, const char *prefix, const char *suffix,
|
||||
int mindigits)
|
||||
{
|
||||
const int flags = O_CREAT | O_EXCL | O_RDWR;
|
||||
const int mode = 0644;
|
||||
int64_t seq = 0; // it should take a while to run out
|
||||
|
||||
if (!suffix) {
|
||||
suffix = "";
|
||||
}
|
||||
while (1) {
|
||||
dsprintf (name, "%s%0*"PRIi64"%s", prefix, mindigits, seq, suffix);
|
||||
int fd = open (name->str, flags, mode);
|
||||
if (fd >= 0) {
|
||||
return fd;
|
||||
}
|
||||
int err = errno;
|
||||
if (err != EEXIST) {
|
||||
dsprintf (name, "%s", strerror (err));
|
||||
return -err;
|
||||
}
|
||||
seq++;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue