how to identify a mounted external volume? - applescript

I have the following to identify if a volume is mounted:
on volumeMounted:aNotification
set volumeName to (NSWorkspaceVolumeLocalizedNameKey of aNotification's userInfo) as text
if volumeName is "myVolume" then
--do something
end if
end volumeMounted:
on volumeUnmounted:aNotification
set volumeName to (NSWorkspaceVolumeLocalizedNameKey of aNotification's userInfo) as text
if volumeName is "myVolume" then
--do something
end if
end volumeUnmounted:
I wanted a way to identify if an external volume is mounted even though it has the same name.
For example:
my internal volume is named "Macintosh HD" and I connect an external volume with the same name
it is only recognizing 1 volume, so I can't unmount both volumes with a Button created in the Interface.
Note: I know I could just right click and ask to eject but I wanted to do that in the UI.

There is another key NSWorkspaceVolumeURLKey in the userInfo dictionary of the volumeMounted notification .
The associated value is the URL of the mount point. You can cast the URL to alias. The default folder for mounted volumes is /Volumes, the path of the startup volume is always /.

Related

Assign the same Drive Letter Every Time to USB Drive with USBDLM

I try to use USBDLM to connect separately a USB sticks and a USB drive to appear always as drive T.
On every USB stich/drive I put a USBDLM.ini with:
[DriveLetters]
Letters=%drive%\usbdlm.ini
and for every drive its own configuration as:
[DriveLetters10]
; Aldistick
DeviceID1=USB 2.0 Flash Disk USB Device
Letter1=T
; many other options are documented in the Help files
[DriveLetters20]
VolumeSerial=16ED-33C5
Letter=T
But I find out that this is not working unless I put the same usbdlm.ini file for every stick/drive into the folder where USBDLM.exe is placed.
Do I something wrong?
Thanks.
On the drive you need an USBDLM.INI which contains a simple [DriveLetters] section with the desired letters:
[DriveLetters]
Letters=T
In the main USBDLM.INI you let is read the letter from the INI on the drive:
[DriveLetters]
Letters=%drive%\usbdlm.ini
Maybe it is more handy to let USBDLM extract the desired drive letter from the volume label, e.g. label it "Drive T" and write in the main USBDLM.INI:
[DriveLetters]
Letters=%LetterFromLabel%
http://www.uwe-sieber.de/usbdlm_help_e.html#by_label
Uwe Sieber

Set specific application volume in AppleScript

I have been trying to use tell application "Google Chrome" to set sound volume to 5 but it gives me error "The variable volume is not defined." number -2753 from "volume". How do I do this?
Chrome doesn't have an application-specific volume setting. You can set the volume for your system with set volume output volume 50, where you can use any integer from 0 to 100.

Cocoa Unmounting drive but not ejecting it

Do you know you to unmount a drive without ejecting it. NSWorkspace has some methods to unmount drives but it also eject them.
Any idea ?
I am doing it as follows and it un-mounts the drive but doesn't eject it.
(Actually I want to eject the disk, I can only un-mount the disk. :P Please share how to eject a disk.)
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
CFURLRef path = CFURLCreateWithString(NULL, CFSTR("<path_to_your_volume_here>"), NULL);
DADiskRef disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, path);
DADiskUnmount(disk, kDADiskUnmountOptionDefault, __unmountCallback, NULL);
This is the code I am still working on and is under development and testing.
I am creating the "path" manually. You can use (and share) a better method to get the path of volume in a generic way. Perhaps this answer has hints of doing it the right way.I'll update when my development is refined and complete.
To do this, use DADiskUnmount in DiskArbitration framework.
http://developer.apple.com/library/mac/#documentation/Darwin/Reference/DiscArbitrationFramework/DiskArbitration_h/index.html#//apple_ref/c/func/DADiskUnmount
To eject the disk, unmount the disk as you stated, and then in your __unmountCallback do the following:
DADiskRef disk2 = DADiskCopyWholeDisk(disk);
DADiskEject(disk2,
kDADiskEjectOptionDefault,
NULL,
NULL);
You can pass any object as context to the DADiskUnmount() and then, for example, use it to determine if the respective disk should be ejected in the __unmountCallback.

How to run an AppleScript automatically once I insert a USB drive?

I need to rename and fill about 70 USB sticks. Having an Applescript run automatically when they are inserted would make it much simpler.
Any external drive you connect to an OS X machine is mounted into /Volumes. If you watch that folder for changes, you can pick up on added external drives and process these. Running this code:
property ignoredVolumes : {"Macintosh HD", "Time Machine Backups"} -- add as needed
tell application "System Events"
set rootVolume to disk item (POSIX file "/Volumes" as text)
set allVolumes to name of every disk item of rootVolume
repeat with aVolume in allVolumes
if aVolume is not in ignoredVolumes then
set name of disk item (path of rootVolume & aVolume) to newName
end if
end repeat
end tell
will rename drives that are not in your ignoredVolumes list (unplug all but those you want to ignore, run ls /Volumes in Terminal and add the names to the property) to newName. To have this triggered on every change, modify the codes to be a Stay-Open script application:
property pollIntervall : 60 -- in seconds
property ignoredVolumes : {…} -- from above
on run
my checkVolumes()
end run
on idle
my checkVolumes()
return pollInterval
end idle
on checkVolumes()
tell … end tell -- from above
end checkVolumes
and save it in AppleScript Editor (select “AppleScript application”, make sure you tick “Stay Open” when you do). Once launched, the script will keep running, executing the on idle handler every pollInterval seconds.
This will do fine if you are basically doing a once-in-a-while batch job. If you want a more permanent solution that does not rely on running a stay-open script application, you can either
attach a Folder Action Script to the /Volumes folder (hat tip to Philip Regan on Ask Different; details on how to configure the action in this Mac OS X Hints post) – the advantage being you strictly process additions to /Volumes, or
use launchd by creating a LaunchAgent with the StartOnMount key set to true – that will trigger the script / app the agent starts every time a filesystem is mounted (tip of the hat to Daniel Beck at Ask Different; see Apple’s Technical Note TN2083 for the gory details).

The Uniqueness of IOCTL_MOUNTDEV_QUERY_UNIQUE_ID

The documentation on IOCTL_MOUNTDEV_QUERY_UNIQUE_ID is a bit confusing... exactly what kind of ID should be returned in the MOUNTDEV_UNIQUE_ID structure?
The documentation for
typedef struct _MOUNTDEV_UNIQUE_ID {
USHORT UniqueIdLength;
UCHAR UniqueId[1];
} MOUNTDEV_UNIQUE_ID, *PMOUNTDEV_UNIQUE_ID;
says:
UniqueIdLength
Contains the length of unique volume ID.
UniqueId
Contains the unique volume ID. The format for unique volume names is "\??\Volume{GUID}\", where GUID is a globally unique identifier that identifies the volume.
However, there's something weird here: What should be the exact format of UniqueId? If it's meant to be in the \??\Volume{GUID}\ format, then what's the point of the UniqueIdLength field -- aren't they all the same size? Otherwise, what format does the device ID need to be in?
Furthermore, is this a device ID or a volume ID? In other words, is this supposed to be unique per medium (e.g. CD) or per device (CD drive)?
This kind of struct is pretty common in MS APIs - the UniqueID[1] variable is just a placeholder, in reality it's used as a UniqueId[UniqueIdLength] variable.
The ID is unique both per medium and per device - it depends on whether you're talking to a volume driver or a device class driver. The ID is intended to identify "something that can be mounted" - so e.g. a CD-ROM device, a fixed disk partition or an unpartitioned removable disk. The mount manager uses the ID a.o. to lookup where this particular volume was mounted before, and remount it at the same point.
From MSDN
Maybe there is misunderstanding about this structure.
I called DeviceIoControl(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID) and got a string as the similar format to Device Interface Path, but it is just different of the prefix 4 characters, and then it saved in registry \HKLM\SYSTEM\MountedDevices.
MOUNTDEV_UNIQUE_ID is acquired upon a volume arrival notification where mountmgr!MountMgrMountedDeviceArrival invokes mountmgr!QueryDeviceInformation, which sends a IOCTL_MOUNTDEV_QUERY_UNIQUE_ID IRP to the volume PDO stack, which volmgr picks up, and I'm not sure what routine it is but in XP's ftdisk it was ftdisk!FtpQueryUniqueIdBuffer that determined whether to set the UniqueID member to a GPT partition GUID, a MBR signature + offset, or the symbolic link like STORAGE#RemovableMedia.... The symbolic link is based on the name of devnode that the volume PDO is part of, and the symbolic link was generated by IoRegisterDeviceInterface, which was then stored in the volume extension before alerting mountmgr of the volume arrival in the first place (alerting is done by IoSetDeviceInterfaceState Enable). On Windows 7 the volume PDO devnode name is STORAGE\Volume\_??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer_B lade&Rev_1.27#4C530399920812105355&0#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}, the symbolic link is STORAGE#Volume#_??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer_Blade&Rev_1.27#4C530399920812105355&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b} but the MountedDevices data is _??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer_Blade&Rev_1.27#4C530399920812105355&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}. The symbolic link that is created is always to the volume PDO name, because the volume PDO is supplied to the call, which is \Device\HarddiskVolumeX.
FtpQueryUniqueIdBuffer uses the MBR signature and partition offset if it's an MBR disk, and uses the GPT partition GUID if it's a GPT disk, and uses the symbolic link if it's neither, which tends to be a regular USB drive mass storage volume that doesn't have a boot sector, and ftdisk considers a disk without a boot sector to be a 'superfloppy', so it looks for that flag on the volume extension. So that's how unique it is, MBR signature and GPT GUID uniqueness speak for themselves, but the symlink doesn't so I'll elaborate: it contains the DIID of the USBSTOR device, which includes the USB serial number, or if it doesn't have one, a system wide unique number determine according to the following scheme.
Mountmgr creates further symbolic links between the drive letter and volume device name, and the volume GUID and the volume device name, and then puts them in the MountedDevices database but uses the unique ID instead of the volume device name. The volume GUID \??\Volume{GUID}\ it generates using ExUuidCreate. IOCTL_MOUNTMGR_QUERY_POINTS shows each symbolic link for a mounted device, so it will show \DosDevices\C: -> \Device\HarddiskVolumeX and \??\Volume{GUID}\ -> \Device\HarddiskVolumeX and the unique ID of the mounted device and the name of the mounted device. It does not however show the symbolic link to \Device\HarddiskVolumeX created by IoRegisterDeviceInterface because the symbolic link wasn't created by mount manager, so it doesn't know about it.

Resources