Example #1
0
/* basic testing of all RAW_FILEINFO_* calls 
   for each call we test that it succeeds, and where possible test 
   for consistency between the calls. 
*/
static bool torture_raw_qfileinfo_internals(struct torture_context *torture, 
					    TALLOC_CTX *mem_ctx, 	
					    struct smbcli_tree *tree, 
					    int fnum, const char *fname,
					    bool is_ipc)
{
	int i;
	bool ret = true;
	int count;
	union smb_fileinfo *s1, *s2;	
	NTTIME correct_time;
	uint64_t correct_size;
	uint32_t correct_attrib;
	const char *correct_name;
	bool skip_streams = false;

	/* scan all the fileinfo and pathinfo levels */
	for (i=0; levels[i].name; i++) {
		if (!levels[i].only_paths) {
			levels[i].fnum_finfo.generic.level = levels[i].level;
			levels[i].fnum_finfo.generic.in.file.fnum = fnum;
			levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx, 
								 &levels[i].fnum_finfo);
		}

		if (!levels[i].only_handles) {
			levels[i].fname_finfo.generic.level = levels[i].level;
			levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
			levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx, 
								  &levels[i].fname_finfo);
		}
	}

	/* check for completely broken levels */
	for (count=i=0; levels[i].name; i++) {
		uint32_t cap = tree->session->transport->negotiate.capabilities;
		/* see if this server claims to support this level */
		if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
			continue;
		}

		if (is_ipc) {
			if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) {
			} else if (!levels[i].only_handles &&
				   NT_STATUS_EQUAL(levels[i].fname_status,
				   NT_STATUS_NOT_SUPPORTED)) {
				torture_warning(torture, "fname level %s %s",
					levels[i].name,
					nt_errstr(levels[i].fname_status));
				continue;
			} else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
				printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n", 
				       levels[i].name, nt_errstr(levels[i].fname_status));
				count++;
			}
			if (!levels[i].only_paths &&
			   (NT_STATUS_EQUAL(levels[i].fnum_status,
			    NT_STATUS_NOT_SUPPORTED) ||
			    NT_STATUS_EQUAL(levels[i].fnum_status,
			    NT_STATUS_NOT_IMPLEMENTED))) {
				torture_warning(torture, "fnum level %s %s",
					levels[i].name,
					nt_errstr(levels[i].fnum_status));
				continue;
			}
			if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
				printf("ERROR: fnum level %s failed, expected %s - %s\n", 
				       levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status), 
				       nt_errstr(levels[i].fnum_status));
				count++;
			}
		} else {
			if (!levels[i].only_paths &&
			   (NT_STATUS_EQUAL(levels[i].fnum_status,
			    NT_STATUS_NOT_SUPPORTED) ||
			    NT_STATUS_EQUAL(levels[i].fnum_status,
			    NT_STATUS_NOT_IMPLEMENTED))) {
				torture_warning(torture, "fnum level %s %s",
					levels[i].name,
					nt_errstr(levels[i].fnum_status));
				continue;
			}

			if (!levels[i].only_handles &&
			   (NT_STATUS_EQUAL(levels[i].fname_status,
			    NT_STATUS_NOT_SUPPORTED) ||
			    NT_STATUS_EQUAL(levels[i].fname_status,
			    NT_STATUS_NOT_IMPLEMENTED))) {
                                torture_warning(torture, "fname level %s %s",
					levels[i].name,
					nt_errstr(levels[i].fname_status));
				continue;
			}

			if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
				printf("ERROR: fnum level %s failed - %s\n", 
				       levels[i].name, nt_errstr(levels[i].fnum_status));
				count++;
			}
			if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
				printf("ERROR: fname level %s failed - %s\n", 
				       levels[i].name, nt_errstr(levels[i].fname_status));
				count++;
			}
		}
		
	}

	if (count != 0) {
		ret = false;
		printf("%d levels failed\n", count);
		if (count > 35) {
			torture_fail(torture, "too many level failures - giving up");
		}
	}

	/* see if we can do streams */
	s1 = fnum_find("STREAM_INFO");
	if (!s1 || s1->stream_info.out.num_streams == 0) {
		if (!is_ipc) {
			printf("STREAM_INFO broken (%d) - skipping streams checks\n",
			       s1 ? s1->stream_info.out.num_streams : -1);
		}
		skip_streams = true;
	}	


	/* this code is incredibly repititive but doesn't lend itself to loops, so
	   we use lots of macros to make it less painful */

	/* first off we check the levels that are supposed to be aliases. It will be quite rare for 
	   this code to fail, but we need to check it for completeness */



