|
| 1 | +<?php |
| 2 | + |
| 3 | +class VaultPress_Filesystem { |
| 4 | + |
| 5 | + var $type = null; |
| 6 | + var $dir = null; |
| 7 | + var $keys = array( 'ino', 'uid', 'gid', 'size', 'mtime', 'blksize', 'blocks' ); |
| 8 | + |
| 9 | + function VaultPress_Filesystem() { |
| 10 | + $this->__construct(); |
| 11 | + } |
| 12 | + |
| 13 | + function __construct() { |
| 14 | + } |
| 15 | + |
| 16 | + function want( $type ) { |
| 17 | + $vp = VaultPress::init(); |
| 18 | + |
| 19 | + if ( $type == 'plugins' ) { |
| 20 | + $this->dir = realpath( $vp->resolve_content_dir() . 'plugins' ); |
| 21 | + $this->type = 'p'; |
| 22 | + return true; |
| 23 | + } |
| 24 | + if ( $type == 'themes' ) { |
| 25 | + $this->dir = realpath( $vp->resolve_content_dir() . 'themes' ); |
| 26 | + $this->type = 't'; |
| 27 | + return true; |
| 28 | + } |
| 29 | + if ( $type == 'uploads' ) { |
| 30 | + $this->dir = realpath( $vp->resolve_upload_path() ); |
| 31 | + $this->type = 'u'; |
| 32 | + return true; |
| 33 | + } |
| 34 | + if ( $type == 'content' ) { |
| 35 | + $this->dir = realpath( $vp->resolve_content_dir() ); |
| 36 | + $this->type = 'c'; |
| 37 | + return true; |
| 38 | + } |
| 39 | + if ( $type == 'root' ) { |
| 40 | + $this->dir = realpath( ABSPATH ); |
| 41 | + $this->type = 'r'; |
| 42 | + return true; |
| 43 | + } |
| 44 | + die( 'naughty naughty' ); |
| 45 | + } |
| 46 | + |
| 47 | + function fdump( $file ) { |
| 48 | + header("Content-Type: application/octet-stream;"); |
| 49 | + header("Content-Transfer-Encoding: binary"); |
| 50 | + @ob_end_clean(); |
| 51 | + if ( !file_exists( $file ) || !is_readable( $file ) ) |
| 52 | + die( "no such file" ); |
| 53 | + if ( !is_file( $file ) && !is_link( $file ) ) |
| 54 | + die( "can only dump files" ); |
| 55 | + $fp = @fopen( $file, 'rb' ); |
| 56 | + if ( !$fp ) |
| 57 | + die( "could not open file" ); |
| 58 | + while ( !feof( $fp ) ) |
| 59 | + echo @fread( $fp, 8192 ); |
| 60 | + @fclose( $fp ); |
| 61 | + die(); |
| 62 | + } |
| 63 | + |
| 64 | + function stat( $file, $md5=true, $sha1=true ) { |
| 65 | + $rval = array(); |
| 66 | + foreach ( stat( $file ) as $i => $v ) { |
| 67 | + if ( is_numeric( $i ) ) |
| 68 | + continue; |
| 69 | + $rval[$i] = $v; |
| 70 | + } |
| 71 | + $rval['type'] = filetype( $file ); |
| 72 | + if ( $rval['type'] == 'file' ) { |
| 73 | + if ( $md5 ) |
| 74 | + $rval['md5'] = md5_file( $file ); |
| 75 | + if ( $sha1 ) |
| 76 | + $rval['sha1'] = sha1_file( $file ); |
| 77 | + } |
| 78 | + $rval['path'] = str_replace( $this->dir, '', $file ); |
| 79 | + return $rval; |
| 80 | + } |
| 81 | + |
| 82 | + function ls( $what, $md5=false, $sha1=false, $limit=null, $offset=null ) { |
| 83 | + clearstatcache(); |
| 84 | + $path = realpath($this->dir . $what); |
| 85 | + if ( is_file($path) ) |
| 86 | + return $this->stat( $path, $md5, $sha1 ); |
| 87 | + if ( is_dir($path) ) { |
| 88 | + $entries = array(); |
| 89 | + $current = 0; |
| 90 | + $offset = (int)$offset; |
| 91 | + $orig_limit = (int)$limit; |
| 92 | + $limit = $offset + (int)$limit; |
| 93 | + foreach ( (array)$this->scan_dir( $path ) as $i ) { |
| 94 | + $current++; |
| 95 | + if ( $offset >= $current ) |
| 96 | + continue; |
| 97 | + if ( $limit && $limit < $current ) |
| 98 | + break; |
| 99 | + |
| 100 | + // don't sha1 files over 100MB if we are batching due to memory consumption |
| 101 | + if ( $sha1 && $orig_limit > 1 && is_file( $i ) && (int)@filesize( $i ) > 104857600 ) |
| 102 | + $sha1 = false; |
| 103 | + |
| 104 | + $entries[] = $this->stat( $i, $md5, $sha1 ); |
| 105 | + } |
| 106 | + return $entries; |
| 107 | + } |
| 108 | + } |
| 109 | + |
| 110 | + function validate( $file ) { |
| 111 | + $rpath = realpath( $this->dir.$file ); |
| 112 | + if ( !$rpath ) |
| 113 | + die( serialize( array( 'type' => 'null', 'path' => $file ) ) ); |
| 114 | + if ( is_dir( $rpath ) ) |
| 115 | + $rpath = "$rpath/"; |
| 116 | + if ( strpos( $rpath, $this->dir ) !== 0 ) |
| 117 | + return false; |
| 118 | + return true; |
| 119 | + } |
| 120 | + |
| 121 | + function dir_examine( $subdir='', $recursive=true, $origin=false ) { |
| 122 | + $res = array(); |
| 123 | + if ( !$subdir ) |
| 124 | + $subdir='/'; |
| 125 | + $dir = $this->dir . $subdir; |
| 126 | + if ( $origin === false ) |
| 127 | + $origin = $this->dir . $subdir; |
| 128 | + if ( is_file($dir) ) { |
| 129 | + if ( $origin == $dir ) |
| 130 | + $name = str_replace( $this->dir, '/', $subdir ); |
| 131 | + else |
| 132 | + $name = str_replace( $origin, '/', $dir ); |
| 133 | + $res[$name] = $this->stat( $dir.$entry ); |
| 134 | + return $res; |
| 135 | + } |
| 136 | + $d = dir( $dir ); |
| 137 | + if ( !$d ) |
| 138 | + return $res; |
| 139 | + while ( false !== ( $entry = $d->read() ) ) { |
| 140 | + $rpath = realpath( $dir.$entry ); |
| 141 | + $bname = basename( $rpath ); |
| 142 | + if ( is_link( $dir.$entry ) ) |
| 143 | + continue; |
| 144 | + if ( $entry == '.' || $entry == '..' || $entry == '...' ) |
| 145 | + continue; |
| 146 | + if ( !$this->validate( $subdir.$entry ) ) |
| 147 | + continue; |
| 148 | + $name = str_replace( $origin, '/', $dir.$entry ); |
| 149 | + $res[$name] = $this->stat( $dir.$entry ); |
| 150 | + if ( $recursive && is_dir( $this->dir.$subdir.'/'.$entry ) ) { |
| 151 | + $res = array_merge( $res, $this->dir_examine( $subdir.$entry.'/', $recursive, $origin ) ); |
| 152 | + } |
| 153 | + } |
| 154 | + return $res; |
| 155 | + } |
| 156 | + |
| 157 | + function dir_checksum( $base, &$list, $recursive=true ) { |
| 158 | + if ( $list == null ) |
| 159 | + $list = array(); |
| 160 | + |
| 161 | + if ( 0 !== strpos( $base, $this->dir ) ) |
| 162 | + $base = $this->dir . rtrim( $base, '/' ); |
| 163 | + |
| 164 | + $shortbase = substr( $base, strlen( $this->dir ) ); |
| 165 | + if ( !$shortbase ) |
| 166 | + $shortbase = '/'; |
| 167 | + $stat = stat( $base ); |
| 168 | + $directories = array(); |
| 169 | + $files = (array)$this->scan_dir( $base ); |
| 170 | + array_push( $files, $base ); |
| 171 | + foreach ( $files as $file ) { |
| 172 | + if ( $file !== $base && @is_dir( $file ) ) { |
| 173 | + $directories[] = $file; |
| 174 | + continue; |
| 175 | + } |
| 176 | + $stat = @stat( $file ); |
| 177 | + if ( !$stat ) |
| 178 | + continue; |
| 179 | + $shortstat = array(); |
| 180 | + foreach( $this->keys as $key ) { |
| 181 | + if ( isset( $stat[$key] ) ) |
| 182 | + $shortstat[$key] = $stat[$key]; |
| 183 | + } |
| 184 | + $list[$shortbase][basename( $file )] = $shortstat; |
| 185 | + } |
| 186 | + $list[$shortbase] = md5( serialize( $list[$shortbase] ) ); |
| 187 | + if ( !$recursive ) |
| 188 | + return $list; |
| 189 | + foreach ( $directories as $dir ) { |
| 190 | + $this->dir_checksum( $dir, $list, $recursive ); |
| 191 | + } |
| 192 | + return $list; |
| 193 | + } |
| 194 | + |
| 195 | + function scan_dir( $path ) { |
| 196 | + $files = array(); |
| 197 | + |
| 198 | + if ( false === is_readable( $path ) ) { |
| 199 | + return array(); |
| 200 | + } |
| 201 | + |
| 202 | + $dh = opendir( $path ); |
| 203 | + |
| 204 | + if ( false === $dh ) { |
| 205 | + return array(); |
| 206 | + } |
| 207 | + |
| 208 | + while ( false !== ( $file = readdir( $dh ) ) ) { |
| 209 | + if ( $file == '.' || $file == '..' ) continue; |
| 210 | + $files[] = "$path/$file"; |
| 211 | + } |
| 212 | + |
| 213 | + closedir( $dh ); |
| 214 | + sort( $files ); |
| 215 | + return $files; |
| 216 | + } |
| 217 | +} |
0 commit comments