source: trunk/phpgwapi/inc/class.vfs_sql.inc.php @ 1750

Revision 1750, 69.5 KB checked in by amuller, 14 years ago (diff)

Ticket #597 - melhoria no módulos gerenciador de arquivos do expresso livre

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1<?php
2  /**************************************************************************\
3  * eGroupWare API - VFS                                                     *
4  * This file written by Jason Wies (Zone) <zone@phpgroupware.org>           *
5  * This class handles file/dir access for eGroupWare                        *
6  * Copyright (C) 2001 Jason Wies                                            *
7  * -------------------------------------------------------------------------*
8  * This library is part of the eGroupWare API                               *
9  * http://www.egroupware.org/api                                            *
10  * ------------------------------------------------------------------------ *
11  * This library is free software; you can redistribute it and/or modify it  *
12  * under the terms of the GNU Lesser General Public License as published by *
13  * the Free Software Foundation; either version 2.1 of the License,         *
14  * or any later version.                                                    *
15  * This library is distributed in the hope that it will be useful, but      *
16  * WITHOUT ANY WARRANTY; without even the implied warranty of               *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                     *
18  * See the GNU Lesser General Public License for more details.              *
19  * You should have received a copy of the GNU Lesser General Public License *
20  * along with this library; if not, write to the Free Software Foundation,  *
21  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA            *
22  \**************************************************************************/
23
24
25        /*!
26        @class vfs
27        @abstract Virtual File System with SQL backend
28        @description Authors: Zone
29        */
30
31        /* These are used in calls to extra_sql () */
32        define ('VFS_SQL_SELECT', 1);
33        define ('VFS_SQL_DELETE', 2);
34        define ('VFS_SQL_UPDATE', 4);
35
36        class vfs extends vfs_shared
37        {
38                var $working_id;
39                var $working_lid;
40                var $my_home;
41                var $meta_types;
42                var $now;
43                var $file_actions;
44
45                /*!
46                @function vfs
47                @abstract constructor, sets up variables
48                */
49                function vfs ()
50                {
51                        $this->vfs_shared ();
52                        $this->basedir = $GLOBALS['phpgw_info']['server']['files_dir'];
53                        $this->working_id = $GLOBALS['phpgw_info']['user']['account_id'];
54                        $this->working_lid = $GLOBALS['phpgw']->accounts->id2name($this->working_id);
55                        $this->my_home = $this->fakebase.'/'.$this->working_lid;
56                        $this->now = date ('Y-m-d H:i:s');
57
58                        /*
59                           File/dir attributes, each corresponding to a database field.  Useful for use in loops
60                           If an attribute was added to the table, add it here and possibly add it to
61                           set_attributes ()
62
63                           set_attributes now uses this array().   07-Dec-01 skeeter
64                        */
65
66                        $this->attributes[] = 'deleteable';
67                        $this->attributes[] = 'content';
68                        $this->attributes[] = 'type';
69
70                        /*
71                           Decide whether to use any actual filesystem calls (fopen(), fread(),
72                           unlink(), rmdir(), touch(), etc.).  If not, then we're working completely
73                           in the database.
74                        */
75                        $this->file_actions = $GLOBALS['phpgw_info']['server']['file_store_contents'] == 'filesystem' ||
76                                !$GLOBALS['phpgw_info']['server']['file_store_contents'];
77
78                        // test if the files-dir is inside the document-root, and refuse working if so
79                        //
80                        if ($this->file_actions && $this->in_docroot($this->basedir))
81                        {
82                                $GLOBALS['phpgw']->common->phpgw_header();
83                                if ($GLOBALS['phpgw_info']['flags']['noheader'])
84                                {
85                                        echo parse_navbar();
86                                }
87                                echo '<p align="center"><font color="red"><b>'.lang('Path to user and group files HAS TO BE OUTSIDE of the webservers document-root!!!')."</b></font></p>\n";
88                                $GLOBALS['phpgw']->common->phpgw_exit();
89                        }
90                        /*
91                           These are stored in the MIME-type field and should normally be ignored.
92                           Adding a type here will ensure it is normally ignored, but you will have to
93                           explicitly add it to acl_check (), and to any other SELECT's in this file
94                        */
95
96                        $this->meta_types = array ('journal', 'journal-deleted');
97
98                        /* We store the linked directories in an array now, so we don't have to make the SQL call again */
99                        if ($GLOBALS['phpgw_info']['server']['db_type']=='mssql'
100                                || $GLOBALS['phpgw_info']['server']['db_type']=='sybase')
101                        {
102                                $query = $GLOBALS['phpgw']->db->query ("SELECT directory, name, link_directory, link_name FROM phpgw_vfs WHERE CONVERT(varchar,link_directory) != '' AND CONVERT(varchar,link_name) != ''" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__,__FILE__);
103                        }
104                        else
105                        {
106                                $query = $GLOBALS['phpgw']->db->query ("SELECT directory, name, link_directory, link_name FROM phpgw_vfs WHERE (link_directory IS NOT NULL or link_directory != '') AND (link_name IS NOT NULL or link_name != '')" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__,__FILE__);
107                        }
108
109                        $this->linked_dirs = array ();
110                        while ($GLOBALS['phpgw']->db->next_record ())
111                        {
112                                $this->linked_dirs[] = $GLOBALS['phpgw']->db->Record;
113                        }
114                }
115
116                /*!
117                @function in_docroot
118                @abstract test if $path lies within the webservers document-root
119                */
120                function in_docroot($path)
121                {
122                        $docroots = array(PHPGW_SERVER_ROOT,$_SERVER['DOCUMENT_ROOT']);
123
124                        foreach ($docroots as $docroot)
125                        {
126                                $len = strlen($docroot);
127
128                                if ($docroot == substr($path,0,$len))
129                                {
130                                        $rest = substr($path,$len);
131
132                                        if (!strlen($rest) || $rest[0] == DIRECTORY_SEPARATOR)
133                                        {
134                                                return True;
135                                        }
136                                }
137                        }
138                        return False;
139                }
140
141                /*!
142                @function extra_sql
143                @abstract Return extra SQL code that should be appended to certain queries
144                @param query_type The type of query to get extra SQL code for, in the form of a VFS_SQL define
145                @result Extra SQL code
146                */
147                function extra_sql ($data)
148                {
149                        if (!is_array ($data))
150                        {
151                                $data = array ('query_type' => VFS_SQL_SELECT);
152                        }
153
154                        if ($data['query_type'] == VFS_SQL_SELECT || $data['query_type'] == VFS_SQL_DELETE || $data['query_type'] = VFS_SQL_UPDATE)
155                        {
156                                $sql = ' AND ((';
157
158                                foreach ($this->meta_types as $num => $type)
159                                {
160                                        if ($num)
161                                                $sql .= ' AND ';
162
163                                        $sql .= "mime_type != '$type'";
164                                }
165
166                                $sql .= ') OR mime_type IS NULL)';
167                        }
168
169                        return ($sql);
170                }
171
172                /*!
173                @function add_journal
174                @abstract Add a journal entry after (or before) completing an operation,
175                          and increment the version number.  This function should be used internally only
176                @discussion Note that state_one and state_two are ignored for some VFS_OPERATION's, for others
177                            they are required.  They are ignored for any "custom" operation
178                            The two operations that require state_two:
179                            operation                   state_two
180                            VFS_OPERATION_COPIED        fake_full_path of copied to
181                            VFS_OPERATION_MOVED         fake_full_path of moved to
182
183                            If deleting, you must call add_journal () before you delete the entry from the database
184                @param string File or directory to add entry for
185                @param relatives Relativity array
186                @param operation The operation that was performed.  Either a VFS_OPERATION define or
187                                  a non-integer descriptive text string
188                @param state_one The first "state" of the file or directory.  Can be a file name, size,
189                                  location, whatever is appropriate for the specific operation
190                @param state_two The second "state" of the file or directory
191                @param incversion Boolean True/False.  Increment the version for the file?  Note that this is
192                                   handled automatically for the VFS_OPERATION defines.
193                                   i.e. VFS_OPERATION_EDITED would increment the version, VFS_OPERATION_COPIED
194                                   would not
195                @result Boolean True/False
196                */
197                function add_journal ($data)
198                {
199                        if (!is_array ($data))
200                        {
201                                $data = array ();
202                        }
203
204                        $default_values = array
205                                (
206                                        'relatives'     => array (RELATIVE_CURRENT),
207                                        'state_one'     => False,
208                                        'state_two'     => False,
209                                        'incversion'    => True
210                                );
211
212                        $data = array_merge ($this->default_values ($data, $default_values), $data);
213
214                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
215
216                        $p = $this->path_parts (array ('string' => $data['string'], 'relatives' => array ($data['relatives'][0])));
217
218                        /* We check that they have some sort of access to the file other than read */
219                        if (!$this->acl_check (array ('string' => $p->fake_full_path, 'relatives' => array ($p->mask), 'operation' => PHPGW_ACL_WRITE)) &&
220                                !$this->acl_check (array ('string' => $p->fake_full_path, 'relatives' => array ($p->mask), 'operation' => PHPGW_ACL_EDIT)) &&
221                                !$this->acl_check (array ('string' => $p->fake_full_path, 'relatives' => array ($p->mask), 'operation' => PHPGW_ACL_DELETE)))
222                        {
223                                return False;
224                        }
225
226                        if (!$this->file_exists (array ('string' => $p->fake_full_path, 'relatives' => array ($p->mask))))
227                        {
228                                return False;
229                        }
230
231                        $ls_array = $this->ls (array (
232                                        'string' => $p->fake_full_path,
233                                        'relatives' => array ($p->mask),
234                                        'checksubdirs' => False,
235                                        'mime_type'     => False,
236                                        'nofiles'       => True
237                                )
238                        );
239                        $file_array = $ls_array[0];
240
241                        $sql = 'INSERT INTO phpgw_vfs (';
242                        $sql2 .= ' VALUES (';
243
244                        for ($i = 0; list ($attribute, $value) = each ($file_array); $i++)
245                        {
246                                if ($attribute == 'file_id' || $attribute == 'content')
247                                {
248                                        continue;
249                                }
250
251                                if ($attribute == 'owner_id')
252                                {
253                                        $value = $account_id;
254                                }
255
256                                if ($attribute == 'created')
257                                {
258                                        $value = $this->now;
259                                }
260
261                                if ($attribute == 'modified' && !$modified)
262                                {
263                                        unset ($value);
264                                }
265
266                                if ($attribute == 'mime_type')
267                                {
268                                        $value = 'journal';
269                                }
270
271                                if ($attribute == 'comment')
272                                {
273                                        switch ($data['operation'])
274                                        {
275                                                case VFS_OPERATION_CREATED:
276                                                        $value = 'Created';
277                                                        $data['incversion'] = True;
278                                                        break;
279                                                case VFS_OPERATION_EDITED:
280                                                        $value = 'Edited';
281                                                        $data['incversion'] = True;
282                                                        break;
283                                                case VFS_OPERATION_EDITED_COMMENT:
284                                                        $value = 'Edited comment';
285                                                        $data['incversion'] = False;
286                                                        break;
287                                                case VFS_OPERATION_COPIED:
288                                                        if (!$data['state_one'])
289                                                        {
290                                                                $data['state_one'] = $p->fake_full_path;
291                                                        }
292                                                        if (!$data['state_two'])
293                                                        {
294                                                                return False;
295                                                        }
296                                                        $value = 'Copied '.$data['state_one'].' to '.$data['state_two'];
297                                                        $data['incversion'] = False;
298                                                        break;
299                                                case VFS_OPERATION_MOVED:
300                                                        if (!$data['state_one'])
301                                                        {
302                                                                $data['state_one'] = $p->fake_full_path;
303                                                        }
304                                                        if (!$data['state_two'])
305                                                        {
306                                                                return False;
307                                                        }
308                                                        $value = 'Moved '.$data['state_one'].' to '.$data['state_two'];
309                                                        $data['incversion'] = False;
310                                                        break;
311                                                case VFS_OPERATION_DELETED:
312                                                        $value = 'Deleted';
313                                                        $data['incversion'] = False;
314                                                        break;
315                                                default:
316                                                        $value = $data['operation'];
317                                                        break;
318                                        }
319                                }
320
321                                /*
322                                   Let's increment the version for the file itself.  We keep the current
323                                   version when making the journal entry, because that was the version that
324                                   was operated on.  The maximum numbers for each part in the version string:
325                                   none.99.9.9
326                                */
327                                if ($attribute == 'version' && $data['incversion'])
328                                {
329                                        $version_parts = split ("\.", $value);
330                                        $newnumofparts = $numofparts = count ($version_parts);
331
332                                        if ($version_parts[3] >= 9)
333                                        {
334                                                $version_parts[3] = 0;
335                                                $version_parts[2]++;
336                                                $version_parts_3_update = 1;
337                                        }
338                                        elseif (isset ($version_parts[3]))
339                                        {
340                                                $version_parts[3]++;
341                                        }
342
343                                        if ($version_parts[2] >= 9 && $version_parts[3] == 0 && $version_parts_3_update)
344                                        {
345                                                $version_parts[2] = 0;
346                                                $version_parts[1]++;
347                                        }
348
349                                        if ($version_parts[1] > 99)
350                                        {
351                                                $version_parts[1] = 0;
352                                                $version_parts[0]++;
353                                        }
354
355                                        for ($i = 0; $i < $newnumofparts; $i++)
356                                        {
357                                                if (!isset ($version_parts[$i]))
358                                                {
359                                                        break;
360                                                }
361
362                                                if ($i)
363                                                {
364                                                        $newversion .= '.';
365                                                }
366
367                                                $newversion .= $version_parts[$i];
368                                        }
369
370                                        $this->set_attributes (array(
371                                                        'string'        => $p->fake_full_path,
372                                                        'relatives'     => array ($p->mask),
373                                                        'attributes'    => array(
374                                                                                'version' => $newversion
375                                                                        )
376                                                )
377                                        );
378                                }
379
380                                if (isset ($value))
381                                {
382                                        if ($i > 1)
383                                        {
384                                                $sql .= ', ';
385                                                $sql2 .= ', ';
386                                        }
387
388                                        $sql .= "$attribute";
389                                        $sql2 .= "'" . $this->clean_string (array ('string' => $value)) . "'";
390                                }
391                        }
392
393                        $sql .= ')';
394                        $sql2 .= ')';
395
396                        $sql .= $sql2;
397
398                        /*
399                           These are some special situations where we need to flush the journal entries
400                           or move the 'journal' entries to 'journal-deleted'.  Kind of hackish, but they
401                           provide a consistent feel to the system
402                        */
403                        if ($data['operation'] == VFS_OPERATION_CREATED)
404                        {
405                                $flush_path = $p->fake_full_path;
406                                $deleteall = True;
407                        }
408
409                        if ($data['operation'] == VFS_OPERATION_COPIED || $data['operation'] == VFS_OPERATION_MOVED)
410                        {
411                                $flush_path = $data['state_two'];
412                                $deleteall = False;
413                        }
414
415                        if ($flush_path)
416                        {
417                                $flush_path_parts = $this->path_parts (array(
418                                                'string'        => $flush_path,
419                                                'relatives'     => array (RELATIVE_NONE)
420                                        )
421                                );
422
423                                $this->flush_journal (array(
424                                                'string'        => $flush_path_parts->fake_full_path,
425                                                'relatives'     => array ($flush_path_parts->mask),
426                                                'deleteall'     => $deleteall
427                                        )
428                                );
429                        }
430
431                        if ($data['operation'] == VFS_OPERATION_COPIED)
432                        {
433                                /*
434                                   We copy it going the other way as well, so both files show the operation.
435                                   The code is a bad hack to prevent recursion.  Ideally it would use VFS_OPERATION_COPIED
436                                */
437                                $this->add_journal (array(
438                                                'string'        => $data['state_two'],
439                                                'relatives'     => array (RELATIVE_NONE),
440                                                'operation'     => 'Copied '.$data['state_one'].' to '.$data['state_two'],
441                                                'state_one'     => NULL,
442                                                'state_two'     => NULL,
443                                                'incversion'    => False
444                                        )
445                                );
446                        }
447
448                        if ($data['operation'] == VFS_OPERATION_MOVED)
449                        {
450                                $state_one_path_parts = $this->path_parts (array(
451                                                'string'        => $data['state_one'],
452                                                'relatives'     => array (RELATIVE_NONE)
453                                        )
454                                );
455
456                                $query = $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET mime_type='journal-deleted' WHERE directory='".
457                                        $GLOBALS['phpgw']->db->db_addslashes($state_one_path_parts->fake_leading_dirs_clean)."' AND name='".
458                                        $GLOBALS['phpgw']->db->db_addslashes($state_one_path_parts->fake_name_clean)."' AND mime_type='journal'");
459
460                                /*
461                                   We create the file in addition to logging the MOVED operation.  This is an
462                                   advantage because we can now search for 'Create' to see when a file was created
463                                */
464                                $this->add_journal (array(
465                                                'string'        => $data['state_two'],
466                                                'relatives'     => array (RELATIVE_NONE),
467                                                'operation'     => VFS_OPERATION_CREATED
468                                        )
469                                );
470                        }
471
472                        /* This is the SQL query we made for THIS request, remember that one? */
473                        $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
474
475                        /*
476                           If we were to add an option of whether to keep journal entries for deleted files
477                           or not, it would go in the if here
478                        */
479                        if ($data['operation'] == VFS_OPERATION_DELETED)
480                        {
481                                $query = $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET mime_type='journal-deleted' WHERE directory='".
482                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
483                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."' AND mime_type='journal'");
484                        }
485
486                        return True;
487                }
488
489                /*!
490                @function flush_journal
491                @abstract Flush journal entries for $string.  Used before adding $string
492                @discussion flush_journal () is an internal function and should be called from add_journal () only
493                @param string File/directory to flush journal entries of
494                @param relatives Realtivity array
495                @param deleteall Delete all types of journal entries, including the active Create entry.
496                                  Normally you only want to delete the Create entry when replacing the file
497                                  Note that this option does not effect $deleteonly
498                @param deletedonly Only flush 'journal-deleted' entries (created when $string was deleted)
499                @result Boolean True/False
500                */
501                function flush_journal ($data)
502                {
503                        if (!is_array ($data))
504                        {
505                                $data = array ();
506                        }
507
508                        $default_values = array
509                                (
510                                        'relatives'     => array (RELATIVE_CURRENT),
511                                        'deleteall'     => False,
512                                        'deletedonly'   => False
513                                );
514
515                        $data = array_merge ($this->default_values ($data, $default_values), $data);
516
517                        $p = $this->path_parts (array(
518                                        'string'        => $data['string'],
519                                        'relatives'     => array ($data['relatives'][0])
520                                )
521                        );
522
523                        $sql = "DELETE FROM phpgw_vfs WHERE directory='".
524                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
525                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'";
526
527                        if (!$data['deleteall'])
528                        {
529                                $sql .= " AND (mime_type != 'journal' AND comment != 'Created')";
530                        }
531
532                        $sql .= "  AND (mime_type='journal-deleted'";
533
534                        if (!$data['deletedonly'])
535                        {
536                                $sql .= " OR mime_type='journal'";
537                        }
538
539                        $sql .= ")";
540
541                        $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
542
543                        if ($query)
544                        {
545                                return True;
546                        }
547                        else
548                        {
549                                return False;
550                        }
551                }
552
553                /*
554                 * See vfs_shared
555                 */
556                function get_journal ($data)
557                {
558                        if (!is_array ($data))
559                        {
560                                $data = array ();
561                        }
562
563                        $default_values = array
564                                (
565                                        'relatives'     => array (RELATIVE_CURRENT),
566                                        'type'  => False
567                                );
568
569                        $data = array_merge ($this->default_values ($data, $default_values), $data);
570
571                        $p = $this->path_parts (array(
572                                        'string'        => $data['string'],
573                                        'relatives'     => array ($data['relatives'][0])
574                                )
575                        );
576
577                        if (!$this->acl_check (array(
578                                        'string' => $p->fake_full_path,
579                                        'relatives' => array ($p->mask)
580                                )))
581                        {
582                                return False;
583                        }
584
585                        $sql = "SELECT * FROM phpgw_vfs WHERE directory='".
586                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
587                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'";
588
589                        if ($data['type'] == 1)
590                        {
591                                $sql .= " AND mime_type='journal'";
592                        }
593                        elseif ($data['type'] == 2)
594                        {
595                                $sql .= " AND mime_type='journal-deleted'";
596                        }
597                        else
598                        {
599                                $sql .= " AND (mime_type='journal' OR mime_type='journal-deleted')";
600                        }
601
602                        $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
603
604                        while ($GLOBALS['phpgw']->db->next_record ())
605                        {
606                                $rarray[] = $GLOBALS['phpgw']->db->Record;
607                        }
608
609                        return $rarray;
610                }
611
612                /*
613                 * See vfs_shared
614                 */
615                function acl_check ($data)
616                {
617
618                        if (!is_array ($data))
619                        {
620                                $data = array ();
621                        }
622       
623                        $default_values = array
624                                (
625                                        'relatives'     => array (RELATIVE_CURRENT),
626                                        'operation'     => PHPGW_ACL_READ,
627                                        'must_exist'    => False
628                                );
629
630                        $data = array_merge ($this->default_values ($data, $default_values), $data);
631
632                        /* Accommodate special situations */
633                        if ($this->override_acl || $data['relatives'][0] == RELATIVE_USER_APP)
634                        {
635                                return True;
636                        }
637
638                        /* ExpressoLivre principle: In your home you do what you want*/
639                        if (strpos($data['string'],$this->my_home) === 0)
640                                return True;
641                        if ($data['relatives'][0] == RELATIVE_NONE || $data['relatives'][0] == RELATIVE_ALL)
642                        {
643                                $path = explode('/',$data['string']);
644                                $data['string'] = '/'.$path[1].'/'.$path[2];
645                        }
646
647
648
649                        if (!$data['owner_id'])
650                        {
651                                $p = $this->path_parts (array(
652                                                'string'        => $data['string'],
653                                                'relatives'     => array ($data['relatives'][0])
654                                        )
655                                );
656
657                                /* Temporary, until we get symlink type files set up */
658                                if ($p->outside)
659                                {
660                                        return True;
661                                }
662
663                                /* Read access is always allowed here, but nothing else is */
664                                if ($data['string'] == '/' || $data['string'] == $this->fakebase)
665                                {
666                                        if ($data['operation'] == PHPGW_ACL_READ)
667                                        {
668                                                return True;
669                                        }
670                                        else
671                                        {
672                                                return False;
673                                        }
674                                }
675
676                                /* If the file doesn't exist, we get ownership from the parent directory */
677                                if (!$this->file_exists (array(
678                                                'string'        => $p->fake_full_path,
679                                                'relatives'     => array ($p->mask)
680                                        ))
681                                )
682                                {
683                                        if ($data['must_exist'])
684                                        {
685                                                return False;
686                                        }
687
688                                        $data['string'] = $p->fake_leading_dirs;
689                                        $p2 = $this->path_parts (array(
690                                                        'string'        => $data['string'],
691                                                        'relatives'     => array ($p->mask)
692                                                )
693                                        );
694
695                                        if (!$this->file_exists (array(
696                                                        'string'        => $data['string'],
697                                                        'relatives'     => array ($p->mask)
698                                                ))
699                                        )
700                                        {
701                                                return False;
702                                        }
703                                }
704                                else
705                                {
706                                        $p2 = $p;
707                                }
708
709                                /*
710                                   We don't use ls () to get owner_id as we normally would,
711                                   because ls () calls acl_check (), which would create an infinite loop
712                                 */
713                                $owner_id = $this->ownerOf($p2->fake_leading_dirs_clean,$p2->fake_name_clean);
714                        }
715                        else
716                        {
717                                $owner_id = $data['owner_id'];
718                        }
719
720                        $user_id = $GLOBALS['phpgw_info']['user']['account_id'];
721
722                        /* They always have access to their own files */
723                        if ($owner_id == $user_id)
724                        {
725                                return True;
726                        }
727
728                        /* Check if they're in the group */
729                        $memberships = $GLOBALS['phpgw']->accounts->membership ($user_id);
730
731                        if (is_array ($memberships))
732                        {
733                                foreach ($memberships as $group_array)
734                                {
735                                        if ($owner_id == $group_array['account_id'])
736                                        {
737                                                $group_ok = 1;
738                                                break;
739                                        }
740                                }
741                        }
742
743                        $acl = CreateObject ('phpgwapi.acl', $owner_id);
744                        $acl->account_id = $owner_id;
745                        $acl->read_repository ();
746
747                        $rights = $acl->get_rights ($user_id);
748
749                        /* Add privileges from the groups this user belongs to */
750                        if (is_array ($memberships))
751                        {
752                                foreach ($memberships as $group_array)
753                                {
754                                        $rights |= $acl->get_rights ($group_array['account_id']);
755                                }
756                        }
757
758                        if ($rights & $data['operation'])
759                        {
760                                return True;
761                        }
762                        elseif (!$rights && $group_ok)
763                        {
764                                $conf = CreateObject('phpgwapi.config', 'phpgwapi');
765                                $conf->read_repository();
766                                if ($conf->config_data['acl_default'] == 'grant')
767                                {
768                                        return True;
769                                }
770                                else
771                                {
772                                        return False;
773                                }
774                        }
775                        else
776                        {
777                                return False;
778                        }
779                }
780                function ownerOf($base,$path){
781                        $query = $GLOBALS['phpgw']->db->query ("SELECT owner_id FROM phpgw_vfs WHERE directory='".
782                        $GLOBALS['phpgw']->db->db_addslashes($base)."' AND name='".
783                        $GLOBALS['phpgw']->db->db_addslashes($path)."' ".$this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
784                        $GLOBALS['phpgw']->db->next_record();
785                        $owner_id = $GLOBALS['phpgw']->db->Record['owner_id'];
786                        if (!$owner_id)
787                        {
788                                $owner_id = 0;
789                        }
790                        return $owner_id;
791                }
792
793                /*used to safe memory in downloads*/
794                function print_content ($data)
795                {
796                        if (!is_array ($data))
797                        {
798                                $data = array ();
799                        }
800
801                        $default_values = array
802                                (
803                                        'relatives'     => array (RELATIVE_CURRENT)
804                                );
805
806                        $data = array_merge ($this->default_values ($data, $default_values), $data);
807
808                        $p = $this->path_parts (array(
809                                        'string'        => $data['string'],
810                                        'relatives'     => array ($data['relatives'][0])
811                                )
812                        );
813
814                        if (!$this->acl_check (array(
815                                        'string'        => $p->fake_full_path,
816                                        'relatives'     => array ($p->mask),
817                                        'operation'     => PHPGW_ACL_READ
818                                ))
819                        )
820                        {
821                                return False;
822                        }
823                        session_write_close();
824                                if ($fp = fopen ($p->real_full_path, 'rb'))
825                                {
826                                        for ($i=0; $i<=filesize($p->real_full_path); $i+=10240)
827                                        {
828                                                echo fread($fp, $i);
829                                                flush();
830                                                usleep(50);
831                                        }
832                                        fclose ($fp);
833                                }
834                                else
835                                {
836                                        return False;
837                                }
838                        return True;
839                }
840
841                /*
842                 * See vfs_shared
843                 */
844                function read ($data)
845                {
846                        if (!is_array ($data))
847                        {
848                                $data = array ();
849                        }
850
851                        $default_values = array
852                                (
853                                        'relatives'     => array (RELATIVE_CURRENT)
854                                );
855
856                        $data = array_merge ($this->default_values ($data, $default_values), $data);
857
858                        $p = $this->path_parts (array(
859                                        'string'        => $data['string'],
860                                        'relatives'     => array ($data['relatives'][0])
861                                )
862                        );
863
864                        if (!$this->acl_check (array(
865                                        'string'        => $p->fake_full_path,
866                                        'relatives'     => array ($p->mask),
867                                        'operation'     => PHPGW_ACL_READ
868                                ))
869                        )
870                        {
871                                return False;
872                        }
873
874                        $conf = CreateObject('phpgwapi.config', 'phpgwapi');
875                        $conf->read_repository();
876                        if ($this->file_actions || $p->outside)
877                        {
878                                if ($fp = fopen ($p->real_full_path, 'rb'))
879                                {
880                                        $contents = fread ($fp, filesize ($p->real_full_path));
881                                        fclose ($fp);
882                                }
883                                else
884                                {
885                                        $contents = False;
886                                }
887                        }
888                        else
889                        {
890                                $ls_array = $this->ls (array(
891                                                'string'        => $p->fake_full_path,
892                                                'relatives'     => array ($p->mask),
893                                        )
894                                );
895
896                                $contents = $ls_array[0]['content'];
897                        }
898
899                        return $contents;
900                }
901
902                /*
903                 * See vfs_shared
904                 */
905                function write ($data)
906                {
907                        if (!is_array ($data))
908                        {
909                                $data = array ();
910                        }
911
912                        $path = explode('/',$data['string']);
913                        $quota = $this->get_quota(array('string' => '/'.$path[1].'/'.$path[2]));
914                        if ($quota > 0 && $this->get_size('/'.$path[1].'/'.$path[2]) >= $quota * 1024 * 1024)
915                                return false;
916
917
918                        $default_values = array
919                                (
920                                        'relatives'     => array (RELATIVE_CURRENT),
921                                        'content'       => ''
922                                );
923
924                        $data = array_merge ($this->default_values ($data, $default_values), $data);
925
926                        $p = $this->path_parts (array(
927                                        'string'        => $data['string'],
928                                        'relatives'     => array ($data['relatives'][0])
929                                )
930                        );
931
932                        if ($this->file_exists (array (
933                                        'string'        => $p->fake_full_path,
934                                        'relatives'     => array ($p->mask)
935                                ))
936                        )
937                        {
938                                $acl_operation = PHPGW_ACL_EDIT;
939                                $journal_operation = VFS_OPERATION_EDITED;
940                        }
941                        else
942                        {
943                                $acl_operation = PHPGW_ACL_ADD;
944                        }
945                        umask(0177);
946
947                        /*
948                           If 'string' doesn't exist, touch () creates both the file and the database entry
949                           If 'string' does exist, touch () sets the modification time and modified by
950                        */
951                        $this->touch (array(
952                                        'string'        => $p->fake_full_path,
953                                        'relatives'     => array ($p->mask)
954                                )
955                        );
956
957                        $conf = CreateObject('phpgwapi.config', 'phpgwapi');
958                        $conf->read_repository();
959                        if ($this->file_actions)
960                        {
961                                if ($fp = fopen ($p->real_full_path, 'wb'))
962                                {
963                                        fwrite ($fp, $data['content']);
964                                        fclose ($fp);
965                                        $write_ok = 1;
966                                }
967                        }
968
969                        if ($write_ok || !$this->file_actions)
970                        {
971                                if ($this->file_actions)
972                                {
973                                        $set_attributes_array = array(
974                                                'size' => filesize ($p->real_full_path)
975                                        );
976                                }
977                                else
978                                {
979                                        $set_attributes_array = array (
980                                                'size'  => strlen ($data['content']),
981                                                'content'       => $data['content']
982                                        );
983                                }
984
985
986                                $this->set_attributes (array
987                                        (
988                                                'string'        => $p->fake_full_path,
989                                                'relatives'     => array ($p->mask),
990                                                'attributes'    => $set_attributes_array
991                                        )
992                                );
993
994                                if ($journal_operation)
995                                {
996                                        $this->add_journal (array(
997                                                        'string'        => $p->fake_full_path,
998                                                        'relatives'     => array ($p->mask),
999                                                        'operation'     => $journal_operation
1000                                                )
1001                                        );
1002                                }
1003
1004                                return True;
1005                        }
1006                        else
1007                        {
1008                                return False;
1009                        }
1010                }
1011
1012                /*
1013                 * See vfs_shared
1014                 */
1015                function touch ($data)
1016                {
1017                        if (!is_array ($data))
1018                        {
1019                                $data = array ();
1020                        }
1021
1022                        $default_values = array
1023                                (
1024                                        'relatives'     => array (RELATIVE_CURRENT)
1025                                );
1026
1027                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1028
1029                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1030                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
1031
1032                        $p = $this->path_parts (array(
1033                                        'string'        => $data['string'],
1034                                        'relatives'     => array ($data['relatives'][0])
1035                                )
1036                        );
1037
1038                        umask (0177);
1039
1040                        if ($this->file_actions)
1041                        {
1042                                /*
1043                                   PHP's touch function will automatically decide whether to
1044                                   create the file or set the modification time
1045                                */
1046                                $rr = @touch ($p->real_full_path);
1047
1048                                if ($p->outside)
1049                                {
1050                                        return $rr;
1051                                }
1052                        }
1053
1054                        /* We, however, have to decide this ourselves */
1055                        if ($this->file_exists (array(
1056                                        'string'        => $p->fake_full_path,
1057                                        'relatives'     => array ($p->mask)
1058                                ))
1059                        )
1060                        {
1061                                if (!$this->acl_check (array(
1062                                                'string'        => $p->fake_full_path,
1063                                                'relatives'     => array ($p->mask),
1064                                                'operation'     => PHPGW_ACL_EDIT
1065                                        )))
1066                                {
1067                                        return False;
1068                                }
1069
1070                                $vr = $this->set_attributes (array(
1071                                                'string'        => $p->fake_full_path,
1072                                                'relatives'     => array ($p->mask),
1073                                                'attributes'    => array(
1074                                                                        'modifiedby_id' => $account_id,
1075                                                                        'modified' => $this->now
1076                                                                )
1077                                                )
1078                                        );
1079                        }
1080                        else
1081                        {
1082                                if (!$this->acl_check (array(
1083                                                'string'        => $p->fake_full_path,
1084                                                'relatives'     => array ($p->mask),
1085                                                'operation'     => PHPGW_ACL_ADD
1086                                        ))
1087                                )
1088                                {
1089                                        return False;
1090                                }
1091
1092                                $query = $GLOBALS['phpgw']->db->query ("INSERT INTO phpgw_vfs (owner_id, directory, name) VALUES ($this->working_id, '".
1093                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."', '".
1094                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."')", __LINE__, __FILE__);
1095
1096                                $this->set_attributes(array(
1097                                        'string'        => $p->fake_full_path,
1098                                        'relatives'     => array ($p->mask),
1099                                        'attributes'    => array (
1100                                                                'createdby_id' => $account_id,
1101                                                                'created' => $this->now,
1102                                                                'size' => 0,
1103                                                                'deleteable' => 'Y',
1104                                                                'app' => $currentapp
1105                                                        )
1106                                        )
1107                                );
1108                                $this->correct_attributes (array(
1109                                                'string'        => $p->fake_full_path,
1110                                                'relatives'     => array ($p->mask)
1111                                        )
1112                                );
1113       
1114                                $this->add_journal (array(
1115                                                'string'        => $p->fake_full_path,
1116                                                'relatives'     => array ($p->mask),
1117                                                'operation'     => VFS_OPERATION_CREATED
1118                                        )
1119                                );
1120                        }
1121
1122                        if ($rr || $vr || $query)
1123                        {
1124                                return True;
1125                        }
1126                        else
1127                        {
1128                                return False;
1129                        }
1130                }
1131
1132                /*
1133                 * See vfs_shared
1134                 * If $data['symlink'] the file is symlinked instead of copied
1135                 */
1136                function cp ($data)
1137                {
1138                        if (!is_array ($data))
1139                        {
1140                                $data = array ();
1141                        }
1142                        if ($data['relatives'][1] == RELATIVE_NONE)
1143                                $path = explode(SEP,$data['to']);
1144                        else
1145                                $path = explode(SEP,$this->my_home);
1146                        $quota = $this->get_quota(array('string' => SEP.$path[1].SEP.$path[2]));
1147                        $size = $this->get_size(array('string' => SEP.$path[1].SEP.$path[2], 'relatives' => $data['relatives'][1]));
1148
1149                        if ($quota > 0 && ($quota * 1024 * 1024) < $size)
1150                                return false;
1151
1152                        $default_values = array
1153                                (
1154                                        'relatives'     => array (RELATIVE_CURRENT, RELATIVE_CURRENT)
1155                                );
1156
1157                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1158
1159                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1160
1161                        $f = $this->path_parts (array(
1162                                        'string'        => $data['from'],
1163                                        'relatives'     => array ($data['relatives'][0])
1164                                )
1165                        );
1166
1167                        $t = $this->path_parts (array(
1168                                        'string'        => $data['to'],
1169                                        'relatives'     => array ($data['relatives'][1])
1170                                )
1171                        );
1172
1173                        if (!$this->acl_check (array(
1174                                        'string'        => $f->fake_full_path,
1175                                        'relatives'     => array ($f->mask),
1176                                        'operation'     => PHPGW_ACL_READ
1177                                ))
1178                        )
1179                        {
1180                                return False;
1181                        }
1182
1183                        if ($exists = $this->file_exists (array(
1184                                        'string'        => $t->fake_full_path,
1185                                        'relatives'     => array ($t->mask)
1186                                ))
1187                        )
1188                        {
1189                                if (!$this->acl_check (array(
1190                                                'string'        => $t->fake_full_path,
1191                                                'relatives'     => array ($t->mask),
1192                                                'operation'     => PHPGW_ACL_EDIT
1193                                        ))
1194                                )
1195                                {
1196                                        return False;
1197                                }
1198                        }
1199                        else
1200                        {
1201                                if (!$this->acl_check (array(
1202                                                'string'        => $t->fake_full_path,
1203                                                'relatives'     => array ($t->mask),
1204                                                'operation'     => PHPGW_ACL_ADD
1205                                        ))
1206                                )
1207                                {
1208                                        return False;
1209                                }
1210                        }
1211
1212                        umask(0177);
1213
1214                        if ($this->file_type (array(
1215                                        'string'        => $f->fake_full_path,
1216                                        'relatives'     => array ($f->mask)
1217                                )) != 'Directory'
1218                        )
1219                        {
1220                                if ($this->file_actions)
1221                                {
1222                                        if (@$data['symlink'])
1223                                        {
1224                                                if ($exists)
1225                                                {
1226                                                        @unlink($t->real_full_path);
1227                                                }
1228                                                if (!symlink($f->real_full_path, $t->real_full_path))
1229                                                {
1230                                                        return False;
1231                                                }
1232                                        }
1233                                        elseif (!copy ($f->real_full_path, $t->real_full_path))
1234                                        {
1235                                                return False;
1236                                        }
1237
1238                                        $size = filesize ($t->real_full_path);
1239                                }
1240                                else
1241                                {
1242                                        $content = $this->read (array(
1243                                                        'string'        => $f->fake_full_path,
1244                                                        'relatives'     => array ($f->mask)
1245                                                )
1246                                        );
1247
1248                                        $size = strlen ($content);
1249                                }
1250
1251                                if ($t->outside)
1252                                {
1253                                        return True;
1254                                }
1255
1256                                $ls_array = $this->ls (array(
1257                                                'string'        => $f->fake_full_path,
1258                                                'relatives'     => array ($f->mask),
1259                                                'checksubdirs'  => False,
1260                                                'mime_type'     => False,
1261                                                'nofiles'       => True
1262                                        )
1263                                );
1264                                $record = $ls_array[0];
1265
1266                                if ($this->file_exists (array(
1267                                                'string'        => $data['to'],
1268                                                'relatives'     => array ($data['relatives'][1])
1269                                        ))
1270                                )
1271                                {
1272                                        $query = $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET owner_id='$this->working_id', directory='".
1273                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_leading_dirs_clean)."', name='".
1274                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_name_clean)."' WHERE owner_id='$this->working_id' AND directory='".
1275                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_leading_dirs_clean)."' AND name='".
1276                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_name_clean)."'" . $this->extra_sql (VFS_SQL_UPDATE), __LINE__, __FILE__);
1277
1278                                        $set_attributes_array = array (
1279                                                'createdby_id' => $account_id,
1280                                                'created' => $this->now,
1281                                                'size' => $size,
1282                                                'mime_type' => $record['mime_type'],
1283                                                'deleteable' => $record['deleteable'],
1284                                                'comment' => $record['comment'],
1285                                                'app' => $record['app']
1286                                        );
1287
1288                                        if (!$this->file_actions)
1289                                        {
1290                                                $set_attributes_array['content'] = $content;
1291                                        }
1292
1293                                        $this->set_attributes(array(
1294                                                'string'        => $t->fake_full_path,
1295                                                'relatives'     => array ($t->mask),
1296                                                'attributes'    => $set_attributes_array
1297                                                )
1298                                        );
1299
1300                                        $this->add_journal (array(
1301                                                        'string'        => $t->fake_full_path,
1302                                                        'relatives'     => array ($t->mask),
1303                                                        'operation'     => VFS_OPERATION_EDITED
1304                                                )
1305                                        );
1306                                }
1307                                else
1308                                {
1309                                        $this->touch (array(
1310                                                        'string'        => $t->fake_full_path,
1311                                                        'relatives'     => array ($t->mask)
1312                                                )
1313                                        );
1314
1315                                        $set_attributes_array = array (
1316                                                'createdby_id' => $account_id,
1317                                                'created' => $this->now,
1318                                                'size' => $size,
1319                                                'mime_type' => $record['mime_type'],
1320                                                'deleteable' => $record['deleteable'],
1321                                                'comment' => $record['comment'],
1322                                                'app' => $record['app']
1323                                        );
1324
1325                                        if (!$this->file_actions)
1326                                        {
1327                                                $set_attributes_array['content'] = $content;
1328                                        }
1329
1330                                        $this->set_attributes(array(
1331                                                        'string'        => $t->fake_full_path,
1332                                                        'relatives'     => array ($t->mask),
1333                                                        'attributes'    => $set_attributes_array
1334                                                )
1335                                        );
1336                                }
1337                                $this->correct_attributes (array(
1338                                                'string'        => $t->fake_full_path,
1339                                                'relatives'     => array ($t->mask)
1340                                        )
1341                                );
1342                        }
1343                        else    /* It's a directory */
1344                        {
1345                                /* First, make the initial directory */
1346                                $this->mkdir (array(
1347                                                'string'        => $data['to'],
1348                                                'relatives'     => array ($data['relatives'][1])
1349                                        )
1350                                );
1351
1352                                /* Next, we create all the directories below the initial directory */
1353                                foreach($this->ls (array(
1354                                                'string'        => $f->fake_full_path,
1355                                                'relatives'     => array ($f->mask),
1356                                                'checksubdirs'  => True,
1357                                                'mime_type'     => 'Directory'
1358                                        )) as $entry)
1359                                {
1360                                        $newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry['directory']);
1361                                        $this->mkdir (array(
1362                                                        'string'        => $newdir.'/'.$entry['name'],
1363                                                        'relatives'     => array ($t->mask)
1364                                                )
1365                                        );
1366                                }
1367
1368                                /* Lastly, we copy the files over */
1369                                foreach($this->ls (array(
1370                                                'string'        => $f->fake_full_path,
1371                                                'relatives'     => array ($f->mask)
1372                                        )) as $entry)
1373                                {
1374                                        if ($entry['mime_type'] == 'Directory')
1375                                        {
1376                                                continue;
1377                                        }
1378
1379                                        $newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry['directory']);
1380                                        $this->cp (array(
1381                                                        'from'  => "$entry[directory]/$entry[name]",
1382                                                        'to'    => "$newdir/$entry[name]",
1383                                                        'relatives'     => array ($f->mask, $t->mask)
1384                                                )
1385                                        );
1386                                }
1387                        }
1388
1389                        if (!$f->outside)
1390                        {
1391                                $this->add_journal (array(
1392                                                'string'        => $f->fake_full_path,
1393                                                'relatives'     => array ($f->mask),
1394                                                'operation'     => VFS_OPERATION_COPIED,
1395                                                'state_one'     => NULL,
1396                                                'state_two'     => $t->fake_full_path
1397                                        )
1398                                );
1399                        }
1400
1401                        return True;
1402                }
1403
1404                /*
1405                 * See vfs_shared
1406                 */
1407                function mv ($data)
1408                {
1409                        if (!is_array ($data))
1410                        {
1411                                $data = array ();
1412                        }
1413                        if ($data['relatives'][1] == RELATIVE_NONE)
1414                        {
1415                                $path = explode('/',$data['to']);
1416                                $quota = $this->get_quota(array('string' => '/'.$path[1].'/'.$path[2]));
1417                                $size = $this->get_size(array('string' => '/'.$path[1].'/'.$path[2], 'relatives' => $data['relatives'][1]));
1418                        }
1419                        else
1420                        {
1421                                $quota = $this->get_quota(array('string' => $this->my_home));
1422                                $size = $this->get_size(array('string' => $this->my_home, 'relatives' => $data['relatives'][1]));
1423                        }
1424                        if ($quota > 0 && $size >= $quota * 1024 * 1024)
1425                                return false;
1426
1427
1428                        $default_values = array
1429                                (
1430                                        'relatives'     => array (RELATIVE_CURRENT, RELATIVE_CURRENT)
1431                                );
1432
1433                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1434
1435                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1436
1437                        $f = $this->path_parts (array(
1438                                        'string'        => $data['from'],
1439                                        'relatives'     => array ($data['relatives'][0])
1440                                )
1441                        );
1442
1443                        $t = $this->path_parts (array(
1444                                        'string'        => $data['to'],
1445                                        'relatives'     => array ($data['relatives'][1])
1446                                )
1447                        );
1448
1449                        if (!$this->acl_check (array(
1450                                        'string'        => $data['to'],
1451                                        'relatives'     => array ($t->mask),
1452                                        'operation'     => PHPGW_ACL_ADD
1453                                ))
1454                        )
1455                        {
1456                                return False;
1457                        }
1458
1459                        if ($this->file_exists (array(
1460                                        'string'        => $t->fake_full_path,
1461                                        'relatives'     => array ($t->mask)
1462                                ))
1463                        )
1464                        {
1465                                if (!$this->acl_check (array(
1466                                                'string'        => $data['to'],
1467                                                'relatives'     => array ($t->mask),
1468                                                'operation'     => PHPGW_ACL_EDIT
1469                                        ))
1470                                )
1471                                {
1472                                        return False;
1473                                }
1474                        }
1475
1476                        umask (0177);
1477
1478                        /* We can't move directories into themselves */
1479                        if (($this->file_type (array(
1480                                        'string'        => $f->fake_full_path,
1481                                        'relatives'     => array ($f->mask)
1482                                ) == 'Directory'))
1483                                && ereg ("^$f->fake_full_path", $t->fake_full_path)
1484                        )
1485                        {
1486                                if (($t->fake_full_path == $f->fake_full_path) || substr ($t->fake_full_path, strlen ($f->fake_full_path), 1) == '/')
1487                                {
1488                                        return False;
1489                                }
1490                        }
1491
1492                        if ($this->file_exists (array(
1493                                        'string'        => $f->fake_full_path,
1494                                        'relatives'     => array ($f->mask)
1495                                ))
1496                        )
1497                        {
1498                                /* We get the listing now, because it will change after we update the database */
1499                                $ls = $this->ls (array(
1500                                                'string'        => $f->fake_full_path,
1501                                                'relatives'     => array ($f->mask)
1502                                        )
1503                                );
1504
1505                                if ($this->file_exists (array(
1506                                                'string'        => $t->fake_full_path,
1507                                                'relatives'     => array ($t->mask)
1508                                        ))
1509                                )
1510                                {
1511                                        $this->rm (array(
1512                                                        'string'        => $t->fake_full_path,
1513                                                        'relatives'     => array ($t->mask)
1514                                                )
1515                                        );
1516                                }
1517
1518                                /*
1519                                   We add the journal entry now, before we delete.  This way the mime_type
1520                                   field will be updated to 'journal-deleted' when the file is actually deleted
1521                                */
1522                                if (!$f->outside)
1523                                {
1524                                        $this->add_journal (array(
1525                                                        'string'        => $f->fake_full_path,
1526                                                        'relatives'     => array ($f->mask),
1527                                                        'operation'     => VFS_OPERATION_MOVED,
1528                                                        'state_one'     => $f->fake_full_path,
1529                                                        'state_two'     => $t->fake_full_path
1530                                                )
1531                                        );
1532                                }
1533
1534                                /*
1535                                   If the from file is outside, it won't have a database entry,
1536                                   so we have to touch it and find the size
1537                                */
1538                                if ($f->outside)
1539                                {
1540                                        $size = filesize ($f->real_full_path);
1541
1542                                        $this->touch (array(
1543                                                        'string'        => $t->fake_full_path,
1544                                                        'relatives'     => array ($t->mask)
1545                                                )
1546                                        );
1547                                        $query = $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET size=$size WHERE directory='".
1548                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_leading_dirs_clean)."' AND name='".
1549                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_UPDATE)), __LINE__, __FILE__);
1550                                }
1551                                elseif (!$t->outside)
1552                                {
1553                                        $query = $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET name='".
1554                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_name_clean)."', directory='".
1555                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_leading_dirs_clean)."' WHERE directory='".
1556                                                $GLOBALS['phpgw']->db->db_addslashes($f->fake_leading_dirs_clean)."' AND name='".
1557                                                $GLOBALS['phpgw']->db->db_addslashes($f->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_UPDATE)), __LINE__, __FILE__);
1558                                }
1559
1560                                $this->set_attributes(array(
1561                                                'string'        => $t->fake_full_path,
1562                                                'relatives'     => array ($t->mask),
1563                                                'attributes'    => array (
1564                                                                        'modifiedby_id' => $account_id,
1565                                                                        'modified' => $this->now
1566                                                                )
1567                                        )
1568                                );
1569
1570                                $this->correct_attributes (array(
1571                                                'string'        => $t->fake_full_path,
1572                                                'relatives'     => array ($t->mask)
1573                                        )
1574                                );
1575
1576                                if ($this->file_actions)
1577                                {
1578                                        $rr = rename ($f->real_full_path, $t->real_full_path);
1579                                }
1580
1581                                /*
1582                                   This removes the original entry from the database
1583                                   The actual file is already deleted because of the rename () above
1584                                */
1585                                if ($t->outside)
1586                                {
1587                                        $this->rm (array(
1588                                                        'string'        => $f->fake_full_path,
1589                                                        'relatives'     => $f->mask
1590                                                )
1591                                        );
1592                                }
1593                        }
1594                        else
1595                        {
1596                                return False;
1597                        }
1598
1599                        if ($this->file_type (array(
1600                                        'string'        => $t->fake_full_path,
1601                                        'relatives'     => array ($t->mask)
1602                                )) == 'Directory'
1603                        )
1604                        {
1605                                /* We got $ls from above, before we renamed the directory */
1606                                foreach ($ls as $entry)
1607                                {
1608                                        $newdir = ereg_replace ("^$f->fake_full_path", $t->fake_full_path, $entry['directory']);
1609                                        $newdir_clean = $this->clean_string (array ('string' => $newdir));
1610
1611                                        $query = $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET directory='".
1612                                                $GLOBALS['phpgw']->db->db_addslashes($newdir_clean)."' WHERE file_id='$entry[file_id]'" .
1613                                                $this->extra_sql (array ('query_type' => VFS_SQL_UPDATE)), __LINE__, __FILE__);
1614                                        $this->correct_attributes (array(
1615                                                        'string'        => "$newdir/$entry[name]",
1616                                                        'relatives'     => array ($t->mask)
1617                                                )
1618                                        );
1619                                }
1620                        }
1621
1622                        $this->add_journal (array(
1623                                        'string'        => $t->fake_full_path,
1624                                        'relatives'     => array ($t->mask),
1625                                        'operation'     => VFS_OPERATION_MOVED,
1626                                        'state_one'     => $f->fake_full_path,
1627                                        'state_two'     => $t->fake_full_path
1628                                )
1629                        );
1630
1631                        return True;
1632                }
1633
1634                /*
1635                 * See vfs_shared
1636                 */
1637                function rm ($data)
1638                {
1639                        if (!is_array ($data))
1640                        {
1641                                $data = array ();
1642                        }
1643
1644                        $default_values = array
1645                                (
1646                                        'relatives'     => array (RELATIVE_CURRENT)
1647                                );
1648
1649                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1650
1651                        $p = $this->path_parts (array(
1652                                        'string'        => $data['string'],
1653                                        'relatives'     => array ($data['relatives'][0])
1654                                )
1655                        );
1656                        if (!$this->file_exists (array(
1657                                        'string'        => $data['string'],
1658                                        'relatives'     => array ($data['relatives'][0])
1659                                ))
1660                        )
1661                        {
1662                                if ($this->file_actions)
1663                                {
1664                                        $rr = unlink ($p->real_full_path);
1665                                }
1666                                else
1667                                {
1668                                        $rr = True;
1669                                }
1670
1671                                if ($rr)
1672                                {
1673                                        return True;
1674                                }
1675                                else
1676                                {
1677                                        return False;
1678                                }
1679                        }
1680
1681                        if ($this->file_type (array(
1682                                        'string'        => $data['string'],
1683                                        'relatives'     => array ($data['relatives'][0])
1684                                )) != 'Directory'
1685                        )
1686                        {
1687                                $this->add_journal (array(
1688                                                'string'        => $p->fake_full_path,
1689                                                'relatives'     => array ($p->mask),
1690                                                'operation'     => VFS_OPERATION_DELETED
1691                                        )
1692                                );
1693
1694                                $query = $GLOBALS['phpgw']->db->query ("DELETE FROM phpgw_vfs WHERE directory='".
1695                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
1696                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'".$this->extra_sql (array ('query_type' => VFS_SQL_DELETE)), __LINE__, __FILE__);
1697
1698                                if ($this->file_actions)
1699                                {
1700                                        $rr = unlink ($p->real_full_path);
1701                                }
1702                                else
1703                                {
1704                                        $rr = True;
1705                                }
1706
1707                                if ($query || $rr)
1708                                {
1709                                        return True;
1710                                }
1711                                else
1712                                {
1713                                        return False;
1714                                }
1715                        }
1716                        else
1717                        {
1718                                $ls = $this->ls (array(
1719                                                'string'        => $p->fake_full_path,
1720                                                'relatives'     => array ($p->mask)
1721                                        )
1722                                );
1723
1724                                /* First, we cycle through the entries and delete the files */
1725                                foreach($ls as $entry)
1726                                {
1727                                        if ($entry['mime_type'] == 'Directory')
1728                                        {
1729                                                continue;
1730                                        }
1731
1732                                        $this->rm (array(
1733                                                        'string'        => "$entry[directory]/$entry[name]",
1734                                                        'relatives'     => array ($p->mask)
1735                                                )
1736                                        );
1737                                }
1738
1739                                /* Now we cycle through again and delete the directories */
1740                                foreach ($ls as $entry)
1741                                {
1742                                        if ($entry['mime_type'] != 'Directory')
1743                                        {
1744                                                continue;
1745                                        }
1746
1747                                        /* Only the best in confusing recursion */
1748                                        $this->rm (array(
1749                                                        'string'        => "$entry[directory]/$entry[name]",
1750                                                        'relatives'     => array ($p->mask)
1751                                                )
1752                                        );
1753                                }
1754
1755                                /* If the directory is linked, we delete the placeholder directory */
1756                                $ls_array = $this->ls (array(
1757                                                'string'        => $p->fake_full_path,
1758                                                'relatives'     => array ($p->mask),
1759                                                'checksubdirs'  => False,
1760                                                'mime_type'     => False,
1761                                                'nofiles'       => True
1762                                        )
1763                                );
1764                                $link_info = $ls_array[0];
1765
1766                                if ($link_info['link_directory'] && $link_info['link_name'])
1767                                {
1768                                        $path = $this->path_parts (array(
1769                                                        'string'        => $link_info['directory'] . '/' . $link_info['name'],
1770                                                        'relatives'     => array ($p->mask),
1771                                                        'nolinks'       => True
1772                                                )
1773                                        );
1774
1775                                        if ($this->file_actions)
1776                                        {
1777                                                rmdir ($path->real_full_path);
1778                                        }
1779                                }
1780
1781                                /* Last, we delete the directory itself */
1782                                $this->add_journal (array(
1783                                                'string'        => $p->fake_full_path,
1784                                                'relatives'     => array ($p->mask),
1785                                                'operaton'      => VFS_OPERATION_DELETED
1786                                        )
1787                                );
1788
1789                                $query = $GLOBALS['phpgw']->db->query ("DELETE FROM phpgw_vfs WHERE directory='".
1790                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
1791                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" .
1792                                        $this->extra_sql (array ('query_type' => VFS_SQL_DELETE)), __LINE__, __FILE__);
1793
1794                                if ($this->file_actions)
1795                                {
1796                                        rmdir ($p->real_full_path);
1797                                }
1798
1799                                return True;
1800                        }
1801                }
1802
1803                /*
1804                 * See vfs_shared
1805                 */
1806                function mkdir ($data)
1807                {
1808                        if (!is_array ($data))
1809                        {
1810                                $data = array ();
1811                        }
1812
1813                        $default_values = array
1814                                (
1815                                        'relatives'     => array (RELATIVE_CURRENT)
1816                                );
1817
1818                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1819
1820                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1821                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
1822
1823                        $p = $this->path_parts (array(
1824                                        'string'        => $data['string'],
1825                                        'relatives'     => array ($data['relatives'][0])
1826                                )
1827                        );
1828
1829                        if (!$this->acl_check (array(
1830                                        'string'        => $p->fake_full_path,
1831                                        'relatives'     => array ($p->mask),
1832                                        'operation'     => PHPGW_ACL_ADD)
1833                                )
1834                        )
1835                        {
1836                                return False;
1837                        }
1838
1839                        /* We don't allow /'s in dir names, of course */
1840                        if (ereg ("/", $p->fake_name))
1841                        {
1842                                return False;
1843                        }
1844
1845                        umask (077);
1846
1847                        if ($this->file_actions)
1848                        {
1849                                if (!@is_dir($p->real_leading_dirs_clean))      // eg. /home or /group does not exist
1850                                {
1851                                        if (!@mkdir($p->real_leading_dirs_clean,0770))  // ==> create it
1852                                        {
1853                                                return False;
1854                                        }
1855                                }
1856                                if (@is_dir($p->real_full_path))        // directory already exists
1857                                {
1858                                        $this->update_real($data,True);         // update its contents
1859                                }
1860                                elseif (!@mkdir ($p->real_full_path, 0770))
1861                                {
1862                                        return False;
1863                                }
1864                        }
1865
1866                        if (!$this->file_exists (array(
1867                                        'string'        => $p->fake_full_path,
1868                                        'relatives'     => array ($p->mask)
1869                                ))
1870                        )
1871                        {
1872                                $query = $GLOBALS['phpgw']->db->query ("INSERT INTO phpgw_vfs (owner_id, name, directory) VALUES ($this->working_id, '".
1873                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."', '".
1874                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."')", __LINE__, __FILE__);
1875       
1876                                $this->set_attributes(array(
1877                                        'string'        => $p->fake_full_path,
1878                                        'relatives'     => array ($p->mask),
1879                                        'attributes'    => array (
1880                                                                'createdby_id' => $account_id,
1881                                                                'size' => 4096,
1882                                                                'mime_type' => 'Directory',
1883                                                                'created' => $this->now,
1884                                                                'deleteable' => 'Y',
1885                                                                'app' => $currentapp
1886                                                        )
1887                                        )
1888                                );
1889
1890                                $this->correct_attributes (array(
1891                                                'string'        => $p->fake_full_path,
1892                                                'relatives'     => array ($p->mask)
1893                                        )
1894                                );
1895
1896                                $this->add_journal (array(
1897                                                'string'        => $p->fake_full_path,
1898                                                'relatives'     => array ($p->mask),
1899                                                'operation'     => VFS_OPERATION_CREATED
1900                                        )
1901                                );
1902                        }
1903                        else
1904                        {
1905                                return False;
1906                        }
1907
1908                        return True;
1909                }
1910
1911                /*
1912                 * See vfs_shared
1913                 */
1914                function make_link ($data)
1915                {
1916                        if (!is_array ($data))
1917                        {
1918                                $data = array ();
1919                        }
1920
1921                        $default_values = array
1922                                (
1923                                        'relatives'     => array (RELATIVE_CURRENT, RELATIVE_CURRENT)
1924                                );
1925
1926                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1927
1928                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1929                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
1930
1931                        $vp = $this->path_parts (array(
1932                                        'string'        => $data['vdir'],
1933                                        'relatives'     => array ($data['relatives'][0])
1934                                )
1935                        );
1936
1937                        $rp = $this->path_parts (array(
1938                                        'string'        => $data['rdir'],
1939                                        'relatives'     => array ($data['relatives'][1])
1940                                )
1941                        );
1942
1943                        if (!$this->acl_check (array(
1944                                        'string'        => $vp->fake_full_path,
1945                                        'relatives'     => array ($vp->mask),
1946                                        'operation'     => PHPGW_ACL_ADD
1947                                ))
1948                        )
1949                        {
1950                                return False;
1951                        }
1952
1953                        if ((!$this->file_exists (array(
1954                                        'string'        => $rp->real_full_path,
1955                                        'relatives'     => array ($rp->mask)
1956                                )))
1957                                && !mkdir ($rp->real_full_path, 0770))
1958                        {
1959                                return False;
1960                        }
1961
1962                        if (!$this->mkdir (array(
1963                                        'string'        => $vp->fake_full_path,
1964                                        'relatives'     => array ($vp->mask)
1965                                ))
1966                        )
1967                        {
1968                                return False;
1969                        }
1970
1971                        $size = $this->get_size (array(
1972                                        'string'        => $rp->real_full_path,
1973                                        'relatives'     => array ($rp->mask)
1974                                )
1975                        );
1976
1977                        $this->set_attributes(array(
1978                                        'string'        => $vp->fake_full_path,
1979                                        'relatives'     => array ($vp->mask),
1980                                        'attributes'    => array (
1981                                                                'link_directory' => $rp->real_leading_dirs,
1982                                                                'link_name' => $rp->real_name,
1983                                                                'size' => $size
1984                                                        )
1985                                )
1986                        );
1987
1988                        $this->correct_attributes (array(
1989                                        'string'        => $vp->fake_full_path,
1990                                        'relatives'     => array ($vp->mask)
1991                                )
1992                        );
1993
1994                        return True;
1995                }
1996
1997                /*
1998                 * See vfs_shared
1999                 */
2000                function set_attributes ($data)
2001                {
2002                        if (!is_array ($data))
2003                        {
2004                                $data = array ();
2005                        }
2006
2007                        $default_values = array
2008                                (
2009                                        'relatives'     => array (RELATIVE_CURRENT),
2010                                        'attributes'    => array ()
2011                                );
2012
2013                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2014
2015                        $p = $this->path_parts (array(
2016                                        'string'        => $data['string'],
2017                                        'relatives'     => array ($data['relatives'][0])
2018                                )
2019                        );
2020
2021                        /*
2022                           This is kind of trivial, given that set_attributes () can change owner_id,
2023                           size, etc.
2024                        */
2025                        if (!$this->acl_check (array(
2026                                        'string'        => $p->fake_full_path,
2027                                        'relatives'     => array ($p->mask),
2028                                        'operation'     => PHPGW_ACL_EDIT
2029                                ))
2030                        )
2031                        {
2032                                return False;
2033                        }
2034
2035                        if (!$this->file_exists (array(
2036                                        'string'        => $data['string'],
2037                                        'relatives'     => array ($data['relatives'][0])
2038                                ))
2039                        )
2040                        {
2041                                return False;
2042                        }
2043
2044                        /*
2045                           All this voodoo just decides which attributes to update
2046                           depending on if the attribute was supplied in the 'attributes' array
2047                        */
2048
2049                        $ls_array = $this->ls (array(
2050                                        'string'        => $p->fake_full_path,
2051                                        'relatives'     => array ($p->mask),
2052                                        'checksubdirs'  => False,
2053                                        'nofiles'       => True
2054                                )
2055                        );
2056                        $record = $ls_array[0];
2057
2058                        $sql = 'UPDATE phpgw_vfs SET ';
2059
2060                        $change_attributes = 0;
2061
2062                        foreach ($this->attributes as $attribute)
2063                        {
2064                                if (isset ($data['attributes'][$attribute]))
2065                                {
2066                                        /*
2067                                           Indicate that the EDITED_COMMENT operation needs to be journaled,
2068                                           but only if the comment changed
2069                                        */
2070                                        if ($attribute == 'comment' && $data['attributes'][$attribute] != $record[$attribute])
2071                                        {
2072                                                $edited_comment = 1;
2073                                        }
2074
2075                                        if ($change_attributes > 0)
2076                                        {
2077                                                $sql .= ', ';
2078                                        }
2079
2080                                        // RalfBecker 2004/07/24:
2081                                        // this is only a hack to fix bug [ 991222 ] Error uploading file
2082                                        // the whole class need to be reworked with the new db-functions
2083                                        if (!isset($this->column_defs))
2084                                        {
2085                                                $table_defs = $GLOBALS['phpgw']->db->get_table_definitions('phpgwapi','phpgw_vfs');
2086                                                $this->column_defs = $table_defs['fd'];
2087                                        }
2088                                        $sql .= $attribute.'=' .$GLOBALS['phpgw']->db->quote($data['attributes'][$attribute],$this->column_defs[$attribute]['type']);
2089
2090                                        $change_attributes++;
2091                                }
2092                        }
2093
2094                        if (!$change_attributes)
2095                        {
2096                                return True;    // nothing to do
2097                        }
2098                        $sql .= ' WHERE file_id='.(int) $record['file_id'];
2099                        $sql .= $this->extra_sql (array ('query_type' => VFS_SQL_UPDATE));
2100                        $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
2101
2102                        if ($query)
2103                        {
2104                                if ($edited_comment)
2105                                {
2106                                        $this->add_journal (array(
2107                                                        'string'        => $p->fake_full_path,
2108                                                        'relatives'     => array ($p->mask),
2109                                                        'operation'     => VFS_OPERATION_EDITED_COMMENT
2110                                                )
2111                                        );
2112                                }
2113
2114                                return True;
2115                        }
2116                        else
2117                        {
2118                                return False;
2119                        }
2120                }
2121
2122                /*!
2123                @function correct_attributes
2124                @abstract Set the correct attributes for 'string' (e.g. owner)
2125                @param string File/directory to correct attributes of
2126                @param relatives Relativity array
2127                @result Boolean True/False
2128                */
2129                function correct_attributes ($data)
2130                {
2131                        if (!is_array ($data))
2132                        {
2133                                $data = array ();
2134                        }
2135
2136                        $default_values = array
2137                                (
2138                                        'relatives'     => array (RELATIVE_CURRENT)
2139                                );
2140
2141                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2142
2143                        $p = $this->path_parts (array(
2144                                        'string'        => $data['string'],
2145                                        'relatives'     => array ($data['relatives'][0])
2146                                )
2147                        );
2148
2149                        if ($p->fake_leading_dirs != $this->fakebase && $p->fake_leading_dirs != '/')
2150                        {
2151                                $ls_array = $this->ls (array(
2152                                                'string'        => $p->fake_leading_dirs,
2153                                                'relatives'     => array ($p->mask),
2154                                                'checksubdirs'  => False,
2155                                                'nofiles'       => True
2156                                        )
2157                                );
2158                                $set_attributes_array = Array(
2159                                        'owner_id' => $ls_array[0]['owner_id']
2160                                );
2161                        }
2162                        elseif (preg_match ("+^$this->fakebase\/(.*)$+U", $p->fake_full_path, $matches))
2163                        {
2164                                $set_attributes_array = Array(
2165                                        'owner_id' => $GLOBALS['phpgw']->accounts->name2id ($matches[1])
2166                                );
2167                        }
2168                        else
2169                        {
2170                                $set_attributes_array = Array(
2171                                        'owner_id' => 0
2172                                );
2173                        }
2174
2175                        $this->set_attributes (array(
2176                                        'string'        => $p->fake_full_name,
2177                                        'relatives'     => array ($p->mask),
2178                                        'attributes'    => $set_attributes_array
2179                                )
2180                        );
2181
2182                        return True;
2183                }
2184
2185                /*
2186                 * See vfs_shared
2187                 */
2188                function file_type ($data)
2189                {
2190                        if (!is_array ($data))
2191                        {
2192                                $data = array ();
2193                        }
2194
2195                        $default_values = array
2196                                (
2197                                        'relatives'     => array (RELATIVE_CURRENT)
2198                                );
2199
2200                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2201
2202                        $p = $this->path_parts (array(
2203                                        'string'        => $data['string'],
2204                                        'relatives'     => array ($data['relatives'][0])
2205                                )
2206                        );
2207
2208                        if (!$this->acl_check (array(
2209                                        'string'        => $p->fake_full_path,
2210                                        'relatives'     => array ($p->mask),
2211                                        'operation'     => PHPGW_ACL_READ,
2212                                        'must_exist'    => True
2213                                ))
2214                        )
2215                        {
2216                                return False;
2217                        }
2218
2219                        if ($p->outside)
2220                        {
2221                                if (is_dir ($p->real_full_path))
2222                                {
2223                                        return ('Directory');
2224                                }
2225
2226                                /*
2227                                   We don't return an empty string here, because it may still match with a database query
2228                                   because of linked directories
2229                                */
2230                        }
2231
2232                        /*
2233                           We don't use ls () because it calls file_type () to determine if it has been
2234                           passed a directory
2235                        */
2236                        $db2 = $GLOBALS['phpgw']->db;
2237                        $db2->query ("SELECT mime_type FROM phpgw_vfs WHERE directory='".
2238                                $db2->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2239                                $db2->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2240                        $db2->next_record ();
2241                        $mime_type = $db2->Record['mime_type'];
2242                        if(!$mime_type)
2243                        {
2244                                $mime_type = $this->get_ext_mime_type (array ('string' => $data['string']));
2245                                {
2246                                        $db2->query ("UPDATE phpgw_vfs SET mime_type='$mime_type' WHERE directory='".
2247                                                $db2->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2248                                                $db2->db_addslashes($p->fake_name_clean)."'" .
2249                                                $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2250                                }
2251                        }
2252
2253                        return $mime_type;
2254                }
2255
2256                /*
2257                 * See vfs_shared
2258                 */
2259                function file_exists ($data)
2260                {
2261                        if (!is_array ($data))
2262                        {
2263                                $data = array ();
2264                        }
2265
2266                        $default_values = array
2267                                (
2268                                        'relatives'     => array (RELATIVE_CURRENT)
2269                                );
2270
2271                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2272
2273                        $p = $this->path_parts (array(
2274                                        'string'        => $data['string'],
2275                                        'relatives'     => array ($data['relatives'][0])
2276                                )
2277                        );
2278
2279                        if ($p->outside)
2280                        {
2281                                $rr = file_exists ($p->real_full_path);
2282
2283                                return $rr;
2284                        }
2285
2286                        $db2 = $GLOBALS['phpgw']->db;
2287                        $db2->query ("SELECT name FROM phpgw_vfs WHERE directory='".
2288                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2289                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2290
2291                        if ($db2->next_record ())
2292                        {
2293                                return True;
2294                        }
2295                        else
2296                        {
2297                                return False;
2298                        }
2299                }
2300
2301                /*
2302                 * See vfs_shared
2303                 */
2304                function get_size ($data)
2305                {
2306                        if (!is_array ($data))
2307                        {
2308                                $data = array ();
2309                        }
2310
2311                        $default_values = array
2312                                (
2313                                        'relatives'     => array (RELATIVE_CURRENT),
2314                                        'checksubdirs'  => True
2315                                );
2316
2317                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2318
2319                        $p = $this->path_parts (array(
2320                                        'string'        => $data['string'],
2321                                        'relatives'     => array ($data['relatives'][0])
2322                                )
2323                        );
2324
2325                        if (!$this->acl_check (array(
2326                                        'string'        => $p->fake_full_path,
2327                                        'relatives'     => array ($p->mask),
2328                                        'operation'     => PHPGW_ACL_READ,
2329                                        'must_exist'    => True
2330                                ))
2331                        )
2332                        {
2333                                return False;
2334                        }
2335
2336                        /*
2337                           WIP - this should run through all of the subfiles/directories in the directory and tally up
2338                           their sizes.  Should modify ls () to be able to return a list for files outside the virtual root
2339                        */
2340                        if ($p->outside)
2341                        {
2342                                $size = filesize ($p->real_full_path);
2343
2344                                return $size;
2345                        }
2346
2347                        foreach($this->ls (array(
2348                                        'string'        => $p->fake_full_path,
2349                                        'relatives'     => array ($p->mask),
2350                                        'checksubdirs'  => $data['checksubdirs'],
2351                                        'nofiles'       => !$data['checksubdirs']
2352                                )) as $file_array)
2353                        {
2354                                /*
2355                                   Make sure the file is in the directory we want, and not
2356                                   some deeper nested directory with a similar name
2357                                */
2358/*
2359                                if (@!ereg ('^' . $file_array['directory'], $p->fake_full_path))
2360                                {
2361                                        continue;
2362                                }
2363*/
2364
2365                                $size += $file_array['size'];
2366                        }
2367
2368                        if ($data['checksubdirs'])
2369                        {
2370                                $query = $GLOBALS['phpgw']->db->query ("SELECT size FROM phpgw_vfs WHERE directory='".
2371                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2372                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" .
2373                                        $this->extra_sql (array ('query_text' => VFS_SQL_SELECT)));
2374                                $GLOBALS['phpgw']->db->next_record ();
2375                                $size += $GLOBALS['phpgw']->db->Record[0];
2376                        }
2377
2378                        return $size;
2379                }
2380                /*
2381                 * get the quota defined for the path in sql table
2382                 */
2383                function get_quota($data){
2384                        if (!is_array ($data))
2385                        {
2386                                $data = array ();
2387                        }
2388
2389                        $default_values = array
2390                                (
2391                                        'relatives'     => array (RELATIVE_CURRENT)
2392                                );
2393
2394                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2395
2396                        $p = $this->path_parts (array(
2397                                        'string'        => $data['string'],
2398                                        'relatives'     => RELATIVE_NONE
2399                                )
2400                        );
2401
2402                        if (!$this->acl_check (array(
2403                                'string'        => $p->fake_full_path,
2404                                'relatives'     => $p->mask,
2405                                'operation'     => PHPGW_ACL_READ
2406                        ))
2407                        )
2408                        {
2409                                return False;
2410                        }
2411                        $query = $GLOBALS['phpgw']->db->query ("SELECT quota_size FROM phpgw_vfs_quota WHERE directory = '".$data['string']."' LIMIT 1;", __LINE__,__FILE__);
2412
2413                        $GLOBALS['phpgw']->db->next_record ();
2414                        $record = $GLOBALS['phpgw']->db->Record;
2415                        return $record['quota_size'];
2416                }
2417                function set_quota($data){
2418                        if (!is_array ($data))
2419                        {
2420                                $data = array ();
2421                        }
2422
2423                        $default_values = array
2424                                (
2425                                        'relatives'     => array (RELATIVE_CURRENT)
2426                                );
2427
2428                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2429
2430                        $p = $this->path_parts (array(
2431                                        'string'        => $data['string'],
2432                                        'relatives'     => array ($data['relatives'][0])
2433                                )
2434                        );
2435
2436                        if (!$this->acl_check (array(
2437                                'string'        => $p->fake_full_path,
2438                                'relatives'     => array ($p->mask),
2439                                'operation'     => PHPGW_ACL_READ
2440                        ))
2441                        )
2442                        {
2443                                return False;
2444                        }
2445                        return $GLOBALS['phpgw']->db->query("INSERT INTO phpgw_vfs_quota VALUES ('".$data['string']."',".$data['new_quota'].");", __LINE__,__FILE__);
2446                }
2447
2448
2449                /*!
2450                @function checkperms
2451                @abstract Check if $this->working_id has write access to create files in $dir
2452                @discussion Simple call to acl_check
2453                @param string Directory to check access of
2454                @param relatives Relativity array
2455                @result Boolean True/False
2456                */
2457                function checkperms ($data)
2458                {
2459                        if (!is_array ($data))
2460                        {
2461                                $data = array ();
2462                        }
2463
2464                        $default_values = array
2465                                (
2466                                        'relatives'     => array (RELATIVE_CURRENT)
2467                                );
2468
2469                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2470
2471                        $p = $this->path_parts (array(
2472                                        'string'        => $data['string'],
2473                                        'relatives'     => array ($data['relatives'][0])
2474                                )
2475                        );
2476
2477                        if (!$this->acl_check (array(
2478                                        'string'        => $p->fake_full_path,
2479                                        'relatives'     => array ($p->mask),
2480                                        'operation'     => PHPGW_ACL_ADD
2481                                ))
2482                        )
2483                        {
2484                                return False;
2485                        }
2486                        else
2487                        {
2488                                return True;
2489                        }
2490                }
2491
2492                /*
2493                 * See vfs_shared
2494                 * If $data['readlink'] then a readlink is tryed on the real file
2495                 * If $data['file_id'] then the file_id is used instead of a path
2496                 */
2497                function ls ($data)
2498                {
2499                        if (!is_array ($data))
2500                        {
2501                                $data = array ();
2502                        }
2503
2504                        $default_values = array
2505                                (
2506                                        'relatives'     => array (RELATIVE_CURRENT),
2507                                        'checksubdirs'  => True,
2508                                        'mime_type'     => False,
2509                                        'nofiles'       => False,
2510                                        'orderby'       => 'directory'
2511                                );
2512
2513                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2514
2515                        $p = $this->path_parts (array(
2516                                        'string'        => $data['string'],
2517                                        'relatives'     => array ($data['relatives'][0])
2518                                )
2519                        );
2520                        $dir = $p->fake_full_path;
2521
2522
2523                        /* If they pass us a file or 'nofiles' is set, return the info for $dir only */
2524                        if (@$data['file_id']
2525                                || ((($type = $this->file_type (array(
2526                                        'string'        => $dir,
2527                                        'relatives'     => array ($p->mask)
2528                                )) != 'Directory'))
2529                                || ($data['nofiles'])) && !$p->outside
2530                        )
2531                        {
2532                                /* SELECT all, the, attributes */
2533                                $sql = 'SELECT ';
2534
2535                                foreach ($this->attributes as $num => $attribute)
2536                                {
2537                                        if ($num)
2538                                        {
2539                                                $sql .= ', ';
2540                                        }
2541
2542                                        $sql .= $attribute;
2543                                }
2544
2545                                $sql .= " FROM phpgw_vfs WHERE ";
2546                                if (@$data['file_id'])
2547                                {
2548                                        $sql .= 'file_id='.(int)$data['file_id'];
2549                                }
2550                                else
2551                                {
2552                                        $sql .= " directory='".$GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND".
2553                                                " name='".$GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'".
2554                                                $this->extra_sql (array ('query_type' => VFS_SQL_SELECT));
2555                                }
2556                                $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
2557
2558                                $GLOBALS['phpgw']->db->next_record ();
2559                                $record = $GLOBALS['phpgw']->db->Record;
2560
2561                                /* We return an array of one array to maintain the standard */
2562                                $rarray = array ();
2563                                foreach($this->attributes as $attribute)
2564                                {
2565                                        if ($attribute == 'mime_type' && !$record[$attribute])
2566                                        {
2567                                                $db2 = $GLOBALS['phpgw']->db;
2568                                                $record[$attribute] = $this->get_ext_mime_type (array(
2569                                                                'string' => $p->fake_name_clean
2570                                                        )
2571                                                );
2572
2573                                                if($record[$attribute])
2574                                                {
2575                                                        $db2->query ("UPDATE phpgw_vfs SET mime_type='".$record[$attribute]."' WHERE directory='".
2576                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2577                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2578                                                }
2579                                        }
2580
2581                                        $rarray[0][$attribute] = $record[$attribute];
2582                                }
2583                                if ($this->file_actions && @$data['readlink'])  // test if file is a symlink and get it's target
2584                                {
2585                                        $rarray[0]['symlink'] = @readlink($p->real_full_path);
2586                                }
2587
2588                                return $rarray;
2589                        }
2590
2591                        //WIP - this should recurse using the same options the virtual part of ls () does
2592                        /* If $dir is outside the virutal root, we have to check the file system manually */
2593                        if ($p->outside)
2594                        {
2595                                if ($this->file_type (array(
2596                                                'string'        => $p->fake_full_path,
2597                                                'relatives'     => array ($p->mask)
2598                                        )) == 'Directory'
2599                                        && !$data['nofiles']
2600                                )
2601                                {
2602                                        $dir_handle = opendir ($p->real_full_path);
2603                                        while ($filename = readdir ($dir_handle))
2604                                        {
2605                                                if ($filename == '.' || $filename == '..')
2606                                                {
2607                                                        continue;
2608                                                }
2609
2610                                                $rarray[] = $this->get_real_info (array(
2611                                                                'string'        => $p->real_full_path . SEP . $filename,
2612                                                                'relatives'     => array ($p->mask)
2613                                                        )
2614                                                );
2615                                        }
2616                                }
2617                                else
2618                                {
2619                                        $rarray[] = $this->get_real_info (array(
2620                                                        'string'        => $p->real_full_path,
2621                                                        'relatives'     => array ($p->mask)
2622                                                )
2623                                        );
2624                                }
2625
2626                                return $rarray;
2627                        }
2628
2629                        /* $dir's not a file, is inside the virtual root, and they want to check subdirs */
2630                        /* SELECT all, the, attributes FROM phpgw_vfs WHERE file=$dir */
2631                        $sql = 'SELECT ';
2632                        if (!$this->acl_check (array (
2633                                'string' => $p->fake_full_path,
2634                                'relatives' => array ($p->mask),
2635                                'operation' => PHPGW_ACL_PRIVATE)
2636                        ))
2637                        $query_type = " type != 1 AND";
2638                        else
2639                                $query_type = "";
2640
2641                        foreach($this->attributes as $num => $attribute)
2642                        {
2643                                if ($num)
2644                                {
2645                                        $sql .= ", ";
2646                                }
2647
2648                                $sql .= $attribute;
2649                        }
2650
2651                        $dir_clean = $this->clean_string (array ('string' => $dir));
2652                        $sql .= " FROM phpgw_vfs WHERE ".$query_type." directory LIKE '".$GLOBALS['phpgw']->db->db_addslashes($dir_clean)."%'";
2653                        $sql .= $this->extra_sql (array ('query_type' => VFS_SQL_SELECT));
2654
2655                        if ($data['mime_type'])
2656                        {
2657                                $sql .= " AND mime_type='".$data['mime_type']."'";
2658                        }
2659                        if (strlen($data['orderby']) > 0)
2660                                $sql .= ' ORDER BY '.$data['orderby'];
2661                        $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
2662
2663                        $rarray = array ();
2664                        for ($i = 0; $GLOBALS['phpgw']->db->next_record (); $i++)
2665                        {
2666                                $record = $GLOBALS['phpgw']->db->Record;
2667
2668                                /* Further checking on the directory.  This makes sure /home/user/test won't match /home/user/test22 */
2669                                if (@!ereg ("^$dir(/|$)", $record['directory']))
2670                                {
2671                                        continue;
2672                                }
2673
2674                                /* If they want only this directory, then $dir should end without a trailing / */
2675                                if (!$data['checksubdirs'] && ereg ("^$dir/", $record['directory']))
2676                                {
2677                                        continue;
2678                                }
2679
2680                                foreach($this->attributes as $attribute)
2681                                {
2682                                        if ($attribute == 'mime_type' && !$record[$attribute])
2683                                        {
2684                                                $db2 = $GLOBALS['phpgw']->db;
2685                                                $record[$attribute] = $this->get_ext_mime_type (array(
2686                                                                'string'        => $p->fake_name_clean
2687                                                        )
2688                                                );
2689
2690                                                if($record[$attribute])
2691                                                {
2692                                                        $db2->query ("UPDATE phpgw_vfs SET mime_type='".$record[$attribute]."' WHERE directory='".
2693                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2694                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2695                                                }
2696                                        }
2697
2698                                        $rarray[$i][$attribute] = $record[$attribute];
2699                                }
2700                        }
2701
2702                        return $rarray;
2703                }
2704
2705                /*
2706                 * See vfs_shared
2707                 */
2708                function update_real ($data,$recursive = False)
2709                {
2710                        if (!is_array ($data))
2711                        {
2712                                $data = array ();
2713                        }
2714
2715                        $default_values = array
2716                                (
2717                                        'relatives'     => array (RELATIVE_CURRENT)
2718                                );
2719
2720                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2721
2722                        $p = $this->path_parts (array(
2723                                        'string'        => $data['string'],
2724                                        'relatives'     => array ($data['relatives'][0])
2725                                )
2726                        );
2727
2728                        if (file_exists ($p->real_full_path))
2729                        {
2730                                if (is_dir ($p->real_full_path))
2731                                {
2732                                        $dir_handle = opendir ($p->real_full_path);
2733                                        while ($filename = readdir ($dir_handle))
2734                                        {
2735                                                if ($filename == '.' || $filename == '..')
2736                                                {
2737                                                        continue;
2738                                                }
2739
2740                                                $rarray[] = $this->get_real_info (array(
2741                                                                'string'        => $p->fake_full_path . '/' . $filename,
2742                                                                'relatives'     => array (RELATIVE_NONE)
2743                                                        )
2744                                                );
2745                                        }
2746                                }
2747                                else
2748                                {
2749                                        $rarray[] = $this->get_real_info (array(
2750                                                        'string'        => $p->fake_full_path,
2751                                                        'relatives'     => array (RELATIVE_NONE)
2752                                                )
2753                                        );
2754                                }
2755
2756                                if (!is_array ($rarray))
2757                                {
2758                                        $rarray = array ();
2759                                }
2760
2761                                foreach($rarray as $num => $file_array)
2762                                {
2763                                        $p2 = $this->path_parts (array(
2764                                                        'string'        => $file_array['directory'] . '/' . $file_array['name'],
2765                                                        'relatives'     => array (RELATIVE_NONE)
2766                                                )
2767                                        );
2768
2769                                        /* Note the mime_type.  This can be "Directory", which is how we create directories */
2770                                        $set_attributes_array = Array(
2771                                                'size' => $file_array['size'],
2772                                                'mime_type' => $file_array['mime_type']
2773                                        );
2774
2775                                        if (!$this->file_exists (array(
2776                                                        'string'        => $p2->fake_full_path,
2777                                                        'relatives'     => array (RELATIVE_NONE)
2778                                                ))
2779                                        )
2780                                        {
2781                                                $this->touch (array(
2782                                                                'string'        => $p2->fake_full_path,
2783                                                                'relatives'     => array (RELATIVE_NONE)
2784                                                        )
2785                                                );
2786                                        }
2787                                        $this->set_attributes (array(
2788                                                        'string'        => $p2->fake_full_path,
2789                                                        'relatives'     => array (RELATIVE_NONE),
2790                                                        'attributes'    => $set_attributes_array
2791                                                )
2792                                        );
2793                                        if ($recursive && $file_array['mime_type'] == 'Directory')
2794                                        {
2795                                                $dir_data = $data;
2796                                                $dir_data['string'] = $file_array['directory'] . '/' . $file_array['name'];
2797                                                $this->update_real($dir_data,$recursive);
2798                                        }
2799                                }
2800                        }
2801                }
2802
2803                /* Helper functions */
2804
2805                /* This fetchs all available file system information for string (not using the database) */
2806                function get_real_info ($data)
2807                {
2808                        if (!is_array ($data))
2809                        {
2810                                $data = array ();
2811                        }
2812
2813                        $default_values = array
2814                                (
2815                                        'relatives'     => array (RELATIVE_CURRENT)
2816                                );
2817
2818                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2819
2820                        $p = $this->path_parts (array(
2821                                        'string'        => $data['string'],
2822                                        'relatives'     => array ($data['relatives'][0])
2823                                )
2824                        );
2825
2826                        if (is_dir ($p->real_full_path))
2827                        {
2828                                $mime_type = 'Directory';
2829                        }
2830                        else
2831                        {
2832                                $mime_type = $this->get_ext_mime_type (array(
2833                                                'string'        => $p->fake_name
2834                                        )
2835                                );
2836
2837                                if($mime_type)
2838                                {
2839                                        $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET mime_type='".$mime_type."' WHERE directory='".
2840                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2841                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" .
2842                                                $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2843                                }
2844                        }
2845
2846                        $size = filesize ($p->real_full_path);
2847                        $rarray = array(
2848                                'directory' => $p->fake_leading_dirs,
2849                                'name' => $p->fake_name,
2850                                'size' => $size,
2851                                'mime_type' => $mime_type
2852                        );
2853
2854                        return ($rarray);
2855                }
2856        }
2857?>
Note: See TracBrowser for help on using the repository browser.