#define ALIAS_CHECK(sname1, sname2) \
	do { \
		s1 = fnum_find(sname1);	 s2 = fnum_find(sname2); \
		if (s1 && s2) { INFO_CHECK } \
		s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
		if (s1 && s2) { INFO_CHECK } \
		s1 = fnum_find(sname1);	 s2 = fname_find(is_ipc, sname2); \
		if (s1 && s2) { INFO_CHECK } \
	} while (0)

#define INFO_CHECK \
		STRUCT_EQUAL(basic_info,  create_time, basic_info, create_time); \
		STRUCT_EQUAL(basic_info,  access_time, basic_info, access_time); \
		STRUCT_EQUAL(basic_info,  write_time,  basic_info, write_time); \
		STRUCT_EQUAL(basic_info,  change_time, basic_info, change_time); \
		VAL_EQUAL   (basic_info,  attrib,      basic_info, attrib);

	ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");

#undef INFO_CHECK
#define INFO_CHECK \
		VAL_EQUAL(standard_info,  alloc_size,     standard_info, alloc_size); \
		VAL_EQUAL(standard_info,  size,           standard_info, size); \
		VAL_EQUAL(standard_info,  nlink,          standard_info, nlink); \
		VAL_EQUAL(standard_info,  delete_pending, standard_info, delete_pending); \
		VAL_EQUAL(standard_info,  directory,      standard_info, directory);

	ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");

#undef INFO_CHECK
#define INFO_CHECK \
		VAL_EQUAL(ea_info,  ea_size,     ea_info, ea_size);

	ALIAS_CHECK("EA_INFO", "EA_INFORMATION");

#undef INFO_CHECK
#define INFO_CHECK \
		STR_EQUAL(name_info,  fname,   name_info, fname);

	ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");

#undef INFO_CHECK
#define INFO_CHECK \
		STRUCT_EQUAL(all_info,  create_time,           all_info, create_time); \
		STRUCT_EQUAL(all_info,  access_time,           all_info, access_time); \
		STRUCT_EQUAL(all_info,  write_time,            all_info, write_time); \
		STRUCT_EQUAL(all_info,  change_time,           all_info, change_time); \
		   VAL_EQUAL(all_info,  attrib,                all_info, attrib); \
		   VAL_EQUAL(all_info,  alloc_size,            all_info, alloc_size); \
		   VAL_EQUAL(all_info,  size,                  all_info, size); \
		   VAL_EQUAL(all_info,  nlink,                 all_info, nlink); \
		   VAL_EQUAL(all_info,  delete_pending,        all_info, delete_pending); \
		   VAL_EQUAL(all_info,  directory,             all_info, directory); \
		   VAL_EQUAL(all_info,  ea_size,               all_info, ea_size); \
		   STR_EQUAL(all_info,  fname,                 all_info, fname);

	ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");

#undef INFO_CHECK
#define INFO_CHECK \
		VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
		VAL_EQUAL(compression_info, format,         compression_info, format); \
		VAL_EQUAL(compression_info, unit_shift,     compression_info, unit_shift); \
		VAL_EQUAL(compression_info, chunk_shift,    compression_info, chunk_shift); \
		VAL_EQUAL(compression_info, cluster_shift,  compression_info, cluster_shift);

	ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");


