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

Revision 1534, 66.0 KB checked in by amuller, 14 years ago (diff)

Ticket #597 - Melhorias no filemanager com correção de bugs

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