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

Revision 2, 65.9 KB checked in by niltonneto, 17 years ago (diff)

Removida todas as tags usadas pelo CVS ($Id, $Source).
Primeira versão no CVS externo.

  • 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
1590                        if (!$this->acl_check (array(
1591                                        'string'        => $p->fake_full_path,
1592                                        'relatives'     => array ($p->mask),
1593                                        'operation'     => PHPGW_ACL_DELETE
1594                                ))
1595                        )
1596                        {
1597                                return False;
1598                        }
1599
1600                        if (!$this->file_exists (array(
1601                                        'string'        => $data['string'],
1602                                        'relatives'     => array ($data['relatives'][0])
1603                                ))
1604                        )
1605                        {
1606                                if ($this->file_actions)
1607                                {
1608                                        $rr = unlink ($p->real_full_path);
1609                                }
1610                                else
1611                                {
1612                                        $rr = True;
1613                                }
1614
1615                                if ($rr)
1616                                {
1617                                        return True;
1618                                }
1619                                else
1620                                {
1621                                        return False;
1622                                }
1623                        }
1624
1625                        if ($this->file_type (array(
1626                                        'string'        => $data['string'],
1627                                        'relatives'     => array ($data['relatives'][0])
1628                                )) != 'Directory'
1629                        )
1630                        {
1631                                $this->add_journal (array(
1632                                                'string'        => $p->fake_full_path,
1633                                                'relatives'     => array ($p->mask),
1634                                                'operation'     => VFS_OPERATION_DELETED
1635                                        )
1636                                );
1637
1638                                $query = $GLOBALS['phpgw']->db->query ("DELETE FROM phpgw_vfs WHERE directory='".
1639                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
1640                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'".$this->extra_sql (array ('query_type' => VFS_SQL_DELETE)), __LINE__, __FILE__);
1641
1642                                if ($this->file_actions)
1643                                {
1644                                        $rr = unlink ($p->real_full_path);
1645                                }
1646                                else
1647                                {
1648                                        $rr = True;
1649                                }
1650
1651                                if ($query || $rr)
1652                                {
1653                                        return True;
1654                                }
1655                                else
1656                                {
1657                                        return False;
1658                                }
1659                        }
1660                        else
1661                        {
1662                                $ls = $this->ls (array(
1663                                                'string'        => $p->fake_full_path,
1664                                                'relatives'     => array ($p->mask)
1665                                        )
1666                                );
1667
1668                                /* First, we cycle through the entries and delete the files */
1669                                foreach($ls as $entry)
1670                                {
1671                                        if ($entry['mime_type'] == 'Directory')
1672                                        {
1673                                                continue;
1674                                        }
1675
1676                                        $this->rm (array(
1677                                                        'string'        => "$entry[directory]/$entry[name]",
1678                                                        'relatives'     => array ($p->mask)
1679                                                )
1680                                        );
1681                                }
1682
1683                                /* Now we cycle through again and delete the directories */
1684                                foreach ($ls as $entry)
1685                                {
1686                                        if ($entry['mime_type'] != 'Directory')
1687                                        {
1688                                                continue;
1689                                        }
1690
1691                                        /* Only the best in confusing recursion */
1692                                        $this->rm (array(
1693                                                        'string'        => "$entry[directory]/$entry[name]",
1694                                                        'relatives'     => array ($p->mask)
1695                                                )
1696                                        );
1697                                }
1698
1699                                /* If the directory is linked, we delete the placeholder directory */
1700                                $ls_array = $this->ls (array(
1701                                                'string'        => $p->fake_full_path,
1702                                                'relatives'     => array ($p->mask),
1703                                                'checksubdirs'  => False,
1704                                                'mime_type'     => False,
1705                                                'nofiles'       => True
1706                                        )
1707                                );
1708                                $link_info = $ls_array[0];
1709
1710                                if ($link_info['link_directory'] && $link_info['link_name'])
1711                                {
1712                                        $path = $this->path_parts (array(
1713                                                        'string'        => $link_info['directory'] . '/' . $link_info['name'],
1714                                                        'relatives'     => array ($p->mask),
1715                                                        'nolinks'       => True
1716                                                )
1717                                        );
1718
1719                                        if ($this->file_actions)
1720                                        {
1721                                                rmdir ($path->real_full_path);
1722                                        }
1723                                }
1724
1725                                /* Last, we delete the directory itself */
1726                                $this->add_journal (array(
1727                                                'string'        => $p->fake_full_path,
1728                                                'relatives'     => array ($p->mask),
1729                                                'operaton'      => VFS_OPERATION_DELETED
1730                                        )
1731                                );
1732
1733                                $query = $GLOBALS['phpgw']->db->query ("DELETE FROM phpgw_vfs WHERE directory='".
1734                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
1735                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" .
1736                                        $this->extra_sql (array ('query_type' => VFS_SQL_DELETE)), __LINE__, __FILE__);
1737
1738                                if ($this->file_actions)
1739                                {
1740                                        rmdir ($p->real_full_path);
1741                                }
1742
1743                                return True;
1744                        }
1745                }
1746
1747                /*
1748                 * See vfs_shared
1749                 */
1750                function mkdir ($data)
1751                {
1752                        if (!is_array ($data))
1753                        {
1754                                $data = array ();
1755                        }
1756
1757                        $default_values = array
1758                                (
1759                                        'relatives'     => array (RELATIVE_CURRENT)
1760                                );
1761
1762                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1763
1764                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1765                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
1766
1767                        $p = $this->path_parts (array(
1768                                        'string'        => $data['string'],
1769                                        'relatives'     => array ($data['relatives'][0])
1770                                )
1771                        );
1772
1773                        if (!$this->acl_check (array(
1774                                        'string'        => $p->fake_full_path,
1775                                        'relatives'     => array ($p->mask),
1776                                        'operation'     => PHPGW_ACL_ADD)
1777                                )
1778                        )
1779                        {
1780                                return False;
1781                        }
1782
1783                        /* We don't allow /'s in dir names, of course */
1784                        if (ereg ("/", $p->fake_name))
1785                        {
1786                                return False;
1787                        }
1788
1789                        umask (077);
1790
1791                        if ($this->file_actions)
1792                        {
1793                                if (!@is_dir($p->real_leading_dirs_clean))      // eg. /home or /group does not exist
1794                                {
1795                                        if (!@mkdir($p->real_leading_dirs_clean,0770))  // ==> create it
1796                                        {
1797                                                return False;
1798                                        }
1799                                }
1800                                if (@is_dir($p->real_full_path))        // directory already exists
1801                                {
1802                                        $this->update_real($data,True);         // update its contents
1803                                }
1804                                elseif (!@mkdir ($p->real_full_path, 0770))
1805                                {
1806                                        return False;
1807                                }
1808                        }
1809
1810                        if (!$this->file_exists (array(
1811                                        'string'        => $p->fake_full_path,
1812                                        'relatives'     => array ($p->mask)
1813                                ))
1814                        )
1815                        {
1816                                $query = $GLOBALS['phpgw']->db->query ("INSERT INTO phpgw_vfs (owner_id, name, directory) VALUES ($this->working_id, '".
1817                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."', '".
1818                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."')", __LINE__, __FILE__);
1819       
1820                                $this->set_attributes(array(
1821                                        'string'        => $p->fake_full_path,
1822                                        'relatives'     => array ($p->mask),
1823                                        'attributes'    => array (
1824                                                                'createdby_id' => $account_id,
1825                                                                'size' => 4096,
1826                                                                'mime_type' => 'Directory',
1827                                                                'created' => $this->now,
1828                                                                'deleteable' => 'Y',
1829                                                                'app' => $currentapp
1830                                                        )
1831                                        )
1832                                );
1833
1834                                $this->correct_attributes (array(
1835                                                'string'        => $p->fake_full_path,
1836                                                'relatives'     => array ($p->mask)
1837                                        )
1838                                );
1839
1840                                $this->add_journal (array(
1841                                                'string'        => $p->fake_full_path,
1842                                                'relatives'     => array ($p->mask),
1843                                                'operation'     => VFS_OPERATION_CREATED
1844                                        )
1845                                );
1846                        }
1847                        else
1848                        {
1849                                return False;
1850                        }
1851
1852                        return True;
1853                }
1854
1855                /*
1856                 * See vfs_shared
1857                 */
1858                function make_link ($data)
1859                {
1860                        if (!is_array ($data))
1861                        {
1862                                $data = array ();
1863                        }
1864
1865                        $default_values = array
1866                                (
1867                                        'relatives'     => array (RELATIVE_CURRENT, RELATIVE_CURRENT)
1868                                );
1869
1870                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1871
1872                        $account_id = $GLOBALS['phpgw_info']['user']['account_id'];
1873                        $currentapp = $GLOBALS['phpgw_info']['flags']['currentapp'];
1874
1875                        $vp = $this->path_parts (array(
1876                                        'string'        => $data['vdir'],
1877                                        'relatives'     => array ($data['relatives'][0])
1878                                )
1879                        );
1880
1881                        $rp = $this->path_parts (array(
1882                                        'string'        => $data['rdir'],
1883                                        'relatives'     => array ($data['relatives'][1])
1884                                )
1885                        );
1886
1887                        if (!$this->acl_check (array(
1888                                        'string'        => $vp->fake_full_path,
1889                                        'relatives'     => array ($vp->mask),
1890                                        'operation'     => PHPGW_ACL_ADD
1891                                ))
1892                        )
1893                        {
1894                                return False;
1895                        }
1896
1897                        if ((!$this->file_exists (array(
1898                                        'string'        => $rp->real_full_path,
1899                                        'relatives'     => array ($rp->mask)
1900                                )))
1901                                && !mkdir ($rp->real_full_path, 0770))
1902                        {
1903                                return False;
1904                        }
1905
1906                        if (!$this->mkdir (array(
1907                                        'string'        => $vp->fake_full_path,
1908                                        'relatives'     => array ($vp->mask)
1909                                ))
1910                        )
1911                        {
1912                                return False;
1913                        }
1914
1915                        $size = $this->get_size (array(
1916                                        'string'        => $rp->real_full_path,
1917                                        'relatives'     => array ($rp->mask)
1918                                )
1919                        );
1920
1921                        $this->set_attributes(array(
1922                                        'string'        => $vp->fake_full_path,
1923                                        'relatives'     => array ($vp->mask),
1924                                        'attributes'    => array (
1925                                                                'link_directory' => $rp->real_leading_dirs,
1926                                                                'link_name' => $rp->real_name,
1927                                                                'size' => $size
1928                                                        )
1929                                )
1930                        );
1931
1932                        $this->correct_attributes (array(
1933                                        'string'        => $vp->fake_full_path,
1934                                        'relatives'     => array ($vp->mask)
1935                                )
1936                        );
1937
1938                        return True;
1939                }
1940
1941                /*
1942                 * See vfs_shared
1943                 */
1944                function set_attributes ($data)
1945                {
1946                        if (!is_array ($data))
1947                        {
1948                                $data = array ();
1949                        }
1950
1951                        $default_values = array
1952                                (
1953                                        'relatives'     => array (RELATIVE_CURRENT),
1954                                        'attributes'    => array ()
1955                                );
1956
1957                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1958
1959                        $p = $this->path_parts (array(
1960                                        'string'        => $data['string'],
1961                                        'relatives'     => array ($data['relatives'][0])
1962                                )
1963                        );
1964
1965                        /*
1966                           This is kind of trivial, given that set_attributes () can change owner_id,
1967                           size, etc.
1968                        */
1969                        if (!$this->acl_check (array(
1970                                        'string'        => $p->fake_full_path,
1971                                        'relatives'     => array ($p->mask),
1972                                        'operation'     => PHPGW_ACL_EDIT
1973                                ))
1974                        )
1975                        {
1976                                return False;
1977                        }
1978
1979                        if (!$this->file_exists (array(
1980                                        'string'        => $data['string'],
1981                                        'relatives'     => array ($data['relatives'][0])
1982                                ))
1983                        )
1984                        {
1985                                return False;
1986                        }
1987
1988                        /*
1989                           All this voodoo just decides which attributes to update
1990                           depending on if the attribute was supplied in the 'attributes' array
1991                        */
1992
1993                        $ls_array = $this->ls (array(
1994                                        'string'        => $p->fake_full_path,
1995                                        'relatives'     => array ($p->mask),
1996                                        'checksubdirs'  => False,
1997                                        'nofiles'       => True
1998                                )
1999                        );
2000                        $record = $ls_array[0];
2001
2002                        $sql = 'UPDATE phpgw_vfs SET ';
2003
2004                        $change_attributes = 0;
2005
2006                        foreach ($this->attributes as $attribute)
2007                        {
2008                                if (isset ($data['attributes'][$attribute]))
2009                                {
2010                                        /*
2011                                           Indicate that the EDITED_COMMENT operation needs to be journaled,
2012                                           but only if the comment changed
2013                                        */
2014                                        if ($attribute == 'comment' && $data['attributes'][$attribute] != $record[$attribute])
2015                                        {
2016                                                $edited_comment = 1;
2017                                        }
2018
2019                                        if ($change_attributes > 0)
2020                                        {
2021                                                $sql .= ', ';
2022                                        }
2023
2024                                        // RalfBecker 2004/07/24:
2025                                        // this is only a hack to fix bug [ 991222 ] Error uploading file
2026                                        // the whole class need to be reworked with the new db-functions
2027                                        if (!isset($this->column_defs))
2028                                        {
2029                                                $table_defs = $GLOBALS['phpgw']->db->get_table_definitions('phpgwapi','phpgw_vfs');
2030                                                $this->column_defs = $table_defs['fd'];
2031                                        }
2032                                        $sql .= $attribute.'=' .$GLOBALS['phpgw']->db->quote($data['attributes'][$attribute],$this->column_defs[$attribute]['type']);
2033
2034                                        $change_attributes++;
2035                                }
2036                        }
2037
2038                        if (!$change_attributes)
2039                        {
2040                                return True;    // nothing to do
2041                        }
2042                        $sql .= ' WHERE file_id='.(int) $record['file_id'];
2043                        $sql .= $this->extra_sql (array ('query_type' => VFS_SQL_UPDATE));
2044                        $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
2045
2046                        if ($query)
2047                        {
2048                                if ($edited_comment)
2049                                {
2050                                        $this->add_journal (array(
2051                                                        'string'        => $p->fake_full_path,
2052                                                        'relatives'     => array ($p->mask),
2053                                                        'operation'     => VFS_OPERATION_EDITED_COMMENT
2054                                                )
2055                                        );
2056                                }
2057
2058                                return True;
2059                        }
2060                        else
2061                        {
2062                                return False;
2063                        }
2064                }
2065
2066                /*!
2067                @function correct_attributes
2068                @abstract Set the correct attributes for 'string' (e.g. owner)
2069                @param string File/directory to correct attributes of
2070                @param relatives Relativity array
2071                @result Boolean True/False
2072                */
2073                function correct_attributes ($data)
2074                {
2075                        if (!is_array ($data))
2076                        {
2077                                $data = array ();
2078                        }
2079
2080                        $default_values = array
2081                                (
2082                                        'relatives'     => array (RELATIVE_CURRENT)
2083                                );
2084
2085                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2086
2087                        $p = $this->path_parts (array(
2088                                        'string'        => $data['string'],
2089                                        'relatives'     => array ($data['relatives'][0])
2090                                )
2091                        );
2092
2093                        if ($p->fake_leading_dirs != $this->fakebase && $p->fake_leading_dirs != '/')
2094                        {
2095                                $ls_array = $this->ls (array(
2096                                                'string'        => $p->fake_leading_dirs,
2097                                                'relatives'     => array ($p->mask),
2098                                                'checksubdirs'  => False,
2099                                                'nofiles'       => True
2100                                        )
2101                                );
2102                                $set_attributes_array = Array(
2103                                        'owner_id' => $ls_array[0]['owner_id']
2104                                );
2105                        }
2106                        elseif (preg_match ("+^$this->fakebase\/(.*)$+U", $p->fake_full_path, $matches))
2107                        {
2108                                $set_attributes_array = Array(
2109                                        'owner_id' => $GLOBALS['phpgw']->accounts->name2id ($matches[1])
2110                                );
2111                        }
2112                        else
2113                        {
2114                                $set_attributes_array = Array(
2115                                        'owner_id' => 0
2116                                );
2117                        }
2118
2119                        $this->set_attributes (array(
2120                                        'string'        => $p->fake_full_name,
2121                                        'relatives'     => array ($p->mask),
2122                                        'attributes'    => $set_attributes_array
2123                                )
2124                        );
2125
2126                        return True;
2127                }
2128
2129                /*
2130                 * See vfs_shared
2131                 */
2132                function file_type ($data)
2133                {
2134                        if (!is_array ($data))
2135                        {
2136                                $data = array ();
2137                        }
2138
2139                        $default_values = array
2140                                (
2141                                        'relatives'     => array (RELATIVE_CURRENT)
2142                                );
2143
2144                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2145
2146                        $p = $this->path_parts (array(
2147                                        'string'        => $data['string'],
2148                                        'relatives'     => array ($data['relatives'][0])
2149                                )
2150                        );
2151
2152                        if (!$this->acl_check (array(
2153                                        'string'        => $p->fake_full_path,
2154                                        'relatives'     => array ($p->mask),
2155                                        'operation'     => PHPGW_ACL_READ,
2156                                        'must_exist'    => True
2157                                ))
2158                        )
2159                        {
2160                                return False;
2161                        }
2162
2163                        if ($p->outside)
2164                        {
2165                                if (is_dir ($p->real_full_path))
2166                                {
2167                                        return ('Directory');
2168                                }
2169
2170                                /*
2171                                   We don't return an empty string here, because it may still match with a database query
2172                                   because of linked directories
2173                                */
2174                        }
2175
2176                        /*
2177                           We don't use ls () because it calls file_type () to determine if it has been
2178                           passed a directory
2179                        */
2180                        $db2 = $GLOBALS['phpgw']->db;
2181                        $db2->query ("SELECT mime_type FROM phpgw_vfs WHERE directory='".
2182                                $db2->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2183                                $db2->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2184                        $db2->next_record ();
2185                        $mime_type = $db2->Record['mime_type'];
2186                        if(!$mime_type)
2187                        {
2188                                $mime_type = $this->get_ext_mime_type (array ('string' => $data['string']));
2189                                {
2190                                        $db2->query ("UPDATE phpgw_vfs SET mime_type='$mime_type' WHERE directory='".
2191                                                $db2->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2192                                                $db2->db_addslashes($p->fake_name_clean)."'" .
2193                                                $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2194                                }
2195                        }
2196
2197                        return $mime_type;
2198                }
2199
2200                /*
2201                 * See vfs_shared
2202                 */
2203                function file_exists ($data)
2204                {
2205                        if (!is_array ($data))
2206                        {
2207                                $data = array ();
2208                        }
2209
2210                        $default_values = array
2211                                (
2212                                        'relatives'     => array (RELATIVE_CURRENT)
2213                                );
2214
2215                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2216
2217                        $p = $this->path_parts (array(
2218                                        'string'        => $data['string'],
2219                                        'relatives'     => array ($data['relatives'][0])
2220                                )
2221                        );
2222
2223                        if ($p->outside)
2224                        {
2225                                $rr = file_exists ($p->real_full_path);
2226
2227                                return $rr;
2228                        }
2229
2230                        $db2 = $GLOBALS['phpgw']->db;
2231                        $db2->query ("SELECT name FROM phpgw_vfs WHERE directory='".
2232                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2233                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2234
2235                        if ($db2->next_record ())
2236                        {
2237                                return True;
2238                        }
2239                        else
2240                        {
2241                                return False;
2242                        }
2243                }
2244
2245                /*
2246                 * See vfs_shared
2247                 */
2248                function get_size ($data)
2249                {
2250                        if (!is_array ($data))
2251                        {
2252                                $data = array ();
2253                        }
2254
2255                        $default_values = array
2256                                (
2257                                        'relatives'     => array (RELATIVE_CURRENT),
2258                                        'checksubdirs'  => True
2259                                );
2260
2261                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2262
2263                        $p = $this->path_parts (array(
2264                                        'string'        => $data['string'],
2265                                        'relatives'     => array ($data['relatives'][0])
2266                                )
2267                        );
2268
2269                        if (!$this->acl_check (array(
2270                                        'string'        => $p->fake_full_path,
2271                                        'relatives'     => array ($p->mask),
2272                                        'operation'     => PHPGW_ACL_READ,
2273                                        'must_exist'    => True
2274                                ))
2275                        )
2276                        {
2277                                return False;
2278                        }
2279
2280                        /*
2281                           WIP - this should run through all of the subfiles/directories in the directory and tally up
2282                           their sizes.  Should modify ls () to be able to return a list for files outside the virtual root
2283                        */
2284                        if ($p->outside)
2285                        {
2286                                $size = filesize ($p->real_full_path);
2287
2288                                return $size;
2289                        }
2290
2291                        foreach($this->ls (array(
2292                                        'string'        => $p->fake_full_path,
2293                                        'relatives'     => array ($p->mask),
2294                                        'checksubdirs'  => $data['checksubdirs'],
2295                                        'nofiles'       => !$data['checksubdirs']
2296                                )) as $file_array)
2297                        {
2298                                /*
2299                                   Make sure the file is in the directory we want, and not
2300                                   some deeper nested directory with a similar name
2301                                */
2302/*
2303                                if (@!ereg ('^' . $file_array['directory'], $p->fake_full_path))
2304                                {
2305                                        continue;
2306                                }
2307*/
2308
2309                                $size += $file_array['size'];
2310                        }
2311
2312                        if ($data['checksubdirs'])
2313                        {
2314                                $query = $GLOBALS['phpgw']->db->query ("SELECT size FROM phpgw_vfs WHERE directory='".
2315                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2316                                        $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" .
2317                                        $this->extra_sql (array ('query_text' => VFS_SQL_SELECT)));
2318                                $GLOBALS['phpgw']->db->next_record ();
2319                                $size += $GLOBALS['phpgw']->db->Record[0];
2320                        }
2321
2322                        return $size;
2323                }
2324
2325                /*!
2326                @function checkperms
2327                @abstract Check if $this->working_id has write access to create files in $dir
2328                @discussion Simple call to acl_check
2329                @param string Directory to check access of
2330                @param relatives Relativity array
2331                @result Boolean True/False
2332                */
2333                function checkperms ($data)
2334                {
2335                        if (!is_array ($data))
2336                        {
2337                                $data = array ();
2338                        }
2339
2340                        $default_values = array
2341                                (
2342                                        'relatives'     => array (RELATIVE_CURRENT)
2343                                );
2344
2345                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2346
2347                        $p = $this->path_parts (array(
2348                                        'string'        => $data['string'],
2349                                        'relatives'     => array ($data['relatives'][0])
2350                                )
2351                        );
2352
2353                        if (!$this->acl_check (array(
2354                                        'string'        => $p->fake_full_path,
2355                                        'relatives'     => array ($p->mask),
2356                                        'operation'     => PHPGW_ACL_ADD
2357                                ))
2358                        )
2359                        {
2360                                return False;
2361                        }
2362                        else
2363                        {
2364                                return True;
2365                        }
2366                }
2367
2368                /*
2369                 * See vfs_shared
2370                 * If $data['readlink'] then a readlink is tryed on the real file
2371                 * If $data['file_id'] then the file_id is used instead of a path
2372                 */
2373                function ls ($data)
2374                {
2375                        if (!is_array ($data))
2376                        {
2377                                $data = array ();
2378                        }
2379
2380                        $default_values = array
2381                                (
2382                                        'relatives'     => array (RELATIVE_CURRENT),
2383                                        'checksubdirs'  => True,
2384                                        'mime_type'     => False,
2385                                        'nofiles'       => False,
2386                                        'orderby'       => 'directory'
2387                                );
2388
2389                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2390
2391                        $p = $this->path_parts (array(
2392                                        'string'        => $data['string'],
2393                                        'relatives'     => array ($data['relatives'][0])
2394                                )
2395                        );
2396                        $dir = $p->fake_full_path;
2397
2398                        /* If they pass us a file or 'nofiles' is set, return the info for $dir only */
2399                        if (@$data['file_id']
2400                                || ((($type = $this->file_type (array(
2401                                        'string'        => $dir,
2402                                        'relatives'     => array ($p->mask)
2403                                )) != 'Directory'))
2404                                || ($data['nofiles'])) && !$p->outside
2405                        )
2406                        {
2407                                /* SELECT all, the, attributes */
2408                                $sql = 'SELECT ';
2409
2410                                foreach ($this->attributes as $num => $attribute)
2411                                {
2412                                        if ($num)
2413                                        {
2414                                                $sql .= ', ';
2415                                        }
2416
2417                                        $sql .= $attribute;
2418                                }
2419
2420                                $sql .= " FROM phpgw_vfs WHERE ";
2421                                if (@$data['file_id'])
2422                                {
2423                                        $sql .= 'file_id='.(int)$data['file_id'];
2424                                }
2425                                else
2426                                {
2427                                        $sql .= "directory='".$GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean).
2428                                                "' AND name='".$GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'".
2429                                                $this->extra_sql (array ('query_type' => VFS_SQL_SELECT));
2430                                }
2431                                $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
2432
2433                                $GLOBALS['phpgw']->db->next_record ();
2434                                $record = $GLOBALS['phpgw']->db->Record;
2435
2436                                /* We return an array of one array to maintain the standard */
2437                                $rarray = array ();
2438                                foreach($this->attributes as $attribute)
2439                                {
2440                                        if ($attribute == 'mime_type' && !$record[$attribute])
2441                                        {
2442                                                $db2 = $GLOBALS['phpgw']->db;
2443                                                $record[$attribute] = $this->get_ext_mime_type (array(
2444                                                                'string' => $p->fake_name_clean
2445                                                        )
2446                                                );
2447
2448                                                if($record[$attribute])
2449                                                {
2450                                                        $db2->query ("UPDATE phpgw_vfs SET mime_type='".$record[$attribute]."' WHERE directory='".
2451                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2452                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2453                                                }
2454                                        }
2455
2456                                        $rarray[0][$attribute] = $record[$attribute];
2457                                }
2458                                if ($this->file_actions && @$data['readlink'])  // test if file is a symlink and get it's target
2459                                {
2460                                        $rarray[0]['symlink'] = @readlink($p->real_full_path);
2461                                }
2462
2463                                return $rarray;
2464                        }
2465
2466                        //WIP - this should recurse using the same options the virtual part of ls () does
2467                        /* If $dir is outside the virutal root, we have to check the file system manually */
2468                        if ($p->outside)
2469                        {
2470                                if ($this->file_type (array(
2471                                                'string'        => $p->fake_full_path,
2472                                                'relatives'     => array ($p->mask)
2473                                        )) == 'Directory'
2474                                        && !$data['nofiles']
2475                                )
2476                                {
2477                                        $dir_handle = opendir ($p->real_full_path);
2478                                        while ($filename = readdir ($dir_handle))
2479                                        {
2480                                                if ($filename == '.' || $filename == '..')
2481                                                {
2482                                                        continue;
2483                                                }
2484
2485                                                $rarray[] = $this->get_real_info (array(
2486                                                                'string'        => $p->real_full_path . SEP . $filename,
2487                                                                'relatives'     => array ($p->mask)
2488                                                        )
2489                                                );
2490                                        }
2491                                }
2492                                else
2493                                {
2494                                        $rarray[] = $this->get_real_info (array(
2495                                                        'string'        => $p->real_full_path,
2496                                                        'relatives'     => array ($p->mask)
2497                                                )
2498                                        );
2499                                }
2500
2501                                return $rarray;
2502                        }
2503
2504                        /* $dir's not a file, is inside the virtual root, and they want to check subdirs */
2505                        /* SELECT all, the, attributes FROM phpgw_vfs WHERE file=$dir */
2506                        $sql = 'SELECT ';
2507
2508                        foreach($this->attributes as $num => $attribute)
2509                        {
2510                                if ($num)
2511                                {
2512                                        $sql .= ", ";
2513                                }
2514
2515                                $sql .= $attribute;
2516                        }
2517
2518                        $dir_clean = $this->clean_string (array ('string' => $dir));
2519                        $sql .= " FROM phpgw_vfs WHERE directory LIKE '".$GLOBALS['phpgw']->db->db_addslashes($dir_clean)."%'";
2520                        $sql .= $this->extra_sql (array ('query_type' => VFS_SQL_SELECT));
2521
2522                        if ($data['mime_type'])
2523                        {
2524                                $sql .= " AND mime_type='".$data['mime_type']."'";
2525                        }
2526
2527                        $sql .= ' ORDER BY '.$data['orderby'];
2528
2529                        $query = $GLOBALS['phpgw']->db->query ($sql, __LINE__, __FILE__);
2530
2531                        $rarray = array ();
2532                        for ($i = 0; $GLOBALS['phpgw']->db->next_record (); $i++)
2533                        {
2534                                $record = $GLOBALS['phpgw']->db->Record;
2535
2536                                /* Further checking on the directory.  This makes sure /home/user/test won't match /home/user/test22 */
2537                                if (@!ereg ("^$dir(/|$)", $record['directory']))
2538                                {
2539                                        continue;
2540                                }
2541
2542                                /* If they want only this directory, then $dir should end without a trailing / */
2543                                if (!$data['checksubdirs'] && ereg ("^$dir/", $record['directory']))
2544                                {
2545                                        continue;
2546                                }
2547
2548                                foreach($this->attributes as $attribute)
2549                                {
2550                                        if ($attribute == 'mime_type' && !$record[$attribute])
2551                                        {
2552                                                $db2 = $GLOBALS['phpgw']->db;
2553                                                $record[$attribute] = $this->get_ext_mime_type (array(
2554                                                                'string'        => $p->fake_name_clean
2555                                                        )
2556                                                );
2557
2558                                                if($record[$attribute])
2559                                                {
2560                                                        $db2->query ("UPDATE phpgw_vfs SET mime_type='".$record[$attribute]."' WHERE directory='".
2561                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2562                                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" . $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2563                                                }
2564                                        }
2565
2566                                        $rarray[$i][$attribute] = $record[$attribute];
2567                                }
2568                        }
2569
2570                        return $rarray;
2571                }
2572
2573                /*
2574                 * See vfs_shared
2575                 */
2576                function update_real ($data,$recursive = False)
2577                {
2578                        if (!is_array ($data))
2579                        {
2580                                $data = array ();
2581                        }
2582
2583                        $default_values = array
2584                                (
2585                                        'relatives'     => array (RELATIVE_CURRENT)
2586                                );
2587
2588                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2589
2590                        $p = $this->path_parts (array(
2591                                        'string'        => $data['string'],
2592                                        'relatives'     => array ($data['relatives'][0])
2593                                )
2594                        );
2595
2596                        if (file_exists ($p->real_full_path))
2597                        {
2598                                if (is_dir ($p->real_full_path))
2599                                {
2600                                        $dir_handle = opendir ($p->real_full_path);
2601                                        while ($filename = readdir ($dir_handle))
2602                                        {
2603                                                if ($filename == '.' || $filename == '..')
2604                                                {
2605                                                        continue;
2606                                                }
2607
2608                                                $rarray[] = $this->get_real_info (array(
2609                                                                'string'        => $p->fake_full_path . '/' . $filename,
2610                                                                'relatives'     => array (RELATIVE_NONE)
2611                                                        )
2612                                                );
2613                                        }
2614                                }
2615                                else
2616                                {
2617                                        $rarray[] = $this->get_real_info (array(
2618                                                        'string'        => $p->fake_full_path,
2619                                                        'relatives'     => array (RELATIVE_NONE)
2620                                                )
2621                                        );
2622                                }
2623
2624                                if (!is_array ($rarray))
2625                                {
2626                                        $rarray = array ();
2627                                }
2628
2629                                foreach($rarray as $num => $file_array)
2630                                {
2631                                        $p2 = $this->path_parts (array(
2632                                                        'string'        => $file_array['directory'] . '/' . $file_array['name'],
2633                                                        'relatives'     => array (RELATIVE_NONE)
2634                                                )
2635                                        );
2636
2637                                        /* Note the mime_type.  This can be "Directory", which is how we create directories */
2638                                        $set_attributes_array = Array(
2639                                                'size' => $file_array['size'],
2640                                                'mime_type' => $file_array['mime_type']
2641                                        );
2642
2643                                        if (!$this->file_exists (array(
2644                                                        'string'        => $p2->fake_full_path,
2645                                                        'relatives'     => array (RELATIVE_NONE)
2646                                                ))
2647                                        )
2648                                        {
2649                                                $this->touch (array(
2650                                                                'string'        => $p2->fake_full_path,
2651                                                                'relatives'     => array (RELATIVE_NONE)
2652                                                        )
2653                                                );
2654                                        }
2655                                        $this->set_attributes (array(
2656                                                        'string'        => $p2->fake_full_path,
2657                                                        'relatives'     => array (RELATIVE_NONE),
2658                                                        'attributes'    => $set_attributes_array
2659                                                )
2660                                        );
2661                                        if ($recursive && $file_array['mime_type'] == 'Directory')
2662                                        {
2663                                                $dir_data = $data;
2664                                                $dir_data['string'] = $file_array['directory'] . '/' . $file_array['name'];
2665                                                $this->update_real($dir_data,$recursive);
2666                                        }
2667                                }
2668                        }
2669                }
2670
2671                /* Helper functions */
2672
2673                /* This fetchs all available file system information for string (not using the database) */
2674                function get_real_info ($data)
2675                {
2676                        if (!is_array ($data))
2677                        {
2678                                $data = array ();
2679                        }
2680
2681                        $default_values = array
2682                                (
2683                                        'relatives'     => array (RELATIVE_CURRENT)
2684                                );
2685
2686                        $data = array_merge ($this->default_values ($data, $default_values), $data);
2687
2688                        $p = $this->path_parts (array(
2689                                        'string'        => $data['string'],
2690                                        'relatives'     => array ($data['relatives'][0])
2691                                )
2692                        );
2693
2694                        if (is_dir ($p->real_full_path))
2695                        {
2696                                $mime_type = 'Directory';
2697                        }
2698                        else
2699                        {
2700                                $mime_type = $this->get_ext_mime_type (array(
2701                                                'string'        => $p->fake_name
2702                                        )
2703                                );
2704
2705                                if($mime_type)
2706                                {
2707                                        $GLOBALS['phpgw']->db->query ("UPDATE phpgw_vfs SET mime_type='".$mime_type."' WHERE directory='".
2708                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_leading_dirs_clean)."' AND name='".
2709                                                $GLOBALS['phpgw']->db->db_addslashes($p->fake_name_clean)."'" .
2710                                                $this->extra_sql (array ('query_type' => VFS_SQL_SELECT)), __LINE__, __FILE__);
2711                                }
2712                        }
2713
2714                        $size = filesize ($p->real_full_path);
2715                        $rarray = array(
2716                                'directory' => $p->fake_leading_dirs,
2717                                'name' => $p->fake_name,
2718                                'size' => $size,
2719                                'mime_type' => $mime_type
2720                        );
2721
2722                        return ($rarray);
2723                }
2724        }
2725?>
Note: See TracBrowser for help on using the repository browser.