#undef INFO_CHECK
#define INFO_CHECK \
		STR_EQUAL(alt_name_info,  fname,   alt_name_info, fname);

	ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");


#define TIME_CHECK_NT(sname, stype, tfield) do { \
	s1 = fnum_find(sname); \
	if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
		printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
		       nt_time_string(mem_ctx, s1->stype.out.tfield), \
		       nt_time_string(mem_ctx, correct_time)); \
		ret = false; \
	} \
	s1 = fname_find(is_ipc, sname); \
	if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
		printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
		       nt_time_string(mem_ctx, s1->stype.out.tfield), \
		       nt_time_string(mem_ctx, correct_time)); \
		ret = false; \
	}} while (0)

#define TIME_CHECK_DOS(sname, stype, tfield) do { \
	s1 = fnum_find(sname); \
	if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
		printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
		       timestring(mem_ctx, s1->stype.out.tfield), \
		       nt_time_string(mem_ctx, correct_time)); \
		ret = false; \
	} \
	s1 = fname_find(is_ipc, sname); \
	if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
		printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
		       timestring(mem_ctx, s1->stype.out.tfield), \
		       nt_time_string(mem_ctx, correct_time)); \
		ret = false; \
	}} while (0)

#if 0 /* unused */
#define TIME_CHECK_UNX(sname, stype, tfield) do { \
	s1 = fnum_find(sname); \
	if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
		printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
		       timestring(mem_ctx, s1->stype.out.tfield), \
		       nt_time_string(mem_ctx, correct_time)); \
		ret = false; \
	} \
	s1 = fname_find(is_ipc, sname); \
	if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
		printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield,  \
		       timestring(mem_ctx, s1->stype.out.tfield), \
		       nt_time_string(mem_ctx, correct_time)); \
		ret = false; \
	}} while (0)
#endif

	/* now check that all the times that are supposed to be equal are correct */
	s1 = fnum_find("BASIC_INFO");
	correct_time = s1->basic_info.out.create_time;
	torture_comment(torture, "create_time: %s\n", nt_time_string(mem_ctx, correct_time));

	TIME_CHECK_NT ("BASIC_INFO",               basic_info, create_time);
	TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, create_time);
	TIME_CHECK_DOS("GETATTRE",                 getattre,   create_time);
	TIME_CHECK_DOS("STANDARD",                 standard,   create_time);
	TIME_CHECK_DOS("EA_SIZE",                  ea_size,    create_time);
	TIME_CHECK_NT ("ALL_INFO",                 all_info,   create_time);
	TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);

	s1 = fnum_find("BASIC_INFO");
	correct_time = s1->basic_info.out.access_time;
	torture_comment(torture, "access_time: %s\n", nt_time_string(mem_ctx, correct_time));

	TIME_CHECK_NT ("BASIC_INFO",               basic_info, access_time);
	TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, access_time);
	TIME_CHECK_DOS("GETATTRE",                 getattre,   access_time);
	TIME_CHECK_DOS("STANDARD",                 standard,   access_time);
	TIME_CHECK_DOS("EA_SIZE",                  ea_size,    access_time);
	TIME_CHECK_NT ("ALL_INFO",                 all_info,   access_time);
	TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);

	s1 = fnum_find("BASIC_INFO");
	correct_time = s1->basic_info.out.write_time;
	torture_comment(torture, "write_time : %s\n", nt_time_string(mem_ctx, correct_time));

	TIME_CHECK_NT ("BASIC_INFO",               basic_info, write_time);
	TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, write_time);
	TIME_CHECK_DOS("GETATTR",                  getattr,    write_time);
	TIME_CHECK_DOS("GETATTRE",                 getattre,   write_time);
	TIME_CHECK_DOS("STANDARD",                 standard,   write_time);
	TIME_CHECK_DOS("EA_SIZE",                  ea_size,    write_time);
	TIME_CHECK_NT ("ALL_INFO",                 all_info,   write_time);
	TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);

	s1 = fnum_find("BASIC_INFO");
	correct_time = s1->basic_info.out.change_time;
	torture_comment(torture, "change_time: %s\n", nt_time_string(mem_ctx, correct_time));

	TIME_CHECK_NT ("BASIC_INFO",               basic_info, change_time);
	TIME_CHECK_NT ("BASIC_INFORMATION",        basic_info, change_time);
	TIME_CHECK_NT ("ALL_INFO",                 all_info,   change_time);
	TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);


