0011996: add fallback app icon
[tine20] / tine20 / Tinebase / FileSystem / StreamWrapper.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Tinebase
6  * @subpackage  Filesystem
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @author      Lars Kneschke <l.kneschke@metaways.de>
9  * @copyright   Copyright (c) 2010-2011 Metaways Infosystems GmbH (http://www.metaways.de)
10  * 
11  */
12
13 /**
14  * filesystem streamwrapper for tine20://
15  *
16  * @package     Tinebase
17  * @subpackage  Filesystem
18  */
19 class Tinebase_FileSystem_StreamWrapper
20 {
21     /**
22      * the context
23      * 
24      * @var resource
25      */
26     public $context;
27     
28     /**
29      * stores the current treenode
30      * 
31      * @var Tinebase_Model_Tree_FileObject
32      */
33     protected $_currentNode;
34     
35     /**
36      * stores the list of directory children for readdir
37      * 
38      * @var Tinebase_Record_RecordTest
39      */
40     protected $_readDirRecordSet;
41     
42     /**
43      * @var resource
44      */
45     protected $_stream;
46     
47     /**
48      * dir_closedir
49      */
50     public function dir_closedir() 
51     {
52         $this->_readDirRecordSet = null;
53         $this->_readDirIterator  = null;
54         
55         return true;
56     }
57     
58     /**
59      * dir_opendir
60      * 
61      * @param string $_path
62      * @param array $_options [unused]
63      */
64     public function dir_opendir($_path, $_options) 
65     {
66         try {
67             $node = Tinebase_FileSystem::getInstance()->stat(substr($_path, 9));
68         } catch (Tinebase_Exception_NotFound $teia) {
69             if (!$quiet) {
70                 trigger_error($teia->getMessage(), E_USER_WARNING);
71             }
72             return false;
73         }
74         
75         if ($node->type != Tinebase_Model_Tree_FileObject::TYPE_FOLDER) {
76             trigger_error("$_path isn't a directory", E_USER_WARNING);
77             return false;
78         }
79         
80         $this->_readDirRecordSet = Tinebase_FileSystem::getInstance()->scanDir(substr($_path, 9));
81         $this->_readDirIterator  = $this->_readDirRecordSet->getIterator();
82         reset($this->_readDirIterator);
83         
84         return true;
85     }
86     
87     /**
88      * dir_readdir
89      */
90     public function dir_readdir() 
91     {
92         if (($node = current($this->_readDirIterator)) === false) {
93             return false;
94         }
95         next($this->_readDirIterator);
96         
97         return $node->name;
98     }
99     
100     /**
101      * dir_rewinddir
102      */
103     public function dir_rewinddir()
104     {
105         reset($this->_readDirIterator);
106     }
107     
108     /**
109      * create directory
110      * 
111      * @param  string  $_path     path to create
112      * @param  int     $_mode     directory mode (for example 0777)
113      * @param  int     $_options  bitmask of options
114      */
115     public function mkdir($_path, $_mode, $_options)
116     {
117         Tinebase_FileSystem::getInstance()->mkdir(substr($_path, 9));
118         
119         return true;
120     }
121     
122     /**
123      * rename file/directory
124      * 
125      * @param  string  $_oldPath
126      * @param  string  $_newPath
127      * @return boolean
128      */
129     public function rename($_oldPath, $_newPath)
130     {
131         return Tinebase_FileSystem::getInstance()->rename(substr($_oldPath, 9), substr($_newPath, 9));
132     }
133     
134     /**
135      * remove dir
136      * 
137      * @param string $_path
138      * @param resource $_context [unused]
139      * @return boolean
140      */
141     public function rmdir($_path, $_context = NULL)
142     {
143         return Tinebase_FileSystem::getInstance()->rmdir(substr($_path, 9), true);
144     }
145     
146     /**
147      * stream_close
148      * 
149      * @return boolean
150      */
151     public function stream_close()
152     {
153         if (!is_resource($this->_stream)) {
154             return false;
155         }
156          
157         Tinebase_FileSystem::getInstance()->fclose($this->_stream);
158         
159         return true;
160     }
161     
162     /**
163      * stream_eof
164      * 
165      * @return boolean
166      */
167     public function stream_eof()
168     {
169         if (!is_resource($this->_stream)) {
170             return true; // yes, true
171         }
172         
173         return feof($this->_stream);
174     }
175     
176     /**
177      * open stream
178      * 
179      * @param string $_path
180      * @param string $_mode
181      * @param array $_options
182      * @param string $_opened_path
183      * @return boolean
184      */
185     public function stream_open($_path, $_mode, $_options, &$_opened_path)
186     {
187         $quiet    = !(bool)($_options & STREAM_REPORT_ERRORS);
188         
189         $stream = Tinebase_FileSystem::getInstance()->fopen(substr($_path, 9), $_mode);
190         
191         if (!is_resource($stream)) {
192             if (!$quiet) {
193                 trigger_error('falied to open stream', E_USER_WARNING);
194             }
195             return false;
196         }
197         
198         $this->_stream = $stream;
199         $_opened_path = $_path;
200         
201         return true;
202     }
203     
204     /**
205      * read stream
206      * 
207      * @param integer $_length
208      * @return boolean|string
209      */
210     public function stream_read($_length)
211     {
212         if (!is_resource($this->_stream)) {
213             return false;
214         }
215         
216         return fread($this->_stream, $_length);
217     }
218     
219     /**
220      * stream_seek
221      * 
222      * @param integer $_offset
223      * @param integer $_whence
224      * @return boolean|integer
225      */
226     public function stream_seek($_offset, $_whence = SEEK_SET)
227     {
228         if (!is_resource($this->_stream)) {
229             return false;
230         }
231         
232         return fseek($this->_stream, $_offset, $_whence);
233     }
234     
235     /**
236      * stream_stat
237      * 
238      * @return boolean|array
239      */
240     public function stream_stat()
241     {
242         if (!is_resource($this->_stream)) {
243             return false;
244         }
245         
246         $streamStat = fstat($this->_stream);
247          
248         $timestamp = Tinebase_DateTime::now()->getTimestamp();
249         
250         // set node type (file)
251         $mode      = 0100000;
252         
253         $stat =  array(
254             0  => 0,
255             1  => 1, // inode
256             2  => $mode,
257             3  => 0,
258             4  => 0,
259             5  => 0,
260             6  => 0,
261             7  => $streamStat['size'],
262             8  => $timestamp,
263             9  => $timestamp,
264             10 => $timestamp,
265             11 => -1,
266             12 => -1,
267             'dev'     => 0,
268             'ino'     => 1,
269             'mode'    => $mode,
270             'nlink'   => 0,
271             'uid'     => 0,
272             'gid'     => 0,
273             'rdev'    => 0,
274             'size'    => $streamStat['size'],
275             'atime'   => $timestamp,
276             'mtime'   => $timestamp, 
277             'ctime'   => $timestamp,
278             'blksize' => -1,
279             'blocks'  => -1
280         );
281         
282         return $stat;
283     }
284     
285     /**
286      * stream_write
287      * 
288      * @param string $_data
289      * @return boolean|integer
290      */
291     public function stream_write($_data)
292     {
293         if (!is_resource($this->_stream)) {
294             return false;
295         }
296         
297         $options = stream_context_get_options($this->_stream);
298         
299         if (!in_array($options['tine20']['mode'], array('w', 'wb', 'x', 'xb'))) {
300             // readonly
301             return false;
302         }
303         
304         return fwrite($this->_stream, $_data);
305     }
306     
307     /**
308      * stream_tell
309      * 
310      * @return boolean|integer
311      */
312     public function stream_tell()
313     {
314         if (!is_resource($this->_stream)) {
315             return false;
316         }
317         
318         return ftell($this->_stream);
319     }
320     
321     /**
322      * unlink
323      * 
324      * @param string $_path
325      * @return boolean
326      */
327     public function unlink($_path)
328     {
329         try {
330             $result = Tinebase_FileSystem::getInstance()->unlink(substr($_path, 9));
331         } catch (Tinebase_Exception_InvalidArgument $teia) {
332             trigger_error($teia->getMessage(), E_USER_WARNING);
333             return false;
334         } catch (Tinebase_Exception_NotFound $tenf) {
335             trigger_error($tenf->getMessage(), E_USER_WARNING);
336             return false;
337         }
338         
339         return $result;
340     }
341     
342     /**
343      * url_stat
344      * 
345      * @param string $_path
346      * @param array $_flags
347      * @return boolean|array
348      */
349     public function url_stat($_path, $_flags)
350     {
351         $statLink = (bool)($_flags & STREAM_URL_STAT_LINK);
352         $quiet    = (bool)($_flags & STREAM_URL_STAT_QUIET);
353         
354         try {
355             $node = Tinebase_FileSystem::getInstance()->stat(substr($_path, 9));
356         } catch (Tinebase_Exception_InvalidArgument $teia) {
357             if (!$quiet) {
358                 trigger_error($teia->getMessage(), E_USER_WARNING);
359             }
360             return false;
361         } catch (Tinebase_Exception_NotFound $tenf) {
362             if (!$quiet) {
363                 trigger_error($tenf->getMessage(), E_USER_WARNING);
364             }
365             return false;
366         }
367         
368         $timestamp = $node->last_modified_time instanceof Tinebase_DateTime ? $node->last_modified_time->getTimestamp() : $node->creation_time->getTimestamp();
369         
370         $mode      = 0;
371         // set node type (directory, file, link)
372         $mode      = $node->type == Tinebase_Model_Tree_FileObject::TYPE_FOLDER ? $mode | 0040000 : $mode | 0100000;
373         
374         $stat =  array(
375             0  => 0,
376             1  => crc32($node->object_id),
377             2  => $mode,
378             3  => 0,
379             4  => 0,
380             5  => 0,
381             6  => 0,
382             7  => $node->size,
383             8  => $timestamp,
384             9  => $timestamp,
385             10 => $node->creation_time->getTimestamp(),
386             11 => -1,
387             12 => -1,
388             'dev'     => 0,
389             'ino'     => crc32($node->object_id),
390             'mode'    => $mode,
391             'nlink'   => 0,
392             'uid'     => 0,
393             'gid'     => 0,
394             'rdev'    => 0,
395             'size'    => $node->size,
396             'atime'   => $timestamp,
397             'mtime'   => $timestamp, 
398             'ctime'   => $node->creation_time->getTimestamp(),
399             'blksize' => -1,
400             'blocks'  => -1
401         );
402         
403         return $stat;
404     }
405 }