nsFileSpecMac.cpp revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// This file is included by nsFile.cp, and includes the Macintosh-specific
// implementations.
#include <string.h>
#include "prtypes.h"
#include "nscore.h"
#include "FullPath.h"
#include "FileCopy.h"
#include "MoreFilesExtras.h"
#include <Aliases.h>
#include <Folders.h>
#include <Math64.h>
#include <TextUtils.h>
#include <Processes.h>
#include <limits.h> // ULONG_MAX
#include "nsFileSpec.h"
#include "nsEscape.h"
#include "nsXPIDLString.h"
const unsigned char* kAliasHavenFolderName = "\pnsAliasHaven";
//========================================================================================
namespace MacFileHelpers
//========================================================================================
{
{
}
void SwapSlashColon(char * s);
const char * unixPath,
Boolean allowPartial = false,
Boolean createDirs = false);
char* MacPathFromUnixPath(
const char* unixPath,
char* EncodeMacPath(
char* inPath, // NOT const - gets clobbered
const char* inPathNamePtr,
char* PathNameFromFSSpec(
long dirID,
short& outRefNum, // Volume of the created folder
long& outDirID); //
// Some routines to support an "alias haven" directory. Aliases in this directory
// are never resolved. There is a ResolveAlias here that respects that. This is
// to support attaching of aliases in mail.
void EnsureAliasHaven();
Boolean sNoResolve = false;
long sAliasHavenDirID = 0;
short sAliasHavenVRefNum = 0;
} // namespace MacFileHelpers
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
}
//-----------------------------------
void MacFileHelpers::SwapSlashColon(char * s)
//-----------------------------------
{
while (*s)
{
if (*s == '/')
*s++ = ':';
else if (*s == ':')
*s++ = '/';
else
*s++;
}
} // MacFileHelpers::SwapSlashColon
//-----------------------------------
char* MacFileHelpers::EncodeMacPath(
char* inPath, // NOT const, gets clobbered
// Transforms Macintosh style path into Unix one
// Method: Swap ':' and '/', hex escape the result
//-----------------------------------
{
return nsnull;
// XP code sometimes chokes if there's a final slash in the unix path.
// Since correct mac paths to folders and volumes will end in ':', strip this
// first.
if (*c == ':')
{
*c = 0;
pathSize--;
}
if (prependSlash)
{
}
else
{
}
if (newPath)
{
if (doEscape)
{
delete [] newPath;
}
else
}
delete [] inPath;
return finalPath;
} // MacFileHelpers::EncodeMacPath
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
} // MacFileHelpers::SetNoResolve
//----------------------------------------------------------------------------------------
// Pass in the spec of an alias. This copies the file to the safe haven folder, and
// returns the spec of the copy to the caller
//----------------------------------------------------------------------------------------
{
// Make sure its name is unique
// Copy the file into the haven directory
{
nil, 0, true);
// Return the spec of the copy to the caller.
return err;
}
return noErr;
} // MacFileHelpers::MakeAliasSafe
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// Relying on the fact that the unix path is always longer than the mac path:
// REMEMBER: at the end we call SwapSlashColon, so bear that in mind when you see
// this code using '/' as a separator in what is supposed to be a Macintosh path!
if (result)
{
src++;
{
// * partial path, and not just a leaf name. The '.' test is there because
// the loop below will add sufficient colons in that case.
*dst++ = '/';
}
// Copy src to dst, but watch out for .. and .
char c = '/';
do
{
char cprev = c; // remember the previous char (initially /)
c = *src++;
{
// Special cases: "." and "..". Convert to ':' and '::'
c = *src++;
if (c == '.')
{
c = *src++;
}
if (c == '/')
{
// ../ becomes :: so just skip the slash
// ./ becomes : " " " " "
src++;
}
else if (c)
{
// Oh. A file called ".foo" or "..foo"
// Back up and just do the normal thing.
// Since c is not '/', we won't do this stuff on the
// next iteration.
}
continue;
}
{
// Hmm. A 'run on' path with two slashes right next to each other.
// This is an illegal path, but, hey, we'll be tough and try to
// deal with it (especially since '::' has loaded semantics in
// a Mac path)
continue;
}
*dst++ = c;
} while (c);
if (hexDecode)
}
return result;
} // MacFileHelpers::MacPathFromUnixPath
//----------------------------------------------------------------------------------------
const char* inPathNamePtr,
// FSSpecFromPathname reverses PathNameFromFSSpec.
// It returns a FSSpec given a c string which is a mac pathname.
//----------------------------------------------------------------------------------------
{
// Simplify this routine to use FSMakeFSSpec if length < 255. Otherwise use the MoreFiles
// routine FSpLocationFromFullPath, which allocates memory, to handle longer pathnames.
#ifdef NS_DEBUG
// Attempt to catch people sending unix paths in to routines that expect native ones.
"Possible unix path where native path is required");
#endif
if (inLength < 255)
{
if (isRelative)
else
}
else if (!isRelative)
else
{
const char* path = inPathNamePtr;
if (isRelative)
{
}
else
{
}
do {
// Locate the colon that terminates the node.
// But if we've a partial path (starting with a colon), find the second one.
// Well, if there are no more colons, point to the end of the string.
if (!nextColon)
// Make a pascal string out of this node. Include initial
// and final colon, if any!
// Use this string as a relative path using the directory created
// on the previous round (or directory 0,0 on the first round).
// If this was the leaf node, then we are done.
if (!*nextColon)
break;
// Since there's more to go, we have to get the directory ID, which becomes
// the parID for the next round.
{
// The directory (or perhaps a file) exists. Find its dirID.
long dirID;
if (!isDirectory)
return dupFNErr; // oops! a file exists with that name.
if (err)
return err;
}
{
// If we got "file not found", then
// we need to create a directory.
// For some reason, this usually returns fnfErr, even though it works.
}
return err;
} while (1);
}
return err;
} // MacFileHelpers::FSSpecFromPathname
//----------------------------------------------------------------------------------------
long dirID,
short& outRefNum, // Volume of the created folder
long& outDirID) //
// Creates a folder named 'folderName' inside a folder.
// The errors returned are same as PBDirCreate
//----------------------------------------------------------------------------------------
{
{
}
else
{
outRefNum = 0;
outDirID = 0;
}
return err;
} // MacFileHelpers::CreateFolderInFolder
//----------------------------------------------------------------------------------------
void MacFileHelpers::EnsureAliasHaven()
//----------------------------------------------------------------------------------------
{
// Alias Haven is a directory in which we never resolve aliases.
if (sAliasHavenVRefNum != 0)
return;
{
kAliasHavenFolderName, // Name of the new folder
sAliasHavenVRefNum, // Volume of the created folder
}
} // MacFileHelpers::EnsureAliasHaven
//----------------------------------------------------------------------------------------
// Returns true if the alias is in the alias haven directory, or if alias resolution
// has been turned off.
//----------------------------------------------------------------------------------------
{
return sNoResolve
} // MacFileHelpers::IsAliasSafe
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
wasAliased = false;
if (IsAliasSafe(inOutSpec))
return noErr;
} // MacFileHelpers::ResolveAliasFile
//-----------------------------------
const char * unixPath,
// File spec from URL. Reverses GetURLFromFileSpec
// Its input is only the <path> part of the URL
// JRM 97/01/08 changed this so that if it's a partial path (doesn't start with '/'),
// then it is combined with inOutSpec's vRefNum and parID to form a new spec.
//-----------------------------------
{
return badFidErr;
if (!macPath)
return memFullErr;
if (!allowPartial)
{
}
delete [] macPath;
return err;
} // MacFileHelpers::FSSpecFromLocalUnixPath
//-----------------------------------
// Returns a full pathname to the given file
// Returned value is allocated with new [], and must be freed with delete []
// For consistency and to work under OS X this creates an nsILocalFileMac and has it do the work.
//-----------------------------------
{
return result;
} // MacFileHelpers::PathNameFromFSSpec
#pragma mark -
//========================================================================================
// Macintosh nsFileSpec implementation
//========================================================================================
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
Clear();
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
if (resolveAlias)
{
}
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED
if (inNativePathString)
{
}
} // nsFileSpec::nsFileSpec
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED
mSpec, inCreateDirs));
} // nsFileSpec::nsFileSpec
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
if (resolveAlias)
{
}
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
*this = inPath.GetFileSpec();
}
//----------------------------------------------------------------------------------------
void nsFileSpec::operator = (const char* inString)
//----------------------------------------------------------------------------------------
{
Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED
if (inString)
{
}
} // nsFileSpec::operator =
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
mPath.SetToEmpty();
} // nsFileSpec::operator =
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
*this = inPath.GetFileSpec();
} // nsFileSpec::operator =
//----------------------------------------------------------------------------------------
inline void nsFileSpec::Clear()
//----------------------------------------------------------------------------------------
{
mPath.SetToEmpty();
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
} // nsFileSpec::Exists()
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
else
outStamp = 0;
} // nsFileSpec::GetModDate
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
return 0;
} // nsFileSpec::GetFileSize
//----------------------------------------------------------------------------------------
// In leaf name can actually be a partial path...
//----------------------------------------------------------------------------------------
{
mPath.SetToEmpty();
if (inLeafName)
{
// what about long relative paths? Hmm? We don't have a routine for this anywhere.
}
} // nsFileSpec::SetLeafName
//----------------------------------------------------------------------------------------
char* nsFileSpec::GetLeafName() const
// Result needs to be nsCRT::free()ed.
//----------------------------------------------------------------------------------------
{
} // nsFileSpec::GetLeafName
//----------------------------------------------------------------------------------------
void nsFileSpec::MakeAliasSafe()
//----------------------------------------------------------------------------------------
{
mPath.SetToEmpty();
} // nsFileSpec::MakeAliasSafe
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
mPath.SetToEmpty();
if (inSuggestedLeafName[0] > 0)
MakeUnique();
} // nsFileSpec::MakeUnique
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
long dirID;
} // nsFileSpec::IsFile
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
long dirID;
} // nsFileSpec::IsDirectory
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
return hidden;
} // nsFileSpec::IsHidden
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
return hidden;
} // nsFileSpec::IsSymlink
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
if (wasAliased2)
{
}
else
return mError;
} // nsFileSpec::ResolveSymlink
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
if (NS_SUCCEEDED(mError))
} // nsFileSpec::GetParent
//----------------------------------------------------------------------------------------
void nsFileSpec::operator += (const char* inRelativePath)
//----------------------------------------------------------------------------------------
{
// Invalidate the path cache string, since we're changing ourselves.
mPath.SetToEmpty();
// if we are already bad, don't allow appendage
{
NS_WARNING("trying to append to a bad nsFileSpec");
return;
}
// Find the dirID of the directory described by this spec
long dirID;
return;
// mSpec.vRefNum is already correct.
// Next, determine if it is a UNIX or Mac style path. Now, Macintosh relative paths
// are either leaf names (in which the distinction between unix and macintosh
// relative paths disappears) or they start with a colon. If we find an initial colon,
// then assume it's a macintosh path.
// If it is a UNIX path (including just a leaf name), we will also look for ':' and
// assert if we find one.
if (*inRelativePath != ':')
{
// Looks like a UNIX path (including possibly just a leaf name)
// Convert unix path (which is unencoded) to a spec
}
else
{
// We must be a mac path!
}
} // nsFileSpec::operator +=
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
long ignoredDirID;
// it's OK if the dir already exists
} // nsFileSpec::CreateDirectory
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
if (inRecursive)
{
// MoreFilesExtras
anErr = ::DeleteDirectory(
}
else
} // nsFileSpec::Delete
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
if (IsDirectory())
{
{
}
{
if (child.IsDirectory())
{
tmpDirSpec += leafname;
}
else
{
}
}
}
else
{
{
}
}
} // nsFileSpec::RecursiveCopy
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
short refNum;
// First see if we have an internal error set
return mError;
// Need to open the file to trunc
return NS_FILE_FAILURE;
// Close the file unless we got an error that it was already closed
return NS_FILE_FAILURE;
return NS_OK;
} // nsFileSpec::Truncate
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
return NS_FILE_FAILURE; // no relative paths here!
return NS_FILE_FAILURE;
return NS_OK;
} // nsFileSpec::Rename
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// We can only copy into a directory, and (for now) can not copy entire directories
return NS_FILE_FAILURE;
const_cast<StringPtr>(GetLeafPName()),
0,
true));
return rv;
} // nsFileSpec::CopyToDir
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// We can only move into a directory
if (!newParentDir.IsDirectory())
return NS_FILE_FAILURE;
const_cast<StringPtr>(GetLeafPName())));
if ( NS_SUCCEEDED(result) )
{
char* leafName = GetLeafName();
*this = newParentDir + leafName;
}
return result;
} // nsFileSpec::MoveToDir
//----------------------------------------------------------------------------------------
nsresult nsFileSpec::Execute(const char* /*args - how can this be cross-platform? problem! */ ) const
//----------------------------------------------------------------------------------------
{
if (IsDirectory())
return NS_FILE_FAILURE;
/* launch the thing */
return result;
} // nsFileSpec::Execute
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
return PBGetCatInfoSync(&outInfo);
} // nsFileSpec::GetCatInfo()
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
return err;
return err;
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
return err;
return noErr;
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
pb.ioVolIndex = 0;
// PBXGetVolInfoSync works on HFS+ volumes too!
{
#ifdef HAVE_LONG_LONG
#else
#endif
}
return space64Bits;
} // nsFileSpec::GetDiskSpace()
//----------------------------------------------------------------------------------------
const char* nsFileSpec::GetCString() const
// This is the only conversion to const char* that is provided, and it allows the
// path to be "passed" to NSPR file routines. This practice is VERY EVIL and should only
// be used to support legacy code. Using it guarantees bugs on Macintosh. The string is
// cached and freed by the nsFileSpec destructor, so do not delete (or free) it.
//----------------------------------------------------------------------------------------
{
{
delete[] path;
} else {
}
}
return mPath;
}
#pragma mark -
//========================================================================================
// Macintosh nsFilePath implementation
//========================================================================================
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
spec,
false,
true, // resolve alias
true,
// Now we have a spec,
// Invoke operator = (const nsFileSpec&) to do the rest.
// Why didn't we just say mPath = inString to get the path? Well, we want it to be
// canonical and absolute.
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
} //nsFilePath::nsFilePath
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
}
//----------------------------------------------------------------------------------------
void nsFilePath::operator = (const char* inString)
//----------------------------------------------------------------------------------------
{
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
*this = inSpec;
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
*this = inOther;
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
} // nsFilePath::operator =
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
}
#pragma mark -
//========================================================================================
// nsFileURL implementation
//========================================================================================
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
true, // need to decode
false, // resolve alias
false, // must be a full path
inCreateDirs));
} // nsFileURL::nsFileURL
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
"Not a URL!");
true, // need to decode
false, // resolve alias
false, // must be a full path
inCreateDirs));
} // nsFileURL::nsFileURL
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
*this = inOther.GetFileSpec();
} // nsFileURL::nsFileURL
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
*this = inOther;
} // nsFileURL::nsFileURL
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
*this = inOther.GetFileSpec();
} // nsFileURL::operator =
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
mURL = encodedURL;
mURL += "/";
} // nsFileURL::operator =
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
true, // need to decode
true, // resolve alias
false, // must be a full path
false)); // don't create dirs.
} // nsFileURL::operator =
#pragma mark -
//========================================================================================
// nsDirectoryIterator
//========================================================================================
//----------------------------------------------------------------------------------------
const nsFileSpec& inDirectory
//----------------------------------------------------------------------------------------
, mExists(false)
, mIndex(-1)
{
// test that we have got a directory back, not a file
return;
// Sorry about this, there seems to be a bug in CWPro 4:
mIndex = 0; // ready to increment
++(*this); // the pre-increment operator
} // nsDirectoryIterator::nsDirectoryIterator
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
{
// Sorry about this, there seems to be a bug in CWPro 4:
if (mExists && mResoveSymLinks)
{
}
return err;
} // nsDirectoryIterator::SetToIndex()
//----------------------------------------------------------------------------------------
nsDirectoryIterator& nsDirectoryIterator::operator -- ()
//----------------------------------------------------------------------------------------
{
mExists = false;
while (--mIndex > 0)
{
break;
}
return *this;
} // nsDirectoryIterator::operator --
//----------------------------------------------------------------------------------------
nsDirectoryIterator& nsDirectoryIterator::operator ++ ()
//----------------------------------------------------------------------------------------
{
mExists = false;
if (mIndex >= 0) // probably trying to use a file as a directory!
{
break;
}
return *this;
} // nsDirectoryIterator::operator ++