mounts: refactor codes

- update the method of getting disk capacity, through GFileInfo

Change-Id: I0e55f40c8f3ef7daa36ca8b0901dbd3cbb7c6a33
This commit is contained in:
jouyouyun 2015-06-08 13:55:24 +08:00
parent e5403b4a1f
commit f850501146
11 changed files with 633 additions and 715 deletions

175
mounts/disk_info.go Normal file
View File

@ -0,0 +1,175 @@
/**
* Copyright (c) 2011 ~ 2015 Deepin, Inc.
* 2013 ~ 2015 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
**/
package mounts
import (
"fmt"
"os"
"pkg.linuxdeepin.com/lib/gio-2.0"
"regexp"
"strings"
)
const (
diskTypeNative = "native"
diskTypeNetwork = "network"
diskTypeRemovable = "removable"
volumeKindUnix = "unix-device"
volumeKindUUID = "uuid"
fsAttrSize = "filesystem::size"
fsAttrUsed = "filesystem::used"
mtpDiskIcon = "drive-removable-media-mtp"
)
type DiskInfo struct {
Name string
Type string
CanUnmount bool
CanEject bool
Used uint64
Size uint64
Path string
UUID string
MountPoint string
Icon string
}
type DiskInfos []DiskInfo
func newDiskInfoFromMount(mount *gio.Mount) DiskInfo {
var root = mount.GetRoot()
defer root.Unref()
var info = DiskInfo{
Name: mount.GetName(),
MountPoint: root.GetUri(),
CanEject: mount.CanEject(),
CanUnmount: mount.CanUnmount(),
Used: getDiskAttrUint64(root, fsAttrUsed),
Size: getDiskAttrUint64(root, fsAttrSize),
}
volume := mount.GetVolume()
if volume != nil {
info.Path = volume.GetIdentifier(volumeKindUnix)
info.UUID = volume.GetIdentifier(volumeKindUUID)
volume.Unref()
}
if len(info.UUID) == 0 {
info.UUID = generateUUID()
}
iconObj := mount.GetIcon()
defer iconObj.Unref()
info.Icon = getIconFromGIcon(iconObj)
if info.CanEject || strings.Contains(info.Icon, "usb") {
info.Type = diskTypeRemovable
} else if root.IsNative() {
info.Type = diskTypeNative
} else {
info.Type = diskTypeNetwork
}
ok, _ := regexp.MatchString(`^mtp://`, info.MountPoint)
if ok {
info.Type = diskTypeRemovable
info.Icon = mtpDiskIcon
}
return info
}
func newDiskInfoFromVolume(volume *gio.Volume) DiskInfo {
mount := volume.GetMount()
if mount != nil {
defer mount.Unref()
return newDiskInfoFromMount(mount)
}
var info = DiskInfo{
Name: volume.GetName(),
Path: volume.GetIdentifier(volumeKindUnix),
UUID: volume.GetIdentifier(volumeKindUUID),
CanEject: volume.CanEject(),
}
if len(info.UUID) == 0 {
info.UUID = generateUUID()
}
iconObj := volume.GetIcon()
defer iconObj.Unref()
info.Icon = getIconFromGIcon(iconObj)
if info.CanEject || strings.Contains(info.Icon, "usb") {
info.Type = diskTypeRemovable
} else {
info.Type = diskTypeNative
}
ok, _ := regexp.MatchString(`^network`, info.Path)
if ok {
info.Type = diskTypeNetwork
}
return info
}
func getDiskAttrUint64(file *gio.File, attr string) uint64 {
info, err := file.QueryFilesystemInfo(attr, nil)
if err != nil {
return 0
}
defer info.Unref()
return info.GetAttributeUint64(attr) / 1024
}
func getIconFromGIcon(iconObj *gio.Icon) string {
icons := strings.Split(iconObj.ToString(), " ")
if len(icons) > 2 {
return icons[2]
}
return ""
}
func generateUUID() string {
f, err := os.Open("/dev/urandom")
if err != nil {
return ""
}
defer f.Close()
b := make([]byte, 16)
f.Read(b)
uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6],
b[6:8], b[8:10], b[10:])
return uuid
}

View File