#define SIZE_CHECK(sname, stype, tfield) do { \
	s1 = fnum_find(sname); \
	if (s1 && s1->stype.out.tfield != correct_size) { \
		printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield,  \
		       (unsigned int)s1->stype.out.tfield, \
		       (unsigned int)correct_size); \
		ret = false; \
	} \
	s1 = fname_find(is_ipc, sname); \
	if (s1 && s1->stype.out.tfield != correct_size) { \
		printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield,  \
		       (unsigned int)s1->stype.out.tfield, \
		       (unsigned int)correct_size); \
		ret = false; \
	}} while (0)

	s1 = fnum_find("STANDARD_INFO");
	correct_size = s1->standard_info.out.size;
	torture_comment(torture, "size: %u\n", (unsigned int)correct_size);
	
	SIZE_CHECK("GETATTR",                  getattr,                  size);
	SIZE_CHECK("GETATTRE",                 getattre,                 size);
	SIZE_CHECK("STANDARD",                 standard,                 size);
	SIZE_CHECK("EA_SIZE",                  ea_size,                  size);
	SIZE_CHECK("STANDARD_INFO",            standard_info,            size);
	SIZE_CHECK("STANDARD_INFORMATION",     standard_info,            size);
	SIZE_CHECK("ALL_INFO",                 all_info,                 size);
	SIZE_CHECK("ALL_INFORMATION",          all_info,                 size);
	SIZE_CHECK("COMPRESSION_INFO",         compression_info,         compressed_size);
	SIZE_CHECK("COMPRESSION_INFORMATION",  compression_info,         compressed_size);
	SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
	if (!skip_streams) {
		SIZE_CHECK("STREAM_INFO",              stream_info,   streams[0].size);
		SIZE_CHECK("STREAM_INFORMATION",       stream_info,   streams[0].size);
	}


	s1 = fnum_find("STANDARD_INFO");
	correct_size = s1->standard_info.out.alloc_size;
	torture_comment(torture, "alloc_size: %u\n", (unsigned int)correct_size);
	
	SIZE_CHECK("GETATTRE",                 getattre,                 alloc_size);
	SIZE_CHECK("STANDARD",                 standard,                 alloc_size);
	SIZE_CHECK("EA_SIZE",                  ea_size,                  alloc_size);
	SIZE_CHECK("STANDARD_INFO",            standard_info,            alloc_size);
	SIZE_CHECK("STANDARD_INFORMATION",     standard_info,            alloc_size);
	SIZE_CHECK("ALL_INFO",                 all_info,                 alloc_size);
	SIZE_CHECK("ALL_INFORMATION",          all_info,                 alloc_size);
	SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
	if (!skip_streams) {
		SIZE_CHECK("STREAM_INFO",              stream_info,   streams[0].alloc_size);
		SIZE_CHECK("STREAM_INFORMATION",       stream_info,   streams[0].alloc_size);
	}

