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

Revision 1575, 66.2 KB checked in by amuller, 14 years ago (diff)

Ticket #597 - Implentação, melhorias do modulo gerenciador de arquivos

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