2016-02-19 08:06:10 +00:00
< ? php
namespace Zotlabs\Storage ;
2020-05-06 04:34:31 +00:00
use App ;
2016-02-19 08:06:10 +00:00
use Sabre\DAV ;
2018-06-05 01:40:11 +00:00
use Zotlabs\Lib\Libsync ;
2020-06-15 07:29:56 +00:00
use Zotlabs\Daemon\Run ;
2020-05-06 04:34:31 +00:00
require_once ( 'include/photos.php' );
2016-02-19 08:06:10 +00:00
/**
* @ brief RedDirectory class .
*
* A class that represents a directory .
*
2016-10-01 22:41:25 +00:00
* @ extends \\Sabre\\DAV\\Node
* @ implements \\Sabre\\DAV\\ICollection
* @ implements \\Sabre\\DAV\\IQuota
2016-02-19 08:06:10 +00:00
*
* @ license http :// opensource . org / licenses / mit - license . php The MIT License ( MIT )
*/
2017-12-07 00:07:40 +00:00
class Directory extends DAV\Node implements DAV\ICollection , DAV\IQuota , DAV\IMoveTarget {
2016-02-19 08:06:10 +00:00
/**
* @ brief The path inside / cloud
*
2016-10-01 22:41:25 +00:00
* @ var string $red_path
2016-02-19 08:06:10 +00:00
*/
private $red_path ;
private $folder_hash ;
/**
* @ brief The full path as seen in the browser .
* / cloud + $red_path
* @ todo I think this is not used anywhere , we always strip '/cloud' and only use it in debug
2016-10-01 22:41:25 +00:00
* @ var string $ext_path
2016-02-19 08:06:10 +00:00
*/
private $ext_path ;
private $root_dir = '' ;
private $auth ;
/**
* @ brief The real path on the filesystem .
* The actual path in store / with the hashed names .
*
2016-10-01 22:41:25 +00:00
* @ var string $os_path
2016-02-19 08:06:10 +00:00
*/
private $os_path = '' ;
/**
* @ brief Sets up the directory node , expects a full path .
*
* @ param string $ext_path a full path
2016-10-01 22:41:25 +00:00
* @ param BasicAuth & $auth_plugin
2016-02-19 08:06:10 +00:00
*/
public function __construct ( $ext_path , & $auth_plugin ) {
2017-03-23 02:31:43 +00:00
// $ext_path = urldecode($ext_path);
2016-02-19 08:06:10 +00:00
logger ( 'directory ' . $ext_path , LOGGER_DATA );
$this -> ext_path = $ext_path ;
// remove "/cloud" from the beginning of the path
2020-05-06 04:34:31 +00:00
$modulename = App :: $module ;
2016-02-19 08:06:10 +00:00
$this -> red_path = (( strpos ( $ext_path , '/' . $modulename ) === 0 ) ? substr ( $ext_path , strlen ( $modulename ) + 1 ) : $ext_path );
2020-05-06 04:34:31 +00:00
if ( ! $this -> red_path ) {
2016-02-19 08:06:10 +00:00
$this -> red_path = '/' ;
}
$this -> auth = $auth_plugin ;
$this -> folder_hash = '' ;
$this -> getDir ();
2016-10-01 22:41:25 +00:00
if ( $this -> auth -> browser ) {
2016-02-19 08:06:10 +00:00
$this -> auth -> browser -> set_writeable ();
}
}
private function log () {
logger ( 'ext_path ' . $this -> ext_path , LOGGER_DATA );
logger ( 'os_path ' . $this -> os_path , LOGGER_DATA );
logger ( 'red_path ' . $this -> red_path , LOGGER_DATA );
}
/**
* @ brief Returns an array with all the child nodes .
*
2016-10-01 22:41:25 +00:00
* @ throw " \ Sabre \ DAV \ Exception \ Forbidden "
* @ return array \\Sabre\\DAV\\INode []
2016-02-19 08:06:10 +00:00
*/
public function getChildren () {
logger ( 'children for ' . $this -> ext_path , LOGGER_DATA );
$this -> log ();
if ( get_config ( 'system' , 'block_public' ) && ( ! $this -> auth -> channel_id ) && ( ! $this -> auth -> observer )) {
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
if (( $this -> auth -> owner_id ) && ( ! perm_is_allowed ( $this -> auth -> owner_id , $this -> auth -> observer , 'view_storage' ))) {
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
2016-07-06 00:54:05 +00:00
$contents = $this -> CollectionData ( $this -> red_path , $this -> auth );
2016-02-19 08:06:10 +00:00
return $contents ;
}
/**
* @ brief Returns a child by name .
*
2016-10-01 22:41:25 +00:00
* @ throw " \ Sabre \ DAV \ Exception \ Forbidden "
* @ throw " \ Sabre \ DAV \ Exception \N otFound "
2016-02-19 08:06:10 +00:00
* @ param string $name
*/
public function getChild ( $name ) {
logger ( $name , LOGGER_DATA );
if ( get_config ( 'system' , 'block_public' ) && ( ! $this -> auth -> channel_id ) && ( ! $this -> auth -> observer )) {
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
if (( $this -> auth -> owner_id ) && ( ! perm_is_allowed ( $this -> auth -> owner_id , $this -> auth -> observer , 'view_storage' ))) {
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
2020-05-06 04:34:31 +00:00
$modulename = App :: $module ;
2016-02-19 08:06:10 +00:00
if ( $this -> red_path === '/' && $name === $modulename ) {
return new Directory ( '/' . $modulename , $this -> auth );
}
2016-07-06 00:54:05 +00:00
$x = $this -> FileData ( $this -> ext_path . '/' . $name , $this -> auth );
2016-02-19 08:06:10 +00:00
if ( $x ) {
return $x ;
}
throw new DAV\Exception\NotFound ( 'The file with name: ' . $name . ' could not be found.' );
}
/**
* @ brief Returns the name of the directory .
*
* @ return string
*/
public function getName () {
return ( basename ( $this -> red_path ));
}
/**
* @ brief Renames the directory .
*
* @ todo handle duplicate directory name
*
2016-10-01 22:41:25 +00:00
* @ throw " \ Sabre \ DAV \ Exception \ Forbidden "
2016-02-19 08:06:10 +00:00
* @ param string $name The new name of the directory .
* @ return void
*/
public function setName ( $name ) {
logger ( 'old name ' . basename ( $this -> red_path ) . ' -> ' . $name , LOGGER_DATA );
if (( ! $name ) || ( ! $this -> auth -> owner_id )) {
logger ( 'permission denied ' . $name );
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
if ( ! perm_is_allowed ( $this -> auth -> owner_id , $this -> auth -> observer , 'write_storage' )) {
logger ( 'permission denied ' . $name );
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
2016-09-28 19:53:16 +00:00
list ( $parent_path , ) = \Sabre\Uri\split ( $this -> red_path );
2016-02-19 08:06:10 +00:00
$new_path = $parent_path . '/' . $name ;
$r = q ( " UPDATE attach SET filename = '%s' WHERE hash = '%s' AND uid = %d " ,
dbesc ( $name ),
dbesc ( $this -> folder_hash ),
intval ( $this -> auth -> owner_id )
);
2017-03-23 02:31:43 +00:00
$x = attach_syspaths ( $this -> auth -> owner_id , $this -> folder_hash );
2018-04-27 09:34:52 +00:00
$y = q ( " update attach set display_path = '%s' where hash = '%s' and uid = %d " ,
2017-03-23 02:31:43 +00:00
dbesc ( $x [ 'path' ]),
dbesc ( $this -> folder_hash ),
intval ( $this -> auth -> owner_id )
);
2016-04-08 01:54:48 +00:00
$ch = channelx_by_n ( $this -> auth -> owner_id );
2016-09-28 19:53:16 +00:00
if ( $ch ) {
$sync = attach_export_data ( $ch , $this -> folder_hash );
2020-05-06 04:34:31 +00:00
if ( $sync ) {
2018-06-05 01:40:11 +00:00
Libsync :: build_sync_packet ( $ch [ 'channel_id' ], array ( 'file' => array ( $sync )));
2020-05-06 04:34:31 +00:00
}
2016-04-08 01:54:48 +00:00
}
2016-02-19 08:06:10 +00:00
$this -> red_path = $new_path ;
}
/**
* @ brief Creates a new file in the directory .
*
* Data will either be supplied as a stream resource , or in certain cases
* as a string . Keep in mind that you may have to support either .
*
* After successful creation of the file , you may choose to return the ETag
* of the new file here .
*
2016-10-01 22:41:25 +00:00
* @ throw " \ Sabre \ DAV \ Exception \ Forbidden "
2016-02-19 08:06:10 +00:00
* @ param string $name Name of the file
* @ param resource | string $data Initial payload
* @ return null | string ETag
*/
public function createFile ( $name , $data = null ) {
2016-05-17 10:27:15 +00:00
logger ( 'create file in directory ' . $name , LOGGER_DEBUG );
2016-02-19 08:06:10 +00:00
if ( ! $this -> auth -> owner_id ) {
logger ( 'permission denied ' . $name );
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
if ( ! perm_is_allowed ( $this -> auth -> owner_id , $this -> auth -> observer , 'write_storage' )) {
logger ( 'permission denied ' . $name );
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
$mimetype = z_mime_content_type ( $name );
2020-05-06 04:34:31 +00:00
$channel = channelx_by_n ( $this -> auth -> owner_id );
2016-02-19 08:06:10 +00:00
2020-05-06 04:34:31 +00:00
if ( ! $channel ) {
2016-02-19 08:06:10 +00:00
logger ( 'no channel' );
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
$filesize = 0 ;
2018-10-29 03:39:01 +00:00
$hash = new_uuid ();
2016-02-19 08:06:10 +00:00
$f = 'store/' . $this -> auth -> owner_nick . '/' . (( $this -> os_path ) ? $this -> os_path . '/' : '' ) . $hash ;
$direct = null ;
2016-09-28 19:53:16 +00:00
if ( $this -> folder_hash ) {
2016-02-19 08:06:10 +00:00
$r = q ( " select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1 " ,
dbesc ( $this -> folder_hash ),
2020-05-06 04:34:31 +00:00
intval ( $channel [ 'channel_id' ])
2016-02-19 08:06:10 +00:00
);
2020-05-06 04:34:31 +00:00
if ( $r ) {
$direct = array_shift ( $r );
}
2016-02-19 08:06:10 +00:00
}
2016-09-28 19:53:16 +00:00
if (( $direct ) && (( $direct [ 'allow_cid' ]) || ( $direct [ 'allow_gid' ]) || ( $direct [ 'deny_cid' ]) || ( $direct [ 'deny_gid' ]))) {
2016-02-19 08:06:10 +00:00
$allow_cid = $direct [ 'allow_cid' ];
$allow_gid = $direct [ 'allow_gid' ];
2020-05-06 04:34:31 +00:00
$deny_cid = $direct [ 'deny_cid' ];
$deny_gid = $direct [ 'deny_gid' ];
2016-02-19 08:06:10 +00:00
}
2016-09-28 19:53:16 +00:00
else {
2020-05-06 04:34:31 +00:00
$allow_cid = $channel [ 'channel_allow_cid' ];
$allow_gid = $channel [ 'channel_allow_gid' ];
$deny_cid = $channel [ 'channel_deny_cid' ];
$deny_gid = $channel [ 'channel_deny_gid' ];
2016-02-19 08:06:10 +00:00
}
2020-05-06 04:34:31 +00:00
$created = $edited = datetime_convert ();
2016-10-13 14:02:18 +00:00
$r = q ( " INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, content, created, edited, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid )
VALUES ( % d , % d , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , % d , % d , % d , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' ) " ,
2020-05-06 04:34:31 +00:00
intval ( $channel [ 'channel_account_id' ]),
intval ( $channel [ 'channel_id' ]),
2016-02-19 08:06:10 +00:00
dbesc ( $hash ),
dbesc ( $this -> auth -> observer ),
dbesc ( $name ),
dbesc ( $this -> folder_hash ),
intval ( 1 ),
dbesc ( $mimetype ),
intval ( $filesize ),
intval ( 0 ),
2020-05-06 04:34:31 +00:00
intval ( 0 ),
2016-02-19 08:06:10 +00:00
dbesc ( $f ),
2020-05-06 04:34:31 +00:00
dbesc ( $created ),
dbesc ( $edited ),
2017-03-23 02:31:43 +00:00
'' ,
'' ,
2016-02-19 08:06:10 +00:00
dbesc ( $allow_cid ),
dbesc ( $allow_gid ),
dbesc ( $deny_cid ),
dbesc ( $deny_gid )
);
2017-03-23 02:31:43 +00:00
// fetch the actual storage paths
$xpath = attach_syspaths ( $this -> auth -> owner_id , $hash );
2020-05-06 04:34:31 +00:00
if ( is_resource ( $data )) {
$fp = fopen ( $f , 'wb' );
if ( $fp ) {
pipe_streams ( $data , $fp );
fclose ( $fp );
}
$size = filesize ( $f );
}
else {
$size = file_put_contents ( $f , $data );
}
2016-02-19 08:06:10 +00:00
// delete attach entry if file_put_contents() failed
if ( $size === false ) {
logger ( 'file_put_contents() failed to ' . $f );
2020-05-06 04:34:31 +00:00
attach_delete ( $channel [ 'channel_id' ], $hash );
2016-02-19 08:06:10 +00:00
return ;
}
$is_photo = 0 ;
2017-03-23 02:31:43 +00:00
$gis = @ getimagesize ( $f );
logger ( 'getimagesize: ' . print_r ( $gis , true ), LOGGER_DATA );
2020-05-06 04:34:31 +00:00
if (( $gis ) && supported_imagetype ( $gis [ 2 ])) {
2016-02-19 08:06:10 +00:00
$is_photo = 1 ;
}
2017-11-15 01:39:33 +00:00
// If we know it's a photo, over-ride the type in case the source system could not determine what it was
2020-05-06 04:34:31 +00:00
if ( $is_photo ) {
2017-11-15 01:39:33 +00:00
q ( " update attach set filetype = '%s' where hash = '%s' and uid = %d " ,
dbesc ( $gis [ 'mime' ]),
dbesc ( $hash ),
2020-05-06 04:34:31 +00:00
intval ( $channel [ 'channel_id' ])
2017-11-15 01:39:33 +00:00
);
}
2020-05-06 04:34:31 +00:00
// updates entry with path and filesize
$d = q ( " UPDATE attach SET filesize = '%s', os_path = '%s', display_path = '%s', is_photo = %d WHERE hash = '%s' AND uid = %d " ,
2016-02-19 08:06:10 +00:00
dbesc ( $size ),
2017-03-23 02:31:43 +00:00
dbesc ( $xpath [ 'os_path' ]),
2020-05-06 04:34:31 +00:00
dbesc ( $xpath [ 'path' ]),
2016-02-19 08:06:10 +00:00
intval ( $is_photo ),
dbesc ( $hash ),
2020-05-06 04:34:31 +00:00
intval ( $channel [ 'channel_id' ])
2016-02-19 08:06:10 +00:00
);
2020-05-06 04:34:31 +00:00
// update the parent folder's lastmodified timestamp
2016-02-19 08:06:10 +00:00
$e = q ( " UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d " ,
dbesc ( $edited ),
dbesc ( $this -> folder_hash ),
2020-05-06 04:34:31 +00:00
intval ( $channel [ 'channel_id' ])
2016-02-19 08:06:10 +00:00
);
$maxfilesize = get_config ( 'system' , 'maxfilesize' );
if (( $maxfilesize ) && ( $size > $maxfilesize )) {
2020-05-06 04:34:31 +00:00
logger ( 'system maxfilesize exceeded. Deleting uploaded file.' );
attach_delete ( $channel [ 'channel_id' ], $hash );
2016-02-19 08:06:10 +00:00
return ;
}
// check against service class quota
2020-05-06 04:34:31 +00:00
$limit = engr_units_to_bytes ( service_class_fetch ( $channel [ 'channel_id' ], 'attach_upload_limit' ));
2016-02-19 08:06:10 +00:00
if ( $limit !== false ) {
2017-03-23 02:31:43 +00:00
$z = q ( " SELECT SUM(filesize) AS total FROM attach WHERE aid = %d " ,
2020-05-06 04:34:31 +00:00
intval ( $channel [ 'channel_account_id' ])
2016-02-19 08:06:10 +00:00
);
2017-03-23 02:31:43 +00:00
if (( $z ) && ( $z [ 0 ][ 'total' ] + $size > $limit )) {
2020-05-06 04:34:31 +00:00
logger ( 'service class limit exceeded for ' . $channel [ 'channel_name' ] . ' total usage is ' . $z [ 0 ][ 'total' ] . ' limit is ' . userReadableSize ( $limit ));
attach_delete ( $channel [ 'channel_id' ], $hash );
2016-02-19 08:06:10 +00:00
return ;
}
}
2020-05-06 04:34:31 +00:00
if ( $is_photo ) {
2016-02-19 08:06:10 +00:00
$album = '' ;
2016-09-28 19:53:16 +00:00
if ( $this -> folder_hash ) {
2017-03-23 02:31:43 +00:00
$f1 = q ( " select filename, display_path from attach WHERE hash = '%s' AND uid = %d " ,
2016-02-19 08:06:10 +00:00
dbesc ( $this -> folder_hash ),
2020-05-06 04:34:31 +00:00
intval ( $channel [ 'channel_id' ])
2016-02-19 08:06:10 +00:00
);
2020-05-06 04:34:31 +00:00
if ( $f1 ) {
2017-03-23 02:31:43 +00:00
$album = (( $f1 [ 0 ][ 'display_path' ]) ? $f1 [ 0 ][ 'display_path' ] : $f1 [ 0 ][ 'filename' ]);
2020-05-06 04:34:31 +00:00
}
2016-02-19 08:06:10 +00:00
}
2020-05-06 04:34:31 +00:00
$args = [
'resource_id' => $hash ,
'album' => $album ,
2021-04-01 01:25:14 +00:00
'folder' => $this -> folder_hash ,
2020-05-06 04:34:31 +00:00
'os_syspath' => $f ,
'os_path' => $xpath [ 'os_path' ],
'display_path' => $xpath [ 'path' ],
'filename' => $name ,
'getimagesize' => $gis ,
'directory' => $direct
];
$p = photo_upload ( $channel , App :: get_observer (), $args );
2016-02-19 08:06:10 +00:00
}
2017-11-20 00:56:59 +00:00
2020-06-15 07:29:56 +00:00
Run :: Summon ([ 'Thumbnail' , $hash ]);
2016-02-19 08:06:10 +00:00
2020-05-06 04:34:31 +00:00
$sync = attach_export_data ( $channel , $hash );
2016-04-07 03:25:52 +00:00
2020-05-06 04:34:31 +00:00
if ( $sync ) {
Libsync :: build_sync_packet ( $channel [ 'channel_id' ], array ( 'file' => array ( $sync )));
}
2016-02-19 08:06:10 +00:00
}
/**
* @ brief Creates a new subdirectory .
*
* @ param string $name the directory to create
* @ return void
*/
public function createDirectory ( $name ) {
2016-05-17 10:27:15 +00:00
logger ( 'create directory ' . $name , LOGGER_DEBUG );
2016-02-19 08:06:10 +00:00
if (( ! $this -> auth -> owner_id ) || ( ! perm_is_allowed ( $this -> auth -> owner_id , $this -> auth -> observer , 'write_storage' ))) {
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
2020-05-06 04:34:31 +00:00
$channel = channelx_by_n ( $this -> auth -> owner_id );
2016-02-19 08:06:10 +00:00
2020-05-06 04:34:31 +00:00
if ( $channel ) {
2018-04-27 00:25:58 +00:00
// When initiated from DAV, set the 'force' flag on attach_mkdir(). This will cause the operation to report success even if the
// folder already exists.
2016-07-17 15:52:21 +00:00
require_once ( 'include/attach.php' );
2020-05-06 04:34:31 +00:00
$result = attach_mkdir ( $channel , $this -> auth -> observer , array ( 'filename' => $name , 'folder' => $this -> folder_hash , 'force' => true ));
2016-04-08 01:54:48 +00:00
2020-05-06 04:34:31 +00:00
if ( $result [ 'success' ]) {
$sync = attach_export_data ( $channel , $result [ 'data' ][ 'hash' ]);
2016-05-17 10:27:15 +00:00
logger ( 'createDirectory: attach_export_data returns $sync:' . print_r ( $sync , true ), LOGGER_DEBUG );
2020-05-06 04:34:31 +00:00
if ( $sync ) {
Libsync :: build_sync_packet ( $channel [ 'channel_id' ], array ( 'file' => array ( $sync )));
2016-04-08 01:54:48 +00:00
}
}
2016-09-28 19:53:16 +00:00
else {
2016-02-19 08:06:10 +00:00
logger ( 'error ' . print_r ( $result , true ), LOGGER_DEBUG );
}
}
}
/**
* @ brief delete directory
*/
public function delete () {
logger ( 'delete file ' . basename ( $this -> red_path ), LOGGER_DEBUG );
if (( ! $this -> auth -> owner_id ) || ( ! perm_is_allowed ( $this -> auth -> owner_id , $this -> auth -> observer , 'write_storage' ))) {
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
if ( $this -> auth -> owner_id !== $this -> auth -> channel_id ) {
if (( $this -> auth -> observer !== $this -> data [ 'creator' ]) || intval ( $this -> data [ 'is_dir' ])) {
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
}
attach_delete ( $this -> auth -> owner_id , $this -> folder_hash );
2016-04-08 01:54:48 +00:00
2020-05-06 04:34:31 +00:00
$channel = channelx_by_n ( $this -> auth -> owner_id );
if ( $channel ) {
$sync = attach_export_data ( $channel , $this -> folder_hash , true );
if ( $sync ) {
Libsync :: build_sync_packet ( $channel [ 'channel_id' ], array ( 'file' => array ( $sync )));
}
2016-04-08 01:54:48 +00:00
}
2016-02-19 08:06:10 +00:00
}
/**
* @ brief Checks if a child exists .
*
* @ param string $name
* The name to check if it exists .
* @ return boolean
*/
public function childExists ( $name ) {
// On /cloud we show a list of available channels.
// @todo what happens if no channels are available?
2020-05-06 04:34:31 +00:00
$modulename = App :: $module ;
2016-02-19 08:06:10 +00:00
if ( $this -> red_path === '/' && $name === $modulename ) {
//logger('We are at ' $modulename . ' show a channel list', LOGGER_DEBUG);
return true ;
}
2016-07-06 00:54:05 +00:00
$x = $this -> FileData ( $this -> ext_path . '/' . $name , $this -> auth , true );
//logger('FileData returns: ' . print_r($x, true), LOGGER_DATA);
2020-05-06 04:34:31 +00:00
if ( $x ) {
2016-02-19 08:06:10 +00:00
return true ;
2020-05-06 04:34:31 +00:00
}
2016-02-19 08:06:10 +00:00
return false ;
}
2017-12-07 00:07:40 +00:00
public function moveInto ( $targetName , $sourcePath , DAV\INode $sourceNode ) {
2020-05-06 04:34:31 +00:00
if ( ! $this -> auth -> owner_id ) {
2017-12-07 00:07:40 +00:00
return false ;
}
2020-12-07 02:42:28 +00:00
if ( ! ( $sourceNode -> data && $sourceNode -> data [ 'hash' ])) {
2017-12-07 00:07:40 +00:00
return false ;
}
2020-12-07 02:42:28 +00:00
return attach_move ( $this -> auth -> owner_id , $sourceNode -> data [ 'hash' ], $this -> folder_hash );
2017-12-07 00:07:40 +00:00
}
2016-02-19 08:06:10 +00:00
/**
* @ todo add description of what this function does .
*
2016-10-01 22:41:25 +00:00
* @ throw " \ Sabre \ DAV \ Exception \N otFound "
2016-02-19 08:06:10 +00:00
* @ return void
*/
function getDir () {
logger ( 'GetDir: ' . $this -> ext_path , LOGGER_DEBUG );
$this -> auth -> log ();
2020-05-06 04:34:31 +00:00
$modulename = App :: $module ;
2016-02-19 08:06:10 +00:00
$file = $this -> ext_path ;
$x = strpos ( $file , '/' . $modulename );
if ( $x === 0 ) {
$file = substr ( $file , strlen ( $modulename ) + 1 );
}
if (( ! $file ) || ( $file === '/' )) {
return ;
}
$file = trim ( $file , '/' );
$path_arr = explode ( '/' , $file );
if ( ! $path_arr )
return ;
logger ( 'paths: ' . print_r ( $path_arr , true ), LOGGER_DATA );
$channel_name = $path_arr [ 0 ];
2020-05-06 04:34:31 +00:00
$channel = channelx_by_nick ( $channel_name );
2016-02-19 08:06:10 +00:00
2020-05-06 04:34:31 +00:00
if ( ! $channel ) {
2016-02-19 08:06:10 +00:00
throw new DAV\Exception\NotFound ( 'The file with name: ' . $channel_name . ' could not be found.' );
}
2020-05-06 04:34:31 +00:00
$channel_id = $channel [ 'channel_id' ];
2016-02-19 08:06:10 +00:00
$this -> auth -> owner_id = $channel_id ;
$this -> auth -> owner_nick = $channel_name ;
$path = '/' . $channel_name ;
$folder = '' ;
$os_path = '' ;
for ( $x = 1 ; $x < count ( $path_arr ); $x ++ ) {
$r = q ( " select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 " ,
dbesc ( $folder ),
dbesc ( $path_arr [ $x ]),
intval ( $channel_id )
);
if ( $r && intval ( $r [ 0 ][ 'is_dir' ])) {
$folder = $r [ 0 ][ 'hash' ];
2020-05-06 04:34:31 +00:00
if ( strlen ( $os_path )) {
2016-02-19 08:06:10 +00:00
$os_path .= '/' ;
2020-05-06 04:34:31 +00:00
}
2016-02-19 08:06:10 +00:00
$os_path .= $folder ;
$path = $path . '/' . $r [ 0 ][ 'filename' ];
}
}
$this -> folder_hash = $folder ;
$this -> os_path = $os_path ;
}
/**
* @ brief Returns the last modification time for the directory , as a UNIX
* timestamp .
*
* It looks for the last edited file in the folder . If it is an empty folder
* it returns the lastmodified time of the folder itself , to prevent zero
* timestamps .
*
* @ return int last modification time in UNIX timestamp
*/
public function getLastModified () {
$r = q ( " SELECT edited FROM attach WHERE folder = '%s' AND uid = %d ORDER BY edited DESC LIMIT 1 " ,
dbesc ( $this -> folder_hash ),
intval ( $this -> auth -> owner_id )
);
if ( ! $r ) {
$r = q ( " SELECT edited FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1 " ,
dbesc ( $this -> folder_hash ),
intval ( $this -> auth -> owner_id )
);
if ( ! $r )
return '' ;
}
return datetime_convert ( 'UTC' , 'UTC' , $r [ 0 ][ 'edited' ], 'U' );
}
2016-07-06 00:54:05 +00:00
/**
2016-10-01 22:41:25 +00:00
* @ brief Array with all Directory and File DAV\\Node items for the given path .
2016-07-06 00:54:05 +00:00
*
* @ param string $file path to a directory
* @ param \Zotlabs\Storage\BasicAuth & $auth
2016-10-01 22:41:25 +00:00
* @ returns null | array \\Sabre\\DAV\\INode []
* @ throw " \ Sabre \ DAV \ Exception \ Forbidden "
* @ throw " \ Sabre \ DAV \ Exception \N otFound "
2016-07-06 00:54:05 +00:00
*/
function CollectionData ( $file , & $auth ) {
2021-03-15 05:10:44 +00:00
$ret = [];
2016-07-06 00:54:05 +00:00
$x = strpos ( $file , '/cloud' );
if ( $x === 0 ) {
$file = substr ( $file , 6 );
}
// return a list of channel if we are not inside a channel
if (( ! $file ) || ( $file === '/' )) {
return $this -> ChannelList ( $auth );
}
$file = trim ( $file , '/' );
$path_arr = explode ( '/' , $file );
2020-05-06 04:34:31 +00:00
if ( ! $path_arr ) {
2016-07-06 00:54:05 +00:00
return null ;
2020-05-06 04:34:31 +00:00
}
2016-07-06 00:54:05 +00:00
$channel_name = $path_arr [ 0 ];
2020-05-06 04:34:31 +00:00
$channel = channelx_by_nick ( $channel_name );
2016-07-06 00:54:05 +00:00
2020-05-06 04:34:31 +00:00
if ( ! $channel ) {
2016-07-06 00:54:05 +00:00
return null ;
2020-05-06 04:34:31 +00:00
}
2016-07-06 00:54:05 +00:00
2020-05-06 04:34:31 +00:00
$channel_id = $channel [ 'channel_id' ];
2016-07-06 00:54:05 +00:00
$perms = permissions_sql ( $channel_id );
$auth -> owner_id = $channel_id ;
$path = '/' . $channel_name ;
$folder = '' ;
$errors = false ;
$permission_error = false ;
for ( $x = 1 ; $x < count ( $path_arr ); $x ++ ) {
$r = q ( " SELECT id, hash, filename, flags, is_dir FROM attach WHERE folder = '%s' AND filename = '%s' AND uid = %d AND is_dir != 0 $perms LIMIT 1 " ,
dbesc ( $folder ),
dbesc ( $path_arr [ $x ]),
intval ( $channel_id )
);
if ( ! $r ) {
// path wasn't found. Try without permissions to see if it was the result of permissions.
$errors = true ;
$r = q ( " select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 limit 1 " ,
dbesc ( $folder ),
basename ( $path_arr [ $x ]),
intval ( $channel_id )
);
if ( $r ) {
$permission_error = true ;
}
break ;
}
if ( $r && intval ( $r [ 0 ][ 'is_dir' ])) {
$folder = $r [ 0 ][ 'hash' ];
$path = $path . '/' . $r [ 0 ][ 'filename' ];
}
}
if ( $errors ) {
if ( $permission_error ) {
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
2016-09-28 19:53:16 +00:00
}
2016-07-06 00:54:05 +00:00
else {
2018-03-16 22:34:09 +00:00
throw new DAV\Exception\NotFound ( 'A component of the requested file path could not be found.' );
2016-07-06 00:54:05 +00:00
}
}
// This should no longer be needed since we just returned errors for paths not found
if ( $path !== '/' . $file ) {
logger ( " Path mismatch: $path !== / $file " );
return NULL ;
}
2017-03-23 02:31:43 +00:00
$prefix = '' ;
2018-03-22 04:19:18 +00:00
if ( ! array_key_exists ( 'cloud_sort' , $_SESSION ))
$_SESSION [ 'cloud_sort' ] = 'name' ;
switch ( $_SESSION [ 'cloud_sort' ]) {
case 'size' :
$suffix = ' order by is_dir desc, filesize asc ' ;
break ;
// The following provides inconsistent results for directories because we re-calculate the date for directories based on the most recent change
case 'date' :
$suffix = ' order by is_dir desc, edited asc ' ;
break ;
case 'name' :
default :
$suffix = ' order by is_dir desc, filename asc ' ;
break ;
}
2017-03-23 02:31:43 +00:00
2016-07-06 00:54:05 +00:00
$r = q ( " select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix " ,
dbesc ( $folder ),
intval ( $channel_id )
);
foreach ( $r as $rr ) {
2020-05-06 04:34:31 +00:00
if ( App :: $module === 'cloud' && ( strpos ( $rr [ 'filename' ], '.' ) === 0 ) && ( ! get_pconfig ( $channel_id , 'system' , 'show_dot_files' )) ) {
2018-05-09 06:01:24 +00:00
continue ;
2020-05-06 04:34:31 +00:00
}
2017-03-23 02:31:43 +00:00
// @FIXME I don't think we use revisions currently in attach structures.
// In case we see any in the wild provide a unique filename. This
// name may or may not be accessible
2020-05-06 04:34:31 +00:00
if ( $rr [ 'revision' ]) {
2017-03-23 02:31:43 +00:00
$rr [ 'filename' ] .= '-' . $rr [ 'revision' ];
2020-05-06 04:34:31 +00:00
}
2017-03-23 02:31:43 +00:00
2020-05-06 04:34:31 +00:00
// logger('filename: ' . $rr['filename'], LOGGER_DEBUG);
2016-07-06 00:54:05 +00:00
if ( intval ( $rr [ 'is_dir' ])) {
$ret [] = new Directory ( $path . '/' . $rr [ 'filename' ], $auth );
2016-09-28 19:53:16 +00:00
}
2016-07-06 00:54:05 +00:00
else {
$ret [] = new File ( $path . '/' . $rr [ 'filename' ], $rr , $auth );
}
}
return $ret ;
}
/**
* @ brief Returns an array with viewable channels .
*
* Get a list of Directory objects with all the channels where the visitor
* has < b > view_storage </ b > perms .
*
*
* @ param BasicAuth & $auth
* @ return array Directory []
*/
function ChannelList ( & $auth ) {
2019-08-14 05:39:20 +00:00
$ret = [];
2021-08-05 07:48:21 +00:00
$disabled = intval ( get_config ( 'system' , 'cloud_disable_siteroot' ));
2021-05-29 23:43:34 +00:00
$r = q ( " SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0 and profile.is_default = 1 " ,
2016-07-06 00:54:05 +00:00
intval ( PAGE_HIDDEN )
);
if ( $r ) {
foreach ( $r as $rr ) {
2021-05-29 23:43:34 +00:00
if (( perm_is_allowed ( $rr [ 'channel_id' ], $auth -> observer , 'view_storage' ) && $rr [ 'publish' ]) || $rr [ 'channel_id' ] == $this -> auth -> channel_id ) {
logger ( 'found channel: /cloud/' . $rr [ 'channel_address' ], LOGGER_DATA );
2021-08-05 07:48:21 +00:00
if ( $disabled ) {
$conn = q ( " select abook_id from abook where abook_channel = %d and abook_xchan = '%s' and abook_pending = 0 " ,
intval ( $rr [ 'channel_id' ]),
dbesc ( $auth -> observer )
);
if ( ! $conn ) {
continue ;
}
}
2019-08-14 05:30:30 +00:00
$ret [] = new Directory ( $rr [ 'channel_address' ], $auth );
2016-07-06 00:54:05 +00:00
}
}
}
return $ret ;
}
/**
2016-09-28 19:53:16 +00:00
* @ brief
2016-07-06 00:54:05 +00:00
*
* @ param string $file
* path to file or directory
* @ param BasicAuth & $auth
* @ param boolean $test ( optional ) enable test mode
* @ return File | Directory | boolean | null
2016-10-01 22:41:25 +00:00
* @ throw " \ Sabre \ DAV \ Exception \ Forbidden "
2016-07-06 00:54:05 +00:00
*/
function FileData ( $file , & $auth , $test = false ) {
logger ( $file . (( $test ) ? ' (test mode) ' : '' ), LOGGER_DATA );
$x = strpos ( $file , '/cloud' );
if ( $x === 0 ) {
$file = substr ( $file , 6 );
}
else {
2016-09-28 19:53:16 +00:00
$x = strpos ( $file , '/dav' );
2016-07-06 00:54:05 +00:00
if ( $x === 0 )
2016-09-28 19:53:16 +00:00
$file = substr ( $file , 4 );
2016-07-06 00:54:05 +00:00
}
if (( ! $file ) || ( $file === '/' )) {
return new Directory ( '/' , $auth );
}
$file = trim ( $file , '/' );
$path_arr = explode ( '/' , $file );
if ( ! $path_arr )
return null ;
$channel_name = $path_arr [ 0 ];
$r = q ( " select channel_id from channel where channel_address = '%s' limit 1 " ,
dbesc ( $channel_name )
);
if ( ! $r )
return null ;
$channel_id = $r [ 0 ][ 'channel_id' ];
$path = '/' . $channel_name ;
$auth -> owner_id = $channel_id ;
$permission_error = false ;
$folder = '' ;
require_once ( 'include/security.php' );
$perms = permissions_sql ( $channel_id );
$errors = false ;
2016-09-28 19:53:16 +00:00
for ( $x = 1 ; $x < count ( $path_arr ); $x ++ ) {
2016-07-06 00:54:05 +00:00
$r = q ( " select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 $perms " ,
dbesc ( $folder ),
dbesc ( $path_arr [ $x ]),
intval ( $channel_id )
);
if ( $r && intval ( $r [ 0 ][ 'is_dir' ])) {
$folder = $r [ 0 ][ 'hash' ];
$path = $path . '/' . $r [ 0 ][ 'filename' ];
}
if ( ! $r ) {
2016-09-28 19:53:16 +00:00
$r = q ( " select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach
2016-07-06 00:54:05 +00:00
where folder = '%s' and filename = '%s' and uid = % d $perms order by filename limit 1 " ,
dbesc ( $folder ),
dbesc ( basename ( $file )),
intval ( $channel_id )
);
}
if ( ! $r ) {
$errors = true ;
2016-09-28 19:53:16 +00:00
$r = q ( " select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach
2016-07-06 00:54:05 +00:00
where folder = '%s' and filename = '%s' and uid = % d order by filename limit 1 " ,
dbesc ( $folder ),
dbesc ( basename ( $file )),
intval ( $channel_id )
);
if ( $r )
$permission_error = true ;
}
}
if ( $path === '/' . $file ) {
if ( $test )
return true ;
// final component was a directory.
return new Directory ( $file , $auth );
}
if ( $errors ) {
logger ( 'not found ' . $file );
if ( $test )
return false ;
if ( $permission_error ) {
logger ( 'permission error ' . $file );
throw new DAV\Exception\Forbidden ( 'Permission denied.' );
}
return ;
}
if ( $r ) {
if ( $test )
return true ;
if ( intval ( $r [ 0 ][ 'is_dir' ])) {
return new Directory ( $path . '/' . $r [ 0 ][ 'filename' ], $auth );
}
else {
return new File ( $path . '/' . $r [ 0 ][ 'filename' ], $r [ 0 ], $auth );
}
}
return false ;
}
2018-06-15 03:40:25 +00:00
public function getQuotaInfo () {
/**
* Returns the quota information
*
* This method MUST return an array with 2 values , the first being the total used space ,
* the second the available space ( in bytes )
*/
$used = 0 ;
$limit = 0 ;
$free = 0 ;
if ( $this -> auth -> owner_id ) {
$channel = channelx_by_n ( $this -> auth -> owner_id );
if ( $channel ) {
$r = q ( " SELECT SUM(filesize) AS total FROM attach WHERE aid = %d " ,
intval ( $channel [ 'channel_account_id' ])
);
$used = (( $r ) ? ( float ) $r [ 0 ][ 'total' ] : 0 );
2019-07-30 01:32:57 +00:00
$limit = ( float ) engr_units_to_bytes ( service_class_fetch ( $this -> auth -> owner_id , 'attach_upload_limit' ));
2018-06-15 03:40:25 +00:00
if ( $limit ) {
// Don't let the result go negative
$free = (( $limit > $used ) ? $limit - $used : 0 );
}
}
}
if ( ! $limit ) {
$free = disk_free_space ( 'store' );
$used = disk_total_space ( 'store' ) - $free ;
}
// prevent integer overflow on 32-bit systems
if ( $used > ( float ) PHP_INT_MAX )
$used = PHP_INT_MAX ;
if ( $free > ( float ) PHP_INT_MAX )
$free = PHP_INT_MAX ;
return [ ( int ) $used , ( int ) $free ];
}
2016-05-17 10:27:15 +00:00
}