CGI-SpeedyCGI

 view release on metacpan or  search on metacpan

src/speedy_file.c  view on Meta::CPAN

    }
}

static void file_map(unsigned int len) {
    if (maplen != len) {
	file_unmap();
	maplen = len;
	if (len) {
	    speedy_file_maddr = (speedy_file_t*)mmap(
		0, len, PROT_READ | PROT_WRITE, MAP_SHARED, file_fd, 0
	    );
	    if (speedy_file_maddr == (speedy_file_t*)MAP_FAILED)
		speedy_util_die("mmap failed");
	}
    }
}

static void file_unlock(void) {
    struct flock fl;

    if (!file_locked)
	return;

    FILE_HEAD.lock_owner = 0;

    fillin_fl(fl);
    fl.l_type = F_UNLCK;
    if (fcntl(file_fd, F_SETLK, &fl) == -1) speedy_util_die("unlock file");
    file_locked = 0;

    speedy_sig_blockall_undo();
}

/* Only call this if you're sure the fd is not suspect */
static void file_close2(void) {

#ifdef SPEEDY_BACKEND
    if (fd_is_suspect)
	DIE_QUIET("file_close2: assertion failed - fd_is_suspect");
#endif

    file_unlock();
    file_unmap();
    if (file_fd != -1) {
	(void) close(file_fd);
	file_fd = -1;
    }
}


#ifdef SPEEDY_BACKEND
SPEEDY_INLINE void speedy_file_fd_is_suspect(void) {
    fd_is_suspect = 1;
}

static void fix_suspect_fd(void) {
    if (fd_is_suspect) {
	if (file_fd != -1) {
	    struct stat stbuf;

	    if (fstat(file_fd, &stbuf) == -1 ||
		stbuf.st_dev != file_stat.st_dev ||
		stbuf.st_ino != file_stat.st_ino)
	    {
		file_unmap();
		file_fd = -1;
	    }
	}
	fd_is_suspect = 0;
    }
}
#endif


#define get_stat() \
    if (fstat(file_fd, &file_stat) == -1) speedy_util_die("fstat")

static void remove_file(int is_corrupt) {
#ifdef SPEEDY_DEBUG
    if (is_corrupt) {
	/* Keep the file for debugging */
	char newname[200];
	struct timeval tv;

	gettimeofday(&tv, NULL);
	sprintf(newname, "%s.corrupt.%d.%06d.%d",
	    file_name, (int)tv.tv_sec, (int)tv.tv_usec, getpid());
	if (rename(file_name, newname) == -1)
	    speedy_util_die("rename temp file");
	FILE_HEAD.file_removed = 1;
	DIE_QUIET("temp file corrupt");
    }
#endif
    if (unlink(file_name) == -1 && errno != ENOENT)
	speedy_util_die("unlink temp file");
    FILE_HEAD.file_removed = 1;
}

static void str_replace(char **ptr, char *newval) {
    if (*ptr)
	speedy_free(*ptr);
    *ptr = newval;
}

static void file_lock(void) {
    static struct timeval file_create_time;
    struct flock fl;
    int tries;
    time_t now;

    if (file_locked)
	return;

#ifdef SPEEDY_BACKEND
    fix_suspect_fd();
#endif

    /* Re-open the temp file occasionally or if tmpbase changed */
    if ((now = speedy_util_time()) - last_reopen > OPTVAL_RESTATTIMEOUT ||
	!saved_tmpbase || strcmp(saved_tmpbase, OPTVAL_TMPBASE) != 0)
    {
	last_reopen = now;
	file_close2();
    }

    for (tries = 5; tries; --tries) {
	/* If file is not open, open it */
	if (file_fd == -1) {
	    str_replace(&saved_tmpbase, speedy_util_strdup(OPTVAL_TMPBASE));
	    str_replace(&file_name, speedy_util_fname(FILE_REV, 'F'));
	    file_fd = speedy_util_pref_fd(
		open(file_name, O_RDWR | O_CREAT, 0600), PREF_FD_FILE
	    );
	    if (file_fd == -1) speedy_util_die("open temp file");
	    fcntl(file_fd, F_SETFD, FD_CLOEXEC);
	}

	/* Lock the file */
	fillin_fl(fl);
	fl.l_type = F_WRLCK;
	if (fcntl(file_fd, F_SETLKW, &fl) == -1) speedy_util_die("lock file");

	/* Fstat the file, now that it's locked down */
	get_stat();

	/* Map into memory */
	file_map(file_stat.st_size);

	/* If file is too small (0 or below MIN_SLOTS_FREE), extend it */
	if (file_stat.st_size < sizeof(file_head_t) ||
	    file_stat.st_size < sizeof(file_head_t) +
		sizeof(slot_t) * (FILE_HEAD.slots_alloced + MIN_SLOTS_FREE))
	{
	    if (ftruncate(file_fd, file_stat.st_size + FILE_ALLOC_CHUNK) == -1)
		speedy_util_die("ftruncate");
	    get_stat();
	    file_map(file_stat.st_size);
	}

	/* Initialize file's create time if necessary */
	if (!FILE_HEAD.create_time.tv_sec)
	    speedy_util_gettimeofday(&(FILE_HEAD.create_time));
	
	/* Initialize our copy of the create-time if necessary */
	if (!file_create_time.tv_sec || cur_state < FS_HAVESLOTS) {
	    file_create_time = FILE_HEAD.create_time;
	}
	/* Check whether this file is a different version  */
	else if ((file_create_time.tv_sec  != FILE_HEAD.create_time.tv_sec ||
	          file_create_time.tv_usec != FILE_HEAD.create_time.tv_usec))
	{
	    remove_file(1);
	}

	/* If file is corrupt (didn't finish all writes), remove it */
	if (FILE_HEAD.lock_owner)
	    remove_file(1);

	/* If file has not been removed then all done */
	if (!FILE_HEAD.file_removed)
	    break;

	/* File is invalid */
	if (cur_state >= FS_HAVESLOTS) {
	    /* Too late for this proc - slotnums have changed, can't recover */
	    DIE_QUIET("temp file is corrupt");
	} else {
	    /* Bad luck - the file was unlinked after we opened it (possibly
	     * by us because it was corrupt), but before we locked it.
	     * Try again.
	     */
	    file_close2();
	}
    }
    if (!tries) {
	DIE_QUIET("could not open temp file");
    }

    /* Block all sigs while writing to file */
    speedy_sig_blockall();
    file_locked = 1;
    FILE_HEAD.lock_owner = speedy_util_getpid();
}

static void file_close(void) {
    /* If no groups left, remove the file */
    if (cur_state >= FS_HAVESLOTS) {
	file_lock();
	if (!FILE_HEAD.group_head && !FILE_HEAD.fe_run_head)
	    remove_file(0);
    }
    file_close2();
}

int speedy_file_size(void) {
    return maplen;



( run in 0.673 second using v1.01-cache-2.11-cpan-5b529ec07f3 )