#define ATTRIB_CHECK(sname, stype, tfield) do { \
	s1 = fnum_find(sname); \
	if (s1 && s1->stype.out.tfield != correct_attrib) { \
		printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield,  \
		       (unsigned int)s1->stype.out.tfield, \
		       (unsigned int)correct_attrib); \
		ret = false; \
	} \
	s1 = fname_find(is_ipc, sname); \
	if (s1 && s1->stype.out.tfield != correct_attrib) { \
		printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield,  \
		       (unsigned int)s1->stype.out.tfield, \
		       (unsigned int)correct_attrib); \
		ret = false; \
	}} while (0)

	s1 = fnum_find("BASIC_INFO");
	correct_attrib = s1->basic_info.out.attrib;
	torture_comment(torture, "attrib: 0x%x\n", (unsigned int)correct_attrib);
	
	ATTRIB_CHECK("GETATTR",                   getattr,                   attrib);
	if (!is_ipc) {
		ATTRIB_CHECK("GETATTRE",                  getattre,                  attrib);
		ATTRIB_CHECK("STANDARD",                  standard,                  attrib);
		ATTRIB_CHECK("EA_SIZE",                   ea_size,                   attrib);
	}
	ATTRIB_CHECK("BASIC_INFO",                basic_info,                attrib);
	ATTRIB_CHECK("BASIC_INFORMATION",         basic_info,                attrib);
	ATTRIB_CHECK("ALL_INFO",                  all_info,                  attrib);
	ATTRIB_CHECK("ALL_INFORMATION",           all_info,                  attrib);
	ATTRIB_CHECK("NETWORK_OPEN_INFORMATION",  network_open_information,  attrib);
	ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);

	correct_name = fname;
	torture_comment(torture, "name: %s\n", correct_name);

#define NAME_CHECK(sname, stype, tfield, flags) do { \
	s1 = fnum_find(sname); \
	if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
	    		wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
		printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield,  \
		       s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
		ret = false; \
	} \
	s1 = fname_find(is_ipc, sname); \
	if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
	    		wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
		printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield,  \
		       s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
		ret = false; \
	}} while (0)

	NAME_CHECK("NAME_INFO",        name_info, fname, STR_UNICODE);
	NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);

	/* the ALL_INFO file name is the full path on the filesystem */
	s1 = fnum_find("ALL_INFO");
	if (s1 && !s1->all_info.out.fname.s) {
		torture_fail(torture, "ALL_INFO didn't give a filename");
	}
	if (s1 && s1->all_info.out.fname.s) {
		char *p = strrchr(s1->all_info.out.fname.s, '\\');
		if (!p) {
			printf("Not a full path in all_info/fname? - '%s'\n", 
			       s1->all_info.out.fname.s);
			ret = false;
		} else {
			if (strcmp_safe(correct_name, p) != 0) {
				printf("incorrect basename in all_info/fname - '%s'\n",
				       s1->all_info.out.fname.s);
				ret = false;
			}
		}
		if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
			printf("Should not null terminate all_info/fname\n");
			ret = false;
		}
	}

	s1 = fnum_find("ALT_NAME_INFO");
	if (s1) {
		correct_name = s1->alt_name_info.out.fname.s;
	}

	if (!correct_name) {
		torture_comment(torture, "no alternate name information\n");
	} else {
		torture_comment(torture, "alt_name: %s\n", correct_name);
		
		NAME_CHECK("ALT_NAME_INFO",        alt_name_info, fname, STR_UNICODE);
		NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
		
		/* and make sure we can open by alternate name */
		smbcli_close(tree, fnum);
		fnum = smbcli_nt_create_full(tree, correct_name, 0, 
					     SEC_RIGHTS_FILE_ALL,
					     FILE_ATTRIBUTE_NORMAL,
					     NTCREATEX_SHARE_ACCESS_DELETE|
					     NTCREATEX_SHARE_ACCESS_READ|
					     NTCREATEX_SHARE_ACCESS_WRITE, 
					     NTCREATEX_DISP_OVERWRITE_IF, 
					     0, 0);
		if (fnum == -1) {
			printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
			ret = false;
		}
		
		if (!skip_streams) {
			correct_name = "::$DATA";
			torture_comment(torture, "stream_name: %s\n", correct_name);
			
			NAME_CHECK("STREAM_INFO",        stream_info, streams[0].stream_name, STR_UNICODE);
			NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
		}
	}
		
	/* make sure the EAs look right */
	s1 = fnum_find("ALL_EAS");
	s2 = fnum_find("ALL_INFO");
	if (s1) {
		for (i=0;i<s1->all_eas.out.num_eas;i++) {
			printf("  flags=%d %s=%*.*s\n", 
			       s1->all_eas.out.eas[i].flags,
			       s1->all_eas.out.eas[i].name.s,
			       (int)s1->all_eas.out.eas[i].value.length,
			       (int)s1->all_eas.out.eas[i].value.length,
			       s1->all_eas.out.eas[i].value.data);
		}
	}
	if (s1 && s2) {
		if (s1->all_eas.out.num_eas == 0) {
			if (s2->all_info.out.ea_size != 0) {
				printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
				       s2->all_info.out.ea_size);
			}
		} else {
			if (s2->all_info.out.ea_size != 
			    ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
				printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
				       (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
				       (int)s2->all_info.out.ea_size);
			}
		}
	}
	s2 = fname_find(is_ipc, "ALL_EAS");
	if (s2) {
		VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
		for (i=0;i<s1->all_eas.out.num_eas;i++) {
			VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
			STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
			VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
		}
	}

