Landing nsIFile.
This commit is contained in:
@@ -28,26 +28,25 @@
|
||||
|
||||
/* we're going to need some autoconf loving, I can just tell */
|
||||
#include <sys/types.h>
|
||||
/* XXXautoconf for glibc */
|
||||
#define __USE_BSD
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <utime.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "nsCRT.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsFileUtils.h"
|
||||
#include "nsIAllocator.h"
|
||||
#include "nsIDirectoryEnumerator.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsLocalFileUnix.h"
|
||||
#include "nsIComponentManager.h"
|
||||
|
||||
#define FILL_STAT_CACHE() \
|
||||
#define VALIDATE_STAT_CACHE() \
|
||||
PR_BEGIN_MACRO \
|
||||
if (!mHaveCachedStat) { \
|
||||
fillStatCache(); \
|
||||
FillStatCache(); \
|
||||
if (!mHaveCachedStat) \
|
||||
return NSRESULT_FOR_ERRNO(); \
|
||||
} \
|
||||
@@ -59,6 +58,123 @@
|
||||
return NS_ERROR_NOT_INITIALIZED; \
|
||||
PR_END_MACRO
|
||||
|
||||
#define mLL_II2L(hi, lo, res) \
|
||||
LL_I2L(res, hi); \
|
||||
LL_SHL(res, res, 32); \
|
||||
LL_ADD(res, res, lo);
|
||||
|
||||
#define mLL_L2II(a64, hi, lo) \
|
||||
PR_BEGIN_MACRO \
|
||||
PRInt64 tmp; \
|
||||
LL_SHR(tmp, a64, 32); \
|
||||
LL_L2I(hi, tmp); \
|
||||
LL_SHL(tmp, a64, 32); \
|
||||
LL_SHR(tmp, tmp, 32); \
|
||||
LL_L2I(lo, tmp); \
|
||||
PR_END_MACRO
|
||||
|
||||
/* directory enumerator */
|
||||
class NS_COM
|
||||
nsDirEnumeratorUnix : public nsISimpleEnumerator
|
||||
{
|
||||
public:
|
||||
nsDirEnumeratorUnix();
|
||||
virtual ~nsDirEnumeratorUnix();
|
||||
|
||||
// nsISupports interface
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsISimpleEnumerator interface
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
|
||||
NS_IMETHOD Init(nsIFile *parent, PRBool ignored);
|
||||
protected:
|
||||
NS_IMETHOD GetNextEntry();
|
||||
|
||||
DIR *mDir;
|
||||
struct dirent *mEntry;
|
||||
nsXPIDLCString mParentPath;
|
||||
};
|
||||
|
||||
nsDirEnumeratorUnix::nsDirEnumeratorUnix() :
|
||||
mDir(nsnull), mEntry(nsnull)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsDirEnumeratorUnix::~nsDirEnumeratorUnix()
|
||||
{
|
||||
if (mDir)
|
||||
closedir(mDir);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsDirEnumeratorUnix, nsISimpleEnumerator)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirEnumeratorUnix::Init(nsIFile *parent, PRBool resolveSymlinks /*ignored*/)
|
||||
{
|
||||
nsXPIDLCString dirPath;
|
||||
if (NS_FAILED(parent->GetPath(getter_Copies(dirPath))) ||
|
||||
(const char *)dirPath == 0)
|
||||
return NS_ERROR_FILE_INVALID_PATH;
|
||||
|
||||
if (NS_FAILED(parent->GetPath(getter_Copies(mParentPath))))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mDir = opendir(dirPath);
|
||||
if (!mDir)
|
||||
return NSRESULT_FOR_ERRNO();
|
||||
return GetNextEntry();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirEnumeratorUnix::HasMoreElements(PRBool *result)
|
||||
{
|
||||
*result = mDir && mEntry;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirEnumeratorUnix::GetNext(nsISupports **_retval)
|
||||
{
|
||||
nsresult rv;
|
||||
if (!mDir || !mEntry) {
|
||||
*_retval = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILocalFile> file = new nsLocalFile();
|
||||
if (!file)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (NS_FAILED(rv = file->InitWithPath(mParentPath)) ||
|
||||
NS_FAILED(rv = file->Append(mEntry->d_name))) {
|
||||
return rv;
|
||||
}
|
||||
*_retval = file;
|
||||
NS_ADDREF(*_retval);
|
||||
return GetNextEntry();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirEnumeratorUnix::GetNextEntry()
|
||||
{
|
||||
do {
|
||||
errno = 0;
|
||||
mEntry = readdir(mDir);
|
||||
|
||||
/* end of dir or error */
|
||||
if (!mEntry)
|
||||
return NSRESULT_FOR_ERRNO();
|
||||
|
||||
/* keep going past "." and ".." */
|
||||
} while (mEntry->d_name[0] == '.' &&
|
||||
(mEntry->d_name[1] == '\0' || /* .\0 */
|
||||
(mEntry->d_name[1] == '.' &&
|
||||
mEntry->d_name[2] == '\0'))); /* ..\0 */
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsLocalFile::nsLocalFile() :
|
||||
mHaveCachedStat(PR_FALSE)
|
||||
{
|
||||
@@ -70,13 +186,13 @@ nsLocalFile::~nsLocalFile()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsLocalFile, nsIFile);
|
||||
NS_IMPL_ISUPPORTS2(nsLocalFile, nsIFile, nsILocalFile);
|
||||
|
||||
nsresult
|
||||
nsLocalFile::Create(nsISupports *outer, const nsIID &aIID, void **aInstancePtr)
|
||||
nsLocalFile::nsLocalFileConstructor(nsISupports *outer, const nsIID &aIID, void **aInstancePtr)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aInstancePtr);
|
||||
NS_ENSURE_PROPER_AGGREGATION(outer, aIID);
|
||||
NS_ENSURE_NO_AGGREGATION(outer);
|
||||
|
||||
*aInstancePtr = 0;
|
||||
|
||||
@@ -86,24 +202,19 @@ nsLocalFile::Create(nsISupports *outer, const nsIID &aIID, void **aInstancePtr)
|
||||
return inst->QueryInterface(aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::Clone(nsIFile **file)
|
||||
{
|
||||
nsresult rv;
|
||||
NS_ENSURE_ARG(file);
|
||||
|
||||
*file = nsnull;
|
||||
|
||||
nsCOMPtr<nsILocalFile> localFile;
|
||||
nsresult rv = nsComponentManager::CreateInstance(NS_LOCAL_FILE_PROGID,
|
||||
nsnull,
|
||||
nsCOMTypeInfo<nsILocalFile>::GetIID(),
|
||||
getter_AddRefs(localFile));
|
||||
nsCOMPtr<nsILocalFile> localFile = new nsLocalFile();
|
||||
if (localFile == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = localfile->InitWithPath(mPath);
|
||||
rv = localFile->InitWithPath(mPath);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
@@ -115,28 +226,70 @@ nsLocalFile::Clone(nsIFile **file)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::InitWithPath(PRUint32 pathType, const char *filePath)
|
||||
nsLocalFile::InitWithPath(const char *filePath)
|
||||
{
|
||||
NS_ENSURE_ARG(filePath);
|
||||
NS_ASSERTION(pathType == NATIVE_PATH ||
|
||||
pathType == UNIX_PATH ||
|
||||
pathType == NSPR_PATH, "unrecognized path type");
|
||||
|
||||
/* NATIVE_PATH == UNIX_PATH == NSPR_PATH for us */
|
||||
mPath = filePath;
|
||||
invalidateCache();
|
||||
InvalidateCache();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::createAllParentDirectories(PRUint32 permissions)
|
||||
nsLocalFile::CreateAllAncestors(PRUint32 permissions)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
/* <jband> I promise to play nice */
|
||||
char *buffer = NS_CONST_CAST(char *, (const char *)mPath),
|
||||
*ptr = buffer;
|
||||
|
||||
#ifdef DEBUG_NSIFILE
|
||||
fprintf(stderr, "nsIFile: before: %s\n", buffer);
|
||||
#endif
|
||||
|
||||
while ((ptr = strchr(ptr + 1, '/'))) {
|
||||
/*
|
||||
* Sequences of '/' are equivalent to a single '/'.
|
||||
*/
|
||||
if (ptr[1] == '/')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If the path has a trailing slash, don't make the last component here,
|
||||
* because we'll get EEXISTS in Create when we try to build the final
|
||||
* component again, and it's easier to condition the logic here than
|
||||
* there.
|
||||
*/
|
||||
if (!ptr[1])
|
||||
break;
|
||||
/* Temporarily NUL-terminate here */
|
||||
*ptr = '\0';
|
||||
#ifdef DEBUG_NSIFILE
|
||||
fprintf(stderr, "nsIFile: mkdir(\"%s\")\n", buffer);
|
||||
#endif
|
||||
int result = mkdir(buffer, permissions);
|
||||
/* Put the / back before we (maybe) return */
|
||||
*ptr = '/';
|
||||
|
||||
/*
|
||||
* We could get EEXISTS for an existing file -- not directory --
|
||||
* with the name of one of our ancestors, but that's OK: we'll get
|
||||
* ENOTDIR when we try to make the next component in the path,
|
||||
* either here on back in Create, and error out appropriately.
|
||||
*/
|
||||
if (result == -1 && errno != EEXIST)
|
||||
return NSRESULT_FOR_ERRNO();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_NSIFILE
|
||||
fprintf(stderr, "nsIFile: after: %s\n", buffer);
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::Open(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
|
||||
nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
|
||||
{
|
||||
CHECK_mPath();
|
||||
|
||||
@@ -148,7 +301,18 @@ nsLocalFile::Open(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval)
|
||||
{
|
||||
CHECK_mPath();
|
||||
|
||||
*_retval = fopen(mPath, mode);
|
||||
|
||||
if (*_retval)
|
||||
return NS_OK;
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::Create(PRUint32 type, PRUint32 permissions)
|
||||
@@ -166,11 +330,33 @@ nsLocalFile::Create(PRUint32 type, PRUint32 permissions)
|
||||
|
||||
if (result == -1 && errno == ENOENT) {
|
||||
/*
|
||||
* if we failed because of missing parent components, try to create them
|
||||
* and then retry the original creation.
|
||||
* If we failed because of missing ancestor components, try to create
|
||||
* them and then retry the original creation.
|
||||
*
|
||||
* Ancestor directories get the same permissions as the file we're
|
||||
* creating, with the X bit set for each of (user,group,other) with
|
||||
* an R bit in the original permissions. If you want to do anything
|
||||
* fancy like setgid or sticky bits, do it by hand.
|
||||
*/
|
||||
if (NS_FAILED(createAllParentDirectories(permissions)))
|
||||
int dirperm = permissions;
|
||||
if (permissions & S_IRUSR)
|
||||
dirperm |= S_IXUSR;
|
||||
if (permissions & S_IRGRP)
|
||||
dirperm |= S_IXGRP;
|
||||
if (permissions & S_IROTH)
|
||||
dirperm |= S_IXOTH;
|
||||
|
||||
#ifdef DEBUG_NSIFILE
|
||||
fprintf(stderr, "nsIFile: perm = %o, dirperm = %o\n", permissions,
|
||||
dirperm);
|
||||
#endif
|
||||
|
||||
if (NS_FAILED(CreateAllAncestors(dirperm)))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
#ifdef DEBUG_NSIFILE
|
||||
fprintf(stderr, "nsIFile: Create(\"%s\") again\n", (const char *)mPath);
|
||||
#endif
|
||||
result = creationFunc((const char *)mPath, permissions);
|
||||
}
|
||||
|
||||
@@ -184,7 +370,7 @@ nsLocalFile::Create(PRUint32 type, PRUint32 permissions)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::AppendPath(const char *fragment)
|
||||
nsLocalFile::Append(const char *fragment)
|
||||
{
|
||||
NS_ENSURE_ARG(fragment);
|
||||
CHECK_mPath();
|
||||
@@ -196,7 +382,7 @@ nsLocalFile::AppendPath(const char *fragment)
|
||||
strcat(newPath, "/");
|
||||
strcat(newPath, fragment);
|
||||
mPath = newPath;
|
||||
invalidateCache();
|
||||
InvalidateCache();
|
||||
nsAllocator::Free(newPath);
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -208,7 +394,7 @@ nsLocalFile::Normalize()
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLocalFile::getLeafNameRaw(const char **_retval)
|
||||
nsLocalFile::GetLeafNameRaw(const char **_retval)
|
||||
{
|
||||
CHECK_mPath();
|
||||
char *leafName = strrchr((const char *)mPath, '/');
|
||||
@@ -224,7 +410,7 @@ nsLocalFile::GetLeafName(char **aLeafName)
|
||||
NS_ENSURE_ARG_POINTER(aLeafName);
|
||||
nsresult rv;
|
||||
const char *leafName;
|
||||
if (NS_FAILED(rv = getLeafNameRaw(&leafName)))
|
||||
if (NS_FAILED(rv = GetLeafNameRaw(&leafName)))
|
||||
return rv;
|
||||
|
||||
*aLeafName = nsCRT::strdup(leafName);
|
||||
@@ -233,8 +419,33 @@ nsLocalFile::GetLeafName(char **aLeafName)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::GetPath(PRUint32 pathType, char **_retval)
|
||||
nsLocalFile::SetLeafName(const char *aLeafName)
|
||||
{
|
||||
NS_ENSURE_ARG(aLeafName);
|
||||
CHECK_mPath();
|
||||
|
||||
nsresult rv;
|
||||
char *leafName;
|
||||
if (NS_FAILED(rv = GetLeafNameRaw((const char**)&leafName)))
|
||||
return rv;
|
||||
char* newPath = (char *)nsAllocator::Alloc(strlen(mPath) +
|
||||
strlen(aLeafName) + 2);
|
||||
*leafName = 0;
|
||||
|
||||
strcpy(newPath, mPath);
|
||||
strcat(newPath, "/");
|
||||
strcat(newPath, aLeafName);
|
||||
mPath = newPath;
|
||||
InvalidateCache();
|
||||
nsAllocator::Free(newPath);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::GetPath(char **_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
|
||||
@@ -243,9 +454,6 @@ nsLocalFile::GetPath(PRUint32 pathType, char **_retval)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(pathType == NATIVE_PATH ||
|
||||
pathType == UNIX_PATH ||
|
||||
pathType == NSPR_PATH, "unrecognized path type");
|
||||
*_retval = nsCRT::strdup((const char *)mPath);
|
||||
if (!*_retval)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
@@ -255,7 +463,204 @@ nsLocalFile::GetPath(PRUint32 pathType, char **_retval)
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::CopyTo(nsIFile *newParent, const char *newName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
nsresult rv;
|
||||
|
||||
// check to make sure that we have a new parent
|
||||
// or have a new name
|
||||
if (newParent == nsnull && newName == nsnull)
|
||||
return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST;
|
||||
|
||||
// check to make sure that this has been initialized properly
|
||||
CHECK_mPath();
|
||||
|
||||
// check to see if we are a directory or if we are a file
|
||||
PRBool isDirectory;
|
||||
IsDirectory(&isDirectory);
|
||||
|
||||
if (isDirectory)
|
||||
{
|
||||
// XXX
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ok, we're a file so this should be easy as pie.
|
||||
// check to see if our target exists
|
||||
PRBool targetExists;
|
||||
newParent->Exists(&targetExists);
|
||||
// check to see if we need to create it
|
||||
if (targetExists == PR_FALSE)
|
||||
{
|
||||
// XXX create the new directory with some permissions
|
||||
rv = newParent->Create(DIRECTORY_TYPE, 0755);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
// make sure that the target is actually a directory
|
||||
PRBool targetIsDirectory;
|
||||
newParent->IsDirectory(&targetIsDirectory);
|
||||
if (targetIsDirectory == PR_FALSE)
|
||||
return NS_ERROR_FILE_DESTINATION_NOT_DIR;
|
||||
// ok, we got this far. create the name of the new file.
|
||||
nsXPIDLCString leafName;
|
||||
nsXPIDLCString newPath;
|
||||
const char *tmpConstChar;
|
||||
char *tmpChar;
|
||||
// get the leaf name of the new file if a name isn't supplied.
|
||||
if (newName == nsnull)
|
||||
{
|
||||
if (NS_FAILED(rv = GetLeafNameRaw(&tmpConstChar)))
|
||||
return rv;
|
||||
leafName = tmpConstChar;
|
||||
}
|
||||
else
|
||||
{
|
||||
leafName = newName;
|
||||
}
|
||||
// get the path name
|
||||
if (NS_FAILED(rv = newParent->GetPath(&tmpChar)))
|
||||
return rv;
|
||||
|
||||
// this is the full path to the dir of the new file
|
||||
newPath = tmpChar;
|
||||
nsAllocator::Free(tmpChar);
|
||||
|
||||
// create the final name
|
||||
char *newPathName;
|
||||
newPathName = (char *)nsAllocator::Alloc(strlen(newPath) + strlen(leafName) + 2);
|
||||
if (!newPathName)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
strcpy(newPathName, newPath);
|
||||
strcat(newPathName, "/");
|
||||
strcat(newPathName, leafName);
|
||||
|
||||
#ifdef DEBUG_blizzard
|
||||
printf("nsLocalFile::CopyTo() %s -> %s\n", (const char *)mPath, newPathName);
|
||||
#endif
|
||||
|
||||
nsXPIDLCString newPathNameAuto;
|
||||
newPathNameAuto = newPathName;
|
||||
nsAllocator::Free(newPathName);
|
||||
|
||||
// actually create the file.
|
||||
|
||||
nsLocalFile *newFile = new nsLocalFile();
|
||||
newFile->AddRef(); // we own this.
|
||||
if (newFile == nsnull)
|
||||
{
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
rv = newFile->InitWithPath(newPathNameAuto);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
NS_RELEASE(newFile);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// get the old permissions
|
||||
PRUint32 myPerms;
|
||||
GetPermissions(&myPerms);
|
||||
// create the new file with the same permissions
|
||||
rv = newFile->Create(NORMAL_FILE_TYPE, myPerms);
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
NS_RELEASE(newFile);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// open the new file.
|
||||
|
||||
PRInt32 openFlags = PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE;
|
||||
PRInt32 modeFlags = myPerms;
|
||||
PRFileDesc *newFD = nsnull;
|
||||
|
||||
rv = newFile->OpenNSPRFileDesc(openFlags, modeFlags, &newFD);
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
NS_RELEASE(newFile);
|
||||
return rv;
|
||||
}
|
||||
if (newFD == nsnull)
|
||||
{
|
||||
NS_RELEASE(newFile);
|
||||
NSRESULT_FOR_ERRNO();
|
||||
}
|
||||
|
||||
// open the old file, too
|
||||
|
||||
openFlags = PR_RDONLY;
|
||||
PRFileDesc *oldFD = nsnull;
|
||||
|
||||
rv = OpenNSPRFileDesc(openFlags, modeFlags, &oldFD);
|
||||
// make sure to clean up properly
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
NS_RELEASE(newFile);
|
||||
PR_Close(newFD);
|
||||
return rv;
|
||||
}
|
||||
if (newFD == nsnull)
|
||||
{
|
||||
NS_RELEASE(newFile);
|
||||
PR_Close(newFD);
|
||||
NSRESULT_FOR_ERRNO();
|
||||
}
|
||||
|
||||
// get the length of the file
|
||||
|
||||
PRStatus status;
|
||||
PRFileInfo fileInfo;
|
||||
status = PR_GetFileInfo(mPath, &fileInfo);
|
||||
if (status != PR_SUCCESS)
|
||||
{
|
||||
NS_RELEASE(newFile);
|
||||
PR_Close(newFD);
|
||||
NSRESULT_FOR_ERRNO();
|
||||
}
|
||||
|
||||
// get the size of the file.
|
||||
|
||||
PROffset32 fileSize;
|
||||
fileSize = fileInfo.size;
|
||||
PRInt32 bytesRead = 0;
|
||||
PRInt32 bytesWritten = 0;
|
||||
PRInt32 totalRead = 0;
|
||||
PRInt32 totalWritten = 0;
|
||||
|
||||
char buf[BUFSIZ];
|
||||
|
||||
while(1)
|
||||
{
|
||||
bytesRead = PR_Read(oldFD, &buf, BUFSIZ);
|
||||
if (bytesRead == 0)
|
||||
break;
|
||||
if (bytesRead == -1)
|
||||
return NS_ERROR_FAILURE;
|
||||
totalRead += bytesRead;
|
||||
bytesWritten = PR_Write(newFD, &buf, bytesRead);
|
||||
if (bytesWritten == -1)
|
||||
return NS_ERROR_FAILURE;
|
||||
totalWritten += bytesWritten;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_blizzard
|
||||
printf("read %d bytes, wrote %d bytes\n",
|
||||
totalRead, totalWritten);
|
||||
#endif
|
||||
|
||||
// close the files
|
||||
PR_Close(newFD);
|
||||
PR_Close(oldFD);
|
||||
|
||||
// free our resources
|
||||
NS_RELEASE(newFile);
|
||||
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@@ -270,37 +675,37 @@ nsLocalFile::MoveTo(nsIFile *newParent, const char *newName)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::MoveToFollowingLinks(nsIFile *newParent, const char *newName)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::Execute(const char *args)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::Delete(PRBool recursive)
|
||||
{
|
||||
FILL_STAT_CACHE();
|
||||
VALIDATE_STAT_CACHE();
|
||||
PRBool isDir = S_ISDIR(mCachedStat.st_mode);
|
||||
|
||||
/* XXX ?
|
||||
* if (!isDir && recursive)
|
||||
* return NS_ERROR_INVALID_ARG;
|
||||
*/
|
||||
invalidateCache();
|
||||
InvalidateCache();
|
||||
|
||||
if (isDir) {
|
||||
if (recursive) {
|
||||
nsCOMPtr<nsIDirectoryEnumerator> iterator;
|
||||
nsresult rv = NS_NewDirectoryEnumerator(this, PR_FALSE,
|
||||
getter_AddRefs(iterator));
|
||||
if (NS_FAILED(rv))
|
||||
nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix();
|
||||
if (!dir)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = dir->Init(this, PR_FALSE);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete dir;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
iterator = do_QueryInterface(dir, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete dir;
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRBool more;
|
||||
rv = iterator->HasMoreElements(&more);
|
||||
while (NS_SUCCEEDED(rv) && more) {
|
||||
@@ -329,39 +734,41 @@ nsLocalFile::Delete(PRBool recursive)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::GetLastModificationDate(PRUint32 *aLastModificationDate)
|
||||
nsLocalFile::GetLastModificationDate(PRInt64 *aLastModificationDate)
|
||||
{
|
||||
NS_ENSURE_ARG(aLastModificationDate);
|
||||
FILL_STAT_CACHE();
|
||||
*aLastModificationDate = (PRUint32)mCachedStat.st_mtime;
|
||||
VALIDATE_STAT_CACHE();
|
||||
mLL_II2L(0, (PRUint32)mCachedStat.st_mtime, *aLastModificationDate);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::SetLastModificationDate(PRUint32 aLastModificationDate)
|
||||
nsLocalFile::SetLastModificationDate(PRInt64 aLastModificationDate)
|
||||
{
|
||||
int result;
|
||||
if (aLastModificationDate) {
|
||||
FILL_STAT_CACHE();
|
||||
VALIDATE_STAT_CACHE();
|
||||
struct utimbuf ut;
|
||||
ut.actime = mCachedStat.st_atime;
|
||||
ut.modtime = (time_t)aLastModificationDate;
|
||||
PRInt32 hi, lo;
|
||||
mLL_L2II(aLastModificationDate, hi, lo);
|
||||
ut.modtime = (time_t)lo;
|
||||
result = utime(mPath, &ut);
|
||||
} else {
|
||||
result = utime(mPath, NULL);
|
||||
}
|
||||
invalidateCache();
|
||||
InvalidateCache();
|
||||
return NSRESULT_FOR_RETURN(result);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::GetLastModificationDateOfLink(PRUint32 *aLastModificationDateOfLink)
|
||||
nsLocalFile::GetLastModificationDateOfLink(PRInt64 *aLastModificationDateOfLink)
|
||||
{
|
||||
NS_ENSURE_ARG(aLastModificationDateOfLink);
|
||||
struct stat sbuf;
|
||||
if (lstat(mPath, &sbuf) == -1)
|
||||
return NSRESULT_FOR_ERRNO();
|
||||
*aLastModificationDateOfLink = (PRUint32)sbuf.st_mtime;
|
||||
mLL_II2L(0, (PRUint32)sbuf.st_mtime, *aLastModificationDateOfLink);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -369,7 +776,7 @@ nsLocalFile::GetLastModificationDateOfLink(PRUint32 *aLastModificationDateOfLink
|
||||
* utime(2) may or may not dereference symlinks, joy.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::SetLastModificationDateOfLink(PRUint32 aLastModificationDateOfLink)
|
||||
nsLocalFile::SetLastModificationDateOfLink(PRInt64 aLastModificationDateOfLink)
|
||||
{
|
||||
return SetLastModificationDate(aLastModificationDateOfLink);
|
||||
}
|
||||
@@ -384,7 +791,7 @@ NS_IMETHODIMP
|
||||
nsLocalFile::GetPermissions(PRUint32 *aPermissions)
|
||||
{
|
||||
NS_ENSURE_ARG(aPermissions);
|
||||
FILL_STAT_CACHE();
|
||||
VALIDATE_STAT_CACHE();
|
||||
*aPermissions = NORMALIZE_PERMS(mCachedStat.st_mode);
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -403,7 +810,7 @@ nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink)
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::SetPermissions(PRUint32 aPermissions)
|
||||
{
|
||||
invalidateCache();
|
||||
InvalidateCache();
|
||||
return NSRESULT_FOR_RETURN(chmod(mPath, aPermissions));
|
||||
}
|
||||
|
||||
@@ -414,28 +821,35 @@ nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::GetFileSize(PRUint32 *aFileSize)
|
||||
nsLocalFile::GetFileSize(PRInt64 *aFileSize)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFileSize);
|
||||
FILL_STAT_CACHE();
|
||||
if (sizeof(off_t) > 4 && mCachedStat.st_size > (off_t)0xffffffff)
|
||||
*aFileSize = 0xffffffff; // return error code?
|
||||
else
|
||||
*aFileSize = (PRUint32)mCachedStat.st_size;
|
||||
InvalidateCache();
|
||||
/* XXX autoconf for and use stat64 if available */
|
||||
mLL_II2L(0, (PRUint32)mCachedStat.st_size, *aFileSize);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::GetFileSizeOfLink(PRUint32 *aFileSize)
|
||||
nsLocalFile::SetFileSize(PRInt64 aFileSize)
|
||||
{
|
||||
PRInt32 hi, lo;
|
||||
mLL_L2II(aFileSize, hi, lo);
|
||||
/* XXX truncate64? */
|
||||
if (truncate((const char *)mPath, (off_t)lo) == -1)
|
||||
return NSRESULT_FOR_ERRNO();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize)
|
||||
{
|
||||
NS_ENSURE_ARG(aFileSize);
|
||||
struct stat sbuf;
|
||||
if (lstat(mPath, &sbuf) == -1)
|
||||
return NSRESULT_FOR_ERRNO();
|
||||
if (sizeof(off_t) > 4 && mCachedStat.st_size > (off_t)0xffffffff)
|
||||
*aFileSize = 0xffffffff; // return error code?
|
||||
else
|
||||
*aFileSize = (PRUint32)sbuf.st_size;
|
||||
/* XXX autoconf for and use lstat64 if available */
|
||||
mLL_II2L(0, (PRInt32)sbuf.st_size, *aFileSize);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -505,7 +919,7 @@ NS_IMETHODIMP
|
||||
nsLocalFile::IsDirectory(PRBool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
FILL_STAT_CACHE();
|
||||
VALIDATE_STAT_CACHE();
|
||||
*_retval = S_ISDIR(mCachedStat.st_mode);
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -514,7 +928,7 @@ NS_IMETHODIMP
|
||||
nsLocalFile::IsFile(PRBool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
FILL_STAT_CACHE();
|
||||
VALIDATE_STAT_CACHE();
|
||||
*_retval = S_ISREG(mCachedStat.st_mode);
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -525,7 +939,7 @@ nsLocalFile::IsHidden(PRBool *_retval)
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
nsresult rv;
|
||||
const char *leafName;
|
||||
if (NS_FAILED(rv = getLeafNameRaw(&leafName)))
|
||||
if (NS_FAILED(rv = GetLeafNameRaw(&leafName)))
|
||||
return rv;
|
||||
*_retval = (leafName[0] == '.');
|
||||
return NS_OK;
|
||||
@@ -535,7 +949,7 @@ NS_IMETHODIMP
|
||||
nsLocalFile::IsSymlink(PRBool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
FILL_STAT_CACHE();
|
||||
VALIDATE_STAT_CACHE();
|
||||
*_retval = S_ISLNK(mCachedStat.st_mode);
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -544,7 +958,7 @@ NS_IMETHODIMP
|
||||
nsLocalFile::IsSpecial(PRBool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
FILL_STAT_CACHE();
|
||||
VALIDATE_STAT_CACHE();
|
||||
*_retval = !(S_ISLNK(mCachedStat.st_mode) || S_ISREG(mCachedStat.st_mode) ||
|
||||
S_ISDIR(mCachedStat.st_mode));
|
||||
return NS_OK;
|
||||
@@ -555,7 +969,18 @@ nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG(inFile);
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
*_retval = PR_FALSE;
|
||||
|
||||
nsresult rv;
|
||||
nsXPIDLCString myPath, inPath;
|
||||
|
||||
if (NS_FAILED(rv = GetPath(getter_Copies(myPath))))
|
||||
return rv;
|
||||
if (NS_FAILED(rv = inFile->GetPath(getter_Copies(inPath))))
|
||||
return rv;
|
||||
*_retval = !strcmp(inPath, myPath);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@@ -563,32 +988,62 @@ nsLocalFile::IsContainedIn(nsIFile *inFile, PRBool recur, PRBool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG(inFile);
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::Truncate(PRUint32 aLength)
|
||||
{
|
||||
return NSRESULT_FOR_RETURN(truncate(mPath, (off_t)aLength));
|
||||
nsXPIDLCString inPath;
|
||||
nsresult rv;
|
||||
|
||||
if (NS_FAILED(rv = inFile->GetPath(getter_Copies(inPath))))
|
||||
return rv;
|
||||
|
||||
ssize_t inLen = strlen(inPath);
|
||||
|
||||
/* remove trailing slashes */
|
||||
while (((const char *)mPath)[inLen - 1] == '/')
|
||||
inLen--;
|
||||
|
||||
/*
|
||||
* See if the given path is a prefix of our path, but make sure that
|
||||
* we don't treat /foo as a parent of /foobar/thing.
|
||||
*/
|
||||
if (strncmp(inPath, mPath, inLen) || ((const char *)mPath)[inLen] != '/') {
|
||||
*_retval = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
if (recur) {
|
||||
/* good enough -- don't need to check for direct parentage */
|
||||
*_retval = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const char *parentEnd = strrchr(mPath, '/');
|
||||
if (inLen == (parentEnd - (const char *)mPath)) {
|
||||
*_retval = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*_retval = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::GetTarget(char **_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
FILL_STAT_CACHE();
|
||||
VALIDATE_STAT_CACHE();
|
||||
if (!S_ISLNK(mCachedStat.st_mode))
|
||||
return NS_ERROR_FILE_INVALID_PATH;
|
||||
|
||||
PRUint32 targetSize;
|
||||
if (NS_FAILED(GetFileSizeOfLink(&targetSize)))
|
||||
PRInt64 targetSize64;
|
||||
if (NS_FAILED(GetFileSizeOfLink(&targetSize64)))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
char *target = (char *)nsAllocator::Alloc(targetSize);
|
||||
PRInt32 hi, lo;
|
||||
mLL_L2II(targetSize64, hi, lo);
|
||||
char *target = (char *)nsAllocator::Alloc(lo);
|
||||
if (!target)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
int result = readlink(mPath, target, (size_t)targetSize);
|
||||
int result = readlink(mPath, target, (size_t)lo);
|
||||
if (!result) {
|
||||
*_retval = target;
|
||||
return NS_OK;
|
||||
@@ -596,3 +1051,54 @@ nsLocalFile::GetTarget(char **_retval)
|
||||
nsAllocator::Free(target);
|
||||
return NSRESULT_FOR_ERRNO();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::Spawn(const char *args)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **entries)
|
||||
{
|
||||
nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix();
|
||||
if (!dir)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = dir->Init(this, PR_FALSE);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete dir;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* QI needed? */
|
||||
return dir->QueryInterface(NS_GET_IID(nsISimpleEnumerator),
|
||||
(void **)entries);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::Load(PRLibrary **_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
*_retval = PR_LoadLibrary(mPath);
|
||||
if (!*_retval)
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewLocalFile(const char* path, nsILocalFile* *result)
|
||||
{
|
||||
nsLocalFile* file = new nsLocalFile();
|
||||
if (file == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(file);
|
||||
|
||||
nsresult rv = file->InitWithPath(path);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(file);
|
||||
return rv;
|
||||
}
|
||||
*result = file;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user