1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * SMB: query_information_disk 28 * 29 * The SMB_COM_QUERY_INFORMATION_DISK command is used to determine the 30 * capacity and remaining free space on the drive hosting the directory 31 * structure indicated by Tid in the SMB header. 32 * 33 * Client Request Description 34 * ================================== ================================= 35 * 36 * UCHAR WordCount; Count of parameter words = 0 37 * USHORT ByteCount; Count of data bytes = 0 38 * 39 * Server Response Description 40 * ================================== ================================= 41 * 42 * UCHAR WordCount; Count of parameter words = 5 43 * USHORT TotalUnits; Total allocation units per server 44 * USHORT BlocksPerUnit; Blocks per allocation unit 45 * USHORT BlockSize; Block size (in bytes) 46 * USHORT FreeUnits; Number of free units 47 * USHORT Reserved; Reserved (client should ignore) 48 * USHORT ByteCount; Count of data bytes = 0 49 * 50 * The blocking/allocation units used in this response may be independent 51 * of the actual physical or logical blocking/allocation algorithm(s) used 52 * internally by the server. However, they must accurately reflect the 53 * amount of space on the server. 54 * 55 * This SMB only returns 16 bits of information for each field, which may 56 * not be large enough for some disk systems. In particular TotalUnits is 57 * commonly > 64K. Fortunately, it turns out the all the client cares 58 * about is the total disk size, in bytes, and the free space, in bytes. 59 * So, it is reasonable for a server to adjust the relative values of 60 * BlocksPerUnit and BlockSize to accommodate. If after all adjustment, 61 * the numbers are still too high, the largest possible values for 62 * TotalUnit or FreeUnits (i.e. 0xFFFF) should be returned. 63 */ 64 65 #include <smbsrv/smb_kproto.h> 66 #include <smbsrv/smb_fsops.h> 67 68 smb_sdrc_t 69 smb_pre_query_information_disk(smb_request_t *sr) 70 { 71 DTRACE_SMB_1(op__QueryInformationDisk__start, smb_request_t *, sr); 72 return (SDRC_SUCCESS); 73 } 74 75 void 76 smb_post_query_information_disk(smb_request_t *sr) 77 { 78 DTRACE_SMB_1(op__QueryInformationDisk__done, smb_request_t *, sr); 79 } 80 81 smb_sdrc_t 82 smb_com_query_information_disk(smb_request_t *sr) 83 { 84 int rc; 85 struct statvfs64 df; 86 fsblkcnt64_t total_blocks, free_blocks; 87 unsigned long block_size, unit_size; 88 unsigned short blocks_per_unit, bytes_per_block; 89 unsigned short total_units, free_units; 90 91 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 92 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 93 return (SDRC_ERROR); 94 } 95 96 rc = smb_fsop_statfs(sr->user_cr, sr->tid_tree->t_snode, &df); 97 if (rc != 0) { 98 smbsr_errno(sr, rc); 99 return (SDRC_ERROR); 100 } 101 102 unit_size = 1; 103 block_size = df.f_frsize; 104 total_blocks = df.f_blocks; 105 free_blocks = df.f_bavail; 106 107 /* 108 * It seems that DOS clients cannot handle block sizes 109 * bigger than 512 KB. So we have to set the block size at 110 * most to 512 111 */ 112 113 while (block_size > 512) { 114 block_size >>= 1; 115 unit_size <<= 1; 116 } 117 118 /* adjust blocks and sizes until they fit into a word */ 119 120 while (total_blocks >= 0xFFFF) { 121 total_blocks >>= 1; 122 free_blocks >>= 1; 123 if ((unit_size <<= 1) > 0xFFFF) { 124 unit_size >>= 1; 125 total_blocks = 0xFFFF; 126 free_blocks <<= 1; 127 break; 128 } 129 } 130 131 total_units = (total_blocks >= 0xFFFF) ? 132 0xFFFF : (unsigned short)total_blocks; 133 free_units = (free_blocks >= 0xFFFF) ? 134 0xFFFF : (unsigned short)free_blocks; 135 bytes_per_block = (unsigned short)block_size; 136 blocks_per_unit = (unsigned short)unit_size; 137 138 rc = smbsr_encode_result(sr, 5, 0, "bwwww2.w", 139 5, 140 total_units, /* total_units */ 141 blocks_per_unit, /* blocks_per_unit */ 142 bytes_per_block, /* blocksize */ 143 free_units, /* free_units */ 144 0); /* bcc */ 145 146 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 147 } 148