ef = talloc_zero(ctx, exfile_t);
if (!ef) return NULL;
+ ef->max_entries = max_entries;
+ ef->max_idle = max_idle;
+ ef->locking = locking;
+
+ /*
+ * If we're not locking the files, just return the
+ * handle. Each call to exfile_open() will just open a
+ * new file descriptor.
+ */
+ if (!locking) return ef;
+
ef->entries = talloc_zero_array(ef, exfile_entry_t, max_entries);
if (!ef->entries) {
talloc_free(ef);
}
#endif
- ef->max_entries = max_entries;
- ef->max_idle = max_idle;
- ef->locking = locking;
-
talloc_set_destructor(ef, _exfile_free);
return ef;
}
+/*
+ * Try to open the file. It it doesn't exist, try to
+ * create it's parent directories.
+ */
+static int exfile_open_mkdir(exfile_t *ef, char const *filename, mode_t permissions)
+{
+ int fd;
+
+ fd = open(filename, O_RDWR | O_CREAT, permissions);
+ if (fd < 0) {
+ mode_t dirperm;
+ char *p, *dir;
+
+ /*
+ * Maybe the directory doesn't exist. Try to
+ * create it.
+ */
+ dir = talloc_strdup(ef, filename);
+ if (!dir) return -1;
+ p = strrchr(dir, FR_DIR_SEP);
+ if (!p) {
+ fr_strerror_printf("No '/' in '%s'", filename);
+ return -1;
+ }
+ *p = '\0';
+
+ /*
+ * Ensure that the 'x' bit is set, so that we can
+ * read the directory.
+ */
+ dirperm = permissions;
+ if ((dirperm & 0600) != 0) dirperm |= 0100;
+ if ((dirperm & 0060) != 0) dirperm |= 0010;
+ if ((dirperm & 0006) != 0) dirperm |= 0001;
+
+ if (rad_mkdir(dir, dirperm, -1, -1) < 0) {
+ fr_strerror_printf("Failed to create directory %s: %s",
+ dir, strerror(errno));
+ talloc_free(dir);
+ return -1;
+ }
+ talloc_free(dir);
+
+ fd = open(filename, O_RDWR | O_CREAT, permissions);
+ if (fd < 0) {
+ fr_strerror_printf("Failed to open file %s: %s",
+ filename, strerror(errno));
+ return -1;
+ }
+ }
+
+ return fd;
+}
+
+
/** Open a new log file, or maybe an existing one.
*
* When multithreaded, the FD is locked via a mutex. This way we're
{
int i, found, tries, unused, oldest;
uint32_t hash;
- time_t now = time(NULL);
+ time_t now;
struct stat st;
if (!ef || !filename) return -1;
+ /*
+ * No locking: just return a new FD.
+ */
+ if (!ef->locking) {
+ found = exfile_open_mkdir(ef, filename, permissions);
+ if (found < 0) return -1;
+
+ if (append) (void) lseek(found, 0, SEEK_END);
+
+ return found;
+ }
+
+ /*
+ * It's faster to do hash comparisons of a string than
+ * full string comparisons.
+ */
hash = fr_hash_string(filename);
+ now = time(NULL);
PTHREAD_MUTEX_LOCK(&ef->mutex);
/*
* Open the file and try to lock it.
*/
- ef->entries[i].fd = open(filename, O_RDWR | O_APPEND | O_CREAT, permissions);
- if (ef->entries[i].fd < 0) {
- mode_t dirperm;
- char *p, *dir;
-
- /*
- * Maybe the directory doesn't exist. Try to
- * create it.
- */
- dir = talloc_strdup(ef, filename);
- if (!dir) goto error;
- p = strrchr(dir, FR_DIR_SEP);
- if (!p) {
- fr_strerror_printf("No '/' in '%s'", filename);
- goto error;
- }
- *p = '\0';
-
- /*
- * Ensure that the 'x' bit is set, so that we can
- * read the directory.
- */
- dirperm = permissions;
- if ((dirperm & 0600) != 0) dirperm |= 0100;
- if ((dirperm & 0060) != 0) dirperm |= 0010;
- if ((dirperm & 0006) != 0) dirperm |= 0001;
-
- if (rad_mkdir(dir, dirperm, -1, -1) < 0) {
- fr_strerror_printf("Failed to create directory %s: %s",
- dir, strerror(errno));
- talloc_free(dir);
- goto error;
- }
- talloc_free(dir);
-
- ef->entries[i].fd = open(filename, O_WRONLY | O_CREAT, permissions);
- if (ef->entries[i].fd < 0) {
- fr_strerror_printf("Failed to open file %s: %s",
- filename, strerror(errno));
- goto error;
- } /* else fall through to creating the rest of the entry */
- } /* else the file was already opened */
+ ef->entries[i].fd = exfile_open_mkdir(ef, filename, permissions);
+ if (ef->entries[i].fd < 0) goto error;
/*
* Try to lock it. If we can't lock it, it's because
* locked it. So, we close the current file, re-open it,
* and try again.
*/
- if (ef->locking) {
- /*
- * Lock from the start of the file.
- */
- if (lseek(ef->entries[i].fd, 0, SEEK_SET) < 0) {
- fr_strerror_printf("Failed to seek in file %s: %s", filename, strerror(errno));
- error:
- exfile_cleanup_entry(&ef->entries[i]);
- PTHREAD_MUTEX_UNLOCK(&(ef->mutex));
- return -1;
- }
+ /*
+ * Lock from the start of the file. It's the
+ * only point in the file which is guaranteed to
+ * exist, and to be consistent across all threads
+ * and processes.
+ */
+ if (lseek(ef->entries[i].fd, 0, SEEK_SET) < 0) {
+ fr_strerror_printf("Failed to seek in file %s: %s", filename, strerror(errno));
- /*
- * Busy-loop trying to lock the file.
- */
- for (tries = 0; tries < MAX_TRY_LOCK; tries++) {
- if (rad_lockfd_nonblock(ef->entries[i].fd, 0) >= 0) break;
+ error:
+ exfile_cleanup_entry(&ef->entries[i]);
+ PTHREAD_MUTEX_UNLOCK(&(ef->mutex));
+ return -1;
+ }
- if (errno != EAGAIN) {
- fr_strerror_printf("Failed to lock file %s: %s", filename, strerror(errno));
- goto error;
- }
+ /*
+ * Busy-loop trying to lock the file.
+ */
+ for (tries = 0; tries < MAX_TRY_LOCK; tries++) {
+ if (rad_lockfd_nonblock(ef->entries[i].fd, 0) >= 0) break;
- /*
- * Close the file and re-open it. It may
- * have been deleted. If it was deleted,
- * then it should now be unlocked.
- */
- close(ef->entries[i].fd);
- ef->entries[i].fd = open(filename, O_WRONLY | O_CREAT, permissions);
- if (ef->entries[i].fd < 0) {
- fr_strerror_printf("Failed to open file %s: %s",
- filename, strerror(errno));
- goto error;
- }
+ if (errno != EAGAIN) {
+ fr_strerror_printf("Failed to lock file %s: %s", filename, strerror(errno));
+ goto error;
}
- if (tries >= MAX_TRY_LOCK) {
- fr_strerror_printf("Failed to lock file %s: too many tries", filename);
+ /*
+ * Close the file and re-open it. It may
+ * have been deleted. If it was deleted,
+ * then it should now be unlocked.
+ */
+ close(ef->entries[i].fd);
+ ef->entries[i].fd = open(filename, O_WRONLY | O_CREAT, permissions);
+ if (ef->entries[i].fd < 0) {
+ fr_strerror_printf("Failed to open file %s: %s",
+ filename, strerror(errno));
goto error;
}
}
+ if (tries >= MAX_TRY_LOCK) {
+ fr_strerror_printf("Failed to lock file %s: too many tries", filename);
+ goto error;
+ }
+
/*
* Maybe someone deleted the file while we were waiting
* for the lock. If so, re-open it.
}
/*
- * Seek to the end of the file before returning the FD to
- * the caller.
+ * If we're appending, eek to the end of the file before
+ * returning the FD to the caller.
*/
if (append) lseek(ef->entries[i].fd, 0, SEEK_END);
{
uint32_t i;
+ /*
+ * No locking: just close the file.
+ */
+ if (!ef->locking) {
+ close(fd);
+ return 0;
+ }
+
+ /*
+ * Unlock the bytes that we had previously locked.
+ */
for (i = 0; i < ef->max_entries; i++) {
- /*
- * Unlock the bytes that we had previously locked.
- */
if (ef->entries[i].fd == fd) {
- if (ef->locking) {
- (void) lseek(ef->entries[i].fd, 0, SEEK_SET);
- (void) rad_unlockfd(ef->entries[i].fd, 0);
- }
+ (void) lseek(ef->entries[i].fd, 0, SEEK_SET);
+ (void) rad_unlockfd(ef->entries[i].fd, 0);
PTHREAD_MUTEX_UNLOCK(&(ef->mutex));
return 0;