// ----------------------------------------------------------------------------
// PixInsight JavaScript Runtime API - PJSR Version 1.0
// ----------------------------------------------------------------------------
// Copyright (c) 2003-2024 Pleiades Astrophoto S.L.
//
// Redistribution and use in both source and binary forms, with or without
// modification, is permitted provided that the following conditions are met:
//
// 1. All redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. All redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
// of their contributors, may be used to endorse or promote products derived
// from this software without specific prior written permission. For written
// permission, please contact info@pixinsight.com.
//
// 4. All products derived from this software, in any form whatsoever, must
// reproduce the following acknowledgment in the end-user documentation
// and/or other materials provided with the product:
//
// "This product is based on software from the PixInsight project, developed
// by Pleiades Astrophoto and its contributors (http://pixinsight.com/)."
//
// Alternatively, if that is where third-party acknowledgments normally
// appear, this acknowledgment must be reproduced in the product itself.
//
// THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
// INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
// DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// ----------------------------------------------------------------------------
/*!
* \brief Secure file removal routine.
*
* \param dirPath The base directory where files will be removed. Must be an
* absolute directory path specification. Relative paths are
* not allowed, as well as attempts to climb up the
* filesystem by means of '..' directory items.
*
* \param pattern A wildcard pattern for file selection, such as "*.txt" or
* "foo*.bar". This parameter is mandatory and cannot be an
* empty string.
*
* \param recursive If true, existing selected files will be removed
* recursively on the entire directory tree rooted at the
* \a dirPath base directory. If false, selected files will
* only be deleted on the base directory. If not specified,
* the default value is \c false.
*
* For enforced security, this routine will not attempt to follow symbolic
* links on platforms that support them.
*
* Returns the total number of files removed.
*
* \warning Incorrect use of this routine is <strong>extremely
* dangerous</strong>. If called with improper parameter values, this
* function may lead to an irreversible data loss. Extreme care must
* be taken in all cases, but very especially when files are deleted
* recursively.
*/
function removeFiles( dirPath, pattern, recursive )
{
function removeFiles_recursive( dirPath, pattern, recursive, baseDir )
{
if ( dirPath.indexOf( ".." ) >= 0 )
throw new Error( "removeFiles(): Attempt to climb up the filesystem." );
if ( !dirPath.startsWith( baseDir ) )
throw new Error( "removeFiles(): Attempt to redirect outside the base directory." );
if ( !File.directoryExists( dirPath ) )
throw new Error( "removeFiles(): Attempt to remove a nonexistent directory." );
let currentDir = dirPath;
if ( !currentDir.endsWith( '/' ) )
currentDir += '/';
let count = 0;
if ( recursive )
{
let f = new FileFind;
if ( f.begin( currentDir + "*" ) )
do
{
let itemPath = currentDir + f.name;
if ( !f.isSymbolicLink )
if ( f.isDirectory )
if ( f.name != "." && f.name != ".." )
count += removeFiles_recursive( itemPath, pattern, true/*recursive*/, baseDir );
}
while ( f.next() );
}
let f = new FileFind;
if ( f.begin( currentDir + pattern ) )
do
{
let itemPath = currentDir + f.name;
if ( !f.isSymbolicLink )
if ( f.isFile )
{
File.remove( itemPath );
++count;
}
}
while ( f.next() );
return count;
}
// Mandatory and default parameters.
if ( dirPath === undefined || dirPath.length == 0 )
throw Error( "removeFiles(): Missing mandatory dirPath argument" );
if ( pattern === undefined || pattern.length == 0 )
throw Error( "removeFiles(): Missing mandatory pattern argument" );
if ( recursive === undefined )
recursive = false;
// Use UNIX directory separators on all platforms.
if ( CoreApplication.platform == "Windows" )
dirPath = File.windowsPathToUnix( dirPath );
// Validate base directory.
if ( (CoreApplication.platform == "Windows") ?
dirPath.indexOf( ':' ) != 1 || dirPath.indexOf( '/' ) != 2 :
dirPath.indexOf( '/' ) != 0 )
throw new Error( "removeFiles(): Relative directory." );
if ( !File.directoryExists( dirPath ) )
throw new Error( "removeFiles(): Nonexistent directory." );
// Remove files.
return removeFiles_recursive( dirPath, pattern, recursive, dirPath );
}