зеркало из https://github.com/mozilla/gecko-dev.git
905 строки
26 KiB
C++
905 строки
26 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
|
|
// Implementation of file-based ITapeFileSystem.
|
|
// Used by the editor to save to disk.
|
|
|
|
#ifdef EDITOR
|
|
|
|
// Work-around for Win16 precompiled header bug -- all .cpp files in
|
|
// lib/layout have to include editor.h first. This file
|
|
// doesn't even need editor.h.
|
|
////// Now it does, edt_StripUsernamePassword.
|
|
#include "editor.h"
|
|
|
|
#include "fsfile.h"
|
|
|
|
#ifdef XP_MAC
|
|
#include "xp_file_mac.h"
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CFileBackup
|
|
//
|
|
// File backup and restore Object, only used by CTapeFSFile.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
class CFileBackup {
|
|
private:
|
|
XP_Bool m_bInitOk;
|
|
char *m_pBackupName;
|
|
char *m_pFileName;
|
|
|
|
public:
|
|
CFileBackup(): m_bInitOk(FALSE), m_pBackupName(0), m_pFileName(0){}
|
|
|
|
~CFileBackup(){
|
|
Reset();
|
|
}
|
|
|
|
void Reset();
|
|
XP_Bool InTransaction(){ return m_bInitOk; }
|
|
ED_FileError BeginTransaction( char *pDestURL );
|
|
char* FileName(){ return m_pFileName; }
|
|
void Commit();
|
|
void Rollback();
|
|
};
|
|
|
|
|
|
void CFileBackup::Reset(){
|
|
if( m_pBackupName ){
|
|
XP_FREE( m_pBackupName );
|
|
m_pBackupName = 0;
|
|
}
|
|
if( m_pFileName ){
|
|
XP_FREE( m_pFileName );
|
|
m_pFileName = 0;
|
|
}
|
|
m_bInitOk = FALSE;
|
|
}
|
|
|
|
ED_FileError CFileBackup::BeginTransaction( char *pDestURL ){
|
|
XP_StatStruct statinfo;
|
|
|
|
if ( pDestURL == NULL || XP_STRLEN(pDestURL) == 0 ||
|
|
!NET_IsLocalFileURL(pDestURL) ) {
|
|
return ED_ERROR_BAD_URL;
|
|
}
|
|
|
|
// Skip past the "file://" in pDestURL
|
|
m_pFileName = NET_ParseURL(pDestURL,GET_PATH_PART);
|
|
if (!m_pFileName) {
|
|
return ED_ERROR_CREATE_BAKNAME;
|
|
}
|
|
if (XP_Stat(m_pFileName, &statinfo, xpURL) != -1) {
|
|
if ( XP_STAT_READONLY( statinfo ) ){
|
|
return ED_ERROR_READ_ONLY;
|
|
}
|
|
|
|
// File exists - rename to backup to protect data
|
|
m_pBackupName = XP_BackupFileName(pDestURL);
|
|
if ( m_pBackupName == NULL ) {
|
|
return ED_ERROR_CREATE_BAKNAME;
|
|
}
|
|
// Delete backup file if it exists
|
|
if ( -1 != XP_Stat(m_pBackupName, &statinfo, xpURL) &&
|
|
statinfo.st_mode & S_IFREG ) {
|
|
if ( 0 != XP_FileRemove(m_pBackupName, xpURL) ) {
|
|
return ED_ERROR_DELETE_BAKFILE;
|
|
}
|
|
}
|
|
if ( 0 != XP_FileRename(m_pFileName, xpURL,
|
|
m_pBackupName, xpURL) ){
|
|
return ED_ERROR_FILE_RENAME_TO_BAK;
|
|
}
|
|
}
|
|
// else file doesn't already exist, so no worries.
|
|
|
|
m_bInitOk = TRUE;
|
|
return ED_ERROR_NONE;
|
|
}
|
|
|
|
|
|
void CFileBackup::Commit() {
|
|
XP_ASSERT( m_bInitOk );
|
|
|
|
#ifdef XP_UNIX
|
|
XP_StatStruct statinfo;
|
|
|
|
if (m_pBackupName != NULL && m_pFileName != NULL &&
|
|
XP_Stat(m_pBackupName, &statinfo, xpURL) != -1) {
|
|
|
|
/*
|
|
* Is there an XP_chmod()? I cannot find one. This will
|
|
* work for Unix, which is probably the only place that cares.
|
|
* Don't bother to check the return status, as it's too late to
|
|
* do anything about, and we are not in dire straights if it fails.
|
|
* Bug #28775..djw
|
|
*/
|
|
chmod(m_pFileName, statinfo.st_mode);
|
|
}
|
|
#endif
|
|
|
|
#ifdef XP_MAC
|
|
// Mac needs to duplicate the resource fork of the old file into new location
|
|
// when there is a save or saveas; this preserves CKID rsrc among other things
|
|
if ( m_pBackupName != NULL && m_pFileName != NULL )
|
|
int result = XP_FileDuplicateResourceFork( m_pBackupName, xpURL,
|
|
m_pFileName, xpURL );
|
|
#endif
|
|
|
|
XP_FileRemove(m_pBackupName, xpURL);
|
|
}
|
|
|
|
void CFileBackup::Rollback(){
|
|
XP_ASSERT( m_bInitOk );
|
|
if ( m_pBackupName ) {
|
|
// Restore previous file
|
|
// If this fails, we're really messed up!
|
|
XP_FileRemove(m_pFileName, xpURL);
|
|
XP_FileRename(m_pBackupName, xpURL, m_pFileName, xpURL);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// CTapeFSFile: File-based version of abstract file system
|
|
//-------------------------------------------------------------------------------
|
|
CTapeFSFile::CTapeFSFile(char *pDestPathURL,char *pDestURL):
|
|
m_pSrcBaseURL(0)
|
|
{
|
|
XP_ASSERT(pDestPathURL && pDestURL);
|
|
m_pDestPathURL = XP_STRDUP(pDestPathURL);
|
|
m_pDestURL = XP_STRDUP(pDestURL);
|
|
XP_ASSERT(m_pDestPathURL && m_pDestURL);
|
|
}
|
|
|
|
CTapeFSFile::~CTapeFSFile()
|
|
{
|
|
///// TODO DELETE TEMP FILES
|
|
|
|
int i;
|
|
for (i = 0; i < m_srcURLs.Size(); i++) {
|
|
if (m_srcURLs[i])
|
|
XP_FREE(m_srcURLs[i]);
|
|
}
|
|
for (i = 0; i < m_destFilenames.Size(); i++) {
|
|
if (m_destFilenames[i])
|
|
XP_FREE(m_destFilenames[i]);
|
|
}
|
|
for (i = 0; i < m_streamOuts.Size(); i++) {
|
|
if (m_streamOuts[i]) // really don't need to check for NULL with C++ delete
|
|
delete m_streamOuts[i];
|
|
}
|
|
for (i = 0; i < m_fileBackups.Size(); i++) {
|
|
if (m_fileBackups[i]) // really don't need to check for NULL with C++ delete
|
|
delete m_fileBackups[i];
|
|
}
|
|
|
|
if (m_pDestPathURL)
|
|
XP_FREE(m_pDestPathURL);
|
|
if (m_pDestURL)
|
|
XP_FREE(m_pDestURL);
|
|
if (m_pSrcBaseURL)
|
|
XP_FREE(m_pSrcBaseURL);
|
|
}
|
|
|
|
void CTapeFSFile::CopyURLInfo(intn, const URL_Struct *)
|
|
{
|
|
}
|
|
|
|
intn CTapeFSFile::GetType() {
|
|
return ITapeFileSystem::File;
|
|
}
|
|
|
|
void CTapeFSFile::SetSourceBaseURL(char *pURL){
|
|
// Shouldn't pass in NULL, and m_pSrcBaseURL shouldn't already exist.
|
|
if (m_pSrcBaseURL || !pURL) {
|
|
XP_ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
m_pSrcBaseURL = XP_STRDUP(pURL);
|
|
}
|
|
|
|
intn CTapeFSFile::AddFile(char *pURL, char *, int16) {
|
|
// MIME type and char set are ignored.
|
|
|
|
// Make pSrcURL absolute if SetSourceBaseURL() was called.
|
|
char *pSrcURL;
|
|
if (m_pSrcBaseURL)
|
|
pSrcURL = NET_MakeAbsoluteURL(m_pSrcBaseURL,pURL);
|
|
else
|
|
pSrcURL = XP_STRDUP(pURL);
|
|
|
|
if (!pSrcURL)
|
|
return ITapeFileSystem::Error;
|
|
|
|
// First file added is the root HTML document, it's destination filename was passed in to
|
|
// the constructor of CTapeFSFile.
|
|
XP_Bool use_m_pDestURL = (m_srcURLs.Size() == 0);
|
|
|
|
// Compute and store relative destination filename.
|
|
char *pDestFilename;
|
|
if (use_m_pDestURL) {
|
|
// Kind of redundant, here we are stripping the path, only to put it back on in CTapeFSFile::OpenStream().
|
|
pDestFilename = FE_URLToLocalName(m_pDestURL);
|
|
}
|
|
else {
|
|
pDestFilename = FE_URLToLocalName(pSrcURL);
|
|
}
|
|
if (!pDestFilename) {
|
|
XP_FREE(pSrcURL);
|
|
return ITapeFileSystem::Error;
|
|
}
|
|
|
|
// Check if source and destination are the same.
|
|
// It's ok for the root HTML document to have the same source and dest.
|
|
//
|
|
// pSrcURL is absolute
|
|
if (!use_m_pDestURL && EDT_IsSameURL(pSrcURL,pDestFilename,NULL,m_pDestURL)) {
|
|
XP_FREE(pSrcURL);
|
|
XP_FREE(pDestFilename);
|
|
return ITapeFileSystem::SourceDestSame;
|
|
}
|
|
|
|
// See if pSrcURL is already in the list.
|
|
int i = 0;
|
|
while( i < m_srcURLs.Size() ){
|
|
if( EDT_IsSameURL( pSrcURL, m_srcURLs[i], NULL, NULL ) ){
|
|
XP_FREE(pSrcURL);
|
|
XP_FREE(pDestFilename);
|
|
return i;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
// Add to lists.
|
|
int ret = m_srcURLs.Add(pSrcURL);
|
|
m_destFilenames.Add(pDestFilename);
|
|
// Keep m_streamOuts and m_fileBackups the same size as the others.
|
|
m_streamOuts.Add(NULL);
|
|
m_fileBackups.Add(NULL);
|
|
return ret;
|
|
}
|
|
|
|
char* CTapeFSFile::GetSourceURL(intn iFileIndex) {
|
|
if (iFileIndex >= 0 && iFileIndex < m_srcURLs.Size()) {
|
|
return XP_STRDUP(m_srcURLs[iFileIndex]);
|
|
}
|
|
else {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
char* CTapeFSFile::GetDestAbsURL() {
|
|
return XP_STRDUP(m_pDestURL);
|
|
}
|
|
|
|
char *CTapeFSFile::GetDestURL(intn iFileIndex) {
|
|
if (iFileIndex >= 0 && iFileIndex < m_destFilenames.Size()) {
|
|
return XP_STRDUP(m_destFilenames[iFileIndex]);
|
|
}
|
|
else {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
char *CTapeFSFile::GetDestPathURL() {
|
|
return XP_STRDUP(m_pDestPathURL);
|
|
}
|
|
|
|
XP_Bool CTapeFSFile::IsLocalPersistentFile(intn) {
|
|
return TRUE;
|
|
}
|
|
|
|
XP_Bool CTapeFSFile::FileExists(intn iFileIndex) {
|
|
// Check iFileIndex
|
|
if (iFileIndex < 0 || iFileIndex >= m_destFilenames.Size()) {
|
|
XP_ASSERT(0);
|
|
return FALSE;
|
|
}
|
|
|
|
char *pLocalName = PR_smprintf( "%s%s", m_pDestPathURL, m_destFilenames[iFileIndex]);
|
|
if (!pLocalName) {
|
|
XP_ASSERT(0);
|
|
return FALSE;
|
|
}
|
|
|
|
// Get everything after "file://"
|
|
char *pxpURL = NET_ParseURL(pLocalName,GET_PATH_PART);
|
|
XP_FREE(pLocalName);
|
|
if (!pxpURL) {
|
|
XP_ASSERT(0);
|
|
return FALSE;
|
|
}
|
|
|
|
XP_StatStruct statinfo;
|
|
Bool result =
|
|
( -1 != XP_Stat(pxpURL, &statinfo, xpURL) && statinfo.st_mode & S_IFREG );
|
|
XP_FREE(pxpURL);
|
|
return result;
|
|
}
|
|
|
|
IStreamOut *
|
|
CTapeFSFile::OpenStream( intn iFileIndex ) {
|
|
// Check iFileIndex
|
|
if (iFileIndex < 0 || iFileIndex >= m_destFilenames.Size()) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
// Create fileBackup object
|
|
XP_ASSERT( m_fileBackups[iFileIndex] == NULL ); // Shouldn't already exist.
|
|
m_fileBackups[iFileIndex]= new CFileBackup;
|
|
m_fileBackups[iFileIndex]->Reset();
|
|
char *pDestURL = PR_smprintf( "%s%s", m_pDestPathURL, m_destFilenames[iFileIndex]);
|
|
if ( !pDestURL ) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
ED_FileError status = m_fileBackups[iFileIndex]->BeginTransaction( pDestURL );
|
|
if( status != ED_ERROR_NONE ){
|
|
XP_FREE(pDestURL);
|
|
return NULL;
|
|
}
|
|
|
|
// Get path part of URL, e.g. without file://, for everything that uses xpURL
|
|
char *pDestPath = NET_ParseURL(pDestURL,GET_PATH_PART);
|
|
XP_FREE(pDestURL);
|
|
if (!pDestPath) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
XP_File outFile = 0;
|
|
// First file is text, rest are binary.
|
|
// Right, well now the first file may be text or binary. This is still
|
|
// bogus-- each file should have a flag telling it's time, but I don't
|
|
// have time to redesign the #!$#@!#!@$ editor.
|
|
XP_FilePerm filePerm = ((iFileIndex == 0) && (!IsFirstBinary())) ?
|
|
XP_FILE_TRUNCATE : XP_FILE_TRUNCATE_BIN;
|
|
outFile = XP_FileOpen(pDestPath, xpURL, filePerm );
|
|
XP_FREE(pDestPath);
|
|
|
|
if( outFile == 0 ){
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// Now open a stream to outFile.
|
|
//
|
|
// First file is text, rest are binary.
|
|
CStreamOutFile *streamOut = new CStreamOutFile(outFile,iFileIndex == 0 ? FALSE : TRUE);
|
|
XP_ASSERT(streamOut);
|
|
|
|
XP_ASSERT(m_streamOuts[iFileIndex] == NULL); // not already set
|
|
// Store stream for later.
|
|
m_streamOuts[iFileIndex] = streamOut;
|
|
|
|
return streamOut;
|
|
}
|
|
|
|
void CTapeFSFile::CloseStream( intn iFileIndex ) {
|
|
if (iFileIndex < 0 || iFileIndex >= m_streamOuts.Size() || !m_streamOuts[iFileIndex]) {
|
|
XP_ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
delete m_streamOuts[iFileIndex];
|
|
m_streamOuts[iFileIndex] = NULL;
|
|
}
|
|
|
|
void CTapeFSFile::Complete( XP_Bool bSuccess,
|
|
EDT_ITapeFileSystemComplete *pfComplete, void *pArg ) {
|
|
// Commit or rollback all file changes, depending on the value of bSuccess.
|
|
int i;
|
|
for ( i = 0; i < m_fileBackups.Size(); i++ ) {
|
|
if ( !m_fileBackups[i] ) {
|
|
continue;
|
|
}
|
|
if ( m_fileBackups[i]->InTransaction() ) {
|
|
if ( bSuccess )
|
|
m_fileBackups[i]->Commit();
|
|
else
|
|
m_fileBackups[i]->Rollback();
|
|
}
|
|
}
|
|
|
|
if (pfComplete) {
|
|
pfComplete(TRUE,pArg);
|
|
}
|
|
delete this;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// CTapeFSPublish: Remote HTTP publish version of abstract file system
|
|
//-------------------------------------------------------------------------------
|
|
CTapeFSPublish::CTapeFSPublish(MWContext *pMWContext, char *pRemoteURL,
|
|
char *pUsername, char *pPassword, char *pTempDir) :
|
|
m_iVerifier(iVerifierKey),
|
|
m_pSrcBaseURL(NULL),
|
|
m_pRemoteURL(XP_STRDUP(pRemoteURL)),
|
|
m_pUsername(pUsername ? XP_STRDUP(pUsername) : 0),
|
|
m_pPassword(pPassword ? XP_STRDUP(pPassword) : 0),
|
|
m_pArg(0),
|
|
m_pfComplete(0),
|
|
m_bIsHTTP(FALSE),
|
|
m_pTempDir(XP_STRDUP(pTempDir))
|
|
{
|
|
m_pMWContext = pMWContext;
|
|
XP_ASSERT( m_pRemoteURL && pMWContext );
|
|
// m_pTempDir must end in a slash.
|
|
XP_ASSERT(m_pTempDir && *m_pTempDir && m_pTempDir[XP_STRLEN(m_pTempDir)-1] == '/');
|
|
|
|
int type = NET_URL_Type(pRemoteURL);
|
|
if (type == FTP_TYPE_URL) {
|
|
m_bIsHTTP = FALSE;
|
|
}
|
|
else if (type == HTTP_TYPE_URL || type == SECURE_HTTP_TYPE_URL) {
|
|
m_bIsHTTP = TRUE;
|
|
}
|
|
else {
|
|
XP_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
CTapeFSPublish::~CTapeFSPublish() {
|
|
XP_FREEIF(m_pSrcBaseURL);
|
|
|
|
int i;
|
|
for (i = 0; i < m_srcURLs.Size(); i++) {
|
|
XP_FREEIF(m_srcURLs[i]);
|
|
}
|
|
|
|
XP_FREEIF(m_pRemoteURL);
|
|
XP_FREEIF(m_pUsername);
|
|
XP_FREEIF(m_pPassword);
|
|
|
|
for (i = 0; i < m_remoteURLs.Size(); i++) {
|
|
XP_FREEIF(m_remoteURLs[i]);
|
|
}
|
|
|
|
XP_FREEIF(m_pTempDir);
|
|
for (i = 0; i < m_tempFilenames.Size(); i++) {
|
|
if (m_tempFilenames[i]) {
|
|
// Delete temp files.
|
|
XP_FileRemove(m_tempFilenames[i], xpFileToPost);
|
|
XP_FREE(m_tempFilenames[i]);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < m_streamOuts.Size(); i++) {
|
|
if (m_streamOuts[i]) // really don't need to check for NULL with C++ delete
|
|
delete m_streamOuts[i];
|
|
}
|
|
}
|
|
|
|
void CTapeFSPublish::CopyURLInfo(intn, const URL_Struct *)
|
|
{
|
|
}
|
|
|
|
intn CTapeFSPublish::GetType() {
|
|
return ITapeFileSystem::Publish;
|
|
}
|
|
|
|
// Some random value.
|
|
int32 CTapeFSPublish::iVerifierKey = 0xABACADAE;
|
|
|
|
void CTapeFSPublish::SetSourceBaseURL(char *pURL){
|
|
// Shouldn't pass in NULL, and m_pSrcBaseURL shouldn't already exist.
|
|
if (m_pSrcBaseURL || !pURL) {
|
|
XP_ASSERT(0);
|
|
return;
|
|
}
|
|
m_pSrcBaseURL = XP_STRDUP(pURL);
|
|
}
|
|
|
|
intn CTapeFSPublish::AddFile(char *pURL, char *, int16) {
|
|
// MIME type and char set are ignored.
|
|
|
|
// Make pSrcURL absolute if SetSourceBaseURL() was called.
|
|
char *pSrcURL;
|
|
if (m_pSrcBaseURL)
|
|
pSrcURL = NET_MakeAbsoluteURL(m_pSrcBaseURL,pURL);
|
|
else
|
|
pSrcURL = XP_STRDUP(pURL);
|
|
|
|
if (!pSrcURL)
|
|
return ITapeFileSystem::Error;
|
|
|
|
// See if pSrcURL is already in the list.
|
|
int i = 0;
|
|
while( i < m_srcURLs.Size() ){
|
|
if( EDT_IsSameURL( pSrcURL, m_srcURLs[i], NULL, NULL)){
|
|
XP_FREE(pSrcURL);
|
|
return i;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
// Note that the way pNewRemoteURL is constructed has the desirable
|
|
// side effect of NOT copying in any username/password information
|
|
// in pURL.
|
|
char *pNewRemoteURL = NULL;
|
|
if (m_srcURLs.Size() == 0)
|
|
// First file added is the root HTML document.
|
|
pNewRemoteURL = XP_STRDUP(m_pRemoteURL);
|
|
|
|
else {
|
|
// All others are images that will be placed in the directory of the root doc.
|
|
pNewRemoteURL = makeLocal(m_pRemoteURL,pSrcURL);
|
|
|
|
}
|
|
if ( !pNewRemoteURL ) {
|
|
XP_FREE(pSrcURL);
|
|
return ITapeFileSystem::Error;
|
|
}
|
|
|
|
// Check if would be copying from one location to itself.
|
|
if (m_srcURLs.Size() > 0 && // Make sure not the root document.
|
|
EDT_IsSameURL(pSrcURL,pNewRemoteURL,NULL,m_pRemoteURL)) {
|
|
XP_FREE(pSrcURL);
|
|
XP_FREE(pNewRemoteURL);
|
|
return ITapeFileSystem::SourceDestSame;
|
|
}
|
|
|
|
// Add to lists.
|
|
int ret = m_srcURLs.Add(pSrcURL);
|
|
m_remoteURLs.Add(pNewRemoteURL);
|
|
// Keep the same size as the other arrays..
|
|
m_tempFilenames.Add(NULL);
|
|
m_streamOuts.Add(NULL);
|
|
return ret;
|
|
}
|
|
|
|
char* CTapeFSPublish::GetSourceURL(intn iFileIndex) {
|
|
if (iFileIndex >= 0 && iFileIndex < m_srcURLs.Size()) {
|
|
return XP_STRDUP(m_srcURLs[iFileIndex]);
|
|
}
|
|
else {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
char* CTapeFSPublish::GetDestAbsURL() {
|
|
return XP_STRDUP(m_pRemoteURL);
|
|
}
|
|
|
|
char *CTapeFSPublish::GetUsername() {
|
|
return m_pUsername ? XP_STRDUP(m_pUsername) : 0;
|
|
}
|
|
|
|
char *CTapeFSPublish::GetPassword() {
|
|
return m_pPassword ? XP_STRDUP(m_pPassword) : 0;
|
|
}
|
|
|
|
char *CTapeFSPublish::GetDestURL(intn iFileIndex) {
|
|
if (iFileIndex >= 0 && iFileIndex < m_remoteURLs.Size()) {
|
|
// Find last slash.
|
|
char *slash = XP_STRRCHR(m_remoteURLs[iFileIndex],'/');
|
|
if (!slash) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
// Copy everything after the slash.
|
|
return XP_STRDUP(slash + 1);
|
|
}
|
|
else {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
char *CTapeFSPublish::GetDestPathURL() {
|
|
// Grab everything before and including the last slash in m_pRemoteURL.
|
|
char *slash = XP_STRRCHR(m_pRemoteURL,'/');
|
|
if (!slash) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
char tmp = *(slash + 1);
|
|
*(slash + 1) = '\0';
|
|
char *ret = XP_STRDUP(m_pRemoteURL);
|
|
*(slash + 1) = tmp;
|
|
return ret;
|
|
}
|
|
|
|
XP_Bool CTapeFSPublish::IsLocalPersistentFile(intn /* iFileIndex */) {
|
|
return FALSE;
|
|
}
|
|
|
|
IStreamOut *
|
|
CTapeFSPublish::OpenStream( intn iFileIndex ) {
|
|
// Check iFileIndex
|
|
if (iFileIndex < 0 || iFileIndex >= m_tempFilenames.Size()) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// WARNING: We are pulling a fast one here, m_pTempDir is xpURL and we treat it as xpFileToPost.
|
|
// Since there are no routines to convert a filename to xpFileToPost, I just take advantage of
|
|
// it being the same as xpURL.
|
|
|
|
// Get filename of temporary file.
|
|
// Use the temporary file of the current document.
|
|
// Start filename with "pub" so it doesn't collide with CEditCommandLog::CreateDocTempFilename()
|
|
// which starts all filenames with "edt" by default.
|
|
char *pTempFilename = PR_smprintf("%spubl%d.tmp",m_pTempDir,(int)iFileIndex); // m_pTempDir ends in slash.
|
|
if (!pTempFilename) {
|
|
return NULL;
|
|
}
|
|
m_tempFilenames[iFileIndex] = pTempFilename;
|
|
|
|
|
|
XP_File outFile = 0;
|
|
// First file is text, rest are binary.
|
|
// Right, well now the first file may be text or binary. This is still
|
|
// bogus-- each file should have a flag telling it's time, but I don't
|
|
// have time to redesign the #!$#@!#!@$ editor.
|
|
XP_FilePerm filePerm = ((iFileIndex == 0) && (!IsFirstBinary())) ?
|
|
XP_FILE_TRUNCATE : XP_FILE_TRUNCATE_BIN;
|
|
outFile = XP_FileOpen(m_tempFilenames[iFileIndex],
|
|
xpFileToPost, filePerm );
|
|
|
|
XP_TRACE(("XP_FileOpen handle = %d", outFile));
|
|
|
|
if( outFile == 0 ){
|
|
XP_TRACE(("Failed to opened file %s", m_tempFilenames[iFileIndex]));
|
|
|
|
// Delete and clear temp filename, this serves as a flag to
|
|
// Complete() that this entry should not be published.
|
|
XP_FREEIF(m_tempFilenames[iFileIndex]);
|
|
return NULL;
|
|
}
|
|
|
|
// Now open a stream to outFile.
|
|
//
|
|
// First file is text, rest are binary.
|
|
CStreamOutFile *streamOut = new CStreamOutFile(outFile,iFileIndex == 0 ? FALSE : TRUE);
|
|
if (!streamOut) {
|
|
// Out of memory.
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
XP_ASSERT(m_streamOuts[iFileIndex] == NULL); // not already set
|
|
// Store stream for later.
|
|
m_streamOuts[iFileIndex] = streamOut;
|
|
|
|
return streamOut;
|
|
}
|
|
|
|
void CTapeFSPublish::CloseStream( intn iFileIndex ) {
|
|
if (iFileIndex < 0 || iFileIndex >= m_streamOuts.Size() || !m_streamOuts[iFileIndex]) {
|
|
XP_ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
if (m_streamOuts[iFileIndex]->Status() != IStreamOut::EOS_NoError) {
|
|
// Delete and clear temp filename, this serves as a flag to
|
|
// Complete() that this entry should not be published.
|
|
XP_FREEIF(m_tempFilenames[iFileIndex]);
|
|
}
|
|
|
|
delete m_streamOuts[iFileIndex];
|
|
m_streamOuts[iFileIndex] = NULL;
|
|
}
|
|
|
|
#if defined(XP_OS2)
|
|
extern "C"
|
|
#else
|
|
PRIVATE
|
|
#endif
|
|
void edt_CTapeFSExit( URL_Struct *pURL, int status, MWContext * ) {
|
|
CTapeFSPublish *tapeFS = (CTapeFSPublish *)pURL->fe_data;
|
|
// Make sure that fe_data can be trusted.
|
|
if (!(tapeFS && tapeFS->Verify())) {
|
|
XP_ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
// Call complete function passed into CTapeFSPublish::Complete().
|
|
if (tapeFS->m_pfComplete) {
|
|
XP_Bool bSuccess = (status >= 0 &&
|
|
(pURL->server_status == 204 || pURL->server_status == 201 || // from HTTP
|
|
pURL->server_status == 0)); // from FTP.
|
|
tapeFS->m_pfComplete(bSuccess,tapeFS->m_pArg);
|
|
}
|
|
|
|
// Kill the tapeFS.
|
|
delete tapeFS;
|
|
}
|
|
|
|
void CTapeFSPublish::Complete(XP_Bool bSuccess,
|
|
EDT_ITapeFileSystemComplete *pfComplete, void *pArg ) {
|
|
m_pfComplete = pfComplete;
|
|
m_pArg = pArg;
|
|
|
|
|
|
// Count number of files we're actually publishing, may be less than
|
|
// m_tempFilenames.Size() if errors occurred.
|
|
int numFilesToPost = 0;
|
|
for (int n = 0; n < m_tempFilenames.Size(); n++) {
|
|
if (m_tempFilenames[n])
|
|
numFilesToPost++;
|
|
}
|
|
|
|
|
|
// Publish temp files. Temp files deleted in destructor.
|
|
if (bSuccess && numFilesToPost ) {
|
|
// One extra for trailing NULL.
|
|
char **filesToPost = (char **)XP_ALLOC((numFilesToPost + 1) * sizeof(char*));
|
|
if ( !filesToPost ) {
|
|
XP_ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
// Where to put the files on the server.
|
|
// FTP publish will ignore the path info in postTo and will just use
|
|
// the filename after the last slash.
|
|
char **postTo = NULL;
|
|
postTo = (char **)XP_ALLOC((numFilesToPost + 1) * sizeof(char*));
|
|
if ( !postTo ) {
|
|
XP_ASSERT(0);
|
|
XP_FREE(filesToPost);
|
|
return;
|
|
}
|
|
|
|
// Not NULL-terminated.
|
|
XP_Bool *addCRLF = (XP_Bool *)XP_ALLOC((numFilesToPost) * sizeof(XP_Bool));
|
|
if (!addCRLF) {
|
|
XP_ASSERT(0);
|
|
XP_FREE(filesToPost);
|
|
XP_FREE(postTo);
|
|
return;
|
|
}
|
|
|
|
// Copying filenames, reversing order or list and removing blanks at
|
|
// the same time.
|
|
int n,m;
|
|
for ( n = 0, m = numFilesToPost - 1;
|
|
n < m_tempFilenames.Size(); n++ ) {
|
|
// Insert into list backwards, because NET_PublishFilesTo publishes in reverse order.
|
|
// So, HTML file will be published first.
|
|
if (m_tempFilenames[n]) {
|
|
filesToPost[m] = XP_STRDUP(m_tempFilenames[n]);
|
|
postTo[m] = XP_STRDUP(m_remoteURLs[n]);
|
|
|
|
// Only first file is treated as text, rest are whatever netlib decides.
|
|
// well actually only if it's not a pre-encrypted file!
|
|
addCRLF[m] = (n == 0) && !IsFirstBinary();
|
|
m--;
|
|
}
|
|
}
|
|
// Otherwise we counted numFilesToPost wrong.
|
|
XP_ASSERT(m == -1);
|
|
|
|
// Trailing NULL.
|
|
filesToPost[numFilesToPost] = NULL;
|
|
postTo[numFilesToPost] = NULL;
|
|
|
|
|
|
|
|
// Temporarily remove characters after final slash
|
|
// from m_pRemoteURL, so pRemoteFullURL is a directory.
|
|
char *lastSlash = XP_STRRCHR(m_pRemoteURL,'/');
|
|
char saved=0;
|
|
if (lastSlash) {
|
|
saved = *(lastSlash + 1);
|
|
*(lastSlash + 1) = '\0';
|
|
}
|
|
|
|
char *pRemoteFullURL = NULL;
|
|
if (!NET_MakeUploadURL(&pRemoteFullURL,m_pRemoteURL,m_pUsername,m_pPassword)) {
|
|
pRemoteFullURL = NULL; // Just to be sure.
|
|
}
|
|
|
|
// Restore m_pRemoteURL.
|
|
*(lastSlash + 1) = saved;
|
|
|
|
if (!pRemoteFullURL) {
|
|
return;
|
|
}
|
|
|
|
if (m_bIsHTTP) {
|
|
// m_pRemoteURL may or may not be a directory.
|
|
// username and password are passed in separately, not through the
|
|
// URL, to avoid ever being displayed on screen to the user.
|
|
NET_PublishFilesTo(m_pMWContext, filesToPost, postTo, addCRLF,
|
|
m_pRemoteURL,m_pUsername,m_pPassword,
|
|
edt_CTapeFSExit, (void *)this);
|
|
}
|
|
else {
|
|
// pRemoteFullURL must be a directory for FTP publishing.
|
|
// pRemoteFullURL contains username/password information, maybe we
|
|
// should modify ns/lib/libnet/mkftp.c to deal with username/password
|
|
// in the URL struct like mkhttp.c does.
|
|
NET_PublishFilesTo(m_pMWContext, filesToPost, postTo, addCRLF,
|
|
pRemoteFullURL,NULL,NULL,
|
|
edt_CTapeFSExit, (void *)this);
|
|
}
|
|
// edt_CTapeFSExit will call pfComplete() and delete this.
|
|
|
|
XP_FREEIF(pRemoteFullURL);
|
|
}
|
|
else {
|
|
if (m_pfComplete) {
|
|
// Pass in TRUE because CTapeFSComplete() did the right thing, even
|
|
// though there may have been errors earlier on.
|
|
m_pfComplete(TRUE,m_pArg);
|
|
}
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
char *CTapeFSPublish::makeLocal(char *baseURL,char *srcURL) {
|
|
// Return value.
|
|
char *ret = NULL;
|
|
|
|
// Set ret to be directory to place files in.
|
|
int len = XP_STRLEN(baseURL);
|
|
if (len < 1) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
if (baseURL[len-1] == '/') {
|
|
// baseURL is already a directory.
|
|
ret = XP_STRDUP(baseURL);
|
|
}
|
|
else {
|
|
char *trail = XP_STRRCHR(baseURL,'/');
|
|
if (trail == NULL) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
// Temporarily set the char after the last slash to NULL and copy everything before and
|
|
// including the last slash. We know the '/' is not the last character, since we checked for that
|
|
// above.
|
|
char tmp = *(trail + 1);
|
|
*(trail + 1) = '\0';
|
|
ret = XP_STRDUP(baseURL);
|
|
*(trail + 1) = tmp;
|
|
}
|
|
|
|
char *localName = FE_URLToLocalName(srcURL);
|
|
if (localName == NULL) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
if (!ret) {
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
|
|
ret = XP_AppendStr(ret,localName);
|
|
XP_ASSERT(ret);
|
|
XP_FREE(localName);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif // EDITOR
|