@ -1,6 +1,6 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
* Copyright (c) 2011 ~ 2015 Deepin, Inc.
* 2013 ~ 2015 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.com>
@ -22,96 +22,76 @@
package mounts
import (
"fmt"
"os/exec"
"pkg.linuxdeepin.com/lib/gio-2.0"
"pkg.linuxdeepin.com/lib/gobject-2.0"
"strings"
"time"
)
const (
TIME_DURATION = 30
MEDIA_HAND_AUTO_MOUNT = "automount"
MEDIA_HAND_AUTO_OPEN = "automount-open"
gsKeyAutoMount = "automount"
gsKeyAutoOpen = "automount-open"
)
var (
mediaHandSetting = gio.NewSettings("org.gnome.desktop.media-handling")
)
func (m *Manager) refrashDiskInfoList() {
for {
select {
case <-time.NewTimer(time.Second * TIME_DURATION).C:
logger.Debug("Refrash Disk Info List")
m.setPropName("DiskList")
//logger.Infof("Disk List: %v", m.DiskList)
case <-m.quitFlag:
return
func (m *Manager) listenDiskChanged() {
m.monitor.Connect("mount-added", func(monitor *gio.VolumeMonitor, mount *gio.Mount) {
if mount.CanEject() && m.isAutoOpen() {
root := mount.GetRoot()
var cmd = fmt.Sprintf("xdg-open %s", root.GetUri())
root.Unref()
go doAction(cmd)
//err := doAction(cmd)
//if err != nil {
//m.logger.Warningf("Exec '%s' failed: %v",
//cmd, err)
//}
}
m.setPropDiskList(m.getDiskInfos())
})
m.monitor.Connect("mount-removed", func(monitor *gio.VolumeMonitor, mount *gio.Mount) {
m.setPropDiskList(m.getDiskInfos())
})
m.monitor.Connect("volume-added", func(monitor *gio.VolumeMonitor, volume *gio.Volume) {
iconObj := volume.GetIcon()
icon := getIconFromGIcon(iconObj)
iconObj.Unref()
if (volume.CanEject() || strings.Contains(icon, "usb")) &&
m.isAutoMount() {
m.mountVolume("", volume)
}
m.setPropDiskList(m.getDiskInfos())
})
m.monitor.Connect("volume-removed", func(monitor *gio.VolumeMonitor, volume *gio.Volume) {
m.setPropDiskList(m.getDiskInfos())
})
}
func (m *Manager) isAutoMount() bool {
if m.setting == nil {
return false
}
return m.setting.GetBoolean(gsKeyAutoMount)
}
func (m *Manager) endDiskrefrash() {
close(m.quitFlag)
func (m *Manager) isAutoOpen() bool {
if m.setting == nil {
return false
}
return m.setting.GetBoolean(gsKeyAutoOpen)
}
func (m *Manager) listenSignalChanged() {
monitor.Connect("mount-added", func(volumeMonitor *gio.VolumeMonitor, mount *gio.Mount) {
// Judge whether the property 'mount_and_open' set true
// if true, open the device use exec.Command("xdg-open", "device").Run()
logger.Info("EVENT: mount added")
if mount.CanUnmount() &&
mediaHandSetting.GetBoolean(MEDIA_HAND_AUTO_MOUNT) &&
mediaHandSetting.GetBoolean(MEDIA_HAND_AUTO_OPEN) {
uri := mount.GetRoot().GetUri()
go exec.Command("/usr/bin/xdg-open", uri).Run()
}
m.setPropName("DiskList")
})
monitor.Connect("mount-removed", func(volumeMonitor *gio.VolumeMonitor, mount *gio.Mount) {
logger.Info("EVENT: mount removed")
m.setPropName("DiskList")
})
monitor.Connect("mount-changed", func(volumeMonitor *gio.VolumeMonitor, mount *gio.Mount) {
m.setPropName("DiskList")
})
func doAction(cmd string) error {
out, err := exec.Command("/bin/sh", "-c",
cmd).CombinedOutput()
if err != nil {
return fmt.Errorf(string(out))
}
monitor.Connect("volume-added", func(volumeMonitor *gio.VolumeMonitor, volume *gio.Volume) {
icons := volume.GetIcon().ToString()
as := strings.Split(icons, " ")
iconName := ""
if len(as) > 2 {
iconName = as[2]
}
if (volume.CanEject() || strings.Contains(iconName, "usb")) &&
mediaHandSetting.GetBoolean(MEDIA_HAND_AUTO_MOUNT) {
volume.Mount(gio.MountMountFlagsNone, nil, nil, gio.AsyncReadyCallback(func(o *gobject.Object, res *gio.AsyncResult) {
_, err := volume.MountFinish(res)
if err != nil {
logger.Warningf("volume mount failed: %s", err)
m.setPropName("DiskList")
}
}))
} else {
m.setPropName("DiskList")
}
})
monitor.Connect("volume-removed", func(volumeMonitor *gio.VolumeMonitor, volume *gio.Volume) {
m.setPropName("DiskList")
})
monitor.Connect("volume-changed", func(volumeMonitor *gio.VolumeMonitor, volume *gio.Volume) {
m.setPropName("DiskList")
})
monitor.Connect("drive-disconnected", func(volumeMonitor *gio.VolumeMonitor, drive *gio.Drive) {
m.setPropName("DiskList")
})
monitor.Connect("drive-connected", func(volumeMonitor *gio.VolumeMonitor, drive *gio.Drive) {
m.setPropName("DiskList")
})
monitor.Connect("drive-changed", func(volumeMonitor *gio.VolumeMonitor, drive *gio.Drive) {
m.setPropName("DiskList")
})
return nil
}

View File

@ -1,134 +0,0 @@
/**
* Copyright (c) 2011 ~ 2014 Deepin, Inc.
* 2013 ~ 2014 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
**/
package mounts
import (
"fmt"
"pkg.linuxdeepin.com/lib/dbus"
"pkg.linuxdeepin.com/lib/gio-2.0"
"pkg.linuxdeepin.com/lib/gobject-2.0"
)
func (m *Manager) DeviceEject(uuid string) (bool, string) {
info, ok := objectMap[uuid]
if !ok {
logger.Warning("Eject id - %s not in objectMap.", uuid)
return false, fmt.Sprintf("Invalid Id: %s\n", uuid)
}
logger.Infof("Eject type: %s", info.Type)
switch info.Type {
case "drive":
op := info.Object.(*gio.Drive)
op.Eject(gio.MountUnmountFlagsNone, nil, gio.AsyncReadyCallback(func(o *gobject.Object, res *gio.AsyncResult) {
_, err := op.EjectFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
logger.Warningf("drive eject failed: %s, %s", uuid, err)
}
}))
case "volume":
op := info.Object.(*gio.Volume)
op.Eject(gio.MountUnmountFlagsNone, nil, gio.AsyncReadyCallback(func(o *gobject.Object, res *gio.AsyncResult) {
_, err := op.EjectFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
logger.Warningf("volume eject failed: %s, %s", uuid, err)
}
}))
case "mount":
op := info.Object.(*gio.Mount)
op.Eject(gio.MountUnmountFlagsNone, nil, gio.AsyncReadyCallback(func(o *gobject.Object, res *gio.AsyncResult) {
_, err := op.EjectFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
logger.Warningf("mount eject failed: %s, %s", uuid, err)
}
}))
default:
logger.Errorf("'%s' invalid type", info.Type)
return false, fmt.Sprintf("Invalid type: '%s'\n", info.Type)
}
return true, ""
}
func (m *Manager) DeviceMount(uuid string) (bool, string) {
info, ok := objectMap[uuid]
if !ok {
logger.Warning("Mount id - %s not in objectMap.", uuid)
return false, fmt.Sprintf("Invalid Id: %s\n", uuid)
}
logger.Infof("Mount type: %s", info.Type)
switch info.Type {
case "volume":
op := info.Object.(*gio.Volume)
op.Mount(gio.MountMountFlagsNone, nil, nil, gio.AsyncReadyCallback(func(o *gobject.Object, res *gio.AsyncResult) {
_, err := op.MountFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
logger.Warningf("volume mount failed: %s, %s", uuid, err)
}
}))
case "mount":
op := info.Object.(*gio.Mount)
op.Remount(gio.MountMountFlagsNone, nil, nil, gio.AsyncReadyCallback(func(o *gobject.Object, res *gio.AsyncResult) {
_, err := op.RemountFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
logger.Warningf("mount remount failed: %s, %s", uuid, err)
}
}))
default:
logger.Errorf("'%s' invalid type", info.Type)
return false, fmt.Sprintf("Invalid type: '%s'\n", info.Type)
}
return true, ""
}
func (m *Manager) DeviceUnmount(uuid string) (bool, string) {
info, ok := objectMap[uuid]
if !ok {
logger.Warningf("Unmount id - %s not in objectMap.", uuid)
return false, fmt.Sprintf("Invalid Id: %s\n", uuid)
}
logger.Infof("Unmount type: %s", info.Type)
switch info.Type {
case "mount":
op := info.Object.(*gio.Mount)
op.Unmount(gio.MountUnmountFlagsNone, nil, gio.AsyncReadyCallback(func(o *gobject.Object, res *gio.AsyncResult) {
_, err := op.UnmountFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
logger.Warningf("mount unmount failed: %s, %s", uuid, err)
}
}))
default:
logger.Errorf("'%s' invalid type", info.Type)
return false, fmt.Sprintf("Invalid type: '%s'\n", info.Type)
}
return true, ""
}

