mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central with services-central
This commit is contained in:
commit
90b157e523
@ -4026,7 +4026,7 @@ SessionStoreService.prototype = {
|
|||||||
// Initialize the file output stream.
|
// Initialize the file output stream.
|
||||||
var ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].
|
var ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].
|
||||||
createInstance(Ci.nsIFileOutputStream);
|
createInstance(Ci.nsIFileOutputStream);
|
||||||
ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, 0);
|
ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, ostream.DEFER_OPEN);
|
||||||
|
|
||||||
// Obtain a converter to convert our data to a UTF-8 encoded input stream.
|
// Obtain a converter to convert our data to a UTF-8 encoded input stream.
|
||||||
var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||||
|
@ -85,10 +85,10 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<activity android:name="Restarter"
|
<activity android:name="Restarter"
|
||||||
|
android:process="@ANDROID_PACKAGE_NAME@Restarter"
|
||||||
android:theme="@style/GreyTheme">
|
android:theme="@style/GreyTheme">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="org.mozilla.gecko.restart"
|
<action android:name="org.mozilla.gecko.restart"/>
|
||||||
android:process="@MOZ_APP_NAME@Restarter"/>
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
#if MOZ_CRASHREPORTER
|
#if MOZ_CRASHREPORTER
|
||||||
|
@ -58,6 +58,7 @@ public class CrashReporter extends Activity
|
|||||||
static final String kMiniDumpPathKey = "upload_file_minidump";
|
static final String kMiniDumpPathKey = "upload_file_minidump";
|
||||||
static final String kPageURLKey = "URL";
|
static final String kPageURLKey = "URL";
|
||||||
static final String kNotesKey = "Notes";
|
static final String kNotesKey = "Notes";
|
||||||
|
Handler mHandler = null;
|
||||||
ProgressDialog mProgressDialog;
|
ProgressDialog mProgressDialog;
|
||||||
File mPendingMinidumpFile;
|
File mPendingMinidumpFile;
|
||||||
File mPendingExtrasFile;
|
File mPendingExtrasFile;
|
||||||
@ -88,6 +89,15 @@ public class CrashReporter extends Activity
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void doFinish() {
|
||||||
|
if (mHandler != null) {
|
||||||
|
mHandler.post(new Runnable(){
|
||||||
|
public void run() {
|
||||||
|
finish();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finish()
|
public void finish()
|
||||||
{
|
{
|
||||||
@ -99,6 +109,8 @@ public class CrashReporter extends Activity
|
|||||||
public void onCreate(Bundle savedInstanceState)
|
public void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
// mHandler is created here so runnables can be run on the main thread
|
||||||
|
mHandler = new Handler();
|
||||||
setContentView(R.layout.crash_reporter);
|
setContentView(R.layout.crash_reporter);
|
||||||
mProgressDialog = new ProgressDialog(CrashReporter.this);
|
mProgressDialog = new ProgressDialog(CrashReporter.this);
|
||||||
mProgressDialog.setMessage(getString(R.string.sending_crash_report));
|
mProgressDialog.setMessage(getString(R.string.sending_crash_report));
|
||||||
@ -125,7 +137,7 @@ public class CrashReporter extends Activity
|
|||||||
{
|
{
|
||||||
final CheckBox sendReportCheckbox = (CheckBox) findViewById(R.id.send_report);
|
final CheckBox sendReportCheckbox = (CheckBox) findViewById(R.id.send_report);
|
||||||
if (!sendReportCheckbox.isChecked()) {
|
if (!sendReportCheckbox.isChecked()) {
|
||||||
finish();
|
doFinish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +231,7 @@ public class CrashReporter extends Activity
|
|||||||
|
|
||||||
String spec = extras.get("ServerURL");
|
String spec = extras.get("ServerURL");
|
||||||
if (spec == null)
|
if (spec == null)
|
||||||
finish();
|
doFinish();
|
||||||
|
|
||||||
Log.i("GeckoCrashReport", "server url: " + spec);
|
Log.i("GeckoCrashReport", "server url: " + spec);
|
||||||
try {
|
try {
|
||||||
@ -298,7 +310,7 @@ public class CrashReporter extends Activity
|
|||||||
Log.e("GeckoCrashReporter", "exception during send: ", e);
|
Log.e("GeckoCrashReporter", "exception during send: ", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
finish();
|
doFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
void doRestart()
|
void doRestart()
|
||||||
|
@ -455,6 +455,8 @@ abstract public class GeckoApp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean haveKilledZombies = false;
|
||||||
|
|
||||||
private void unpackFile(ZipFile zip, byte[] buf, ZipEntry fileEntry,
|
private void unpackFile(ZipFile zip, byte[] buf, ZipEntry fileEntry,
|
||||||
String name)
|
String name)
|
||||||
throws IOException, FileNotFoundException
|
throws IOException, FileNotFoundException
|
||||||
@ -471,7 +473,10 @@ abstract public class GeckoApp
|
|||||||
outFile.length() == fileEntry.getSize())
|
outFile.length() == fileEntry.getSize())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
killAnyZombies();
|
if (!haveKilledZombies) {
|
||||||
|
haveKilledZombies = true;
|
||||||
|
GeckoAppShell.killAnyZombies();
|
||||||
|
}
|
||||||
|
|
||||||
File dir = outFile.getParentFile();
|
File dir = outFile.getParentFile();
|
||||||
if (!outFile.exists())
|
if (!outFile.exists())
|
||||||
@ -492,27 +497,6 @@ abstract public class GeckoApp
|
|||||||
outFile.setLastModified(fileEntry.getTime());
|
outFile.setLastModified(fileEntry.getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean haveKilledZombies = false;
|
|
||||||
|
|
||||||
void killAnyZombies() {
|
|
||||||
if (haveKilledZombies)
|
|
||||||
return;
|
|
||||||
haveKilledZombies = true;
|
|
||||||
File proc = new File("/proc");
|
|
||||||
File[] files = proc.listFiles();
|
|
||||||
for (int i = 0; i < files.length; i++) {
|
|
||||||
File p = files[i];
|
|
||||||
File pEnv = new File(p, "environ");
|
|
||||||
if (pEnv.canRead() && !p.getName().equals("self")) {
|
|
||||||
int pid = Integer.parseInt(p.getName());
|
|
||||||
if (pid != android.os.Process.myPid()) {
|
|
||||||
Log.i("GeckoProcs", "gonna kill pid: " + p.getName());
|
|
||||||
android.os.Process.killProcess(pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addEnvToIntent(Intent intent) {
|
public void addEnvToIntent(Intent intent) {
|
||||||
Map<String,String> envMap = System.getenv();
|
Map<String,String> envMap = System.getenv();
|
||||||
Set<Map.Entry<String,String>> envSet = envMap.entrySet();
|
Set<Map.Entry<String,String>> envSet = envMap.entrySet();
|
||||||
@ -537,15 +521,14 @@ abstract public class GeckoApp
|
|||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
|
||||||
Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||||
Log.i("GeckoAppJava", intent.toString());
|
Log.i("GeckoAppJava", intent.toString());
|
||||||
|
GeckoAppShell.killAnyZombies();
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.i("GeckoAppJava", "error doing restart", e);
|
Log.i("GeckoAppJava", "error doing restart", e);
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
// Give the restart process time to start before we die
|
// Give the restart process time to start before we die
|
||||||
try {
|
GeckoAppShell.waitForAnotherGeckoProc();
|
||||||
Thread.currentThread().sleep(1000);
|
|
||||||
} catch (InterruptedException ie) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleNotification(String action, String alertName, String alertCookie) {
|
public void handleNotification(String action, String alertName, String alertCookie) {
|
||||||
|
@ -44,6 +44,7 @@ import java.nio.channels.*;
|
|||||||
import java.text.*;
|
import java.text.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.zip.*;
|
import java.util.zip.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
import android.os.*;
|
import android.os.*;
|
||||||
import android.app.*;
|
import android.app.*;
|
||||||
@ -63,7 +64,7 @@ import android.net.Uri;
|
|||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
|
|
||||||
class GeckoAppShell
|
public class GeckoAppShell
|
||||||
{
|
{
|
||||||
// static members only
|
// static members only
|
||||||
private GeckoAppShell() { }
|
private GeckoAppShell() { }
|
||||||
@ -343,6 +344,11 @@ class GeckoAppShell
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void sendEventToGeckoSync(GeckoEvent e) {
|
||||||
|
sendEventToGecko(e);
|
||||||
|
geckoEventSync();
|
||||||
|
}
|
||||||
|
|
||||||
// Tell the Gecko event loop that an event is available.
|
// Tell the Gecko event loop that an event is available.
|
||||||
public static native void notifyGeckoOfEvent(GeckoEvent event);
|
public static native void notifyGeckoOfEvent(GeckoEvent event);
|
||||||
|
|
||||||
@ -471,6 +477,28 @@ class GeckoAppShell
|
|||||||
imm, text, start, end, newEnd);
|
imm, text, start, end, newEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CountDownLatch sGeckoPendingAcks = null;
|
||||||
|
|
||||||
|
// Block the current thread until the Gecko event loop is caught up
|
||||||
|
synchronized public static void geckoEventSync() {
|
||||||
|
sGeckoPendingAcks = new CountDownLatch(1);
|
||||||
|
GeckoAppShell.sendEventToGecko(
|
||||||
|
new GeckoEvent(GeckoEvent.GECKO_EVENT_SYNC));
|
||||||
|
while (sGeckoPendingAcks.getCount() != 0) {
|
||||||
|
try {
|
||||||
|
sGeckoPendingAcks.await();
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
|
}
|
||||||
|
sGeckoPendingAcks = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal the Java thread that it's time to wake up
|
||||||
|
public static void acknowledgeEventSync() {
|
||||||
|
CountDownLatch tmp = sGeckoPendingAcks;
|
||||||
|
if (tmp != null)
|
||||||
|
tmp.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
public static void enableAccelerometer(boolean enable) {
|
public static void enableAccelerometer(boolean enable) {
|
||||||
SensorManager sm = (SensorManager)
|
SensorManager sm = (SensorManager)
|
||||||
GeckoApp.surfaceView.getContext().getSystemService(Context.SENSOR_SERVICE);
|
GeckoApp.surfaceView.getContext().getSystemService(Context.SENSOR_SERVICE);
|
||||||
@ -868,4 +896,47 @@ class GeckoAppShell
|
|||||||
config.locale = locale;
|
config.locale = locale;
|
||||||
res.updateConfiguration(config, res.getDisplayMetrics());
|
res.updateConfiguration(config, res.getDisplayMetrics());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void killAnyZombies() {
|
||||||
|
File proc = new File("/proc");
|
||||||
|
File[] files = proc.listFiles();
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
File p = files[i];
|
||||||
|
File pEnv = new File(p, "environ");
|
||||||
|
if (pEnv.canRead() && !p.getName().equals("self")) {
|
||||||
|
int pid = Integer.parseInt(p.getName());
|
||||||
|
if (pid != android.os.Process.myPid()) {
|
||||||
|
Log.i("GeckoProcs", "gonna kill pid: " + p.getName());
|
||||||
|
android.os.Process.killProcess(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkForGeckoProcs() {
|
||||||
|
File proc = new File("/proc");
|
||||||
|
File[] files = proc.listFiles();
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
File p = files[i];
|
||||||
|
File pEnv = new File(p, "environ");
|
||||||
|
if (pEnv.canRead() && !p.getName().equals("self")) {
|
||||||
|
int pid = Integer.parseInt(p.getName());
|
||||||
|
if (pid != android.os.Process.myPid()) {
|
||||||
|
Log.i("GeckoProcs", "found pid: " + p.getName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.i("GeckoProcs", "didn't find any other procs");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void waitForAnotherGeckoProc(){
|
||||||
|
int countdown = 40;
|
||||||
|
while (!checkForGeckoProcs() && --countdown > 0) {
|
||||||
|
try {
|
||||||
|
Thread.currentThread().sleep(100);
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ public class GeckoEvent {
|
|||||||
|
|
||||||
public static final int SURFACE_CREATED = 12;
|
public static final int SURFACE_CREATED = 12;
|
||||||
public static final int SURFACE_DESTROYED = 13;
|
public static final int SURFACE_DESTROYED = 13;
|
||||||
|
public static final int GECKO_EVENT_SYNC = 14;
|
||||||
|
|
||||||
public static final int IME_COMPOSITION_END = 0;
|
public static final int IME_COMPOSITION_END = 0;
|
||||||
public static final int IME_COMPOSITION_BEGIN = 1;
|
public static final int IME_COMPOSITION_BEGIN = 1;
|
||||||
|
@ -561,9 +561,10 @@ public class GeckoInputConnection
|
|||||||
|
|
||||||
GeckoAppShell.sendEventToGecko(
|
GeckoAppShell.sendEventToGecko(
|
||||||
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start + count, 0));
|
new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start + count, 0));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Block this thread until all pending events are processed
|
||||||
|
GeckoAppShell.geckoEventSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterTextChanged(Editable s)
|
public void afterTextChanged(Editable s)
|
||||||
|
@ -43,30 +43,24 @@ import android.content.*;
|
|||||||
import android.util.*;
|
import android.util.*;
|
||||||
import android.os.*;
|
import android.os.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
|
|
||||||
public class Restarter extends Activity {
|
public class Restarter extends Activity {
|
||||||
|
|
||||||
void killAnyZombies() {
|
|
||||||
File proc = new File("/proc");
|
|
||||||
File[] files = proc.listFiles();
|
|
||||||
for (int i = 0; i < files.length; i++) {
|
|
||||||
File p = files[i];
|
|
||||||
File pEnv = new File(p, "environ");
|
|
||||||
if (pEnv.canRead() && !p.getName().equals("self")) {
|
|
||||||
int pid = Integer.parseInt(p.getName());
|
|
||||||
if (pid != android.os.Process.myPid()) {
|
|
||||||
Log.i("GeckoProcs", "gonna kill pid: " + p.getName());
|
|
||||||
android.os.Process.killProcess(pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
Log.i("Restarter", "trying to restart @MOZ_APP_NAME@");
|
Log.i("Restarter", "trying to restart @MOZ_APP_NAME@");
|
||||||
try {
|
try {
|
||||||
killAnyZombies();
|
int countdown = 40;
|
||||||
|
while (GeckoAppShell.checkForGeckoProcs() && --countdown > 0) {
|
||||||
|
// Wait for the old process to die before we continue
|
||||||
|
try {
|
||||||
|
Thread.currentThread().sleep(100);
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (countdown <= 0) // if the countdown expired, something is hung
|
||||||
|
GeckoAppShell.killAnyZombies();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.i("Restarter", e.toString());
|
Log.i("Restarter", e.toString());
|
||||||
}
|
}
|
||||||
@ -84,6 +78,8 @@ public class Restarter extends Activity {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.i("Restarter", e.toString());
|
Log.i("Restarter", e.toString());
|
||||||
}
|
}
|
||||||
|
// Give the new process time to start before we die
|
||||||
|
GeckoAppShell.waitForAnotherGeckoProc();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2237,6 +2237,7 @@ ComputeIsJITBroken()
|
|||||||
do {
|
do {
|
||||||
if (0 == line.find("Hardware")) {
|
if (0 == line.find("Hardware")) {
|
||||||
const char* blacklist[] = {
|
const char* blacklist[] = {
|
||||||
|
"SCH-I400", // Samsung Continuum
|
||||||
"SGH-T959", // Samsung i9000, Vibrant device
|
"SGH-T959", // Samsung i9000, Vibrant device
|
||||||
"SGH-I897", // Samsung i9000, Captivate device
|
"SGH-I897", // Samsung i9000, Captivate device
|
||||||
"SCH-I500", // Samsung i9000, Fascinate device
|
"SCH-I500", // Samsung i9000, Fascinate device
|
||||||
|
@ -81,6 +81,28 @@ interface nsIFileInputStream : nsIInputStream
|
|||||||
* (The file will only be reopened if it is closed for some reason.)
|
* (The file will only be reopened if it is closed for some reason.)
|
||||||
*/
|
*/
|
||||||
const long REOPEN_ON_REWIND = 1<<3;
|
const long REOPEN_ON_REWIND = 1<<3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this is set, the file will be opened (i.e., a call to
|
||||||
|
* PR_Open done) only when we do an actual operation on the stream,
|
||||||
|
* or more specifically, when one of the following is called:
|
||||||
|
* - Seek
|
||||||
|
* - Tell
|
||||||
|
* - Available
|
||||||
|
* - Read
|
||||||
|
* - ReadLine
|
||||||
|
*
|
||||||
|
* DEFER_OPEN is useful if we use the stream on a background
|
||||||
|
* thread, so that the opening and possible |stat|ing of the file
|
||||||
|
* happens there as well.
|
||||||
|
*
|
||||||
|
* @note Using this flag results in the file not being opened
|
||||||
|
* during the call to Init. This means that any errors that might
|
||||||
|
* happen when this flag is not set would happen during the
|
||||||
|
* first read. Also, the file is not locked when Init is called,
|
||||||
|
* so it might be deleted before we try to read from it.
|
||||||
|
*/
|
||||||
|
const long DEFER_OPEN = 1<<4;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,6 +124,22 @@ interface nsIFileOutputStream : nsIOutputStream
|
|||||||
*/
|
*/
|
||||||
void init(in nsIFile file, in long ioFlags, in long perm,
|
void init(in nsIFile file, in long ioFlags, in long perm,
|
||||||
in long behaviorFlags);
|
in long behaviorFlags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See the same constant in nsIFileInputStream. The deferred open will
|
||||||
|
* be performed when one of the following is called:
|
||||||
|
* - Seek
|
||||||
|
* - Tell
|
||||||
|
* - Write
|
||||||
|
* - Flush
|
||||||
|
*
|
||||||
|
* @note Using this flag results in the file not being opened
|
||||||
|
* during the call to Init. This means that any errors that might
|
||||||
|
* happen when this flag is not set would happen during the
|
||||||
|
* first write, and if the file is to be created, then it will not
|
||||||
|
* appear on the disk until the first write.
|
||||||
|
*/
|
||||||
|
const long DEFER_OPEN = 1<<0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,39 +72,25 @@
|
|||||||
|
|
||||||
nsFileStream::nsFileStream()
|
nsFileStream::nsFileStream()
|
||||||
: mFD(nsnull)
|
: mFD(nsnull)
|
||||||
, mCloseFD(PR_TRUE)
|
, mBehaviorFlags(0)
|
||||||
|
, mDeferredOpen(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
nsFileStream::~nsFileStream()
|
nsFileStream::~nsFileStream()
|
||||||
{
|
{
|
||||||
if (mCloseFD)
|
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStream, nsISeekableStream)
|
NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStream, nsISeekableStream)
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsFileStream::InitWithFileDescriptor(PRFileDesc* fd, nsISupports* parent)
|
|
||||||
{
|
|
||||||
NS_ENSURE_TRUE(mFD == nsnull, NS_ERROR_ALREADY_INITIALIZED);
|
|
||||||
//
|
|
||||||
// this file stream is dependent on its parent to keep the
|
|
||||||
// file descriptor valid. an owning reference to the parent
|
|
||||||
// prevents the file descriptor from going away prematurely.
|
|
||||||
//
|
|
||||||
mFD = fd;
|
|
||||||
mCloseFD = PR_FALSE;
|
|
||||||
mParent = parent;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsFileStream::Close()
|
nsFileStream::Close()
|
||||||
{
|
{
|
||||||
|
CleanUpOpen();
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
if (mFD) {
|
if (mFD) {
|
||||||
if (mCloseFD)
|
|
||||||
if (PR_Close(mFD) == PR_FAILURE)
|
if (PR_Close(mFD) == PR_FAILURE)
|
||||||
rv = NS_BASE_STREAM_OSERROR;
|
rv = NS_BASE_STREAM_OSERROR;
|
||||||
mFD = nsnull;
|
mFD = nsnull;
|
||||||
@ -115,6 +101,9 @@ nsFileStream::Close()
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFileStream::Seek(PRInt32 whence, PRInt64 offset)
|
nsFileStream::Seek(PRInt32 whence, PRInt64 offset)
|
||||||
{
|
{
|
||||||
|
nsresult rv = DoPendingOpen();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (mFD == nsnull)
|
if (mFD == nsnull)
|
||||||
return NS_BASE_STREAM_CLOSED;
|
return NS_BASE_STREAM_CLOSED;
|
||||||
|
|
||||||
@ -128,6 +117,9 @@ nsFileStream::Seek(PRInt32 whence, PRInt64 offset)
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFileStream::Tell(PRInt64 *result)
|
nsFileStream::Tell(PRInt64 *result)
|
||||||
{
|
{
|
||||||
|
nsresult rv = DoPendingOpen();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (mFD == nsnull)
|
if (mFD == nsnull)
|
||||||
return NS_BASE_STREAM_CLOSED;
|
return NS_BASE_STREAM_CLOSED;
|
||||||
|
|
||||||
@ -174,6 +166,62 @@ nsFileStream::SetEOF()
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsFileStream::MaybeOpen(nsILocalFile* aFile, PRInt32 aIoFlags, PRInt32 aPerm,
|
||||||
|
bool aDeferred)
|
||||||
|
{
|
||||||
|
mOpenParams.ioFlags = aIoFlags;
|
||||||
|
mOpenParams.perm = aPerm;
|
||||||
|
|
||||||
|
if (aDeferred) {
|
||||||
|
// Clone the file, as it may change between now and the deferred open
|
||||||
|
nsCOMPtr<nsIFile> file;
|
||||||
|
nsresult rv = aFile->Clone(getter_AddRefs(file));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
mOpenParams.localFile = do_QueryInterface(file);
|
||||||
|
NS_ENSURE_TRUE(mOpenParams.localFile, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
mDeferredOpen = true;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpenParams.localFile = aFile;
|
||||||
|
|
||||||
|
return DoOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsFileStream::CleanUpOpen()
|
||||||
|
{
|
||||||
|
mOpenParams.localFile = nsnull;
|
||||||
|
mDeferredOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsFileStream::DoOpen()
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(mOpenParams.localFile, "Must have a file to open");
|
||||||
|
|
||||||
|
PRFileDesc* fd;
|
||||||
|
nsresult rv = mOpenParams.localFile->OpenNSPRFileDesc(mOpenParams.ioFlags, mOpenParams.perm, &fd);
|
||||||
|
CleanUpOpen();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
mFD = fd;
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsFileStream::DoPendingOpen()
|
||||||
|
{
|
||||||
|
if (!mDeferredOpen) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DoOpen();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// nsFileInputStream
|
// nsFileInputStream
|
||||||
|
|
||||||
@ -232,12 +280,10 @@ nsFileInputStream::Open(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm)
|
|||||||
if (aPerm == -1)
|
if (aPerm == -1)
|
||||||
aPerm = 0;
|
aPerm = 0;
|
||||||
|
|
||||||
PRFileDesc* fd;
|
rv = MaybeOpen(localFile, aIOFlags, aPerm,
|
||||||
rv = localFile->OpenNSPRFileDesc(aIOFlags, aPerm, &fd);
|
mBehaviorFlags & nsIFileInputStream::DEFER_OPEN);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
mFD = fd;
|
|
||||||
|
|
||||||
if (mBehaviorFlags & DELETE_ON_CLOSE) {
|
if (mBehaviorFlags & DELETE_ON_CLOSE) {
|
||||||
// POSIX compatible filesystems allow a file to be unlinked while a
|
// POSIX compatible filesystems allow a file to be unlinked while a
|
||||||
// file descriptor is still referencing the file. since we've already
|
// file descriptor is still referencing the file. since we've already
|
||||||
@ -259,7 +305,7 @@ nsFileInputStream::Init(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm,
|
|||||||
PRInt32 aBehaviorFlags)
|
PRInt32 aBehaviorFlags)
|
||||||
{
|
{
|
||||||
NS_ENSURE_TRUE(!mFD, NS_ERROR_ALREADY_INITIALIZED);
|
NS_ENSURE_TRUE(!mFD, NS_ERROR_ALREADY_INITIALIZED);
|
||||||
NS_ENSURE_TRUE(!mParent, NS_ERROR_ALREADY_INITIALIZED);
|
NS_ENSURE_TRUE(!mDeferredOpen, NS_ERROR_ALREADY_INITIALIZED);
|
||||||
|
|
||||||
mBehaviorFlags = aBehaviorFlags;
|
mBehaviorFlags = aBehaviorFlags;
|
||||||
|
|
||||||
@ -291,6 +337,9 @@ nsFileInputStream::Close()
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFileInputStream::Available(PRUint32* aResult)
|
nsFileInputStream::Available(PRUint32* aResult)
|
||||||
{
|
{
|
||||||
|
nsresult rv = DoPendingOpen();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!mFD) {
|
if (!mFD) {
|
||||||
return NS_BASE_STREAM_CLOSED;
|
return NS_BASE_STREAM_CLOSED;
|
||||||
}
|
}
|
||||||
@ -310,6 +359,9 @@ nsFileInputStream::Available(PRUint32* aResult)
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFileInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32* aResult)
|
nsFileInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32* aResult)
|
||||||
{
|
{
|
||||||
|
nsresult rv = DoPendingOpen();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!mFD) {
|
if (!mFD) {
|
||||||
*aResult = 0;
|
*aResult = 0;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -333,6 +385,9 @@ nsFileInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32* aResult)
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFileInputStream::ReadLine(nsACString& aLine, PRBool* aResult)
|
nsFileInputStream::ReadLine(nsACString& aLine, PRBool* aResult)
|
||||||
{
|
{
|
||||||
|
nsresult rv = DoPendingOpen();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!mLineBuffer) {
|
if (!mLineBuffer) {
|
||||||
nsresult rv = NS_InitLineBuffer(&mLineBuffer);
|
nsresult rv = NS_InitLineBuffer(&mLineBuffer);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
@ -365,6 +420,9 @@ nsFileInputStream::IsNonBlocking(PRBool *aNonBlocking)
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFileInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset)
|
nsFileInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset)
|
||||||
{
|
{
|
||||||
|
nsresult rv = DoPendingOpen();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
PR_FREEIF(mLineBuffer); // this invalidates the line buffer
|
PR_FREEIF(mLineBuffer); // this invalidates the line buffer
|
||||||
if (!mFD) {
|
if (!mFD) {
|
||||||
if (mBehaviorFlags & REOPEN_ON_REWIND) {
|
if (mBehaviorFlags & REOPEN_ON_REWIND) {
|
||||||
@ -564,6 +622,9 @@ nsFileOutputStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm,
|
|||||||
PRInt32 behaviorFlags)
|
PRInt32 behaviorFlags)
|
||||||
{
|
{
|
||||||
NS_ENSURE_TRUE(mFD == nsnull, NS_ERROR_ALREADY_INITIALIZED);
|
NS_ENSURE_TRUE(mFD == nsnull, NS_ERROR_ALREADY_INITIALIZED);
|
||||||
|
NS_ENSURE_TRUE(!mDeferredOpen, NS_ERROR_ALREADY_INITIALIZED);
|
||||||
|
|
||||||
|
mBehaviorFlags = behaviorFlags;
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(file, &rv);
|
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(file, &rv);
|
||||||
@ -573,12 +634,8 @@ nsFileOutputStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm,
|
|||||||
if (perm <= 0)
|
if (perm <= 0)
|
||||||
perm = 0664;
|
perm = 0664;
|
||||||
|
|
||||||
PRFileDesc* fd;
|
return MaybeOpen(localFile, ioFlags, perm,
|
||||||
rv = localFile->OpenNSPRFileDesc(ioFlags, perm, &fd);
|
mBehaviorFlags & nsIFileOutputStream::DEFER_OPEN);
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
mFD = fd;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
@ -590,6 +647,9 @@ nsFileOutputStream::Close()
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFileOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result)
|
nsFileOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result)
|
||||||
{
|
{
|
||||||
|
nsresult rv = DoPendingOpen();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (mFD == nsnull)
|
if (mFD == nsnull)
|
||||||
return NS_BASE_STREAM_CLOSED;
|
return NS_BASE_STREAM_CLOSED;
|
||||||
|
|
||||||
@ -604,6 +664,9 @@ nsFileOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result)
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFileOutputStream::Flush(void)
|
nsFileOutputStream::Flush(void)
|
||||||
{
|
{
|
||||||
|
nsresult rv = DoPendingOpen();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (mFD == nsnull)
|
if (mFD == nsnull)
|
||||||
return NS_BASE_STREAM_CLOSED;
|
return NS_BASE_STREAM_CLOSED;
|
||||||
|
|
||||||
@ -653,7 +716,16 @@ NS_IMETHODIMP
|
|||||||
nsSafeFileOutputStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm,
|
nsSafeFileOutputStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm,
|
||||||
PRInt32 behaviorFlags)
|
PRInt32 behaviorFlags)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG(file);
|
return nsFileOutputStream::Init(file, ioFlags, perm, behaviorFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsSafeFileOutputStream::DoOpen()
|
||||||
|
{
|
||||||
|
// Make sure mOpenParams.localFile will be empty if we bail somewhere in
|
||||||
|
// this function
|
||||||
|
nsCOMPtr<nsILocalFile> file;
|
||||||
|
file.swap(mOpenParams.localFile);
|
||||||
|
|
||||||
nsresult rv = file->Exists(&mTargetFileExists);
|
nsresult rv = file->Exists(&mTargetFileExists);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
@ -680,16 +752,21 @@ nsSafeFileOutputStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm,
|
|||||||
PRUint32 origPerm;
|
PRUint32 origPerm;
|
||||||
if (NS_FAILED(file->GetPermissions(&origPerm))) {
|
if (NS_FAILED(file->GetPermissions(&origPerm))) {
|
||||||
NS_ERROR("Can't get permissions of target file");
|
NS_ERROR("Can't get permissions of target file");
|
||||||
origPerm = perm;
|
origPerm = mOpenParams.perm;
|
||||||
}
|
}
|
||||||
// XXX What if |perm| is more restrictive then |origPerm|?
|
// XXX What if |perm| is more restrictive then |origPerm|?
|
||||||
// This leaves the user supplied permissions as they were.
|
// This leaves the user supplied permissions as they were.
|
||||||
rv = tempResult->CreateUnique(nsIFile::NORMAL_FILE_TYPE, origPerm);
|
rv = tempResult->CreateUnique(nsIFile::NORMAL_FILE_TYPE, origPerm);
|
||||||
}
|
}
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
// nsFileOutputStream::DoOpen will work on the temporary file, so we
|
||||||
|
// prepare it and place it in mOpenParams.localFile.
|
||||||
|
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(tempResult, &rv);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
mOpenParams.localFile = localFile;
|
||||||
mTempFile = tempResult;
|
mTempFile = tempResult;
|
||||||
mTargetFile = file;
|
mTargetFile = file;
|
||||||
rv = nsFileOutputStream::Init(mTempFile, ioFlags, perm, behaviorFlags);
|
rv = nsFileOutputStream::DoOpen();
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -64,13 +64,57 @@ public:
|
|||||||
virtual ~nsFileStream();
|
virtual ~nsFileStream();
|
||||||
|
|
||||||
nsresult Close();
|
nsresult Close();
|
||||||
nsresult InitWithFileDescriptor(PRFileDesc* fd, nsISupports* parent);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PRFileDesc* mFD;
|
PRFileDesc* mFD;
|
||||||
nsCOMPtr<nsISupports> mParent; // strong reference to parent nsFileIO,
|
|
||||||
// which ensures mFD remains valid.
|
/**
|
||||||
PRBool mCloseFD;
|
* Flags describing our behavior. See the IDL file for possible values.
|
||||||
|
*/
|
||||||
|
PRInt32 mBehaviorFlags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether we have a pending open (see DEFER_OPEN in the IDL file).
|
||||||
|
*/
|
||||||
|
bool mDeferredOpen;
|
||||||
|
|
||||||
|
struct OpenParams {
|
||||||
|
nsCOMPtr<nsILocalFile> localFile;
|
||||||
|
PRInt32 ioFlags;
|
||||||
|
PRInt32 perm;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data we need to do an open.
|
||||||
|
*/
|
||||||
|
OpenParams mOpenParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the data we need to open the file, and either does the open now
|
||||||
|
* by calling DoOpen(), or leaves it to be opened later by a call to
|
||||||
|
* DoPendingOpen().
|
||||||
|
*/
|
||||||
|
nsresult MaybeOpen(nsILocalFile* aFile, PRInt32 aIoFlags, PRInt32 aPerm,
|
||||||
|
bool aDeferred);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up data prepared in MaybeOpen.
|
||||||
|
*/
|
||||||
|
void CleanUpOpen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the file. This is called either from MaybeOpen (during Init)
|
||||||
|
* or from DoPendingOpen (if DEFER_OPEN is used when initializing this
|
||||||
|
* stream). The default behavior of DoOpen is to open the file and save the
|
||||||
|
* file descriptor.
|
||||||
|
*/
|
||||||
|
virtual nsresult DoOpen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there is a pending open, do it now. It's important for this to be
|
||||||
|
* inline since we do it in almost every stream API call.
|
||||||
|
*/
|
||||||
|
inline nsresult DoPendingOpen();
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -93,7 +137,6 @@ public:
|
|||||||
nsFileInputStream() : nsFileStream()
|
nsFileInputStream() : nsFileStream()
|
||||||
{
|
{
|
||||||
mLineBuffer = nsnull;
|
mLineBuffer = nsnull;
|
||||||
mBehaviorFlags = 0;
|
|
||||||
}
|
}
|
||||||
virtual ~nsFileInputStream()
|
virtual ~nsFileInputStream()
|
||||||
{
|
{
|
||||||
@ -118,10 +161,6 @@ protected:
|
|||||||
* The permissions passed to Init() for the file open.
|
* The permissions passed to Init() for the file open.
|
||||||
*/
|
*/
|
||||||
PRInt32 mPerm;
|
PRInt32 mPerm;
|
||||||
/**
|
|
||||||
* Flags describing our behavior. See the IDL file for possible values.
|
|
||||||
*/
|
|
||||||
PRInt32 mBehaviorFlags;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -194,6 +233,8 @@ public:
|
|||||||
|
|
||||||
virtual ~nsSafeFileOutputStream() { nsSafeFileOutputStream::Close(); }
|
virtual ~nsSafeFileOutputStream() { nsSafeFileOutputStream::Close(); }
|
||||||
|
|
||||||
|
virtual nsresult DoOpen();
|
||||||
|
|
||||||
NS_IMETHODIMP Close();
|
NS_IMETHODIMP Close();
|
||||||
NS_IMETHODIMP Write(const char *buf, PRUint32 count, PRUint32 *result);
|
NS_IMETHODIMP Write(const char *buf, PRUint32 count, PRUint32 *result);
|
||||||
NS_IMETHODIMP Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags);
|
NS_IMETHODIMP Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags);
|
||||||
|
@ -49,6 +49,9 @@ Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
|||||||
// files.
|
// files.
|
||||||
do_get_profile();
|
do_get_profile();
|
||||||
|
|
||||||
|
const OUTPUT_STREAM_CONTRACT_ID = "@mozilla.org/network/file-output-stream;1";
|
||||||
|
const SAFE_OUTPUT_STREAM_CONTRACT_ID = "@mozilla.org/network/safe-file-output-stream;1";
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Helper Methods
|
//// Helper Methods
|
||||||
|
|
||||||
@ -75,10 +78,15 @@ function getFileContents(aFile)
|
|||||||
return string.value;
|
return string.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
/**
|
||||||
//// Tests
|
* Tests asynchronously writing a file using NetUtil.asyncCopy.
|
||||||
|
*
|
||||||
function test_async_write_file()
|
* @param aContractId
|
||||||
|
* The contract ID to use for the output stream
|
||||||
|
* @param aDeferOpen
|
||||||
|
* Whether to use DEFER_OPEN in the output stream.
|
||||||
|
*/
|
||||||
|
function async_write_file(aContractId, aDeferOpen)
|
||||||
{
|
{
|
||||||
do_test_pending();
|
do_test_pending();
|
||||||
|
|
||||||
@ -90,9 +98,8 @@ function test_async_write_file()
|
|||||||
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
||||||
|
|
||||||
// Then, we need an output stream to our output file.
|
// Then, we need an output stream to our output file.
|
||||||
let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
|
let ostream = Cc[aContractId].createInstance(Ci.nsIFileOutputStream);
|
||||||
createInstance(Ci.nsIFileOutputStream);
|
ostream.init(file, -1, -1, aDeferOpen ? Ci.nsIFileOutputStream.DEFER_OPEN : 0);
|
||||||
ostream.init(file, -1, -1, 0);
|
|
||||||
|
|
||||||
// Finally, we need an input stream to take data from.
|
// Finally, we need an input stream to take data from.
|
||||||
const TEST_DATA = "this is a test string";
|
const TEST_DATA = "this is a test string";
|
||||||
@ -113,39 +120,23 @@ function test_async_write_file()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_async_write_file_nsISafeOutputStream()
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
{
|
//// Tests
|
||||||
do_test_pending();
|
|
||||||
|
|
||||||
// First, we need an output file to write to.
|
function test_async_write_file() {
|
||||||
let file = Cc["@mozilla.org/file/directory_service;1"].
|
async_write_file(OUTPUT_STREAM_CONTRACT_ID);
|
||||||
getService(Ci.nsIProperties).
|
}
|
||||||
get("ProfD", Ci.nsIFile);
|
|
||||||
file.append("NetUtil-async-test-file.tmp");
|
|
||||||
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
|
||||||
|
|
||||||
// Then, we need an output stream to our output file.
|
function test_async_write_file_deferred() {
|
||||||
let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].
|
async_write_file(OUTPUT_STREAM_CONTRACT_ID, true);
|
||||||
createInstance(Ci.nsIFileOutputStream);
|
}
|
||||||
ostream.init(file, -1, -1, 0);
|
|
||||||
|
|
||||||
// Finally, we need an input stream to take data from.
|
function test_async_write_file_safe() {
|
||||||
const TEST_DATA = "this is a test string";
|
async_write_file(SAFE_OUTPUT_STREAM_CONTRACT_ID);
|
||||||
let istream = Cc["@mozilla.org/io/string-input-stream;1"].
|
}
|
||||||
createInstance(Ci.nsIStringInputStream);
|
|
||||||
istream.setData(TEST_DATA, TEST_DATA.length);
|
|
||||||
|
|
||||||
NetUtil.asyncCopy(istream, ostream, function(aResult) {
|
function test_async_write_file_safe_deferred() {
|
||||||
// Make sure the copy was successful!
|
async_write_file(SAFE_OUTPUT_STREAM_CONTRACT_ID, true);
|
||||||
do_check_true(Components.isSuccessCode(aResult));
|
|
||||||
|
|
||||||
// Check the file contents.
|
|
||||||
do_check_eq(TEST_DATA, getFileContents(file));
|
|
||||||
|
|
||||||
// Finish the test.
|
|
||||||
do_test_finished();
|
|
||||||
run_next_test();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_newURI_no_spec_throws()
|
function test_newURI_no_spec_throws()
|
||||||
@ -529,7 +520,9 @@ function test_readInputStreamToString_too_many_bytes()
|
|||||||
|
|
||||||
let tests = [
|
let tests = [
|
||||||
test_async_write_file,
|
test_async_write_file,
|
||||||
test_async_write_file_nsISafeOutputStream,
|
test_async_write_file_deferred,
|
||||||
|
test_async_write_file_safe,
|
||||||
|
test_async_write_file_safe_deferred,
|
||||||
test_newURI_no_spec_throws,
|
test_newURI_no_spec_throws,
|
||||||
test_newURI,
|
test_newURI,
|
||||||
test_newURI_takes_nsIFile,
|
test_newURI_takes_nsIFile,
|
||||||
|
231
netwerk/test/unit/test_filestreams.js
Normal file
231
netwerk/test/unit/test_filestreams.js
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
let Cc = Components.classes;
|
||||||
|
let Ci = Components.interfaces;
|
||||||
|
|
||||||
|
// We need the profile directory so the test harness will clean up our test
|
||||||
|
// files.
|
||||||
|
do_get_profile();
|
||||||
|
|
||||||
|
const OUTPUT_STREAM_CONTRACT_ID = "@mozilla.org/network/file-output-stream;1";
|
||||||
|
const SAFE_OUTPUT_STREAM_CONTRACT_ID = "@mozilla.org/network/safe-file-output-stream;1";
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//// Helper Methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a leafName for a file that does not exist, but does *not*
|
||||||
|
* create the file. Similar to createUnique except for the fact that createUnique
|
||||||
|
* does create the file.
|
||||||
|
*
|
||||||
|
* @param aFile
|
||||||
|
* The file to modify in order for it to have a unique leafname.
|
||||||
|
*/
|
||||||
|
function ensure_unique(aFile)
|
||||||
|
{
|
||||||
|
ensure_unique.fileIndex = ensure_unique.fileIndex || 0;
|
||||||
|
|
||||||
|
var leafName = aFile.leafName;
|
||||||
|
while (aFile.clone().exists()) {
|
||||||
|
aFile.leafName = leafName + "_" + (ensure_unique.fileIndex++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for files being accessed at the right time. Streams that use
|
||||||
|
* DEFER_OPEN should only open or create the file when an operation is
|
||||||
|
* done, and not during Init().
|
||||||
|
*
|
||||||
|
* Note that for writing, we check for actual writing in test_NetUtil (async)
|
||||||
|
* and in sync_operations in this file (sync), whereas in this function we
|
||||||
|
* just check that the file is *not* created during init.
|
||||||
|
*
|
||||||
|
* @param aContractId
|
||||||
|
* The contract ID to use for the output stream
|
||||||
|
* @param aDeferOpen
|
||||||
|
* Whether to check with DEFER_OPEN or not
|
||||||
|
* @param aTrickDeferredOpen
|
||||||
|
* Whether we try to 'trick' deferred opens by changing the file object before
|
||||||
|
* the actual open. The stream should have a clone, so changes to the file
|
||||||
|
* object after Init and before Open should not affect it.
|
||||||
|
*/
|
||||||
|
function check_access(aContractId, aDeferOpen, aTrickDeferredOpen)
|
||||||
|
{
|
||||||
|
const LEAF_NAME = "filestreams-test-file.tmp";
|
||||||
|
const TRICKY_LEAF_NAME = "BetYouDidNotExpectThat.tmp";
|
||||||
|
let file = Cc["@mozilla.org/file/directory_service;1"].
|
||||||
|
getService(Ci.nsIProperties).
|
||||||
|
get("ProfD", Ci.nsIFile);
|
||||||
|
file.append(LEAF_NAME);
|
||||||
|
|
||||||
|
// Writing
|
||||||
|
|
||||||
|
ensure_unique(file);
|
||||||
|
let ostream = Cc[aContractId].createInstance(Ci.nsIFileOutputStream);
|
||||||
|
ostream.init(file, -1, -1, aDeferOpen ? Ci.nsIFileOutputStream.DEFER_OPEN : 0);
|
||||||
|
do_check_eq(aDeferOpen, !file.clone().exists()); // If defer, should not exist and vice versa
|
||||||
|
if (aDeferOpen) {
|
||||||
|
// File should appear when we do write to it.
|
||||||
|
if (aTrickDeferredOpen) {
|
||||||
|
// See |@param aDeferOpen| in the JavaDoc comment for this function
|
||||||
|
file.leafName = TRICKY_LEAF_NAME;
|
||||||
|
}
|
||||||
|
ostream.write("data", 4);
|
||||||
|
if (aTrickDeferredOpen) {
|
||||||
|
file.leafName = LEAF_NAME;
|
||||||
|
}
|
||||||
|
// We did a write, so the file should now exist
|
||||||
|
do_check_true(file.clone().exists());
|
||||||
|
}
|
||||||
|
ostream.close();
|
||||||
|
|
||||||
|
// Reading
|
||||||
|
|
||||||
|
ensure_unique(file);
|
||||||
|
let istream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||||
|
createInstance(Ci.nsIFileInputStream);
|
||||||
|
var initOk, getOk;
|
||||||
|
try {
|
||||||
|
istream.init(file, -1, 0, aDeferOpen ? Ci.nsIFileInputStream.DEFER_OPEN : 0);
|
||||||
|
initOk = true;
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
initOk = false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let fstream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||||
|
createInstance(Ci.nsIFileInputStream);
|
||||||
|
fstream.init(aFile, -1, 0, 0);
|
||||||
|
getOk = true;
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
getOk = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the open is deferred, then Init should succeed even though the file we
|
||||||
|
// intend to read does not exist, and then trying to read from it should
|
||||||
|
// fail. The other case is where the open is not deferred, and there we should
|
||||||
|
// get an error when we Init (and also when we try to read).
|
||||||
|
do_check_true( (aDeferOpen && initOk && !getOk) ||
|
||||||
|
(!aDeferOpen && !initOk && !getOk) );
|
||||||
|
istream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We test async operations in test_NetUtil.js, and here test for simple sync
|
||||||
|
* operations on input streams.
|
||||||
|
*
|
||||||
|
* @param aDeferOpen
|
||||||
|
* Whether to use DEFER_OPEN in the streams.
|
||||||
|
*/
|
||||||
|
function sync_operations(aDeferOpen)
|
||||||
|
{
|
||||||
|
const TEST_DATA = "this is a test string";
|
||||||
|
const LEAF_NAME = "filestreams-test-file.tmp";
|
||||||
|
|
||||||
|
let file = Cc["@mozilla.org/file/directory_service;1"].
|
||||||
|
getService(Ci.nsIProperties).
|
||||||
|
get("ProfD", Ci.nsIFile);
|
||||||
|
file.append(LEAF_NAME);
|
||||||
|
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
||||||
|
|
||||||
|
let ostream = Cc[OUTPUT_STREAM_CONTRACT_ID].
|
||||||
|
createInstance(Ci.nsIFileOutputStream);
|
||||||
|
ostream.init(file, -1, -1, aDeferOpen ? Ci.nsIFileOutputStream.DEFER_OPEN : 0);
|
||||||
|
|
||||||
|
ostream.write(TEST_DATA, TEST_DATA.length);
|
||||||
|
ostream.close();
|
||||||
|
|
||||||
|
let fstream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||||
|
createInstance(Ci.nsIFileInputStream);
|
||||||
|
fstream.init(file, -1, 0, aDeferOpen ? Ci.nsIFileInputStream.DEFER_OPEN : 0);
|
||||||
|
|
||||||
|
let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].
|
||||||
|
createInstance(Ci.nsIConverterInputStream);
|
||||||
|
cstream.init(fstream, "UTF-8", 0, 0);
|
||||||
|
|
||||||
|
let string = {};
|
||||||
|
cstream.readString(-1, string);
|
||||||
|
cstream.close();
|
||||||
|
fstream.close();
|
||||||
|
|
||||||
|
do_check_eq(string.value, TEST_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//// Tests
|
||||||
|
|
||||||
|
function test_access()
|
||||||
|
{
|
||||||
|
check_access(OUTPUT_STREAM_CONTRACT_ID, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_access_trick()
|
||||||
|
{
|
||||||
|
check_access(OUTPUT_STREAM_CONTRACT_ID, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_access_defer()
|
||||||
|
{
|
||||||
|
check_access(OUTPUT_STREAM_CONTRACT_ID, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_access_defer_trick()
|
||||||
|
{
|
||||||
|
check_access(OUTPUT_STREAM_CONTRACT_ID, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_access_safe()
|
||||||
|
{
|
||||||
|
check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_access_safe_trick()
|
||||||
|
{
|
||||||
|
check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_access_safe_defer()
|
||||||
|
{
|
||||||
|
check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_access_safe_defer_trick()
|
||||||
|
{
|
||||||
|
check_access(SAFE_OUTPUT_STREAM_CONTRACT_ID, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_sync_operations()
|
||||||
|
{
|
||||||
|
sync_operations();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_sync_operations_deferred()
|
||||||
|
{
|
||||||
|
sync_operations(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//// Test Runner
|
||||||
|
|
||||||
|
let tests = [
|
||||||
|
test_access,
|
||||||
|
test_access_trick,
|
||||||
|
test_access_defer,
|
||||||
|
test_access_defer_trick,
|
||||||
|
test_access_safe,
|
||||||
|
test_access_safe_trick,
|
||||||
|
test_access_safe_defer,
|
||||||
|
test_access_safe_defer_trick,
|
||||||
|
test_sync_operations,
|
||||||
|
test_sync_operations_deferred,
|
||||||
|
];
|
||||||
|
|
||||||
|
function run_test()
|
||||||
|
{
|
||||||
|
tests.forEach(function(test) {
|
||||||
|
test();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -455,8 +455,8 @@ static void * mozload(const char * path, void *zip,
|
|||||||
|
|
||||||
#ifdef DEBUG_EXTRACT_LIBS
|
#ifdef DEBUG_EXTRACT_LIBS
|
||||||
if (extractLibs) {
|
if (extractLibs) {
|
||||||
char fullpath[256];
|
char fullpath[PATH_MAX];
|
||||||
snprintf(fullpath, 256, "%s/%s", getenv("CACHE_PATH"), path + 4);
|
snprintf(fullpath, PATH_MAX, "%s/%s", getenv("CACHE_PATH"), path + 4);
|
||||||
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "resolved %s to %s", path, fullpath);
|
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "resolved %s to %s", path, fullpath);
|
||||||
extractFile(fullpath, entry, data);
|
extractFile(fullpath, entry, data);
|
||||||
handle = __wrap_dlopen(fullpath, RTLD_LAZY);
|
handle = __wrap_dlopen(fullpath, RTLD_LAZY);
|
||||||
@ -474,7 +474,7 @@ static void * mozload(const char * path, void *zip,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
size_t offset = letoh32(entry->offset) + sizeof(*file) + letoh16(file->filename_size) + letoh16(file->extra_field_size);
|
size_t offset = letoh32(entry->offset) + sizeof(*file) + letoh16(file->filename_size) + letoh16(file->extra_field_size);
|
||||||
|
bool skipLibCache = false;
|
||||||
int fd = zip_fd;
|
int fd = zip_fd;
|
||||||
void * buf = NULL;
|
void * buf = NULL;
|
||||||
uint32_t lib_size = letoh32(entry->uncompressed_size);
|
uint32_t lib_size = letoh32(entry->uncompressed_size);
|
||||||
@ -483,8 +483,8 @@ static void * mozload(const char * path, void *zip,
|
|||||||
cache_fd = lookupLibCacheFd(path + 4);
|
cache_fd = lookupLibCacheFd(path + 4);
|
||||||
fd = cache_fd;
|
fd = cache_fd;
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
char fullpath[256];
|
char fullpath[PATH_MAX];
|
||||||
snprintf(fullpath, 256, "%s/%s", getenv("CACHE_PATH"), path + 4);
|
snprintf(fullpath, PATH_MAX, "%s/%s", getenv("CACHE_PATH"), path + 4);
|
||||||
fd = open(fullpath, O_RDWR);
|
fd = open(fullpath, O_RDWR);
|
||||||
struct stat status;
|
struct stat status;
|
||||||
if (stat(fullpath, &status) ||
|
if (stat(fullpath, &status) ||
|
||||||
@ -504,9 +504,26 @@ static void * mozload(const char * path, void *zip,
|
|||||||
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loading %s from cache", path + 4);
|
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loading %s from cache", path + 4);
|
||||||
#endif
|
#endif
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't open " ASHMEM_NAME_DEF ", Error %d, %s", errno, strerror(errno));
|
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't open " ASHMEM_NAME_DEF ", Error %d, %s, using a file", errno, strerror(errno));
|
||||||
|
char fullpath[PATH_MAX];
|
||||||
|
snprintf(fullpath, PATH_MAX, "%s/%s", getenv("CACHE_PATH"), path + 4);
|
||||||
|
fd = open(fullpath, O_RDWR | O_CREAT);
|
||||||
|
if (fd < 0) {
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't create a file either, giving up");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
// we'd like to use fallocate here, but it doesn't exist currently?
|
||||||
|
if (lseek(fd, lib_size - 1, SEEK_SET) == (off_t) - 1) {
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "seeking file failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (write(fd, "", 1) != 1) {
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "writting one byte to the file failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
skipLibCache = true;
|
||||||
|
addLibCacheFd(path + 4, fd);
|
||||||
|
}
|
||||||
buf = mmap(NULL, lib_size,
|
buf = mmap(NULL, lib_size,
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED, fd, 0);
|
MAP_SHARED, fd, 0);
|
||||||
@ -520,8 +537,10 @@ static void * mozload(const char * path, void *zip,
|
|||||||
|
|
||||||
if (cache_fd < 0) {
|
if (cache_fd < 0) {
|
||||||
extractLib(entry, data, buf);
|
extractLib(entry, data, buf);
|
||||||
|
if (!skipLibCache)
|
||||||
addLibCacheFd(path + 4, fd, lib_size, buf);
|
addLibCacheFd(path + 4, fd, lib_size, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// preload libxul, to avoid slowly demand-paging it
|
// preload libxul, to avoid slowly demand-paging it
|
||||||
if (!strcmp(path, "lib/libxul.so"))
|
if (!strcmp(path, "lib/libxul.so"))
|
||||||
madvise(buf, entry->uncompressed_size, MADV_WILLNEED);
|
madvise(buf, entry->uncompressed_size, MADV_WILLNEED);
|
||||||
@ -719,9 +738,9 @@ Java_org_mozilla_gecko_GeckoAppShell_loadLibs(JNIEnv *jenv, jclass jGeckoAppShel
|
|||||||
if (!info->buffer)
|
if (!info->buffer)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
char fullpath[256];
|
char fullpath[PATH_MAX];
|
||||||
snprintf(fullpath, 256, "%s/%s", getenv("CACHE_PATH"), info->name);
|
snprintf(fullpath, PATH_MAX, "%s/%s", getenv("CACHE_PATH"), info->name);
|
||||||
char tmp_path[256];
|
char tmp_path[PATH_MAX];
|
||||||
sprintf(tmp_path, "%s.tmp", fullpath);
|
sprintf(tmp_path, "%s.tmp", fullpath);
|
||||||
int file_fd = open(tmp_path, O_CREAT | O_WRONLY);
|
int file_fd = open(tmp_path, O_CREAT | O_WRONLY);
|
||||||
// using sendfile would be preferable, but it doesn't seem to work
|
// using sendfile would be preferable, but it doesn't seem to work
|
||||||
|
@ -2560,7 +2560,7 @@ SearchService.prototype = {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
LOG("_buildCache: Writing to cache file.");
|
LOG("_buildCache: Writing to cache file.");
|
||||||
ostream.init(cacheFile, (MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE), PERMS_FILE, 0);
|
ostream.init(cacheFile, (MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE), PERMS_FILE, ostream.DEFER_OPEN);
|
||||||
converter.charset = "UTF-8";
|
converter.charset = "UTF-8";
|
||||||
let data = converter.convertToInputStream(JSON.stringify(cache));
|
let data = converter.convertToInputStream(JSON.stringify(cache));
|
||||||
|
|
||||||
|
@ -929,6 +929,40 @@ function validateFileName(aFileName)
|
|||||||
}
|
}
|
||||||
else if (navigator.appVersion.indexOf("Macintosh") != -1)
|
else if (navigator.appVersion.indexOf("Macintosh") != -1)
|
||||||
re = /[\:\/]+/g;
|
re = /[\:\/]+/g;
|
||||||
|
else if (navigator.appVersion.indexOf("Android") != -1 ||
|
||||||
|
navigator.appVersion.indexOf("Maemo") != -1) {
|
||||||
|
// On mobile devices, the filesystem may be very limited in what
|
||||||
|
// it considers valid characters. To avoid errors, we sanitize
|
||||||
|
// conservatively.
|
||||||
|
const dangerousChars = "*?<>|\":/\\[];,+=";
|
||||||
|
var processed = "";
|
||||||
|
for (var i = 0; i < aFileName.length; i++)
|
||||||
|
processed += aFileName.charCodeAt(i) >= 32 &&
|
||||||
|
!(dangerousChars.indexOf(aFileName[i]) >= 0) ? aFileName[i]
|
||||||
|
: "_";
|
||||||
|
|
||||||
|
// Last character should not be a space
|
||||||
|
processed = processed.trim();
|
||||||
|
|
||||||
|
// If a large part of the filename has been sanitized, then we
|
||||||
|
// will use a default filename instead
|
||||||
|
if (processed.replace(/_/g, "").length <= processed.length/2) {
|
||||||
|
// We purposefully do not use a localized default filename,
|
||||||
|
// which we could have done using
|
||||||
|
// ContentAreaUtils.stringBundle.GetStringFromName("DefaultSaveFileName")
|
||||||
|
// since it may contain invalid characters.
|
||||||
|
var original = processed;
|
||||||
|
processed = "download";
|
||||||
|
|
||||||
|
// Preserve a suffix, if there is one
|
||||||
|
if (original.indexOf(".") >= 0) {
|
||||||
|
var suffix = original.split(".").slice(-1)[0];
|
||||||
|
if (suffix && suffix.indexOf("_") < 0)
|
||||||
|
processed += "." + suffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
return aFileName.replace(re, "_");
|
return aFileName.replace(re, "_");
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,8 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
|||||||
jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V");
|
jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V");
|
||||||
jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;)V");
|
jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;)V");
|
||||||
jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
|
jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
|
||||||
|
jAcknowledgeEventSync = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "acknowledgeEventSync", "()V");
|
||||||
|
|
||||||
jEnableAccelerometer = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableAccelerometer", "(Z)V");
|
jEnableAccelerometer = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableAccelerometer", "(Z)V");
|
||||||
jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V");
|
jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V");
|
||||||
jReturnIMEQueryResult = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "returnIMEQueryResult", "(Ljava/lang/String;II)V");
|
jReturnIMEQueryResult = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "returnIMEQueryResult", "(Ljava/lang/String;II)V");
|
||||||
@ -263,6 +265,13 @@ AndroidBridge::NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen,
|
|||||||
sBridge->jNotifyIMEChange, args);
|
sBridge->jNotifyIMEChange, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AndroidBridge::AcknowledgeEventSync()
|
||||||
|
{
|
||||||
|
ALOG_BRIDGE("AndroidBridge::AcknowledgeEventSync");
|
||||||
|
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jAcknowledgeEventSync);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AndroidBridge::EnableAccelerometer(bool aEnable)
|
AndroidBridge::EnableAccelerometer(bool aEnable)
|
||||||
{
|
{
|
||||||
|
@ -111,6 +111,8 @@ public:
|
|||||||
|
|
||||||
static void NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen, int aStart, int aEnd, int aNewEnd);
|
static void NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen, int aStart, int aEnd, int aNewEnd);
|
||||||
|
|
||||||
|
void AcknowledgeEventSync();
|
||||||
|
|
||||||
void EnableAccelerometer(bool aEnable);
|
void EnableAccelerometer(bool aEnable);
|
||||||
|
|
||||||
void EnableLocation(bool aEnable);
|
void EnableLocation(bool aEnable);
|
||||||
@ -246,6 +248,7 @@ protected:
|
|||||||
jmethodID jNotifyIME;
|
jmethodID jNotifyIME;
|
||||||
jmethodID jNotifyIMEEnabled;
|
jmethodID jNotifyIMEEnabled;
|
||||||
jmethodID jNotifyIMEChange;
|
jmethodID jNotifyIMEChange;
|
||||||
|
jmethodID jAcknowledgeEventSync;
|
||||||
jmethodID jEnableAccelerometer;
|
jmethodID jEnableAccelerometer;
|
||||||
jmethodID jEnableLocation;
|
jmethodID jEnableLocation;
|
||||||
jmethodID jReturnIMEQueryResult;
|
jmethodID jReturnIMEQueryResult;
|
||||||
|
@ -451,6 +451,7 @@ public:
|
|||||||
LOAD_URI = 11,
|
LOAD_URI = 11,
|
||||||
SURFACE_CREATED = 12,
|
SURFACE_CREATED = 12,
|
||||||
SURFACE_DESTROYED = 13,
|
SURFACE_DESTROYED = 13,
|
||||||
|
GECKO_EVENT_SYNC = 14,
|
||||||
dummy_java_enum_list_end
|
dummy_java_enum_list_end
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ nsWindow::Show(PRBool aState)
|
|||||||
BringToFront();
|
BringToFront();
|
||||||
} else if (TopWindow() == this) {
|
} else if (TopWindow() == this) {
|
||||||
// find the next visible window to show
|
// find the next visible window to show
|
||||||
int i;
|
unsigned int i;
|
||||||
for (i = 1; i < gTopLevelWindows.Length(); i++) {
|
for (i = 1; i < gTopLevelWindows.Length(); i++) {
|
||||||
nsWindow *win = gTopLevelWindows[i];
|
nsWindow *win = gTopLevelWindows[i];
|
||||||
if (!win->mIsVisible)
|
if (!win->mIsVisible)
|
||||||
@ -853,6 +853,10 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
|
|||||||
sValidSurface = false;
|
sValidSurface = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AndroidGeckoEvent::GECKO_EVENT_SYNC:
|
||||||
|
AndroidBridge::Bridge()->AcknowledgeEventSync();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,7 @@ static nsresult MacErrorMapper(OSErr inErr);
|
|||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
#include "AndroidBridge.h"
|
#include "AndroidBridge.h"
|
||||||
#include "nsIMIMEService.h"
|
#include "nsIMIMEService.h"
|
||||||
|
#include <linux/magic.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "nsNativeCharsetUtils.h"
|
#include "nsNativeCharsetUtils.h"
|
||||||
@ -1103,9 +1104,20 @@ nsLocalFile::SetPermissions(PRUint32 aPermissions)
|
|||||||
* Race condition here: we should use fchmod instead, there's no way to
|
* Race condition here: we should use fchmod instead, there's no way to
|
||||||
* guarantee the name still refers to the same file.
|
* guarantee the name still refers to the same file.
|
||||||
*/
|
*/
|
||||||
if (chmod(mPath.get(), aPermissions) < 0)
|
if (chmod(mPath.get(), aPermissions) >= 0)
|
||||||
return NSRESULT_FOR_ERRNO();
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
#if defined(ANDROID) && defined(STATFS)
|
||||||
|
// For the time being, this is restricted for use by Android, but we
|
||||||
|
// will figure out what to do for all platforms in bug 638503
|
||||||
|
struct STATFS sfs;
|
||||||
|
if (STATFS(mPath.get(), &sfs) < 0)
|
||||||
|
return NSRESULT_FOR_ERRNO();
|
||||||
|
|
||||||
|
// if this is a FAT file system we can't set file permissions
|
||||||
|
if (sfs.f_type == MSDOS_SUPER_MAGIC )
|
||||||
|
return NS_OK;
|
||||||
|
#endif
|
||||||
|
return NSRESULT_FOR_ERRNO();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
Loading…
Reference in New Issue
Block a user