Update of /cvsroot/azureus/azureus2/build/libOSXAccess In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv31943/build/libOSXAccess Added Files: org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess.h makefile IONotification.m IONotification.h libOSXAccess.jnilib OSXAccess.mm Log Message: Add Drive Dectection for Mac Move jnilib code to build/libOSXAccess --- NEW FILE: OSXAccess.mm --- #include <Carbon/Carbon.h> #include <JavaVM/jni.h> #include <AEDataModel.h> #include "org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess.h" #include <IOKit/IOBSD.h> #include <sys/mount.h> #include <wchar.h> #import <IOKit/storage/IOMedia.h> #import <IOKit/storage/IOCDMedia.h> #import <IOKit/storage/IODVDMedia.h> #include "IONotification.h" #define VERSION "1.04" #define assertNot0(a) if (a == 0) { fprintf(stderr, "%s is 0\n", #a); return; } extern "C" { void notify(const char *mount, io_service_t service, struct statfs *fs, bool added); } void fillServiceInfo(io_service_t service, JNIEnv *env, jobject hashMap, jmethodID methPut); /** * AEDesc code from SWT, os_structs.c * Copyright (c) 2000, 2006 IBM Corporation and others. */ typedef struct AEDesc_FID_CACHE { int cached; jclass clazz; jfieldID descriptorType, dataHandle; } AEDesc_FID_CACHE; AEDesc_FID_CACHE AEDescFc; static jclass gCallBackClass = 0; static jobject gCallBackObj = 0; static JavaVM *gjvm = 0; jint JNI_OnLoad(JavaVM *vm, void *reserved) { gjvm = vm; return JNI_VERSION_1_4; } void cacheAEDescFields(JNIEnv *env, jobject lpObject) { if (AEDescFc.cached) return; AEDescFc.clazz = env->GetObjectClass(lpObject); AEDescFc.descriptorType = env->GetFieldID(AEDescFc.clazz, "descriptorType", "I"); AEDescFc.dataHandle = env->GetFieldID(AEDescFc.clazz, "dataHandle", "I"); AEDescFc.cached = 1; } AEDesc *getAEDescFields(JNIEnv *env, jobject lpObject, AEDesc *lpStruct) { if (!AEDescFc.cached) cacheAEDescFields(env, lpObject); lpStruct->descriptorType = (DescType) env->GetIntField(lpObject, AEDescFc.descriptorType); lpStruct->dataHandle = (AEDataStorage) env->GetIntField(lpObject, AEDescFc.dataHandle); return lpStruct; } void setAEDescFields(JNIEnv *env, jobject lpObject, AEDesc *lpStruct) { if (!AEDescFc.cached) cacheAEDescFields(env, lpObject); env->SetIntField(lpObject, AEDescFc.descriptorType, (jint) lpStruct->descriptorType); env->SetIntField(lpObject, AEDescFc.dataHandle, (jint) lpStruct->dataHandle); } JNIEXPORT jint JNICALL Java_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess_AEGetParamDesc(JNIEnv *env, jclass that, jint theAppleEvent, jint theAEKeyword, jint desiredType, jobject result) { AEDesc _result, *lpresult = NULL; jint rc = 0; if (result) if ((lpresult = getAEDescFields(env, result, &_result)) == NULL) goto fail; rc = (jint) AEGetParamDesc((const AppleEvent *) theAppleEvent, (AEKeyword) theAEKeyword, (DescType) desiredType, (AEDescList *) lpresult); fail: if (result && lpresult) setAEDescFields(env, result, lpresult); return rc; } JNIEXPORT jstring JNICALL Java_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess_getVersion( JNIEnv *env, jclass cla) { jstring result = env->NewStringUTF((char *) VERSION); return (result); } JNIEXPORT jstring JNICALL Java_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess_getDocDir( JNIEnv *env, jclass cla) { CFURLRef docURL; CFStringRef docPath; FSRef fsRef; OSErr err = FSFindFolder(kUserDomain, kDocumentsFolderType, kDontCreateFolder, &fsRef); jstring result = 0; if (err == noErr) { if ((docURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &fsRef))) { docPath = CFURLCopyFileSystemPath(docURL, kCFURLPOSIXPathStyle); if (docPath) { // convert to unicode CFIndex strLen = CFStringGetLength(docPath); UniChar uniStr[strLen]; CFRange strRange; strRange.location = 0; strRange.length = strLen; CFStringGetCharacters(docPath, strRange, uniStr); result = env->NewString((jchar*) uniStr, (jsize) strLen); CFRelease(docPath); return result; } CFRelease(docURL); } } return result; } JNIEXPORT void JNICALL Java_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess_memmove( JNIEnv *env, jclass cla, jbyteArray dest, jint src, jint count) { jbyte *dest1; if (dest) { dest1 = env->GetByteArrayElements(dest, NULL); memmove((void *) dest1, (void *) src, count); env->ReleaseByteArrayElements(dest, dest1, 0); } } JNIEXPORT void JNICALL Java_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess_initializeDriveDetection (JNIEnv *env, jclass cla, jobject listener) { // OSXDriveDetectListener jclass callback_class = env->GetObjectClass(listener); gCallBackClass = (jclass) env->NewGlobalRef(callback_class); gCallBackObj = (jobject) env->NewGlobalRef(listener); IONotification *mountNotification = [IONotification alloc]; [mountNotification setup]; } jstring wchar2jstring(JNIEnv* env, const wchar_t* s) { jstring result = 0; size_t len = wcslen(s); size_t sz = wcstombs(0, s, len); char c[sz + 1]; wcstombs(c, s, len); c[sz] = '\0'; result = env->NewStringUTF(c); return result; } jstring char2jstring(JNIEnv* env, const char *str) { return (jstring) env->NewStringUTF(str); } jstring CFString2jstring(JNIEnv *env, CFStringRef cfstr) { int len = CFStringGetLength(cfstr) * 2 + 1; char s[len]; CFStringGetCString(cfstr, s, len, kCFStringEncodingUTF8); return env->NewStringUTF(s); } jstring NSString2jstring(JNIEnv *env, NSString *s) { if (s == NULL) { return 0; } const char *c = [s UTF8String]; return env->NewStringUTF(c); } jobject createLong(JNIEnv *env, jlong l) { jclass clsLong = env->FindClass("java/lang/Long"); jmethodID longInit = env->GetMethodID(clsLong, "<init>", "(J)V"); jobject o = env->NewObject(clsLong, longInit, l); return o; } #define IOOBJECTRELEASE(x) if ((x)) IOObjectRelease((x)); (x) = NULL; io_object_t IOKitObjectFindParentOfClass(io_object_t inService, io_name_t inClassName) { io_object_t rval = NULL; io_iterator_t iter = NULL; io_object_t service = NULL; kern_return_t kr; if (!inService || !inClassName) { return NULL; } kr = IORegistryEntryCreateIterator(inService, kIOServicePlane, kIORegistryIterateRecursively | kIORegistryIterateParents, &iter); if (kr != KERN_SUCCESS) { goto IORegistryEntryCreateIterator_FAILED; } if (!IOIteratorIsValid(iter)) { IOIteratorReset(iter); } while ((service = IOIteratorNext(iter))) { if (IOObjectConformsTo(service, inClassName)) { rval = service; break; } IOOBJECTRELEASE(service); } IOOBJECTRELEASE(iter); IORegistryEntryCreateIterator_FAILED: return rval; } void notify(const char *mount, io_service_t service, struct statfs *fs, bool added) { assertNot0(gCallBackClass); assertNot0(gjvm); JNIEnv* env = NULL; jint attachResult = gjvm->AttachCurrentThread((void **) &env, NULL); assertNot0(env); jmethodID meth; if (added) { meth = env->GetMethodID(gCallBackClass, "driveDetected", "(Ljava/io/File;Ljava/util/Map;)V"); } else { meth = env->GetMethodID(gCallBackClass, "driveRemoved", "(Ljava/io/File;Ljava/util/Map;)V"); } assertNot0(meth); jclass clsHashMap = env->FindClass("java/util/HashMap"); assertNot0(clsHashMap); jmethodID constHashMap = env->GetMethodID(clsHashMap, "<init>", "()V"); assertNot0(constHashMap); jmethodID methPut = env->GetMethodID(clsHashMap, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); assertNot0(methPut); jclass clsFile = env->FindClass("java/io/File"); assertNot0(clsFile); jmethodID constFile = env->GetMethodID(clsFile, "<init>", "(Ljava/lang/String;)V"); assertNot0(constFile); jobject file = 0; if (mount) { file = env->NewObject(clsFile, constFile, char2jstring(env, mount)); assertNot0(file); } jobject hashMap = env->NewObject(clsHashMap, constHashMap, ""); assertNot0(hashMap); NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; if (fs) { NSString *path = [[NSString alloc] initWithUTF8String:fs->f_mntonname]; NSWorkspace *ws = [NSWorkspace sharedWorkspace]; BOOL removable; BOOL writable; BOOL unmountable; NSString *description; NSString *fileSystemType; BOOL gotInfo = [ws getFileSystemInfoForPath:path isRemovable:&removable isWritable:&writable isUnmountable:&unmountable description:&description type:&fileSystemType]; if (gotInfo) { if (description) { env->CallObjectMethod(hashMap, methPut, char2jstring(env, "description"), NSString2jstring(env, description)); } if (fileSystemType) { env->CallObjectMethod(hashMap, methPut, char2jstring(env, "fileSystemType"), NSString2jstring(env, fileSystemType)); } env->CallObjectMethod(hashMap, methPut, char2jstring(env, "removable"), createLong(env, (jlong) removable)); env->CallObjectMethod(hashMap, methPut, char2jstring(env, "writable"), createLong(env, (jlong) writable)); env->CallObjectMethod(hashMap, methPut, char2jstring(env, "unmountable"), createLong(env, (jlong) unmountable)); } [path release]; env->CallObjectMethod(hashMap, methPut, char2jstring(env, "mntfromname"), char2jstring(env, fs->f_mntfromname)); env->CallObjectMethod(hashMap, methPut, char2jstring(env, "mntonname"), char2jstring(env, fs->f_mntonname)); } if (service) { fillServiceInfo(service, env, hashMap, methPut); } env->CallVoidMethod(gCallBackObj, meth, file, hashMap); [pool release]; } void fillServiceInfo(io_service_t service, JNIEnv *env, jobject hashMap, jmethodID methPut) { io_name_t deviceName; kern_return_t kr = IORegistryEntryGetName(service, deviceName); if (KERN_SUCCESS == kr) { env->CallObjectMethod(hashMap, methPut, char2jstring(env, "DeviceName"), char2jstring(env, deviceName)); } CFStringRef str_bsd_path = (CFStringRef) IORegistryEntryCreateCFProperty(service, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0); if (str_bsd_path) { env->CallObjectMethod(hashMap, methPut, char2jstring(env, "BSDName"), CFString2jstring(env, str_bsd_path)); } BOOL cd = IOObjectConformsTo(service, kIOCDMediaClass); BOOL dvd = IOObjectConformsTo(service, kIODVDMediaClass); io_service_t ioparent; ioparent = IOKitObjectFindParentOfClass(service, kIOMediaClass); if (ioparent) { jclass clsHashMap = env->FindClass("java/util/HashMap"); assertNot0(clsHashMap); jmethodID constHashMap = env->GetMethodID(clsHashMap, "<init>", "()V"); assertNot0(constHashMap); jobject parentHashMap = env->NewObject(clsHashMap, constHashMap, ""); assertNot0(parentHashMap); env->CallObjectMethod(hashMap, methPut, char2jstring(env, "parent"), parentHashMap); fillServiceInfo(ioparent, env, parentHashMap, methPut); cd |= IOObjectConformsTo(ioparent, kIOCDMediaClass); dvd |= IOObjectConformsTo(ioparent, kIODVDMediaClass); IOOBJECTRELEASE(ioparent) } env->CallObjectMethod(hashMap, methPut, char2jstring(env, "isCD"), createLong(env, (jlong) cd)); env->CallObjectMethod(hashMap, methPut, char2jstring(env, "isDVD"), createLong(env, (jlong) dvd)); // we can expand this one later if needed env->CallObjectMethod(hashMap, methPut, char2jstring(env, "isOptical"), createLong(env, (jlong)(dvd || cd))); } --- NEW FILE: libOSXAccess.jnilib --- (This appears to be a binary file; contents omitted.) --- NEW FILE: org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess.h --- /* DO NOT EDIT THIS FILE - it is machine generated */ #include <JavaVM/jni.h> /* Header for class org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess */ #ifndef _Included_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess #define _Included_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess #ifdef __cplusplus extern "C" { #endif /* * Class: org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess * Method: AEGetParamDesc * Signature: (IIILorg/eclipse/swt/internal/carbon/AEDesc;)I */ JNIEXPORT jint JNICALL Java_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess_AEGetParamDesc (JNIEnv *, jclass, jint, jint, jint, jobject); /* * Class: org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess * Method: getVersion * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess_getVersion (JNIEnv *, jclass); /* * Class: org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess * Method: getDocDir * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess_getDocDir (JNIEnv *, jclass); /* * Class: org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess * Method: memmove * Signature: ([BII)V */ JNIEXPORT void JNICALL Java_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess_memmove (JNIEnv *, jclass, jbyteArray, jint, jint); /* * Class: org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess * Method: initializeDriveDetection * Signature: (Lorg/gudy/azureus2/platform/macosx/access/jnilib/OSXDriveDetectListener;)V */ JNIEXPORT void JNICALL Java_org_gudy_azureus2_platform_macosx_access_jnilib_OSXAccess_initializeDriveDetection (JNIEnv *, jclass, jobject); #ifdef __cplusplus } #endif #endif --- NEW FILE: IONotification.m --- // // IONotification.m // USBPrivateDataSample // // Created by Vuze on 8/11/09. // Copyright 2009 __MyCompanyName__. All rights reserved. // #import "IONotification.h" #include <IOKit/IOKitLib.h> #include <IOKit/IOMessage.h> #include <IOKit/IOCFPlugIn.h> #include <IOKit/usb/IOUSBLib.h> #include <IOKit/storage/IOMedia.h> #include <IOKit/IOBSD.h> #include <sys/mount.h> #include <JavaVM/jni.h> //#define IODISMOUNT 1 //#define IONOTIFYDISMOUNT 1 #define _PATH_DEV "/dev/" static IONotificationPortRef gNotifyPort; void DeviceNotification(void *refCon, io_service_t service, natural_t messageType, void *messageArgument); /** * lookup a disk based on "dev" mount and return fileSystem Status * **/ static struct statfs * getFileSystemStatusDevMount(char * disk) { struct statfs * mountList; int mountListCount; int mountListIndex; mountListCount = getmntinfo(&mountList, MNT_NOWAIT); for (mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++) { fprintf(stderr, "test looking for %s mounto %s fr %s\n ", disk, mountList[mountListIndex].f_mntonname, mountList[mountListIndex].f_mntfromname); if (strncmp(mountList[mountListIndex].f_mntfromname, _PATH_DEV, strlen(_PATH_DEV)) == 0) { if (strcmp(mountList[mountListIndex].f_mntfromname + strlen(_PATH_DEV), disk) == 0) { break; } } } return (mountListIndex < mountListCount) ? (mountList + mountListIndex) : (NULL); } /** * Lookup a disk based on "Volumes" mount point and return filesystem status * **/ static struct statfs * getFileSystemStatusFromMount(const char * mount) { struct statfs * mountList; int mountListCount; int mountListIndex; mountListCount = getmntinfo(&mountList, MNT_NOWAIT); for (mountListIndex = 0; mountListIndex < mountListCount; mountListIndex++) { //fprintf(stderr, "test mounto %s fr %s\n ", mountList[mountListIndex].f_mntonname, mountList[mountListIndex].f_mntfromname); if (strcmp(mountList[mountListIndex].f_mntonname, mount) == 0) { break; } } return (mountListIndex < mountListCount) ? (mountList + mountListIndex) : (NULL); } @implementation IONotification /** * Prepare file system info we gathered and pass it to a function that * will do something with it (like send it back to Java) * **/ extern void notify(const char *mount, io_service_t service, struct statfs *fs, bool added); #ifdef IODISMOUNT void DeviceRemoved(void *refCon, io_iterator_t iterator) { kern_return_t kr; io_service_t service; while ((service = IOIteratorNext(iterator))) { CFTypeRef str_bsd_path = IORegistryEntryCreateCFProperty(service, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0); if (str_bsd_path != NULL) { int len = CFStringGetLength(str_bsd_path) * 2 + 1; char s[len]; CFStringGetCString((CFStringRef) str_bsd_path, s, len, kCFStringEncodingUTF8); io_name_t deviceName; kern_return_t kr = IORegistryEntryGetName(service, deviceName); fprintf(stderr, "DR %s -- %s\n", s, deviceName); CFRelease(str_bsd_path); struct statfs *fs = getFileSystemStatusDevMount(s); const char *mount = (fs == 0) ? 0 : fs->f_mntonname; notify(mount, service, fs, false); } kr = IOObjectRelease(service); } } #endif -(int) checkExisting { CFMutableDictionaryRef matchingDict; kern_return_t kr; io_iterator_t iter; #ifdef IODISMOUNT matchingDict = IOServiceMatching(kIOMediaClass); if (matchingDict == NULL) { fprintf(stderr, "IOServiceMatching returned NULL.\n"); return -1; } kr = IOServiceAddMatchingNotification(gNotifyPort, kIOTerminatedNotification, matchingDict, // matching DeviceRemoved, // callback NULL, &iter); io_service_t service; while (service = IOIteratorNext(iter)) { IOObjectRelease(service); } #endif #ifdef NOCODE matchingDict = IOServiceMatching(kIOMediaClass); if (matchingDict == NULL) { fprintf(stderr, "IOServiceMatching returned NULL.\n"); return -1; } kr = IOServiceAddMatchingNotification(gNotifyPort, kIOMatchedNotification, matchingDict, // matching rawDeviceAdded, // callback NULL, &iter); //io_service_t service; //while (service = IOIteratorNext(iter)) { // IOObjectRelease(service); //} #endif matchingDict = IOServiceMatching(kIOMediaClass); kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter); //[self rawDeviceAdded:iter]; rawDeviceAdded(0,iter); return 0; } - (void) setup { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; gNotifyPort = IONotificationPortCreate(kIOMasterPortDefault); CFRunLoopSourceRef runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort); CFRunLoopRef runLoop = CFRunLoopGetCurrent(); CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopDefaultMode); NSWorkspace *ws = [NSWorkspace sharedWorkspace]; NSNotificationCenter *center = [ws notificationCenter]; [center addObserver:self selector:@selector(mount:) name:NSWorkspaceDidMountNotification object:ws]; [center addObserver:self selector:@selector(unmount:) name:NSWorkspaceDidUnmountNotification object:ws]; [ self checkExisting ]; } #ifdef IONOTIFYDISMOUNT void DeviceNotification(void *refCon, io_service_t service, natural_t messageType, void *messageArgument) { io_name_t deviceName; kern_return_t kr = IORegistryEntryGetName(service, deviceName); fprintf(stderr, "Device %s Not %d.\n", deviceName, messageType); if (messageType == kIOMessageServiceIsTerminated || messageType == kIOMessageServiceWasClosed) { if (messageType == kIOMessageServiceWasClosed) { fprintf(stderr, "Device close.\n"); } else { fprintf(stderr, "Device terminated.\n"); } CFTypeRef str_bsd_path = IORegistryEntryCreateCFProperty(service, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0); if (str_bsd_path != NULL) { int len = CFStringGetLength(str_bsd_path) * 2 + 1; char s[len]; CFStringGetCString((CFStringRef) str_bsd_path, s, len, kCFStringEncodingUTF8); CFRelease(str_bsd_path); fprintf(stderr, "WTF %s\n", s); struct statfs *fs = getFileSystemStatusDevMount(s); const char *mount = (fs == 0) ? 0 : fs->f_mntonname; notify(mount, service, fs, false); } if (refCon) { IOObjectRelease((io_object_t) refCon); } } } #endif //- (void)rawDeviceAdded:(io_iterator_t)iterator void rawDeviceAdded(void *refCon, io_iterator_t iterator) { kern_return_t kr; io_service_t service; while ((service = IOIteratorNext(iterator))) { io_name_t deviceName; kr = IORegistryEntryGetName(service, deviceName); fprintf(stderr, "rDA: %s\n", deviceName); CFTypeRef str_bsd_path = IORegistryEntryCreateCFProperty(service, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0); if (str_bsd_path != NULL) { int len = CFStringGetLength(str_bsd_path) * 2 + 1; char s[len]; CFStringGetCString((CFStringRef) str_bsd_path, s, len, kCFStringEncodingUTF8); fprintf(stderr, "rDA BSD %s\n", s); CFRelease(str_bsd_path); #ifdef NOCODE NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:2.0]; NSTimer *timer = [[NSTimer alloc] initWithFireDate:fireDate target:self selector:@selector(countedtargetMethod:) userInfo:[self userInfo] repeats:NO]; #endif struct statfs *fs; fs = getFileSystemStatusDevMount(s); if (fs) { notify(fs->f_mntonname, service, fs, true); #ifdef IONOTIFYDISMOUNT io_object_t obj; kr = IOServiceAddInterestNotification(gNotifyPort, // notifyPort service, // service kIOGeneralInterest, // interestType DeviceNotification, // callback &obj, // refCon &obj // notification ); #endif } } kr = IOObjectRelease(service); } } -(void)mount:(id)notification { NSLog(@"mount: %@", notification); NSString *path = [[notification userInfo] valueForKey:@"NSDevicePath"]; // With the path, we can use statfs to get the device name (/mnt/<name>) // from device name, we can query UIServiceGetMatchingService and get info (like if it's optical media) const char *cPath = [path UTF8String]; fprintf(stderr, "mount %s\n", cPath); struct statfs *fs = getFileSystemStatusFromMount(cPath); if (fs) { CFMutableDictionaryRef matchingDict; matchingDict = IOServiceMatching(kIOMediaClass); if (matchingDict == NULL) { fprintf(stderr, "IOServiceMatching returned NULL.\n"); return; } char *sBSDName = strrchr(fs->f_mntfromname, (int) '/'); if (sBSDName) { sBSDName++; fprintf(stderr, "Searching for %s\n", sBSDName); CFStringRef bsdname = CFStringCreateWithCString(kCFAllocatorDefault, sBSDName, kCFStringEncodingMacRoman); CFDictionarySetValue(matchingDict, CFSTR(kIOBSDNameKey), bsdname); } io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict); if (service) { notify(cPath, service, fs, true); #ifdef IONOTIFYDISMOUNT io_object_t obj; kern_return_t kr = IOServiceAddInterestNotification(gNotifyPort, // notifyPort service, // service kIOGeneralInterest, // interestType DeviceNotification, // callback &obj, // refCon &obj // notification ); #endif IOObjectRelease(service); } } } -(void)unmount:(id)notification { NSString *path = [[notification userInfo] valueForKey:@"NSDevicePath"]; // With the path, we can use statfs to get the device name (/mnt/<name>) // from device name, we can query UIServiceGetMatchingService and get info (like if it's optical media) NSLog(@"unmount: %@", notification); const char *cPath = [path UTF8String]; fprintf(stderr, "unmount %s\n", cPath); struct statfs *fs = getFileSystemStatusFromMount(cPath); io_service_t service = 0; // Alas, fs will always be null, so service lookup will never run // If we stored the NSDevicePath : fs->f_mntfromname mapping, and looked // it up, we might have a chance to get the ioservice.. if (fs) { CFMutableDictionaryRef matchingDict; matchingDict = IOServiceMatching(kIOMediaClass); if (matchingDict == NULL) { fprintf(stderr, "IOServiceMatching returned NULL.\n"); return; } char *sBSDName = strrchr(fs->f_mntfromname, (int) '/'); if (sBSDName) { sBSDName++; CFStringRef bsdname = CFStringCreateWithCString(kCFAllocatorDefault, sBSDName, kCFStringEncodingMacRoman); CFDictionarySetValue(matchingDict, CFSTR(kIOBSDNameKey), bsdname); service = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict); //fprintf(stderr, "Searching for %s, result = %p\n", sBSDName, service); } } notify(cPath, service, fs, false); if (service) { IOObjectRelease(service); } } @end --- NEW FILE: makefile --- SDK = /Developer/SDKs/MacOSX10.4u.sdk ARCHS = -arch i386 -arch ppc LFLAGS = -bundle -isysroot $(SDK) $(ARCHS) -framework JavaVM -framework Carbon -framework AppKit -framework IOKit CFLAGS = -c $(ARCHS) -I $(SDK)/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Headers OBJECTS = OSXAccess.o IONotification.o OUTLIB = libOSXAccess.jnilib all: g++ $(CFLAGS) OSXAccess.mm IONotification.m g++ -o $(OUTLIB) $(LFLAGS) $(OBJECTS) rm -f *.o --- NEW FILE: IONotification.h --- #import <Cocoa/Cocoa.h> #define fprintf @interface IONotification : NSObject { } - (void) setup; -(void)mount:(id)notification; -(void)unmount:(id)notification; void rawDeviceAdded(void *refCon, io_iterator_t iterator); @end |