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

Revision 1693, 68.5 KB checked in by amuller, 14 years ago (diff)

Ticket #597 - melhorias no modulo gerenciador de arquivos para arquivos grandes

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