View File

@ -1,12 +0,0 @@
package mounts
import "pkg.linuxdeepin.com/dde-daemon"
func init() {
loader.Register(&loader.Module{
Name: "mounts",
Start: Start,
Stop: Stop,
Enable: true,
})
}

195
mounts/manager.go Normal file
View File

@ -0,0 +1,195 @@
/**
* Copyright (c) 2011 ~ 2015 Deepin, Inc.
* 2013 ~ 2015 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
**/
package mounts
import (
"pkg.linuxdeepin.com/lib/gio-2.0"
"pkg.linuxdeepin.com/lib/log"
dutils "pkg.linuxdeepin.com/lib/utils"
"sync"
"time"
)
const (
mediaHandlerSchema = "org.gnome.desktop.media-handling"
diskTypeVolume int = iota + 1
diskTypeMount
refrashTimeout = 90
)
type diskObjectInfo struct {
Type int
Obj interface{}
}
type Manager struct {
DiskList DiskInfos
//Error(uuid, reason)
Error func(string, string)
monitor *gio.VolumeMonitor
setting *gio.Settings
logger *log.Logger
endFlag chan struct{}
cacheLocker sync.Mutex
diskCache map[string]*diskObjectInfo
}
func NewManager() *Manager {
var m = Manager{}
m.logger = log.NewLogger(dbusSender)
m.monitor = gio.VolumeMonitorGet()
m.setting, _ = dutils.CheckAndNewGSettings(mediaHandlerSchema)
m.diskCache = make(map[string]*diskObjectInfo)
m.endFlag = make(chan struct{})
m.DiskList = m.getDiskInfos()
return &m
}
func (m *Manager) destroy() {
if m.diskCache != nil {
m.clearDiskCache()
m.diskCache = nil
}
if m.monitor != nil {
m.monitor.Unref()
m.monitor = nil
}
if m.logger != nil {
m.logger.EndTracing()
m.logger = nil
}
if m.endFlag != nil {
close(m.endFlag)
m.endFlag = nil
}
}
func (m *Manager) refrashDiskInfos() {
for {
select {
case <-time.NewTicker(time.Second * refrashTimeout).C:
m.setPropDiskList(m.getDiskInfos())
case <-m.endFlag:
return
}
}
}
func (m *Manager) getDiskInfos() DiskInfos {
m.clearDiskCache()
m.diskCache = make(map[string]*diskObjectInfo)
var infos DiskInfos
volumes := m.monitor.GetVolumes()
for _, volume := range volumes {
mount := volume.GetMount()
if mount != nil {
mount.Unref()
continue
}
info := newDiskInfoFromVolume(volume)
m.setDiskCache(info.UUID, &diskObjectInfo{
Type: diskTypeVolume,
Obj: volume,
})
infos = append(infos, info)
}
mounts := m.monitor.GetMounts()
for _, mount := range mounts {
info := newDiskInfoFromMount(mount)
m.setDiskCache(info.UUID, &diskObjectInfo{
Type: diskTypeMount,
Obj: mount,
})
infos = append(infos, info)
}
return infos
}
func (m *Manager) setDiskCache(key string, value *diskObjectInfo) {
m.cacheLocker.Lock()
defer m.cacheLocker.Unlock()
_, ok := m.diskCache[key]
if ok {
m.deleteDiskCache(key)
}
m.diskCache[key] = value
}
func (m *Manager) getDiskCache(key string) *diskObjectInfo {
m.cacheLocker.Lock()
defer m.cacheLocker.Unlock()
v, ok := m.diskCache[key]
if !ok {
return nil
}
return v
}
func (m *Manager) deleteDiskCache(key string) {
m.cacheLocker.Lock()
defer m.cacheLocker.Unlock()
v, ok := m.diskCache[key]
if !ok {
return
}
switch v.Type {
case diskTypeVolume:
volume := v.Obj.(*gio.Volume)
volume.Unref()
case diskTypeMount:
mount := v.Obj.(*gio.Mount)
mount.Unref()
}
delete(m.diskCache, key)
}
func (m *Manager) clearDiskCache() {
m.cacheLocker.Lock()
defer m.cacheLocker.Unlock()
for _, v := range m.diskCache {
switch v.Type {
case diskTypeVolume:
volume := v.Obj.(*gio.Volume)
volume.Unref()
case diskTypeMount:
mount := v.Obj.(*gio.Mount)
mount.Unref()
}
}
}

