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

Revision 1741, 69.4 KB checked in by amuller, 14 years ago (diff)

Ticket #597 - Melhorias 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                                if ($fp = fopen ($p->real_full_path, 'rb'))
824                                {
825                                        for ($i=0; $i<=filesize($p->real_full_path); $i+=10240)
826                                        {
827                                                echo fread($fp, $i);
828                                                flush();
829                                                ob_clean();
830                                        }
831                                        fclose ($fp);
832                                }
833                                else
834                                {
835                                        return False;
836                                }
837                        return True;
838                }
839
840                /*
841                 * See vfs_shared
842                 */
843                function read ($data)
844                {
845                        if (!is_array ($data))
846                        {
847                                $data = array ();
848                        }
849
850                        $default_values = array
851                                (
852                                        'relatives'     => array (RELATIVE_CURRENT)
853                                );
854
855                        $data = array_merge ($this->default_values ($data, $default_values), $data);
856
857                        $p = $this->path_parts (array(
858                                        'string'        => $data['string'],
859                                        'relatives'     => array ($data['relatives'][0])
860                                )
861                        );
862
863                        if (!$this->acl_check (array(
864                                        'string'        => $p->fake_full_path,
865                                        'relatives'     => array ($p->mask),
866                                        'operation'     => PHPGW_ACL_READ
867                                ))
868                        )
869                        {
870                                return False;
871                        }
872
873                        $conf = CreateObject('phpgwapi.config', 'phpgwapi');
874                        $conf->read_repository();
875                        if ($this->file_actions || $p->outside)
876                        {
877                                if ($fp = fopen ($p->real_full_path, 'rb'))
878                                {
879                                        $contents = fread ($fp, filesize ($p->real_full_path));
880                                        fclose ($fp);
881                                }
882                                else
883                                {
884                                        $contents = False;
885                                }
886                        }
887                        else
888                        {
889                                $ls_array = $this->ls (array(
890                                                'string'        => $p->fake_full_path,
891                                                'relatives'     => array ($p->mask),
892                                        )
893                                );
894
895                                $contents = $ls_array[0]['content'];
896                        }
897
898                        return $contents;
899                }
900
901                /*
902                 * See vfs_shared
903                 */
904                function write ($data)
905                {
906                        if (!is_array ($data))
907                        {
908                                $data = array ();
909                        }
910
911                        $path = explode('/',$data['string']);
912                        $quota = $this->get_quota(array('string' => '/'.$path[1].'/'.$path[2]));
913                        if ($quota > 0 && $this->get_size('/'.$path[1].'/'.$path[2]) >= $quota * 1024 * 1024)
914                                return false;
915
916
917                        $default_values = array
918                                (
919                                        'relatives'     => array (RELATIVE_CURRENT),
920                                        'content'       => ''
921                                );
922
923                        $data = array_merge ($this->default_values ($data, $default_values), $data);
924
925                        $p = $this->path_parts (array(
926                                        'string'        => $data['string'],
927                                        'relatives'     => array ($data['relatives'][0])
928                                )
929                        );
930
931                        if ($this->file_exists (array (
932                                        'string'        => $p->fake_full_path,
933                                        'relatives'     => array ($p->mask)
934                                ))
935                        )
936                        {
937                                $acl_operation = PHPGW_ACL_EDIT;
938                                $journal_operation = VFS_OPERATION_EDITED;
939                        }
940                        else
941                        {
942                                $acl_operation = PHPGW_ACL_ADD;
943                        }
944                        umask(0177);
945
946                        /*
947                           If 'string' doesn't exist, touch () creates both the file and the database entry
948                           If 'string' does exist, touch () sets the modification time and modified by
949                        */
950                        $this->touch (array(
951                                        'string'        => $p->fake_full_path,
952                                        'relatives'     => array ($p->mask)
953                                )
954                        );
955
956                        $conf = CreateObject('phpgwapi.config', 'phpgwapi');
957                        $conf->read_repository();
958                        if ($this->file_actions)
959                        {
960                                if ($fp = fopen ($p->real_full_path, 'wb'))
961                                {
962                                        fwrite ($fp, $data['content']);
963                                        fclose ($fp);
964                                        $write_ok = 1;
965                                }
966                        }
967
968                        if ($write_ok || !$this->file_actions)
969                        {
970                                if ($this->file_actions)
971                                {
972                                        $set_attributes_array = array(
973                                                'size' => filesize ($p->real_full_path)
974                                        );
975                                }
976                                else
977                                {
978                                        $set_attributes_array = array (
979                                                'size'  => strlen ($data['content']),
980                                                'content'       => $data['content']
981                                        );
982                                }
983
984
985                                $this->set_attributes (array
986                                        (
987                                                'string'        => $p->fake_full_path,
988                                                'relatives'     => array ($p->mask),
989                                                'attributes'    => $set_attributes_array
990                                        )
991                                );
992
993                                if ($journal_operation)
994                                {
995                                        $this->add_journal (array(
996                                                        'string'        => $p->fake_full_path,
997                                                        'relatives'     => array ($p->mask),
998                                                        'operation'     => $journal_operation
999                                                )
1000                                        );
1001                                }
1002
1003                                return True;
1004                        }
1005                        else
1006                        {
1007                                return False;
1008                        }
1009                }
1010
1011                /*
1012                 * See vfs_shared
1013                 */
1014                function touch ($data)
1015                {
1016                        if (!is_array ($data))
1017                        {
1018                                $data = array ();
1019                        }
1020
1021                        $default_values = array
1022                                (
1023                                        'relatives'     => array (RELATIVE_CURRENT)
1024                                );
1025
1026                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1027
1028                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1029                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
1030
1031                        $p = $this->path_parts (array(
1032                                        'string'        => $data['string'],
1033                                        'relatives'     => array ($data['relatives'][0])
1034                                )
1035                        );
1036
1037                        umask (0177);
1038
1039                        if ($this->file_actions)
1040                        {
1041                                /*
1042                                   PHP's touch function will automatically decide whether to
1043                                   create the file or set the modification time
1044                                */
1045                                $rr = @touch ($p->real_full_path);
1046
1047                                if ($p->outside)
1048                                {
1049                                        return $rr;
1050                                }
1051                        }
1052
1053                        /* We, however, have to decide this ourselves */
1054                        if ($this->file_exists (array(
1055                                        'string'        => $p->fake_full_path,
1056                                        'relatives'     => array ($p->mask)
1057                                ))
1058                        )
1059                        {
1060                                if (!$this->acl_check (array(
1061                                                'string'        => $p->fake_full_path,
1062                                                'relatives'     => array ($p->mask),
1063                                                'operation'     => PHPGW_ACL_EDIT
1064                                        )))
1065                                {
1066                                        return False;
1067                                }
1068
1069                                $vr = $this->set_attributes (array(
1070                                                'string'        => $p->fake_full_path,
1071                                                'relatives'     => array ($p->mask),
1072                                                'attributes'    => array(
1073                                                                        'modifiedby_id' => $account_id,
1074                                                                        'modified' => $this->now
1075                                                                )
1076                                                )
1077                                        );
1078                        }
1079                        else
1080                        {
1081                                if (!$this->acl_check (array(
1082                                                'string'        => $p->fake_full_path,
1083                                                'relatives'     => array ($p->mask),
1084                                                'operation'     => PHPGW_ACL_ADD
1085                                        ))
1086                                )
1087                                {
1088                                        return False;
1089                                }
1090
1091                                $query = $GLOBALS['phpgw']->db->query ("INSERT INTO phpgw_vfs (owner_id, directory, name) VALUES ($this->working_id, '".
1092                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."', '".
1093                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."')", __LINE__, __FILE__);
1094
1095                                $this->set_attributes(array(
1096                                        'string'        => $p->fake_full_path,
1097                                        'relatives'     => array ($p->mask),
1098                                        'attributes'    => array (
1099                                                                'createdby_id' => $account_id,
1100                                                                'created' => $this->now,
1101                                                                'size' => 0,
1102                                                                'deleteable' => 'Y',
1103                                                                'app' => $currentapp
1104                                                        )
1105                                        )
1106                                );
1107                                $this->correct_attributes (array(
1108                                                'string'        => $p->fake_full_path,
1109                                                'relatives'     => array ($p->mask)
1110                                        )
1111                                );
1112       
1113                                $this->add_journal (array(
1114                                                'string'        => $p->fake_full_path,
1115                                                'relatives'     => array ($p->mask),
1116                                                'operation'     => VFS_OPERATION_CREATED
1117                                        )
1118                                );
1119                        }
1120
1121                        if ($rr || $vr || $query)
1122                        {
1123                                return True;
1124                        }
1125                        else
1126                        {
1127                                return False;
1128                        }
1129                }
1130
1131                /*
1132                 * See vfs_shared
1133                 * If $data['symlink'] the file is symlinked instead of copied
1134                 */
1135                function cp ($data)
1136                {
1137                        if (!is_array ($data))
1138                        {
1139                                $data = array ();
1140                        }
1141                        if ($data['relatives'][1] == RELATIVE_NONE)
1142                                $path = explode(SEP,$data['to']);
1143                        else
1144                                $path = explode(SEP,$this->my_home);
1145                        $quota = $this->get_quota(array('string' => SEP.$path[1].SEP.$path[2]));
1146                        $size = $this->get_size(array('string' => SEP.$path[1].SEP.$path[2], 'relatives' => $data['relatives'][1]));
1147
1148                        if ($quota > 0 && ($quota * 1024 * 1024) < $size)
1149                                return false;
1150
1151                        $default_values = array
1152                                (
1153                                        'relatives'     => array (RELATIVE_CURRENT, RELATIVE_CURRENT)
1154                                );
1155
1156                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1157
1158                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1159
1160                        $f = $this->path_parts (array(
1161                                        'string'        => $data['from'],
1162                                        'relatives'     => array ($data['relatives'][0])
1163                                )
1164                        );
1165
1166                        $t = $this->path_parts (array(
1167                                        'string'        => $data['to'],
1168                                        'relatives'     => array ($data['relatives'][1])
1169                                )
1170                        );
1171
1172                        if (!$this->acl_check (array(
1173                                        'string'        => $f->fake_full_path,
1174                                        'relatives'     => array ($f->mask),
1175                                        'operation'     => PHPGW_ACL_READ
1176                                ))
1177                        )
1178                        {
1179                                return False;
1180                        }
1181
1182                        if ($exists = $this->file_exists (array(
1183                                        'string'        => $t->fake_full_path,
1184                                        'relatives'     => array ($t->mask)
1185                                ))
1186                        )
1187                        {
1188                                if (!$this->acl_check (array(
1189                                                'string'        => $t->fake_full_path,
1190                                                'relatives'     => array ($t->mask),
1191                                                'operation'     => PHPGW_ACL_EDIT
1192                                        ))
1193                                )
1194                                {
1195                                        return False;
1196                                }
1197                        }
1198                        else
1199                        {
1200                                if (!$this->acl_check (array(
1201                                                'string'        => $t->fake_full_path,
1202                                                'relatives'     => array ($t->mask),
1203                                                'operation'     => PHPGW_ACL_ADD
1204                                        ))
1205                                )
1206                                {
1207                                        return False;
1208                                }
1209                        }
1210
1211                        umask(0177);
1212
1213                        if ($this->file_type (array(
1214                                        'string'        => $f->fake_full_path,
1215                                        'relatives'     => array ($f->mask)
1216                                )) != 'Directory'
1217                        )
1218                        {
1219                                if ($this->file_actions)
1220                                {
1221                                        if (@$data['symlink'])
1222                                        {
1223                                                if ($exists)
1224                                                {
1225                                                        @unlink($t->real_full_path);
1226                                                }
1227                                                if (!symlink($f->real_full_path, $t->real_full_path))
1228                                                {
1229                                                        return False;
1230                                                }
1231                                        }
1232                                        elseif (!copy ($f->real_full_path, $t->real_full_path))
1233                                        {
1234                                                return False;
1235                                        }
1236
1237                                        $size = filesize ($t->real_full_path);
1238                                }
1239                                else
1240                                {
1241                                        $content = $this->read (array(
1242                                                        'string'        => $f->fake_full_path,
1243                                                        'relatives'     => array ($f->mask)
1244                                                )
1245                                        );
1246
1247                                        $size = strlen ($content);
1248                                }
1249
1250                                if ($t->outside)
1251                                {
1252                                        return True;
1253                                }
1254
1255                                $ls_array = $this->ls (array(
1256                                                'string'        => $f->fake_full_path,
1257                                                'relatives'     => array ($f->mask),
1258                                                'checksubdirs'  => False,
1259                                                'mime_type'     => False,
1260                                                'nofiles'       => True
1261                                        )
1262                                );
1263                                $record = $ls_array[0];
1264
1265                                if ($this->file_exists (array(
1266                                                'string'        => $data['to'],
1267                                                'relatives'     => array ($data['relatives'][1])
1268                                        ))
1269                                )
1270                                {
1271                                        $query = $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET owner_id='$this->working_id', directory='".
1272                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_leading_dirs_clean)."', name='".
1273                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_name_clean)."' WHERE owner_id='$this->working_id' AND directory='".
1274                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_leading_dirs_clean)."' AND name='".
1275                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_name_clean)."'" . $this->extra_sql (VFS_SQL_UPDATE), __LINE__, __FILE__);
1276
1277                                        $set_attributes_array = array (
1278                                                'createdby_id' => $account_id,
1279                                                'created' => $this->now,
1280                                                'size' => $size,
1281                                                'mime_type' => $record['mime_type'],
1282                                                'deleteable' => $record['deleteable'],
1283                                                'comment' => $record['comment'],
1284                                                'app' => $record['app']
1285                                        );
1286
1287                                        if (!$this->file_actions)
1288                                        {
1289                                                $set_attributes_array['content'] = $content;
1290                                        }
1291
1292                                        $this->set_attributes(array(
1293                                                'string'        => $t->fake_full_path,
1294                                                'relatives'     => array ($t->mask),
1295                                                'attributes'    => $set_attributes_array
1296                                                )
1297                                        );
1298
1299                                        $this->add_journal (array(
1300                                                        'string'        => $t->fake_full_path,
1301                                                        'relatives'     => array ($t->mask),
1302                                                        'operation'     => VFS_OPERATION_EDITED
1303                                                )
1304                                        );
1305                                }
1306                                else
1307                                {
1308                                        $this->touch (array(
1309                                                        'string'        => $t->fake_full_path,
1310                                                        'relatives'     => array ($t->mask)
1311                                                )
1312                                        );
1313
1314                                        $set_attributes_array = array (
1315                                                'createdby_id' => $account_id,
1316                                                'created' => $this->now,
1317                                                'size' => $size,
1318                                                'mime_type' => $record['mime_type'],
1319                                                'deleteable' => $record['deleteable'],
1320                                                'comment' => $record['comment'],
1321                                                'app' => $record['app']
1322                                        );
1323
1324                                        if (!$this->file_actions)
1325                                        {
1326                                                $set_attributes_array['content'] = $content;
1327                                        }
1328
1329                                        $this->set_attributes(array(
1330                                                        'string'        => $t->fake_full_path,
1331                                                        'relatives'     => array ($t->mask),
1332                                                        'attributes'    => $set_attributes_array
1333                                                )
1334                                        );
1335                                }
1336                                $this->correct_attributes (array(
1337                                                'string'        => $t->fake_full_path,
1338                                                'relatives'     => array ($t->mask)
1339                                        )
1340                                );
1341                        }
1342                        else    /* It's a directory */
1343                        {
1344                                /* First, make the initial directory */
1345                                $this->mkdir (array(
1346                                                'string'        => $data['to'],
1347                                                'relatives'     => array ($data['relatives'][1])
1348                                        )
1349                                );
1350
1351                                /* Next, we create all the directories below the initial directory */
1352                                foreach($this->ls (array(
1353                                                'string'        => $f->fake_full_path,
1354                                                'relatives'     => array ($f->mask),
1355                                                'checksubdirs'  => True,
1356                                                'mime_type'     => 'Directory'
1357                                        )) as $entry)
1358                                {
1359                                        $newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry['directory']);
1360                                        $this->mkdir (array(
1361                                                        'string'        => $newdir.'/'.$entry['name'],
1362                                                        'relatives'     => array ($t->mask)
1363                                                )
1364                                        );
1365                                }
1366
1367                                /* Lastly, we copy the files over */
1368                                foreach($this->ls (array(
1369                                                'string'        => $f->fake_full_path,
1370                                                'relatives'     => array ($f->mask)
1371                                        )) as $entry)
1372                                {
1373                                        if ($entry['mime_type'] == 'Directory')
1374                                        {
1375                                                continue;
1376                                        }
1377
1378                                        $newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry['directory']);
1379                                        $this->cp (array(
1380                                                        'from'  => "$entry[directory]/$entry[name]",
1381                                                        'to'    => "$newdir/$entry[name]",
1382                                                        'relatives'     => array ($f->mask, $t->mask)
1383                                                )
1384                                        );
1385                                }
1386                        }
1387
1388                        if (!$f->outside)
1389                        {
1390                                $this->add_journal (array(
1391                                                'string'        => $f->fake_full_path,
1392                                                'relatives'     => array ($f->mask),
1393                                                'operation'     => VFS_OPERATION_COPIED,
1394                                                'state_one'     => NULL,
1395                                                'state_two'     => $t->fake_full_path
1396                                        )
1397                                );
1398                        }
1399
1400                        return True;
1401                }
1402
1403                /*
1404                 * See vfs_shared
1405                 */
1406                function mv ($data)
1407                {
1408                        if (!is_array ($data))
1409                        {
1410                                $data = array ();
1411                        }
1412                        if ($data['relatives'][1] == RELATIVE_NONE)
1413                        {
1414                                $path = explode('/',$data['to']);
1415                                $quota = $this->get_quota(array('string' => '/'.$path[1].'/'.$path[2]));
1416                                $size = $this->get_size(array('string' => '/'.$path[1].'/'.$path[2], 'relatives' => $data['relatives'][1]));
1417                        }
1418                        else
1419                        {
1420                                $quota = $this->get_quota(array('string' => $this->my_home));
1421                                $size = $this->get_size(array('string' => $this->my_home, 'relatives' => $data['relatives'][1]));
1422                        }
1423                        if ($quota > 0 && $size >= $quota * 1024 * 1024)
1424                                return false;
1425
1426
1427                        $default_values = array
1428                                (
1429                                        'relatives'     => array (RELATIVE_CURRENT, RELATIVE_CURRENT)
1430                                );
1431
1432                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1433
1434                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1435
1436                        $f = $this->path_parts (array(
1437                                        'string'        => $data['from'],
1438                                        'relatives'     => array ($data['relatives'][0])
1439                                )
1440                        );
1441
1442                        $t = $this->path_parts (array(
1443                                        'string'        => $data['to'],
1444                                        'relatives'     => array ($data['relatives'][1])
1445                                )
1446                        );
1447
1448                        if (!$this->acl_check (array(
1449                                        'string'        => $data['to'],
1450                                        'relatives'     => array ($t->mask),
1451                                        'operation'     => PHPGW_ACL_ADD
1452                                ))
1453                        )
1454                        {
1455                                return False;
1456                        }
1457
1458                        if ($this->file_exists (array(
1459                                        'string'        => $t->fake_full_path,
1460                                        'relatives'     => array ($t->mask)
1461                                ))
1462                        )
1463                        {
1464                                if (!$this->acl_check (array(
1465                                                'string'        => $data['to'],
1466                                                'relatives'     => array ($t->mask),
1467                                                'operation'     => PHPGW_ACL_EDIT
1468                                        ))
1469                                )
1470                                {
1471                                        return False;
1472                                }
1473                        }
1474
1475                        umask (0177);
1476
1477                        /* We can't move directories into themselves */
1478                        if (($this->file_type (array(
1479                                        'string'        => $f->fake_full_path,
1480                                        'relatives'     => array ($f->mask)
1481                                ) == 'Directory'))
1482                                && ereg ("^$f->fake_full_path", $t->fake_full_path)
1483                        )
1484                        {
1485                                if (($t->fake_full_path == $f->fake_full_path) || substr ($t->fake_full_path, strlen ($f->fake_full_path), 1) == '/')
1486                                {
1487                                        return False;
1488                                }
1489                        }
1490
1491                        if ($this->file_exists (array(
1492                                        'string'        => $f->fake_full_path,
1493                                        'relatives'     => array ($f->mask)
1494                                ))
1495                        )
1496                        {
1497                                /* We get the listing now, because it will change after we update the database */
1498                                $ls = $this->ls (array(
1499                                                'string'        => $f->fake_full_path,
1500                                                'relatives'     => array ($f->mask)
1501                                        )
1502                                );
1503
1504                                if ($this->file_exists (array(
1505                                                'string'        => $t->fake_full_path,
1506                                                'relatives'     => array ($t->mask)
1507                                        ))
1508                                )
1509                                {
1510                                        $this->rm (array(
1511                                                        'string'        => $t->fake_full_path,
1512                                                        'relatives'     => array ($t->mask)
1513                                                )
1514                                        );
1515                                }
1516
1517                                /*
1518                                   We add the journal entry now, before we delete.  This way the mime_type
1519                                   field will be updated to 'journal-deleted' when the file is actually deleted
1520                                */
1521                                if (!$f->outside)
1522                                {
1523                                        $this->add_journal (array(
1524                                                        'string'        => $f->fake_full_path,
1525                                                        'relatives'     => array ($f->mask),
1526                                                        'operation'     => VFS_OPERATION_MOVED,
1527                                                        'state_one'     => $f->fake_full_path,
1528                                                        'state_two'     => $t->fake_full_path
1529                                                )
1530                                        );
1531                                }
1532
1533                                /*
1534                                   If the from file is outside, it won't have a database entry,
1535                                   so we have to touch it and find the size
1536                                */
1537                                if ($f->outside)
1538                                {
1539                                        $size = filesize ($f->real_full_path);
1540
1541                                        $this->touch (array(
1542                                                        'string'        => $t->fake_full_path,
1543                                                        'relatives'     => array ($t->mask)
1544                                                )
1545                                        );
1546                                        $query = $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET size=$size WHERE directory='".
1547                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_leading_dirs_clean)."' AND name='".
1548                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_UPDATE)), __LINE__, __FILE__);
1549                                }
1550                                elseif (!$t->outside)
1551                                {
1552                                        $query = $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET name='".
1553                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_name_clean)."', directory='".
1554                                                $GLOBALS['phpgw']->db->db_addslashes($t->fake_leading_dirs_clean)."' WHERE directory='".
1555                                                $GLOBALS['phpgw']->db->db_addslashes($f->fake_leading_dirs_clean)."' AND name='".
1556                                                $GLOBALS['phpgw']->db->db_addslashes($f->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_UPDATE)), __LINE__, __FILE__);
1557                                }
1558
1559                                $this->set_attributes(array(
1560                                                'string'        => $t->fake_full_path,
1561                                                'relatives'     => array ($t->mask),
1562                                                'attributes'    => array (
1563                                                                        'modifiedby_id' => $account_id,
1564                                                                        'modified' => $this->now
1565                                                                )
1566                                        )
1567                                );
1568
1569                                $this->correct_attributes (array(
1570                                                'string'        => $t->fake_full_path,
1571                                                'relatives'     => array ($t->mask)
1572                                        )
1573                                );
1574
1575                                if ($this->file_actions)
1576                                {
1577                                        $rr = rename ($f->real_full_path, $t->real_full_path);
1578                                }
1579
1580                                /*
1581                                   This removes the original entry from the database
1582                                   The actual file is already deleted because of the rename () above
1583                                */
1584                                if ($t->outside)
1585                                {
1586                                        $this->rm (array(
1587                                                        'string'        => $f->fake_full_path,
1588                                                        'relatives'     => $f->mask
1589                                                )
1590                                        );
1591                                }
1592                        }
1593                        else
1594                        {
1595                                return False;
1596                        }
1597
1598                        if ($this->file_type (array(
1599                                        'string'        => $t->fake_full_path,
1600                                        'relatives'     => array ($t->mask)
1601                                )) == 'Directory'
1602                        )
1603                        {
1604                                /* We got $ls from above, before we renamed the directory */
1605                                foreach ($ls as $entry)
1606                                {
1607                                        $newdir = ereg_replace ("^$f->fake_full_path", $t->fake_full_path, $entry['directory']);
1608                                        $newdir_clean = $this->clean_string (array ('string' => $newdir));
1609
1610                                        $query = $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET directory='".
1611                                                $GLOBALS['phpgw']->db->db_addslashes($newdir_clean)."' WHERE file_id='$entry[file_id]'" .
1612                                                $this->extra_sql (array ('query_type' => VFS_SQL_UPDATE)), __LINE__, __FILE__);
1613                                        $this->correct_attributes (array(
1614                                                        'string'        => "$newdir/$entry[name]",
1615                                                        'relatives'     => array ($t->mask)
1616                                                )
1617                                        );
1618                                }
1619                        }
1620
1621                        $this->add_journal (array(
1622                                        'string'        => $t->fake_full_path,
1623                                        'relatives'     => array ($t->mask),
1624                                        'operation'     => VFS_OPERATION_MOVED,
1625                                        'state_one'     => $f->fake_full_path,
1626                                        'state_two'     => $t->fake_full_path
1627                                )
1628                        );
1629
1630                        return True;
1631                }
1632
1633                /*
1634                 * See vfs_shared
1635                 */
1636                function rm ($data)
1637                {
1638                        if (!is_array ($data))
1639                        {
1640                                $data = array ();
1641                        }
1642
1643                        $default_values = array
1644                                (
1645                                        'relatives'     => array (RELATIVE_CURRENT)
1646                                );
1647
1648                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1649
1650                        $p = $this->path_parts (array(
1651                                        'string'        => $data['string'],
1652                                        'relatives'     => array ($data['relatives'][0])
1653                                )
1654                        );
1655                        if (!$this->file_exists (array(
1656                                        'string'        => $data['string'],
1657                                        'relatives'     => array ($data['relatives'][0])
1658                                ))
1659                        )
1660                        {
1661                                if ($this->file_actions)
1662                                {
1663                                        $rr = unlink ($p->real_full_path);
1664                                }
1665                                else
1666                                {
1667                                        $rr = True;
1668                                }
1669
1670                                if ($rr)
1671                                {
1672                                        return True;
1673                                }
1674                                else
1675                                {
1676                                        return False;
1677                                }
1678                        }
1679
1680                        if ($this->file_type (array(
1681                                        'string'        => $data['string'],
1682                                        'relatives'     => array ($data['relatives'][0])
1683                                )) != 'Directory'
1684                        )
1685                        {
1686                                $this->add_journal (array(
1687                                                'string'        => $p->fake_full_path,
1688                                                'relatives'     => array ($p->mask),
1689                                                'operation'     => VFS_OPERATION_DELETED
1690                                        )
1691                                );
1692
1693                                $query = $GLOBALS['phpgw']->db->query ("DELETE FROM phpgw_vfs WHERE directory='".
1694                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
1695                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'".$this->extra_sql (array ('query_type' => VFS_SQL_DELETE)), __LINE__, __FILE__);
1696
1697                                if ($this->file_actions)
1698                                {
1699                                        $rr = unlink ($p->real_full_path);
1700                                }
1701                                else
1702                                {
1703                                        $rr = True;
1704                                }
1705
1706                                if ($query || $rr)
1707                                {
1708                                        return True;
1709                                }
1710                                else
1711                                {
1712                                        return False;
1713                                }
1714                        }
1715                        else
1716                        {
1717                                $ls = $this->ls (array(
1718                                                'string'        => $p->fake_full_path,
1719                                                'relatives'     => array ($p->mask)
1720                                        )
1721                                );
1722
1723                                /* First, we cycle through the entries and delete the files */
1724                                foreach($ls as $entry)
1725                                {
1726                                        if ($entry['mime_type'] == 'Directory')
1727                                        {
1728                                                continue;
1729                                        }
1730
1731                                        $this->rm (array(
1732                                                        'string'        => "$entry[directory]/$entry[name]",
1733                                                        'relatives'     => array ($p->mask)
1734                                                )
1735                                        );
1736                                }
1737
1738                                /* Now we cycle through again and delete the directories */
1739                                foreach ($ls as $entry)
1740                                {
1741                                        if ($entry['mime_type'] != 'Directory')
1742                                        {
1743                                                continue;
1744                                        }
1745
1746                                        /* Only the best in confusing recursion */
1747                                        $this->rm (array(
1748                                                        'string'        => "$entry[directory]/$entry[name]",
1749                                                        'relatives'     => array ($p->mask)
1750                                                )
1751                                        );
1752                                }
1753
1754                                /* If the directory is linked, we delete the placeholder directory */
1755                                $ls_array = $this->ls (array(
1756                                                'string'        => $p->fake_full_path,
1757                                                'relatives'     => array ($p->mask),
1758                                                'checksubdirs'  => False,
1759                                                'mime_type'     => False,
1760                                                'nofiles'       => True
1761                                        )
1762                                );
1763                                $link_info = $ls_array[0];
1764
1765                                if ($link_info['link_directory'] && $link_info['link_name'])
1766                                {
1767                                        $path = $this->path_parts (array(
1768                                                        'string'        => $link_info['directory'] . '/' . $link_info['name'],
1769                                                        'relatives'     => array ($p->mask),
1770                                                        'nolinks'       => True
1771                                                )
1772                                        );
1773
1774                                        if ($this->file_actions)
1775                                        {
1776                                                rmdir ($path->real_full_path);
1777                                        }
1778                                }
1779
1780                                /* Last, we delete the directory itself */
1781                                $this->add_journal (array(
1782                                                'string'        => $p->fake_full_path,
1783                                                'relatives'     => array ($p->mask),
1784                                                'operaton'      => VFS_OPERATION_DELETED
1785                                        )
1786                                );
1787
1788                                $query = $GLOBALS['phpgw']->db->query ("DELETE FROM phpgw_vfs WHERE directory='".
1789                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
1790                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" .
1791                                        $this->extra_sql (array ('query_type' => VFS_SQL_DELETE)), __LINE__, __FILE__);
1792
1793                                if ($this->file_actions)
1794                                {
1795                                        rmdir ($p->real_full_path);
1796                                }
1797
1798                                return True;
1799                        }
1800                }
1801
1802                /*
1803                 * See vfs_shared
1804                 */
1805                function mkdir ($data)
1806                {
1807                        if (!is_array ($data))
1808                        {
1809                                $data = array ();
1810                        }
1811
1812                        $default_values = array
1813                                (
1814                                        'relatives'     => array (RELATIVE_CURRENT)
1815                                );
1816
1817                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1818
1819                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1820                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
1821
1822                        $p = $this->path_parts (array(
1823                                        'string'        => $data['string'],
1824                                        'relatives'     => array ($data['relatives'][0])
1825                                )
1826                        );
1827
1828                        if (!$this->acl_check (array(
1829                                        'string'        => $p->fake_full_path,
1830                                        'relatives'     => array ($p->mask),
1831                                        'operation'     => PHPGW_ACL_ADD)
1832                                )
1833                        )
1834                        {
1835                                return False;
1836                        }
1837
1838                        /* We don't allow /'s in dir names, of course */
1839                        if (ereg ("/", $p->fake_name))
1840                        {
1841                                return False;
1842                        }
1843
1844                        umask (077);
1845
1846                        if ($this->file_actions)
1847                        {
1848                                if (!@is_dir($p->real_leading_dirs_clean))      // eg. /home or /group does not exist
1849                                {
1850                                        if (!@mkdir($p->real_leading_dirs_clean,0770))  // ==> create it
1851                                        {
1852                                                return False;
1853                                        }
1854                                }
1855                                if (@is_dir($p->real_full_path))        // directory already exists
1856                                {
1857                                        $this->update_real($data,True);         // update its contents
1858                                }
1859                                elseif (!@mkdir ($p->real_full_path, 0770))
1860                                {
1861                                        return False;
1862                                }
1863                        }
1864
1865                        if (!$this->file_exists (array(
1866                                        'string'        => $p->fake_full_path,
1867                                        'relatives'     => array ($p->mask)
1868                                ))
1869                        )
1870                        {
1871                                $query = $GLOBALS['phpgw']->db->query ("INSERT INTO phpgw_vfs (owner_id, name, directory) VALUES ($this->working_id, '".
1872                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."', '".
1873                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."')", __LINE__, __FILE__);
1874       
1875                                $this->set_attributes(array(
1876                                        'string'        => $p->fake_full_path,
1877                                        'relatives'     => array ($p->mask),
1878                                        'attributes'    => array (
1879                                                                'createdby_id' => $account_id,
1880                                                                'size' => 4096,
1881                                                                'mime_type' => 'Directory',
1882                                                                'created' => $this->now,
1883                                                                'deleteable' => 'Y',
1884                                                                'app' => $currentapp
1885                                                        )
1886                                        )
1887                                );
1888
1889                                $this->correct_attributes (array(
1890                                                'string'        => $p->fake_full_path,
1891                                                'relatives'     => array ($p->mask)
1892                                        )
1893                                );
1894
1895                                $this->add_journal (array(
1896                                                'string'        => $p->fake_full_path,
1897                                                'relatives'     => array ($p->mask),
1898                                                'operation'     => VFS_OPERATION_CREATED
1899                                        )
1900                                );
1901                        }
1902                        else
1903                        {
1904                                return False;
1905                        }
1906
1907                        return True;
1908                }
1909
1910                /*
1911                 * See vfs_shared
1912                 */
1913                function make_link ($data)
1914                {
1915                        if (!is_array ($data))
1916                        {
1917                                $data = array ();
1918                        }
1919
1920                        $default_values = array
1921                                (
1922                                        'relatives'     => array (RELATIVE_CURRENT, RELATIVE_CURRENT)
1923                                );
1924
1925                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1926
1927                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1928                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
1929
1930                        $vp = $this->path_parts (array(
1931                                        'string'        => $data['vdir'],
1932                                        'relatives'     => array ($data['relatives'][0])
1933                                )
1934                        );
1935
1936                        $rp = $this->path_parts (array(
1937                                        'string'        => $data['rdir'],
1938                                        'relatives'     => array ($data['relatives'][1])
1939                                )
1940                        );
1941
1942                        if (!$this->acl_check (array(
1943                                        'string'        => $vp->fake_full_path,
1944                                        'relatives'     => array ($vp->mask),
1945                                        'operation'     => PHPGW_ACL_ADD
1946                                ))
1947                        )
1948                        {
1949                                return False;
1950                        }
1951
1952                        if ((!$this->file_exists (array(
1953                                        'string'        => $rp->real_full_path,
1954                                        'relatives'     => array ($rp->mask)
1955                                )))
1956                                && !mkdir ($rp->real_full_path, 0770))
1957                        {
1958                                return False;
1959                        }
1960
1961                        if (!$this->mkdir (array(
1962                                        'string'        => $vp->fake_full_path,
1963                                        'relatives'     => array ($vp->mask)
1964                                ))
1965                        )
1966                        {
1967                                return False;
1968                        }
1969
1970                        $size = $this->get_size (array(
1971                                        'string'        => $rp->real_full_path,
1972                                        'relatives'     => array ($rp->mask)
1973                                )
1974                        );
1975
1976                        $this->set_attributes(array(
1977                                        'string'        => $vp->fake_full_path,
1978                                        'relatives'     => array ($vp->mask),
1979                                        'attributes'    => array (
1980                                                                'link_directory' => $rp->real_leading_dirs,
1981                                                                'link_name' => $rp->real_name,
1982                                                                'size' => $size
1983                                                        )
1984                                )
1985                        );
1986
1987                        $this->correct_attributes (array(
1988                                        'string'        => $vp->fake_full_path,
1989                                        'relatives'     => array ($vp->mask)
1990                                )
1991                        );
1992
1993                        return True;
1994                }
1995
1996                /*
1997                 * See vfs_shared
1998                 */
1999                function set_attributes ($data)
2000                {
2001                        if (!is_array ($data))
2002                        {
2003                                $data = array ();
2004                        }
2005
2006                        $default_values = array
2007                                (
2008                                        'relatives'     => array (RELATIVE_CURRENT),
2009                                        'attributes'    => array ()
2010                                );
2011
2012                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2013
2014                        $p = $this->path_parts (array(
2015                                        'string'        => $data['string'],
2016                                        'relatives'     => array ($data['relatives'][0])
2017                                )
2018                        );
2019
2020                        /*
2021                           This is kind of trivial, given that set_attributes () can change owner_id,
2022                           size, etc.
2023                        */
2024                        if (!$this->acl_check (array(
2025                                        'string'        => $p->fake_full_path,
2026                                        'relatives'     => array ($p->mask),
2027                                        'operation'     => PHPGW_ACL_EDIT
2028                                ))
2029                        )
2030                        {
2031                                return False;
2032                        }
2033
2034                        if (!$this->file_exists (array(
2035                                        'string'        => $data['string'],
2036                                        'relatives'     => array ($data['relatives'][0])
2037                                ))
2038                        )
2039                        {
2040                                return False;
2041                        }
2042
2043                        /*
2044                           All this voodoo just decides which attributes to update
2045                           depending on if the attribute was supplied in the 'attributes' array
2046                        */
2047
2048                        $ls_array = $this->ls (array(
2049                                        'string'        => $p->fake_full_path,
2050                                        'relatives'     => array ($p->mask),
2051                                        'checksubdirs'  => False,
2052                                        'nofiles'       => True
2053                                )
2054                        );
2055                        $record = $ls_array[0];
2056
2057                        $sql = 'UPDATE phpgw_vfs SET ';
2058
2059                        $change_attributes = 0;
2060
2061                        foreach ($this->attributes as $attribute)
2062                        {
2063                                if (isset ($data['attributes'][$attribute]))
2064                                {
2065                                        /*
2066                                           Indicate that the EDITED_COMMENT operation needs to be journaled,
2067                                           but only if the comment changed
2068                                        */
2069                                        if ($attribute == 'comment' && $data['attributes'][$attribute] != $record[$attribute])
2070                                        {
2071                                                $edited_comment = 1;
2072                                        }
2073
2074                                        if ($change_attributes > 0)
2075                                        {
2076                                                $sql .= ', ';
2077                                        }
2078
2079                                        // RalfBecker 2004/07/24:
2080                                        // this is only a hack to fix bug [ 991222 ] Error uploading file
2081                                        // the whole class need to be reworked with the new db-functions
2082                                        if (!isset($this->column_defs))
2083                                        {
2084                                                $table_defs = $GLOBALS['phpgw']->db->get_table_definitions('phpgwapi','phpgw_vfs');
2085                                                $this->column_defs = $table_defs['fd'];
2086                                        }
2087                                        $sql .= $attribute.'=' .$GLOBALS['phpgw']->db->quote($data['attributes'][$attribute],$this->column_defs[$attribute]['type']);
2088
2089                                        $change_attributes++;
2090                                }
2091                        }
2092
2093                        if (!$change_attributes)
2094                        {
2095                                return True;    // nothing to do
2096                        }
2097                        $sql .= ' WHERE file_id='.(int) $record['file_id'];
2098                        $sql .= $this->extra_sql (array ('query_type' => VFS_SQL_UPDATE));
2099                        $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
2100
2101                        if ($query)
2102                        {
2103                                if ($edited_comment)
2104                                {
2105                                        $this->add_journal (array(
2106                                                        'string'        => $p->fake_full_path,
2107                                                        'relatives'     => array ($p->mask),
2108                                                        'operation'     => VFS_OPERATION_EDITED_COMMENT
2109                                                )
2110                                        );
2111                                }
2112
2113                                return True;
2114                        }
2115                        else
2116                        {
2117                                return False;
2118                        }
2119                }
2120
2121                /*!
2122                @function correct_attributes
2123                @abstract Set the correct attributes for 'string' (e.g. owner)
2124                @param string File/directory to correct attributes of
2125                @param relatives Relativity array
2126                @result Boolean True/False
2127                */
2128                function correct_attributes ($data)
2129                {
2130                        if (!is_array ($data))
2131                        {
2132                                $data = array ();
2133                        }
2134
2135                        $default_values = array
2136                                (
2137                                        'relatives'     => array (RELATIVE_CURRENT)
2138                                );
2139
2140                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2141
2142                        $p = $this->path_parts (array(
2143                                        'string'        => $data['string'],
2144                                        'relatives'     => array ($data['relatives'][0])
2145                                )
2146                        );
2147
2148                        if ($p->fake_leading_dirs != $this->fakebase && $p->fake_leading_dirs != '/')
2149                        {
2150                                $ls_array = $this->ls (array(
2151                                                'string'        => $p->fake_leading_dirs,
2152                                                'relatives'     => array ($p->mask),
2153                                                'checksubdirs'  => False,
2154                                                'nofiles'       => True
2155                                        )
2156                                );
2157                                $set_attributes_array = Array(
2158                                        'owner_id' => $ls_array[0]['owner_id']
2159                                );
2160                        }
2161                        elseif (preg_match ("+^$this->fakebase\/(.*)$+U", $p->fake_full_path, $matches))
2162                        {
2163                                $set_attributes_array = Array(
2164                                        'owner_id' => $GLOBALS['phpgw']->accounts->name2id ($matches[1])
2165                                );
2166                        }
2167                        else
2168                        {
2169                                $set_attributes_array = Array(
2170                                        'owner_id' => 0
2171                                );
2172                        }
2173
2174                        $this->set_attributes (array(
2175                                        'string'        => $p->fake_full_name,
2176                                        'relatives'     => array ($p->mask),
2177                                        'attributes'    => $set_attributes_array
2178                                )
2179                        );
2180
2181                        return True;
2182                }
2183
2184                /*
2185                 * See vfs_shared
2186                 */
2187                function file_type ($data)
2188                {
2189                        if (!is_array ($data))
2190                        {
2191                                $data = array ();
2192                        }
2193
2194                        $default_values = array
2195                                (
2196                                        'relatives'     => array (RELATIVE_CURRENT)
2197                                );
2198
2199                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2200
2201                        $p = $this->path_parts (array(
2202                                        'string'        => $data['string'],
2203                                        'relatives'     => array ($data['relatives'][0])
2204                                )
2205                        );
2206
2207                        if (!$this->acl_check (array(
2208                                        'string'        => $p->fake_full_path,
2209                                        'relatives'     => array ($p->mask),
2210                                        'operation'     => PHPGW_ACL_READ,
2211                                        'must_exist'    => True
2212                                ))
2213                        )
2214                        {
2215                                return False;
2216                        }
2217
2218                        if ($p->outside)
2219                        {
2220                                if (is_dir ($p->real_full_path))
2221                                {
2222                                        return ('Directory');
2223                                }
2224
2225                                /*
2226                                   We don't return an empty string here, because it may still match with a database query
2227                                   because of linked directories
2228                                */
2229                        }
2230
2231                        /*
2232                           We don't use ls () because it calls file_type () to determine if it has been
2233                           passed a directory
2234                        */
2235                        $db2 = $GLOBALS['phpgw']->db;
2236                        $db2->query ("SELECT mime_type FROM phpgw_vfs WHERE directory='".
2237                                $db2->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2238                                $db2->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2239                        $db2->next_record ();
2240                        $mime_type = $db2->Record['mime_type'];
2241                        if(!$mime_type)
2242                        {
2243                                $mime_type = $this->get_ext_mime_type (array ('string' => $data['string']));
2244                                {
2245                                        $db2->query ("UPDATE phpgw_vfs SET mime_type='$mime_type' WHERE directory='".
2246                                                $db2->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2247                                                $db2->db_addslashes($p->fake_name_clean)."'" .
2248                                                $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2249                                }
2250                        }
2251
2252                        return $mime_type;
2253                }
2254
2255                /*
2256                 * See vfs_shared
2257                 */
2258                function file_exists ($data)
2259                {
2260                        if (!is_array ($data))
2261                        {
2262                                $data = array ();
2263                        }
2264
2265                        $default_values = array
2266                                (
2267                                        'relatives'     => array (RELATIVE_CURRENT)
2268                                );
2269
2270                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2271
2272                        $p = $this->path_parts (array(
2273                                        'string'        => $data['string'],
2274                                        'relatives'     => array ($data['relatives'][0])
2275                                )
2276                        );
2277
2278                        if ($p->outside)
2279                        {
2280                                $rr = file_exists ($p->real_full_path);
2281
2282                                return $rr;
2283                        }
2284
2285                        $db2 = $GLOBALS['phpgw']->db;
2286                        $db2->query ("SELECT name FROM phpgw_vfs WHERE directory='".
2287                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2288                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2289
2290                        if ($db2->next_record ())
2291                        {
2292                                return True;
2293                        }
2294                        else
2295                        {
2296                                return False;
2297                        }
2298                }
2299
2300                /*
2301                 * See vfs_shared
2302                 */
2303                function get_size ($data)
2304                {
2305                        if (!is_array ($data))
2306                        {
2307                                $data = array ();
2308                        }
2309
2310                        $default_values = array
2311                                (
2312                                        'relatives'     => array (RELATIVE_CURRENT),
2313                                        'checksubdirs'  => True
2314                                );
2315
2316                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2317
2318                        $p = $this->path_parts (array(
2319                                        'string'        => $data['string'],
2320                                        'relatives'     => array ($data['relatives'][0])
2321                                )
2322                        );
2323
2324                        if (!$this->acl_check (array(
2325                                        'string'        => $p->fake_full_path,
2326                                        'relatives'     => array ($p->mask),
2327                                        'operation'     => PHPGW_ACL_READ,
2328                                        'must_exist'    => True
2329                                ))
2330                        )
2331                        {
2332                                return False;
2333                        }
2334
2335                        /*
2336                           WIP - this should run through all of the subfiles/directories in the directory and tally up
2337                           their sizes.  Should modify ls () to be able to return a list for files outside the virtual root
2338                        */
2339                        if ($p->outside)
2340                        {
2341                                $size = filesize ($p->real_full_path);
2342
2343                                return $size;
2344                        }
2345
2346                        foreach($this->ls (array(
2347                                        'string'        => $p->fake_full_path,
2348                                        'relatives'     => array ($p->mask),
2349                                        'checksubdirs'  => $data['checksubdirs'],
2350                                        'nofiles'       => !$data['checksubdirs']
2351                                )) as $file_array)
2352                        {
2353                                /*
2354                                   Make sure the file is in the directory we want, and not
2355                                   some deeper nested directory with a similar name
2356                                */
2357/*
2358                                if (@!ereg ('^' . $file_array['directory'], $p->fake_full_path))
2359                                {
2360                                        continue;
2361                                }
2362*/
2363
2364                                $size += $file_array['size'];
2365                        }
2366
2367                        if ($data['checksubdirs'])
2368                        {
2369                                $query = $GLOBALS['phpgw']->db->query ("SELECT size FROM phpgw_vfs WHERE directory='".
2370                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2371                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" .
2372                                        $this->extra_sql (array ('query_text' => VFS_SQL_SELECT)));
2373                                $GLOBALS['phpgw']->db->next_record ();
2374                                $size += $GLOBALS['phpgw']->db->Record[0];
2375                        }
2376
2377                        return $size;
2378                }
2379                /*
2380                 * get the quota defined for the path in sql table
2381                 */
2382                function get_quota($data){
2383                        if (!is_array ($data))
2384                        {
2385                                $data = array ();
2386                        }
2387
2388                        $default_values = array
2389                                (
2390                                        'relatives'     => array (RELATIVE_CURRENT)
2391                                );
2392
2393                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2394
2395                        $p = $this->path_parts (array(
2396                                        'string'        => $data['string'],
2397                                        'relatives'     => RELATIVE_NONE
2398                                )
2399                        );
2400
2401                        if (!$this->acl_check (array(
2402                                'string'        => $p->fake_full_path,
2403                                'relatives'     => $p->mask,
2404                                'operation'     => PHPGW_ACL_READ
2405                        ))
2406                        )
2407                        {
2408                                return False;
2409                        }
2410                        $query = $GLOBALS['phpgw']->db->query ("SELECT quota_size FROM phpgw_vfs_quota WHERE directory = '".$data['string']."' LIMIT 1;", __LINE__,__FILE__);
2411
2412                        $GLOBALS['phpgw']->db->next_record ();
2413                        $record = $GLOBALS['phpgw']->db->Record;
2414                        return $record['quota_size'];
2415                }
2416                function set_quota($data){
2417                        if (!is_array ($data))
2418                        {
2419                                $data = array ();
2420                        }
2421
2422                        $default_values = array
2423                                (
2424                                        'relatives'     => array (RELATIVE_CURRENT)
2425                                );
2426
2427                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2428
2429                        $p = $this->path_parts (array(
2430                                        'string'        => $data['string'],
2431                                        'relatives'     => array ($data['relatives'][0])
2432                                )
2433                        );
2434
2435                        if (!$this->acl_check (array(
2436                                'string'        => $p->fake_full_path,
2437                                'relatives'     => array ($p->mask),
2438                                'operation'     => PHPGW_ACL_READ
2439                        ))
2440                        )
2441                        {
2442                                return False;
2443                        }
2444                        return $GLOBALS['phpgw']->db->query("INSERT INTO phpgw_vfs_quota VALUES ('".$data['string']."',".$data['new_quota'].");", __LINE__,__FILE__);
2445                }
2446
2447
2448                /*!
2449                @function checkperms
2450                @abstract Check if $this->working_id has write access to create files in $dir
2451                @discussion Simple call to acl_check
2452                @param string Directory to check access of
2453                @param relatives Relativity array
2454                @result Boolean True/False
2455                */
2456                function checkperms ($data)
2457                {
2458                        if (!is_array ($data))
2459                        {
2460                                $data = array ();
2461                        }
2462
2463                        $default_values = array
2464                                (
2465                                        'relatives'     => array (RELATIVE_CURRENT)
2466                                );
2467
2468                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2469
2470                        $p = $this->path_parts (array(
2471                                        'string'        => $data['string'],
2472                                        'relatives'     => array ($data['relatives'][0])
2473                                )
2474                        );
2475
2476                        if (!$this->acl_check (array(
2477                                        'string'        => $p->fake_full_path,
2478                                        'relatives'     => array ($p->mask),
2479                                        'operation'     => PHPGW_ACL_ADD
2480                                ))
2481                        )
2482                        {
2483                                return False;
2484                        }
2485                        else
2486                        {
2487                                return True;
2488                        }
2489                }
2490
2491                /*
2492                 * See vfs_shared
2493                 * If $data['readlink'] then a readlink is tryed on the real file
2494                 * If $data['file_id'] then the file_id is used instead of a path
2495                 */
2496                function ls ($data)
2497                {
2498                        if (!is_array ($data))
2499                        {
2500                                $data = array ();
2501                        }
2502
2503                        $default_values = array
2504                                (
2505                                        'relatives'     => array (RELATIVE_CURRENT),
2506                                        'checksubdirs'  => True,
2507                                        'mime_type'     => False,
2508                                        'nofiles'       => False,
2509                                        'orderby'       => 'directory'
2510                                );
2511
2512                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2513
2514                        $p = $this->path_parts (array(
2515                                        'string'        => $data['string'],
2516                                        'relatives'     => array ($data['relatives'][0])
2517                                )
2518                        );
2519                        $dir = $p->fake_full_path;
2520
2521
2522                        /* If they pass us a file or 'nofiles' is set, return the info for $dir only */
2523                        if (@$data['file_id']
2524                                || ((($type = $this->file_type (array(
2525                                        'string'        => $dir,
2526                                        'relatives'     => array ($p->mask)
2527                                )) != 'Directory'))
2528                                || ($data['nofiles'])) && !$p->outside
2529                        )
2530                        {
2531                                /* SELECT all, the, attributes */
2532                                $sql = 'SELECT ';
2533
2534                                foreach ($this->attributes as $num => $attribute)
2535                                {
2536                                        if ($num)
2537                                        {
2538                                                $sql .= ', ';
2539                                        }
2540
2541                                        $sql .= $attribute;
2542                                }
2543
2544                                $sql .= " FROM phpgw_vfs WHERE ";
2545                                if (@$data['file_id'])
2546                                {
2547                                        $sql .= 'file_id='.(int)$data['file_id'];
2548                                }
2549                                else
2550                                {
2551                                        $sql .= " directory='".$GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND".
2552                                                " name='".$GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'".
2553                                                $this->extra_sql (array ('query_type' => VFS_SQL_SELECT));
2554                                }
2555                                $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
2556
2557                                $GLOBALS['phpgw']->db->next_record ();
2558                                $record = $GLOBALS['phpgw']->db->Record;
2559
2560                                /* We return an array of one array to maintain the standard */
2561                                $rarray = array ();
2562                                foreach($this->attributes as $attribute)
2563                                {
2564                                        if ($attribute == 'mime_type' && !$record[$attribute])
2565                                        {
2566                                                $db2 = $GLOBALS['phpgw']->db;
2567                                                $record[$attribute] = $this->get_ext_mime_type (array(
2568                                                                'string' => $p->fake_name_clean
2569                                                        )
2570                                                );
2571
2572                                                if($record[$attribute])
2573                                                {
2574                                                        $db2->query ("UPDATE phpgw_vfs SET mime_type='".$record[$attribute]."' WHERE directory='".
2575                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2576                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2577                                                }
2578                                        }
2579
2580                                        $rarray[0][$attribute] = $record[$attribute];
2581                                }
2582                                if ($this->file_actions && @$data['readlink'])  // test if file is a symlink and get it's target
2583                                {
2584                                        $rarray[0]['symlink'] = @readlink($p->real_full_path);
2585                                }
2586
2587                                return $rarray;
2588                        }
2589
2590                        //WIP - this should recurse using the same options the virtual part of ls () does
2591                        /* If $dir is outside the virutal root, we have to check the file system manually */
2592                        if ($p->outside)
2593                        {
2594                                if ($this->file_type (array(
2595                                                'string'        => $p->fake_full_path,
2596                                                'relatives'     => array ($p->mask)
2597                                        )) == 'Directory'
2598                                        && !$data['nofiles']
2599                                )
2600                                {
2601                                        $dir_handle = opendir ($p->real_full_path);
2602                                        while ($filename = readdir ($dir_handle))
2603                                        {
2604                                                if ($filename == '.' || $filename == '..')
2605                                                {
2606                                                        continue;
2607                                                }
2608
2609                                                $rarray[] = $this->get_real_info (array(
2610                                                                'string'        => $p->real_full_path . SEP . $filename,
2611                                                                'relatives'     => array ($p->mask)
2612                                                        )
2613                                                );
2614                                        }
2615                                }
2616                                else
2617                                {
2618                                        $rarray[] = $this->get_real_info (array(
2619                                                        'string'        => $p->real_full_path,
2620                                                        'relatives'     => array ($p->mask)
2621                                                )
2622                                        );
2623                                }
2624
2625                                return $rarray;
2626                        }
2627
2628                        /* $dir's not a file, is inside the virtual root, and they want to check subdirs */
2629                        /* SELECT all, the, attributes FROM phpgw_vfs WHERE file=$dir */
2630                        $sql = 'SELECT ';
2631                        if (!$this->acl_check (array (
2632                                'string' => $p->fake_full_path,
2633                                'relatives' => array ($p->mask),
2634                                'operation' => PHPGW_ACL_PRIVATE)
2635                        ))
2636                        $query_type = " type != 1 AND";
2637                        else
2638                                $query_type = "";
2639
2640                        foreach($this->attributes as $num => $attribute)
2641                        {
2642                                if ($num)
2643                                {
2644                                        $sql .= ", ";
2645                                }
2646
2647                                $sql .= $attribute;
2648                        }
2649
2650                        $dir_clean = $this->clean_string (array ('string' => $dir));
2651                        $sql .= " FROM phpgw_vfs WHERE ".$query_type." directory LIKE '".$GLOBALS['phpgw']->db->db_addslashes($dir_clean)."%'";
2652                        $sql .= $this->extra_sql (array ('query_type' => VFS_SQL_SELECT));
2653
2654                        if ($data['mime_type'])
2655                        {
2656                                $sql .= " AND mime_type='".$data['mime_type']."'";
2657                        }
2658                        if (strlen($data['orderby']) > 0)
2659                                $sql .= ' ORDER BY '.$data['orderby'];
2660                        $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
2661
2662                        $rarray = array ();
2663                        for ($i = 0; $GLOBALS['phpgw']->db->next_record (); $i++)
2664                        {
2665                                $record = $GLOBALS['phpgw']->db->Record;
2666
2667                                /* Further checking on the directory.  This makes sure /home/user/test won't match /home/user/test22 */
2668                                if (@!ereg ("^$dir(/|$)", $record['directory']))
2669                                {
2670                                        continue;
2671                                }
2672
2673                                /* If they want only this directory, then $dir should end without a trailing / */
2674                                if (!$data['checksubdirs'] && ereg ("^$dir/", $record['directory']))
2675                                {
2676                                        continue;
2677                                }
2678
2679                                foreach($this->attributes as $attribute)
2680                                {
2681                                        if ($attribute == 'mime_type' && !$record[$attribute])
2682                                        {
2683                                                $db2 = $GLOBALS['phpgw']->db;
2684                                                $record[$attribute] = $this->get_ext_mime_type (array(
2685                                                                'string'        => $p->fake_name_clean
2686                                                        )
2687                                                );
2688
2689                                                if($record[$attribute])
2690                                                {
2691                                                        $db2->query ("UPDATE phpgw_vfs SET mime_type='".$record[$attribute]."' WHERE directory='".
2692                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2693                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2694                                                }
2695                                        }
2696
2697                                        $rarray[$i][$attribute] = $record[$attribute];
2698                                }
2699                        }
2700
2701                        return $rarray;
2702                }
2703
2704                /*
2705                 * See vfs_shared
2706                 */
2707                function update_real ($data,$recursive = False)
2708                {
2709                        if (!is_array ($data))
2710                        {
2711                                $data = array ();
2712                        }
2713
2714                        $default_values = array
2715                                (
2716                                        'relatives'     => array (RELATIVE_CURRENT)
2717                                );
2718
2719                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2720
2721                        $p = $this->path_parts (array(
2722                                        'string'        => $data['string'],
2723                                        'relatives'     => array ($data['relatives'][0])
2724                                )
2725                        );
2726
2727                        if (file_exists ($p->real_full_path))
2728                        {
2729                                if (is_dir ($p->real_full_path))
2730                                {
2731                                        $dir_handle = opendir ($p->real_full_path);
2732                                        while ($filename = readdir ($dir_handle))
2733                                        {
2734                                                if ($filename == '.' || $filename == '..')
2735                                                {
2736                                                        continue;
2737                                                }
2738
2739                                                $rarray[] = $this->get_real_info (array(
2740                                                                'string'        => $p->fake_full_path . '/' . $filename,
2741                                                                'relatives'     => array (RELATIVE_NONE)
2742                                                        )
2743                                                );
2744                                        }
2745                                }
2746                                else
2747                                {
2748                                        $rarray[] = $this->get_real_info (array(
2749                                                        'string'        => $p->fake_full_path,
2750                                                        'relatives'     => array (RELATIVE_NONE)
2751                                                )
2752                                        );
2753                                }
2754
2755                                if (!is_array ($rarray))
2756                                {
2757                                        $rarray = array ();
2758                                }
2759
2760                                foreach($rarray as $num => $file_array)
2761                                {
2762                                        $p2 = $this->path_parts (array(
2763                                                        'string'        => $file_array['directory'] . '/' . $file_array['name'],
2764                                                        'relatives'     => array (RELATIVE_NONE)
2765                                                )
2766                                        );
2767
2768                                        /* Note the mime_type.  This can be "Directory", which is how we create directories */
2769                                        $set_attributes_array = Array(
2770                                                'size' => $file_array['size'],
2771                                                'mime_type' => $file_array['mime_type']
2772                                        );
2773
2774                                        if (!$this->file_exists (array(
2775                                                        'string'        => $p2->fake_full_path,
2776                                                        'relatives'     => array (RELATIVE_NONE)
2777                                                ))
2778                                        )
2779                                        {
2780                                                $this->touch (array(
2781                                                                'string'        => $p2->fake_full_path,
2782                                                                'relatives'     => array (RELATIVE_NONE)
2783                                                        )
2784                                                );
2785                                        }
2786                                        $this->set_attributes (array(
2787                                                        'string'        => $p2->fake_full_path,
2788                                                        'relatives'     => array (RELATIVE_NONE),
2789                                                        'attributes'    => $set_attributes_array
2790                                                )
2791                                        );
2792                                        if ($recursive && $file_array['mime_type'] == 'Directory')
2793                                        {
2794                                                $dir_data = $data;
2795                                                $dir_data['string'] = $file_array['directory'] . '/' . $file_array['name'];
2796                                                $this->update_real($dir_data,$recursive);
2797                                        }
2798                                }
2799                        }
2800                }
2801
2802                /* Helper functions */
2803
2804                /* This fetchs all available file system information for string (not using the database) */
2805                function get_real_info ($data)
2806                {
2807                        if (!is_array ($data))
2808                        {
2809                                $data = array ();
2810                        }
2811
2812                        $default_values = array
2813                                (
2814                                        'relatives'     => array (RELATIVE_CURRENT)
2815                                );
2816
2817                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2818
2819                        $p = $this->path_parts (array(
2820                                        'string'        => $data['string'],
2821                                        'relatives'     => array ($data['relatives'][0])
2822                                )
2823                        );
2824
2825                        if (is_dir ($p->real_full_path))
2826                        {
2827                                $mime_type = 'Directory';
2828                        }
2829                        else
2830                        {
2831                                $mime_type = $this->get_ext_mime_type (array(
2832                                                'string'        => $p->fake_name
2833                                        )
2834                                );
2835
2836                                if($mime_type)
2837                                {
2838                                        $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET mime_type='".$mime_type."' WHERE directory='".
2839                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2840                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" .
2841                                                $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2842                                }
2843                        }
2844
2845                        $size = filesize ($p->real_full_path);
2846                        $rarray = array(
2847                                'directory' => $p->fake_leading_dirs,
2848                                'name' => $p->fake_name,
2849                                'size' => $size,
2850                                'mime_type' => $mime_type
2851                        );
2852
2853                        return ($rarray);
2854                }
2855        }
2856?>
Note: See TracBrowser for help on using the repository browser.