#define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
	s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
	if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
		printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
                       #stype1, #tfield1, #stype2, #tfield2,  \
		       s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
		ret = false; \
	} \
	s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
	if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
		printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
                       #stype1, #tfield1, #stype2, #tfield2,  \
		       s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
		ret = false; \
	} \
	s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
	if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
		printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
                       #stype1, #tfield1, #stype2, #tfield2,  \
		       s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
		ret = false; \
	} \
	s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
	if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
		printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
                       #stype1, #tfield1, #stype2, #tfield2,  \
		       s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
		ret = false; \
	}} while (0)

	VAL_CHECK("STANDARD_INFO", standard_info, delete_pending, 
		  "ALL_INFO",      all_info,      delete_pending);
	VAL_CHECK("STANDARD_INFO", standard_info, directory, 
		  "ALL_INFO",      all_info,      directory);
	VAL_CHECK("STANDARD_INFO", standard_info, nlink, 
		  "ALL_INFO",      all_info,      nlink);
	s1 = fnum_find("BASIC_INFO");
	if (s1 && is_ipc) {
		if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
			printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, (int)FILE_ATTRIBUTE_NORMAL);
			ret = false;
		}
	}
	s1 = fnum_find("STANDARD_INFO");
	if (s1 && is_ipc) {
		if (s1->standard_info.out.nlink != 1) {
			printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
			ret = false;
		}
		if (s1->standard_info.out.delete_pending != 1) {
			printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
			ret = false;
		}
	}
	VAL_CHECK("EA_INFO",       ea_info,       ea_size, 
		  "ALL_INFO",      all_info,      ea_size);
	if (!is_ipc) {
		VAL_CHECK("EA_SIZE",       ea_size,       ea_size, 
			  "ALL_INFO",      all_info,      ea_size);
	}

#define NAME_PATH_CHECK(sname, stype, field) do { \
	s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
        if (s1 && s2) { \
		VAL_EQUAL(stype, field, stype, field); \
	} \
} while (0)


	s1 = fnum_find("INTERNAL_INFORMATION");
	if (s1) {
		torture_comment(torture, "file_id=%.0f\n", (double)s1->internal_information.out.file_id);
	}

	NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
	NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
	if (s1 && s2) {
		printf("fnum pos = %.0f, fname pos = %.0f\n",
		       (double)s2->position_information.out.position,
		       (double)s1->position_information.out.position );
	}
	NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
	NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
	NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
	NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);

#if 0
	/* these are expected to differ */
	NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
#endif

#if 0 /* unused */
#define UNKNOWN_CHECK(sname, stype, tfield) do { \
	s1 = fnum_find(sname); \
	if (s1 && s1->stype.out.tfield != 0) { \
		printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
                       #stype, #tfield, \
		       (unsigned int)s1->stype.out.tfield); \
	} \
	s1 = fname_find(is_ipc, sname); \
	if (s1 && s1->stype.out.tfield != 0) { \
		printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
                       #stype, #tfield, \
		       (unsigned int)s1->stype.out.tfield); \
	}} while (0)
