/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (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. * * This 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@ */ /* * hfsVols.c * - implements a table of hfs volume entries with creation/lookup functions * - the volume entry maps between the hfs volume name and its mount point */ /* * Modification History: * * May 15, 1998 Dieter Siegmund (dieter@apple) * - created */ #include #include #include #include #include #include #include #include #include #include #include #include #include "hfsvols.h" #include "afp.h" #include "dynarray.h" typedef struct { long length; long device_id; u_long signature; attrreference_t volume_name; u_char extra[512]; } volumeInfo_t; static boolean_t volumeInfo_get(u_char * path, volumeInfo_t * volinfo) { struct attrlist attrspec; bzero(volinfo, sizeof(*volinfo)); attrspec.bitmapcount = ATTR_BIT_MAP_COUNT; attrspec.reserved = 0; attrspec.commonattr = ATTR_CMN_DEVID; attrspec.volattr = ATTR_VOL_SIGNATURE | ATTR_VOL_INFO | ATTR_VOL_NAME; attrspec.dirattr = 0; attrspec.fileattr = 0; attrspec.forkattr = 0; if (getattrlist(path, &attrspec, volinfo, sizeof(*volinfo), 0)) { #ifdef DEBUG perror("getattrlist"); #endif DEBUG return (FALSE); } return (TRUE); } /* Signatures used to differentiate between HFS and HFS Plus volumes */ enum { kSignatureHFS = 0x4244, /* 'BD' in ASCII */ kSignatureHFSPlus = 0x482b, /* 'H+' in ASCII */ }; static u_char * S_get_volume_name(volumeInfo_t * volinfo, int * len_p) { u_char * source_name; source_name = ((u_char *)&volinfo->volume_name) + volinfo->volume_name.attr_dataoffset; *len_p = volinfo->volume_name.attr_length; return (source_name); } static __inline__ void print_fsstat_list(struct statfs * stat_p, int number) { int i; for (i = 0; i < number; i++) { struct statfs * p = stat_p + i; printf("%s (%x %x) on %s from %s\n", p->f_fstypename, p->f_fsid.val[0], p->f_fsid.val[1], p->f_mntonname, p->f_mntfromname); } } static __inline__ 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 __inline__ struct statfs * fsstat_lookup(struct statfs * list_p, int n, dev_t dev) { struct statfs * scan; int i; for (i = 0, scan = list_p; i < n; i++, scan++) { if (scan->f_fsid.val[0] == dev) return (scan); } return (NULL); } static void hfsVol_print(hfsVol_t * entry) { printf("%s: mounted on %s from %s, device_id 0x%x (%ld)\n", entry->name, entry->mounted_on, entry->mounted_from, (int)entry->device_id, entry->device_id); return; } hfsVol_t * hfsVolList_entry(hfsVolList_t vols, int i) { dynarray_t * list = (dynarray_t *)vols; return (dynarray_element(list, i)); } int hfsVolList_count(hfsVolList_t vols) { dynarray_t * list = (dynarray_t *)vols; return (dynarray_count(list)); } void hfsVolList_print(hfsVolList_t vols) { dynarray_t * list = (dynarray_t *)vols; int i; printf("There are %d HFS+ volume(s) on this computer\n", dynarray_count(list)); for (i = 0; i < dynarray_count(list); i++) { hfsVol_t * entry = (hfsVol_t *)dynarray_element(list, i); hfsVol_print(entry); } return; } void hfsVolList_free(hfsVolList_t * l) { dynarray_t * list; if (l == NULL) return; list = *((dynarray_t * *)l); if (list == NULL) return; dynarray_free(list); free(list); *l = NULL; return; } hfsVolList_t hfsVolList_init() { dynarray_t * list = NULL; int i; struct statfs * stat_p; int stat_number; stat_p = get_fsstat_list(&stat_number); if (stat_p == NULL || stat_number == 0) goto err; for (i = 0; i < stat_number; i++) { hfsVol_t * entry; struct statfs * p = stat_p + i; volumeInfo_t volinfo; int mounted_on_len = 0; int mounted_from_len = 0; u_char * name = NULL; int name_len = 0; if (strcmp(p->f_fstypename, "hfs")) continue; if (volumeInfo_get(p->f_mntonname, &volinfo) == FALSE) continue; if (volinfo.signature != kSignatureHFSPlus) continue; if (list == NULL) { list = (dynarray_t *)malloc(sizeof(*list)); if (list == NULL) { goto err; } bzero(list, sizeof(*list)); dynarray_init(list, free, NULL); } mounted_on_len = strlen(p->f_mntonname); mounted_from_len = strlen(p->f_mntfromname); name = S_get_volume_name(&volinfo, &name_len); entry = malloc(sizeof(*entry) + mounted_on_len + mounted_from_len + name_len + 3); if (entry == NULL) continue; bzero(entry, sizeof(*entry)); entry->device_id = volinfo.device_id; entry->mounted_on = (char *)(entry + 1); strncpy(entry->mounted_on, p->f_mntonname, mounted_on_len); entry->mounted_on[mounted_on_len] = '\0'; entry->mounted_from = entry->mounted_on + mounted_on_len + 1; strncpy(entry->mounted_from, p->f_mntfromname, mounted_from_len); entry->mounted_from[mounted_from_len] = '\0'; entry->name = entry->mounted_from + mounted_from_len + 1; strncpy(entry->name, name, name_len); entry->name[name_len] = '\0'; dynarray_add(list, entry); } err: if (stat_p) { free(stat_p); } return ((hfsVolList_t)list); } typedef struct { u_long len; u_long finderInfo[8]; } finderInfo_t; static __inline__ void S_print_finderInfo(finderInfo_t * finder) { int i; char * cptr = (u_char *)finder->finderInfo; printf("we got %ld bytes back\n", finder->len); for (i = 0; i < 32; i++) printf(" %c", cptr[i]); printf("\n"); return; } /* * Function: hfs_set_file_size * * Purpose: * Set a file to be a certain length. */ int hfs_set_file_size(int fd, off_t size) { #ifdef F_SETSIZE fcntl(fd, F_SETSIZE, &size); #endif F_SETSIZE return (ftruncate(fd, size)); } /* * Function: hfs_copy_finder_info * * Purpose: * Copy the finder information of one file to another file. */ boolean_t hfs_copy_finder_info(u_char * target_path, u_char * source_path) { struct attrlist attrspec; finderInfo_t finder; bzero(&finder, sizeof(finder)); attrspec.bitmapcount = ATTR_BIT_MAP_COUNT; attrspec.reserved = 0; attrspec.commonattr = ATTR_CMN_FNDRINFO; attrspec.volattr = 0; attrspec.dirattr = 0; attrspec.fileattr = 0; attrspec.forkattr = 0; /* if no source path, target is source */ if (source_path == NULL) source_path = target_path; if (getattrlist(source_path, &attrspec, &finder, sizeof(finder), 0)) return (FALSE); if (setattrlist(target_path, &attrspec, finder.finderInfo, sizeof(finder.finderInfo), 0)) return (FALSE); return (TRUE); } #ifdef TEST_HFSVOLS #include #include #include int main(int argc, u_char * argv[]) { int number; hfsVolList_t vlist; int ret; vlist = hfsVolList_init(); if (vlist) hfsVolList_print(vlist); exit(0); } #endif TEST_HFSVOLS