Index: extensions/EStat/lib/statDB.class.inc.php
===================================================================
--- extensions/EStat/lib/statDB.class.inc.php	(revision 17760)
+++ extensions/EStat/lib/statDB.class.inc.php	(revision 17862)
@@ -9,8 +9,10 @@
 define('ASDF_EXIST_PACKED',   0x01);
 define('ASDF_EXIST_UNPACKED', 0x02);
+define('ASDF_EXIST_LOCK',     0x04);
 define('ASDF_EXIST_ALL', ASDF_EXIST_PACKED|ASDF_EXIST_UNPACKED);
 
 define('ASDF_FILE_EXT', '.db');
 define('ASDF_FILE_EXT_ZIP', ASDF_FILE_EXT.'.gz');
+define('ASDF_FILE_EXT_LOCK', '.lock');
 define('ASDF_FILE_ROOT_MONTH', 'M');
 define('ASDF_FILE_ROOT_GLOBAL', 'G');
@@ -55,5 +57,6 @@
   protected $transacOpen=false;
   protected $ipCountryFile='';
-
+  protected $lckFileNumber=0;
+  //protected $logs=''; for debug
   private $deleteUnpackedWhenClose=ASDF_CLOSE_DO_NOTHING;
 
@@ -218,9 +221,10 @@
    * if $mode=ASDF_OPEN_WRITE and file doesn't exist, create it; if a packed file
    * exist, try to unpack the packed file; in this case the unpacked file will be
-   * packed and removed automatically when the process will close.
+   * packed and removed automatically when the process will close
    *
    * if $mode=ASDF_OPEN_READ, and unpacked file doesn't exist, try to unpack
    * packed file (if exists); in this case the unpacked file will be removed
-   * automatically when the process will close.
+   * automatically when the process will close (if there's no lock
+   * files linked to the uncompressed file); a new lock file is created
    *
    * @param Integer $mode: READ or WRITE
@@ -230,4 +234,6 @@
   {
     $dbFile=$this->getFileName(ASDF_EXIST_UNPACKED, true);
+    $this->createLockFile();
+    $this->waitForUnpackedFile();
 
     /*
@@ -252,4 +258,9 @@
         $this->deleteUnpackedWhenClose=ASDF_CLOSE_DO_DELETE; // the unpacked file will be deleted when the process will close
       }
+    }
+    else
+    {
+      if($this->lckFileNumber>1 and $this->getFileName(ASDF_EXIST_PACKED, true)!='' and $mode==ASDF_OPEN_READ)
+        $this->deleteUnpackedWhenClose=ASDF_CLOSE_DO_DELETE;
     }
 
@@ -293,5 +304,7 @@
       }
 
-      if(($this->deleteUnpackedWhenClose&ASDF_CLOSE_DO_DELETE)==ASDF_CLOSE_DO_DELETE)
+      $this->deleteLockFile();
+      if(($this->deleteUnpackedWhenClose&ASDF_CLOSE_DO_DELETE)==ASDF_CLOSE_DO_DELETE and
+          !$this->fileIsLocked())
       {
         $this->delete(ASDF_DELETE_UNPACKED);
@@ -330,15 +343,18 @@
     if($this->fileExist() & ASDF_EXIST_PACKED==ASDF_EXIST_PACKED)
     {
-      $returned=GPCCompress::gunzip($this->getFileName(ASDF_EXIST_PACKED), $this->getFileName(ASDF_EXIST_UNPACKED));
-      /*
-      $dir=dirName(dirName($this->getFileName(ASDF_EXIST_UNPACKED)));
-      $tH=fopen($dir.'/logs.log', 'a');
-      if($tH)
-      {
-        $dest=$this->getFileName(ASDF_EXIST_UNPACKED);
-        fwrite($tH, sprintf("%s - %30s - %10d - %s\n", date('Y-m-d H:i:s'), $dest, filesize($dest), $returned?'y':'n'));
-        fclose($tH);
-      }
-*/
+      $unpackedFile=$this->getFileName(ASDF_EXIST_UNPACKED);
+
+      // create a temp file
+      $fHandle=fopen($unpackedFile, 'w');
+      fclose($fHandle);
+
+      $returned=GPCCompress::gunzip($this->getFileName(ASDF_EXIST_PACKED), $unpackedFile.'.tmp');
+
+      unlink($unpackedFile);
+      if($returned)
+      {
+        rename($unpackedFile.'.tmp', $unpackedFile);
+      }
+
       return($returned);
     }
@@ -422,4 +438,7 @@
       case ASDF_EXIST_UNPACKED:
         $fileName=$this->fileDir.$this->fileName.$this->fileRootName.ASDF_FILE_EXT;
+        break;
+      case ASDF_EXIST_LOCK:
+        $fileName=$this->fileDir.$this->fileName.$this->fileRootName.'-'.$this->lckFileNumber.ASDF_FILE_EXT_LOCK;
         break;
     }
@@ -517,4 +536,145 @@
     if($returned==null) $returned=$value;
     return($returned);