156
mounts/manager_ifc.go Normal file
View File

@ -0,0 +1,156 @@
/**
* Copyright (c) 2011 ~ 2015 Deepin, Inc.
* 2013 ~ 2015 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
**/
package mounts
import (
"fmt"
"pkg.linuxdeepin.com/lib/dbus"
"pkg.linuxdeepin.com/lib/gio-2.0"
"pkg.linuxdeepin.com/lib/gobject-2.0"
)
func (m *Manager) DeviceEject(uuid string) (bool, error) {
value := m.getDiskCache(uuid)
if value == nil {
var reason = fmt.Sprintf("Eject failed: invalid id '%s'", uuid)
dbus.Emit(m, "Error", uuid, reason)
return false, fmt.Errorf(reason)
}
switch value.Type {
case diskTypeVolume:
volume := value.Obj.(*gio.Volume)
m.ejectVolume(uuid, volume)
case diskTypeMount:
mount := value.Obj.(*gio.Mount)
m.ejectMount(uuid, mount)
}
return true, nil
}
func (m *Manager) DeviceMount(uuid string) (bool, error) {
value := m.getDiskCache(uuid)
if value == nil {
var reason = fmt.Sprintf("Mount failed: invalid id '%s'", uuid)
dbus.Emit(m, "Error", uuid, reason)
return false, fmt.Errorf(reason)
}
switch value.Type {
case diskTypeVolume:
volume := value.Obj.(*gio.Volume)
m.mountVolume(uuid, volume)
case diskTypeMount:
mount := value.Obj.(*gio.Mount)
m.remountMount(uuid, mount)
}
return true, nil
}
func (m *Manager) DeviceUnmount(uuid string) (bool, error) {
value := m.getDiskCache(uuid)
if value == nil {
var reason = fmt.Sprintf("Unmount failed: invalid id '%s'", uuid)
dbus.Emit(m, "Error", uuid, reason)
return false, fmt.Errorf(reason)
}
switch value.Type {
case diskTypeMount:
mount := value.Obj.(*gio.Mount)
m.unmountMount(uuid, mount)
}
return true, nil
}
func (m *Manager) ejectVolume(uuid string, volume *gio.Volume) {
volume.Eject(gio.MountUnmountFlagsNone, nil,
gio.AsyncReadyCallback(
func(o *gobject.Object, res *gio.AsyncResult) {
if volume == nil || volume.Object.C == nil {
return
}
_, err := volume.EjectFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
}
}))
}
func (m *Manager) ejectMount(uuid string, mount *gio.Mount) {
mount.Eject(gio.MountUnmountFlagsNone, nil,
gio.AsyncReadyCallback(
func(o *gobject.Object, res *gio.AsyncResult) {
if mount == nil || mount.Object.C == nil {
return
}
_, err := mount.EjectFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
}
}))
}
func (m *Manager) mountVolume(uuid string, volume *gio.Volume) {
volume.Mount(gio.MountMountFlagsNone, nil, nil,
gio.AsyncReadyCallback(
func(o *gobject.Object, res *gio.AsyncResult) {
if volume == nil || volume.Object.C == nil {
return
}
_, err := volume.MountFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
}
}))
}
func (m *Manager) remountMount(uuid string, mount *gio.Mount) {
mount.Remount(gio.MountMountFlagsNone, nil, nil,
gio.AsyncReadyCallback(
func(o *gobject.Object, res *gio.AsyncResult) {
if mount == nil || mount.Object.C == nil {
return
}
_, err := mount.RemountFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
}
}))
}
func (m *Manager) unmountMount(uuid string, mount *gio.Mount) {
mount.Unmount(gio.MountUnmountFlagsNone, nil,
gio.AsyncReadyCallback(
func(o *gobject.Object, res *gio.AsyncResult) {
if mount == nil || mount.Object.C == nil {
return
}
_, err := mount.UnmountFinish(res)
if err != nil {
dbus.Emit(m, "Error", uuid, err.Error())
}
}))
}

