getLocalDiskFileStorageRoot(); // Generate a random, unique file path like "ab/29/1f918a9ac39201ff". We // put a couple of subdirectories up front to avoid a situation where we // have one directory with a zillion files in it, since this is generally // bad news. do { $name = md5(mt_rand()); $name = preg_replace('/^(..)(..)(.*)$/', '\\1/\\2/\\3', $name); if (!Filesystem::pathExists($root.'/'.$name)) { break; } } while (true); AphrontWriteGuard::willWrite(); $binary = Filesystem::resolveBinary('write-file-to-storage.sh'); $command = csprintf('%s %s', $binary, $root.'/'.$name); $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); id(new ExecFuture('%C', $command)) ->write($data) ->resolvex(); return $name; } /** * Read the file data off local disk. * @task impl */ public function readFile($handle) { $path = $this->getLocalDiskFileStorageFullPath($handle); return Filesystem::readFile($path); } /** * Deletes the file from local disk, if it exists. * @task impl */ public function deleteFile($handle) { $path = $this->getLocalDiskFileStorageFullPath($handle); if (Filesystem::pathExists($path)) { AphrontWriteGuard::willWrite(); $binary = Filesystem::resolveBinary('rm-file-from-storage.php'); $command = csprintf('%s %s', $binary, $path); $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); execx('%C', $command); } } /* -( Internals )---------------------------------------------------------- */ /** * Get the configured local disk path for file storage. * * @return string Absolute path to somewhere that files can be stored. * @task internal */ private function getLocalDiskFileStorageRoot() { $root = PhabricatorEnv::getEnvConfig('storage.local-disk.path'); if (!$root || $root == '/' || $root[0] != '/') { throw new PhabricatorFileStorageConfigurationException( pht( "Malformed local disk storage root. You must provide an absolute ". "path, and can not use '%s' as the root.", '/')); } return rtrim($root, '/'); } /** * Convert a handle into an absolute local disk path. * * @param string File data handle. * @return string Absolute path to the corresponding file. * @task internal */ private function getLocalDiskFileStorageFullPath($handle) { // Make sure there's no funny business going on here. Users normally have // no ability to affect the content of handles, but double-check that // we're only accessing local storage just in case. if (!preg_match('@^[a-f0-9]{2}/[a-f0-9]{2}/[a-f0-9]{28}\z@', $handle)) { throw new Exception( pht( "Local disk filesystem handle '%s' is malformed!", $handle)); } $root = $this->getLocalDiskFileStorageRoot(); return $root.'/'.$handle; } } /** // rm-file-from-storage.php: #!/usr/bin/env php &2 exit 3 fi mkdir -p $(dirname $DEST_FILE) cat - > $DEST_FILE */