/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 1.0 (the 'License'). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License." * * @APPLE_LICENSE_HEADER_END@ */ /* * DiskVolume.m * - objects for DiskVolume and DiskVolumes * - a convenient way to store information about filesystems (volumes) * and perform actions on them */ /* * Modification History: * * Dieter Siegmund (dieter@apple.com) Thu Aug 20 18:31:29 PDT 1998 * - initial revision * Dieter Siegmund (dieter@apple.com) Thu Oct 1 13:42:34 PDT 1998 * - added support for hfs and cd9660 filesystems * Brent Knight (bknight@apple.com) Thu Apr 1 15:54:48 PST 1999 * - adapted for Beaker, with caveats described in Radar 2320396 * Brent Knight (bknight@apple.com) Fri Apr 9 11:16:04 PDT 1999 * - [2320396] added support for ioWritable/ioRemovable * Brent Knight (bknight@apple.com) Thu Sep 9 11:36:01 PDT 1999 * - added support for fsck_hfs, disk insertion and ejection * Dieter Siegmund (dieter@apple.com) Wed Nov 10 10:58:43 PST 1999 * - added support for named UFS volumes * - added logic to use the NeXT label name if a "new" ufs label is * not present * - homogenized the filesystem probing logic for ufs, hfs, and cd9660 * - homogenized the fsck logic for ufs and hfs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DiskVolume.h" #include "GetRegistry.h" #include "DiskArbitrationServerMain.h" #include #include #include #define kIsInvisible 0x4000 /* * Generic Finder file/dir data */ struct FinderInfo { u_int32_t opaque_1[2]; u_int16_t fdFlags; /* Finder flags */ int16_t opaque_2[11]; }; typedef struct FinderInfo FinderInfo; /* getattrlist buffers start with an extra length field */ struct FinderAttrBuf { unsigned long infoLength; FinderInfo finderInfo; }; typedef struct FinderAttrBuf FinderAttrBuf; #define MAXNAMELEN 256 extern CFMutableArrayRef matchingArray; int DiskArbIsHandlingUnrecognizedDisks(void) { ClientPtr clientPtr; int i; for (clientPtr = g.Clients, i = 0; clientPtr != NULL; clientPtr = clientPtr->next, i++) { if (clientPtr->flags & kDiskArbClientHandlesUninitializedDisks) { return FALSE; } } return TRUE; } extern mach_port_t gNotifyPort; void * UnrecognizedDiskDiscovered(void * args) { DiskPtr diskPtr = args; // display UI to inform the user that an unrecognized disk was inserted. this must be done asynch. // we also need to pass the diskPtr so that it can be ejected SInt32 retval = ERR_SUCCESS; CFOptionFlags responseFlags; CFURLRef daFrameworkURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/System/Library/PrivateFrameworks/DiskArbitration.framework"), kCFURLPOSIXPathStyle, TRUE); // use the url of the DiskArbitration Framework and put a Localizable.strings file in there. if (currentConsoleUser >= 0 ) { //someone's logged in retval = CFUserNotificationDisplayAlert(60.0, kCFUserNotificationStopAlertLevel, NULL, NULL, daFrameworkURL, unrecognizedHeader, unrecognizedMessage, ejectString, ignoreString, initString, &responseFlags); } else { // someone's at the login window retval = CFUserNotificationDisplayAlert(60.0, kCFUserNotificationStopAlertLevel, NULL, NULL, daFrameworkURL, unrecognizedHeader, unrecognizedMessage, ejectString, ignoreString, NULL, &responseFlags); } if (responseFlags == kCFUserNotificationDefaultResponse) { // Eject the disk DiskPtr localPtr = LookupWholeDiskForThisPartition(diskPtr); if (localPtr && localPtr->state != kDiskStateNewlyEjected) { mach_msg_empty_send_t msg; if (diskPtr->ioBSDName) { DiskArbUnmountAndEjectRequest_async_rpc( 0, diskPtr->ioBSDName, FALSE); } msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); msg.header.msgh_size = sizeof(msg); msg.header.msgh_remote_port = gNotifyPort; msg.header.msgh_local_port = NULL; msg.header.msgh_id = INTERNAL_MSG; //send a mach_msg to the main thread to kick it in to action ... mach_msg(&msg.header, /* msg */ MACH_SEND_MSG, /* option */ msg.header.msgh_size, /* send_size */ 0, /* rcv_size */ MACH_PORT_NULL, /* rcv_name */ MACH_MSG_TIMEOUT_NONE, /* timeout */ MACH_PORT_NULL); /* notify */ } } else if (responseFlags == kCFUserNotificationAlternateResponse) { // Ignore and continue } else if (responseFlags == kCFUserNotificationOtherResponse) { // Launch Disk Utility // switch to the console user uid and ... if (currentConsoleUser >= 0) { seteuid(currentConsoleUser); system("/usr/bin/open \"/Applications/Utilities/Disk Utility.app\""); // then switch back ... seteuid(0); } } CFRelease(daFrameworkURL); return NULL; } // Disconnected arbitration messages void StartUnrecognizedDiskDialogThread(DiskPtr disk) { pthread_attr_t attr; pthread_t tid; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&tid, &attr, UnrecognizedDiskDiscovered, disk); pthread_attr_destroy(&attr); } static void eject_media(char * dev) { int fd; char specName[MAXNAMELEN]; sprintf(specName, "/dev/r%s", dev); fd = open(specName, O_RDONLY | O_NDELAY); if ( fd >= 0 ) { if (ioctl(fd, DKIOCEJECT, 0) < 0) { pwarning(("eject %s failed: %s\n", dev, strerror(errno))); } close(fd); } return; } static struct statfs * get_fsstat_list(int * number) { int n; struct statfs * stat_p; n = getfsstat(NULL, 0, MNT_NOWAIT); if (n <= 0) { return (NULL); } stat_p = (struct statfs *)malloc(n * sizeof(*stat_p)); if (stat_p == NULL) { return (NULL); } if (getfsstat(stat_p, n * sizeof(*stat_p), MNT_NOWAIT) <= 0) { free(stat_p); return (NULL); } *number = n; return (stat_p); } static struct statfs * fsstat_lookup_spec(struct statfs * list_p, int n, char * spec, char * fstype) { char alt_spec[MAXNAMELEN]; int i; struct statfs * scan; sprintf(alt_spec, "/private%s", spec); for (i = 0, scan = list_p; i < n; i++, scan++) { if (strcmp(scan->f_fstypename, fstype) == 0 && (strcmp(scan->f_mntfromname, spec) == 0 || strcmp(scan->f_mntfromname, alt_spec) == 0)) { return (scan); } } return (NULL); } boolean_t fsck_needed(char * devname, char * fstype) { char command[1024]; FILE * f; int ret; struct stat sb; char fsck_command_line[1024]; char *fsckCmd = repairPathForFileSystem(fstype); sprintf(command, "%s -q /dev/r%s", fsckCmd, devname); sprintf(fsck_command_line, fsckCmd); { /* determine if the fsck command line exists if it doesn't, set the volume clean */ if (stat(fsck_command_line, &sb) != 0) { // the file doesn't exist dwarning(("%s: '%s' not found...\n", __FUNCTION__, fsck_command_line)); return (FALSE); } } dwarning(("%s('%s'): '%s'...\n", __FUNCTION__, devname, command)); f = popen(command, "w"); if (f == NULL) { dwarning(("%s('%s'): popen('%s') failed", __FUNCTION__, devname, command)); // Couldn't find an appropriate fsck_* - assume one isn't needed return (FALSE); } fflush(f); ret = pclose(f); free(fsckCmd); dwarning(("%s('%s'): '%s' => %d\n", __FUNCTION__, devname, command, ret)); if (ret <= 0) { return (FALSE); } return (TRUE); } #define FILESYSTEM_ERROR 0 #define FILESYSTEM_MOUNTED 1 #define FILESYSTEM_MOUNTED_ALREADY 2 #define FILESYSTEM_NEEDS_REPAIR 3 /* foreignLabel: return the label written to the file by the -p(robe) option of the fs.util program */ static char * foreignLabel(char * fsName) { int fd; static char theLabel[MAXNAMELEN], buf[MAXPATHLEN]; sprintf(buf, "%s/%s%s/%s%s", FS_DIR_LOCATION, fsName, FS_DIR_SUFFIX, fsName, FS_LABEL_SUFFIX); fd = open(buf, O_RDONLY, 0); if (fd >= 0) { int i = read(fd, theLabel, 255); close(fd); if (i > 0) { theLabel[i] = '\0'; return (theLabel); } } return (NULL); } /* foreignProbe: run the -p(robe) option of the given .util program in a child process */ static int foreignProbe(const char *fsName, const char *execPath, const char *probeCmd, const char *devName, int removable, int writable) { int result; const char *childArgv[] = { execPath, probeCmd, devName, removable ? DEVICE_REMOVABLE : DEVICE_FIXED, writable? DEVICE_WRITABLE : DEVICE_READONLY, 0 }; char *fsDir = fsDirForFS((char *)fsName); int pid; dwarning(("%s('%s', '%s', removable=%d, writable=%d):\n'%s %s %s %s %s'\n", __FUNCTION__, fsName, devName, removable, writable, execPath, childArgv[1], childArgv[2], childArgv[3], childArgv[4])); if (access(execPath,F_OK) == 0) { if ((pid = fork()) == 0) { /* CHILD PROCESS */ cleanUpAfterFork(); chdir(fsDir); execve(execPath, childArgv, 0); exit(-127); } else if (pid > 0) { int statusp; int waitResult; /* PARENT PROCESS */ dwarning(("wait4(pid=%d,&statusp,0,NULL)...\n", pid)); waitResult = wait4(pid,&statusp,0,NULL); dwarning(("wait4(pid=%d,&statusp,0,NULL) => %d\n", pid, waitResult)); if (waitResult > 0) { if (WIFEXITED(statusp)) { result = (int)(char)(WEXITSTATUS(statusp)); goto Return; } } } } result = FSUR_IO_FAIL; Return: free(fsDir); dwarning(("%s(...) => %d\n", __FUNCTION__, result)); return result; } /* foreignMountDevice: run the -(mount) option of the given .util program in a child process */ static int foreignMountDevice(const char *fsName, const char *execPath, const char *devName, int removable, int writable, const char *mountPoint) { int result; char cmd[] = {'-', FSUC_MOUNT, 0}; // char *execPath = utilPathForFS((char *)fsName); const char *childArgv[] = { execPath, cmd, devName, mountPoint, removable ? DEVICE_REMOVABLE : DEVICE_FIXED, writable? DEVICE_WRITABLE : DEVICE_READONLY, 0 }; char *fsDir = fsDirForFS((char *)fsName); int pid; dwarning(("%s('%s', '%s', removable=%d, writable=%d, '%s'):\n'%s %s %s %s %s %s'\n", __FUNCTION__, fsName, devName, removable, writable, mountPoint, execPath, childArgv[1], childArgv[2], childArgv[3], childArgv[4], childArgv[5])); if ((pid = fork()) == 0) { /* CHILD PROCESS */ cleanUpAfterFork(); chdir(fsDir); execve(execPath, childArgv, 0); exit(-127); } else if (pid > 0) { int statusp; int waitResult; /* PARENT PROCESS */ dwarning(("wait4(pid=%d,&statusp,0,NULL)...\n", pid)); waitResult = wait4(pid,&statusp,0,NULL); dwarning(("wait4(pid=%d,&statusp,0,NULL) => %d\n", pid, waitResult)); if (waitResult > 0) { if (WIFEXITED(statusp)) { int i = (int)(char)(WEXITSTATUS(statusp)); if (i == FSUR_IO_SUCCESS) { result = FILESYSTEM_MOUNTED; goto Return; } else if (i == FSUR_IO_UNCLEAN) { result = FILESYSTEM_NEEDS_REPAIR; goto Return; } } } } result = FILESYSTEM_ERROR; Return: free(execPath); free(fsDir); dwarning(("%s(...) => %d\n", __FUNCTION__, result)); return result; } /** ripped off from workspace - end **/ boolean_t DiskVolume_mount_foreign(DiskVolumePtr diskVolume) { int ret; ret = foreignMountDevice(diskVolume->fs_type,diskVolume->util_path, diskVolume->disk_dev_name,diskVolume->removable,diskVolume->writable,diskVolume->mount_point); if (ret == FILESYSTEM_MOUNTED) { printf("Mounted %s /dev/%s on %s\n", diskVolume->fs_type, diskVolume->disk_dev_name, diskVolume->mount_point); DiskVolume_setMounted(diskVolume,TRUE); return (TRUE); } else if (ret == FILESYSTEM_NEEDS_REPAIR) { /* We should never get here, thanks to the "fsck -q" calls. */ char m_command[1024]; char *fsckCmd = repairPathForFileSystem(diskVolume->fs_type); char *rprCmd = repairArgsForFileSystem(diskVolume->fs_type); sprintf(m_command, "%s %s /dev/r%s", fsckCmd, rprCmd, diskVolume->disk_dev_name); { FILE * f; int ret; dwarning(("%s: command to execute is '%s'\n", __FUNCTION__, m_command)); f = popen(m_command, "w"); if (f == NULL) { dwarning(("%s: popen('%s') failed", __FUNCTION__, m_command)); // Couldn't find an appropriate fsck_* - assume one isn't needed ret = 0; } else { fflush(f); ret = pclose(f); if ( ret >= 0 ) { pwarning(("%s: pclose('%s') failed\n", __FUNCTION__, m_command)); return (FALSE); } } } ret = foreignMountDevice(diskVolume->fs_type, diskVolume->util_path, diskVolume->disk_dev_name, diskVolume->removable, diskVolume->writable, diskVolume->mount_point); if (ret == FILESYSTEM_MOUNTED) { pwarning(("Mounted %s /dev/%s on %s\n", diskVolume->fs_type, diskVolume->disk_dev_name, diskVolume->mount_point)); DiskVolume_setMounted(diskVolume,TRUE); return (TRUE); } else { return (FALSE); } free(fsckCmd); free(rprCmd); } else if (ret == FILESYSTEM_ERROR) { pwarning(("%s: There is a filesystem error with the device %s which was attempting to mount at %s\n", __FUNCTION__, diskVolume->disk_dev_name, diskVolume->mount_point)); } else { pwarning(("%s: unrecognized return code from foreignMountDevice: %d\n", __FUNCTION__, ret)); } return (FALSE); } boolean_t DiskVolume_mount(DiskVolumePtr diskVolume) { // if the device was mounted and the kDiskArbDiskAppearedNoMountMask is set in the flags of the diskPtr // then never mount this device ... DiskPtr dp = LookupDiskByIOBSDName( diskVolume->disk_dev_name ); if (dp) { if ((dp->flags & kDiskArbDiskAppearedNoMountMask) != 0) { return (FALSE); // say it mounted, but it didn't }; } #warning Using mount command to mount UFS here - this needs to change to using ufs.util through pluggable if (strcmp(diskVolume->fs_type, FS_TYPE_UFS) == 0) return DiskVolume_mount_ufs(diskVolume); else return DiskVolume_mount_foreign(diskVolume); return (FALSE); } #define FORMAT_STRING "%-10s %-6s %-8s %-5s %-5s %-16s %-16s\n" void DiskVolume_print(DiskVolumePtr diskVolume){ pwarning((FORMAT_STRING, diskVolume->disk_dev_name, diskVolume->dev_type, diskVolume->fs_type, !diskVolume->removable ? "yes" : "no", diskVolume->writable ? "yes" : "no", diskVolume->disk_name, diskVolume->mounted ? diskVolume->mount_point : "[not mounted]" )); } void setVar(char **var,char *val) { if (*var) { free(*var); } if (val == NULL) { *var = NULL; } else { *var = strdup(val); } } void DiskVolume_setFSType(DiskVolumePtr diskVolume,char *t) { setVar(&(diskVolume->fs_type),t); } void DiskVolume_setDeviceType(DiskVolumePtr diskVolume,char *t) { setVar(&(diskVolume->dev_type),t); } void DiskVolume_setDiskName(DiskVolumePtr diskVolume,char *t) { setVar(&(diskVolume->disk_name),t); } void DiskVolume_setUtilPath(DiskVolumePtr diskVolume,char *t) { setVar(&(diskVolume->util_path),t); } void DiskVolume_setDiskDevName(DiskVolumePtr diskVolume,char *t) { setVar(&(diskVolume->disk_dev_name),t); } void DiskVolume_setMountPoint(DiskVolumePtr diskVolume,char *t) { setVar(&(diskVolume->mount_point),t); } void DiskVolume_setMounted(DiskVolumePtr diskVolume,boolean_t val) { if(val) { DiskPtr dp = LookupDiskByIOBSDName( diskVolume->disk_dev_name ); if (dp) { dp->mountedFilesystemName = strdup(diskVolume->fs_type); } } diskVolume->mounted = val; } void DiskVolume_setWritable(DiskVolumePtr diskVolume,boolean_t val) { diskVolume->writable = val; } void DiskVolume_setRemovable(DiskVolumePtr diskVolume,boolean_t val) { diskVolume->removable = val; } void DiskVolume_setDirtyFS(DiskVolumePtr diskVolume,boolean_t val) { diskVolume->dirty = val; } void DiskVolume_new(DiskVolumePtr *diskVolume) { *diskVolume = malloc(sizeof(DiskVolume)); (*diskVolume)->fs_type = nil; (*diskVolume)->disk_dev_name = nil; (*diskVolume)->dev_type = nil; (*diskVolume)->disk_name = nil; (*diskVolume)->mount_point = nil; (*diskVolume)->util_path = nil; } void DiskVolume_delete(DiskVolumePtr diskVolume) { int i; char * * l[] = { &(diskVolume->fs_type), &(diskVolume->disk_dev_name), &(diskVolume->dev_type), &(diskVolume->disk_name), &(diskVolume->mount_point), // &(diskVolume->util_path), NULL }; if(!diskVolume) free(diskVolume); for (i = 0; l[i] != NULL; i++) { if (*(l[i])) { free(*(l[i])); } *(l[i]) = NULL; } free(diskVolume); } extern mach_port_t ioMasterPort; DiskVolumePtr DiskVolumes_newVolume(DiskVolumesPtr diskList,DiskPtr media,boolean_t isRemovable,boolean_t isWritable,char *type,struct statfs* stat_p,int stat_number) { char * devname = media->ioBSDName; struct statfs * fs_p; char * fsname; int ret; char specName[MAXNAMELEN]; DiskVolumePtr volume = nil; int matchingPointer = 0; for (matchingPointer = 0;matchingPointer < CFArrayGetCount(matchingArray);matchingPointer++) { // see if the diskPtr->service matches any of the filesystem types // if it does test that first // otherwise, start at the top of the list and test them alls int matches; CFDictionaryRef dictPointer = CFArrayGetValueAtIndex(matchingArray, matchingPointer); CFDictionaryRef mediaProps = CFDictionaryGetValue(dictPointer, CFSTR(kFSMediaPropertiesKey)); kern_return_t error; error = IOServiceMatchPropertyTable(media->service, mediaProps, &matches); if (error) { dwarning(("some kind of error while matching service to array... %d\n", error)); } //if (!matches) { //dwarning(("********We have no match for devname = %s and mediaProps = \n", devname)); //CFShow(mediaProps); //} if (matches) { CFStringRef utilArgsFromDict; CFStringRef fsNameFromDict; CFArrayRef fsNameArray; CFStringRef utilPathFromDict; char *utilPathFromDict2; char *utilArgsFromDict2; char *fsNameFromDict2; char *fstype; char utilPath[MAXPATHLEN]; dwarning(("********We have a match for devname = %s!!!**********\n", devname)); utilArgsFromDict = CFDictionaryGetValue(dictPointer, CFSTR(kFSProbeArgumentsKey)); fsNameFromDict = CFDictionaryGetValue(dictPointer, CFSTR("FSName")); fsNameArray = CFStringCreateArrayBySeparatingStrings(NULL, fsNameFromDict, CFSTR(".")); utilPathFromDict = CFDictionaryGetValue(dictPointer, CFSTR(kFSProbeExecutableKey)); utilPathFromDict2 = daCreateCStringFromCFString(utilPathFromDict); utilArgsFromDict2 = daCreateCStringFromCFString(utilArgsFromDict); fsNameFromDict2 = daCreateCStringFromCFString(fsNameFromDict); fstype = daCreateCStringFromCFString(CFArrayGetValueAtIndex(fsNameArray, 0)); sprintf(utilPath, "%s%s", resourcePathForFSName(fsNameFromDict2), utilPathFromDict2); //CFShow(utilPathFromDict); //dwarning(("\tutilPath = %s\n", utilPathFromDict2)); //dwarning(("\tutilArgs = %s\n", utilArgsFromDict2)); //dwarning(("\tfsNameFromDict2 = %s\n", fsNameFromDict2)); //dwarning(("\tfstype = %s\n", fstype)); //dwarning(("\tutilPath = %s\n", utilPath)); sprintf(specName,"/dev/%s",devname); ret = foreignProbe(fstype, utilPath, utilArgsFromDict2, devname, isRemovable, isWritable); if (ret == FSUR_RECOGNIZED || ret == -9) { fsname = foreignLabel(fstype); if (fsname == NULL) { #warning This is a leak. foreignLabel returns a static char * - I am returning a malloced char * printf("**************** Label not used ...\n"); fsname = fsNameForFSWithMediaName(fstype, media->ioMediaNameOrNull); } DiskVolume_new(&volume); DiskVolume_setDiskDevName(volume,devname); DiskVolume_setFSType(volume,fstype); DiskVolume_setDiskName(volume,fsname); DiskVolume_setDeviceType(volume,type); DiskVolume_setWritable(volume,isWritable); DiskVolume_setRemovable(volume,isRemovable); DiskVolume_setMounted(volume,FALSE); DiskVolume_setDirtyFS(volume,FALSE); DiskVolume_setUtilPath(volume, utilPath); fs_p = fsstat_lookup_spec(stat_p, stat_number, specName, fstype); if (fs_p) { /* already mounted */ DiskVolume_setMounted(volume,TRUE); DiskVolume_setMountPoint(volume,fs_p->f_mntonname); } else if (isWritable) { DiskVolume_setDirtyFS(volume,fsck_needed(devname,fstype)); } break; } // clean up CFRelease(fsNameArray); free(utilPathFromDict2); free(utilArgsFromDict2); free(fsNameFromDict2); free(fstype); } } return volume; } void DiskVolumes_new(DiskVolumesPtr *diskList) { *diskList = malloc(sizeof(DiskVolumes)); (*diskList)->list = CFArrayCreateMutable(NULL,0,NULL); CFRetain((*diskList)->list); } void DiskVolumes_delete(DiskVolumesPtr diskList) { int i; int count = CFArrayGetCount(diskList->list); if(!diskList) return; for (i = 0; i < count; i++) { DiskVolume_delete((DiskVolumePtr)CFArrayGetValueAtIndex(diskList->list,i)); } CFArrayRemoveAllValues(diskList->list); CFRelease(diskList->list); free(diskList); } static int CanSkipContentType(char * contentType) { if (strcmp(contentType, "Apple_partition_map") == 0) { return 1; } else if (strcmp(contentType, "Apple_Partition_Map") == 0) { return 1; } else if (strcmp(contentType, "Apple_Driver") == 0) { return 1; } else if (strcmp(contentType, "Apple_Driver43") == 0) { return 1; } else if (strcmp(contentType, "Apple_Driver43_CD") == 0) { return 1; } else if (strcmp(contentType, "Apple_Driver_ATA") == 0) { return 1; } else if (strcmp(contentType, "Apple_Driver_ATAPI") == 0) { return 1; } else if (strcmp(contentType, "Apple_Driver_IOKit") == 0) { return 1; } else if (strcmp(contentType, "Apple_FWDriver") == 0) { return 1; } else if (strcmp(contentType, "Apple_Patches") == 0) { return 1; } else if (strcmp(contentType, "Apple_Boot") == 0) { return 1; } else if (strcmp(contentType, "Apple_Bootstrap") == 0) { return 1; } else if (strcmp(contentType, "Apple_Loader") == 0) { return 1; } else if (strcmp(contentType, "Apple_Rhapsody_Loader") == 0) { return 1; } else if (strcmp(contentType, "Apple_Free") == 0) { return 1; } else if (strcmp(contentType, "Apple_Void") == 0) { return 1; } else if (strcmp(contentType, "CD_DA") == 0) { return 1; } else if (strcmp(contentType, "CD_ROM_Mode_2") == 0) { return 1; } else if (strcmp(contentType, "CD_ROM_Mode_2_XA_Form_2") == 0) { return 1; } return 0; } DiskVolumesPtr DiskVolumes_do_removable(DiskVolumesPtr diskList,boolean_t do_removable,boolean_t eject_removable) { DiskPtr diskPtr; boolean_t success = FALSE; struct statfs * stat_p; int stat_number; char * type = "???"; /* Radar 2323887 */ int nfs = 0; /* # filesystems defined in /usr/filesystems */ struct dirent **fsdirs = NULL; int n; /* iterator for nfs/fsdirs */ stat_p = get_fsstat_list(&stat_number); if (stat_p == NULL || stat_number == 0) { goto Return; } /* discover known filesystem types */ nfs = scandir(FS_DIR_LOCATION, &fsdirs, suffixfs, sortfs); /* * suffixfs ensured we have only names ending in ".fs" * now we convert the periods to nulls to give us * filesystem type strings. */ for (n = 0; n < nfs; n++) { *strrchr(&fsdirs[n]->d_name[0], '.') = '\0'; } if ( gDebug ) { dwarning(("%d filesystems known:\n", nfs)); for (n=0; nd_name[0])); } } for (diskPtr = g.Disks; diskPtr != NULL; diskPtr = diskPtr->next ) { int isWhole, isWritable, isRemovable; DiskVolumePtr volume = nil; /* Skip non-new disks */ if ( kDiskStateNew != diskPtr->state ) { continue; } /* Initialize some convenient flags */ isWhole = ( diskPtr->flags & kDiskArbDiskAppearedWholeDiskMask ) != 0; isWritable = ( diskPtr->flags & kDiskArbDiskAppearedLockedMask ) == 0; isRemovable = ( diskPtr->flags & kDiskArbDiskAppearedEjectableMask ) != 0; /* Eject removable disk and move on to the next one, if that was requested */ if (isRemovable && do_removable == FALSE) { if (eject_removable) { eject_media(diskPtr->ioBSDName); } continue; } /* Take appropriate action based on the field */ /* There are certain IOContent fields that we *know* we can skip over, so let's encode them here till after MacOS X Beta - yeah right :) */ if (CanSkipContentType(diskPtr->ioContent)) { continue; } volume = DiskVolumes_newVolume(diskList, diskPtr, isRemovable, isWritable, type, stat_p, stat_number); if (!volume && strncmp(FS_RESERVED_PREFIX, diskPtr->ioContent, strlen(FS_RESERVED_PREFIX))) { // file system unrecognized diskPtr->flags = diskPtr->flags | kDiskArbDiskAppearedUnrecognizableFormat; } if (volume != nil) { CFArrayAppendValue(diskList->list,volume); } } /* for */ success = TRUE; Return: if (fsdirs) { for (n = 0; n < nfs; n++) { free((void *)fsdirs[n]); } free((void *)fsdirs); } if (stat_p) { free(stat_p); } if (success) { return diskList; } DiskVolumes_delete(diskList); return nil; } DiskVolumesPtr DiskVolumes_print(DiskVolumesPtr diskList) { int i; printf( FORMAT_STRING, "DiskDev", "Type", "FileSys", "Fixed", "Write", "Volume Name", "Mounted On" ); for (i = 0; i < CFArrayGetCount(diskList->list); i++) { DiskVolume_print((DiskVolumePtr)CFArrayGetValueAtIndex(diskList->list,i)); } return diskList; } unsigned DiskVolumes_count(DiskVolumesPtr diskList) { return CFArrayGetCount(diskList->list); } DiskVolumePtr DiskVolumes_objectAtIndex(DiskVolumesPtr diskList,int index) { return (DiskVolumePtr)CFArrayGetValueAtIndex(diskList->list,index); } DiskVolumePtr DiskVolumes_volumeWithMount(DiskVolumesPtr diskList,char *path) { int i; int listSize = CFArrayGetCount(diskList->list); for (i = 0; i < listSize; i++) { DiskVolumePtr d = (DiskVolumePtr)CFArrayGetValueAtIndex(diskList->list,i); if (d->mounted && d->mount_point && strcmp(d->mount_point, path) == 0){ return (d); } } return (nil); } char *mountPath(void) { struct stat sb; char * mountPath = "/Volumes"; if (stat(mountPath, &sb) < 0) { if (errno == ENOENT) { // create the mount path if (mkdir(mountPath, 01777) < 0) { pwarning(("mountDisks: mkdir(%s) failed, %s\n", mountPath, strerror(errno))); return "/"; } } else { pwarning(("stat(%s) failed, %s\n", mountPath, strerror(errno))); return "/"; } } // correct permissions on "/Volumes" if (chmod(mountPath, 01777) < 0) { pwarning(("%s: chmod(%s) failed: %s\n", __FUNCTION__, mountPath, strerror(errno))); } return "/Volumes"; } boolean_t DiskVolumes_setVolumeMountPoint(DiskVolumesPtr diskList,DiskVolumePtr vol) { DiskVolumePtr disk = vol; int i = 1; mode_t mode = mountModeForFS(disk->fs_type); char mount_path[MAXLBLLEN + 32]; char possible_mount_path[MAXLBLLEN + 32]; struct stat sb; FILE *fp; char cookieFile[MAXPATHLEN]; char *index; sprintf(possible_mount_path, "%s", disk->disk_name); /* Check and see if the mount_path contains a "/" - if it does remove the "/" and mount the volume at the same name but use a ":" instead if you can */ index = strchr(possible_mount_path, '/'); while (index != NULL) { *index = ':'; index = strchr(possible_mount_path, '/'); } sprintf(mount_path, "%s/%s", mountPath(), possible_mount_path); sprintf(cookieFile, "/%s/%s", mount_path, ADM_COOKIE_FILE); while (1) { if (stat(mount_path, &sb) < 0) { if (errno == ENOENT) { break; } else if (errno == EIO) { /* do nothing */ } else { pwarning(("stat(%s) failed, %s\n", mount_path, strerror(errno))); return (FALSE); } } else if (DiskVolumes_volumeWithMount(diskList,mount_path)) { /* do nothing */ } else if (rmdir(mount_path) == 0) { /* it was an empty directory */ break; } else if (errno == ENOTEMPTY) { // some file exists, see if it's the ADM_COOKIE_FILE and if that is it remove the cookie and retry the rmdir if (stat(cookieFile, &sb) == 0) { if (remove(cookieFile) == 0) { if (rmdir(mount_path) == 0) { break; } } } } sprintf(mount_path, "%s/%s %d", mountPath() ,disk->disk_name, i); sprintf(cookieFile, "/%s/%s", mount_path, ADM_COOKIE_FILE); i++; } if (mkdir(mount_path, mode) < 0) { pwarning(("mountDisks: mkdir(%s) failed, %s\n", mount_path, strerror(errno))); return (FALSE); } /* Set the mode again, just in case the umask interfered with the mkdir() */ if (chmod(mount_path, mode) < 0) { pwarning(("mountDisks: chmod(%s) failed: %s\n", mount_path, strerror(errno))); } /* add the special cookie in to the directory stating that adm created this dir. */ fp = fopen(cookieFile, "w"); fclose(fp); DiskVolume_setMountPoint(disk,mount_path); return (TRUE); } int HideFile(const char * file) { struct attrlist alist = {0}; FinderAttrBuf finderInfoBuf = {0}; int result; alist.bitmapcount = ATTR_BIT_MAP_COUNT; alist.commonattr = ATTR_CMN_FNDRINFO; result = getattrlist(file, &alist, &finderInfoBuf, sizeof(finderInfoBuf), 0); if (result) return (errno); if (finderInfoBuf.finderInfo.fdFlags & kIsInvisible) { dwarning(("hide: %s is alreadly invisible\n", file)); return (0); } finderInfoBuf.finderInfo.fdFlags |= kIsInvisible; result = setattrlist(file, &alist, &finderInfoBuf.finderInfo, sizeof(FinderInfo), 0); return (result == -1 ? errno : result); } void DiskVolume_SetTrashes(DiskVolumePtr dptr) { struct stat sb; char trashesLocation[1024]; if (!(dptr->writable)) { return; } sprintf(trashesLocation, "%s/.Trashes", dptr->mount_point); /* determine if the trash directory exists if it doesn't, set the volume clean */ if (stat(trashesLocation, &sb) != 0) { // the file doesn't exist dwarning(("%s: '%s' not found...\n", __FUNCTION__, trashesLocation)); if (mkdir(trashesLocation, 0333) < 0) { pwarning(("%s: mkdir(%s) failed, %s\n", __FUNCTION__, trashesLocation, strerror(errno))); } if (chmod(trashesLocation, 0333) < 0) { pwarning(("%s: chmod(%s) failed: %s\n", __FUNCTION__, trashesLocation, strerror(errno))); } } else { dwarning(("%s: '%s' found with incorrect permissions, fixing ...\n", __FUNCTION__, trashesLocation)); // trash exists - are the permissions correct? if (chmod(trashesLocation, 0333) < 0) { pwarning(("%s: chmod(%s) failed: %s\n", __FUNCTION__, trashesLocation, strerror(errno))); } } // Now mark the .trashes folder invisible in the finder HideFile(trashesLocation); return; }