+  }
+
+  /**
+   * how the file lock system works:
+   *
+   * the lock system is used only when for uncompressed files, allowing to know
+   * if an uncompressed file can be deleted or not; locks function are called only
+   * in READ mode by function open() and close()
+   *
+   * createLockFile()
+   *  1/ Search for existing lock files
+   *  2/ If files are found, increase the $lckFileNumber with number of existing files + 1
+   *  3/ Create the lock file
+   *
+   * deleteLockFile()
+   *  delete the lock file associated with the current $lckFileNumber
+   *
+   * fileIsLocked()
+   *  return true if at least, one lock exists
+   *
+   *  ......................................
+   *          ......................................
+   *                   ..............
+   * -+-------+--------+------------+------+-------+-->
+   * (A)     (B)      (C)          (D)    (E)     (F)
+   *  ^       ^        ^            ^      ^       ^
+   *  p1      p2       p3           p3     p1      p2
+   *  start   start    start        end    end     end
+   *
+   * (A) process 1 start: createLockFile() => lock file '1' is created
+   * (B) process 2 start: createLockFile() => lock file '2' is created
+   * (C) process 3 start: createLockFile() => lock file '3' is created
+   * (D) process 3 end:   deleteLockFile() => lock file '3' is deleted
+   *                                          lock files '1' & '2' still exist (uncompressed SQLite file can't be deleted)
+   * (E) process 1 end:   deleteLockFile() => lock file '1' is deleted
+   *                                          lock file '2' still exist (uncompressed SQLite file can't be deleted)
+   * (F) process 2 end:   deleteLockFile() => lock file '2' is deleted
+   *                                          there's no lock files (uncompressed SQLite file can be deleted)
+   *
+   * @return Boolean: true if the lock file was created, otherwise false
+   */
+  protected function createLockFile()
+  {
+    $this->lckFileNumber=$this->getNumberOfLockFiles()+1;
+    $fHandle=fopen($this->getFileName(ASDF_EXIST_LOCK), 'w');
+    if($fHandle)
+    {
+      fclose($fHandle);
+      return(true);
+    }
+    $this->lckFileNumber=0;
+    return(false);
+  }
+
+  /**
+   * delete the current lock file
+   * return true if file is deleted (or file doesn't exists => there's no more file to delete...), otherwise return false
+   *
+   * the function also delete all lock files older than current timestamp+max_execution_time (if
+   * the file still exist, it means that a problem has occured at a moment)
+   *
+   * @return Boolean
+   */
+  protected function deleteLockFile()
+  {
+    $returned=true;
+    $file=$this->getFileName(ASDF_EXIST_LOCK);
+    if(file_exists($file)) $returned=unlink($file);
+
+    if($returned) $this->lckFileNumber=0;
+
+    $regExp="/\\".ASDF_FILE_EXT_LOCK.'/i';
+    scandir(dirName($this->fileDir));
+    $files=scandir($this->fileDir);
+    $timeOut=time()-ini_get('max_execution_time');
+
+    foreach($files as $file)
+    {
+      if(preg_match($regExp, $file, $result)>0)
+      {
+        if(filemtime($this->fileDir.$file)<$timeOut)
+        {
+          unlink($this->fileDir.$file);
+        }
+      }
+    }
+
+
+
+    return($returned);
+  }
+
+  /**
+   * return true if a lock file exists
+   *
+   * @return Boolean
+   */
+  protected function fileIsLocked()
+  {
+    if($this->getNumberOfLockFiles()>0) return(true);
+    return(false);
+  }
+
+  /**
+   * return true the number of existing lock files
+   *
+   * @return Integer: number of existing lock files
+   */
+  protected function getNumberOfLockFiles()
+  {
+    $returned=0;
+    $regExp='/'.$this->fileName.$this->fileRootName."-(\d+)\\".ASDF_FILE_EXT_LOCK.'/i';
+    $files=scandir($this->fileDir);
+    foreach($files as $file)
+    {
+      if(preg_match($regExp, $file, $result)>0)
+      {
+        $tmp=$result[1]*1;
+        if($tmp>$returned) $returned=$tmp;
+      }
+    }
+    return($returned);
+  }
+
+  /**
+   * if the unpacked exist with a '.tmp' extension, assume that an unpacking process
+   * is running and loop until the file doesn't exist anymore
+   *
+   * @param Integer $maxWait: maximum wait time in millisecond...
+   * @return Boolean: true if file was unpacked in the waiting time, otherwise false
+   */
+  protected function waitForUnpackedFile($maxWait=2000)
+  {
+    $tmpFile=$this->getFileName(ASDF_EXIST_UNPACKED).'.tmp';
+    $maxTimer=microtime(true)+$maxWait/1000;
+    while(file_exists($tmpFile))
+    {
+      if(microtime(true)>=$maxTimer) return(false);
+      usleep(5000); //wait 5milliseconds before next check
+    }
+    return(true);
   }
 
@@ -1190,5 +1350,23 @@
 
 
-}
+/*
+  for debug
+
+  private function log($data)
+  {
+    if($this->logs=='') return(false);
+    $tH=fopen(dirName($this->fileDir).'/logs.log', 'a');
+    if($tH)
+    {
+      $time=microtime(true);
+      fwrite($tH, sprintf("%s %f - %s\n", $this->logs, $time, $data));
+
+      fclose($tH);
+    }
+  }
+*/
+
+
+} // StatDB
 
 
@@ -1213,4 +1391,3 @@
 
 
-
 ?>
Index: extensions/EStat/lib/statDBGlobal.class.inc.php
===================================================================
--- extensions/EStat/lib/statDBGlobal.class.inc.php	(revision 17760)
+++ extensions/EStat/lib/statDBGlobal.class.inc.php	(revision 17862)
@@ -240,6 +240,7 @@
     if($packed!='')
     {
+      // packed file was unpacked, pack file only if file was already packed
       if($fmPeriod->pack())
-        $fmPeriod->delete(ASDF_DELETE_UNPACKED); //packed file was unpacked, keep only packed file
+        $fmPeriod->delete(ASDF_DELETE_UNPACKED);
     }
     return($returned);
