850 lines
25 KiB
PHP
Executable File
850 lines
25 KiB
PHP
Executable File
#!/usr/bin/php
|
|
<?php
|
|
|
|
date_default_timezone_set("America/Los_Angeles");
|
|
$time_start = microtime(true);
|
|
|
|
// Yuba
|
|
// //
|
|
//////////////////////////////////////////
|
|
$version = "0.4.7.2";
|
|
|
|
// Treat these directories as files
|
|
$wopt_bundles = array( "app",
|
|
"bundle",
|
|
"sparsebundle",
|
|
"photoslibrary",
|
|
"aplibrary",
|
|
"apvault",
|
|
"abbu",
|
|
"calendar",
|
|
"framework",
|
|
"plugin",
|
|
"kext",
|
|
"rtfd"
|
|
);
|
|
|
|
foreach ($wopt_bundles as $bundle) {
|
|
$wopt_nodescend[] = "*.".$bundle;
|
|
}
|
|
|
|
// Ignore matching files and directories
|
|
$wopt_ignore = array( ".DS_Store",
|
|
".DocumentRevisions-V100",
|
|
".Spotlight-V100",
|
|
".TemporaryItems",
|
|
".apdisk",
|
|
".com.apple.timemachine.donotpresent",
|
|
".fseventsd",
|
|
".metadata-never-index",
|
|
".neofinder.abemeda.volinfo.xml"
|
|
);
|
|
|
|
if (in_array("-hash", $argv)) { $wopt_hash = 1; } else { $wopt_hash = 0; }
|
|
|
|
$wopt_thumb_size = "256";
|
|
$wopt_thumb_factor = $wopt_thumb_size/128;
|
|
|
|
// Location of binaries used to collect metadata
|
|
|
|
$bin_gfi = "/Applications/Xcode.app/Contents/Developer/usr/bin/GetFileInfo";
|
|
$bin_mediainfo = "/opt/local/bin/mediainfo";
|
|
$bin_exiftool = "/opt/local/bin/exiftool";
|
|
|
|
// Functions
|
|
|
|
function stringPrint($string) {
|
|
echo $string.@str_repeat(" ", (10-strlen($string)));
|
|
}
|
|
|
|
function getWoptString() {
|
|
global $wopt_nodescend, $wopt_ignore, $wopt_hash, $wopt_mediainfo, $wopt_exiftool, $wopt_thumb_size, $wopt_thumb_factor, $wopt_tmpdir, $wopt_paranoid;
|
|
return array( array("nodescend", $wopt_nodescend),
|
|
array("ignore", $wopt_ignore),
|
|
array("hash", $wopt_hash),
|
|
array("mediainfo", $wopt_mediainfo),
|
|
array("exiftool", $wopt_exiftool),
|
|
array("thumb_size", $wopt_thumb_size),
|
|
array("thumb_factor", $wopt_thumb_factor),
|
|
array("wopt_paranoid", $wopt_paranoid)
|
|
);
|
|
}
|
|
|
|
class plistParser extends XMLReader {
|
|
public function parseString($string) { $this->XML($string); return $this->process(); }
|
|
private function process() {
|
|
$this->read();
|
|
if($this->nodeType !== XMLReader::DOC_TYPE || $this->name !== "plist") { throw new Exception(sprintf("Error parsing plist. nodeType: %d -- Name: %s", $this->nodeType, $this->name), 2); }
|
|
if(!$this->next("plist") || $this->nodeType !== XMLReader::ELEMENT || $this->name !== "plist") { throw new Exception(sprintf("Error parsing plist. nodeType: %d -- Name: %s", $this->nodeType, $this->name), 3); }
|
|
$plist = array(); while($this->read()) { if($this->nodeType == XMLReader::ELEMENT) { $plist[] = $this->parse_node(); } }
|
|
if(count($plist) == 1 && $plist[0]) { return $plist[0]; } else { return $plist; }
|
|
}
|
|
private function parse_node() {
|
|
if($this->nodeType !== XMLReader::ELEMENT) return;
|
|
switch($this->name) {
|
|
case 'data': return base64_decode($this->getNodeText()); break;
|
|
case 'real': return floatval($this->getNodeText()); break;
|
|
case 'string': return $this->getNodeText(); break;
|
|
case 'integer': return intval($this->getNodeText()); break;
|
|
case 'date': return $this->getNodeText(); break;
|
|
case 'true': return true; break;
|
|
case 'false': return false; break;
|
|
case 'array': return $this->parse_array(); break;
|
|
case 'dict': return $this->parse_dict(); break;
|
|
default: throw new Exception(sprintf("Not a valid plist. %s is not a valid type", $this->name), 4);
|
|
}
|
|
}
|
|
private function parse_dict() {
|
|
$array = array(); $this->nextOfType(XMLReader::ELEMENT);
|
|
do { if($this->nodeType !== XMLReader::ELEMENT || $this->name !== "key") { if(!$this->next("key")) { return $array; } } $key = $this->getNodeText(); $this->nextOfType(XMLReader::ELEMENT); $array[$key] = $this->parse_node(); $this->nextOfType(XMLReader::ELEMENT, XMLReader::END_ELEMENT); }
|
|
while($this->nodeType && !$this->isNodeOfTypeName(XMLReader::END_ELEMENT, "dict")); return $array;
|
|
}
|
|
private function parse_array() {
|
|
$array = array(); $this->nextOfType(XMLReader::ELEMENT);
|
|
do { $array[] = $this->parse_node(); $this->nextOfType(XMLReader::ELEMENT, XMLReader::END_ELEMENT); }
|
|
while($this->nodeType && !$this->isNodeOfTypeName(XMLReader::END_ELEMENT, "array")); return $array;
|
|
}
|
|
private function getNodeText() { $string = $this->readString(); $this->nextOfType(XMLReader::END_ELEMENT); return $string; }
|
|
private function nextOfType() { $types = func_get_args(); $this->read(); while($this->nodeType && !(in_array($this->nodeType, $types))) { $this->read(); } }
|
|
private function isNodeOfTypeName($type, $name) { return $this->nodeType === $type && $this->name === $name; }
|
|
}
|
|
|
|
function parseMediaInfo ($xml) {
|
|
$xml = simplexml_load_string($xml);
|
|
$data = array();
|
|
$data['version'] = (string) $xml['version'];
|
|
foreach ($xml->File->track as $track) {
|
|
$trackType = strtolower($track['type']);
|
|
$trackId = isset($track['streamid']) ? $track['streamid'] : 1;
|
|
$trackId = (string)$trackId;
|
|
$trackData = [];
|
|
foreach ($track as $rawKey => $rawVal) {
|
|
$key = strtolower($rawKey);
|
|
$val = (string)$rawVal;
|
|
if ($key == 'stream_identifier') { continue; }
|
|
if (!array_key_exists($key, $trackData)) {
|
|
$trackData[$key] = array($val);
|
|
} elseif (!in_array($val, $trackData[$key])) {
|
|
$trackData[$key][] = $val;
|
|
}
|
|
}
|
|
if ($trackType == 'general') {
|
|
$data['file']['general'] = $trackData;
|
|
} else {
|
|
$data['file'][$trackType][$trackId] = $trackData;
|
|
}
|
|
}
|
|
return $data;
|
|
}
|
|
|
|
function bashcolor($str,$fgcolor="white",$bgcolor=null) {
|
|
static $fgcolors = array('black' => '0;30', 'dark gray' => '1;30', 'blue' => '0;34', 'light blue' => '1;34', 'green' => '0;32', 'light green' => '1;32', 'cyan' => '0;36', 'light cyan' => '1;36', 'red' => '0;31', 'light red' => '1;31', 'purple' => '0;35', 'light purple' => '1;35', 'brown' => '0;33', 'yellow' => '1;33', 'light gray' => '0;37', 'white' => '1;37', 'underline' => '4');
|
|
static $bgcolors = array('black' => '40', 'red' => '41', 'green' => '42', 'yellow' => '43', 'blue' => '44', 'magenta' => '45', 'cyan' => '46', 'light gray' => '47');
|
|
$out="";
|
|
if (!isset($fgcolors[$fgcolor])) { $fgcolor='white'; }
|
|
if (!isset($bgcolors[$bgcolor])) { $bgcolor=null; }
|
|
if ($fgcolor) { $out .= "\033[{$fgcolors[$fgcolor]}m"; }
|
|
if ($bgcolor) { $out .= "\033[{$bgcolors[$bgcolor]}m"; }
|
|
$out .= $str."\033[0m";
|
|
return $out;
|
|
}
|
|
|
|
// Path arguments
|
|
|
|
$zpath = realpath($argv[1]);
|
|
if (!is_dir($zpath)) { echo "Usage: walk <path> <dbfile>"; die; }
|
|
if (isset($argv[2]) && is_dir($argv[2])) {
|
|
$dbprefix = realpath($argv[2]);
|
|
} else {
|
|
$dbprefix = ".";
|
|
}
|
|
|
|
if (is_writable($zpath)) { $wopt_paranoid = 1; } else { $wopt_paranoid = 0; }
|
|
|
|
// File checks
|
|
|
|
$stamp = date("Y-m-d_H-i-s", time());
|
|
$wopt_tmpdir = "/tmp/WalkWalk_".$stamp."/";
|
|
if (!is_dir($wopt_tmpdir)) { mkdir($wopt_tmpdir); }
|
|
$base = preg_replace("/[^A-Za-z0-9\.]/", "_", basename($zpath));
|
|
if (!$base) { $base = "root"; }
|
|
$dbfile = $dbprefix."/".$stamp."_".$base.".sqlite3";
|
|
if (file_exists($dbfile)) { echo "File \"".$dbfile."\" already exists!"; die; }
|
|
|
|
// Banner
|
|
|
|
echo "Yuba ".$version."\n";
|
|
echo "-----------------------------------------------\n";
|
|
$banner = $zpath." -> ".$dbfile;
|
|
echo $banner."\n";
|
|
echo str_repeat("-", strlen($banner))."\n";
|
|
|
|
// Disk info
|
|
|
|
$host = gethostname();
|
|
$disks = shell_exec("diskutil list 2>&1");
|
|
|
|
if (substr($zpath, 0, 9) != "/Volumes/") {
|
|
$zbase = "/";
|
|
} else {
|
|
$zparts = explode("/", $zpath);
|
|
$zbase = "/Volumes/".$zparts[2];
|
|
}
|
|
|
|
$diskutil = shell_exec("diskutil info ".$zbase." 2>&1");
|
|
$getstats = array( "Volume Name",
|
|
"Protocol",
|
|
"Volume UUID",
|
|
"Device Location",
|
|
"Volume Total Space",
|
|
"Volume Available Space",
|
|
"Level Type"
|
|
);
|
|
foreach ($getstats as $stat) {
|
|
preg_match("/(".$stat.":)(.*)(\n)/",$diskutil,$matches);
|
|
if (isset($matches[2])) {
|
|
if (substr($stat, -5, 5) == "Space") {
|
|
$pieces = explode(" ", trim($matches[2]));
|
|
$summary = $pieces[0]." ".$pieces[1];
|
|
$stats[$stat] = $summary;
|
|
} else {
|
|
$stats[$stat] = trim($matches[2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
$dstats = serialize($stats);
|
|
if ($zpath == "/") {
|
|
$type = "Startup disk";
|
|
} elseif (strtolower($zpath) == strtolower("/Volumes/".$stats["Volume Name"])) {
|
|
if ($stats["Protocol"] == "Disk Image") {
|
|
$type = "Disk image";
|
|
} else {
|
|
$type = "External disk";
|
|
}
|
|
} else {
|
|
$type = "Folder";
|
|
}
|
|
|
|
$profile = shell_exec("system_profiler SPHardwareDataType SPStorageDataType SPThunderboltDataType SPUSBDataType 2>&1");
|
|
$qlmanage = shell_exec("qlmanage -m 2>&1");
|
|
$sysvers = shell_exec("sw_vers 2>&1");
|
|
|
|
// Database
|
|
|
|
// use mysql?
|
|
//$dbo = new PDO("mysql:dbname=testdb;host=127.0.0.1", $user, $pass);
|
|
|
|
$dbo = new PDO("sqlite:".$dbfile);
|
|
$dbo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
|
$dbo->query("PRAGMA page_size = 4096");
|
|
$dbo->query("PRAGMA cache_size = 10000");
|
|
$dbo->query("PRAGMA locking_mode = EXCLUSIVE");
|
|
$dbo->query("PRAGMA synchronous = NORMAL");
|
|
$dbo->query("PRAGMA journal_mode = WAL");
|
|
|
|
$dbo->exec("CREATE TABLE files (
|
|
id INTEGER PRIMARY KEY,
|
|
parent INTEGER,
|
|
Pathname TEXT,
|
|
Path TEXT,
|
|
Filename TEXT,
|
|
Extension TEXT,
|
|
Type TEXT,
|
|
items INTEGER,
|
|
newest INTEGER,
|
|
stat TEXT,
|
|
LinkTarget TEXT,
|
|
RealPath TEXT,
|
|
Inode INTEGER,
|
|
Size INTEGER,
|
|
Perms INTEGER,
|
|
Owner TEXT,
|
|
ATime INTEGER,
|
|
MTime INTEGER,
|
|
CTime INTEGER,
|
|
gfi_type TEXT,
|
|
gfi_attr TEXT,
|
|
gfi_created TEXT,
|
|
hash TEXT,
|
|
tinfo TEXT
|
|
)");
|
|
|
|
$dbo->exec("CREATE TABLE mdls (
|
|
id INTEGER PRIMARY KEY,
|
|
hasmeta INTEGER,
|
|
DateAdded TEXT,
|
|
ContentType TEXT,
|
|
Creator TEXT,
|
|
Kind TEXT,
|
|
UserTags TEXT,
|
|
FSInvisible INTEGER,
|
|
PixelWidth INTEGER,
|
|
PixelHeight INTEGER,
|
|
spotlight TEXT
|
|
)");
|
|
|
|
$dbo->exec("CREATE TABLE metadata (
|
|
id INTEGER PRIMARY KEY,
|
|
duration TEXT,
|
|
mediainfo TEXT,
|
|
exiftool TEXT
|
|
)");
|
|
|
|
$dbo->exec("CREATE TABLE thumbs (
|
|
id INTEGER PRIMARY KEY,
|
|
thumb BLOB
|
|
)");
|
|
|
|
$dbo->exec("CREATE TABLE _walkwalk (
|
|
version TEXT,
|
|
opts TEXT,
|
|
host TEXT,
|
|
zpath TEXT,
|
|
type TEXT,
|
|
nodescended INTEGER,
|
|
ignored INTEGER,
|
|
stats TEXT,
|
|
qlmanage TEXT,
|
|
sysvers TEXT,
|
|
diskutil TEXT,
|
|
disks TEXT,
|
|
profile TEXT,
|
|
status TEXT
|
|
)");
|
|
|
|
$stmt = $dbo->prepare("INSERT INTO _walkwalk VALUES (:version, :opts, :host, :zpath, :type, :nodescended, :ignored, :stats, :qlmanage, :sysvers, :diskutil, :disks, :profile, :status)");
|
|
$stmt->BindValue(":version",$version." (".posix_getuid().")");
|
|
$stmt->BindValue(":opts",serialize(getWoptString()));
|
|
$stmt->BindValue(":host",$host);
|
|
$stmt->BindValue(":zpath",$zpath);
|
|
$stmt->BindValue(":type",$type);
|
|
$stmt->BindValue(":nodescended",null);
|
|
$stmt->BindValue(":ignored",null);
|
|
$stmt->BindValue(":stats",$dstats);
|
|
$stmt->BindValue(":qlmanage",$qlmanage);
|
|
$stmt->BindValue(":sysvers",$sysvers);
|
|
$stmt->BindValue(":diskutil",$diskutil);
|
|
$stmt->BindValue(":disks",$disks);
|
|
$stmt->BindValue(":profile",$profile);
|
|
$stmt->BindValue(":status","aborted");
|
|
$stmt->execute();
|
|
|
|
// Iterate
|
|
|
|
$nodescended = 0;
|
|
$ignored = 0;
|
|
$files = new RecursiveIteratorIterator(
|
|
new RecursiveCallbackFilterIterator(
|
|
new RecursiveDirectoryIterator(
|
|
// start in parent dir to include self
|
|
dirname($zpath),
|
|
RecursiveDirectoryIterator::SKIP_DOTS
|
|
),
|
|
function ($current, $key, $iterator) use ($wopt_ignore, $wopt_nodescend) {
|
|
global $nodescended, $ignored, $zpath;
|
|
$clean = true;
|
|
// ensure we don't traverse zpath siblings
|
|
if ($zpath != "/" && (substr($current->getRealpath(), 0, strlen($zpath)+1) != $zpath."/") && ($current->getRealpath() != $zpath)) {
|
|
$clean = false;
|
|
}
|
|
// filenames to ignore
|
|
if (is_array($wopt_ignore)) {
|
|
foreach ($wopt_ignore as $wildcard) {
|
|
if (fnmatch($wildcard, $current->getFilename())) {
|
|
$clean = false;
|
|
$ignored++;
|
|
echo "\nSkipping: ".$current->getRealpath()."\n\n";
|
|
}
|
|
}
|
|
}
|
|
// directories to ignore
|
|
if (is_array($wopt_nodescend)) {
|
|
foreach ($wopt_nodescend as $wildcard) {
|
|
if (fnmatch($wildcard, $current->getPath())) {
|
|
$clean = false;
|
|
$nodescended++;
|
|
echo "\nNodescending: ".$current->getRealpath()."\n\n";
|
|
}
|
|
}
|
|
}
|
|
return $clean;
|
|
}
|
|
),
|
|
RecursiveIteratorIterator::SELF_FIRST,
|
|
RecursiveIteratorIterator::CATCH_GET_CHILD
|
|
);
|
|
|
|
// Debug input array
|
|
|
|
/*
|
|
foreach ($files as $splFileInfo) {
|
|
echo "====================================================================================\n";
|
|
print_r($splFileInfo);
|
|
echo "====================================================================================\n";
|
|
echo "getRealPath = ".$splFileInfo->getRealPath()."\n";
|
|
echo "getPathname = ".$splFileInfo->getPathname()."\n";
|
|
echo "isLink = ".$splFileInfo->isLink()."\n";
|
|
if ($splFileInfo->isLink()) {
|
|
echo "getLinkTarget = ".$splFileInfo->getLinkTarget()."\n";
|
|
} else {
|
|
echo "getLinkTarget = N/A\n";
|
|
}
|
|
echo "getType = ".$splFileInfo->getType()." (".filetype($splFileInfo->getPathname()).")\n";
|
|
echo "isDir = ".$splFileInfo->isDir()."\n";
|
|
echo "isFile = ".$splFileInfo->isFile()."\n";
|
|
echo "-----------------------------------------------------------------------\n";
|
|
echo "getPath = ".$splFileInfo->getPath()."\n";
|
|
echo "getFilename = ".$splFileInfo->getFilename()."\n";
|
|
echo "getBasename = ".$splFileInfo->getBasename()." (".basename($splFileInfo->getPathname()).")\n";
|
|
echo "getExtension = ".$splFileInfo->getExtension()."\n";
|
|
echo "-----------------------------------------------------------------------\n";
|
|
if (!$splFileInfo->isLink()) {
|
|
echo "getATime = ".$splFileInfo->getAtime()." (".fileatime($splFileInfo->getPathname()).")\n";
|
|
echo "getMTime = ".$splFileInfo->getMtime()." (".filemtime($splFileInfo->getPathname()).")\n";
|
|
echo "getCTime = ".$splFileInfo->getCtime()." (".filectime($splFileInfo->getPathname()).")\n";
|
|
echo "getInode = ".$splFileInfo->getInode()." (".fileinode($splFileInfo->getPathname()).")\n";
|
|
echo "getPerms = ".$splFileInfo->getPerms()." (".fileperms($splFileInfo->getPathname()).")\n";
|
|
echo "getGroup = ".$splFileInfo->getGroup()." (".filegroup($splFileInfo->getPathname()).")\n";
|
|
echo "getOwner = ".$splFileInfo->getOwner()." (".fileowner($splFileInfo->getPathname()).")\n";
|
|
echo "getSize = ".$splFileInfo->getSize()." (".filesize($splFileInfo->getPathname()).")\n";
|
|
}
|
|
}
|
|
die;
|
|
*/
|
|
|
|
// Check perms
|
|
|
|
if (posix_getuid()) {
|
|
|
|
echo bashcolor("You are not root. Checking file readability: ", "red");
|
|
|
|
echo "\n";
|
|
|
|
$oops = 0;
|
|
foreach ($files as $splFileInfo) {
|
|
$path = $splFileInfo->getRealPath();
|
|
if (!is_readable($path)) {
|
|
$oops = 1;
|
|
echo "x";
|
|
} else {
|
|
echo ".";
|
|
}
|
|
}
|
|
|
|
echo "\n\n";
|
|
|
|
if ($oops) {
|
|
echo "Some files could not be read. Continue? (Y/n)";
|
|
$line = trim(fgets(fopen("php://stdin","r")));
|
|
$line = $line ?: "y";
|
|
if($line != "y"){
|
|
echo "Exiting!\n"; die;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
echo bashcolor("Running as root. Some QuickLook plugins may not be available.", "red");
|
|
echo "\n";
|
|
|
|
}
|
|
|
|
$fixatimes = 0;
|
|
if ($wopt_paranoid) {
|
|
|
|
echo bashcolor("\nFilesystem is writable. You can choose:\n(c) Preserve ctimes (default)\n(a) Preserve atimes\n", "purple");
|
|
$line = trim(fgets(fopen("php://stdin","r"))) ?: "c";
|
|
if ($line == "a") { $fixatimes = 1; }
|
|
|
|
}
|
|
|
|
// Filetypes for special handling
|
|
|
|
$m_files = array( "mkv",
|
|
"ogg",
|
|
"avi",
|
|
"wav",
|
|
"mpeg",
|
|
"mpg",
|
|
"vob",
|
|
"mp4",
|
|
"m2v",
|
|
"mp3",
|
|
"asf",
|
|
"wma",
|
|
"wmv",
|
|
"qt",
|
|
"mov",
|
|
"rm",
|
|
"ifo",
|
|
"ac3",
|
|
"dts",
|
|
"aac",
|
|
"ape",
|
|
"flac",
|
|
"aiff",
|
|
"m2ts" );
|
|
|
|
$e_files = array( "ai",
|
|
"aiff",
|
|
"ape",
|
|
"asf",
|
|
"avi",
|
|
"bmp",
|
|
"divx",
|
|
"dng",
|
|
"doc",
|
|
"docx",
|
|
"eps",
|
|
"epub",
|
|
"exe",
|
|
"exif",
|
|
"fla",
|
|
"flac",
|
|
"flv",
|
|
"gif",
|
|
"icc",
|
|
"iso",
|
|
"jpg",
|
|
"jpeg",
|
|
"m2ts",
|
|
"m4a",
|
|
"m4b",
|
|
"m4v",
|
|
"mkv",
|
|
"mobi",
|
|
"azw",
|
|
"azw3",
|
|
"mov",
|
|
"qt",
|
|
"mp3",
|
|
"mp4",
|
|
"mpeg",
|
|
"mpg",
|
|
"m2v",
|
|
"nef",
|
|
"numbers",
|
|
"ogg",
|
|
"pages",
|
|
"pdf",
|
|
"pict",
|
|
"png",
|
|
"ppm",
|
|
"ppt",
|
|
"psd",
|
|
"psb",
|
|
"qif",
|
|
"raw",
|
|
"rtf",
|
|
"sr2",
|
|
"srf",
|
|
"svg",
|
|
"swf",
|
|
"tiff",
|
|
"tif",
|
|
"torrent",
|
|
"vcf",
|
|
"vob",
|
|
"wav",
|
|
"webm",
|
|
"wma",
|
|
"wmv",
|
|
"xls",
|
|
"xlsx",
|
|
"xmp",
|
|
"zip" );
|
|
|
|
foreach ($e_files as $ext) { $e_files[] = strtoupper($ext); }
|
|
foreach ($m_files as $ext) { $m_files[] = strtoupper($ext); }
|
|
|
|
// Inserts
|
|
|
|
foreach ($files as $splFileInfo) {
|
|
|
|
$type = $splFileInfo->getType();
|
|
if ($type == "dir") {
|
|
foreach ($wopt_bundles as $bundle) {
|
|
$check = ".".$bundle;
|
|
if (substr($splFileInfo->getFilename(), -(strlen($check)), strlen($check)) == $check) { $type = "bundle"; }
|
|
}
|
|
}
|
|
|
|
if ($type != "link") { $atime = $splFileInfo->getATime(); }
|
|
$pathname = $splFileInfo->getPathname();
|
|
$path = $splFileInfo->getPath();
|
|
$filename = $splFileInfo->getFilename();
|
|
$extension = $splFileInfo->getExtension();
|
|
$shellpath = escapeshellarg($pathname);
|
|
|
|
echo bashcolor("\n".$pathname."\n","blue");
|
|
|
|
if (!$type) { echo "\nBREAK: can't determine type of ".$pathname; die; }
|
|
|
|
if ($type != "link") {
|
|
$stat = chop(@shell_exec("stat -x ".$shellpath." 2>&1"));
|
|
} else {
|
|
$stat = null;
|
|
}
|
|
|
|
if ($type != "link" && $wopt_paranoid) {
|
|
$pre_access = null;
|
|
$pre_modify = null;
|
|
$pre_change = null;
|
|
foreach (explode("\n", $stat) as $line) {
|
|
$check = substr($line, 0, 6);
|
|
if ($check == "Access") { $pre_access = $line; }
|
|
if ($check == "Modify") { $pre_modify = $line; }
|
|
if ($check == "Change") { $pre_change = $line; }
|
|
}
|
|
}
|
|
|
|
// Determine ID of parent dir by querying database
|
|
|
|
$parent = $dbo->query("SELECT id FROM files WHERE (Pathname='".str_replace("'", "''", $path)."')")->fetch()['id'];
|
|
stringPrint("parent");
|
|
|
|
// Gather file attributes
|
|
|
|
$stmt = $dbo->prepare("INSERT INTO files VALUES (:id, :parent, :Pathname, :Path, :Filename, :Extension, :Type, :items, :newest, :stat, :LinkTarget, :RealPath, :Inode, :Size, :Perms, :Owner, :ATime, :MTime, :CTime, :gfi_type, :gfi_attr, :gfi_created, :hash, :tinfo)");
|
|
|
|
if ($type == "dir") {
|
|
$size = trim(shell_exec("du -ks ".$shellpath." | cut -f1"))*1024;
|
|
} elseif ($type == "file" || $type == "bundle") {
|
|
$size = $splFileInfo->getSize();
|
|
} else {
|
|
$size = null;
|
|
}
|
|
$stmt->BindValue(":Size",@$size);
|
|
stringPrint(floor($size/1024)."k");
|
|
|
|
if ($parent) {
|
|
$stmt->BindValue(":parent",$parent);
|
|
} else {
|
|
$stmt->BindValue(":parent",0);
|
|
}
|
|
|
|
stringPrint("items");
|
|
|
|
if ($type == "dir" || $type == "bundle" ) {
|
|
$items = chop(@shell_exec("find ".$shellpath." \( ! -regex '.*/\..*' \) | wc -l 2>&1"))-1;
|
|
} else {
|
|
$items = null;
|
|
}
|
|
|
|
$stmt->BindValue(":items",@$items);
|
|
|
|
stringPrint("newest");
|
|
|
|
if ($type == "dir") {
|
|
$newest = filemtime(chop(shell_exec("find ".$shellpath." -type f -not -path '*/\.*' -print0 | xargs -0 stat -f \"%m %N\" | sort -rn | head -1 | cut -f2- -d\" \"")));
|
|
} else {
|
|
$newest = null;
|
|
}
|
|
|
|
$stmt->BindValue(":newest",@$newest);
|
|
|
|
$stmt->BindValue(":stat",@$stat);
|
|
|
|
$stmt->BindValue(":Pathname",$pathname);
|
|
$stmt->BindValue(":Path",$path);
|
|
$stmt->BindValue(":Filename",$filename);
|
|
$stmt->BindValue(":Extension",$extension);
|
|
$stmt->BindValue(":Type",$type);
|
|
|
|
if ($type == "link") {
|
|
|
|
$stmt->BindValue(":LinkTarget",$splFileInfo->getLinkTarget());
|
|
$stmt->BindValue(":RealPath",$splFileInfo->getRealPath());
|
|
|
|
} else {
|
|
|
|
$stmt->BindValue(":Inode",$splFileInfo->getInode());
|
|
$stmt->BindValue(":Perms",$splFileInfo->getPerms());
|
|
$stmt->BindValue(":Owner",$splFileInfo->getOwner().":".$splFileInfo->getGroup());
|
|
|
|
$stmt->BindValue(":ATime",$atime);
|
|
$stmt->BindValue(":CTime",$splFileInfo->getCTime());
|
|
$stmt->BindValue(":MTime",$splFileInfo->getMTime());
|
|
|
|
}
|
|
|
|
stringPrint("attr");
|
|
|
|
$gfiparts = explode("\n", chop(shell_exec($bin_gfi." -P ".$shellpath." 2>&1")));
|
|
if (is_array($gfiparts)) {
|
|
foreach ($gfiparts as $line) {
|
|
list($label, $value) = explode(": ", $line);
|
|
$gfi[$label] = isset($value) ? trim($value,"\"") : null;
|
|
}
|
|
}
|
|
|
|
$writegfitype = @$gfi['type'].":".@$gfi['creator'];
|
|
if ($writegfitype == "\\0\\0\\0\\0:\\0\\0\\0\\0" || $writegfitype == ":") { $writegfitype = null; }
|
|
|
|
$stmt->BindValue("gfi_type",$writegfitype);
|
|
$stmt->BindValue("gfi_attr",@$gfi['attributes']);
|
|
$stmt->BindValue("gfi_created",strtotime($gfi['created']));
|
|
|
|
stringPrint("gfi");
|
|
|
|
if ($wopt_hash && $type != "link") {
|
|
$stmt->BindValue(":hash",md5_file($pathname));
|
|
StringPrint("hash");
|
|
} else {
|
|
$stmt->BindValue(":hash",null);
|
|
StringPrint("(x)hash");
|
|
}
|
|
|
|
$thumb = $wopt_tmpdir.$filename.".png";
|
|
/*
|
|
// insane workaround for insane apple bug
|
|
if (@pathinfo($pathname)['extension'] == "mp3" | "MP3" | "m4a" | "M4A" | "m4b" | "M4B" ) {
|
|
$zprefix = "sudo qlmanage";
|
|
} else {
|
|
$zprefix = "qlmanage";
|
|
}
|
|
*/
|
|
$zprefix = "sudo qlmanage"; // prevent hang
|
|
@exec($zprefix." -t -f ".$wopt_thumb_factor." -o ".$wopt_tmpdir." ".$shellpath." 2>&1");
|
|
stringPrint("thumb");
|
|
if ($size && !file_exists($thumb) && (in_array($extension, $m_files) || in_array($extension, $e_files))) {
|
|
@exec("ffmpegthumbnailer -i ".$shellpath." -o \"".$thumb."\" -s ".$wopt_thumb_size." -c png 2>&1");
|
|
stringPrint("fthumb");
|
|
} else {
|
|
stringPrint("(x)fthumb");
|
|
}
|
|
if (file_exists($thumb) && filesize($thumb)) {
|
|
$stmt->BindValue(":tinfo",serialize(getimagesize($thumb)));
|
|
}
|
|
|
|
$stmt->execute();
|
|
stringPrint("->files");
|
|
|
|
// Gather spotlight metadata
|
|
|
|
$stmt = $dbo->prepare("INSERT INTO mdls VALUES (:id, :hasmeta, :DateAdded, :ContentType, :Creator, :Kind, :UserTags, :FSInvisible, :PixelWidth, :PixelHeight, :spotlight)");
|
|
$mdls = shell_exec("mdls -plist - ".$shellpath." 2>&1");
|
|
stringPrint("mdls");
|
|
|
|
if ($mdls != $pathname.": could not find ".$pathname.".\n") {
|
|
|
|
$stmt->BindValue(":hasmeta",1);
|
|
$parser = new plistParser();
|
|
$spotlight = $parser->parseString($mdls);
|
|
|
|
$stmt->BindValue(":DateAdded",@strtotime($spotlight['kMDItemDateAdded']));
|
|
$stmt->BindValue(":ContentType",@$spotlight['kMDItemContentType']);
|
|
$stmt->BindValue(":Creator",@$spotlight['kMDItemCreator']);
|
|
$stmt->BindValue(":Kind",@$spotlight['kMDItemKind']);
|
|
if (isset($spotlight['kMDItemUserTags'])) {
|
|
$stmt->BindValue(":UserTags",serialize($spotlight['kMDItemUserTags']));
|
|
}
|
|
$stmt->BindValue(":FSInvisible",@$spotlight['kMDItemFSInvisible']);
|
|
$stmt->BindValue(":PixelWidth",@$spotlight['kMDItemPixelWidth']);
|
|
$stmt->BindValue(":PixelHeight",@$spotlight['kMDItemPixelHeight']);
|
|
$stmt->BindValue(":spotlight",serialize($spotlight));
|
|
|
|
} else {
|
|
$stmt->BindValue(":hasmeta",0);
|
|
}
|
|
$stmt->execute();
|
|
stringPrint("->mdls");
|
|
|
|
// Gather external metadata
|
|
|
|
$stmt = $dbo->prepare("INSERT INTO metadata VALUES (:id, :duration, :mediainfo, :exiftool)");
|
|
|
|
if ($type != "dir" && in_array($extension, $m_files)) {
|
|
$minfo = parseMediaInfo(shell_exec($bin_mediainfo." --Output=OLDXML ".$shellpath." 2>&1"));
|
|
if ($minfo['file']['general']['duration'][0]) {
|
|
$stmt->BindValue(":duration",$minfo['file']['general']['duration'][0]);
|
|
} else {
|
|
$stmt->BindValue(":duration",null);
|
|
}
|
|
$stmt->BindValue(":mediainfo",serialize($minfo));
|
|
stringPrint("minfo");
|
|
} else {
|
|
$stmt->BindValue(":duration",null);
|
|
$stmt->BindValue(":mediainfo",null);
|
|
stringPrint("(x)info");
|
|
}
|
|
|
|
if ($type != "dir" && $type != "link" && in_array($extension, $e_files)) {
|
|
$stmt->BindValue(":exiftool",serialize(eval("return ".`$bin_exiftool -php $shellpath`)));
|
|
stringPrint("etool");
|
|
} else {
|
|
$stmt->BindValue(":exiftool",null);
|
|
stringPrint("(x)etool");
|
|
}
|
|
$stmt->execute();
|
|
stringPrint("->meta");
|
|
|
|
// Gather thumbnail
|
|
|
|
$stmt = $dbo->prepare("INSERT INTO thumbs VALUES (:id, :thumb)");
|
|
if (file_exists($thumb) && filesize($thumb)) {
|
|
$stmt->BindValue(":thumb",file_get_contents($thumb));
|
|
} else {
|
|
$stmt->BindValue(":thumb",null);
|
|
}
|
|
$stmt->execute();
|
|
stringPrint("->thumb");
|
|
|
|
// Set fileatime back to original value
|
|
|
|
if ($type != "link" && is_writable($pathname) && $fixatimes) {
|
|
@exec("touch -at `date -r ".$atime." +%Y%m%d%H%M.%S` ".$shellpath." 2>&1");
|
|
stringPrint("touch");
|
|
}
|
|
|
|
echo "\n";
|
|
|
|
// Double check stat for file against pre-run value
|
|
|
|
if ($type != "link" && $wopt_paranoid) {
|
|
|
|
$restat = chop(@shell_exec("stat -x ".$shellpath." 2>&1"));
|
|
$post_access = null;
|
|
$post_modify = null;
|
|
$post_change = null;
|
|
|
|
foreach (explode("\n", $restat) as $line) {
|
|
$check = substr($line, 0, 6);
|
|
if ($check == "Access") { $post_access = $line; }
|
|
if ($check == "Modify") { $post_modify = $line; }
|
|
if ($check == "Change") { $post_change = $line; }
|
|
}
|
|
|
|
$message = array();
|
|
if ($pre_access != $post_access) {
|
|
$message[] = "ATIME CHANGED";
|
|
}
|
|
if ($pre_modify != $post_modify) {
|
|
$message[] = "MTIME CHANGED";
|
|
}
|
|
if ($pre_change != $post_change) {
|
|
$message[] = "CTIME CHANGED";
|
|
}
|
|
|
|
if (count($message)) { echo bashcolor(str_repeat(" ",99).implode(" ~ ", $message), "purple"); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
echo "\n\n\n";
|
|
|
|
// Footer
|
|
|
|
$seconds = floor($time = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]);
|
|
$fbanner = "Finished in ".$seconds." seconds";
|
|
echo str_repeat("-", strlen($fbanner))."\n".$fbanner."\n";
|
|
echo "Files ignored: ".$ignored." / Files nodescended: ".$nodescended."\n";
|
|
|
|
// Write app summary values
|
|
|
|
$dbo->exec("UPDATE _walkwalk SET nodescended=".$nodescended.", ignored=".$ignored.", status='completed_in_".$seconds."'");
|
|
|
|
?>
|