1/* 2 * 32bit_inode_tests.c 3 * xnu_quick_test 4 * 5 * Created by Ryan Branche on 2/17/08. 6 * Copyright 2008 Apple Inc. All rights reserved. 7 * 8 */ 9 10/* 11 * Explicitely turn off 64-bit inodes because we are testing the 32-bit inode 12 * versions of statfs functions and getdirentries doesn't support 64-bit inodes. 13 */ 14#define _DARWIN_NO_64_BIT_INODE 1 15 16#include "tests.h" 17#include <mach/mach.h> 18#include <dirent.h> 19 20extern char g_target_path[ PATH_MAX ]; 21extern int g_skip_setuid_tests; 22extern int g_is_single_user; 23 24/* ************************************************************************************************************** 25 * Test getdirentries system call. 26 * ************************************************************************************************************** 27 */ 28struct test_attr_buf { 29 uint32_t length; 30 fsobj_type_t obj_type; 31 fsobj_id_t obj_id; 32 struct timespec backup_time; 33}; 34 35typedef struct test_attr_buf test_attr_buf; 36 37int getdirentries_test( void * the_argp ) 38{ 39 int my_err, done, found_it, i; 40 int my_fd = -1; 41 int is_ufs = 0; 42 char * my_pathp = NULL; 43 char * my_bufp = NULL; 44 char * my_file_namep; 45 long my_base; 46 unsigned long my_count; 47 unsigned long my_new_state; 48 fsobj_id_t my_obj_id; 49 struct timespec my_new_backup_time; 50 struct attrlist my_attrlist; 51 test_attr_buf my_attr_buf[4]; 52 struct statfs my_statfs_buf; 53 kern_return_t my_kr; 54 55 /* need to know type of file system */ 56 my_err = statfs( &g_target_path[0], &my_statfs_buf ); 57 if ( my_err == -1 ) { 58 printf( "statfs call failed. got errno %d - %s. \n", errno, strerror( errno ) ); 59 goto test_failed_exit; 60 } 61 if ( memcmp( &my_statfs_buf.f_fstypename[0], "ufs", 3 ) == 0 ) { 62 is_ufs = 1; 63 } 64 65 my_kr = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*)&my_bufp, (1024 * 5), VM_FLAGS_ANYWHERE); 66 if(my_kr != KERN_SUCCESS){ 67 printf( "vm_allocate failed with error %d - \"%s\" \n", errno, strerror( errno) ); 68 goto test_failed_exit; 69 } 70 71 my_kr = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*)&my_pathp, PATH_MAX, VM_FLAGS_ANYWHERE); 72 if(my_kr != KERN_SUCCESS){ 73 printf( "vm_allocate failed with error %d - \"%s\" \n", errno, strerror( errno) ); 74 goto test_failed_exit; 75 } 76 77 *my_pathp = 0x00; 78 strcat( my_pathp, &g_target_path[0] ); 79 strcat( my_pathp, "/" ); 80 81 /* create a test file */ 82 my_err = create_random_name( my_pathp, 1 ); 83 if ( my_err != 0 ) { 84 goto test_failed_exit; 85 } 86 87 /* get pointer to just the file name */ 88 my_file_namep = strrchr( my_pathp, '/' ); 89 my_file_namep++; 90 91 /* check out the test directory */ 92 my_fd = open( &g_target_path[0], (O_RDONLY), 0 ); 93 if ( my_fd == -1 ) { 94 printf( "open failed with error %d - \"%s\" \n", errno, strerror( errno) ); 95 goto test_failed_exit; 96 } 97 98 done = found_it = 0; 99 while ( done == 0 ) { 100 int my_result, i; 101 struct dirent * my_dirent_p; 102 103 /* This call requires that 64-bit inodes are disabled */ 104 my_result = getdirentries( my_fd, my_bufp, (1024 * 5), &my_base ); 105 if ( my_result <= 0 ) 106 break; 107 for ( i = 0; i < my_result; ) { 108 my_dirent_p = (struct dirent *) (my_bufp + i); 109#if DEBUG 110 printf( "d_ino %d d_reclen %d d_type %d d_namlen %d \"%s\" \n", 111 my_dirent_p->d_ino, my_dirent_p->d_reclen, my_dirent_p->d_type, 112 my_dirent_p->d_namlen, &my_dirent_p->d_name[0] ); 113#endif 114 115 i += my_dirent_p->d_reclen; 116 /* validate results by looking for our test file */ 117 if ( my_dirent_p->d_type == DT_REG && my_dirent_p->d_ino != 0 && 118 strlen( my_file_namep ) == my_dirent_p->d_namlen && 119 memcmp( &my_dirent_p->d_name[0], my_file_namep, my_dirent_p->d_namlen ) == 0 ) { 120 done = found_it = 1; 121 break; 122 } 123 } 124 } 125 if ( found_it == 0 ) { 126 printf( "getdirentries failed to find test file. \n" ); 127 goto test_failed_exit; 128 } 129 130test_failed_exit: 131 if(my_err != 0) 132 my_err = -1; 133 134test_passed_exit: 135 if ( my_fd != -1 ) 136 close( my_fd ); 137 if ( my_pathp != NULL ) { 138 remove( my_pathp ); 139 vm_deallocate(mach_task_self(), (vm_address_t)my_pathp, PATH_MAX); 140 } 141 if ( my_bufp != NULL ) { 142 vm_deallocate(mach_task_self(), (vm_address_t)my_bufp, (1024 * 5)); 143 } 144 145 return( my_err ); 146} 147 148 149/* ************************************************************************************************************** 150 * Test 32-bit inode versions of statfs, fstatfs, and getfsstat system calls. 151 * ************************************************************************************************************** 152 */ 153 154#pragma pack(4) 155struct vol_attr_buf { 156 u_int32_t length; 157 off_t volume_size; 158 u_int32_t io_blksize; 159}; 160#pragma pack() 161typedef struct vol_attr_buf vol_attr_buf; 162 163int statfs_32bit_inode_tests( void * the_argp ) 164{ 165 int my_err, my_count, i; 166 int my_buffer_size; 167 int my_fd = -1; 168 int is_ufs = 0; 169 void * my_bufferp = NULL; 170 struct statfs * my_statfsp; 171 long my_io_size; 172 fsid_t my_fsid; 173 struct attrlist my_attrlist; 174 vol_attr_buf my_attr_buf; 175 kern_return_t my_kr; 176 177 my_buffer_size = (sizeof(struct statfs) * 10); 178 my_kr = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*)&my_bufferp, my_buffer_size, VM_FLAGS_ANYWHERE); 179 if(my_kr != KERN_SUCCESS){ 180 printf( "vm_allocate failed with error %d - \"%s\" \n", errno, strerror( errno) ); 181 goto test_failed_exit; 182 } 183 184 my_statfsp = (struct statfs *) my_bufferp; 185 my_err = statfs( "/", my_statfsp ); 186 if ( my_err == -1 ) { 187 printf( "statfs call failed. got errno %d - %s. \n", errno, strerror( errno ) ); 188 goto test_failed_exit; 189 } 190 if ( memcmp( &my_statfsp->f_fstypename[0], "ufs", 3 ) == 0 ) { 191 is_ufs = 1; 192 } 193 194 my_count = getfsstat( (struct statfs *)my_bufferp, my_buffer_size, MNT_NOWAIT ); 195 if ( my_count == -1 ) { 196 printf( "getfsstat call failed. got errno %d - %s. \n", errno, strerror( errno ) ); 197 goto test_failed_exit; 198 } 199 200 /* validate results */ 201 my_statfsp = (struct statfs *) my_bufferp; 202 for ( i = 0; i < my_count; i++, my_statfsp++ ) { 203 if ( memcmp( &my_statfsp->f_fstypename[0], "hfs", 3 ) == 0 || 204 memcmp( &my_statfsp->f_fstypename[0], "ufs", 3 ) == 0 || 205 memcmp( &my_statfsp->f_fstypename[0], "devfs", 5 ) == 0 || 206 memcmp( &my_statfsp->f_fstypename[0], "volfs", 5 ) == 0 ) { 207 /* found a valid entry */ 208 break; 209 } 210 } 211 if ( i >= my_count ) { 212 printf( "getfsstat call failed. could not find valid f_fstypename! \n" ); 213 goto test_failed_exit; 214 } 215 216 /* set up to validate results via multiple sources. we use getattrlist to get volume 217 * related attributes to verify against results from fstatfs and statfs - but only if 218 * we are not targeting ufs volume since it doesn't support getattr calls 219 */ 220 if ( is_ufs == 0 ) { 221 memset( &my_attrlist, 0, sizeof(my_attrlist) ); 222 my_attrlist.bitmapcount = ATTR_BIT_MAP_COUNT; 223 my_attrlist.volattr = (ATTR_VOL_SIZE | ATTR_VOL_IOBLOCKSIZE); 224 my_err = getattrlist( "/", &my_attrlist, &my_attr_buf, sizeof(my_attr_buf), 0 ); 225 if ( my_err != 0 ) { 226 printf( "getattrlist call failed. got errno %d - %s. \n", errno, strerror( errno ) ); 227 goto test_failed_exit; 228 } 229 } 230 231 /* open kernel to use as test file for fstatfs */ 232 my_fd = open( "/System/Library/Kernels/kernel", O_RDONLY, 0 ); 233 if ( my_fd == -1 ) { 234 printf( "open call failed. got errno %d - %s. \n", errno, strerror( errno ) ); 235 goto test_failed_exit; 236 } 237 238 /* testing fstatfs */ 239 my_statfsp = (struct statfs *) my_bufferp; 240 my_err = fstatfs( my_fd, my_statfsp ); 241 if ( my_err == -1 ) { 242 printf( "fstatfs call failed. got errno %d - %s. \n", errno, strerror( errno ) ); 243 goto test_failed_exit; 244 } 245 246 /* validate results */ 247 if ( !(memcmp( &my_statfsp->f_fstypename[0], "hfs", 3 ) == 0 || 248 memcmp( &my_statfsp->f_fstypename[0], "ufs", 3 ) == 0) ) { 249 printf( "fstatfs call failed. could not find valid f_fstypename! \n" ); 250 goto test_failed_exit; 251 } 252 my_io_size = my_statfsp->f_iosize; 253 my_fsid = my_statfsp->f_fsid; 254 if ( is_ufs == 0 && my_statfsp->f_iosize != my_attr_buf.io_blksize ) { 255 printf( "fstatfs and getattrlist results do not match for volume block size \n" ); 256 goto test_failed_exit; 257 } 258 259 /* try again with statfs */ 260 my_err = statfs( "/System/Library/Kernels/kernel", my_statfsp ); 261 if ( my_err == -1 ) { 262 printf( "statfs call failed. got errno %d - %s. \n", errno, strerror( errno ) ); 263 goto test_failed_exit; 264 } 265 266 /* validate resutls */ 267 if ( my_io_size != my_statfsp->f_iosize || my_fsid.val[0] != my_statfsp->f_fsid.val[0] || 268 my_fsid.val[1] != my_statfsp->f_fsid.val[1] ) { 269 printf( "statfs call failed. wrong f_iosize or f_fsid! \n" ); 270 goto test_failed_exit; 271 } 272 if ( is_ufs == 0 && my_statfsp->f_iosize != my_attr_buf.io_blksize ) { 273 printf( "statfs and getattrlist results do not match for volume block size \n" ); 274 goto test_failed_exit; 275 } 276 277 /* We passed the test */ 278 my_err = 0; 279 280test_failed_exit: 281 if(my_err != 0) 282 my_err = -1; 283 284test_passed_exit: 285 if ( my_fd != -1 ) 286 close( my_fd ); 287 if ( my_bufferp != NULL ) { 288 vm_deallocate(mach_task_self(), (vm_address_t)my_bufferp, my_buffer_size); 289 } 290 291 return( my_err ); 292} 293 294