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