Initial version of new Session library
diff --git a/system/libraries/Session/drivers/Session_files_driver.php b/system/libraries/Session/drivers/Session_files_driver.php
new file mode 100644
index 0000000..4acbcf6
--- /dev/null
+++ b/system/libraries/Session/drivers/Session_files_driver.php
@@ -0,0 +1,276 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst.  It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		Andrey Andreev
+ * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * CodeIgniter Session Files Driver
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Sessions
+ * @author		Andrey Andreev
+ * @link		http://codeigniter.com/user_guide/libraries/sessions.html
+ */
+class CI_Session_files_driver extends CI_Session_driver implements SessionHandlerInterface {
+
+	/**
+	 * Save path
+	 *
+	 * @var	string
+	 */
+	protected $_save_path;
+
+	/**
+	 * File handle
+	 *
+	 * @var	resource
+	 */
+	protected $_file_handle;
+
+	/**
+	 * File name
+	 *
+	 * @var	resource
+	 */
+	protected $_file_path;
+
+	/**
+	 * File new flag
+	 *
+	 * @var	bool
+	 */
+	protected $_file_new;
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Class constructor
+	 *
+	 * @param	array	$params	Configuration parameters
+	 * @return	void
+	 */
+	public function __construct(&$params)
+	{
+		parent::__construct($params);
+
+		if (isset($this->_save_path))
+		{
+			$this->_save_path = rtrim($this->_save_path, '/\\');
+			ini_set('session.save_path', $this->_save_path);
+		}
+		else
+		{
+			$this->_save_path = rtrim(ini_get('session.save_path'), '/\\');
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function open($save_path, $name)
+	{
+		if ( ! is_dir($save_path) && ! mkdir($save_path, 0700, TRUE))
+		{
+			log_message('error', "Session: Configured save path '".$this->_save_path."' is not a directory, doesn't exist or cannot be created.");
+			return FALSE;
+		}
+
+		$this->_save_path = $save_path;
+		$this->_file_path = $this->_save_path.DIRECTORY_SEPARATOR
+			.$name // we'll use the session cookie name as a prefix to avoid collisions
+			.($this->_match_ip ? md5($_SERVER['REMOTE_ADDR']) : '');
+
+		return TRUE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function read($session_id)
+	{
+		// This might seem weird, but PHP 5.6 introduces session_reset(),
+		// which re-reads session data
+		if ($this->_file_handle === NULL)
+		{
+			$this->_file_path .= $session_id;
+
+			// Just using fopen() with 'c+b' mode would be perfect, but it is only
+			// available since PHP 5.2.6 and we have to set permissions for new files,
+			// so we'd have to hack around this ...
+			if (($this->_file_new = ! file_exists($this->_file_path)) === TRUE)
+			{
+				if (($this->_file_handle = fopen($this->_file_path, 'w+b')) === FALSE)
+				{
+					log_message('error', "Session: File '".$this->_file_path."' doesn't exist and cannot be created.");
+					return FALSE;
+				}
+			}
+			elseif (($this->_file_handle = fopen($this->_file_path, 'r+b')) === FALSE)
+			{
+				log_message('error', "Session: Unable to open file '".$this->_file_path."'.");
+				return FALSE;
+			}
+
+			if (flock($this->_file_handle, LOCK_EX) === FALSE)
+			{
+				log_message('error', "Session: Unable to obtain lock for file '".$this->_file_path."'.");
+				fclose($this->_file_handle);
+				$this->_file_handle = NULL;
+				return FALSE;
+			}
+
+			if ($this->_file_new)
+			{
+				chmod($this->_file_path, 0600);
+				$this->_fingerprint = md5('');
+				return '';
+			}
+		}
+		else
+		{
+			rewind($this->_file_handle);
+		}
+
+		$session_data = '';
+		for ($read = 0, $length = filesize($this->_file_path); $read < $length; $read += strlen($buffer))
+		{
+			if (($buffer = fread($this->_file_handle, $length - $read)) === FALSE)
+			{
+				break;
+			}
+
+			$session_data .= $buffer;
+		}
+
+		$this->_fingerprint = md5($session_data);
+		return $session_data;
+	}
+
+	public function write($session_id, $session_data)
+	{
+		if ( ! is_resource($this->_file_handle))
+		{
+			return FALSE;
+		}
+		elseif ($this->_fingerprint === md5($session_data))
+		{
+			return ($this->_file_new)
+				? TRUE
+				: touch($this->_file_path);
+		}
+
+		if ( ! $this->_file_new)
+		{
+			ftruncate($this->_file_handle, 0);
+			rewind($this->_file_handle);
+		}
+
+		for ($written = 0, $length = strlen($session_data); $written < $length; $written += $result)
+		{
+			if (($result = fwrite($this->_file_handle, substr($session_data, $written))) === FALSE)
+			{
+				break;
+			}
+		}
+
+		if ( ! is_int($result))
+		{
+			$this->_fingerprint = md5(substr($session_data, 0, $written));
+			log_message('error', 'Session: Unable to write data.');
+			return FALSE;
+		}
+
+		$this->_fingerprint = md5($session_data);
+		return TRUE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function close()
+	{
+		if (is_resource($this->_file_handle))
+		{
+			flock($this->_file_handle, LOCK_UN);
+			fclose($this->_file_handle);
+
+			$this->_file_handle = $this->_file_new = NULL;
+			return TRUE;
+		}
+
+		return FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function destroy($session_id)
+	{
+		if ($this->close())
+		{
+			return unlink($this->_file_path) && $this->_cookie_destroy();
+		}
+		elseif ($this->_file_path !== NULL)
+		{
+			clearstatcache();
+			return file_exists($this->_file_path)
+				? (unlink($this->_file_path) && $this->_cookie_destroy())
+				: TRUE;
+		}
+
+		return FALSE;
+	}
+
+	// ------------------------------------------------------------------------
+
+	public function gc($maxlifetime)
+	{
+		if ( ! is_dir($this->_save_path) OR ($files = scandir($this->_save_path)) === FALSE)
+		{
+			log_message('debug', "Session: Garbage collector couldn't list files under directory '".$this->_save_path."'.");
+			return FALSE;
+		}
+
+		$ts = time() - $maxlifetime;
+
+		foreach ($files as $file)
+		{
+			// If the filename doesn't match this pattern, it's either not a session file or is not ours
+			if ( ! preg_match('/(?:[0-9a-f]{32})?[0-9a-f]{40}$/i', $file)
+				OR ! is_file($this->_save_path.DIRECTORY_SEPARATOR.$file)
+				OR ($mtime = filemtime($file)) === FALSE
+				OR $mtime > $ts)
+			{
+				continue;
+			}
+
+			unlink($this->_save_path.DIRECTORY_SEPARATOR.$file);
+		}
+
+		return TRUE;
+	}
+
+}
+
+/* End of file Session_files_driver.php */
+/* Location: ./system/libraries/Session/drivers/Session_files_driver.php */
\ No newline at end of file