View File

@ -1,6 +1,6 @@
/**
* Copyright (c) 2011 ~ 2013 Deepin, Inc.
* 2011 ~ 2013 jouyouyun
* Copyright (c) 2011 ~ 2015 Deepin, Inc.
* 2013 ~ 2015 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.com>
@ -26,25 +26,20 @@ import (
)
const (
DISK_INFO_DEST = "com.deepin.daemon.DiskMount"
DISK_INFO_PATH = "/com/deepin/daemon/DiskMount"
DISK_INFO_IFC = "com.deepin.daemon.DiskMount"
dbusSender = "com.deepin.daemon.DiskMount"
dbusPath = "/com/deepin/daemon/DiskMount"
dbusIFC = "com.deepin.daemon.DiskMount"
)
func (m *Manager) GetDBusInfo() dbus.DBusInfo {
return dbus.DBusInfo{
Dest: DISK_INFO_DEST,
ObjectPath: DISK_INFO_PATH,
Interface: DISK_INFO_IFC,
Dest: dbusSender,
ObjectPath: dbusPath,
Interface: dbusIFC,
}
}
func (m *Manager) setPropName(name string) {
switch name {
case "DiskList":
m.DiskList = getDiskInfoList()
dbus.NotifyChange(m, name)
default:
logger.Warningf("'%s': invalid mount property")
}
func (m *Manager) setPropDiskList(infos DiskInfos) {
m.DiskList = infos
dbus.NotifyChange(m, "DiskList")
}

View File

@ -1,89 +0,0 @@
/**
* Copyright (c) 2011 ~ 2013 Deepin, Inc.
* 2011 ~ 2013 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
**/
package mounts
import (
"os/exec"
"strconv"
"strings"
"time"
)
const (
CMD_DF = "/bin/df"
)
func getDiskCap(path string) (int64, int64) {
contents := []byte{}
for i := 0; i < 10; i++ {
bytes, err := exec.Command(CMD_DF).Output()
if err != nil || len(string(bytes)) < 1 {
if i == 9 {
logger.Warning("Exec 'df -h' failed:", err)
return 0, 0
}
<-time.After(time.Second * 1)
} else {
contents = bytes
break
}
}
usedSize := int64(0)
totalSize := int64(0)
outStrs := strings.Split(string(contents), "\n")
for _, str := range outStrs {
array := strings.Split(str, " ")
rets := delSpaceElment(array)
l := len(rets)
if l <= 2 {
break
}
isMatch := false
for _, v := range rets {
if path == v {
isMatch = true
usedSize, _ = strconv.ParseInt(rets[2], 10, 64)
totalSize, _ = strconv.ParseInt(rets[1], 10, 64)
break
}
}
if isMatch {
break
}
}
return totalSize, usedSize
}
func delSpaceElment(strs []string) []string {
rets := []string{}
for _, v := range strs {
if len(v) > 0 {
rets = append(rets, v)
}
}
return rets
}

