int main(int argc, char *argv[]) { char *path = NULL; struct attrlist alist; struct directoryinfo dirinfo; struct volumeinfo volinfo; struct statfs sfs; path = argv[1]; bzero(&alist, sizeof(alist)); alist.bitmapcount = 5; alist.commonattr = ATTR_CMN_OBJID; getattrlist(path, &alist, &dirinfo, sizeof(dirinfo), 0); printf("directory id: %lu\n", dirinfo.dirid); statfs(path, &sfs); printf("mountpoint: %s\n", sfs.f_mntonname); alist.commonattr = ATTR_CMN_FNDRINFO; alist.volattr = ATTR_VOL_INFO; getattrlist(sfs.f_mntonname, &alist, &volinfo, sizeof(volinfo), 0); volinfo.finderinfo[2] = dirinfo.dirid; setattrlist(sfs.f_mntonname, &alist, volinfo.finderinfo, sizeof(volinfo.finderinfo), 0); return EXIT_SUCCESS; }
int main(int argc, char **argv) { int i; struct attrlist attrs; struct attr_buffer attrbuf; if (argc < 2) { fprintf(stderr, "Usage: checktrigger <pathname>...\n"); return 1; } argv++; argc--; for (i = 0; i < argc; i++) { memset(&attrs, 0, sizeof(attrs)); attrs.bitmapcount = ATTR_BIT_MAP_COUNT; attrs.dirattr = ATTR_DIR_MOUNTSTATUS; if (getattrlist(argv[i], &attrs, &attrbuf, sizeof attrbuf, FSOPT_NOFOLLOW) == -1) { fprintf(stderr, "checktrigger: getattrlist of %s failed: %s\n", argv[i], strerror(errno)); return 2; } printf("%s %s a trigger\n", argv[i], (attrbuf.mount_flags & DIR_MNTSTATUS_TRIGGER) ? "is" : "is not"); } return 0; }
/** Checks that the basename component of the input path exactly * matches the canonical case of the path on disk. * It only makes sense to call this function on a case insensitive filesystem. * If the case does not match, throws an exception. */ static void checkCanonicalBaseName(const char *path) { #ifdef __APPLE__ struct attrlist attrlist; struct { uint32_t len; attrreference_t ref; char canonical_name[WATCHMAN_NAME_MAX]; } vomit; w_string_piece pathPiece(path); auto base = pathPiece.baseName(); memset(&attrlist, 0, sizeof(attrlist)); attrlist.bitmapcount = ATTR_BIT_MAP_COUNT; attrlist.commonattr = ATTR_CMN_NAME; if (getattrlist(path, &attrlist, &vomit, sizeof(vomit), FSOPT_NOFOLLOW) == -1) { throw std::system_error(errno, std::generic_category(), to<std::string>("checkCanonicalBaseName(", path, "): getattrlist failed")); } w_string_piece name(((char *)&vomit.ref) + vomit.ref.attr_dataoffset); if (name != base) { throw std::system_error( ENOENT, std::generic_category(), to<std::string>("checkCanonicalBaseName(", path, "): (", name, ") doesn't match canonical base (", base, ")")); } #else // Older Linux and BSDish systems are in this category. // This is the awful portable fallback used in the absence of // a system specific way to detect this. w_string_piece pathPiece(path); auto parent = pathPiece.dirName().asWString(); auto dir = w_dir_open(parent.c_str()); auto base = pathPiece.baseName(); while (true) { auto ent = dir->readDir(); if (!ent) { // We didn't find an entry that exactly matched -> fail throw std::system_error( ENOENT, std::generic_category(), to<std::string>("checkCanonicalBaseName(", path, "): no match found in parent dir")); } // Note: we don't break out early if we get a case-insensitive match // because the dir may contain multiple representations of the same // name. For example, Bash-for-Windows has dirs that contain both // "pod" and "Pod" dirs in its perl installation. We want to make // sure that we've observed all of the entries in the dir before // giving up. if (w_string_piece(ent->d_name) == base) { // Exact match; all is good! return; } } #endif }
CFStringRef _DAFileSystemCopyName( DAFileSystemRef filesystem, CFURLRef mountpoint ) { struct attr_name_t { uint32_t size; attrreference_t data; char name[MAXNAMLEN + 1]; }; struct attr_name_t attr = { 0 }; struct attrlist attrlist = { 0 }; CFStringRef name = NULL; char * path = NULL; int status = 0; attrlist.bitmapcount = ATTR_BIT_MAP_COUNT; attrlist.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME; path = ___CFURLCopyFileSystemRepresentation( mountpoint ); if ( path == NULL ) goto _DAFileSystemCopyNameErr; status = getattrlist( path, &attrlist, &attr, sizeof( attr ), 0 ); if ( status == -1 ) goto _DAFileSystemCopyNameErr; if ( attr.data.attr_length ) { name = CFStringCreateWithCString( kCFAllocatorDefault, ( ( char * ) &attr.data ) + attr.data.attr_dataoffset, kCFStringEncodingUTF8 ); } _DAFileSystemCopyNameErr: if ( path ) free( path ); return name; }
struct timespec get_birthtime(const char* path) { struct attrlist attrlist; struct { u_int32_t length; struct timespec ts; } attrbuf; int err; bzero(&attrlist, sizeof(attrlist)); attrlist.bitmapcount = ATTR_BIT_MAP_COUNT; attrlist.commonattr = ATTR_CMN_CRTIME; err = getattrlist( path, &attrlist, &attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW ); if(err != 0) { perror("getattrlist"); exit(EXIT_FAILURE); } if(attrbuf.length != sizeof(attrbuf)) { printf("ERROR: getattrlist failed to get birthtime\n"); exit(EXIT_FAILURE); } return attrbuf.ts; }
int BLGetVolumeFinderInfo(BLContextPtr context, const char * mountpoint, uint32_t * words) { int err, i; struct volinfobuf vinfo; struct attrlist alist; alist.bitmapcount = 5; alist.reserved = 0; alist.commonattr = ATTR_CMN_FNDRINFO; alist.volattr = ATTR_VOL_INFO; alist.dirattr = 0; alist.fileattr = 0; alist.forkattr = 0; err = getattrlist(mountpoint, &alist, &vinfo, sizeof(vinfo), 0); if(err) { contextprintf(context, kBLLogLevelError, "Can't get volume information for %s\n", mountpoint ); return 1; } /* Finder info words are just opaque and in big-endian format on disk for HFS+ */ for(i=0; i<6; i++) { words[i] = CFSwapInt32BigToHost(vinfo.finderinfo[i]); } *(uint64_t *)&words[6] = CFSwapInt64BigToHost( (*(uint64_t *)&vinfo.finderinfo[6])); return 0; }
long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5) { struct attrlist * attrlist = (void *)arg2; long ret; #if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__) gemu_log("SYS_getdirentriesattr unimplemented\n"); return -ENOTSUP; #endif /* XXX: don't let the %s stay in there */ DPRINTF("getattrlist(%s, %p, %p, 0x%x, 0x%x)\n", (char *)arg1, arg2, arg3, arg4, arg5); if(arg2) /* XXX: We should handle that in a copy especially if the structure is not writable */ byteswap_attrlist(attrlist); ret = get_errno(getattrlist((const char* )arg1, attrlist, (void *)arg3, arg4, arg5)); if(!is_error(ret)) { byteswap_attrbuf((void *)arg3, attrlist); byteswap_attrlist(attrlist); } return ret; }
CAMLprim value getFileInfos (value path, value need_size) { #ifdef __APPLE__ CAMLparam1(path); CAMLlocal3(res, fInfo, length); int retcode; struct attrlist attrList; unsigned long options = FSOPT_REPORT_FULLSIZE; struct { u_int32_t length; char finderInfo [32]; off_t rsrcLength; } __attribute__ ((packed)) attrBuf; attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.reserved = 0; attrList.commonattr = ATTR_CMN_FNDRINFO; attrList.volattr = 0; /* volume attribute group */ attrList.dirattr = 0; /* directory attribute group */ if (Bool_val (need_size)) attrList.fileattr = ATTR_FILE_RSRCLENGTH; /* file attribute group */ else attrList.fileattr = 0; attrList.forkattr = 0; /* fork attribute group */ retcode = getattrlist(String_val (path), &attrList, &attrBuf, sizeof attrBuf, options); if (retcode == -1) uerror("getattrlist", path); if (Bool_val (need_size)) { if (attrBuf.length != sizeof attrBuf) unix_error (EINVAL, "getattrlist", path); } else { if (attrBuf.length != sizeof (u_int32_t) + 32) unix_error (EINVAL, "getattrlist", path); } fInfo = alloc_string (32); memcpy (String_val (fInfo), attrBuf.finderInfo, 32); if (Bool_val (need_size)) length = copy_int64 (attrBuf.rsrcLength); else length = copy_int64 (0); res = alloc_small (2, 0); Field (res, 0) = fInfo; Field (res, 1) = length; CAMLreturn (res); #else unix_error (ENOSYS, "getattrlist", path); #endif }
int osx_attr_getattrlist (const char *path, struct attrlist * attrList, void * attrBuf, size_t attrBufSize, unsigned long options) { int r; caml_release_runtime_system(); r = getattrlist(path, attrList, attrBuf, attrBufSize, options); caml_acquire_runtime_system(); return r; }
static int loopback_getxtimes(const char *path, struct timespec *bkuptime, struct timespec *crtime) { int res = 0; struct attrlist attributes; attributes.bitmapcount = ATTR_BIT_MAP_COUNT; attributes.reserved = 0; attributes.commonattr = 0; attributes.dirattr = 0; attributes.fileattr = 0; attributes.forkattr = 0; attributes.volattr = 0; struct xtimeattrbuf { uint32_t size; struct timespec xtime; } __attribute__ ((packed)); struct xtimeattrbuf buf; attributes.commonattr = ATTR_CMN_BKUPTIME; res = getattrlist(path, &attributes, &buf, sizeof(buf), FSOPT_NOFOLLOW); if (res == 0) { (void)memcpy(bkuptime, &(buf.xtime), sizeof(struct timespec)); } else { (void)memset(bkuptime, 0, sizeof(struct timespec)); } attributes.commonattr = ATTR_CMN_CRTIME; res = getattrlist(path, &attributes, &buf, sizeof(buf), FSOPT_NOFOLLOW); if (res == 0) { (void)memcpy(crtime, &(buf.xtime), sizeof(struct timespec)); } else { (void)memset(crtime, 0, sizeof(struct timespec)); } return 0; }
uint32_t dirlinkcount(char *path) { struct attrlist al; bzero(&al, sizeof(al)); al.bitmapcount = ATTR_BIT_MAP_COUNT; al.dirattr = ATTR_DIR_LINKCOUNT; struct linkcount_buf_t buf; if (getattrlist(path, &al, &buf, sizeof(buf), 0)) die("getattrlist"); return buf.links; }
int main(int argc, char *argv[]) { char *path = NULL; struct attrlist alist; struct directoryinfo dirinfo; struct volumeinfo volinfo; struct statfs sfs; if (argc <= 1) { fprintf(stderr,"Usage: %s /Volumes/Foo/OpenMe/\n", argv[0]); exit(1); } path = argv[1]; memset(&alist, 0, sizeof(alist)); alist.bitmapcount = 5; alist.commonattr = ATTR_CMN_OBJID; getattrlist(path, &alist, &dirinfo, sizeof(dirinfo), 0); printf("directory id: %lu\n", dirinfo.dirid); statfs(path, &sfs); printf("mountpoint: %s\n", sfs.f_mntonname); alist.commonattr = ATTR_CMN_FNDRINFO; alist.volattr = ATTR_VOL_INFO; getattrlist(sfs.f_mntonname, &alist, &volinfo, sizeof(volinfo), 0); volinfo.finderinfo[2] = dirinfo.dirid; setattrlist(sfs.f_mntonname, &alist, volinfo.finderinfo, sizeof(volinfo.finderinfo), 0); return 0; }
static int darwin_fs_capabilities(const char * path) { int caps = 0; vol_capabilities_attr_t *vcaps; struct attrlist attrlist; char attrbuf[sizeof(u_int32_t) + sizeof(vol_capabilities_attr_t)]; #define FORMAT_CAP(vinfo, cap) \ ( ((vinfo)->valid[VOL_CAPABILITIES_FORMAT] & (cap)) && \ ((vinfo)->capabilities[VOL_CAPABILITIES_FORMAT] & (cap)) ) #define INTERFACE_CAP(vinfo, cap) \ ( ((vinfo)->valid[VOL_CAPABILITIES_INTERFACES] & (cap)) && \ ((vinfo)->capabilities[VOL_CAPABILITIES_INTERFACES] & (cap)) ) ZERO_STRUCT(attrlist); attrlist.bitmapcount = ATTR_BIT_MAP_COUNT; attrlist.volattr = ATTR_VOL_CAPABILITIES; if (getattrlist(path, &attrlist, attrbuf, sizeof(attrbuf), 0) != 0) { DEBUG(0, ("getattrlist for %s capabilities failed: %s\n", path, strerror(errno))); /* Return no capabilities on failure. */ return 0; } vcaps = (vol_capabilities_attr_t *)(attrbuf + sizeof(u_int32_t)); if (FORMAT_CAP(vcaps, VOL_CAP_FMT_SPARSE_FILES)) { caps |= FILE_SUPPORTS_SPARSE_FILES; } if (FORMAT_CAP(vcaps, VOL_CAP_FMT_CASE_SENSITIVE)) { caps |= FILE_CASE_SENSITIVE_SEARCH; } if (FORMAT_CAP(vcaps, VOL_CAP_FMT_CASE_PRESERVING)) { caps |= FILE_CASE_PRESERVED_NAMES; } if (INTERFACE_CAP(vcaps, VOL_CAP_INT_EXTENDED_SECURITY)) { caps |= FILE_PERSISTENT_ACLS; } return caps; }
__private_extern__ u_int32_t volumeCapabilities(const char *path) { struct attrlist alist; bzero(&alist, sizeof(alist)); alist.bitmapcount = ATTR_BIT_MAP_COUNT; alist.volattr = ATTR_VOL_INFO|ATTR_VOL_CAPABILITIES; // XXX: VOL_INFO must always be set struct { u_int32_t v_size; /* Fixed storage */ vol_capabilities_attr_t v_caps; } vinfo; bzero(&vinfo, sizeof(vinfo)); if (0 == getattrlist(path, &alist, &vinfo, sizeof(vinfo), 0) && 0 != (alist.volattr & ATTR_VOL_CAPABILITIES)) { return (vinfo.v_caps.capabilities[VOL_CAPABILITIES_INTERFACES]); } return (0); }
int main(int argc, char *argv[]) { int ret, i; struct volinfobuf vinfo; struct attrlist alist; alist.bitmapcount = 5; alist.reserved = 0; alist.commonattr = ATTR_CMN_FNDRINFO; alist.volattr = ATTR_VOL_INFO; alist.dirattr = 0; alist.fileattr = 0; alist.forkattr = 0; ret = getattrlist(argv[1], &alist, &vinfo, sizeof(vinfo), 0); if(ret) err(1, "getattrlist"); printf("%u\n", ntohl(vinfo.finderinfo[0])); return 0; }
__private_extern__ int ___chattr( const char * path, ___attr_t attr, ___attr_t noattr ) { /* * Change file flags. */ struct __chattrbuf { uint32_t size; uint8_t reserved0032[8]; ___attr_t attr; uint8_t reserved0112[22]; }; typedef struct __chattrbuf __chattrbuf; struct attrlist attributes; __chattrbuf buffer; int status; attributes.bitmapcount = ATTR_BIT_MAP_COUNT; attributes.commonattr = ATTR_CMN_FNDRINFO; attributes.dirattr = 0; attributes.fileattr = 0; attributes.forkattr = 0; attributes.volattr = 0; status = getattrlist( path, &attributes, &buffer, sizeof( buffer ), 0 ); if ( status == 0 ) { buffer.attr = OSSwapHostToBigInt16( ( OSSwapBigToHostInt16( buffer.attr ) & ~noattr ) | attr ); status = setattrlist( path, &attributes, ( ( uint8_t * ) &buffer ) + sizeof( buffer.size ), sizeof( buffer ) - sizeof( buffer.size ), 0 ); } return status; }
struct timespec get_bkuptime(const char* filename) { struct attrlist alist; struct { u_int32_t length; struct timespec ts; } buf; bzero(&alist, sizeof(alist)); alist.bitmapcount = ATTR_BIT_MAP_COUNT; alist.commonattr = ATTR_CMN_BKUPTIME; int err = getattrlist( filename, &alist, &buf, sizeof(buf), FSOPT_NOFOLLOW ); if(err != 0) { perror("getattrlist"); exit(EXIT_FAILURE); } if(buf.length != sizeof(buf)) { printf("ERROR: failed to obtain backuptime\n"); exit(EXIT_FAILURE); } /* // format the date as: 2001_12_28_23_59_59 time_t t = buf.ts.tv_sec; struct tm tm; localtime_r(&t, &tm); char str[50]; strftime(str, 50, "%Y_%m_%d_%H_%M_%S", &tm); puts(str);*/ return buf.ts; }
/* * char *realpath(const char *path, char resolved[PATH_MAX]); * * Find the real name of path, by removing all ".", ".." and symlink * components. Returns (resolved) on success, or (NULL) on failure, * in which case the path which caused trouble is left in (resolved). */ char * realpath(const char *path, char inresolved[PATH_MAX]) { struct attrs attrs; struct stat sb; char *p, *q, *s; size_t left_len, resolved_len, save_resolved_len; unsigned symlinks; int serrno, slen, useattrs, islink; char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; dev_t dev, lastdev; struct statfs sfs; static dev_t rootdev; static int rootdev_inited = 0; ino_t inode; char *resolved; if (path == NULL) { errno = EINVAL; return (NULL); } #if __DARWIN_UNIX03 if (*path == 0) { errno = ENOENT; return (NULL); } #endif /* __DARWIN_UNIX03 */ /* * Extension to the standard; if inresolved == NULL, allocate memory */ if (!inresolved) { if ((resolved = malloc(PATH_MAX)) == NULL) return (NULL); } else { resolved = inresolved; } if (!rootdev_inited) { rootdev_inited = 1; if (stat("/", &sb) < 0) { error_return: if (!inresolved) { int e = errno; free(resolved); errno = e; } return (NULL); } rootdev = sb.st_dev; } serrno = errno; symlinks = 0; if (path[0] == '/') { resolved[0] = '/'; resolved[1] = '\0'; if (path[1] == '\0') { return (resolved); } resolved_len = 1; left_len = strlcpy(left, path + 1, sizeof(left)); } else { #if !defined(VARIANT_DARWINEXTSN) && __DARWIN_UNIX03 /* 4447159: don't use GETPATH, so this will fail if */ /* if parent directories are not readable, as per POSIX */ if (__private_getcwd(resolved, PATH_MAX, 0) == NULL) #else /* VARIANT_DARWINEXTSN || !__DARWIN_UNIX03 */ if (__private_getcwd(resolved, PATH_MAX, 1) == NULL) #endif /* !VARIANT_DARWINEXTSN && __DARWIN_UNIX03 */ { strlcpy(resolved, ".", PATH_MAX); goto error_return; } resolved_len = strlen(resolved); left_len = strlcpy(left, path, sizeof(left)); } if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { errno = ENAMETOOLONG; goto error_return; } if (resolved_len > 1) { if (stat(resolved, &sb) < 0) { goto error_return; } lastdev = sb.st_dev; } else lastdev = rootdev; /* * Iterate over path components in `left'. */ while (left_len != 0) { /* * Extract the next path component and adjust `left' * and its length. */ p = strchr(left, '/'); s = p ? p : left + left_len; if (s - left >= sizeof(next_token)) { errno = ENAMETOOLONG; goto error_return; } memcpy(next_token, left, s - left); next_token[s - left] = '\0'; left_len -= s - left; if (p != NULL) memmove(left, s + 1, left_len + 1); if (resolved[resolved_len - 1] != '/') { if (resolved_len + 1 >= PATH_MAX) { errno = ENAMETOOLONG; goto error_return; } resolved[resolved_len++] = '/'; resolved[resolved_len] = '\0'; } if (next_token[0] == '\0') continue; else if (strcmp(next_token, ".") == 0) continue; else if (strcmp(next_token, "..") == 0) { /* * Strip the last path component except when we have * single "/" */ if (resolved_len > 1) { resolved[resolved_len - 1] = '\0'; q = strrchr(resolved, '/') + 1; *q = '\0'; resolved_len = q - resolved; } continue; } /* * Save resolved_len, so that we can later null out * the the appended next_token, and replace with the * real name (matters on case-insensitive filesystems). */ save_resolved_len = resolved_len; /* * Append the next path component and lstat() it. If * lstat() fails we still can return successfully if * there are no more path components left. */ resolved_len = strlcat(resolved, next_token, PATH_MAX); if (resolved_len >= PATH_MAX) { errno = ENAMETOOLONG; goto error_return; } if (getattrlist(resolved, (void *)&_rp_alist, &attrs, sizeof(attrs), FSOPT_NOFOLLOW) == 0) { useattrs = 1; islink = (attrs.type == VLNK); dev = attrs.dev; inode = attrs.id.fid_objno; } else if (errno == ENOTSUP || errno == EINVAL) { if ((useattrs = lstat(resolved, &sb)) == 0) { islink = S_ISLNK(sb.st_mode); dev = sb.st_dev; inode = sb.st_ino; } } else useattrs = -1; if (useattrs < 0) { #if !__DARWIN_UNIX03 if (errno == ENOENT && p == NULL) { errno = serrno; return (resolved); } #endif /* !__DARWIN_UNIX03 */ goto error_return; } if (dev != lastdev) { /* * We have crossed a mountpoint. For volumes like UDF * the getattrlist name may not match the actual * mountpoint, so we just copy the mountpoint directly. * (3703138). However, the mountpoint may not be * accessible, as when chroot-ed, so check first. * There may be a file on the chroot-ed volume with * the same name as the mountpoint, so compare device * and inode numbers. */ lastdev = dev; if (statfs(resolved, &sfs) == 0 && lstat(sfs.f_mntonname, &sb) == 0 && dev == sb.st_dev && inode == sb.st_ino) { /* * However, it's possible that the mountpoint * path matches, even though it isn't the real * path in the chroot-ed environment, so check * that each component of the mountpoint * is a directory (and not a symlink) */ char temp[sizeof(sfs.f_mntonname)]; char *cp; int ok = 1; strcpy(temp, sfs.f_mntonname); for(;;) { if ((cp = strrchr(temp, '/')) == NULL) { ok = 0; break; } if (cp <= temp) break; *cp = 0; if (lstat(temp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR) { ok = 0; break; } } if (ok) { resolved_len = strlcpy(resolved, sfs.f_mntonname, PATH_MAX); continue; } } /* if we fail, use the other methods. */ } if (islink) { if (symlinks++ > MAXSYMLINKS) { errno = ELOOP; goto error_return; } slen = readlink(resolved, symlink, sizeof(symlink) - 1); if (slen < 0) { goto error_return; } symlink[slen] = '\0'; if (symlink[0] == '/') { resolved[1] = 0; resolved_len = 1; lastdev = rootdev; } else if (resolved_len > 1) { /* Strip the last path component. */ resolved[resolved_len - 1] = '\0'; q = strrchr(resolved, '/') + 1; *q = '\0'; resolved_len = q - resolved; } /* * If there are any path components left, then * append them to symlink. The result is placed * in `left'. */ if (p != NULL) { if (symlink[slen - 1] != '/') { if (slen + 1 >= sizeof(symlink)) { errno = ENAMETOOLONG; goto error_return; } symlink[slen] = '/'; symlink[slen + 1] = 0; } left_len = strlcat(symlink, left, sizeof(symlink)); if (left_len >= sizeof(left)) { errno = ENAMETOOLONG; goto error_return; } } left_len = strlcpy(left, symlink, sizeof(left)); } else if (useattrs) { /* * attrs already has the real name. */ resolved[save_resolved_len] = '\0'; resolved_len = strlcat(resolved, (const char *)&attrs.name + attrs.name.attr_dataoffset, PATH_MAX); if (resolved_len >= PATH_MAX) { errno = ENAMETOOLONG; goto error_return; } } /* * For the case of useattrs == 0, we could scan the directory * and try to match the inode. There are many problems with * this: (1) the directory may not be readable, (2) for multiple * hard links, we would find the first, but not necessarily * the one specified in the path, (3) we can't try to do * a case-insensitive search to match the right one in (2), * because the underlying filesystem may do things like * decompose composed characters. For most cases, doing * nothing is the right thing when useattrs == 0, so we punt * for now. */ } /* * Remove trailing slash except when the resolved pathname * is a single "/". */ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') resolved[resolved_len - 1] = '\0'; return (resolved); }
int statfs_32bit_inode_tests( void * the_argp ) { int my_err, my_count, i; int my_buffer_size; int my_fd = -1; int is_ufs = 0; void * my_bufferp = NULL; struct statfs * my_statfsp; long my_io_size; fsid_t my_fsid; struct attrlist my_attrlist; vol_attr_buf my_attr_buf; kern_return_t my_kr; my_buffer_size = (sizeof(struct statfs) * 10); my_kr = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*)&my_bufferp, my_buffer_size, VM_FLAGS_ANYWHERE); if(my_kr != KERN_SUCCESS){ printf( "vm_allocate failed with error %d - \"%s\" \n", errno, strerror( errno) ); goto test_failed_exit; } my_statfsp = (struct statfs *) my_bufferp; my_err = statfs( "/", my_statfsp ); if ( my_err == -1 ) { printf( "statfs call failed. got errno %d - %s. \n", errno, strerror( errno ) ); goto test_failed_exit; } if ( memcmp( &my_statfsp->f_fstypename[0], "ufs", 3 ) == 0 ) { is_ufs = 1; } my_count = getfsstat( (struct statfs *)my_bufferp, my_buffer_size, MNT_NOWAIT ); if ( my_count == -1 ) { printf( "getfsstat call failed. got errno %d - %s. \n", errno, strerror( errno ) ); goto test_failed_exit; } /* validate results */ my_statfsp = (struct statfs *) my_bufferp; for ( i = 0; i < my_count; i++, my_statfsp++ ) { if ( memcmp( &my_statfsp->f_fstypename[0], "hfs", 3 ) == 0 || memcmp( &my_statfsp->f_fstypename[0], "ufs", 3 ) == 0 || memcmp( &my_statfsp->f_fstypename[0], "devfs", 5 ) == 0 || memcmp( &my_statfsp->f_fstypename[0], "volfs", 5 ) == 0 ) { /* found a valid entry */ break; } } if ( i >= my_count ) { printf( "getfsstat call failed. could not find valid f_fstypename! \n" ); goto test_failed_exit; } /* set up to validate results via multiple sources. we use getattrlist to get volume * related attributes to verify against results from fstatfs and statfs - but only if * we are not targeting ufs volume since it doesn't support getattr calls */ if ( is_ufs == 0 ) { memset( &my_attrlist, 0, sizeof(my_attrlist) ); my_attrlist.bitmapcount = ATTR_BIT_MAP_COUNT; my_attrlist.volattr = (ATTR_VOL_SIZE | ATTR_VOL_IOBLOCKSIZE); my_err = getattrlist( "/", &my_attrlist, &my_attr_buf, sizeof(my_attr_buf), 0 ); if ( my_err != 0 ) { printf( "getattrlist call failed. got errno %d - %s. \n", errno, strerror( errno ) ); goto test_failed_exit; } } /* open kernel to use as test file for fstatfs */ my_fd = open( "/mach_kernel", O_RDONLY, 0 ); if ( my_fd == -1 ) { printf( "open call failed. got errno %d - %s. \n", errno, strerror( errno ) ); goto test_failed_exit; } /* testing fstatfs */ my_statfsp = (struct statfs *) my_bufferp; my_err = fstatfs( my_fd, my_statfsp ); if ( my_err == -1 ) { printf( "fstatfs call failed. got errno %d - %s. \n", errno, strerror( errno ) ); goto test_failed_exit; } /* validate results */ if ( !(memcmp( &my_statfsp->f_fstypename[0], "hfs", 3 ) == 0 || memcmp( &my_statfsp->f_fstypename[0], "ufs", 3 ) == 0) ) { printf( "fstatfs call failed. could not find valid f_fstypename! \n" ); goto test_failed_exit; } my_io_size = my_statfsp->f_iosize; my_fsid = my_statfsp->f_fsid; if ( is_ufs == 0 && my_statfsp->f_iosize != my_attr_buf.io_blksize ) { printf( "fstatfs and getattrlist results do not match for volume block size \n" ); goto test_failed_exit; } /* try again with statfs */ my_err = statfs( "/mach_kernel", my_statfsp ); if ( my_err == -1 ) { printf( "statfs call failed. got errno %d - %s. \n", errno, strerror( errno ) ); goto test_failed_exit; } /* validate resutls */ if ( my_io_size != my_statfsp->f_iosize || my_fsid.val[0] != my_statfsp->f_fsid.val[0] || my_fsid.val[1] != my_statfsp->f_fsid.val[1] ) { printf( "statfs call failed. wrong f_iosize or f_fsid! \n" ); goto test_failed_exit; } if ( is_ufs == 0 && my_statfsp->f_iosize != my_attr_buf.io_blksize ) { printf( "statfs and getattrlist results do not match for volume block size \n" ); goto test_failed_exit; } /* We passed the test */ my_err = 0; test_failed_exit: if(my_err != 0) my_err = -1; test_passed_exit: if ( my_fd != -1 ) close( my_fd ); if ( my_bufferp != NULL ) { vm_deallocate(mach_task_self(), (vm_address_t)my_bufferp, my_buffer_size); } return( my_err ); }
static int dirlinkchk(FTSENT *p) { struct links_entry { struct links_entry *next; struct links_entry *previous; int links; dev_t dev; ino_t ino; }; static const size_t links_hash_initial_size = 8192; static struct links_entry **buckets; static struct links_entry *free_list; static size_t number_buckets; static unsigned long number_entries; static char stop_allocating; struct links_entry *le, **new_buckets; struct stat *st; size_t i, new_size; int hash; struct attrbuf { int size; int linkcount; } buf; struct attrlist attrList; memset(&attrList, 0, sizeof(attrList)); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.dirattr = ATTR_DIR_LINKCOUNT; if (-1 == getattrlist(p->fts_path, &attrList, &buf, sizeof(buf), 0)) return 0; if (buf.linkcount == 1) return 0; st = p->fts_statp; /* If necessary, initialize the hash table. */ if (buckets == NULL) { number_buckets = links_hash_initial_size; buckets = malloc(number_buckets * sizeof(buckets[0])); if (buckets == NULL) errx(1, "No memory for directory hardlink detection"); for (i = 0; i < number_buckets; i++) buckets[i] = NULL; } /* If the hash table is getting too full, enlarge it. */ if (number_entries > number_buckets * 10 && !stop_allocating) { new_size = number_buckets * 2; new_buckets = malloc(new_size * sizeof(struct links_entry *)); /* Try releasing the free list to see if that helps. */ if (new_buckets == NULL && free_list != NULL) { while (free_list != NULL) { le = free_list; free_list = le->next; free(le); } new_buckets = malloc(new_size * sizeof(new_buckets[0])); } if (new_buckets == NULL) { stop_allocating = 1; warnx("No more memory for tracking directory hard links"); } else { memset(new_buckets, 0, new_size * sizeof(struct links_entry *)); for (i = 0; i < number_buckets; i++) { while (buckets[i] != NULL) { /* Remove entry from old bucket. */ le = buckets[i]; buckets[i] = le->next; /* Add entry to new bucket. */ hash = (le->dev ^ le->ino) % new_size; if (new_buckets[hash] != NULL) new_buckets[hash]->previous = le; le->next = new_buckets[hash]; le->previous = NULL; new_buckets[hash] = le; } } free(buckets); buckets = new_buckets; number_buckets = new_size; } } /* Try to locate this entry in the hash table. */ hash = ( st->st_dev ^ st->st_ino ) % number_buckets; for (le = buckets[hash]; le != NULL; le = le->next) { if (le->dev == st->st_dev && le->ino == st->st_ino) { /* * Save memory by releasing an entry when we've seen * all of it's links. */ if (--le->links <= 0) { if (le->previous != NULL) le->previous->next = le->next; if (le->next != NULL) le->next->previous = le->previous; if (buckets[hash] == le) buckets[hash] = le->next; number_entries--; /* Recycle this node through the free list */ if (stop_allocating) { free(le); } else { le->next = free_list; free_list = le; } } return (1); } } if (stop_allocating) return (0); /* Add this entry to the links cache. */ if (free_list != NULL) { /* Pull a node from the free list if we can. */ le = free_list; free_list = le->next; } else /* Malloc one if we have to. */ le = malloc(sizeof(struct links_entry)); if (le == NULL) { stop_allocating = 1; warnx("No more memory for tracking hard links"); return (0); } le->dev = st->st_dev; le->ino = st->st_ino; le->links = buf.linkcount - 1; number_entries++; le->next = buckets[hash]; le->previous = NULL; if (buckets[hash] != NULL) buckets[hash]->previous = le; buckets[hash] = le; return (0); }