-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 16/04/10 14:59, Fabian Knittel wrote:
> Hi David,
>
> David Sommerseth wrote:
> (BTW, I thought creat() took a flags parameter, but it only takes a mode
> param. My mistake. So you're correct in wanting to use open() instead of
> creat().)
>
> To let the code speak, here's my suggestion (not compile-tested):
>
>> do
>> {
>> uint8_t rndbytes[16];
>> const char *rndstr;
>>
>> ++attempts;
>> mutex_lock_static (L_CREATE_TEMP);
>> ++counter;
>> mutex_unlock_static (L_CREATE_TEMP);
>>
>> prng_bytes (rndbytes, sizeof rndbytes);
>> rndstr = format_hex_ex (rndbytes, sizeof rndbytes, 40, 0, NULL, gc);
>> buf_printf (&fname, PACKAGE "_%s_%s.tmp", prefix, rndstr);
>>
>> retfname = gen_path (directory, BSTR (&fname), gc);
>> if (!retfname)
>> {
>> msg (M_FATAL, "Failed to create temporary filename and path");
>> return NULL;
>> }
>>
>> /* Atomically create the file. Errors out if the file already
>> exists. */
>> fd = open (retfname, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
>> if (fd != -1)
>> {
>> close (fd);
>> return retfname;
>> }
>> else if (fd == -1 && errno != EEXIST)
>> {
>> /* Something else went wrong, no need to retry. */
>> struct gc_arena gcerr = gc_new ();
>> msg (M_FATAL, "Could not create temporary file '%s': %s",
>> retfname, strerror_ts (errno, &gcerr));
>> gc_free (&gcerr);
>> return NULL;
>> }
>> }
>> while (attempts < 6);
>>
>> msg (M_FATAL, "Failed to create temporary file after %i attempts", attempts);
>> return NULL;
I like it! It looks cleaner! Thanks for standing the argument ;-)
I'll look at a new patch, hopefully today.
> (Regarding the code style: The above uses what I had thought would be
> the current style, but as I've only read parts of the OpenVPN code, I'm
> likely to be wrong. Are there any code-parts / newer code-parts which
> should be considered reference material?)
I don't think so. You might find some few differences throughout the
code, but the coding style is not documented anywhere, to my knowledge.
>> I've dived into the kernel code to see what it *really* does (when the
>> man page are so unclear), and it should behave as those other Unices
>> does as well. So, O_EXCL do make sense to avoid overwriting existing
>> files if it is a symlink to an existing file.
>
> IMHO the Linux man-page ist quite clear (I'm using version 3.24):
>
>> O_EXCL Ensure that this call creates the file: if this flag is
>> speci‐
>> fied in conjunction with O_CREAT, and pathname already
>> exists,
>> then open() will fail. The behavior of O_EXCL is undefined
>> if
>> O_CREAT is not specified.
>>
>> When these two flags are specified, symbolic links are not
>> fol‐
>> lowed: if pathname is a symbolic link, then open() fails
>> regard‐
>> less of where the symbolic link points to.
>>
>> O_EXCL is only supported on NFS when using NFSv3 or later
>> on
>> kernel 2.6 or later.
This sentence is the one which made me uncertain. Because here it
restricts things more to NFS. I've already suggested a patch to the
man-pages maintainer clarifying this paragraph.
>> In environments where NFS O_EXCL support
>> is not provided, programs that rely on it for performing
>> locking
>> tasks will contain a race condition. Portable programs
>> that
>> want to perform atomic file locking using a lockfile, and
>> need
>> to avoid reliance on NFS support for O_EXCL, can create a
>> unique
>> file on the same file system (e.g., incorporating hostname
>> and
>> PID), and use link(2) to make a link to the lockfile.
>> If
>> link(2) returns 0, the lock is successful. Otherwise,
>> use
>> stat(2) on the unique file to check if its link count
>> has
>> increased to 2, in which case the lock is also successful.
>
> Using open with O_CREAT|O_EXCL:
> - makes the atomic guarantee, that the file was created by us (or
> the function call fails)
> - does not follow symlinks (if a symlink exists, it fails)
> - works over NFS for NFS implementations that support O_EXCL. (This
> should apply to all current Linux NFS implementations.)
>
> So, anything remaining that you'd like cleared up?
Nope :)
kind regards,
David Sommerseth
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
iEUEARECAAYFAkvIrLUACgkQDC186MBRfrroVwCfWA0XoZHtQ/oTWC0pSTIL1qum
54gAmMH1al5cXbaEafUS6PMkqnmMm2U=
=E8fx
-----END PGP SIGNATURE-----