View File

@ -1,349 +0,0 @@
/**
* Copyright (c) 2011 ~ 2013 Deepin, Inc.
* 2011 ~ 2013 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
**/
package mounts
import (
"pkg.linuxdeepin.com/lib/dbus"
"pkg.linuxdeepin.com/lib/gio-2.0"
"pkg.linuxdeepin.com/lib/log"
"regexp"
"strings"
)
type DiskInfo struct {
Name string
Type string
CanUnmount bool
CanEject bool
UsableCap int64
TotalCap int64
Path string
UUID string
MountURI string
IconName string
}
type ObjectInfo struct {
Object interface{}
Type string
}
type Manager struct {
DiskList []DiskInfo
Error func(string, string)
quitFlag chan struct{}
}
const (
DEVICE_KIND = "unix-device"
)
var (
monitor = gio.VolumeMonitorGet()
objectMap = make(map[string]*ObjectInfo)
logger = log.NewLogger(DISK_INFO_DEST)
)
func newDiskInfo(value interface{}, t string) DiskInfo {
defer func() {
if err := recover(); err != nil {
logger.Error("Received Error: ", err)
}
}()
info := DiskInfo{}
switch t {
case "volume":
v := value.(*gio.Volume)
info.Name = v.GetName()
info.CanEject = v.CanEject()
id := v.GetIdentifier(DEVICE_KIND)
//info.TotalCap, info.UsableCap = getDiskCap(id)
info.Path = v.GetIdentifier(gio.VolumeIdentifierKindUnixDevice)
info.UUID = v.GetIdentifier(gio.VolumeIdentifierKindUuid)
logger.Debugf("VOLUME Name: %s, UUID: %v", info.Name, info.UUID)
if len(info.UUID) < 1 {
info.UUID = generateUUID()
logger.Debugf("VOLUME Name: %s, Generate UUID: %v", info.Name, info.UUID)
}
if mount := v.GetMount(); mount != nil {
info.CanUnmount = mount.CanUnmount()
}
icons := v.GetIcon().ToString()
as := strings.Split(icons, " ")
if len(as) > 2 {
info.IconName = as[2]
}
if containStart("network", id) {
info.Type = "network"
} else if info.CanEject ||
strings.Contains(info.IconName, "usb") {
info.Type = "removable"
} else {
info.Type = "native"
}
case "drive":
v := value.(*gio.Drive)
info.Name = v.GetName()
info.CanEject = v.CanEject()
id := v.GetIdentifier(DEVICE_KIND)
//info.TotalCap, info.UsableCap = getDiskCap(id)
info.Path = v.GetIdentifier(gio.VolumeIdentifierKindUnixDevice)
info.UUID = v.GetIdentifier(gio.VolumeIdentifierKindUuid)
logger.Infof("DRIVE Name: %s, UUID: %v", info.Name, info.UUID)
if len(info.UUID) < 1 {
info.UUID = generateUUID()
logger.Infof("DRIVE Name: %s, Generate UUID: %v", info.Name, info.UUID)
}
icons := v.GetIcon().ToString()
as := strings.Split(icons, " ")
if len(as) > 2 {
info.IconName = as[2]
}
if containStart("network", id) {
info.Type = "network"
} else if info.CanEject ||
strings.Contains(info.IconName, "usb") {
info.Type = "removable"
} else {
info.Type = "native"
}
case "mount":
v := value.(*gio.Mount)
info.Name = v.GetName()
info.CanEject = v.CanEject()
info.CanUnmount = v.CanUnmount()
root := v.GetRoot()
info.MountURI = root.GetUri()
info.TotalCap, info.UsableCap = getDiskCap(root.GetPath())
icons := v.GetIcon().ToString()
as := strings.Split(icons, " ")
if len(as) > 2 {
info.IconName = as[2]
}
if info.CanEject ||
strings.Contains(info.IconName, "usb") {
info.Type = "removable"
} else if root.IsNative() {
info.Type = "native"
} else {
info.Type = "network"
}
if volume := v.GetVolume(); volume != nil {
info.Path = volume.GetIdentifier(gio.VolumeIdentifierKindUnixDevice)
info.UUID = volume.GetIdentifier(gio.VolumeIdentifierKindUuid)
}
logger.Infof("MOUNT Name: %s, UUID: %v", info.Name, info.UUID)
if len(info.UUID) < 1 {
info.UUID = generateUUID()
logger.Infof("MOUNT Name: %s, Generate UUID: %v", info.Name, info.UUID)
}
if ok, _ := regexp.MatchString(`^mtp://`, info.MountURI); ok {
info.Type = "removable"
info.IconName = "drive-removable-media-mtp"
}
if info.TotalCap == 0 {
info.TotalCap, info.UsableCap = getDiskCap(info.Path)
}
default:
logger.Errorf("'%s' invalid type", t)
}
return info
}
func newObjectInfo(v interface{}, t string) *ObjectInfo {
return &ObjectInfo{Object: v, Type: t}
}
func driverList() []DiskInfo {
list := []DiskInfo{}
drivers := monitor.GetConnectedDrives()
for _, driver := range drivers {
volumes := driver.GetVolumes()
if volumes == nil {
if driver.IsMediaRemovable() &&
!driver.IsMediaCheckAutomatic() {
info := newDiskInfo(driver, "drive")
objectMap[info.UUID] = newObjectInfo(driver, "drive")
list = append(list, info)
}
continue
}
for _, volume := range volumes {
mount := volume.GetMount()
if mount != nil {
info := newDiskInfo(mount, "mount")
objectMap[info.UUID] = newObjectInfo(mount, "mount")
list = append(list, info)
} else {
info := newDiskInfo(volume, "volume")
objectMap[info.UUID] = newObjectInfo(volume, "volume")
list = append(list, info)
}
}
}
return list
}
func volumeList() []DiskInfo {
list := []DiskInfo{}
volumes := monitor.GetVolumes()
for _, volume := range volumes {
driver := volume.GetDrive()
if driver != nil {
continue
}
//id := volume.GetIdentifier("unix-device")
mount := volume.GetMount()
if mount != nil {
info := newDiskInfo(mount, "mount")
objectMap[info.UUID] = newObjectInfo(mount, "mount")
list = append(list, info)
} else {
info := newDiskInfo(volume, "volume")
objectMap[info.UUID] = newObjectInfo(volume, "volume")
list = append(list, info)
}
}
return list
}
func mountList() []DiskInfo {
list := []DiskInfo{}
mounts := monitor.GetMounts()
for _, mount := range mounts {
if mount.IsShadowed() {
continue
}
volume := mount.GetVolume()
if volume != nil {
continue
}
info := newDiskInfo(mount, "mount")
objectMap[info.UUID] = newObjectInfo(mount, "mount")
list = append(list, info)
}
return list
}
func containStart(str1, str2 string) bool {
for i, _ := range str1 {
if str1[i] != str2[i] {
return false
}
}
return true
}
func getDiskInfoList() []DiskInfo {
list := []DiskInfo{}
destroyObjectMap()
l1 := driverList()
l2 := volumeList()
l3 := mountList()
list = append(list, l1...)
list = append(list, l2...)
list = append(list, l3...)
return list
}
func destroyObjectMap() {
for _, info := range objectMap {
switch info.Type {
case "drive":
op := info.Object.(*gio.Drive)
op.Unref()
case "volume":
op := info.Object.(*gio.Volume)
op.Unref()
case "mount":
op := info.Object.(*gio.Mount)
op.Unref()
}
}
objectMap = make(map[string]*ObjectInfo)
}
func (m *Manager) destroy() {
m.endDiskrefrash()
dbus.UnInstallObject(m)
}
func NewManager() *Manager {
m := &Manager{}
m.setPropName("DiskList")
m.listenSignalChanged()
m.quitFlag = make(chan struct{})
go m.refrashDiskInfoList()
return m
}
var _manager *Manager
func finalize() {
_manager.destroy()
_manager = nil
logger.EndTracing()
}
func Start() {
if _manager != nil {
return
}
logger.BeginTracing()
_manager = NewManager()
err := dbus.InstallOnSession(_manager)
if err != nil {
logger.Error("Install DBus Session Failed:", err)
finalize()
return
}
}
func Stop() {
if _manager == nil {
return
}
finalize()
}

