2012-07-16 16:38:18 +00:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "nsVolumeService.h"
|
|
|
|
|
|
|
|
#include "Volume.h"
|
|
|
|
#include "VolumeManager.h"
|
|
|
|
#include "VolumeServiceIOThread.h"
|
|
|
|
|
|
|
|
#include "nsAutoPtr.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsDependentSubstring.h"
|
|
|
|
#include "nsIObserver.h"
|
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#include "nsISupportsUtils.h"
|
|
|
|
#include "nsIVolume.h"
|
|
|
|
#include "nsIVolumeService.h"
|
|
|
|
#include "nsLocalFile.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
#include "nsTArray.h"
|
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
#include "nsXULAppAPI.h"
|
|
|
|
#include "mozilla/Services.h"
|
|
|
|
|
|
|
|
#define VOLUME_MANAGER_LOG_TAG "nsVolumeService"
|
|
|
|
#include "VolumeManagerLog.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
using namespace mozilla::services;
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace system {
|
|
|
|
|
2013-01-08 06:59:32 +00:00
|
|
|
NS_IMPL_ISUPPORTS1(nsVolumeService, nsIVolumeService)
|
2012-07-16 16:38:18 +00:00
|
|
|
|
|
|
|
nsVolumeService::nsVolumeService()
|
|
|
|
{
|
|
|
|
// Startup the IOThread side of things. The actual volume changes
|
|
|
|
// are captured by the IOThread and forwarded to main thread.
|
|
|
|
XRE_GetIOMessageLoop()->PostTask(
|
|
|
|
FROM_HERE,
|
2013-01-08 06:59:32 +00:00
|
|
|
NewRunnableFunction(InitVolumeServiceIOThread));
|
2012-07-16 16:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsVolumeService::~nsVolumeService()
|
|
|
|
{
|
2013-01-08 06:59:32 +00:00
|
|
|
XRE_GetIOMessageLoop()->PostTask(
|
|
|
|
FROM_HERE,
|
|
|
|
NewRunnableFunction(ShutdownVolumeServiceIOThread));
|
2012-07-16 16:38:18 +00:00
|
|
|
}
|
|
|
|
|
2013-01-08 06:59:32 +00:00
|
|
|
/* nsIVolume getVolumeByName (in DOMString volName); */
|
|
|
|
NS_IMETHODIMP nsVolumeService::GetVolumeByName(const nsAString &aVolName, nsIVolume **aResult)
|
2012-07-16 16:38:18 +00:00
|
|
|
{
|
2012-08-06 21:32:29 +00:00
|
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
2012-07-16 16:38:18 +00:00
|
|
|
nsRefPtr<nsVolume> vol = FindVolumeByName(aVolName);
|
|
|
|
if (!vol) {
|
2012-08-06 21:32:29 +00:00
|
|
|
ERR("GetVolumeByName: Unable to locate volume '%s'",
|
|
|
|
NS_LossyConvertUTF16toASCII(aVolName).get());
|
2012-07-16 16:38:18 +00:00
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(*aResult = vol);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-01-08 06:59:32 +00:00
|
|
|
/* nsIVolume getVolumeByPath (in DOMString path); */
|
|
|
|
NS_IMETHODIMP nsVolumeService::GetVolumeByPath(const nsAString &aPath, nsIVolume **aResult)
|
2012-07-16 16:38:18 +00:00
|
|
|
{
|
2012-08-06 21:32:29 +00:00
|
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
2012-07-16 16:38:18 +00:00
|
|
|
nsCString utf8Path = NS_ConvertUTF16toUTF8(aPath);
|
|
|
|
char realPathBuf[PATH_MAX];
|
|
|
|
|
|
|
|
if (!realpath(utf8Path.get(), realPathBuf)) {
|
2012-08-06 21:32:29 +00:00
|
|
|
ERR("GetVolumeByPath: realpath on '%s' failed: %d", utf8Path.get(), errno);
|
2012-07-16 16:38:18 +00:00
|
|
|
return NSRESULT_FOR_ERRNO();
|
|
|
|
}
|
|
|
|
|
|
|
|
// The volume mount point is always a directory. Something like /mnt/sdcard
|
|
|
|
// Once we have a full qualified pathname with symlinks removed (which is
|
|
|
|
// what realpath does), we basically check if aPath starts with the mount
|
|
|
|
// point, but we don't want to have /mnt/sdcard match /mnt/sdcardfoo but we
|
|
|
|
// do want it to match /mnt/sdcard/foo
|
|
|
|
// So we add a trailing slash to the mount point and the pathname passed in
|
|
|
|
// prior to doing the comparison.
|
|
|
|
|
|
|
|
strlcat(realPathBuf, "/", sizeof(realPathBuf));
|
|
|
|
|
|
|
|
nsVolume::Array::size_type numVolumes = mVolumeArray.Length();
|
|
|
|
nsVolume::Array::index_type volIndex;
|
|
|
|
for (volIndex = 0; volIndex < numVolumes; volIndex++) {
|
|
|
|
nsRefPtr<nsVolume> vol = mVolumeArray[volIndex];
|
2012-09-02 02:35:17 +00:00
|
|
|
nsAutoCString volMountPointSlash = NS_ConvertUTF16toUTF8(vol->MountPoint());
|
2012-07-16 16:38:18 +00:00
|
|
|
volMountPointSlash.Append(NS_LITERAL_CSTRING("/"));
|
|
|
|
nsDependentCSubstring testStr(realPathBuf, volMountPointSlash.Length());
|
|
|
|
if (volMountPointSlash.Equals(testStr)) {
|
|
|
|
NS_ADDREF(*aResult = vol);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
2012-12-06 17:31:57 +00:00
|
|
|
|
|
|
|
// In order to support queries by DeviceStorage and the updater, we will fabricate
|
|
|
|
// a volume from the pathname, so that the caller can determine the volume size
|
|
|
|
nsRefPtr<nsVolume> vol = new nsVolume(NS_LITERAL_STRING("fake"),
|
2013-01-08 06:59:32 +00:00
|
|
|
aPath, nsIVolume::STATE_MOUNTED);
|
2012-12-06 17:31:57 +00:00
|
|
|
NS_ADDREF(*aResult = vol);
|
|
|
|
return NS_OK;
|
2012-07-16 16:38:18 +00:00
|
|
|
}
|
|
|
|
|
2013-01-08 06:59:32 +00:00
|
|
|
already_AddRefed<nsVolume> nsVolumeService::FindVolumeByName(const nsAString &aName)
|
2012-07-16 16:38:18 +00:00
|
|
|
{
|
2012-08-06 21:32:29 +00:00
|
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
2012-07-16 16:38:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
nsVolume::Array::size_type numVolumes = mVolumeArray.Length();
|
|
|
|
nsVolume::Array::index_type volIndex;
|
|
|
|
for (volIndex = 0; volIndex < numVolumes; volIndex++) {
|
|
|
|
nsRefPtr<nsVolume> vol = mVolumeArray[volIndex];
|
|
|
|
if (vol->Name().Equals(aName)) {
|
|
|
|
return vol.forget();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-01-08 06:59:32 +00:00
|
|
|
already_AddRefed<nsVolume> nsVolumeService::FindAddVolumeByName(const nsAString &aName)
|
2012-07-16 16:38:18 +00:00
|
|
|
{
|
2012-08-06 21:32:29 +00:00
|
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
2012-07-16 16:38:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
nsRefPtr<nsVolume> vol;
|
|
|
|
vol = FindVolumeByName(aName);
|
|
|
|
if (vol) {
|
|
|
|
return vol.forget();
|
|
|
|
}
|
|
|
|
// Volume not found - add a new one
|
|
|
|
vol = new nsVolume(aName);
|
|
|
|
mVolumeArray.AppendElement(vol);
|
|
|
|
return vol.forget();
|
|
|
|
}
|
|
|
|
|
2013-01-08 06:59:32 +00:00
|
|
|
void nsVolumeService::UpdateVolume(const nsVolume *aVolume)
|
2012-07-16 16:38:18 +00:00
|
|
|
{
|
2012-08-06 21:32:29 +00:00
|
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
2012-07-16 16:38:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
nsRefPtr<nsVolume> vol = FindAddVolumeByName(aVolume->Name());
|
|
|
|
if (vol->Equals(aVolume)) {
|
|
|
|
// Nothing has really changed. Don't bother telling anybody.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
vol->Set(aVolume);
|
2012-08-03 00:28:59 +00:00
|
|
|
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
2012-07-16 16:38:18 +00:00
|
|
|
if (!obs) {
|
|
|
|
return;
|
|
|
|
}
|
2013-01-08 06:59:32 +00:00
|
|
|
if (aVolume->State() == nsIVolume::STATE_MOUNTED) {
|
|
|
|
LOG("UpdateVolume: '%s' state %s @ '%s'",
|
|
|
|
aVolume->NameStr(), aVolume->StateStr(), aVolume->MountPointStr());
|
|
|
|
} else {
|
|
|
|
LOG("UpdateVolume: '%s' state %s",
|
|
|
|
aVolume->NameStr(), aVolume->StateStr());
|
|
|
|
}
|
2012-07-16 16:38:18 +00:00
|
|
|
nsString stateStr(NS_ConvertUTF8toUTF16(vol->StateStr()));
|
|
|
|
obs->NotifyObservers(vol, NS_VOLUME_STATE_CHANGED, stateStr.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* The UpdateVolumeRunnable creates an nsVolume and updates the main thread
|
|
|
|
* data structure while running on the main thread.
|
|
|
|
*/
|
|
|
|
class UpdateVolumeRunnable : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
2013-01-08 06:59:32 +00:00
|
|
|
UpdateVolumeRunnable(const Volume *aVolume)
|
|
|
|
: mVolume(new nsVolume(aVolume))
|
2012-07-16 16:38:18 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-01-08 06:59:32 +00:00
|
|
|
DBG("UpdateVolumeRunnable::Run '%s' state %s",
|
|
|
|
mVolume->NameStr(), mVolume->StateStr());
|
2012-07-16 16:38:18 +00:00
|
|
|
|
2013-01-08 06:59:32 +00:00
|
|
|
nsCOMPtr<nsIVolumeService> ivs = do_GetService(NS_VOLUMESERVICE_CONTRACTID);
|
|
|
|
if (!ivs) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsVolumeService> vs(do_QueryInterface(ivs));
|
|
|
|
if (!vs) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
vs->UpdateVolume(mVolume);
|
2012-07-16 16:38:18 +00:00
|
|
|
mVolume = NULL;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2013-01-08 06:59:32 +00:00
|
|
|
nsRefPtr<nsVolume> mVolume;
|
2012-07-16 16:38:18 +00:00
|
|
|
};
|
|
|
|
|
2013-01-08 06:59:32 +00:00
|
|
|
//static
|
|
|
|
void nsVolumeService::UpdateVolumeIOThread(const Volume *aVolume)
|
2012-07-16 16:38:18 +00:00
|
|
|
{
|
2013-01-08 06:59:32 +00:00
|
|
|
DBG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s'",
|
|
|
|
aVolume->NameStr(), aVolume->StateStr(), aVolume->MountPoint().get());
|
2012-07-16 16:38:18 +00:00
|
|
|
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
|
2013-01-08 06:59:32 +00:00
|
|
|
NS_DispatchToMainThread(new UpdateVolumeRunnable(aVolume));
|
2012-07-16 16:38:18 +00:00
|
|
|
}
|
|
|
|
|
2013-01-08 06:59:32 +00:00
|
|
|
} // system
|
|
|
|
} // mozilla
|