#endif
	/* now get a bit fancier .... */
	
	/* when we set the delete disposition then the link count should drop
	   to 0 and delete_pending should be 1 */
	
	return ret;
}
Example #2
0
/* basic testing of all RAW_QFS_* calls 
   for each call we test that it succeeds, and where possible test 
   for consistency between the calls. 

   Some of the consistency tests assume that the target filesystem is
   quiescent, which is sometimes hard to achieve
*/
bool torture_raw_qfsinfo(struct torture_context *torture, 
			 struct smbcli_state *cli)
{
	int i;
	bool ret = true;
	int count;
	union smb_fsinfo *s1, *s2;	

	/* scan all the levels, pulling the results */
	for (i=0; levels[i].name; i++) {
		torture_comment(torture, "Running level %s\n", levels[i].name);
		levels[i].fsinfo.generic.level = levels[i].level;
		levels[i].status = smb_raw_fsinfo(cli->tree, torture, &levels[i].fsinfo);
	}

	/* check for completely broken levels */
	for (count=i=0; levels[i].name; i++) {
		uint32_t cap = cli->transport->negotiate.capabilities;
		/* see if this server claims to support this level */
		if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
			continue;
		}
		
		if (!NT_STATUS_IS_OK(levels[i].status)) {
			printf("ERROR: level %s failed - %s\n", 
			       levels[i].name, nt_errstr(levels[i].status));
			count++;
		}
	}

	if (count != 0) {
		torture_comment(torture, "%d levels failed\n", count);
		torture_assert(torture, count > 13, "too many level failures - giving up");
	}

	torture_comment(torture, "check for correct aliases\n");
	s1 = find("SIZE_INFO");
	s2 = find("SIZE_INFORMATION");
	if (s1 && s2) {
		VAL_EQUAL(size_info, total_alloc_units, size_info, total_alloc_units);
		VAL_APPROX_EQUAL(size_info, avail_alloc_units, size_info, avail_alloc_units);
		VAL_EQUAL(size_info, sectors_per_unit,  size_info, sectors_per_unit);
		VAL_EQUAL(size_info, bytes_per_sector,  size_info, bytes_per_sector);
	}	

	s1 = find("DEVICE_INFO");
	s2 = find("DEVICE_INFORMATION");
	if (s1 && s2) {
		VAL_EQUAL(device_info, device_type,     device_info, device_type);
		VAL_EQUAL(device_info, characteristics, device_info, characteristics);
	}	

	s1 = find("VOLUME_INFO");
	s2 = find("VOLUME_INFORMATION");
	if (s1 && s2) {
		STRUCT_EQUAL(volume_info, create_time,    volume_info, create_time);
		VAL_EQUAL   (volume_info, serial_number,  volume_info, serial_number);
		STR_EQUAL   (volume_info, volume_name.s,    volume_info, volume_name.s);
		torture_comment(torture, "volume_info.volume_name = '%s'\n", s1->volume_info.out.volume_name.s);
	}	

	s1 = find("ATTRIBUTE_INFO");
	s2 = find("ATTRIBUTE_INFORMATION");
	if (s1 && s2) {
		VAL_EQUAL(attribute_info, fs_attr,    
			  attribute_info, fs_attr);
		VAL_EQUAL(attribute_info, max_file_component_length, 
			  attribute_info, max_file_component_length);
		STR_EQUAL(attribute_info, fs_type.s, attribute_info, fs_type.s);
		torture_comment(torture, "attribute_info.fs_type = '%s'\n", s1->attribute_info.out.fs_type.s);
	}	

	torture_comment(torture, "check for consistent disk sizes\n");
	s1 = find("DSKATTR");
	s2 = find("ALLOCATION");
	if (s1 && s2) {
		double size1, size2;
		double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
		size1 = 1.0 * 
			s1->dskattr.out.units_total * 
			s1->dskattr.out.blocks_per_unit * 
			s1->dskattr.out.block_size / scale;
		size2 = 1.0 *
			s2->allocation.out.sectors_per_unit *
			s2->allocation.out.total_alloc_units *
			s2->allocation.out.bytes_per_sector / scale;
		if (abs(size1 - size2) > 1) {
			printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n", 
			       size1, size2);
			ret = false;
		}
		torture_comment(torture, "total disk = %.0f MB\n", size1*scale/1.0e6);
	}

	torture_comment(torture, "check consistent free disk space\n");
	s1 = find("DSKATTR");
	s2 = find("ALLOCATION");
	if (s1 && s2) {
		double size1, size2;
		double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
		size1 = 1.0 * 
			s1->dskattr.out.units_free * 
			s1->dskattr.out.blocks_per_unit * 
			s1->dskattr.out.block_size / scale;
		size2 = 1.0 *
			s2->allocation.out.sectors_per_unit *
			s2->allocation.out.avail_alloc_units *
			s2->allocation.out.bytes_per_sector / scale;
		if (abs(size1 - size2) > 1) {
			printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n", 
			       size1, size2);
			ret = false;
		}
		torture_comment(torture, "free disk = %.0f MB\n", size1*scale/1.0e6);
	}
	
	torture_comment(torture, "volume info consistency\n");
	s1 = find("VOLUME");
	s2 = find("VOLUME_INFO");
	if (s1 && s2) {
		VAL_EQUAL(volume, serial_number,  volume_info, serial_number);
		STR_EQUAL(volume, volume_name.s,  volume_info, volume_name.s);
	}	

	/* disk size consistency - notice that 'avail_alloc_units' maps to the caller
	   available allocation units, not the total */
	s1 = find("SIZE_INFO");
	s2 = find("FULL_SIZE_INFORMATION");
	if (s1 && s2) {
		VAL_EQUAL(size_info, total_alloc_units, full_size_information, total_alloc_units);
		VAL_APPROX_EQUAL(size_info, avail_alloc_units, full_size_information, call_avail_alloc_units);
		VAL_EQUAL(size_info, sectors_per_unit,  full_size_information, sectors_per_unit);
		VAL_EQUAL(size_info, bytes_per_sector,  full_size_information, bytes_per_sector);
	}	

	printf("check for non-zero unknown fields\n");
	s1 = find("QUOTA_INFORMATION");
	if (s1) {
		VAL_UNKNOWN(quota_information, unknown[0]);
		VAL_UNKNOWN(quota_information, unknown[1]);
		VAL_UNKNOWN(quota_information, unknown[2]);
	}

	s1 = find("OBJECTID_INFORMATION");
	if (s1) {
		VAL_UNKNOWN(objectid_information, unknown[0]);
		VAL_UNKNOWN(objectid_information, unknown[1]);
		VAL_UNKNOWN(objectid_information, unknown[2]);
		VAL_UNKNOWN(objectid_information, unknown[3]);
		VAL_UNKNOWN(objectid_information, unknown[4]);
		VAL_UNKNOWN(objectid_information, unknown[5]);
	}


#define STR_CHECK(sname, stype, field, flags) do { \
	s1 = find(sname); \
	if (s1) { \
		if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli->transport)) { \
			printf("(%d) incorrect string termination in %s/%s\n", \
			       __LINE__, #stype, #field); \
			ret = false; \
		} \
	}} while (0)

	torture_comment(torture, "check for correct termination\n");
	
	STR_CHECK("VOLUME",                volume,         volume_name, 0);
	STR_CHECK("VOLUME_INFO",           volume_info,    volume_name, STR_UNICODE);
	STR_CHECK("VOLUME_INFORMATION",    volume_info,    volume_name, STR_UNICODE);
	STR_CHECK("ATTRIBUTE_INFO",        attribute_info, fs_type, STR_UNICODE);
	STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info, fs_type, STR_UNICODE);

	return ret;
}