View File

@ -1,6 +1,6 @@
/**
* Copyright (c) 2011 ~ 2013 Deepin, Inc.
* 2011 ~ 2013 jouyouyun
* Copyright (c) 2011 ~ 2015 Deepin, Inc.
* 2013 ~ 2015 jouyouyun
*
* Author: jouyouyun <jouyouwen717@gmail.com>
* Maintainer: jouyouyun <jouyouwen717@gmail.com>
@ -22,23 +22,46 @@
package mounts
import (
C "launchpad.net/gocheck"
"testing"
"pkg.linuxdeepin.com/dde-daemon"
"pkg.linuxdeepin.com/lib/dbus"
)
type TestWrapper struct{}
func Test(t *testing.T) {
C.TestingT(t)
}
var (
_manager *Manager
)
func init() {
C.Suite(&TestWrapper{})
loader.Register(&loader.Module{
Name: "mounts",
Start: Start,
Stop: Stop,
Enable: true,
})
}
func (t *TestWrapper) TestUUidGenerate(c *C.C) {
uuid := generateUUID()
if uuid == "" {
c.Errorf("Generate UUID Failed")
func Start() {
if _manager != nil {
return
}
_manager = NewManager()
_manager.logger.BeginTracing()
err := dbus.InstallOnSession(_manager)
if err != nil {
_manager.logger.Error("Install mounts dbus failed:", err)
_manager.destroy()
_manager = nil
return
}
_manager.listenDiskChanged()
go _manager.refrashDiskInfos()
}
func Stop() {
if _manager == nil {
return
}
_manager.destroy()
_manager = nil
}

View File

@ -1,22 +0,0 @@
package mounts
import (
"fmt"
"os"
)
func generateUUID() string {
f, err := os.Open("/dev/urandom")
if err != nil {
fmt.Println(err)
return ""
}
defer f.Close()
b := make([]byte, 16)
f.Read(b)
uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6],
b[6:8], b[8:10], b[10:])
return uuid
}