-----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-----