]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
baculum: Add to BVFS lsdirs, lsfiles and versions endpoints new output=raw/json parameter
authorMarcin Haba <marcin.haba@bacula.pl>
Thu, 12 Dec 2019 04:16:56 +0000 (05:16 +0100)
committerMarcin Haba <marcin.haba@bacula.pl>
Tue, 17 Dec 2019 17:19:39 +0000 (18:19 +0100)
gui/baculum/protected/API/Class/BLStat.php [new file with mode: 0644]
gui/baculum/protected/API/Class/BVFS.php [new file with mode: 0644]
gui/baculum/protected/API/Class/ConsoleOutputPage.php
gui/baculum/protected/API/Pages/API/BVFSLsDirs.php
gui/baculum/protected/API/Pages/API/BVFSLsFiles.php
gui/baculum/protected/API/Pages/API/BVFSVersions.php
gui/baculum/protected/API/Pages/API/ClientShow.php
gui/baculum/protected/API/Pages/API/config.xml
gui/baculum/protected/API/openapi_baculum.json
gui/baculum/protected/Common/Class/Miscellaneous.php
gui/baculum/protected/Web/Pages/RestoreWizard.php

diff --git a/gui/baculum/protected/API/Class/BLStat.php b/gui/baculum/protected/API/Class/BLStat.php
new file mode 100644 (file)
index 0000000..5845ba5
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2019 Kern Sibbald
+ *
+ * The main author of Baculum is Marcin Haba.
+ * The original author of Bacula is Kern Sibbald, with contributions
+ * from many others, a complete list can be found in the file AUTHORS.
+ *
+ * You may use this file and others of this release according to the
+ * license defined in the LICENSE file, which includes the Affero General
+ * Public License, v3.0 ("AGPLv3") and some additional permissions and
+ * terms pursuant to its AGPLv3 Section 7.
+ *
+ * This notice must be preserved when any source code is
+ * conveyed and/or propagated.
+ *
+ * Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+
+/**
+ * Bacula LStat value support.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Module
+ * @package Baculum API
+ */
+class BLStat extends APIModule {
+
+       /**
+        * Decode Bacula base64 encoded LStat value.
+        *
+        * @param string $lstat encoded LStat string
+        * @return array decoded values from LStat string
+        */
+       public function decode($lstat) {
+               $base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+               $lstat = trim($lstat);
+               $lstat_fields = explode(' ', $lstat);
+               $lstat_len = count($lstat_fields);
+               if ($lstat_len < 16) {
+                       // not known or empty lstat value
+                       return;
+               } elseif ($lstat_len > 16) {
+                       // cut off unknown fields
+                       array_splice($lstat_fields, 16);
+               }
+
+               list(
+                       $dev,
+                       $inode,
+                       $mode,
+                       $nlink,
+                       $uid,
+                       $gid,
+                       $rdev,
+                       $size,
+                       $blocksize,
+                       $blocks,
+                       $atime,
+                       $mtime,
+                       $ctime,
+                       $linkfi,
+                       $flags,
+                       $data
+               ) = $lstat_fields;
+               $encoded_values = array(
+                       'dev' => $dev,
+                       'inode' => $inode,
+                       'mode' => $mode,
+                       'nlink' => $nlink,
+                       'uid' => $uid,
+                       'gid' => $gid,
+                       'rdev' => $rdev,
+                       'size' => $size,
+                       'blocksize' => $blocksize,
+                       'blocks' => $blocks,
+                       'atime' => $atime,
+                       'mtime' => $mtime,
+                       'ctime' => $ctime,
+                       'linkfi' => $linkfi,
+                       'flags' => $flags,
+                       'data' => $data
+               );
+
+               $ret = array();
+               foreach($encoded_values as $key => $val) {
+                       $result = 0;
+                       $is_minus = false;
+                       $start = 0;
+
+                       if(substr($val, 0, 1) === '-') {
+                               $is_minus = true;
+                               $start++;
+                       }
+
+                       for($i = $start; $i < strlen($val); $i++) {
+                               $result = bcmul($result, bcpow(2,6));
+                               $result +=  strpos($base64, substr($val, $i , 1));
+                       }
+                       $ret[$key] = ($is_minus === true) ? -$result : $result;
+               }
+               return $ret;
+       }
+}
+?>
diff --git a/gui/baculum/protected/API/Class/BVFS.php b/gui/baculum/protected/API/Class/BVFS.php
new file mode 100644 (file)
index 0000000..a3fb505
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum   - Bacula web interface
+ *
+ * Copyright (C) 2013-2019 Kern Sibbald
+ *
+ * The main author of Baculum is Marcin Haba.
+ * The original author of Bacula is Kern Sibbald, with contributions
+ * from many others, a complete list can be found in the file AUTHORS.
+ *
+ * You may use this file and others of this release according to the
+ * license defined in the LICENSE file, which includes the Affero General
+ * Public License, v3.0 ("AGPLv3") and some additional permissions and
+ * terms pursuant to its AGPLv3 Section 7.
+ *
+ * This notice must be preserved when any source code is
+ * conveyed and/or propagated.
+ *
+ * Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+
+/**
+ * BVFS module class.
+ * It provides tools to work with BVFS outputs.
+ *
+ * @author Marcin Haba <marcin.haba@bacula.pl>
+ * @category Module
+ * @package Baculum API
+ */
+class BVFS extends APIModule {
+
+       const DIR_PATTERN = '/^(?P<pathid>\d+)\t(?P<filenameid>\d+)\t(?P<fileid>\d+)\t(?P<jobid>\d+)\t(?P<lstat>[a-zA-z0-9\+\/\ ]+)\t(?P<name>(.*\/|\.{2}))$/';
+       const FILE_PATTERN = '/^(?P<pathid>\d+)\t(?P<filenameid>\d+)\t(?P<fileid>\d+)\t(?P<jobid>\d+)\t(?P<lstat>[a-zA-z0-9\+\-\/\ ]+)\t(?P<name>[^\/]+)$/';
+       const VERSION_PATTERN = '/^(?P<pathid>\d+)\t(?P<filenameid>\d+)\t(?P<fileid>\d+)\t(?P<jobid>\d+)\t(?P<lstat>[a-zA-Z0-9\+\/\ ]+)\t(?P<md5>.+)\t(?P<volname>.+)\t(?P<inchanger>\d+)$/';
+
+       public function parseFileDirList($list) {
+               $elements = array();
+               $blstat = $this->getModule('blstat');
+               for($i = 0; $i < count($list); $i++) {
+                       if(preg_match(self::DIR_PATTERN, $list[$i], $match) == 1) {
+                               if($match['name'] == '.') {
+                                       continue;
+                               }
+                               $elements[] = array(
+                                       'pathid' => $match['pathid'],
+                                       'filenameid' => $match['filenameid'],
+                                       'fileid' => $match['fileid'],
+                                       'jobid' => $match['jobid'],
+                                       'lstat' => $blstat->decode($match['lstat']),
+                                       'name' => $match['name'],
+                                       'type' => 'dir'
+                               );
+                       } elseif(preg_match(self::FILE_PATTERN, $list[$i], $match) == 1) {
+                               if($match['name'] == '.') {
+                                       continue;
+                               }
+                               $elements[] = array(
+                                       'pathid' => $match['pathid'],
+                                       'filenameid' => $match['filenameid'],
+                                       'fileid' => $match['fileid'],
+                                       'jobid' => $match['jobid'],
+                                       'lstat' => $blstat->decode($match['lstat']),
+                                       'name' => $match['name'],
+                                       'type' => 'file'
+                               );
+                       }
+               }
+               usort($elements, 'sortFilesListByName');
+               return $elements;
+       }
+
+       public function parseFileVersions($list) {
+               $elements = array();
+               for($i = 0; $i < count($list); $i++) {
+                       if(preg_match(self::VERSION_PATTERN, $list[$i], $match) == 1) {
+                               $elements[$match['fileid']] = array(
+                                       'pathid' => $match['pathid'],
+                                       'filenameid' => $match['filenameid'],
+                                       'fileid' => $match['fileid'],
+                                       'jobid' => $match['jobid'],
+                                       'lstat' => $this->getModule('blstat')->decode($match['lstat']),
+                                       'md5' => $match['md5'],
+                                       'volname' => $match['volname'],
+                                       'inchanger' => $match['inchanger'],
+                                       'type' => 'file'
+                               );
+                       }
+               }
+               return $elements;
+       }
+
+}
+
+/*
+ * Small sorting callback function to sort files and directories by name.
+ * Function keeps '.' and '..' names always in the beginning of array.
+ * Used to sort files and directories from Bvfs.
+ */
+function sortFilesListByName($a, $b) {
+       $firstLeft = substr($a['name'], 0, 1);
+       $firstRight = substr($b['name'], 0, 1);
+       if ($firstLeft == '.' && $firstRight != '.') {
+               return -1;
+       } else if ($firstRight == '.' && $firstLeft != '.') {
+               return 1;
+       }
+       return strcasecmp($a['name'], $b['name']);
+}
+?>
index 2c8a8d39df922a1ff9af30bb03352baba97200e5..ad196c66ce11c0a3f5b7aa7edbb8b6d90ac862c2 100644 (file)
@@ -38,12 +38,12 @@ abstract class ConsoleOutputPage extends BaculumAPIServer {
        /**
         * Get raw output from console.
         */
-       abstract protected function getRawOutput($params = array());
+       abstract protected function getRawOutput($params = []);
 
        /**
         * Get parsed JSON output from console.
         */
-       abstract protected function getJSONOutput($params = array());
+       abstract protected function getJSONOutput($params = []);
 
        /**
         * Validate output format.
index 1a6f418412cfd87905381421c5954ca808c307ae..28d44f160f6d130c67f0529325eb8ada116e8ac9 100644 (file)
@@ -19,6 +19,8 @@
  *
  * Bacula(R) is a registered trademark of Kern Sibbald.
  */
+
+Prado::using('Application.API.Class.ConsoleOutputPage');
  
 /**
  * BVFS list directories.
  * @category API
  * @package Baculum API
  */
-class BVFSLsDirs extends BaculumAPIServer {
-
-       private $jobids;
-       private $path;
+class BVFSLsDirs extends ConsoleOutputPage {
 
        public function get() {
                $misc = $this->getModule('misc');
@@ -38,13 +37,7 @@ class BVFSLsDirs extends BaculumAPIServer {
                $offset = $this->Request->contains('offset') ? intval($this->Request['offset']) : 0;
                $jobids = $this->Request->contains('jobids') && $misc->isValidIdsList($this->Request['jobids']) ? $this->Request['jobids'] : null;
                $path = $this->Request->contains('path') && $misc->isValidPath($this->Request['path']) ? $this->Request['path'] : null;
-               if (is_null($jobids) && !is_null($this->jobids)) {
-                       $jobids = $this->jobids;
-               }
-
-               if (is_null($path) && !is_null($this->path)) {
-                       $path = $this->path;
-               }
+               $out_format = $this->Request->contains('output') && $this->isOutputFormatValid($this->Request['output']) ? $this->Request['output'] : parent::OUTPUT_FORMAT_RAW;
 
                if (is_null($jobids)) {
                        $this->output = BVFSError::MSG_ERROR_INVALID_JOBID_LIST;
@@ -58,17 +51,60 @@ class BVFSLsDirs extends BaculumAPIServer {
                        return;
                }
 
-               $cmd = array('.bvfs_lsdirs', 'jobid="' . $jobids . '"', 'path="' . $path . '"');
+               $params = [
+                       'jobids' => $jobids,
+                       'path' => $path,
+                       'offset' => $offset,
+                       'limit' => $limit
+               ];
+               $out = (object)['output' => [], 'exitcode' => 0];
+               if ($out_format === parent::OUTPUT_FORMAT_RAW) {
+                       $out = $this->getRawOutput($params);
+               } elseif($out_format === parent::OUTPUT_FORMAT_JSON) {
+                       $out = $this->getJSONOutput($params);
+               }
+
+               $this->output = $out->output;
+               $this->error = $out->exitcode;
+       }
+
+       /**
+        * Get BVFS list directories output from console in raw format.
+        *
+        * @param array $params command  parameters
+        * @return StdClass object with output and exitcode
+        */
+       protected function getRawOutput($params = []) {
+               $cmd = [
+                       '.bvfs_lsdirs',
+                       'jobid="' . $params['jobids'] . '"',
+                       'path="' . $params['path'] . '"'
+               ];
 
-               if ($offset > 0) {
-                       array_push($cmd, 'offset="' .  $offset . '"');
+               if ($params['offset'] > 0) {
+                       array_push($cmd, 'offset="' .  $params['offset'] . '"');
                }
-               if ($limit > 0) {
-                       array_push($cmd, 'limit="' .  $limit . '"');
+               if ($params['limit'] > 0) {
+                       array_push($cmd, 'limit="' .  $params['limit'] . '"');
+               }
+               return $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd);
+       }
+
+       /**
+        * Get BVFS list directories output in JSON format.
+        *
+        * @param array $params command  parameters
+        * @return StdClass object with output and exitcode
+        */
+       protected function getJSONOutput($params = []) {
+               $result = (object)['output' => [], 'exitcode' => 0];
+               $raw = $this->getRawOutput($params);
+               if ($raw->exitcode === 0) {
+                       $result->output = $this->getModule('bvfs')->parseFileDirList($raw->output);
+               } else {
+                       $result = $raw;
                }
-               $result = $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd);
-               $this->output = $result->output;
-               $this->error = $result->exitcode;
+               return $result;
        }
 }
 ?>
index a226f400deb438ea2a9e8e219c9028365c3c9975..9f67c6d968744d45f527767cc5a31a4778703e4d 100644 (file)
@@ -20,6 +20,8 @@
  * Bacula(R) is a registered trademark of Kern Sibbald.
  */
  
+Prado::using('Application.API.Class.ConsoleOutputPage');
+
 /**
  * BVFS list files.
  *
@@ -27,7 +29,7 @@
  * @category API
  * @package Baculum API
  */
-class BVFSLsFiles extends BaculumAPIServer {
+class BVFSLsFiles extends ConsoleOutputPage {
 
        private $jobids;
        private $path;
@@ -38,13 +40,7 @@ class BVFSLsFiles extends BaculumAPIServer {
                $offset = $this->Request->contains('offset') ? intval($this->Request['offset']) : 0;
                $jobids = $this->Request->contains('jobids') && $misc->isValidIdsList($this->Request['jobids']) ? $this->Request['jobids'] : null;
                $path = $this->Request->contains('path') && $misc->isValidPath($this->Request['path']) ? $this->Request['path'] : null;
-               if (is_null($jobids) && !is_null($this->jobids)) {
-                       $jobids = $this->jobids;
-               }
-
-               if (is_null($path) && !is_null($this->path)) {
-                       $path = $this->path;
-               }
+               $out_format = $this->Request->contains('output') && $this->isOutputFormatValid($this->Request['output']) ? $this->Request['output'] : parent::OUTPUT_FORMAT_RAW;
 
                if (is_null($jobids)) {
                        $this->output = BVFSError::MSG_ERROR_INVALID_JOBID_LIST;
@@ -58,17 +54,60 @@ class BVFSLsFiles extends BaculumAPIServer {
                        return;
                }
 
-               $cmd = array('.bvfs_lsfiles', 'jobid="' . $jobids . '"', 'path="' . $path . '"');
+               $params = [
+                       'jobids' => $jobids,
+                       'path' => $path,
+                       'offset' => $offset,
+                       'limit' => $limit
+               ];
+               $out = (object)['output' => [], 'exitcode' => 0];
+               if ($out_format === parent::OUTPUT_FORMAT_RAW) {
+                       $out = $this->getRawOutput($params);
+               } elseif($out_format === parent::OUTPUT_FORMAT_JSON) {
+                       $out = $this->getJSONOutput($params);
+               }
 
-               if ($offset > 0) {
-                       array_push($cmd, 'offset="' .  $offset . '"');
+               $this->output = $out->output;
+               $this->error = $out->exitcode;
+       }
+
+       /**
+        * Get BVFS list files output from console in raw format.
+        *
+        * @param array $params command  parameters
+        * @return StdClass object with output and exitcode
+        */
+       protected function getRawOutput($params = []) {
+               $cmd = [
+                       '.bvfs_lsfiles',
+                       'jobid="' . $params['jobids'] . '"',
+                       'path="' . $params['path'] . '"'
+               ];
+
+               if ($params['offset'] > 0) {
+                       array_push($cmd, 'offset="' .  $params['offset'] . '"');
+               }
+               if ($params['limit'] > 0) {
+                       array_push($cmd, 'limit="' .  $params['limit'] . '"');
                }
-               if ($limit > 0) {
-                       array_push($cmd, 'limit="' .  $limit . '"');
+               return $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd);
+       }
+
+       /**
+        * Get BVFS list files output in JSON format.
+        *
+        * @param array $params command  parameters
+        * @return StdClass object with output and exitcode
+        */
+       protected function getJSONOutput($params = []) {
+               $result = (object)['output' => [], 'exitcode' => 0];
+               $raw = $this->getRawOutput($params);
+               if ($raw->exitcode === 0) {
+                       $result->output = $this->getModule('bvfs')->parseFileDirList($raw->output);
+               } else {
+                       $result = $raw;
                }
-               $result = $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd);
-               $this->output = $result->output;
-               $this->error = $result->exitcode;
+               return $result;
        }
 }
 ?>
index 626909cc26c0faacd635a233c5c1d03e6befc272..c513fe54d1d8d105028aca20d4f686b851030feb 100644 (file)
@@ -20,6 +20,8 @@
  * Bacula(R) is a registered trademark of Kern Sibbald.
  */
  
+Prado::using('Application.API.Class.ConsoleOutputPage');
+
 /**
  * BVFS versions.
  *
  * @category API
  * @package Baculum API
  */
-class BVFSVersions extends BaculumAPIServer {
+class BVFSVersions extends ConsoleOutputPage {
 
        public function get() {
                $jobid = $this->Request->contains('jobid') ? intval($this->Request['jobid']) : 0;
                $pathid = $this->Request->contains('pathid') ? intval($this->Request['pathid']) : 0;
                $filenameid = $this->Request->contains('filenameid') ? intval($this->Request['filenameid']) : 0;
                $copies = $this->Request->contains('copies') ? intval($this->Request['copies']) : 0;
+               $out_format = $this->Request->contains('output') && $this->isOutputFormatValid($this->Request['output']) ? $this->Request['output'] : parent::OUTPUT_FORMAT_RAW;
                $client = null;
                if ($this->Request->contains('client') && $this->getModule('misc')->isValidName($this->Request['client'])) {
                        $client = $this->Request['client'];
@@ -44,20 +47,59 @@ class BVFSVersions extends BaculumAPIServer {
                        $this->error = BVFSError::ERROR_INVALID_CLIENT;
                        return;
                }
+               $params = [
+                       'client' => $client,
+                       'jobid' => $jobid,
+                       'pathid' => $pathid,
+                       'filenameid' => $filenameid,
+                       'copies' => $copies
+               ];
+               $out = (object)['output' => [], 'exitcode' => 0];
+               if ($out_format === parent::OUTPUT_FORMAT_RAW) {
+                       $out = $this->getRawOutput($params);
+               } elseif($out_format === parent::OUTPUT_FORMAT_JSON) {
+                       $out = $this->getJSONOutput($params);
+               }
+
+               $this->output = $out->output;
+               $this->error = $out->exitcode;
+       }
 
+       /**
+        * Get BVFS versions output from console in raw format.
+        *
+        * @param array $params command  parameters
+        * @return StdClass object with output and exitcode
+        */
+       protected function getRawOutput($params = []) {
                $cmd = array(
                        '.bvfs_versions',
-                       'client="' . $client . '"',
-                       'jobid="' . $jobid . '"',
-                       'pathid="' . $pathid . '"',
-                       'fnid="' . $filenameid . '"'
+                       'client="' . $params['client'] . '"',
+                       'jobid="' . $params['jobid'] . '"',
+                       'pathid="' . $params['pathid'] . '"',
+                       'fnid="' . $params['filenameid'] . '"'
                );
-               if ($copies == 1) {
+               if ($params['copies'] == 1) {
                        $cmd[] = 'copies';
                }
-               $result = $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd);
-               $this->output = $result->output;
-               $this->error = $result->exitcode;
+               return $this->getModule('bconsole')->bconsoleCommand($this->director, $cmd);
+       }
+
+       /**
+        * Get BVFS versions output in JSON format.
+        *
+        * @param array $params command  parameters
+        * @return StdClass object with output and exitcode
+        */
+       protected function getJSONOutput($params = []) {
+               $result = (object)['output' => [], 'exitcode' => 0];
+               $raw = $this->getRawOutput($params);
+               if ($raw->exitcode === 0) {
+                       $result->output = $this->getModule('bvfs')->parseFileVersions($raw->output);
+               } else {
+                       $result = $raw;
+               }
+               return $result;
        }
 }
 ?>
index c55fac6d4aeba7c2cdfc61400d4e6137132d3c6f..99f463dfc6cbeeef5317d7b0ab5571756ae8093f 100644 (file)
@@ -60,7 +60,13 @@ class ClientShow extends ConsoleOutputPage {
                }
        }
 
-       protected function getRawOutput($params = array()) {
+       /**
+        * Get show client output from console in raw format.
+        *
+        * @param array $params command  parameters
+        * @return StdClass object with output and exitcode
+        */
+       protected function getRawOutput($params = []) {
                $result = $this->getModule('bconsole')->bconsoleCommand(
                        $this->director,
                        array('show', 'client="' . $params['client'] . '"')
@@ -68,7 +74,13 @@ class ClientShow extends ConsoleOutputPage {
                return $result;
        }
 
-       protected function getJSONOutput($params = array()) {
+       /**
+        * Get show client output in JSON format.
+        *
+        * @param array $params command  parameters
+        * @return StdClass object with output and exitcode
+        */
+       protected function getJSONOutput($params = []) {
                $result = (object)array('output' => array(), 'exitcode' => 0);
                $output = $this->getRawOutput($params);
                if ($output->exitcode === 0) {
index 687a19d7de486b520b54045c079fd93594cb2c93..766f2af5ae7c5d1a7a6b808fe06c57cb40c0d520 100644 (file)
@@ -23,6 +23,8 @@
                <!-- tools modules -->
                <module id="bconsole" class="Application.API.Class.Bconsole" />
                <module id="json_tools" class="Application.API.Class.JSONTools" />
+               <module id="bvfs" class="Application.API.Class.BVFS" />
+               <module id="blstat" class="Application.API.Class.BLStat" />
                <!-- config modules -->
                <module id="api_config" class="Application.API.Class.APIConfig" />
                <module id="bacula_config" class="Application.API.Class.BaculaConfig" />
index 4fcbbcfd5829d8bfa1d980568ab5807948d9f78e..242eabfeaaaa1c94c9b69e51c48fcfab8ae63ddb 100644 (file)
                                                "schema": {
                                                        "type": "string"
                                                }
+                                       },
+                                       {
+                                               "$ref": "#/components/parameters/Output"
                                        }
                                ]
                        }
                                                "schema": {
                                                        "type": "string"
                                                }
+                                       },
+                                       {
+                                               "$ref": "#/components/parameters/Output"
                                        }
                                ]
                        }
                                                        "type": "integer",
                                                        "default": 0
                                                }
+                                       },
+                                       {
+                                               "$ref": "#/components/parameters/Output"
                                        }
                                ]
                        }
index b9b09489c9bce386564bb3e7ed0586f2b489affe..530edcc637c23d6283b7a0c813c716ef1e686c0f 100644 (file)
@@ -266,6 +266,10 @@ class Miscellaneous extends TModule {
                return (preg_match('/^(all|deleted)$/', $type) === 1);
        }
 
+       public function isValidOutput($type) {
+               return (preg_match('/^(raw|json)$/', $type) === 1);
+       }
+
        public function escapeCharsToConsole($path) {
                return preg_replace('/([$])/', '\\\${1}', $path);
        }
@@ -274,134 +278,6 @@ class Miscellaneous extends TModule {
                return json_decode(json_encode($data), true);
        }
 
-       public function decodeBaculaLStat($lstat) {
-               $base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
-               $lstat = trim($lstat);
-               $lstat_fields = explode(' ', $lstat);
-               $lstat_len = count($lstat_fields);
-               if ($lstat_len < 16) {
-                       // not known or empty lstat value
-                       return;
-               } elseif ($lstat_len > 16) {
-                       // cut off unknown fields
-                       array_splice($lstat_fields, 16);
-               }
-
-               list(
-                       $dev,
-                       $inode,
-                       $mode,
-                       $nlink,
-                       $uid,
-                       $gid,
-                       $rdev,
-                       $size,
-                       $blocksize,
-                       $blocks,
-                       $atime,
-                       $mtime,
-                       $ctime,
-                       $linkfi,
-                       $flags,
-                       $data
-               ) = $lstat_fields;
-               $encoded_values = array(
-                       'dev' => $dev,
-                       'inode' => $inode,
-                       'mode' => $mode,
-                       'nlink' => $nlink,
-                       'uid' => $uid,
-                       'gid' => $gid,
-                       'rdev' => $rdev,
-                       'size' => $size,
-                       'blocksize' => $blocksize,
-                       'blocks' => $blocks,
-                       'atime' => $atime,
-                       'mtime' => $mtime,
-                       'ctime' => $ctime,
-                       'linkfi' => $linkfi,
-                       'flags' => $flags,
-                       'data' => $data
-               );
-
-               $ret = array();
-               foreach($encoded_values as $key => $val) {
-                       $result = 0;
-                       $is_minus = false;
-                       $start = 0;
-
-                       if(substr($val, 0, 1) === '-') {
-                               $is_minus = true;
-                               $start++;
-                       }
-
-                       for($i = $start; $i < strlen($val); $i++) {
-                               $result = bcmul($result, bcpow(2,6));
-                               $result +=  strpos($base64, substr($val, $i , 1));
-                       }
-                       $ret[$key] = ($is_minus === true) ? -$result : $result;
-               }
-               return $ret;
-       }
-
-       public function parseBvfsList($list) {
-               $elements = array();
-               for($i = 0; $i < count($list); $i++) {
-                       if(preg_match('/^(?P<pathid>\d+)\t(?P<filenameid>\d+)\t(?P<fileid>\d+)\t(?P<jobid>\d+)\t(?P<lstat>[a-zA-z0-9\+\/\ ]+)\t(?P<name>.*)\/$/', $list[$i], $match) == 1 || preg_match('/^(?P<pathid>\d+)\t(?P<filenameid>\d+)\t(?P<fileid>\d+)\t(?P<jobid>\d+)\t(?P<lstat>[a-zA-z0-9\+\/\ ]+)\t(?P<name>\.{2})$/', $list[$i], $match) == 1) {
-                               if($match['name'] == '.') {
-                                       continue;
-                               } elseif($match['name'] != '..') {
-                                       $match['name'] .= '/';
-                               }
-                               $elements[] = array(
-                                       'pathid' => $match['pathid'],
-                                       'filenameid' => $match['filenameid'],
-                                       'fileid' => $match['fileid'],
-                                       'jobid' => $match['jobid'],
-                                       'lstat' => $this->decodeBaculaLStat($match['lstat']),
-                                       'name' => $match['name'],
-                                       'type' => 'dir'
-                               );
-                       } elseif(preg_match('/^(?P<pathid>\d+)\t(?P<filenameid>\d+)\t(?P<fileid>\d+)\t(?P<jobid>\d+)\t(?P<lstat>[a-zA-z0-9\+\-\/\ ]+)\t(?P<name>[^\/]+)$/', $list[$i], $match) == 1) {
-                               if($match['name'] == '.') {
-                                       continue;
-                               }
-                               $elements[] = array(
-                                       'pathid' => $match['pathid'],
-                                       'filenameid' => $match['filenameid'],
-                                       'fileid' => $match['fileid'],
-                                       'jobid' => $match['jobid'],
-                                       'lstat' => $this->decodeBaculaLStat($match['lstat']),
-                                       'name' => $match['name'],
-                                       'type' => 'file'
-                               );
-                       }
-               }
-               usort($elements, 'sortFilesListByName');
-               return $elements;
-       }
-
-       public function parseFileVersions($filename, $list) {
-               $elements = array();
-               for($i = 0; $i < count($list); $i++) {
-                       if(preg_match('/^(?P<pathid>\d+)\t(?P<filenameid>\d+)\t(?P<fileid>\d+)\t(?P<jobid>\d+)\t(?P<lstat>[a-zA-Z0-9\+\/\ ]+)\t(?P<md5>.+)\t(?P<volname>.+)\t(?P<inchanger>\d+)$/', $list[$i], $match) == 1) {
-                               $elements[$match['fileid']] = array(
-                                       'name' => $filename,
-                                       'pathid' => $match['pathid'],
-                                       'filenameid' => $match['filenameid'],
-                                       'fileid' => $match['fileid'],
-                                       'jobid' => $match['jobid'],
-                                       'lstat' => $this->decodeBaculaLStat($match['lstat']),
-                                       'md5' => $match['md5'],
-                                       'volname' => $match['volname'],
-                                       'inchanger' => $match['inchanger'],
-                                       'type' => 'file'
-                               );
-                       }
-               }
-               return $elements;
-       }
-
        public function findJobIdStartedJob($output) {
                $jobid = null;
                $output = array_reverse($output); // jobid is ussually at the end of output
@@ -484,20 +360,4 @@ class Miscellaneous extends TModule {
                return sprintf('$apr1$%s$%s', $salt, $tmp);
        }
 }
-
-/*
- * Small sorting callback function to sort files and directories by name.
- * Function keeps '.' and '..' names always in the beginning of array.
- * Used to sort files and directories from Bvfs.
- */
-function sortFilesListByName($a, $b) {
-       $firstLeft = substr($a['name'], 0, 1);
-       $firstRight = substr($b['name'], 0, 1);
-       if ($firstLeft == '.' && $firstRight != '.') {
-               return -1;
-       } else if ($firstRight == '.' && $firstLeft != '.') {
-               return 1;
-       }
-       return strcasecmp($a['name'], $b['name']);
-}
 ?>
index 63b8d5c43c8ab54b3312ffac8f4a0b6fdda4df68..1da3eba8f26a0f6265ffec80adc566b2caca512a 100644 (file)
@@ -395,18 +395,18 @@ class RestoreWizard extends BaculumWebPage
                        // generating Bvfs may take a moment
                        $this->generateBvfsCache($jobids);
 
-                       // get directories list
-                       $query = sprintf(
-                               '?jobids=%s&path=%s',
-                               rawurlencode($jobids),
-                               rawurlencode(implode($_SESSION['restore_path']))
-                       );
+                       // get directory and file list
+                       $query = '?' . http_build_query(array(
+                               'jobids' => $jobids,
+                               'path' => implode($_SESSION['restore_path']),
+                               'output' => 'json'
+                       ));
                        $bvfs_dirs = $this->getModule('api')->get(
                                array('bvfs', 'lsdirs', $query)
                        );
                        $dirs = array();
                        if ($bvfs_dirs->error === 0) {
-                               $dirs = $this->getModule('misc')->parseBvfsList($bvfs_dirs->output);
+                               $dirs = json_decode(json_encode($bvfs_dirs->output), true);
                        }
 
                        // get files list
@@ -415,7 +415,7 @@ class RestoreWizard extends BaculumWebPage
                        );
                        $files = array();
                        if ($bvfs_files->error === 0) {
-                               $files = $this->getModule('misc')->parseBvfsList($bvfs_files->output);
+                               $files = json_decode(json_encode($bvfs_files->output), true);
                        }
 
                        $elements = array_merge($dirs, $files);
@@ -615,14 +615,28 @@ class RestoreWizard extends BaculumWebPage
                        'client' => $clientname,
                        'jobid' => $jobid,
                        'pathid' => $pathid,
-                       'filenameid' => $filenameid
+                       'filenameid' => $filenameid,
+                       'output' => 'json'
                ];
                if ($this->EnableCopyJobRestore->Checked) {
                        $params['copies'] = 1;
                }
+
+               /**
+                * Helper for adding filename to versions list.
+                *
+                * @param array $el version list element
+                * @return return version list element
+                */
+               $add_version_filename_func = function ($el) use ($filename) {
+                       $el['name'] = $filename;
+                       return $el;
+               };
+
                $query = '?' . http_build_query($params);
                $versions = $this->getModule('api')->get(array('bvfs', 'versions', $query))->output;
-               $file_versions = $this->getModule('misc')->parseFileVersions($filename, $versions);
+               $versions = json_decode(json_encode($versions), true);
+               $file_versions = array_map($add_version_filename_func, $versions);
                $file_versions = array_map(array('RestoreWizard', 'addUniqid'), $file_versions);
                $this->setFileVersions($file_versions);
                $this->VersionsDataGrid->dataSource = $file_versions;