├── APPLE_LICENSE ├── CONTRIBUTING.md ├── PULL_REQUEST_TEMPLATE.md └── src ├── fstorture ├── CHANGELOG ├── LICENSE ├── Makefile ├── README ├── basictypes.h ├── cmpdir.c ├── cmpdir.h ├── cmpfile.c ├── cmpfile.h ├── fileemu.c ├── fileemu.h ├── fstorture.c ├── stdheaders.h ├── testPerformance └── util.h └── fsx ├── Makefile └── fsx.c /APPLE_LICENSE: -------------------------------------------------------------------------------- 1 | APPLE PUBLIC SOURCE LICENSE 2 | Version 2.0 - August 6, 2003 3 | 4 | Please read this License carefully before downloading this software. By 5 | downloading or using this software, you are agreeing to be bound by the terms 6 | of this License. If you do not or cannot agree to the terms of this License, 7 | please do not download or use the software. 8 | 9 | Apple Note: In January 2007, Apple changed its corporate name from "Apple 10 | Computer, Inc." to "Apple Inc." This change has been reflected below and 11 | copyright years updated, but no other changes have been made to the APSL 2.0. 12 | 13 | 1. General; Definitions. This License applies to any program or other 14 | work which Apple Inc. ("Apple") makes publicly available and which contains a 15 | notice placed by Apple identifying such program or work as "Original Code" and 16 | stating that it is subject to the terms of this Apple Public Source License 17 | version 2.0 ("License"). As used in this License: 18 | 19 | 1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is the 20 | grantor of rights, (i) claims of patents that are now or hereafter acquired, 21 | owned by or assigned to Apple and (ii) that cover subject matter contained in 22 | the Original Code, but only to the extent necessary to use, reproduce and/or 23 | distribute the Original Code without infringement; and (b) in the case where 24 | You are the grantor of rights, (i) claims of patents that are now or hereafter 25 | acquired, owned by or assigned to You and (ii) that cover subject matter in 26 | Your Modifications, taken alone or in combination with Original Code. 27 | 28 | 1.2 "Contributor" means any person or entity that creates or contributes to 29 | the creation of Modifications. 30 | 31 | 1.3 "Covered Code" means the Original Code, Modifications, the combination 32 | of Original Code and any Modifications, and/or any respective portions thereof. 33 | 34 | 1.4 "Externally Deploy" means: (a) to sublicense, distribute or otherwise 35 | make Covered Code available, directly or indirectly, to anyone other than You; 36 | and/or (b) to use Covered Code, alone or as part of a Larger Work, in any way 37 | to provide a service, including but not limited to delivery of content, through 38 | electronic communication with a client other than You. 39 | 40 | 1.5 "Larger Work" means a work which combines Covered Code or portions 41 | thereof with code not governed by the terms of this License. 42 | 43 | 1.6 "Modifications" mean any addition to, deletion from, and/or change to, 44 | the substance and/or structure of the Original Code, any previous 45 | Modifications, the combination of Original Code and any previous Modifications, 46 | and/or any respective portions thereof. When code is released as a series of 47 | files, a Modification is: (a) any addition to or deletion from the contents of 48 | a file containing Covered Code; and/or (b) any new file or other representation 49 | of computer program statements that contains any part of Covered Code. 50 | 51 | 1.7 "Original Code" means (a) the Source Code of a program or other work as 52 | originally made available by Apple under this License, including the Source 53 | Code of any updates or upgrades to such programs or works made available by 54 | Apple under this License, and that has been expressly identified by Apple as 55 | such in the header file(s) of such work; and (b) the object code compiled from 56 | such Source Code and originally made available by Apple under this License 57 | 58 | 1.8 "Source Code" means the human readable form of a program or other work 59 | that is suitable for making modifications to it, including all modules it 60 | contains, plus any associated interface definition files, scripts used to 61 | control compilation and installation of an executable (object code). 62 | 63 | 1.9 "You" or "Your" means an individual or a legal entity exercising rights 64 | under this License. For legal entities, "You" or "Your" includes any entity 65 | which controls, is controlled by, or is under common control with, You, where 66 | "control" means (a) the power, direct or indirect, to cause the direction or 67 | management of such entity, whether by contract or otherwise, or (b) ownership 68 | of fifty percent (50%) or more of the outstanding shares or beneficial 69 | ownership of such entity. 70 | 71 | 2. Permitted Uses; Conditions & Restrictions. Subject to the terms and 72 | conditions of this License, Apple hereby grants You, effective on the date You 73 | accept this License and download the Original Code, a world-wide, royalty-free, 74 | non-exclusive license, to the extent of Apple's Applicable Patent Rights and 75 | copyrights covering the Original Code, to do the following: 76 | 77 | 2.1 Unmodified Code. You may use, reproduce, display, perform, internally 78 | distribute within Your organization, and Externally Deploy verbatim, unmodified 79 | copies of the Original Code, for commercial or non-commercial purposes, 80 | provided that in each instance: 81 | 82 | (a) You must retain and reproduce in all copies of Original Code the 83 | copyright and other proprietary notices and disclaimers of Apple as they appear 84 | in the Original Code, and keep intact all notices in the Original Code that 85 | refer to this License; and 86 | 87 | (b) You must include a copy of this License with every copy of Source Code 88 | of Covered Code and documentation You distribute or Externally Deploy, and You 89 | may not offer or impose any terms on such Source Code that alter or restrict 90 | this License or the recipients' rights hereunder, except as permitted under 91 | Section 6. 92 | 93 | 2.2 Modified Code. You may modify Covered Code and use, reproduce, 94 | display, perform, internally distribute within Your organization, and 95 | Externally Deploy Your Modifications and Covered Code, for commercial or 96 | non-commercial purposes, provided that in each instance You also meet all of 97 | these conditions: 98 | 99 | (a) You must satisfy all the conditions of Section 2.1 with respect to the 100 | Source Code of the Covered Code; 101 | 102 | (b) You must duplicate, to the extent it does not already exist, the notice 103 | in Exhibit A in each file of the Source Code of all Your Modifications, and 104 | cause the modified files to carry prominent notices stating that You changed 105 | the files and the date of any change; and 106 | 107 | (c) If You Externally Deploy Your Modifications, You must make Source Code 108 | of all Your Externally Deployed Modifications either available to those to whom 109 | You have Externally Deployed Your Modifications, or publicly available. Source 110 | Code of Your Externally Deployed Modifications must be released under the terms 111 | set forth in this License, including the license grants set forth in Section 3 112 | below, for as long as you Externally Deploy the Covered Code or twelve (12) 113 | months from the date of initial External Deployment, whichever is longer. You 114 | should preferably distribute the Source Code of Your Externally Deployed 115 | Modifications electronically (e.g. download from a web site). 116 | 117 | 2.3 Distribution of Executable Versions. In addition, if You Externally 118 | Deploy Covered Code (Original Code and/or Modifications) in object code, 119 | executable form only, You must include a prominent notice, in the code itself 120 | as well as in related documentation, stating that Source Code of the Covered 121 | Code is available under the terms of this License with information on how and 122 | where to obtain such Source Code. 123 | 124 | 2.4 Third Party Rights. You expressly acknowledge and agree that although 125 | Apple and each Contributor grants the licenses to their respective portions of 126 | the Covered Code set forth herein, no assurances are provided by Apple or any 127 | Contributor that the Covered Code does not infringe the patent or other 128 | intellectual property rights of any other entity. Apple and each Contributor 129 | disclaim any liability to You for claims brought by any other entity based on 130 | infringement of intellectual property rights or otherwise. As a condition to 131 | exercising the rights and licenses granted hereunder, You hereby assume sole 132 | responsibility to secure any other intellectual property rights needed, if any. 133 | For example, if a third party patent license is required to allow You to 134 | distribute the Covered Code, it is Your responsibility to acquire that license 135 | before distributing the Covered Code. 136 | 137 | 3. Your Grants. In consideration of, and as a condition to, the licenses 138 | granted to You under this License, You hereby grant to any person or entity 139 | receiving or distributing Covered Code under this License a non-exclusive, 140 | royalty-free, perpetual, irrevocable license, under Your Applicable Patent 141 | Rights and other intellectual property rights (other than patent) owned or 142 | controlled by You, to use, reproduce, display, perform, modify, sublicense, 143 | distribute and Externally Deploy Your Modifications of the same scope and 144 | extent as Apple's licenses under Sections 2.1 and 2.2 above. 145 | 146 | 4. Larger Works. You may create a Larger Work by combining Covered Code 147 | with other code not governed by the terms of this License and distribute the 148 | Larger Work as a single product. In each such instance, You must make sure the 149 | requirements of this License are fulfilled for the Covered Code or any portion 150 | thereof. 151 | 152 | 5. Limitations on Patent License. Except as expressly stated in Section 153 | 2, no other patent rights, express or implied, are granted by Apple herein. 154 | Modifications and/or Larger Works may require additional patent licenses from 155 | Apple which Apple may grant in its sole discretion. 156 | 157 | 6. Additional Terms. You may choose to offer, and to charge a fee for, 158 | warranty, support, indemnity or liability obligations and/or other rights 159 | consistent with the scope of the license granted herein ("Additional Terms") to 160 | one or more recipients of Covered Code. However, You may do so only on Your own 161 | behalf and as Your sole responsibility, and not on behalf of Apple or any 162 | Contributor. You must obtain the recipient's agreement that any such Additional 163 | Terms are offered by You alone, and You hereby agree to indemnify, defend and 164 | hold Apple and every Contributor harmless for any liability incurred by or 165 | claims asserted against Apple or such Contributor by reason of any such 166 | Additional Terms. 167 | 168 | 7. Versions of the License. Apple may publish revised and/or new versions 169 | of this License from time to time. Each version will be given a distinguishing 170 | version number. Once Original Code has been published under a particular 171 | version of this License, You may continue to use it under the terms of that 172 | version. You may also choose to use such Original Code under the terms of any 173 | subsequent version of this License published by Apple. No one other than Apple 174 | has the right to modify the terms applicable to Covered Code created under this 175 | License. 176 | 177 | 8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in 178 | part pre-release, untested, or not fully tested works. The Covered Code may 179 | contain errors that could cause failures or loss of data, and may be incomplete 180 | or contain inaccuracies. You expressly acknowledge and agree that use of the 181 | Covered Code, or any portion thereof, is at Your sole and entire risk. THE 182 | COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF 183 | ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" 184 | FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM 185 | ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT 186 | LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF 187 | SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF 188 | QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE AND EACH 189 | CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE 190 | COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR 191 | REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR 192 | ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR 193 | WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE AUTHORIZED 194 | REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You acknowledge 195 | that the Covered Code is not intended for use in the operation of nuclear 196 | facilities, aircraft navigation, communication systems, or air traffic control 197 | machines in which case the failure of the Covered Code could lead to death, 198 | personal injury, or severe physical or environmental damage. 199 | 200 | 9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO 201 | EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, 202 | INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR 203 | YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER 204 | UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS 205 | LIABILITY OR OTHERWISE, EVEN IF APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF 206 | THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL 207 | PURPOSE OF ANY REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF 208 | LIABILITY OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT 209 | APPLY TO YOU. In no event shall Apple's total liability to You for all damages 210 | (other than as may be required by applicable law) under this License exceed the 211 | amount of fifty dollars ($50.00). 212 | 213 | 10. Trademarks. This License does not grant any rights to use the 214 | trademarks or trade names "Apple", "Mac", "Mac OS", "QuickTime", "QuickTime 215 | Streaming Server" or any other trademarks, service marks, logos or trade names 216 | belonging to Apple (collectively "Apple Marks") or to any trademark, service 217 | mark, logo or trade name belonging to any Contributor. You agree not to use 218 | any Apple Marks in or as part of the name of products derived from the Original 219 | Code or to endorse or promote products derived from the Original Code other 220 | than as expressly permitted by and in strict compliance at all times with 221 | Apple's third party trademark usage guidelines which are posted at 222 | http://www.apple.com/legal/guidelinesfor3rdparties.html. 223 | 224 | 11. Ownership. Subject to the licenses granted under this License, each 225 | Contributor retains all rights, title and interest in and to any Modifications 226 | made by such Contributor. Apple retains all rights, title and interest in and 227 | to the Original Code and any Modifications made by or on behalf of Apple 228 | ("Apple Modifications"), and such Apple Modifications will not be automatically 229 | subject to this License. Apple may, at its sole discretion, choose to license 230 | such Apple Modifications under this License, or on different terms from those 231 | contained in this License or may choose not to license them at all. 232 | 233 | 12. Termination. 234 | 235 | 12.1 Termination. This License and the rights granted hereunder will 236 | terminate: 237 | 238 | (a) automatically without notice from Apple if You fail to comply with any 239 | term(s) of this License and fail to cure such breach within 30 days of becoming 240 | aware of such breach; 241 | (b) immediately in the event of the circumstances described in Section 242 | 13.5(b); or 243 | (c) automatically without notice from Apple if You, at any time during the 244 | term of this License, commence an action for patent infringement against Apple; 245 | provided that Apple did not first commence an action for patent infringement 246 | against You in that instance. 247 | 248 | 12.2 Effect of Termination. Upon termination, You agree to immediately stop 249 | any further use, reproduction, modification, sublicensing and distribution of 250 | the Covered Code. All sublicenses to the Covered Code which have been properly 251 | granted prior to termination shall survive any termination of this License. 252 | Provisions which, by their nature, should remain in effect beyond the 253 | termination of this License shall survive, including but not limited to 254 | Sections 3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other 255 | for compensation, indemnity or damages of any sort solely as a result of 256 | terminating this License in accordance with its terms, and termination of this 257 | License will be without prejudice to any other right or remedy of any party. 258 | 259 | 13. Miscellaneous. 260 | 261 | 13.1 Government End Users. The Covered Code is a "commercial item" as 262 | defined in FAR 2.101. Government software and technical data rights in the 263 | Covered Code include only those rights customarily provided to the public as 264 | defined in this License. This customary commercial license in technical data 265 | and software is provided in accordance with FAR 12.211 (Technical Data) and 266 | 12.212 (Computer Software) and, for Department of Defense purchases, DFAR 267 | 252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3 (Rights in 268 | Commercial Computer Software or Computer Software Documentation). Accordingly, 269 | all U.S. Government End Users acquire Covered Code with only those rights set 270 | forth herein. 271 | 272 | 13.2 Relationship of Parties. This License will not be construed as 273 | creating an agency, partnership, joint venture or any other form of legal 274 | association between or among You, Apple or any Contributor, and You will not 275 | represent to the contrary, whether expressly, by implication, appearance or 276 | otherwise. 277 | 278 | 13.3 Independent Development. Nothing in this License will impair Apple's 279 | right to acquire, license, develop, have others develop for it, market and/or 280 | distribute technology or products that perform the same or similar functions 281 | as, or otherwise compete with, Modifications, Larger Works, technology or 282 | products that You may develop, produce, market or distribute. 283 | 284 | 13.4 Waiver; Construction. Failure by Apple or any Contributor to enforce 285 | any provision of this License will not be deemed a waiver of future enforcement 286 | of that or any other provision. Any law or regulation which provides that the 287 | language of a contract shall be construed against the drafter will not apply to 288 | this License. 289 | 290 | 13.5 Severability. (a) If for any reason a court of competent jurisdiction 291 | finds any provision of this License, or portion thereof, to be unenforceable, 292 | that provision of the License will be enforced to the maximum extent 293 | permissible so as to effect the economic benefits and intent of the parties, 294 | and the remainder of this License will continue in full force and effect. (b) 295 | Notwithstanding the foregoing, if applicable law prohibits or restricts You 296 | from fully and/or specifically complying with Sections 2 and/or 3 or prevents 297 | the enforceability of either of those Sections, this License will immediately 298 | terminate and You must immediately discontinue any use of the Covered Code and 299 | destroy all copies of it that are in your possession or control. 300 | 301 | 13.6 Dispute Resolution. Any litigation or other dispute resolution between 302 | You and Apple relating to this License shall take place in the Northern 303 | District of California, and You and Apple hereby consent to the personal 304 | jurisdiction of, and venue in, the state and federal courts within that 305 | District with respect to this License. The application of the United Nations 306 | Convention on Contracts for the International Sale of Goods is expressly 307 | excluded. 308 | 309 | 13.7 Entire Agreement; Governing Law. This License constitutes the entire 310 | agreement between the parties with respect to the subject matter hereof. This 311 | License shall be governed by the laws of the United States and the State of 312 | California, except that body of California law concerning conflicts of law. 313 | 314 | Where You are located in the province of Quebec, Canada, the following clause 315 | applies: The parties hereby confirm that they have requested that this License 316 | and all related documents be drafted in English. Les parties ont exigé que le 317 | présent contrat et tous les documents connexes soient rédigés en anglais. 318 | 319 | EXHIBIT A. 320 | 321 | "Portions Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. 322 | 323 | This file contains Original Code and/or Modifications of Original Code as 324 | defined in and that are subject to the Apple Public Source License Version 2.0 325 | (the 'License'). You may not use this file except in compliance with the 326 | License. Please obtain a copy of the License at 327 | http://www.opensource.apple.com/apsl/ and read it before using this file. 328 | 329 | The Original Code and all software distributed under the License are 330 | distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 331 | OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 332 | LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 333 | PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 334 | specific language governing rights and limitations under the License." 335 | 336 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | By submitting a request, you represent that you have the right to license 2 | your contribution to the community, and agree that your contributions are 3 | licensed under the [GNU General Public License Version 4 | 2](src/fstorture/LICENSE) (for just the fstorture portions of the FS Tools 5 | project) or the [Apple Public Source License Version 2.0](APPLE_LICENSE) 6 | (for the remainder of the FS Tools project). 7 | 8 | For existing files modified by your request, you represent that you have 9 | retained any existing copyright notices and licensing terms. For each new 10 | file in your request, you represent that you have added to the file a 11 | copyright notice (including the year and the copyright owner's name) and the 12 | FS Tools licensing terms. 13 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | By submitting a request, you represent that you have the right to license 2 | your contribution to the community, and agree that your contributions are 3 | licensed under the [GNU General Public License Version 4 | 2](src/fstorture/LICENSE) (for just the fstorture portions of the FS Tools 5 | project) or the [Apple Public Source License Version 2.0](APPLE_LICENSE) 6 | (for the remainder of the FS Tools project). 7 | 8 | For existing files modified by your request, you represent that you have 9 | retained any existing copyright notices and licensing terms. For each new 10 | file in your request, you represent that you have added to the file a 11 | copyright notice (including the year and the copyright owner's name) and the 12 | FS Tools licensing terms. 13 | -------------------------------------------------------------------------------- /src/fstorture/CHANGELOG: -------------------------------------------------------------------------------- 1 | 2.1 [01/16/06] 2 | * George Colley: Added "windows_volume"/"windows98" & "no_unlink_open_files" flags 3 | * Log file handling bug fixes 4 | 5 | 2.0 [11/30/05] 6 | Added XILog functionality; cleaned up error handling 7 | Added lots of options 8 | Removed "Kill this PID on error" argument (but we're still backwards-compatible) 9 | Added XIPing 10 | 11 | 1.7 [11/17/05] 12 | Check volume capabilities for soft/hard links and ACLs 13 | 14 | 1.6 [11/07/05] 15 | soft/hard links added 16 | 17 | 1.5 [10/27/05] 18 | Unlinked files support 19 | 20 | 1.4 [10/13/05] 21 | ACL support added 22 | -------------------------------------------------------------------------------- /src/fstorture/LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /src/fstorture/Makefile: -------------------------------------------------------------------------------- 1 | # Name: Makefile 2 | # Project: CIFS Client Automatic Test 3 | # Author: Christian Starkjohann 4 | # Creation Date: 1998-04-20 5 | # Tabsize: 4 6 | # Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 7 | # under the terms of the Gnu General Public License (GPL). 8 | # 9 | # Copyright © 2009 Apple Inc. 10 | # This program is free software; you can redistribute it and/or modify it 11 | # under the terms of the GNU General Public License version 2 only. This 12 | # program is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 14 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | # version 2 for more details. A copy of the GNU General Public License 16 | # version 2 is included along with this program. 17 | # 18 | 19 | # 20 | # The testsoftware is currently not ported to all platforms Sharity 21 | # runs on. It is a naive quick hack to find bugs quickly. Please modify 22 | # the CFLAGS and LIBS lines appropriately for your platform. 23 | # 24 | 25 | # USE XILOG 26 | #CFLAGS= -Wall -g -O0 -DXILOG -F/AppleInternal/Library/Frameworks 27 | #ARCHES= -arch ppc -arch i386 -arch x86_64 28 | ARCHES= -arch x86_64 29 | #CFLAGS= $(ARCHES) -Wall -O3 -DXILOG -F/AppleInternal/Library/Frameworks 30 | #LDFLAGS= -framework XILog 31 | 32 | # DON'T USE XILOG 33 | CFLAGS= -Wall -O3 -fomit-frame-pointer 34 | 35 | # For Linux add: 36 | # LIBS = -lm 37 | 38 | OBJ = fileemu.o cmpfile.o cmpdir.o fstorture.o 39 | 40 | XNAME = fstorture 41 | 42 | all: $(XNAME) 43 | 44 | Project = $(XNAME) 45 | 46 | #include $(MAKEFILEPATH)/CoreOS/ReleaseControl/Common.make 47 | 48 | 49 | .c.o: 50 | $(CC) $(CFLAGS) -c $*.c -o $*.o 51 | 52 | clean:: 53 | rm -f $(OBJ) $(XNAME) 54 | 55 | $(XNAME):$(OBJ) 56 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) 57 | 58 | 59 | 60 | 61 | # More stuff 62 | 63 | 64 | XintInstall = $(DSTROOT)/$(HOME)/TestSuite/Tools/$(XNAME) 65 | 66 | install:: $(XintInstall)/$(XNAME) 67 | 68 | $(XintInstall)/$(XNAME):$(XNAME) 69 | $(CP) $(SRCROOT)/$(XNAME) $(SYMROOT) 70 | $(STRIP) $(SRCROOT)/$(XNAME) 71 | $(MKDIR) $(XintInstall) 72 | $(MV) $(SRCROOT)/$(XNAME) $(XintInstall) 73 | 74 | -------------------------------------------------------------------------------- /src/fstorture/README: -------------------------------------------------------------------------------- 1 | This is the README file for fstorture, a test program written to find bugs 2 | in Sharity. This test program performs random operations on the filesystem 3 | and verifies the results. 4 | 5 | WARNING: This program may crash your machine! See section "Known Problems" 6 | for details! 7 | 8 | 9 | What is fstorture? 10 | ================== 11 | fstorture performs the following filesystem operations in a reasonable (but 12 | still random) order with reasonable parameters and verifies the results: 13 | - creat() 14 | - mkdir() 15 | - open() 16 | - close() 17 | - read() 18 | - write() 19 | - truncate() 20 | - ftruncate() 21 | - chmod() 22 | - stat() 23 | - rename() 24 | - unlink() 25 | This is done in parallel from a given number of processes. 26 | fstorture is not user friendly and not distributed in binary versions, 27 | because it is intended for developers. If no problems are found, nothing 28 | will be printed. If you want to know the details of the test procedure, 29 | please look into the source code. 30 | 31 | In addition to fstorture, this package contains the shell script 32 | "testPerformance". This script performs some trivial performance tests on a 33 | given directory (which is assumed to be located on a remote server). It 34 | takes the path to the directory as a parameter and prints out the 35 | performance statistics. 36 | 37 | 38 | Commandline parameters 39 | ====================== 40 | The usage of fstorture is: 41 | 42 | fstorture [] 43 | 44 | The and are the directories where the 45 | filesystem test will be performed. There are two root directories 46 | to better test cross-directory renames. The root directories must 47 | exist and must be empty before fstorture is started. is the number of parallel running processes that will 49 | be used for the test. Each process operates on only one file or 50 | subdirectory at a time. You should choose this number appropriate 51 | for your system. Higher numbers mean more testing but can put a 52 | heavy load on the operating system. Good numbers are in the range 53 | of 5 to 100, depending on the load your kernel can take. 54 | are options that modify the way certain tests are performed or that 55 | switch off certain tests. It may be necessary to use these options 56 | to compensate for operating system bugs, different ideas of how 57 | things should work or different semantics. 58 | 59 | Available options: 60 | ------------------ 61 | * fsync_before_ftruncate 62 | It seems as if the truncate functionality were implemented totally 63 | independent of the rest of the filesystem functions on some 64 | operating systems. For instance, it may happen that a truncate 65 | operation "overtakes" a write operation. The sequence 66 | write(offset=1000, length=1000) 67 | truncate(500) 68 | may in fact be executed as 69 | truncate(500) 70 | write(offset=1000, length=1000) 71 | which results in a completely different file, of course. To work 72 | around this operating system bug, you can define 73 | "fsync_before_ftruncate". If this parameter is passed to fstorture, 74 | it executes an fsync() before every truncate() or ftruncate(). 75 | 76 | * no_rename_open_files 77 | Unix semantics allow to rename files while they are still open. 78 | Reads and writes will go to the same file even after renaming. 79 | Older versions of Sharity do not provide this behaviour and reads 80 | and writes to the old file will fail. If you test an older version 81 | of Sharity, add this option. 82 | 83 | * no_test_dirs 84 | fstorture also creates, renames and destroys directories during 85 | the test. The directories are populated with open files, even during 86 | renames. This is a hard test for the filing system and there are 87 | operating systems that introduce structural errors on the hard 88 | drive if this test is performed (on the hard drive, of course). If 89 | you don't want to perform the directory test, add this option. 90 | 91 | 92 | Setting up a Test 93 | ================= 94 | Before you start testing, you should be aware of several facts. You are 95 | testing the entire filesystem between the application and the disk. In the 96 | case of Sharity this consists of the system call library, the nfs client 97 | in the kernel, the Sharity daemon, the CIFS/SMB-server software and the 98 | filesystem on the kernel. If an error occures, it may be in any of these 99 | components. 100 | 101 | Before you start testing Sharity, please make sure the other 102 | components work appropriately. First you should try fstorture on the local 103 | filesystem. There you can verify whether your OS has bugs. If you find one, 104 | you can disable the specific test or aspect of the test. 105 | 106 | If that works, try it on an NFS mounted directory. This tests the local 107 | filesystem code, the NFS client in the kernel and the NFS server. If no 108 | problems occure, you can switch over to Sharity. Always start with a low 109 | number of parallel processes until you become more confident. 110 | 111 | 112 | Known Problems 113 | ============== 114 | Here is a list of known problems in clients, servers and Sharity: 115 | 116 | NEXTSTEP, OPENSTEP/Mach operating system: 117 | ----------------------------------------- 118 | Never try fstorture with the directory test enabled on NEXTSTEP! It will 119 | destroy parts of the filesystem structure and you will have to perform 120 | a manual disk check (which resulted in a kernel panic when I did it....). 121 | 122 | The NFS client code is buggy. You will always read incorrect file sizes with 123 | any NFS server. After some minutes or even seconds of test with any NFS 124 | server, the system will freeze. 125 | 126 | Linux operating system: 127 | ----------------------- 128 | No known bugs. If you are low on real memory (RAM), the kernel 129 | might get into trouble being inable to get real memory. The system 130 | may freeze in this case. 131 | 132 | Windows NT server: 133 | ------------------ 134 | NT does not always give correct file sizes. In fact, the file size is almost 135 | always wrong if the file has been written to recently. NT probably does 136 | writeback caching and returns the size of the file on disk instead of the 137 | logical size determined by the cache. Sharity tries to work around this 138 | problem, but it might fail sometimes. NT does not always send OPLOCK breaks 139 | when it should. This made older versions of Sharity fail on some rename 140 | operations. Newer versions of Sharity don't rely on OPLOCKs for renames, 141 | but the bug might still be a problem if some clients access the same file 142 | concurrently. 143 | 144 | Windows 95 server: 145 | ------------------ 146 | The CIFS/SMB server code in Win 95 is, well, very buggy. There are the same 147 | bugs as with Win NT and others related to write protection semantics. 148 | Sharity can not always work around these problems, although it tries 149 | everything that is possible. It is, for instance, impossible to have a file 150 | open for write that is write protected. If this is required from the 151 | Unix side, the file is simply un-writeprotected transparently. The file will 152 | then stat with wrong write protection status, of course. The workaround 153 | for the "wrong filesize" bug also does not work as good as for NT because 154 | Win 95 does not support oplocks. 155 | 156 | Sharity: 157 | -------- 158 | Sharity has two possible options for the file lookup strategy (see the 159 | manual, section "configuration file" for details). One provides real 160 | Unix-like semantics (the "database" option) and the other does not allow 161 | renaming open files (the "pseudoInode" option). If you test Sharity with 162 | the "pseudoInode" option, you should use the options no_rename_open_files 163 | and no_test_dirs. On Solaris you will see errors even with these options due 164 | to a bug in the writeback cache implementation of the Solaris NFS client. 165 | 166 | 167 | Note for Developers 168 | =================== 169 | This program is not supported software, it is also not a reference for 170 | good programming style, but it's a real quick hack. It has limited 171 | complexity and should do it's job quite well. It's not intended to be 172 | easily portable, although it probably is due to the low number of system 173 | calls needed. I have tested it on NEXTSTEP, OPENSTEP/Mach and Linux, others 174 | probably need some porting. fstorture is probably not bug-free, although 175 | I have gone through all of the code several times. 176 | 177 | General Disclaimer 178 | ================== 179 | Be prepared for the worst! The sentence "This software may 180 | damage your machine or kill your hamster", usually inserted as default 181 | disclaimer, has to be taken seriously with fstorture! It's built to trigger 182 | problems in the filesystem! For the exact wording of the disclaimer please 183 | consult the GNU General Public License. 184 | 185 | 186 | --- 187 | Contact information: 188 | e-mail: office@obdev.at 189 | www: http://www.obdev.at/ 190 | Author: Christian Starkjohann 191 | 192 | -------------------------------------------------------------------------------- /src/fstorture/basictypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: basictypes.h 3 | * Project: CIFS Client Automatic Test 4 | * Author: Christian Starkjohann 5 | * Creation Date: 1998-04-20 6 | * Tabsize: 4 7 | * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | * under the terms of the Gnu General Public License (GPL). 9 | * 10 | * Copyright © 2009 Apple Inc. 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 only. This 13 | * program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * version 2 for more details. A copy of the GNU General Public License 17 | * version 2 is included along with this program. 18 | */ 19 | 20 | #ifndef __BASICTYPES_H_INCLUDED__ 21 | #define __BASICTYPES_H_INCLUDED__ 22 | 23 | /* 24 | General Description: 25 | This header defines an abstraction for the primitive C datatypes. It is not 26 | necessary to have this in the simple test program, but I became used to 27 | the bt* names... 28 | */ 29 | 30 | #define bti8 char 31 | #define bti16 short 32 | #define bti32 int 33 | #define bti64 long long 34 | #define btu8 unsigned char 35 | #define btu16 unsigned short 36 | #define btu32 unsigned 37 | #define btu64 unsigned long long 38 | #define btoffset btu32 /* offset in files (currently 32 bit) */ 39 | #define btuni unsigned short /* unicode character */ 40 | #define btbool char 41 | 42 | #define btsize int /* for data block sizes */ 43 | #define btint int /* fast integer, min 32 bit long */ 44 | 45 | 46 | #endif /* __BASICTYPES_H_INCLUDED__ */ 47 | -------------------------------------------------------------------------------- /src/fstorture/cmpdir.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: cmpdir.c 3 | * Project: CIFS Client Automatic Test 4 | * Author: Christian Starkjohann 5 | * Creation Date: 1998-04-28 6 | * Tabsize: 4 7 | * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | * under the terms of the Gnu General Public License (GPL). 9 | * 10 | * Copyright © 2009 Apple Inc. 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 only. This 13 | * program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * version 2 for more details. A copy of the GNU General Public License 17 | * version 2 is included along with this program. 18 | */ 19 | 20 | #include "stdheaders.h" 21 | #include "cmpdir.h" 22 | #include "util.h" 23 | 24 | extern int trace; 25 | char *acl_perm_dir_n[] = { "list", "add_file", "search", "delete", "add_subdirectory", "delete_child", "readattr", "writeattr", "readextattr", "writeextattr", "readsecurity", "writesecurity", "chown" }; 26 | int acl_perm_t_dir_r[] = { ACL_LIST_DIRECTORY, ACL_ADD_FILE, ACL_SEARCH, ACL_DELETE, ACL_ADD_SUBDIRECTORY, ACL_DELETE_CHILD, ACL_READ_ATTRIBUTES, ACL_WRITE_ATTRIBUTES, ACL_READ_EXTATTRIBUTES, ACL_WRITE_EXTATTRIBUTES, ACL_READ_SECURITY, ACL_WRITE_SECURITY, ACL_CHANGE_OWNER }; 27 | char errstr[1024]; 28 | 29 | /* ------------------------------------------------------------------------- */ 30 | 31 | const int BUF_SIZE=32768; 32 | 33 | static unsigned char *blockWithPattern(int pattern, unsigned char block[BUF_SIZE]) 34 | { 35 | int i; 36 | srand(pattern); /* make reproducible random sequence */ 37 | for(i=0;i> 8; 39 | return block; 40 | } 41 | 42 | static btbool verifyFile(cmpdir_t *dir, int i) 43 | { 44 | int fileLen; 45 | unsigned char block[BUF_SIZE], buffer[BUF_SIZE]; 46 | 47 | if(lseek(dir->files[i].fd, 0, SEEK_SET) == -1){ 48 | perr(errno, "error seeking (read) in file %s in dir %s", dir->files[i].name, dir->name); 49 | return 0; 50 | } 51 | fileLen = read(dir->files[i].fd, buffer, BUF_SIZE); 52 | if(fileLen < 0){ 53 | perr(errno, "error reading file %s in dir %s", dir->files[i].name, dir->name); 54 | return 0; 55 | } 56 | if(fileLen != BUF_SIZE){ 57 | perr(errno, "read size error reading file %s in dir %s: %d", dir->files[i].name, dir->name, fileLen); 58 | return 0; 59 | } 60 | blockWithPattern(dir->files[i].filePattern, block); 61 | if(memcmp(block, buffer, BUF_SIZE) != 0){ 62 | perr(errno, "verify error in file %s in dir %s filepattern:%d", dir->files[i].name, dir->name, dir->files[i].filePattern); 63 | return 0; 64 | } 65 | return 1; 66 | } 67 | 68 | /* ------------------------------------------------------------------------- */ 69 | 70 | cmpdir_t *cmpdirNew(char *path) 71 | { 72 | cmpdir_t *dir = calloc(1, sizeof(cmpdir_t)); 73 | 74 | if(trace) 75 | printf("creating directory %s\n", path); 76 | dir->name = malloc(strlen(path) + 1); 77 | strcpy(dir->name, path); 78 | if(mkdir(path, 0700) != 0){ 79 | perr(errno, "error making dir %s", path); 80 | free(dir->name); 81 | free(dir); 82 | return NULL; 83 | } 84 | return dir; 85 | } 86 | 87 | /* ------------------------------------------------------------------------- */ 88 | 89 | btbool cmpdirFree(cmpdir_t *dir) 90 | { 91 | int i; 92 | btbool rval = 1; 93 | char path[1024]; 94 | 95 | if(trace) 96 | printf("destroying directory %s\n", dir->name); 97 | for(i=0;ifiles[i].name[0] != 0){ 99 | if(!verifyFile(dir, i)) 100 | rval = 0; 101 | if(close(dir->files[i].fd)){ 102 | perr(errno, "error closing file %s in dir %s", dir->files[i].name, dir->name); 103 | rval = 0; 104 | } 105 | sprintf(path, "%s/%s", dir->name, dir->files[i].name); 106 | if(unlink(path)){ 107 | perr(errno, "error unlinking file %s", path); 108 | rval = 0; 109 | } 110 | dir->files[i].fd = 0; 111 | dir->files[i].name[0] = 0; 112 | } 113 | } 114 | if(rmdir(dir->name)){ 115 | perr(errno, "error removing dir %s", dir->name); 116 | rval = 0; 117 | } 118 | if(dir->name != NULL) 119 | free(dir->name); 120 | free(dir); 121 | return rval; 122 | } 123 | 124 | /* ------------------------------------------------------------------------- */ 125 | 126 | btbool cmpdirRename(cmpdir_t *dir, char *newPath, int WinVolume) 127 | { 128 | int ii; 129 | 130 | if(trace) 131 | printf("renaming directory %s to %s\n", dir->name, newPath); 132 | if(rename(dir->name, newPath) < 0) { 133 | /* 134 | * Remember that Windows will not let you rename a directory, if 135 | * there is an open file in the directory. So if we get an EACCES 136 | * error, and there are any open files in the directory just ignore 137 | * the error. 138 | */ 139 | if (WinVolume && (errno == EACCES)) { 140 | for (ii = 0; ii < CMPDIR_MAX_FILES; ii++) 141 | if (dir->files[ii].fd) 142 | return 1; 143 | } 144 | perr(errno, "error renaming dir %s to %s", dir->name, newPath); 145 | return 0; 146 | } 147 | free(dir->name); 148 | dir->name = malloc(strlen(newPath) + 1); 149 | strcpy(dir->name, newPath); 150 | return 1; 151 | } 152 | 153 | /* ------------------------------------------------------------------------- */ 154 | 155 | btbool cmpdirChangeFiles(cmpdir_t *dir) 156 | { 157 | btbool rval = 1; 158 | int i, len; 159 | char path[1024]; 160 | unsigned char block[BUF_SIZE]; 161 | 162 | if(trace) 163 | printf("changing file in %s\n", dir->name); 164 | i = random_int(CMPDIR_MAX_FILES); 165 | if(dir->files[i].name[0]){ /* file exists */ 166 | if(!verifyFile(dir, i)) 167 | rval = 0; 168 | if(close(dir->files[i].fd)){ 169 | perr(errno, "error closing file %s in dir %s", dir->files[i].name, dir->name); 170 | rval = 0; 171 | } 172 | sprintf(path, "%s/%s", dir->name, dir->files[i].name); 173 | if(unlink(path)){ 174 | perr(errno, "error unlinking file %s", path); 175 | rval = 0; 176 | } 177 | dir->files[i].fd = 0; 178 | dir->files[i].name[0] = 0; 179 | }else{ /* file does not exist */ 180 | random_name(dir->files[i].name, 8, i); 181 | dir->files[i].filePattern = random_int(65536); 182 | sprintf(path, "%s/%s", dir->name, dir->files[i].name); 183 | if((dir->files[i].fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0){ 184 | perr(errno, "error creating file %s in dir %s", dir->files[i].name, dir->name); 185 | rval = 0; 186 | dir->files[i].fd = 0; 187 | dir->files[i].name[0] = 0; 188 | }else{ 189 | if((len = write(dir->files[i].fd, blockWithPattern(dir->files[i].filePattern, block), BUF_SIZE)) != BUF_SIZE){ 190 | perr(errno, "error writing file %s, wlen = %d", path, len); 191 | rval = 0; 192 | } 193 | } 194 | } 195 | return rval; 196 | } 197 | 198 | /* ------------------------------------------------------------------------- */ 199 | 200 | btbool cmpdirVerifyFiles(cmpdir_t *dir) 201 | { 202 | btbool rval = 1; 203 | int i; 204 | 205 | if(trace) 206 | printf("verifying all in %s\n", dir->name); 207 | for(i=0;ifiles[i].name[0]){ /* file exists */ 209 | if(!verifyFile(dir, i)) 210 | rval = 0; 211 | } 212 | } 213 | return rval; 214 | } 215 | 216 | /* ------------------------------------------------------------------------- */ 217 | -------------------------------------------------------------------------------- /src/fstorture/cmpdir.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: cmpdir.h 3 | * Project: CIFS Client Automatic Test 4 | * Author: Christian Starkjohann 5 | * Creation Date: 1998-04-28 6 | * Tabsize: 4 7 | * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | * under the terms of the Gnu General Public License (GPL). 9 | * 10 | * Copyright © 2009 Apple Inc. 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 only. This 13 | * program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * version 2 for more details. A copy of the GNU General Public License 17 | * version 2 is included along with this program. 18 | */ 19 | 20 | /* ------------------------------------------------------------------------- */ 21 | 22 | #include "basictypes.h" 23 | #include 24 | 25 | //char *acl_perm_dir_n[] = { "list", "add_file", "search", "delete", "add_subdirectory", "delete_child", "readattr", "writeattr", "readextattr", "writeextattr", "readsecurity", "writesecurity", "chown" }; 26 | //int acl_perm_t_dir_r[] = { ACL_LIST_DIRECTORY, ACL_ADD_FILE, ACL_SEARCH, ACL_DELETE, ACL_ADD_SUBDIRECTORY, ACL_DELETE_CHILD, ACL_READ_ATTRIBUTES, ACL_WRITE_ATTRIBUTES, ACL_READ_EXTATTRIBUTES, ACL_WRITE_EXTATTRIBUTES, ACL_READ_SECURITY, ACL_WRITE_SECURITY, ACL_CHANGE_OWNER }; 27 | 28 | //int acl_perm_t_ALL[] = { ACL_READ_DATA, ACL_LIST_DIRECTORY, ACL_WRITE_DATA, ACL_ADD_FILE, ACL_EXECUTE, ACL_SEARCH, ACL_DELETE, ACL_APPEND_DATA, ACL_ADD_SUBDIRECTORY, ACL_DELETE_CHILD, ACL_READ_ATTRIBUTES, ACL_WRITE_ATTRIBUTES, ACL_READ_EXTATTRIBUTES, ACL_WRITE_EXTATTRIBUTES, ACL_READ_SECURITY, ACL_WRITE_SECURITY, ACL_CHANGE_OWNER }; 29 | //char *acl_d[] = { "delete", "readattr", "writeattr", "readextattr", "writeextattr", "readsecurity", "writesecurity", "chown", "search", "add_file", "add_subdirectory", "delete_child", "file_inherit", "directory_inherit", "limit_inherit", "only_inherit" }; 30 | 31 | 32 | 33 | #define CMPDIR_MAX_FILES 10 34 | 35 | 36 | 37 | typedef struct cmpdir{ 38 | char *name; 39 | struct{ 40 | char name[16]; 41 | int fd; 42 | int filePattern; 43 | } files[CMPDIR_MAX_FILES]; 44 | }cmpdir_t; 45 | 46 | /* ------------------------------------------------------------------------- */ 47 | 48 | cmpdir_t *cmpdirNew(char *path); 49 | btbool cmpdirFree(cmpdir_t *dir); 50 | btbool cmpdirRename(cmpdir_t *dir, char *newPath, int WinVolume); 51 | btbool cmpdirChangeFiles(cmpdir_t *dir); 52 | btbool cmpdirVerifyFiles(cmpdir_t *dir); 53 | 54 | /* ------------------------------------------------------------------------- */ 55 | -------------------------------------------------------------------------------- /src/fstorture/cmpfile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: cmpfile.c 3 | * Project: CIFS Client Automatic Test 4 | * Author: Christian Starkjohann 5 | * Creation Date: 1998-04-20 6 | * Tabsize: 4 7 | * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | * under the terms of the Gnu General Public License (GPL). 9 | * 10 | * Copyright © 2009 Apple Inc. 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 only. This 13 | * program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * version 2 for more details. A copy of the GNU General Public License 17 | * version 2 is included along with this program. 18 | */ 19 | 20 | #include "stdheaders.h" 21 | #include "cmpfile.h" 22 | #include "fileemu.h" 23 | #include "util.h" 24 | 25 | extern int trace; 26 | char *acl_perm_t_file_n[] = { "read", "write", "execute", "delete", "append", "readattr", "writeattr", "readextattr", "writeextattr", "readsecurity", "writesecurity", "chown" }; 27 | int acl_perm_t_file_r[] = { ACL_READ_DATA, ACL_WRITE_DATA, ACL_EXECUTE, ACL_DELETE, ACL_APPEND_DATA, ACL_READ_ATTRIBUTES, ACL_WRITE_ATTRIBUTES, ACL_READ_EXTATTRIBUTES, ACL_WRITE_EXTATTRIBUTES, ACL_READ_SECURITY, ACL_WRITE_SECURITY, ACL_CHANGE_OWNER }; 28 | extern uuid_t *uuid; 29 | extern pthread_t thr[THREADS]; 30 | extern pthread_mutex_t mutex_start; 31 | extern pthread_cond_t cond_start; 32 | char filename_shared[1024]; 33 | int howmany = 0; 34 | int acl_err = 1; 35 | 36 | 37 | /* ------------------------------------------------------------------------- */ 38 | 39 | cmpfile_t *cmpfileNew(char *path, const char *root) 40 | { 41 | cmpfile_t *cmpfile = calloc(1, sizeof(cmpfile_t)); 42 | 43 | if(trace) 44 | printf("creating file %s\n", path); 45 | cmpfile->refFile = fileNew(); 46 | cmpfile->fd = creat(path, 0600); 47 | if(cmpfile->fd < 0){ 48 | perr(errno, "error creating file %s", path); 49 | } 50 | if(close(cmpfile->fd) < 0){ 51 | perr(errno, "error closing file %s", path); 52 | } 53 | cmpfile->name = malloc(strlen(path) + 1); 54 | strcpy(cmpfile->name, path); 55 | cmpfile->isOpen = 0; 56 | cmpfile->root = root; 57 | return cmpfile; 58 | } 59 | 60 | /* ------------------------------------------------------------------------- */ 61 | 62 | btbool cmpfileLink(cmpfile_t *cmpfile, char *linkName, int hard) 63 | { 64 | if (!strcasecmp(cmpfile->name, linkName)) { 65 | // printf("CASE MATCHES: %s %s\n", cmpfile->name, linkName); 66 | return 1; 67 | } 68 | 69 | if (trace) 70 | printf("%s linking file %s to %s\n", hard ? "hard" : "soft", cmpfile->name, linkName); 71 | 72 | if (hard) { // Hard link request 73 | if (link(cmpfile->name, linkName) < 0) { 74 | perr(errno, "error hard linking file %s to %s", cmpfile->name, linkName); 75 | return 0; 76 | } 77 | } else { // Soft link request 78 | if (symlink(cmpfile->name, linkName) < 0) { 79 | perr(errno, "error soft linking file %s to %s", cmpfile->name, linkName); 80 | return 0; 81 | } 82 | } 83 | unlink(linkName); 84 | return 1; 85 | } 86 | 87 | 88 | /* ------------------------------------------------------------------------- */ 89 | 90 | btbool cmpfileRename(cmpfile_t *cmpfile, char *newName) 91 | { 92 | filename_shared[0] = '\0'; 93 | if (trace) 94 | printf("Renaming file %s to %s\n", cmpfile->name, newName); 95 | if(rename(cmpfile->name, newName) < 0){ 96 | perr(errno, "error renaming file %s to %s", cmpfile->name, newName); 97 | return 0; 98 | } 99 | free(cmpfile->name); 100 | cmpfile->name = malloc(strlen(newName) + 1); 101 | strcpy(cmpfile->name, newName); 102 | return 1; 103 | } 104 | 105 | /* ------------------------------------------------------------------------- */ 106 | 107 | void cmpfileFree(cmpfile_t *cmpfile, btbool hadErr, btbool unlinkme) 108 | { 109 | char errName[1024]; 110 | 111 | if(trace) 112 | printf("destroying file %s\n", cmpfile->name); 113 | if(cmpfile->isOpen){ 114 | if(close(cmpfile->fd) < 0){ 115 | perr(errno, "error closing file %s", cmpfile->name); 116 | } 117 | cmpfile->isOpen = 0; 118 | } 119 | if(hadErr){ 120 | sprintf(errName, "%s.error", cmpfile->name); 121 | if(rename(cmpfile->name, errName) < 0){ 122 | perr(errno, "error renaming file %s to %s", cmpfile->name, errName); 123 | } 124 | }else if (unlinkme) { 125 | if(unlink(cmpfile->name) < 0){ 126 | perr(errno, "error unlinking file %s", cmpfile->name); 127 | } 128 | } 129 | fileFree(cmpfile->refFile); 130 | cmpfile->refFile = NULL; 131 | free(cmpfile->name); 132 | cmpfile->name = NULL; 133 | free(cmpfile); 134 | } 135 | 136 | /* ------------------------------------------------------------------------- */ 137 | 138 | btbool cmpfileOpen(cmpfile_t *cmpfile, btbool writable, btbool nocache) 139 | { 140 | if(trace) 141 | printf("opening file %s %s\n", cmpfile->name, writable ? "writable" : ""); 142 | if(!fileOpen(cmpfile->refFile, writable)) 143 | return 0; 144 | cmpfile->fd = open(cmpfile->name, writable ? O_RDWR : O_RDONLY, 0); 145 | if(cmpfile->fd < 0){ 146 | perr(errno, "error opening file %s %s", cmpfile->name, writable ? "RDWR" : "RDONLY"); 147 | fileClose(cmpfile->refFile); 148 | return 0; 149 | } 150 | 151 | if (nocache) 152 | fcntl(cmpfile->fd, F_NOCACHE, 1); 153 | cmpfile->isOpen = 1; 154 | return 1; 155 | } 156 | 157 | /* ------------------------------------------------------------------------- */ 158 | 159 | btbool cmpfileClose(cmpfile_t *cmpfile) 160 | { 161 | if(trace) 162 | printf("closing file %s\n", cmpfile->name); 163 | fileClose(cmpfile->refFile); 164 | if(close(cmpfile->fd) < 0){ 165 | perr(errno, "error closing file %s", cmpfile->name); 166 | } 167 | cmpfile->isOpen = 0; 168 | return 1; 169 | } 170 | 171 | /* ------------------------------------------------------------------------- */ 172 | 173 | btbool cmpfileWrite(cmpfile_t *cmpfile, int offset, int len, void *data) 174 | { 175 | int wlen; 176 | 177 | if(trace) 178 | printf("writing file %s offset=%d, len=%d\n", cmpfile->name, offset, len); 179 | fileWrite(cmpfile->refFile, offset, len, data); 180 | if(lseek(cmpfile->fd, offset, SEEK_SET) == -1){ 181 | perr(errno, "error seeking (write) in file %s", cmpfile->name); 182 | return 0; 183 | } 184 | wlen = write(cmpfile->fd, data, len); 185 | if(wlen != len){ 186 | perr(errno, "error writing file %s, wlen = %d", cmpfile->name, wlen); 187 | return 0; 188 | } 189 | return 1; 190 | } 191 | 192 | /* ------------------------------------------------------------------------- */ 193 | 194 | btbool cmpfileRead(cmpfile_t *cmpfile, int offset, int len) 195 | { 196 | char *fileBuf; 197 | int refLen, fileLen; 198 | btbool rval = 1; 199 | 200 | if(trace) 201 | printf("reading file %s offset=%d, len=%d\n", cmpfile->name, offset, len); 202 | fileBuf = malloc(len); 203 | refLen = fileReadSize(cmpfile->refFile, offset, len); 204 | if(lseek(cmpfile->fd, offset, SEEK_SET) == -1){ 205 | perr(errno, "error seeking (read) in file %s", cmpfile->name); 206 | rval = 0; 207 | }else{ 208 | fileLen = read(cmpfile->fd, fileBuf, len); 209 | if(fileLen < 0){ 210 | perr(errno, "error reading file %s", cmpfile->name); 211 | rval = 0; 212 | }else{ 213 | if(refLen != fileLen){ 214 | perr(0, "read size error reading file %s: %d instead of %d", cmpfile->name, fileLen, refLen); 215 | rval = 0; 216 | }else{ 217 | if(!fileCompareRead(cmpfile->refFile, offset, refLen, fileBuf)){ 218 | perr(0, "read error file %s: content error offset=%d len=%d size=%d", cmpfile->name, offset, len, fileSize(cmpfile->refFile)); 219 | rval = 0; 220 | } 221 | } 222 | } 223 | } 224 | free(fileBuf); 225 | return rval; 226 | } 227 | 228 | /* ------------------------------------------------------------------------- */ 229 | 230 | btbool cmpfileTruncate(cmpfile_t *cmpfile, int len) 231 | { 232 | int rval; 233 | 234 | fileTruncate(cmpfile->refFile, len); 235 | if(cmpfile->isOpen){ 236 | if(trace) 237 | printf("ftruncating file %s to %d\n", cmpfile->name, len); 238 | rval = ftruncate(cmpfile->fd, len); 239 | }else{ 240 | if(trace) 241 | printf("truncating file %s to %d\n", cmpfile->name, len); 242 | rval = truncate(cmpfile->name, len); 243 | } 244 | if(rval < 0){ 245 | perr(errno, "error (f)truncating file %s", cmpfile->name); 246 | return 0; 247 | } 248 | return 1; 249 | } 250 | 251 | /* ------------------------------------------------------------------------- */ 252 | 253 | btbool cmpfileSetMode(cmpfile_t *cmpfile, btbool writable) 254 | { 255 | int rval = 0; 256 | if(trace) 257 | printf("setting mode of file %s to %s\n", cmpfile->name, writable ? "writable" : "not writable"); 258 | fileSetMode(cmpfile->refFile, writable); 259 | if (cmpfile->isOpen) { 260 | rval = fchmod(cmpfile->fd, writable ? 0600 : 0400); 261 | } else { 262 | rval = chmod(cmpfile->name, writable ? 0600 : 0400); 263 | } 264 | if(rval < 0){ 265 | perr(errno, "error chmoding file %s", cmpfile->name); 266 | return 0; 267 | } 268 | return 1; 269 | } 270 | 271 | /* ------------------------------------------------------------------------- */ 272 | 273 | void *thr_start() { // here, we just wait for work == when howmany != 0 274 | while (1) { 275 | pthread_cond_wait(&cond_start, &mutex_start); 276 | pthread_mutex_unlock(&mutex_start); 277 | while (howmany > 0) { 278 | acl_err = cmpfileAcls_do(); 279 | howmany--; 280 | usleep(100); 281 | } 282 | } 283 | return(0); 284 | } 285 | 286 | btbool cmpfileAcls(cmpfile_t *cmpfile) 287 | { 288 | howmany = random_int(200); // how many iterations of acl bustin' we should do 289 | if (trace) { 290 | printf("acl busting: %i times\n", howmany); 291 | } 292 | strcpy(filename_shared, cmpfile->name); 293 | pthread_cond_broadcast(&cond_start); 294 | while (howmany > 0) { 295 | if (acl_err == 0) { 296 | return 0; 297 | } 298 | usleep(1); 299 | } 300 | return 1; 301 | } 302 | btbool cmpfileAcls_do() 303 | { // don't forget: sudo /usr/sbin/fsaclctl -p / -e 304 | acl_t acl; 305 | acl_entry_t ace; 306 | acl_permset_t perms; 307 | 308 | if (trace) 309 | printf("%p: acl'ing file %s\n", pthread_self(), filename_shared); 310 | 311 | if (NULL == (acl = acl_init(32))) { 312 | perr(errno, "acl_init()"); 313 | return 0; 314 | } 315 | 316 | if (0 != acl_create_entry(&acl, &ace)) { 317 | perr(errno, "acl_create_entry()"); 318 | return 0; 319 | } 320 | 321 | /* allow or deny */ 322 | if (0 != acl_set_tag_type(ace, (random_int(2) == 1) ? ACL_EXTENDED_ALLOW : ACL_EXTENDED_DENY)) { 323 | perr(errno, "acl_set_tag_type()"); 324 | return 0; 325 | } 326 | 327 | /* associate this with our uuid */ 328 | if (0 != acl_set_qualifier(ace, uuid)) { 329 | perr(errno, "acl_set_qualifier()"); 330 | return 0; 331 | } 332 | 333 | if (0 != acl_get_permset(ace, &perms)) { 334 | perr(errno, "acl_get_permset()"); 335 | return 0; 336 | } 337 | 338 | switch(random_int(3)) { 339 | case 0: /* ADD */ 340 | if (0 != acl_add_perm(perms, acl_perm_t_file_r[random_int(12)])) { 341 | perr(errno, "acl_add_perm()"); 342 | return 0; 343 | } 344 | break; 345 | case 1: /* DELETE */ 346 | if (0 != acl_delete_perm(perms, acl_perm_t_file_r[random_int(12)])) { 347 | perr(errno, "acl_delete_perms()"); 348 | return 0; 349 | } 350 | break; 351 | case 2: /* CLEAR */ 352 | if (0 != acl_clear_perms(perms)) { 353 | perr(errno, "acl_clear_perms()"); 354 | return 0; 355 | } 356 | break; 357 | } 358 | 359 | if (0 != acl_set_permset(ace, perms)) { 360 | perr(errno, "acl_set_permset()"); 361 | return 0; 362 | } 363 | 364 | if (filename_shared[0] != '\0') { 365 | if (0 != acl_set_file(filename_shared, ACL_TYPE_EXTENDED, acl)) { 366 | perr(errno, "acl_set_file()"); 367 | printf("f:%s\n", filename_shared); 368 | return 0; 369 | } 370 | } 371 | 372 | acl_free(acl); 373 | 374 | return 1; 375 | } 376 | 377 | 378 | 379 | // This is unused and was the first quick attempt 380 | int cmpfileAcls2(cmpfile_t *cmpfile) 381 | { // don't forget: sudo /usr/sbin/fsaclctl -p / -e 382 | char dothis[100]; 383 | sprintf(dothis, "www"); 384 | 385 | switch(random_int(3)) { 386 | case 0: /* ADD */ 387 | sprintf(dothis, "%s %s %s", dothis, 388 | (random_int(2) == 1) ? "allow" : "deny", 389 | acl_perm_t_file_n[random_int(12)]); 390 | 391 | strcpy(cmpfile->acl, dothis); 392 | sprintf(dothis, "exec chmod +a \"%s\" %s", cmpfile->acl, cmpfile->name); 393 | break; 394 | 395 | case 1: /* REMOVE */ 396 | if (cmpfile->acl[0] != '\0') { 397 | sprintf(dothis, "exec chmod -a \"%s\" %s", cmpfile->acl, cmpfile->name); 398 | cmpfile->acl[0] = '\0'; 399 | } else { dothis[0] = '\0'; } 400 | break; 401 | 402 | case 2: /* CHANGE */ 403 | if (cmpfile->acl[0] != 'z') { 404 | sprintf(dothis, "%s %s %s", dothis, 405 | (random_int(2) == 1) ? "allow" : "deny", 406 | acl_perm_t_file_n[random_int(12)]); 407 | strcpy(cmpfile->acl, dothis); 408 | sprintf(dothis, "exec chmod =a# 0 \"%s\" %s", cmpfile->acl, cmpfile->name); 409 | } else { dothis[0] = '\0'; } 410 | break; 411 | } 412 | 413 | if (dothis[0] != '\0') { 414 | // printf("dothis=%s\n", dothis); 415 | system(dothis); 416 | } 417 | 418 | return 1; 419 | } 420 | 421 | /* ------------------------------------------------------------------------- */ 422 | 423 | btbool cmpfileStat(cmpfile_t *cmpfile, int noPerms) 424 | { 425 | btbool isW; 426 | int refSize; 427 | struct stat buf; 428 | int sret = 0; 429 | 430 | if(trace) 431 | printf("stating file %s\n", cmpfile->name); 432 | isW = fileIsWritable(cmpfile->refFile); 433 | refSize = fileSize(cmpfile->refFile); 434 | if (cmpfile->isOpen) { 435 | sret = fstat(cmpfile->fd, &buf); 436 | } else { 437 | sret = stat(cmpfile->name, &buf); 438 | } 439 | if(sret < 0){ 440 | perr(errno, "error stating file %s\n", cmpfile->name); 441 | return 0; 442 | }else{ 443 | if(buf.st_size != refSize){ 444 | perr(0, "file %s %sstats with wrong size (%d instead of %d)\n", cmpfile->name, cmpfile->isOpen ? "f" : "",(int)buf.st_size, refSize); 445 | return 0; 446 | } 447 | if(((buf.st_mode & 0200) != 0) != isW){ 448 | if (!noPerms) { 449 | perr(0, "file %s %sstats with wrong write protection status (0%o)\n", cmpfile->name, cmpfile->isOpen ? "f" : "", buf.st_mode); 450 | return 0; 451 | } 452 | } 453 | } 454 | return 1; 455 | } 456 | 457 | /* ------------------------------------------------------------------------- */ 458 | 459 | btbool cmpfileUnlink(cmpfile_t *cmpfile) { 460 | int rval = 0; 461 | if (trace) 462 | printf("Unlinking %s\n", cmpfile->name); 463 | rval = unlink(cmpfile->name); 464 | if (rval < 0) { 465 | perr(errno, "error unlinking file %s\n", cmpfile->name); 466 | return 0; 467 | } 468 | return 1; 469 | } 470 | -------------------------------------------------------------------------------- /src/fstorture/cmpfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: cmpfile.h 3 | * Project: CIFS Client Automatic Test 4 | * Author: Christian Starkjohann 5 | * Creation Date: 1998-04-20 6 | * Tabsize: 4 7 | * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | * under the terms of the Gnu General Public License (GPL). 9 | * 10 | * Copyright © 2009 Apple Inc. 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 only. This 13 | * program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * version 2 for more details. A copy of the GNU General Public License 17 | * version 2 is included along with this program. 18 | */ 19 | 20 | /* 21 | General Description: 22 | This class defines a "comparing file". The file class defined herein 23 | implements the usual file operations. All these operations are performed 24 | on a stored reference file (file_t object, type defined by fileemu.h) _and_ 25 | on a real file in the filesystem. The results are compared when possible 26 | and errors are reported. The only return value is whether the operation 27 | succeeded without errors (both files returned the same results). The return 28 | value is 1 on success, 0 on failure. 29 | */ 30 | 31 | /* ------------------------------------------------------------------------- */ 32 | 33 | #include "basictypes.h" 34 | #include 35 | 36 | #define THREADS 5 37 | 38 | //char *acl_perm_t_file_n[] = { "read", "write", "execute", "delete", "append", "readattr", "writeattr", "readextattr", "writeextattr", "readsecurity", "writesecurity", "chown" }; 39 | //int acl_perm_t_file_r[] = { ACL_READ_DATA, ACL_WRITE_DATA, ACL_EXECUTE, ACL_DELETE, ACL_APPEND_DATA, ACL_READ_ATTRIBUTES, ACL_WRITE_ATTRIBUTES, ACL_READ_EXTATTRIBUTES, ACL_WRITE_EXTATTRIBUTES, ACL_READ_SECURITY, ACL_WRITE_SECURITY, ACL_CHANGE_OWNER }; 40 | 41 | //int acl_perm_t_ALL[] = { ACL_READ_DATA, ACL_LIST_DIRECTORY, ACL_WRITE_DATA, ACL_ADD_FILE, ACL_EXECUTE, ACL_SEARCH, ACL_DELETE, ACL_APPEND_DATA, ACL_ADD_SUBDIRECTORY, ACL_DELETE_CHILD, ACL_READ_ATTRIBUTES, ACL_WRITE_ATTRIBUTES, ACL_READ_EXTATTRIBUTES, ACL_WRITE_EXTATTRIBUTES, ACL_READ_SECURITY, ACL_WRITE_SECURITY, ACL_CHANGE_OWNER }; 42 | 43 | 44 | typedef struct cmpfile{ 45 | struct file *refFile; 46 | int fd; 47 | char *name; 48 | const char *root; 49 | char acl[100]; 50 | btbool isOpen; 51 | }cmpfile_t; 52 | 53 | /* ------------------------------------------------------------------------- */ 54 | 55 | cmpfile_t *cmpfileNew(char *path, const char *root); 56 | /* Creates a new object. This method also creates the embedded reference 57 | * file object and creates the file on disk. 58 | */ 59 | void cmpfileFree(cmpfile_t *cmpfile, btbool hadErr, btbool unlinkme); 60 | /* Frees the object and the embedded reference file. The file on disk is 61 | * unlinked if 'hadErr' is 0 or renamed to .error if 'hadErr' is 1. 62 | */ 63 | 64 | btbool cmpfileLink(cmpfile_t *cmpfile, char *linkName, int hard); 65 | 66 | btbool cmpfileRename(cmpfile_t *cmpfile, char *newName); 67 | /* Renames the file on disk and stores the new name for further named 68 | * references to the file. 69 | */ 70 | btbool cmpfileOpen(cmpfile_t *cmpfile, btbool writable, btbool nocache); 71 | /* Opens the file read/write, if 'writable' is 1, read only if 'writable' 72 | * is 0. 73 | */ 74 | btbool cmpfileClose(cmpfile_t *cmpfile); 75 | /* Closes the file. 76 | */ 77 | btbool cmpfileWrite(cmpfile_t *cmpfile, int offset, int len, void *data); 78 | /* Writes the given data block to the file. The file must be open for write. 79 | */ 80 | btbool cmpfileRead(cmpfile_t *cmpfile, int offset, int len); 81 | /* Reads the data block at the given position from the file and verifies the 82 | * result. 83 | */ 84 | btbool cmpfileTruncate(cmpfile_t *cmpfile, int len); 85 | /* Sets the file size to the given size. 86 | */ 87 | btbool cmpfileSetMode(cmpfile_t *cmpfile, btbool writable); 88 | /* Changes the write protection mode of the file. 89 | */ 90 | 91 | btbool cmpfileAcls_do(); 92 | btbool cmpfileAcls(cmpfile_t *cmpfile); 93 | 94 | btbool cmpfileStat(cmpfile_t *cmpfile, int noPerms); 95 | /* Compares write protection status and size of the "real" file and the 96 | * reference file. 97 | */ 98 | btbool cmpfileUnlink(cmpfile_t *cmpfile); 99 | 100 | /* ------------------------------------------------------------------------- */ 101 | -------------------------------------------------------------------------------- /src/fstorture/fileemu.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: fileemu.c 3 | * Project: CIFS Client Automatic Test 4 | * Author: Christian Starkjohann 5 | * Creation Date: 1998-04-20 6 | * Tabsize: 4 7 | * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | * under the terms of the Gnu General Public License (GPL). 9 | * 10 | * Copyright © 2009 Apple Inc. 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 only. This 13 | * program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * version 2 for more details. A copy of the GNU General Public License 17 | * version 2 is included along with this program. 18 | */ 19 | 20 | #include "stdheaders.h" 21 | #include "fileemu.h" 22 | 23 | /* ------------------------------------------------------------------------- */ 24 | 25 | static void reallocTouched(file_t *file) 26 | { 27 | int size = file->allocSize / 8 + 1; 28 | 29 | file->touchedBits = realloc(file->touchedBits, size); 30 | memset(file->touchedBits + file->touchedSize, 0, size - file->touchedSize); 31 | file->touchedSize = size; 32 | } 33 | 34 | /* ------------------------------------------------------------------------- */ 35 | 36 | static void bitarrSetRange(btu8 *arr, btsize startBitIndex, btsize numBits, btbool value) 37 | { 38 | btsize fillStart, startRemainder, fillEnd, endRemainder; 39 | btu8 startMask, endMask; 40 | 41 | fillStart = startBitIndex / 8 + 1; 42 | startRemainder = startBitIndex % 8; 43 | fillEnd = (startBitIndex + numBits) / 8; 44 | endRemainder = (startBitIndex + numBits) % 8; 45 | if(fillEnd > fillStart) 46 | memset(arr + fillStart, value ? 0xff : 0, fillEnd - fillStart); 47 | startMask = ~((1<isOpen = 0; 81 | file->isWritable = 1; 82 | file->allocSize = 32768; 83 | file->data = calloc(1, file->allocSize); 84 | file->size = 0; 85 | reallocTouched(file); 86 | return file; 87 | } 88 | 89 | /* ------------------------------------------------------------------------- */ 90 | 91 | void fileFree(file_t *file) 92 | { 93 | free(file->data); 94 | if(file->touchedBits != NULL) 95 | free(file->touchedBits); 96 | free(file); 97 | } 98 | 99 | /* ------------------------------------------------------------------------- */ 100 | 101 | btbool fileOpen(file_t *file, btbool writable) 102 | { 103 | if(writable && !file->isWritable) 104 | return 0; 105 | file->isOpen = 1; 106 | return 1; 107 | } 108 | 109 | /* ------------------------------------------------------------------------- */ 110 | 111 | void fileClose(file_t *file) 112 | { 113 | file->isOpen = 0; 114 | } 115 | 116 | /* ------------------------------------------------------------------------- */ 117 | 118 | void fileWrite(file_t *file, int offset, int len, void *data) 119 | { 120 | int maxlen = offset + len, newSize; 121 | 122 | if(!file->isOpen){ 123 | fprintf(stderr, "fileemu: write to closed file\n"); 124 | return; 125 | } 126 | if(maxlen > file->allocSize){ 127 | newSize = file->allocSize; 128 | while(maxlen > newSize) 129 | newSize *= 2; 130 | file->data = realloc(file->data, newSize); 131 | memset(file->data + file->allocSize, 0, newSize - file->allocSize); 132 | file->allocSize = newSize; 133 | reallocTouched(file); 134 | } 135 | memcpy(file->data + offset, data, len); 136 | bitarrSetRange(file->touchedBits, offset, len, 1); 137 | if(file->size < maxlen) 138 | file->size = maxlen; 139 | } 140 | 141 | /* ------------------------------------------------------------------------- */ 142 | 143 | int fileReadSize(file_t *file, int offset, int len) 144 | { 145 | int maxlen = offset + len; 146 | 147 | if(!file->isOpen){ 148 | fprintf(stderr, "fileemu: read from closed file\n"); 149 | return 0; 150 | } 151 | if(maxlen > file->size){ 152 | len = file->size - offset; 153 | } 154 | if(len <= 0){ 155 | return 0; 156 | } 157 | return len; 158 | } 159 | 160 | /* ------------------------------------------------------------------------- */ 161 | 162 | int fileRead(file_t *file, int offset, int len, void *dest) 163 | { 164 | len = fileReadSize(file, offset, len); 165 | memcpy(dest, file->data + offset, len); 166 | return len; 167 | } 168 | 169 | /* ------------------------------------------------------------------------- */ 170 | 171 | btbool fileCompareRead(file_t *file, int offset, int len, void *data) 172 | { 173 | int i; 174 | char *refData = data; 175 | int errors = 0, firstErrorIndex=0, lastErrorIndex=0; 176 | int originalOffset = offset; 177 | 178 | if(fileReadSize(file, offset, len) != len){ 179 | fprintf(stderr, "file compare failed due to size error\n"); 180 | return 0; 181 | } 182 | for(i=0;itouchedBits, offset)){ /* is touched */ 184 | if(file->data[offset] != refData[i]){ 185 | if(errors == 0) 186 | firstErrorIndex = offset; 187 | lastErrorIndex = offset; 188 | if(errors < 20) 189 | fprintf(stderr, "data in file[%d] is 0x%02x instead of 0x%02x\n", offset, (btu8)refData[i], (btu8)file->data[offset]); 190 | errors++; 191 | } 192 | } 193 | offset++; 194 | } 195 | if(errors != 0){ 196 | fprintf(stderr, "fileCompareRead: %d errors in data block: first=%d last=%d, blockstart=%d, blocklen=%d\n", errors, firstErrorIndex, lastErrorIndex, originalOffset, len); 197 | } 198 | return errors == 0; 199 | } 200 | 201 | /* ------------------------------------------------------------------------- */ 202 | 203 | void fileTruncate(file_t *file, int len) 204 | { 205 | int maxlen = len, newSize; 206 | 207 | if(maxlen > file->allocSize){ 208 | newSize = file->allocSize; 209 | while(maxlen > newSize) 210 | newSize *= 2; 211 | file->data = realloc(file->data, newSize); 212 | memset(file->data + file->allocSize, 0, newSize - file->allocSize); 213 | file->allocSize = newSize; 214 | reallocTouched(file); 215 | } 216 | if(maxlen < file->size){ /* file shrinks */ 217 | bitarrSetRange(file->touchedBits, maxlen, file->size - maxlen, 0); 218 | } 219 | file->size = maxlen; 220 | } 221 | 222 | /* ------------------------------------------------------------------------- */ 223 | 224 | void fileSetMode(file_t *file, btbool writable) 225 | { 226 | file->isWritable = writable; 227 | } 228 | 229 | /* ------------------------------------------------------------------------- */ 230 | 231 | btbool fileIsWritable(file_t *file) 232 | { 233 | return file->isWritable; 234 | } 235 | 236 | /* ------------------------------------------------------------------------- */ 237 | -------------------------------------------------------------------------------- /src/fstorture/fileemu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: fileemu.h 3 | * Project: CIFS Client Automatic Test 4 | * Author: Christian Starkjohann 5 | * Creation Date: 1998-04-20 6 | * Tabsize: 4 7 | * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | * under the terms of the Gnu General Public License (GPL). 9 | * 10 | * Copyright © 2009 Apple Inc. 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 only. This 13 | * program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * version 2 for more details. A copy of the GNU General Public License 17 | * version 2 is included along with this program. 18 | */ 19 | 20 | /* 21 | General Description: 22 | The file class defined in this module emulates the behaviour of files on 23 | disk media. It is used as a reference when the results of file operations 24 | must be verified. 25 | */ 26 | 27 | /* ------------------------------------------------------------------------- */ 28 | 29 | #include "basictypes.h" 30 | 31 | typedef struct file{ 32 | btbool isOpen; 33 | btbool isWritable; 34 | btu8 *touchedBits; 35 | int touchedSize; 36 | char *data; 37 | int allocSize; 38 | int size; 39 | }file_t; 40 | 41 | /* ------------------------------------------------------------------------- */ 42 | 43 | file_t *fileNew(void); 44 | /* Creates a new file_t object 45 | */ 46 | void fileFree(file_t *file); 47 | /* Frees an existing file_t object 48 | */ 49 | btbool fileOpen(file_t *file, btbool writable); 50 | /* Sets a file_t object into the "opened" state. The flag "writable" defines 51 | * whether writes to the file will be possible. 52 | */ 53 | void fileClose(file_t *file); 54 | /* Sets the file_t object into the closed state. 55 | */ 56 | void fileWrite(file_t *file, int offset, int len, void *data); 57 | /* Writes to the file_t object. The data written to the file is stored in 58 | * memory and the range of already written-to bytes is also stored. 59 | */ 60 | int fileReadSize(file_t *file, int offset, int len); 61 | /* Returns the number of bytes that would be read from the file_t object 62 | * if a read with the parameters 'offset' and 'len' would be performed. 63 | */ 64 | int fileRead(file_t *file, int offset, int len, void *dest); 65 | /* Reads data from the file. This method is currently not used. 66 | */ 67 | btbool fileCompareRead(file_t *file, int offset, int len, void *data); 68 | /* This method verifies whether the data read from the "real" file is correct. 69 | * It takes into account that only those parts of the block should be verified 70 | * that have already been written to. Unwritten parts that are not entire 71 | * filesystem blocks or pages may contain old data of previous contents. 72 | * The function returns 1, if no compare error occured. 73 | */ 74 | void fileTruncate(file_t *file, int len); 75 | /* Sets the file size to the given value and invalidates all data behind the 76 | * end of file. 77 | */ 78 | void fileSetMode(file_t *file, btbool writable); 79 | /* Changes the write protection mode of the file. The write protection is only 80 | * checked by fileOpen(). Whether writes are possible depends on the open mode 81 | * used. 82 | */ 83 | btbool fileIsWritable(file_t *file); 84 | /* Returns the write protection status of the file. 85 | */ 86 | 87 | static inline int fileSize(file_t *file) 88 | { 89 | return file->size; 90 | } 91 | 92 | /* ------------------------------------------------------------------------- */ 93 | -------------------------------------------------------------------------------- /src/fstorture/fstorture.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: fstorture.c 3 | * Project: CIFS Client Automatic Test 4 | * Author: Christian Starkjohann 5 | * Creation Date: 1998-04-20 6 | * Tabsize: 4 7 | * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | * under the terms of the Gnu General Public License (GPL). 9 | * 10 | * Copyright © 2009 Apple Inc. 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 only. This 13 | * program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * version 2 for more details. A copy of the GNU General Public License 17 | * version 2 is included along with this program. 18 | */ 19 | 20 | #include "stdheaders.h" 21 | #include "cmpfile.h" 22 | #include "cmpdir.h" 23 | #include "fileemu.h" 24 | #include "util.h" 25 | #ifdef XILOG 26 | #include 27 | #endif /* XILOG */ 28 | 29 | #define VERS "2.1-pfh" 30 | 31 | // Global variables 32 | uuid_t *uuid=NULL; 33 | pthread_t thr[THREADS]; 34 | extern void *thr_start(); 35 | pthread_mutex_t mutex_start; 36 | pthread_cond_t cond_start; 37 | 38 | /* ------------------------------------------------------------------------- */ 39 | /* ------------------------ commandline parameters ------------------------- */ 40 | /* ------------------------------------------------------------------------- */ 41 | static btbool bugFtruncateReadonly = 0; 42 | static btbool bugFtruncateSync = 0; 43 | static btbool noRenameOpenFiles = 0; 44 | static btbool noUnlinkOpenFiles = 0; 45 | static btbool noTestDirs = 0; 46 | static btbool WinVolume = 0; 47 | static btbool noStats = 0; 48 | static btbool noPerms = 0; 49 | static btbool softlinks = 1; 50 | static btbool hardlinks = 1; 51 | static btbool sleepy = 0; 52 | static btbool acl = 0; 53 | static btbool nocache = 0; 54 | static char *root1; /* directories where to perform test */ 55 | static char *root2; 56 | static int count = 0; // how many to do 57 | static int mycount = 0; // how many we've done so far 58 | static int gStopTime = 0; 59 | pid_t parent_pid = 0; 60 | int trace = 0; 61 | 62 | #ifdef XILOG 63 | static XILogRef gLogRef; 64 | char* gLogPath; 65 | Boolean gXML = false; 66 | Boolean gEcho = false; 67 | #endif //XILOG 68 | 69 | int parsetime(char *t) { 70 | int i = 0; 71 | int secs = 0; 72 | char b[128]; bzero(b, 128); 73 | 74 | for (i=0; i < strlen(t); i++) { 75 | switch (t[i]) { 76 | case 's': 77 | secs += atoi(b); 78 | bzero(b, 128); 79 | break; 80 | case 'm': 81 | secs += atoi(b) * 60; 82 | bzero(b, 128); 83 | break; 84 | case 'h': 85 | secs += atoi(b) * 60 * 60; 86 | bzero(b, 128); 87 | break; 88 | case 'd': 89 | secs += atoi(b) * 60 * 60 * 24; 90 | bzero(b, 128); 91 | break; 92 | case 'w': 93 | secs += atoi(b) * 60 * 60 * 24 * 7; 94 | bzero(b, 128); 95 | break; 96 | case 'y': 97 | secs += atoi(b) * 60 * 60 * 24 * 365; 98 | bzero(b, 128); 99 | break; 100 | default: 101 | sprintf(b, "%s%c", b, t[i]); 102 | } 103 | } 104 | if (secs == 0) // maybe they just gave us a number? 105 | secs = atoi(t); 106 | return(secs); 107 | } 108 | 109 | /* ------------------------------------------------------------------------- */ 110 | /* ------------------- random number generator for tests ------------------- */ 111 | /* ------------------------------------------------------------------------- */ 112 | 113 | struct random_status{ 114 | int i; 115 | real_t u[97]; 116 | real_t c; 117 | }; 118 | 119 | struct random_status random_status; 120 | 121 | /* ------------------------------------------------------------------------- */ 122 | 123 | real_t random_get(void) /* 3.56 microseconds execution-time on 486/66 */ 124 | { 125 | real_t r; 126 | 127 | r = random_status.u[random_status.i] 128 | - random_status.u[(random_status.i + 33) % 97]; 129 | if(r < 0) 130 | r += 1; 131 | random_status.u[random_status.i--] = r; 132 | if(random_status.i < 0) 133 | random_status.i = 96; 134 | random_status.c = random_status.c - 7654321./16777216.; 135 | if(random_status.c < 0) 136 | random_status.c += 16777213./16777216.; 137 | r -= random_status.c; 138 | if(r < 0) 139 | r += 1; 140 | return r; 141 | } 142 | 143 | /* ------------------------------------------------------------------------- */ 144 | 145 | void random_init(int na1, int na2, int na3, int nb1) 146 | { 147 | int i, j, mat; 148 | real_t s, t; 149 | 150 | random_status.i = 96; 151 | for(j = 0; j < 97; j++){ 152 | s = 0; 153 | t = 0.5; 154 | for(i = 0; i < 24; i++){ 155 | mat = (((na1 * na2) % 179) * na3) % 179; 156 | na1 = na2; 157 | na2 = na3; 158 | na3 = mat; 159 | nb1 = (53 * nb1 + 1) % 169; 160 | if((nb1 * mat % 64) >= 32) 161 | s += t; 162 | t /= 2; 163 | 164 | } 165 | random_status.u[j] = s; 166 | } 167 | random_status.c = 362436./16777216.; 168 | } 169 | 170 | /* ------------------------------------------------------------------------- */ 171 | 172 | int random_int(int exclusive_range) 173 | { 174 | int r = (int)(random_get() * exclusive_range); 175 | 176 | if(r < 0 || r >= exclusive_range){ 177 | printf("random number %d illegal\n", r); 178 | exit(1); 179 | } 180 | return r; 181 | } 182 | 183 | /* ------------------------------------------------------------------------- */ 184 | 185 | /* This is not a real gaussian random number generator. Don't use it for 186 | * something where the probability distribution really counts! It is 187 | * shaped after what is mathematically easy and what the application 188 | * demands. 189 | */ 190 | real_t random_gauss(real_t stdval, real_t maxRange) 191 | { 192 | real_t val, x, f, m, a, b, h; 193 | 194 | a = 10; b = 2; 195 | m = M_PI/2 - 1 + a + a/b; /* mean value of distribution */ 196 | f = stdval / m; 197 | for(;;){ 198 | x = random_get(); 199 | h = sqrt(1 - x*x); 200 | if(h == 0) 201 | continue; 202 | val = a * pow(x, 1/b) + 1/h - 1; 203 | val *= f; 204 | if(val < maxRange) 205 | return val; 206 | } 207 | } 208 | 209 | void random_block(void *block, int len) 210 | { 211 | int i; 212 | btu8 *p = block; 213 | 214 | for(i=0;i= 10 || prefix < 0) { 237 | perr(0, "CMPDIR_MAX_FILES and prefix must be no larger than 10"); 238 | #if XILOG 239 | XILogEndTestCase(gLogRef, kXILogTestPassOnErrorLevel); 240 | XILogCloseLog(gLogRef); 241 | #endif /* XILOG */ 242 | exit(1); 243 | } 244 | name[0] = '0' + prefix; 245 | 246 | for(i=1;ifd); 363 | if(!random_int(10)){ /* do much less truncates than rest */ 364 | if(!bugFtruncateReadonly || (w && fileIsWritable(f->refFile))){ 365 | rval = cmpfileTruncate(f, random_int(50000)); 366 | } 367 | } 368 | break; 369 | case 5: /* chmod */ 370 | rval = cmpfileSetMode(f, random_int(3) != 0); 371 | break; 372 | case 6: /* stat */ 373 | if (!noStats) { // if the noStats flag ISN'T set 374 | rval = cmpfileStat(f, noPerms); 375 | } 376 | break; 377 | case 7: /* sleep */ 378 | if (sleepy) { 379 | if(!random_int(4)){ 380 | usleep(1000000 * random_gauss(1, 200)); 381 | } 382 | } 383 | break; 384 | case 8: /* rename */ 385 | if(!noRenameOpenFiles) { 386 | random_path(path, id, running, (WinVolume) ? f->root : random_root()); 387 | rval = cmpfileRename(f, path); 388 | } 389 | break; 390 | case 9: /* acls */ 391 | if (acl) { 392 | if(!random_int(5)) { // do less ACL busting 393 | rval = cmpfileAcls(f); 394 | } 395 | } 396 | break; 397 | case 10: /* link */ 398 | if (!random_int(2)) { 399 | if (softlinks) { 400 | random_path(path, id, running, random_root()); 401 | rval = cmpfileLink(f, path, 0); // Soft link 402 | } 403 | } else { 404 | if (hardlinks) { 405 | random_path(path, id, running, random_root()); 406 | rval = cmpfileLink(f, path, 1); // Hard link 407 | } 408 | } 409 | break; 410 | } 411 | return rval; 412 | } 413 | 414 | /* ------------------------------------------------------------------------- */ 415 | 416 | static btbool randomClosedOp(cmpfile_t *f, int id, int running) 417 | { 418 | btbool rval = 1; 419 | char path[1024]; 420 | const char *root; 421 | 422 | switch(random_int(7)){ 423 | case 0: /* truncate */ 424 | if(!random_int(10)){ /* do much less truncates than rest */ 425 | if(fileIsWritable(f->refFile)){ 426 | rval = cmpfileTruncate(f, random_int(50000)); 427 | } 428 | } 429 | break; 430 | case 1: /* chmod */ 431 | rval = cmpfileSetMode(f, random_int(3) != 0); 432 | break; 433 | case 2: /* stat */ 434 | if (!noStats) { // if the noStats flag ISN'T set 435 | rval = cmpfileStat(f, noPerms); 436 | } 437 | break; 438 | case 3: /* sleep */ 439 | if (sleepy) { 440 | if(!random_int(4)){ 441 | usleep(1000000 * random_gauss(1, 200)); 442 | } 443 | } 444 | break; 445 | case 4: /* rename */ 446 | root = random_root(); 447 | random_path(path, id, running, root); 448 | rval = cmpfileRename(f, path); 449 | if (rval) /* Rename sucessed so reset the root */ 450 | f->root = root; 451 | break; 452 | case 5: /* acls */ 453 | if(!random_int(5)){ // do less ACL busting than the rest 454 | if (acl) 455 | rval = cmpfileAcls(f); 456 | } 457 | break; 458 | case 6: /* link */ 459 | if (!random_int(2)) { 460 | if (softlinks) { 461 | random_path(path, id, running, random_root()); 462 | rval = cmpfileLink(f, path, 0); // Soft link 463 | } 464 | } else { 465 | if (hardlinks) { 466 | random_path(path, id, running, random_root()); 467 | rval = cmpfileLink(f, path, 1); // Hard link 468 | } 469 | } 470 | break; 471 | } 472 | return rval; 473 | } 474 | 475 | /* ------------------------------------------------------------------------- */ 476 | 477 | static btbool randomUnlinkOp(cmpfile_t *f, btbool w, int id, int running) 478 | { 479 | btbool rval = 1; 480 | int offset, len; 481 | void *block; 482 | 483 | 484 | switch(random_int(5)){ 485 | case 0: /* read */ 486 | offset = random_int(30000) + random_gauss(10, 100000); 487 | len = 1 + random_gauss(20000, 100000); 488 | rval = cmpfileRead(f, offset, len); 489 | break; 490 | case 1: /* write */ 491 | if(w){ 492 | offset = random_int(30000) + random_gauss(10, 100000); 493 | len = 1 + random_gauss(30000, 500000); 494 | block = malloc(len); 495 | random_block(block, len); 496 | rval = cmpfileWrite(f, offset, len, block); 497 | free(block); 498 | } 499 | break; 500 | 501 | case 2: /* ftruncate */ 502 | if(bugFtruncateSync) 503 | fsync(f->fd); 504 | if(!bugFtruncateReadonly || (w && fileIsWritable(f->refFile))){ 505 | rval = cmpfileTruncate(f, random_int(50000)); 506 | } 507 | break; 508 | case 3: /* fchmod */ 509 | rval = cmpfileSetMode(f, random_int(3) != 0); 510 | break; 511 | case 4: /* fstat */ 512 | if (!noStats) { // if the noStats flag ISN'T set 513 | rval = cmpfileStat(f, noPerms); 514 | } 515 | break; 516 | } 517 | return rval; 518 | } 519 | 520 | /* ------------------------------------------------------------------------- */ 521 | 522 | 523 | static void testOneFile(int id, int running) 524 | { 525 | char path[1024]; 526 | cmpfile_t *f; 527 | int w, i, l, i1, l1; 528 | btbool hadErr = 1; 529 | const char *root = random_root(); 530 | 531 | random_path(path, id, running, root); 532 | f = cmpfileNew(path, root); 533 | l1 = random_gauss(50,5000); 534 | for(i1=0;i1refFile)) 539 | w = 0; 540 | w = w != 0; 541 | if(!cmpfileOpen(f, w, nocache)) 542 | goto errorOccured; 543 | l = random_gauss(20, 5000); 544 | for(i=0;irefFile)) 586 | w = 0; 587 | w = w != 0; 588 | if(!cmpfileOpen(f, w, nocache)) 589 | goto errorOccured; 590 | if(!cmpfileUnlink(f)) 591 | goto errorOccured; 592 | for(i1=0;i1 0)) { // whichever is LONGER is run 673 | if(noTestDirs || random_int(7)) { 674 | testOneFile(id, i); 675 | testOneUnlinkedFile(id, i); 676 | } else 677 | testOneDirectory(id, i); 678 | i++; 679 | count -= n; 680 | mycount += n; 681 | #ifdef XILOG 682 | if (isParent) 683 | if ((i*n % 100) == 0) 684 | XIPing(i); 685 | #endif /* XILOG */ 686 | } 687 | 688 | } else { // Just run indefinitely 689 | for(i=0;;i++){ 690 | #ifdef XILOG 691 | if (isParent) 692 | if ((i*n % 100) == 0) 693 | XIPing(mycount); 694 | #endif /* XILOG */ 695 | if(noTestDirs || random_int(7)){ 696 | testOneFile(id, i); 697 | testOneUnlinkedFile(id, i); 698 | }else{ 699 | testOneDirectory(id, i); 700 | } 701 | mycount += n; 702 | } 703 | 704 | } 705 | if (isParent) { 706 | printf("Test completed [fstorture %s]: ", VERS); fflush(NULL); 707 | system("date"); 708 | } 709 | } 710 | 711 | 712 | /* ------------------------------------------------------------------------- */ 713 | void usage(char *argv) { 714 | fprintf(stderr, "fstorture %s\n", VERS); 715 | fprintf(stderr, "usage: %s [options]\n", argv); 716 | fprintf(stderr, "available options are:\n"); 717 | fprintf(stderr, " fsync_before_ftruncate\n"); 718 | fprintf(stderr, " no_rename_open_files\n"); 719 | fprintf(stderr, " no_unlink_open_files\n"); 720 | fprintf(stderr, " no_test_dirs\n"); 721 | fprintf(stderr, " no_stats\n"); 722 | fprintf(stderr, " no_perms\n"); 723 | fprintf(stderr, " windows_volume\n"); 724 | fprintf(stderr, " windows98\n"); 725 | fprintf(stderr, " nocache Adds fcntl(F_NOCACHE) after open\n"); 726 | fprintf(stderr, " acl Performs ACL busting\n"); 727 | fprintf(stderr, " nosoftlinks Disables soft-links\n"); 728 | fprintf(stderr, " nohardlinks Disables hard-links\n"); 729 | fprintf(stderr, " sleep Adds sleep between operations\n"); 730 | fprintf(stderr, " -v Increases verbosity\n"); 731 | fprintf(stderr, " -c 100 Each process will run this many tests\n"); 732 | fprintf(stderr, " -t 5h35m18s Runs for 5hours 35min 18sec\n"); 733 | fprintf(stderr, " NOTE: Both count & time may be given; whichever takes longer is used\n"); 734 | fprintf(stderr, " NOTE: If you specify 4 processes instead of 1, -c 100 will take 4x as long\n"); 735 | exit(1); 736 | } 737 | 738 | int main(int argc, char **argv) 739 | { 740 | int n, i; 741 | struct stat sbuf; 742 | struct volcapbuf { 743 | u_long buffer_size; 744 | vol_capabilities_attr_t caps; 745 | }; 746 | struct attrlist alist; 747 | struct volcapbuf buf; 748 | struct statfs st; 749 | int dirs = 0; 750 | 751 | if(argc < 4) 752 | usage(argv[0]); 753 | root1 = argv[1]; 754 | root2 = argv[2]; 755 | if(stat(root1, &sbuf) != 0){ 756 | fprintf(stderr, "root1 = %s does not exist\n", root1); 757 | exit(1); 758 | } 759 | if(stat(root2, &sbuf) != 0){ 760 | fprintf(stderr, "root2 = %s does not exist\n", root2); 761 | exit(1); 762 | } 763 | if(!isdigit(argv[3][0])){ 764 | fprintf(stderr, " must be a number, not %s!\n", argv[3]); 765 | usage(argv[0]); 766 | } 767 | n = atoi(argv[3]); // number of processes to spawn 768 | bugFtruncateReadonly = 1; /* always on, documentation bug */ 769 | for(i=4;i%s<- not known\n", argv[i]); 839 | exit(1); 840 | } 841 | } 842 | #ifdef XILOG 843 | } 844 | #endif /* XILOG */ 845 | } 846 | 847 | 848 | // Check if root1 and root2 are empty directories 849 | DIR* dirp; 850 | struct dirent *dp; 851 | dirs = 0; 852 | dirp = opendir(root1); 853 | while ((dp = readdir(dirp)) != NULL) 854 | dirs++; 855 | (void)closedir(dirp); 856 | if (dirs != 2) 857 | printf("--> WARNING: %s should be an EMPTY DIRECTORY <-- \n", root1); 858 | 859 | dirs = 0; 860 | dirp = opendir(root2); 861 | while ((dp = readdir(dirp)) != NULL) 862 | dirs++; 863 | (void)closedir(dirp); 864 | if (dirs != 2) 865 | printf("--> WARNING: %s should be an EMPTY DIRECTORY <--\n", root2); 866 | 867 | 868 | // Check if soft/hard links & ACLs are supported 869 | alist.bitmapcount = 5; 870 | alist.reserved = 0; 871 | alist.commonattr = 0; 872 | alist.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES; 873 | alist.dirattr = 0; 874 | alist.fileattr = 0; 875 | alist.forkattr = 0; 876 | 877 | if (statfs(root1, &st) < 0) { 878 | perr(errno, "statfs"); 879 | exit(-1); 880 | } 881 | if (getattrlist(st.f_mntonname, &alist, &buf, sizeof buf, 0) < 0) { 882 | perr(errno, "getattrlist"); 883 | exit(-1); 884 | } 885 | printf("Capabilities of %s (on %s): softlinks?", root1, st.f_mntonname); 886 | if (buf.caps.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_SYMBOLICLINKS) { 887 | printf("Y"); 888 | } else { 889 | printf("N"); 890 | softlinks = 0; 891 | } 892 | 893 | printf(" hardlinks?"); 894 | if (buf.caps.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_HARDLINKS) { 895 | printf("Y"); 896 | } else { 897 | printf("N"); 898 | hardlinks = 0; 899 | } 900 | printf(" ACLs?"); 901 | if(buf.caps.capabilities[VOL_CAPABILITIES_INTERFACES]&VOL_CAP_INT_EXTENDED_SECURITY){ 902 | printf("Y"); 903 | } else { 904 | printf("N"); 905 | acl = 0; 906 | } 907 | printf("\n"); 908 | 909 | if (statfs(root1, &st) < 0) { 910 | perr(errno, "statfs"); 911 | exit(-1); 912 | } 913 | if (getattrlist(st.f_mntonname, &alist, &buf, sizeof buf, 0) < 0) { 914 | perr(errno, "getattrlist"); 915 | exit(-1); 916 | } 917 | printf("Capabilities of %s (on %s): softlinks?", root2, st.f_mntonname); 918 | if (buf.caps.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_SYMBOLICLINKS) { 919 | printf("Y"); 920 | } else { 921 | printf("N"); 922 | softlinks = 0; 923 | } 924 | printf(" hardlinks?"); 925 | 926 | if (buf.caps.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_HARDLINKS) { 927 | printf("Y"); 928 | } else { 929 | printf("N"); 930 | hardlinks = 0; 931 | } 932 | printf(" ACLs?"); 933 | if(buf.caps.capabilities[VOL_CAPABILITIES_INTERFACES]&VOL_CAP_INT_EXTENDED_SECURITY){ 934 | printf("Y"); 935 | } else { 936 | printf("N"); 937 | acl = 0; 938 | } 939 | printf("\n"); 940 | 941 | 942 | 943 | if (acl) { 944 | // Now, put user "www"'s UUID into the global variable "uuid" 945 | char *u = "www"; 946 | struct passwd *tpass = NULL; 947 | //uuid_t *uuid=NULL; // this was defined globally 948 | if (NULL == (uuid = (uuid_t *)calloc(1,sizeof(uuid_t)))) 949 | perr(errno, "unable to allocate a uuid"); 950 | tpass = getpwnam(u); 951 | if (tpass) { 952 | if (0 != mbr_uid_to_uuid(tpass->pw_uid, *uuid)) { 953 | perr(errno, "mbr_uid_to_uuid(): Unable to translate"); 954 | } 955 | } 956 | 957 | // Next, make our threads 958 | pthread_mutex_init(&mutex_start, NULL); 959 | pthread_cond_init (&cond_start, NULL); 960 | 961 | for (i=0;i= 2 ) ? "s" : ""); 1008 | if (gStopTime != 0) 1009 | printf("Running for %d seconds\n", gStopTime - (int)time(NULL)); 1010 | if (sleepy) 1011 | printf("Throwing in random sleeps\n"); 1012 | 1013 | signal(SIGHUP, cleanup); 1014 | signal(SIGINT, cleanup); 1015 | signal(SIGPIPE, cleanup); 1016 | signal(SIGALRM, cleanup); 1017 | signal(SIGTERM, cleanup); 1018 | signal(SIGXCPU, cleanup); 1019 | signal(SIGXFSZ, cleanup); 1020 | signal(SIGVTALRM,cleanup); 1021 | signal(SIGUSR1, cleanup); 1022 | signal(SIGUSR2, cleanup); 1023 | 1024 | #ifdef XILOG 1025 | XIPing(0); 1026 | #endif /* XILOG */ 1027 | 1028 | for(i=0;i 5 | * Creation Date: 1998-04-20 6 | * Tabsize: 4 7 | * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | * under the terms of the Gnu General Public License (GPL). 9 | * 10 | * Copyright © 2009 Apple Inc. 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 only. This 13 | * program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * version 2 for more details. A copy of the GNU General Public License 17 | * version 2 is included along with this program. 18 | */ 19 | 20 | /* 21 | General Description: 22 | This header includes all system headers that are needed. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #ifdef NeXT 42 | # include 43 | #endif 44 | -------------------------------------------------------------------------------- /src/fstorture/testPerformance: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Name: testPerformance 3 | # Project: CIFS Client 4 | # Author: Christian Starkjohann 5 | # Creation Date: 1998-05-16 6 | # Tabsize: 4 7 | # Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | # under the terms of the Gnu General Public License (GPL). 9 | # 10 | # Copyright © 2009 Apple Inc. 11 | # This program is free software; you can redistribute it and/or modify it 12 | # under the terms of the GNU General Public License version 2 only. This 13 | # program is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | # version 2 for more details. A copy of the GNU General Public License 17 | # version 2 is included along with this program. 18 | # 19 | # General Description: 20 | # This script runs some performance tests within a given directory of the 21 | # file system. 22 | 23 | mypath=`pwd` 24 | 25 | PATH=$PATH:/etc:/usr/ucb # extend search path 26 | 27 | srvdir="$1" 28 | 29 | testLarge=/bin/true 30 | testMany=/bin/true 31 | 32 | if [ -z "$srvdir" ]; then 33 | echo "You need to specify a destination directory" 34 | echo "Usage: $0 " 35 | exit 1 36 | fi 37 | 38 | if [ -r "$srvdir" ]; then 39 | deletesrv=no 40 | else 41 | if mkdir "$srvdir"; then 42 | true 43 | else 44 | echo "error creating test directory" 45 | exit 1 46 | fi 47 | deletesrv=yes 48 | fi 49 | 50 | tmpdir="/tmp/testperf-`whoami`-$$" 51 | 52 | many="$tmpdir/many" 53 | large="$tmpdir/large" 54 | 55 | mkdir "$tmpdir" 56 | mkdir "$many" 57 | 58 | if $testLarge; then 59 | echo "Setting up large file with 64MB " 60 | echo 123456789012345678901234567890123456789012345678901234567890123 >$large 61 | dd if=$large bs=64 count=1023 >>$large # file should now be 64k 62 | dd if=$large bs=65536 count=1023 >>$large # file should now be 64MB 63 | fi 64 | 65 | if $testMany; then 66 | echo -n "Setting up directory with 2000 files " 67 | for i in 0 1; do 68 | for j in 0 1 2 3 4 5 6 7 8 9; do 69 | for k in 0 1 2 3 4 5 6 7 8 9; do 70 | for l in 0 1 2 3 4 5 6 7 8 9; do 71 | echo "this is file $i$j$k$l" >$many/file-$i$j$k$l.txt 72 | done 73 | echo -n '.' 74 | done 75 | done 76 | done 77 | fi 78 | 79 | echo 80 | 81 | if $testLarge; then 82 | echo "----------------------------------------------------------------------" 83 | echo "First test: copy large file to server" 84 | time cp $large $srvdir 85 | 86 | echo "----------------------------------------------------------------------" 87 | echo "Second test: copy large file from server" 88 | rm $large 89 | time cp $srvdir/large $large 90 | rm $srvdir/large 91 | fi 92 | 93 | if /$testMany; then 94 | echo "----------------------------------------------------------------------" 95 | echo "Copy 2000 files to server" 96 | time cp -r $many $srvdir 97 | 98 | echo "----------------------------------------------------------------------" 99 | echo "Copy 2000 files from server" 100 | rm -r $many 101 | time cp -r $srvdir/many $many 102 | 103 | echo "----------------------------------------------------------------------" 104 | echo "Disk usage of large directory" 105 | time du $srvdir/many 106 | 107 | echo "----------------------------------------------------------------------" 108 | echo "Listing of large directory" 109 | time ls -al $srvdir/many >/dev/null 110 | 111 | echo "----------------------------------------------------------------------" 112 | echo "Deleting 2000 files on server" 113 | time rm -r $srvdir/many 114 | fi 115 | 116 | echo "----------------------------------------------------------------------" 117 | echo "cleaning up" 118 | 119 | rm -rf "$tmpdir" 120 | if [ $deletesrv '=' yes ]; then 121 | rmdir $srvdir 122 | fi 123 | 124 | echo "ready." 125 | -------------------------------------------------------------------------------- /src/fstorture/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: util.h 3 | * Project: CIFS Client Automatic Test 4 | * Author: Christian Starkjohann 5 | * Creation Date: 1998-04-28 6 | * Tabsize: 4 7 | * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed 8 | * under the terms of the Gnu General Public License (GPL). 9 | * 10 | * Copyright © 2009 Apple Inc. 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2 only. This 13 | * program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * version 2 for more details. A copy of the GNU General Public License 17 | * version 2 is included along with this program. 18 | */ 19 | 20 | #include "basictypes.h" 21 | 22 | /* ------------------------------------------------------------------------- */ 23 | 24 | typedef double real_t; /* real numbers are double */ 25 | 26 | void random_init(int na1, int na2, int na3, int nb1); 27 | real_t random_get(void); 28 | int random_int(int exclusive_range); 29 | real_t random_gauss(real_t stdval, real_t maxRange); 30 | void random_block(void *block, int len); 31 | void random_name(char *name, int len, int prefix); 32 | const char * random_root(); 33 | void random_path(char *path, int id, int running, const char *root); 34 | 35 | void perr(int e, char *s, ...); 36 | void cleanup(int sig); 37 | /* ------------------------------------------------------------------------- */ 38 | 39 | -------------------------------------------------------------------------------- /src/fsx/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2009 Apple Inc. All rights reserved. 3 | # 4 | # @APPLE_LICENSE_HEADER_START@ 5 | # 6 | # This file contains Original Code and/or Modifications of Original Code 7 | # as defined in and that are subject to the Apple Public Source License 8 | # Version 2.0 (the 'License'). You may not use this file except in 9 | # compliance with the License. Please obtain a copy of the License at 10 | # http://www.opensource.apple.com/apsl/ and read it before using this 11 | # file. 12 | # 13 | # The Original Code and all software distributed under the License are 14 | # distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | # EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | # Please see the License for the specific language governing rights and 19 | # limitations under the License. 20 | # 21 | # @APPLE_LICENSE_HEADER_END@ 22 | # 23 | 24 | ARCHS := ppc i386 x86_64 25 | INTERNAL_FRAMEWORKS := /AppleInternal/Library/Frameworks 26 | CFLAGS := $(ARCHS:%=-arch %) -Wall -O3 27 | 28 | ifeq ($(wildcard $(INTERNAL_FRAMEWORKS)), $(INTERNAL_FRAMEWORKS)) 29 | CPPFLAGS += -DXILOG 30 | CFLAGS += -F/AppleInternal/Library/Frameworks 31 | LIBS += -framework XILog 32 | endif 33 | 34 | .PHONY: clean 35 | 36 | fsx: 37 | $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ fsx.c $(LIBS) 38 | 39 | clean: 40 | -rm -f *.o fsx 41 | 42 | -------------------------------------------------------------------------------- /src/fsx/fsx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998-2009 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | * 23 | * File: fsx.c 24 | * Author: Avadis Tevanian, Jr. 25 | * 26 | * File system exerciser. 27 | * 28 | * Rewrite and enhancements 1998-2003 Conrad Minshall -- conrad@mac.com 29 | * 30 | * Various features from Joe Sokol, Pat Dirks, and Clark Warner. 31 | * 32 | * Small changes to work under Linux -- davej@suse.de 33 | * 34 | * Sundry porting patches from Guy Harris 12/2001 35 | * 36 | * Checks for mmap last-page zero fill. 37 | * 38 | * Oct 2006: Now includes Wenguang's changes, Jim's Named Fork support, 39 | * Peter's EA changes, and XILog additions 40 | * 41 | * Various features/enhancements from Mike Mackovitch -- macko@apple.com 42 | * 43 | * Added no-cached r/w option May 2008 -- rtucker@apple.com, bsuinn@apple.com 44 | * 45 | * Compile with: 46 | cc -Wall -O3 fsx.c -o fsx 47 | gcc -arch ppc -arch i386 -arch ppc64 -arch x86_64 -Wall -O3 fsx.c -o fsx -DXILOG -F/AppleInternal/Library/Frameworks -framework XILog 48 | * 49 | */ 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #ifdef _UWIN 59 | # include 60 | # include 61 | #endif 62 | #include 63 | #include 64 | #ifndef MAP_FILE 65 | # define MAP_FILE 0 66 | #endif 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #ifdef XILOG 77 | # include 78 | #endif 79 | 80 | /* 81 | * A log entry is an operation and a bunch of arguments. 82 | */ 83 | 84 | struct log_entry { 85 | int opnum; 86 | int operation; 87 | int args[3]; 88 | }; 89 | 90 | #define DEFAULT_LOGSIZE 1024 91 | 92 | struct log_entry *oplog; /* the log */ 93 | int logptr = 0; /* current position in log */ 94 | int logcount = 0; /* total ops */ 95 | 96 | /* 97 | * Define operations 98 | */ 99 | 100 | #define OP_READ 1 101 | #define OP_WRITE 2 102 | #define OP_TRUNCATE 3 103 | #define OP_CLOSEOPEN 4 104 | #define OP_MAPREAD 5 105 | #define OP_MAPWRITE 6 106 | #define OP_SKIPPED 7 107 | #define OP_NOCACHEREAD 8 108 | #define OP_NOCACHEWRITE 9 109 | 110 | int page_size; 111 | int page_mask; 112 | 113 | char *good_buf; /* a pointer to the correct data */ 114 | char *temp_buf; /* a pointer to the current data */ 115 | char fname[MAXPATHLEN]; /* name of our test file */ 116 | int fd; /* fd for our test file */ 117 | int ea_lastwrite = 0; /* Size of the last EA Write */ 118 | char *eaname; /* Name of the EA key */ 119 | 120 | off_t file_size = 0; 121 | off_t biggest = 0; 122 | char state[256]; 123 | unsigned long testcalls = 0; /* calls to function "test" */ 124 | 125 | unsigned long simulatedopcount = 0; /* -b flag */ 126 | int closeprob = 0; /* -c flag */ 127 | int debug = 0; /* -v flag */ 128 | unsigned long debugstart = 0; /* -D flag */ 129 | int ea = 0; /* -e flag */ 130 | unsigned long maxfilelen = 256 * 1024; /* -l flag */ 131 | int sizechecks = 1; /* -n flag disables them */ 132 | int maxoplen = 64 * 1024; /* -o flag */ 133 | int quiet = 0; /* -q flag */ 134 | unsigned long progressinterval = 0; /* -p flag */ 135 | int readbdy = 1; /* -r flag */ 136 | int style = 0; /* -s flag */ 137 | int truncbdy = 1; /* -t flag */ 138 | int writebdy = 1; /* -w flag */ 139 | long monitorstart = -1; /* -m flag */ 140 | long monitorend = -1; /* -m flag */ 141 | int lite = 0; /* -L flag */ 142 | long numops = -1; /* -N flag */ 143 | int randomoplen = 1; /* -O flag disables it */ 144 | int seed = 0; /* -S flag */ 145 | int mapped_writes = 1; /* -W flag disables */ 146 | int mapped_reads = 1; /* -R flag disables it */ 147 | int logsize = DEFAULT_LOGSIZE; /* -G flag */ 148 | int datasize = 4; /* -T flag */ 149 | int modsize = 0; 150 | int fsxgoodfd = -1; 151 | FILE * fsxlogf = NULL; 152 | int badoff = -1; 153 | int closeopen = 0; 154 | int sync_before_close = 0; /* -y flag enables it */ 155 | int interactive = 0; /* -i flag interactive */ 156 | int interactiveSince = -1; /* -I flag when to start interactive */ 157 | int usehole = 1; // by default use hole (sparse file) 158 | int slow_motion = 0; 159 | long duration = 0; /* -d flag */ 160 | unsigned int pinginterval = 10000; // About every 30sec? 161 | #ifdef XILOG 162 | XILogRef xilogref; 163 | #endif 164 | int gUseRandomNoCache = 0; /* -C randomly mix cached and un-cached r/w ops */ 165 | 166 | char *msgbuf; 167 | int msgbuflen; 168 | 169 | void dotruncate(unsigned size); 170 | void writefileimage(void); 171 | 172 | #define get_data_at(cp) \ 173 | (((*(((unsigned char *)(cp)) + 0)) << 0) | \ 174 | ((datasize < 2) ? 0 : \ 175 | ((*(((unsigned char *)(cp)) + 1)) << 8)) | \ 176 | ((datasize < 4) ? 0 : \ 177 | (((*(((unsigned char *)(cp)) + 2)) << 16) | \ 178 | ((*(((unsigned char *)(cp)) + 3)) << 24)))) 179 | 180 | #define set_data_at(cp, val) \ 181 | do { \ 182 | (*(((unsigned char *)(cp)) + 0)) = ((val) >> 0) & 0xff; \ 183 | if (datasize < 2) break; \ 184 | (*(((unsigned char *)(cp)) + 1)) = (((val) >> 8) & 0xff); \ 185 | if (datasize < 4) break; \ 186 | (*(((unsigned char *)(cp)) + 2)) = (((val) >> 16) & 0xff); \ 187 | (*(((unsigned char *)(cp)) + 3)) = (((val) >> 24) & 0xff); \ 188 | } while (0) 189 | 190 | #define SHOWLOGENTRY(OPSTART, OPEND) \ 191 | (!quiet && \ 192 | ((progressinterval && (testcalls % progressinterval == 0)) || \ 193 | (debug && \ 194 | ((monitorstart == -1) || \ 195 | (((OPEND) > monitorstart) && \ 196 | ((monitorend == -1) || ((OPSTART) <= monitorend))))))) 197 | 198 | void docloseopen(void); 199 | 200 | int parsetime(char *t) 201 | { 202 | int i = 0; 203 | int secs = 0; 204 | char b[128]; bzero(b, 128); 205 | 206 | for (i=0; i < strlen(t); i++) { 207 | switch (t[i]) { 208 | case 's': 209 | secs += atoi(b); 210 | bzero(b, 128); 211 | break; 212 | case 'm': 213 | secs += atoi(b) * 60; 214 | bzero(b, 128); 215 | break; 216 | case 'h': 217 | secs += atoi(b) * 60 * 60; 218 | bzero(b, 128); 219 | break; 220 | case 'd': 221 | secs += atoi(b) * 60 * 60 * 24; 222 | bzero(b, 128); 223 | break; 224 | case 'w': 225 | secs += atoi(b) * 60 * 60 * 24 * 7; 226 | bzero(b, 128); 227 | break; 228 | case 'y': 229 | secs += atoi(b) * 60 * 60 * 24 * 365; 230 | bzero(b, 128); 231 | break; 232 | default: 233 | sprintf(b, "%s%c", b, t[i]); 234 | } 235 | } 236 | if (secs == 0) // maybe they just gave us a number? 237 | secs = atoi(t); 238 | return(secs); 239 | } 240 | 241 | 242 | void 243 | mvwarnc(code, fmt, ap) 244 | int code; 245 | const char *fmt; 246 | va_list ap; 247 | { 248 | fprintf(stderr, "fsx: "); 249 | if (fmt != NULL) { 250 | vfprintf(stderr, fmt, ap); 251 | fprintf(stderr, ": "); 252 | } 253 | fprintf(stderr, "%s\n", strerror(code)); 254 | } 255 | 256 | 257 | void 258 | mwarn(const char * fmt, ...) 259 | { 260 | va_list ap; 261 | va_start(ap, fmt); 262 | #ifdef XILOG 263 | XILogMsg(fmt, ap); 264 | XILogMsg("%s", strerror(errno)); 265 | va_end(ap); 266 | va_start(ap, fmt); 267 | #endif 268 | mvwarnc(errno, fmt, ap); 269 | va_end(ap); 270 | } 271 | 272 | 273 | void 274 | prt(char *fmt, ...) 275 | { 276 | va_list args; 277 | 278 | va_start(args, fmt); 279 | #ifdef XILOG 280 | XILogMsg(fmt, args); 281 | va_end(args); 282 | va_start(args, fmt); 283 | #endif 284 | vfprintf(stdout, fmt, args); 285 | fflush(stdout); 286 | va_end(args); 287 | if (fsxlogf) { 288 | va_start(args, fmt); 289 | vfprintf(fsxlogf, fmt, args); 290 | fflush(fsxlogf); 291 | va_end(args); 292 | } 293 | fflush(stdout); 294 | } 295 | 296 | void 297 | prt2(char *fmt, ...) 298 | { 299 | va_list args; 300 | 301 | va_start(args, fmt); 302 | vfprintf(stdout, fmt, args); 303 | va_end(args); 304 | if (fsxlogf) { 305 | va_start(args, fmt); 306 | vfprintf(fsxlogf, fmt, args); 307 | va_end(args); 308 | } 309 | fflush(stdout); 310 | } 311 | 312 | 313 | void 314 | prterr(char *prefix) 315 | { 316 | #ifdef XILOG 317 | XILogErr("%s%s%s", prefix, prefix ? ": " : "", strerror(errno)); 318 | #endif 319 | prt2("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno)); 320 | } 321 | 322 | 323 | int 324 | log4(int operation, int arg0, int arg1, int arg2) 325 | { 326 | int logent = logptr; 327 | struct log_entry *le = &oplog[logent]; 328 | le->opnum = logcount + 1; 329 | le->operation = operation; 330 | if (closeopen) 331 | le->operation = ~ le->operation; 332 | le->args[0] = arg0; 333 | le->args[1] = arg1; 334 | le->args[2] = arg2; 335 | logptr++; 336 | logcount++; 337 | if (msgbuflen) { 338 | snprintf(msgbuf, msgbuflen+1, "%d", logcount); 339 | } 340 | if (logptr >= logsize) 341 | logptr = 0; 342 | return logent; 343 | } 344 | 345 | 346 | void 347 | offset_last_mod(int offset, int *write, int *tdown, int *tup) 348 | { 349 | int i, count, down, opnum, operation; 350 | struct log_entry *lp; 351 | 352 | *write = *tdown = *tup = -1; 353 | 354 | opnum = logcount; 355 | i = logptr - 1; 356 | if (i < 0) 357 | i = logsize - 1; 358 | if (logcount < logsize) { 359 | count = logcount; 360 | } else { 361 | count = logsize; 362 | } 363 | for ( ; count > 0; count--, opnum--) { 364 | lp = &oplog[i]; 365 | operation = lp->operation; 366 | if ((closeopen = operation < 0)) 367 | operation = ~ operation; 368 | switch (operation) { 369 | case OP_MAPWRITE: 370 | case OP_WRITE: 371 | if (*write != -1) 372 | break; 373 | if ((offset >= lp->args[0]) && (offset < (lp->args[0] + lp->args[1]))) 374 | *write = opnum; 375 | break; 376 | case OP_TRUNCATE: 377 | down = lp->args[0] < lp->args[1]; 378 | if ((offset >= lp->args[!down]) && (offset < lp->args[!!down])) { 379 | if (down && (*tdown == -1)) 380 | *tdown = opnum; 381 | else if (!down && (*tup == -1)) 382 | *tup = opnum; 383 | } 384 | break; 385 | } 386 | if ((*write != -1) && (*tdown != -1) && (*tup != -1)) 387 | return; 388 | i--; 389 | if (i < 0) 390 | i = logsize - 1; 391 | } 392 | } 393 | 394 | void 395 | logentrydump(int logent, int opnum) 396 | { 397 | struct log_entry *lp = &oplog[logent]; 398 | int down; 399 | 400 | if (modsize) 401 | prt("%d(%d): ", opnum, opnum%modsize); 402 | else 403 | prt("%d: ", opnum); 404 | if ((closeopen = lp->operation < 0)) 405 | lp->operation = ~ lp->operation; 406 | 407 | switch (lp->operation) { 408 | case OP_MAPREAD: 409 | prt("%-15s 0x%x (%d) thru 0x%x (%d)\t(0x%x (%d) bytes)", "MAPREAD", 410 | lp->args[0], lp->args[0], 411 | lp->args[0] + lp->args[1] - 1, lp->args[0] + lp->args[1] - 1, 412 | lp->args[1], lp->args[1]); 413 | if ((badoff >= lp->args[0]) && (badoff < lp->args[0] + lp->args[1])) 414 | { 415 | prt("\t***RRRR***"); 416 | } 417 | break; 418 | case OP_MAPWRITE: 419 | prt("%-15s 0x%x (%d) thru 0x%x (%d)\t(0x%x (%d) bytes)", "MAPWRITE", 420 | lp->args[0], lp->args[0], 421 | lp->args[0] + lp->args[1] - 1, lp->args[0] + lp->args[1] - 1, 422 | lp->args[1], lp->args[1]); 423 | if ((badoff >= lp->args[0]) && (badoff < lp->args[0] + lp->args[1])) 424 | { 425 | prt("\t******WWWW"); 426 | } 427 | break; 428 | case OP_READ: 429 | prt("%-15s 0x%x (%d) thru 0x%x (%d)\t(0x%x (%d) bytes)", "READ", 430 | lp->args[0], lp->args[0], 431 | lp->args[0] + lp->args[1] - 1, lp->args[0] + lp->args[1] - 1, 432 | lp->args[1], lp->args[1]); 433 | if (badoff >= lp->args[0] && 434 | badoff < lp->args[0] + lp->args[1]) 435 | { 436 | prt("\t***RRRR***"); 437 | } 438 | break; 439 | case OP_WRITE: 440 | prt("%-15s 0x%x (%d) thru 0x%x (%d)\t(0x%x (%d) bytes)", "WRITE", 441 | lp->args[0], lp->args[0], 442 | lp->args[0] + lp->args[1] - 1, lp->args[0] + lp->args[1] - 1, 443 | lp->args[1], lp->args[1]); 444 | if (lp->args[0] > lp->args[2]) 445 | { 446 | prt(" HOLE"); 447 | } 448 | else if ((lp->args[0] + lp->args[1]) > lp->args[2]) 449 | { 450 | prt(" EXTEND"); 451 | } 452 | if (((badoff >= lp->args[0]) || (badoff >= lp->args[2])) && 453 | (badoff < (lp->args[0] + lp->args[1]))) 454 | { 455 | prt("\t***WWWW"); 456 | } 457 | break; 458 | case OP_NOCACHEREAD: 459 | prt("%-15s 0x%x (%d) thru 0x%x (%d)\t(0x%x (%d) bytes)", "NOCACHEREAD", 460 | lp->args[0], lp->args[0], 461 | lp->args[0] + lp->args[1] - 1, lp->args[0] + lp->args[1] - 1, 462 | lp->args[1], lp->args[1]); 463 | if (badoff >= lp->args[0] && 464 | badoff < lp->args[0] + lp->args[1]) 465 | { 466 | prt("\t***RRRR***"); 467 | } 468 | break; 469 | case OP_NOCACHEWRITE: 470 | prt("%-15s 0x%x (%d) thru 0x%x (%d)\t(0x%x (%d) bytes)", "NOCACHEWRITE", 471 | lp->args[0], lp->args[0], 472 | lp->args[0] + lp->args[1] - 1, lp->args[0] + lp->args[1] - 1, 473 | lp->args[1], lp->args[1]); 474 | if (lp->args[0] > lp->args[2]) 475 | { 476 | prt(" HOLE"); 477 | } 478 | else if ((lp->args[0] + lp->args[1]) > lp->args[2]) 479 | { 480 | prt(" EXTEND"); 481 | } 482 | if (((badoff >= lp->args[0]) || (badoff >= lp->args[2])) && 483 | (badoff < (lp->args[0] + lp->args[1]))) 484 | { 485 | prt("\t***WWWW"); 486 | } 487 | break; 488 | case OP_TRUNCATE: 489 | down = lp->args[0] < lp->args[1]; 490 | prt("%-15s from 0x%x (%d) to 0x%x (%d)", 491 | down ? "TRUNCATE DOWN" : "TRUNCATE UP", 492 | lp->args[1], lp->args[1], 493 | lp->args[0], lp->args[0]); 494 | if ((badoff >= lp->args[!down]) && 495 | (badoff < lp->args[!!down])) 496 | { 497 | prt("\t******WWWW"); 498 | } 499 | break; 500 | case OP_SKIPPED: 501 | prt("SKIPPED (no operation)"); 502 | break; 503 | default: 504 | prt("BOGUS LOG ENTRY (operation code = %d)!", 505 | lp->operation); 506 | } 507 | if (closeopen) 508 | { 509 | prt("\n\t\tCLOSE/OPEN"); 510 | } 511 | prt("\n"); 512 | } 513 | 514 | 515 | void 516 | logdump(void) 517 | { 518 | int i, count, opnum; 519 | 520 | // don't dump log if we've been logging ops via debug 521 | if (debug) return; 522 | 523 | prt("LOG DUMP (%d total operations):\n", logcount); 524 | if (logcount < logsize) { 525 | i = 0; 526 | count = logcount; 527 | opnum = 1; 528 | } else { 529 | i = logptr; 530 | count = logsize; 531 | opnum = 1 + logcount - logsize; 532 | } 533 | for ( ; count > 0; count--, opnum++) { 534 | logentrydump(i, opnum); 535 | i++; 536 | if (i == logsize) 537 | i = 0; 538 | } 539 | } 540 | 541 | 542 | void 543 | save_buffer(char *buffer, off_t bufferlength, int fd) 544 | { 545 | off_t ret; 546 | ssize_t byteswritten; 547 | 548 | if (fd <= 0 || bufferlength == 0) 549 | return; 550 | 551 | if (bufferlength > SSIZE_MAX) { 552 | prt("fsx flaw: overflow in save_buffer\n"); 553 | exit(67); 554 | } 555 | if (lite) { 556 | off_t size_by_seek = lseek(fd, (off_t)0, SEEK_END); 557 | if (size_by_seek == (off_t)-1) 558 | prterr("save_buffer: lseek eof"); 559 | else if (bufferlength > size_by_seek) { 560 | mwarn("WARNING: save_buffer: .fsxgood file too short... will save 0x%llx bytes instead of 0x%llx\n", (unsigned long long)size_by_seek, 561 | (unsigned long long)bufferlength); 562 | bufferlength = size_by_seek; 563 | } 564 | } 565 | 566 | ret = lseek(fd, (off_t)0, SEEK_SET); 567 | if (ret == (off_t)-1) 568 | prterr("save_buffer: lseek 0"); 569 | 570 | byteswritten = write(fd, buffer, (size_t)bufferlength); 571 | if (byteswritten != bufferlength) { 572 | if (byteswritten == -1) 573 | prterr("save_buffer write"); 574 | else 575 | mwarn("WARNING: save_buffer: short write, 0x%x bytes instead of 0x%llx\n", 576 | (unsigned)byteswritten, 577 | (unsigned long long)bufferlength); 578 | } 579 | } 580 | 581 | 582 | void 583 | failure(int status) 584 | { 585 | if (fsxgoodfd >= 0) { 586 | if (good_buf) { 587 | save_buffer(good_buf, file_size, fsxgoodfd); 588 | prt("Correct content saved for comparison\n"); 589 | prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n", 590 | fname, fname); 591 | } 592 | close(fsxgoodfd); 593 | } 594 | prt("Seed was set to %d\n", seed); 595 | exit(status); 596 | } 597 | 598 | 599 | void 600 | check_buffers(unsigned offset, unsigned size) 601 | { 602 | unsigned int c, t; 603 | unsigned i = 0; 604 | unsigned n = 0; 605 | unsigned sizeleft = size; 606 | unsigned start, good, bad; 607 | int op, w, td, tu; 608 | 609 | start = good = bad = 0; 610 | op = -1; 611 | 612 | if (memcmp(good_buf + offset, temp_buf, size) != 0) { 613 | prt("data miscompare @ %d\n", offset); 614 | while (sizeleft > 0) { 615 | c = get_data_at(&good_buf[offset+i]); 616 | t = get_data_at(&temp_buf[i]); 617 | if (c != t) { 618 | if (n == 0) { 619 | start = offset + i; 620 | good = c; 621 | bad = t; 622 | op = ((t > 0) && (t <= logcount)) ? t : -1; 623 | } 624 | n+=datasize; 625 | if (badoff < 0) { 626 | badoff = offset + i; 627 | logdump(); 628 | prt("data miscompare @ %d\n", offset); 629 | prt("%-10s %-10s %-10s %-10s %-8s Last: %-8s %-8s %-8s\n", 630 | "OFFSET", "GOOD", "BAD", "LENGTH", "BADOP#", 631 | "WRITE", "TRUNC-", "TRUNC+"); 632 | } 633 | } 634 | i+=datasize; 635 | sizeleft-=datasize; 636 | if (n && ((c == t) || (sizeleft <= 0))) { 637 | w = td = tu = -1; 638 | offset_last_mod(start, &w, &td, &tu); 639 | prt("0x%08x 0x%08x 0x%08x 0x%08x %-8d %-8d %-8d %-8d\n", 640 | start, good, bad, n, op, w, td, tu); 641 | if (c == t) 642 | n = 0; 643 | } 644 | } 645 | if (badoff == -1) { 646 | logdump(); 647 | prt("transient data miscompare @ %d ????????\n", offset); 648 | prt("memcmp(%d,%d) failed but no differences found ????????\n", offset, size); 649 | } 650 | failure(110); 651 | } 652 | } 653 | 654 | 655 | void 656 | check_size(void) 657 | { 658 | struct stat statbuf; 659 | off_t size_by_seek; 660 | 661 | if (fstat(fd, &statbuf)) { 662 | prterr("check_size: fstat"); 663 | statbuf.st_size = -1; 664 | } 665 | size_by_seek = lseek(fd, (off_t)0, SEEK_END); 666 | if (file_size != statbuf.st_size || file_size != size_by_seek) { 667 | logdump(); 668 | prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n", 669 | (unsigned long long)file_size, 670 | (unsigned long long)statbuf.st_size, 671 | (unsigned long long)size_by_seek); 672 | failure(120); 673 | } 674 | } 675 | 676 | 677 | void 678 | check_trunc_hack(void) 679 | { 680 | struct stat statbuf; 681 | ftruncate(fd, (off_t)0); 682 | 683 | if (!usehole) 684 | return; 685 | 686 | ftruncate(fd, (off_t)100000); 687 | fstat(fd, &statbuf); 688 | if (statbuf.st_size != (off_t)100000) { 689 | prt("no extend on truncate! not posix!\n"); 690 | exit(130); 691 | } 692 | ftruncate(fd, (off_t)0); 693 | } 694 | 695 | 696 | void 697 | doread(unsigned offset, unsigned size) 698 | { 699 | off_t ret; 700 | unsigned iret; 701 | int logent; 702 | int cache_off = 0; 703 | 704 | if (ea) 705 | size = ea_lastwrite; 706 | 707 | offset -= offset % readbdy; 708 | if (size == 0) { 709 | if (debug && testcalls > simulatedopcount) 710 | { 711 | prt("skipping zero size read\n"); 712 | } 713 | log4(OP_SKIPPED, OP_READ, offset, size); 714 | return; 715 | } 716 | if (size + offset > file_size) { 717 | if (debug && testcalls > simulatedopcount) 718 | { 719 | prt("skipping seek/read past end of file\n"); 720 | } 721 | log4(OP_SKIPPED, OP_READ, offset, size); 722 | return; 723 | } 724 | 725 | /* When the gUseRandomNoCache option is enable (-C), 726 | * randomly turn caching off for 30% of the read calls. 727 | * Re-enable caching after the read is complete. 728 | */ 729 | if (gUseRandomNoCache && ((random() % 100) < 30)) { 730 | cache_off = 1; 731 | logent = log4(OP_NOCACHEREAD, offset, size, 0); 732 | } else { 733 | logent = log4(OP_READ, offset, size, 0); 734 | } 735 | 736 | if (SHOWLOGENTRY(offset, offset + size)) 737 | { 738 | logentrydump(logent, logcount); 739 | } 740 | 741 | if (testcalls <= simulatedopcount) 742 | return; 743 | 744 | if (interactive) { 745 | printf("Hit return when ready..."); 746 | getchar(); 747 | } 748 | 749 | if (!ea) { 750 | ret = lseek(fd, (off_t)offset, SEEK_SET); 751 | if (ret == (off_t)-1) { 752 | logdump(); 753 | prterr("doread: lseek"); 754 | failure(140); 755 | } 756 | 757 | if (cache_off && (fcntl(fd, F_NOCACHE, 1) != 0)) { // turn data caching off 758 | logdump(); 759 | prterr("doread: fcntl(F_NOCACHE, 1)"); 760 | failure(201); 761 | } 762 | iret = read(fd, temp_buf, size); 763 | if (cache_off && (fcntl(fd, F_NOCACHE, 0) != 0)) { 764 | logdump(); 765 | prterr("doread: fcntl(F_NOCACHE, 0)"); 766 | failure(201); 767 | } 768 | } else { 769 | iret = fgetxattr(fd, eaname, temp_buf, size, 0, 0); 770 | } 771 | 772 | if (iret != size) { 773 | logdump(); 774 | if (iret == -1) 775 | prterr("doread: read"); 776 | else 777 | prt("short read: 0x%x bytes instead of 0x%x\n", iret, size); 778 | failure(141); 779 | } 780 | 781 | check_buffers(offset, size); 782 | } 783 | 784 | 785 | void 786 | check_eofpage(char *s, unsigned offset, char *p, int size) 787 | { 788 | uintptr_t last_page, should_be_zero; 789 | 790 | if (offset + size <= (file_size & ~page_mask)) 791 | return; 792 | /* 793 | * we landed in the last page of the file 794 | * test to make sure the VM system provided 0's 795 | * beyond the true end of the file mapping 796 | * (as required by mmap def in 1996 posix 1003.1) 797 | */ 798 | last_page = ((uintptr_t)p + (offset & page_mask) + size) & ~page_mask; 799 | 800 | for (should_be_zero = last_page + (file_size & page_mask); 801 | should_be_zero < last_page + page_size; 802 | should_be_zero++) 803 | if (*(char *)should_be_zero) { 804 | logdump(); 805 | prt("Mapped %s: non-zero data past EOF (0x%llx) page offset 0x%x is 0x%04x\n", 806 | s, file_size - 1, should_be_zero & page_mask, 807 | (*(char *)should_be_zero)); 808 | failure(205); 809 | } 810 | } 811 | 812 | 813 | void 814 | domapread(unsigned offset, unsigned size) 815 | { 816 | unsigned pg_offset; 817 | unsigned map_size; 818 | char *p; 819 | int logent; 820 | 821 | if (ea) 822 | return; 823 | 824 | offset -= offset % readbdy; 825 | if (size == 0) { 826 | if (debug && testcalls > simulatedopcount) 827 | { 828 | prt("skipping zero size read\n"); 829 | } 830 | log4(OP_SKIPPED, OP_MAPREAD, offset, size); 831 | return; 832 | } 833 | if (size + offset > file_size) { 834 | if (debug && testcalls > simulatedopcount) 835 | { 836 | prt("skipping seek/read past end of file\n"); 837 | } 838 | log4(OP_SKIPPED, OP_MAPREAD, offset, size); 839 | return; 840 | } 841 | 842 | logent = log4(OP_MAPREAD, offset, size, 0); 843 | 844 | if (SHOWLOGENTRY(offset, offset + size)) 845 | { 846 | logentrydump(logent, logcount); 847 | } 848 | 849 | if (testcalls <= simulatedopcount) 850 | return; 851 | 852 | pg_offset = offset & page_mask; 853 | map_size = pg_offset + size; 854 | 855 | if (interactive) { 856 | printf("Hit return when ready..."); 857 | getchar(); 858 | } 859 | 860 | if ((p = (char *)mmap(0, map_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 861 | (off_t)(offset - pg_offset))) == (char *)-1) { 862 | logdump(); 863 | prterr("domapread: mmap"); 864 | failure(190); 865 | } 866 | memcpy(temp_buf, p + pg_offset, size); 867 | 868 | check_eofpage("Read", offset, p, size); 869 | 870 | if (munmap(p, map_size) != 0) { 871 | logdump(); 872 | prterr("domapread: munmap"); 873 | failure(191); 874 | } 875 | 876 | check_buffers(offset, size); 877 | } 878 | 879 | 880 | void 881 | gendata(char *good_buf, unsigned offset, unsigned size) 882 | { 883 | while (size > 0) { 884 | size -= datasize; 885 | set_data_at(&good_buf[offset], testcalls); 886 | offset += datasize; 887 | } 888 | } 889 | 890 | 891 | void 892 | dowrite(unsigned offset, unsigned size) 893 | { 894 | off_t ret; 895 | unsigned iret; 896 | int logent; 897 | int cache_off = 0; 898 | 899 | offset -= offset % writebdy; 900 | if (size == 0) { 901 | if (debug && testcalls > simulatedopcount) 902 | { 903 | prt("skipping zero size write\n"); 904 | } 905 | log4(OP_SKIPPED, OP_WRITE, offset, size); 906 | return; 907 | } 908 | 909 | /* When the gUseRandomNoCache option is enable (-C), 910 | * randomly turn caching off for 30% of the write calls. 911 | * Re-enable caching after the write is complete. 912 | */ 913 | if (gUseRandomNoCache && ((random() % 100) < 30)) { // turn data caching off 914 | cache_off = 1; 915 | logent = log4(OP_NOCACHEWRITE, offset, size, file_size); 916 | } else { 917 | logent = log4(OP_WRITE, offset, size, file_size); 918 | } 919 | 920 | gendata(good_buf, offset, size); 921 | 922 | if (SHOWLOGENTRY(offset, offset + size)) 923 | { 924 | logentrydump(logent, logcount); 925 | } 926 | 927 | if (file_size < offset + size) { 928 | if (SHOWLOGENTRY(offset, offset + size)) 929 | { 930 | prt("extend file size from 0x%x (%d) to 0x%x (%d)\n", (int)file_size, (int)file_size, offset+size, offset+size); 931 | } 932 | 933 | if (file_size < offset) { 934 | memset(good_buf + file_size, '\0', offset - file_size); 935 | if (!usehole) { 936 | off_t ret; 937 | unsigned iret; 938 | 939 | if (interactive) { 940 | printf("Hit return when ready..."); 941 | getchar(); 942 | } 943 | 944 | ret = lseek(fd, (off_t)file_size, SEEK_SET); 945 | if (ret == (off_t)-1) { 946 | logdump(); 947 | prterr("dowrite: lseek"); 948 | failure(150); 949 | } 950 | if (cache_off && (fcntl(fd, F_NOCACHE, 1) != 0)) { // turn data caching off 951 | logdump(); 952 | prterr("dowrite: fcntl(F_NOCACHE, 1)"); 953 | failure(201); 954 | } 955 | iret = write(fd, good_buf + file_size, offset - file_size); 956 | if (iret != offset - file_size) { 957 | logdump(); 958 | if (iret == -1) 959 | prterr("dowrite: write 0s"); 960 | else 961 | { 962 | prt("short write: 0x%x bytes instead of 0x%x\n", 963 | iret, size); 964 | } 965 | failure(151); 966 | } 967 | if (cache_off && (fcntl(fd, F_NOCACHE, 0) != 0)) { 968 | logdump(); 969 | prterr("dowrite: fcntl(F_NOCACHE, 0)"); 970 | failure(201); 971 | } 972 | } 973 | } 974 | file_size = offset + size; 975 | if (lite) { 976 | logdump(); 977 | mwarn("WARNING: Lite file size bug in fsx!"); 978 | failure(149); 979 | } 980 | } 981 | 982 | if (testcalls <= simulatedopcount) 983 | return; 984 | 985 | if (interactive) { 986 | printf("Hit return when ready..."); 987 | getchar(); 988 | } 989 | 990 | if (!ea) { 991 | ret = lseek(fd, (off_t)offset, SEEK_SET); 992 | if (ret == (off_t)-1) { 993 | logdump(); 994 | prterr("dowrite: lseek"); 995 | failure(150); 996 | } 997 | if (cache_off && (fcntl(fd, F_NOCACHE, 1) != 0)) { // turn data caching off 998 | logdump(); 999 | prterr("dowrite: fcntl(F_NOCACHE, 1)"); 1000 | failure(201); 1001 | } 1002 | iret = write(fd, good_buf + offset, size); 1003 | if (iret != size) { 1004 | logdump(); 1005 | if (iret == -1) 1006 | prterr("dowrite: write"); 1007 | else 1008 | { 1009 | prt("short write: 0x%x bytes instead of 0x%x\n", 1010 | iret, size); 1011 | } 1012 | failure(151); 1013 | } 1014 | if (cache_off && (fcntl(fd, F_NOCACHE, 0) != 0)) { 1015 | logdump(); 1016 | prterr("dowrite: fcntl(F_NOCACHE, 0)"); 1017 | failure(201); 1018 | } 1019 | } else { 1020 | if (random() % 2000 == 0) { 1021 | iret = fremovexattr(fd, eaname, 0); 1022 | if (iret != 0) { 1023 | logdump(); 1024 | prterr("ea_dowrite: removexattr"); 1025 | failure(151); 1026 | } 1027 | } 1028 | iret = fsetxattr(fd, eaname, good_buf, size, 0, 0); 1029 | ea_lastwrite = size; 1030 | if (iret != 0) { 1031 | logdump(); 1032 | prterr("ea_dowrite: setxattr"); 1033 | failure(151); 1034 | } 1035 | } 1036 | } 1037 | 1038 | 1039 | void 1040 | domapwrite(unsigned offset, unsigned size) 1041 | { 1042 | unsigned pg_offset; 1043 | unsigned map_size; 1044 | char *p; 1045 | int logent; 1046 | 1047 | offset -= offset % writebdy; 1048 | if (size == 0) { 1049 | if (debug && testcalls > simulatedopcount) 1050 | { 1051 | prt("skipping zero size write\n"); 1052 | } 1053 | log4(OP_SKIPPED, OP_MAPWRITE, offset, size); 1054 | return; 1055 | } 1056 | 1057 | if (file_size < offset + size) { 1058 | if (file_size < offset) 1059 | memset(good_buf + file_size, '\0', offset - file_size); 1060 | if (lite) { 1061 | logdump(); 1062 | mwarn("WARNING: Lite file size bug in fsx!"); 1063 | failure(200); 1064 | } 1065 | if (SHOWLOGENTRY(offset, offset + size)) 1066 | { 1067 | prt("extend file size from 0x%x (%d) to 0x%x (%d)\n", (int)file_size, (int)file_size, offset+size, offset+size); 1068 | } 1069 | dotruncate(offset + size); 1070 | if (closeopen) 1071 | docloseopen(); 1072 | if (simulatedopcount > 0 && testcalls == simulatedopcount) 1073 | writefileimage(); 1074 | testcalls++; 1075 | } 1076 | gendata(good_buf, offset, size); 1077 | 1078 | logent = log4(OP_MAPWRITE, offset, size, 0); 1079 | 1080 | if (SHOWLOGENTRY(offset, offset + size)) 1081 | { 1082 | logentrydump(logent, logcount); 1083 | } 1084 | 1085 | if (testcalls <= simulatedopcount) 1086 | return; 1087 | 1088 | pg_offset = offset & page_mask; 1089 | map_size = pg_offset + size; 1090 | 1091 | if (interactive) { 1092 | printf("Hit return when ready..."); 1093 | getchar(); 1094 | } 1095 | 1096 | if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE, 1097 | MAP_FILE | MAP_SHARED, fd, 1098 | (off_t)(offset - pg_offset))) == (char *)-1) { 1099 | logdump(); 1100 | prterr("domapwrite: mmap"); 1101 | failure(202); 1102 | } 1103 | memcpy(p + pg_offset, good_buf + offset, size); 1104 | if (msync(p, map_size, 0) != 0) { 1105 | logdump(); 1106 | prterr("domapwrite: msync"); 1107 | failure(203); 1108 | } 1109 | 1110 | check_eofpage("Write", offset, p, size); 1111 | 1112 | if (munmap(p, map_size) != 0) { 1113 | logdump(); 1114 | prterr("domapwrite: munmap"); 1115 | failure(204); 1116 | } 1117 | } 1118 | 1119 | 1120 | void 1121 | dotruncate(unsigned size) 1122 | { 1123 | off_t oldsize, start, end; 1124 | int logent; 1125 | 1126 | oldsize = file_size; 1127 | if (oldsize < size) { 1128 | start = oldsize; 1129 | end = size; 1130 | } else { 1131 | start = size; 1132 | end = oldsize; 1133 | } 1134 | 1135 | size -= size % truncbdy; 1136 | if (size > biggest) { 1137 | biggest = size; 1138 | if (!quiet && testcalls > simulatedopcount) 1139 | { 1140 | prt("truncating to largest ever: 0x%x\n", size); 1141 | } 1142 | } 1143 | 1144 | logent = log4(OP_TRUNCATE, size, (unsigned)file_size, 0); 1145 | 1146 | if (size > file_size) 1147 | memset(good_buf + file_size, '\0', size - file_size); 1148 | file_size = size; 1149 | 1150 | if (SHOWLOGENTRY(start, end)) 1151 | { 1152 | logentrydump(logent, logcount); 1153 | } 1154 | 1155 | if (testcalls <= simulatedopcount) 1156 | return; 1157 | 1158 | if (interactive) { 1159 | printf("Hit return when ready..."); 1160 | getchar(); 1161 | } 1162 | 1163 | if (usehole || size <= oldsize) { // shrink the file or we want a sparse file 1164 | if (ftruncate(fd, (off_t)size) == -1) { 1165 | logdump(); 1166 | prt("ftruncate1: %x\n", size); 1167 | prterr("dotruncate: ftruncate"); 1168 | failure(160); 1169 | } 1170 | } else { // write zeros instead of creating a sparse file to extend the file 1171 | off_t ret; 1172 | unsigned iret; 1173 | ret = lseek(fd, (off_t)oldsize, SEEK_SET); 1174 | if (ret == (off_t)-1) { 1175 | logdump(); 1176 | prterr("dowrite: lseek"); 1177 | failure(150); 1178 | } 1179 | iret = write(fd, good_buf + oldsize, size - oldsize); 1180 | if (iret != size - oldsize) { 1181 | logdump(); 1182 | if (iret == -1) 1183 | prterr("dotruncate: write"); 1184 | else 1185 | { 1186 | prt("short write: 0x%x bytes instead of 0x%x\n", 1187 | iret, size); 1188 | } 1189 | failure(151); 1190 | } 1191 | } 1192 | } 1193 | 1194 | 1195 | void 1196 | writefileimage(void) 1197 | { 1198 | ssize_t iret; 1199 | 1200 | if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 1201 | logdump(); 1202 | prterr("writefileimage: lseek"); 1203 | failure(171); 1204 | } 1205 | iret = write(fd, good_buf, file_size); 1206 | if ((off_t)iret != file_size) { 1207 | logdump(); 1208 | if (iret == -1) 1209 | prterr("writefileimage: write"); 1210 | else 1211 | { 1212 | prt("short write: 0x%x bytes instead of 0x%llx\n", 1213 | iret, (unsigned long long)file_size); 1214 | } 1215 | failure(172); 1216 | } 1217 | if (usehole) { 1218 | if (lite ? 0 : ftruncate(fd, file_size) == -1) { 1219 | logdump(); 1220 | prt("ftruncate2: %llx\n", (unsigned long long)file_size); 1221 | prterr("writefileimage: ftruncate"); 1222 | failure(173); 1223 | } 1224 | } 1225 | } 1226 | 1227 | 1228 | void 1229 | docloseopen(void) 1230 | { 1231 | if (testcalls <= simulatedopcount) 1232 | return; 1233 | 1234 | if (debug) 1235 | { 1236 | prt("%lu close/open\n", testcalls); 1237 | } 1238 | if (sync_before_close && fsync(fd)) { 1239 | logdump(); 1240 | prterr("docloseopen: fsync"); 1241 | failure(182); 1242 | } 1243 | if (close(fd)) { 1244 | logdump(); 1245 | prterr("docloseopen: close"); 1246 | failure(180); 1247 | } 1248 | fd = open(fname, O_RDWR, 0); 1249 | if (fd < 0) { 1250 | logdump(); 1251 | prterr("docloseopen: open"); 1252 | failure(181); 1253 | } 1254 | } 1255 | 1256 | 1257 | void 1258 | test(void) 1259 | { 1260 | unsigned long offset; 1261 | unsigned long size = maxoplen; 1262 | unsigned long rv = random(); 1263 | unsigned long op = rv % (3 + !lite + mapped_writes); 1264 | 1265 | /* turn off the map read if necessary */ 1266 | 1267 | if (op == 2 && !mapped_reads) 1268 | op = 0; 1269 | 1270 | if (simulatedopcount > 0 && testcalls == simulatedopcount) 1271 | writefileimage(); 1272 | 1273 | testcalls++; 1274 | 1275 | if (closeprob) 1276 | closeopen = (rv >> 3) < (1 << 28) / closeprob; 1277 | 1278 | if (debugstart > 0 && testcalls >= debugstart) 1279 | debug = 1; 1280 | 1281 | if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0) 1282 | { 1283 | prt("%lu...\n", testcalls); 1284 | } 1285 | 1286 | /* 1287 | * READ: op = 0 1288 | * WRITE: op = 1 1289 | * MAPREAD: op = 2 1290 | * TRUNCATE: op = 3 1291 | * MAPWRITE: op = 3 or 4 1292 | */ 1293 | if (lite ? 0 : op == 3 && style == 0 && ea == 0) /* vanilla truncate? */ 1294 | dotruncate(((random() + datasize - 1) & ~(datasize - 1)) % maxfilelen); 1295 | else { 1296 | if (randomoplen) 1297 | size = random() % (maxoplen+1); 1298 | size = (size + datasize - 1) & ~(datasize - 1); // round up to multiple of datasize 1299 | if (lite ? 0 : op == 3 && ea == 0) 1300 | dotruncate(size); 1301 | else { 1302 | offset = random(); 1303 | offset &= ~(datasize - 1); // trunc to multiple of datasize 1304 | if (op == 1 || op == (lite ? 3 : 4)) { 1305 | offset %= maxfilelen; 1306 | if (ea != 0) 1307 | offset = 0; 1308 | if (offset + size > maxfilelen) 1309 | size = maxfilelen - offset; 1310 | if (op != 1) 1311 | domapwrite(offset, size); 1312 | else 1313 | dowrite(offset, size); 1314 | } else { 1315 | if (ea || !file_size) { 1316 | offset = 0; 1317 | } else { 1318 | offset %= file_size; 1319 | offset &= ~(datasize - 1); 1320 | } 1321 | if (offset + size > file_size) { 1322 | size = file_size - offset; 1323 | size &= ~(datasize - 1); // trunc to multiple of datasize 1324 | } 1325 | if (op != 0) 1326 | domapread(offset, size); 1327 | else 1328 | doread(offset, size); 1329 | } 1330 | } 1331 | } 1332 | if (sizechecks && testcalls > simulatedopcount) 1333 | check_size(); 1334 | if (closeopen) 1335 | docloseopen(); 1336 | } 1337 | 1338 | 1339 | void 1340 | cleanup(sig) 1341 | int sig; 1342 | { 1343 | if (sig) 1344 | { 1345 | prt("signal %d\n", sig); 1346 | } 1347 | prt("testcalls = %lu\n", testcalls); 1348 | #ifdef XILOG 1349 | XILogEndTestCase(xilogref, kXILogTestPassOnErrorLevel); 1350 | XILogCloseLog(xilogref); 1351 | #endif 1352 | exit(0); 1353 | } 1354 | 1355 | 1356 | void 1357 | usage(void) 1358 | { 1359 | fprintf(stdout, "usage: %s", 1360 | "fsx [-ehinqvxCLMORW] [-b opnum] [-c Prob] [-d duration] [-f forkname] [-l logpath] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-F flen] [-G logsize] [-I opnum] [-N numops] [-P dirpath] [-S seed] [-T datasize] fname [xxxxx]\n\ 1361 | -b opnum: beginning operation number (default 1)\n\ 1362 | -c P: 1 in P chance of file close+open at each op (default infinity)\n\ 1363 | -d duration: number of hours for the tool to run\n\ 1364 | -e: tests using an extended attribute rather than a file\n\ 1365 | -f forkname: test the named fork of fname\n\ 1366 | -g logpath: path for .fsxlog file\n\ 1367 | -h: write 0s instead of creating holes (i.e. sparse file)\n\ 1368 | -i: interactive mode, hit return before performing the current operation\n\ 1369 | -l logpath: path for XILog file\n\ 1370 | -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\ 1371 | -n: no verifications of file size\n\ 1372 | -o oplen: the upper bound on operation size (default 65536)\n\ 1373 | -p progressinterval: debug output at specified operation interval\n\ 1374 | -q: quieter operation\n\ 1375 | -r readbdy: 4096 would make reads page aligned (default 1)\n\ 1376 | -s style: 1 gives smaller truncates (default 0)\n\ 1377 | -t truncbdy: 4096 would make truncates page aligned (default 1)\n\ 1378 | -v: debug output for all operations\n\ 1379 | -w writebdy: 4096 would make writes page aligned (default 1)\n\ 1380 | -x: write output in XML (XILOG)\n\ 1381 | -y: call fsync before closing the file\n\ 1382 | -C mix cached and un-cached read/write ops\n\ 1383 | -D startingop: debug output starting at specified operation\n\ 1384 | -G logsize: #entries in oplog (default 1024)\n\ 1385 | -F flen: the upper bound on file size (default 262144)\n\ 1386 | -I: start interactive mode since operation opnum\n\ 1387 | -L: fsxLite - no file creations & no file size changes\n\ 1388 | -M: slow motion mode, wait 1 second before each op\n\ 1389 | -N numops: total # operations to do (default infinity)\n\ 1390 | -O: use oplen (see -o flag) for every op (default random)\n\ 1391 | -P dirpath: save .fsxlog and .fsxgood files in dirpath (default ./)\n\ 1392 | -R: mapped read operations DISabled\n\ 1393 | -S seed: for random # generator (default 0, gets timestamp+pid)\n\ 1394 | -T datasize: size of atomic data elements written to file [1,2,4] (default 4)\n\ 1395 | -W: mapped write operations DISabled\n\ 1396 | fname: this filename is REQUIRED (no default)\n\ 1397 | xxxxx: will be overwritten with operation #s, viewable in \"ps\"\n"); 1398 | exit(90); 1399 | } 1400 | 1401 | 1402 | int 1403 | getnum(char *s, char **e) 1404 | { 1405 | int ret = -1; 1406 | 1407 | *e = (char *) 0; 1408 | ret = strtol(s, e, 0); 1409 | if (*e) 1410 | switch (**e) { 1411 | case 'b': 1412 | case 'B': 1413 | ret *= 512; 1414 | *e = *e + 1; 1415 | break; 1416 | case 'k': 1417 | case 'K': 1418 | ret *= 1024; 1419 | *e = *e + 1; 1420 | break; 1421 | case 'm': 1422 | case 'M': 1423 | ret *= 1024*1024; 1424 | *e = *e + 1; 1425 | break; 1426 | case 'w': 1427 | case 'W': 1428 | ret *= 4; 1429 | *e = *e + 1; 1430 | break; 1431 | } 1432 | return (ret); 1433 | } 1434 | 1435 | 1436 | int 1437 | main(int argc, char **argv) 1438 | { 1439 | int ch; 1440 | char *endp, **oargv = argv; 1441 | char goodfile[MAXPATHLEN]; bzero(goodfile, MAXPATHLEN); 1442 | char logfile[MAXPATHLEN]; bzero(logfile, MAXPATHLEN); 1443 | char forkname[MAXPATHLEN]; bzero(forkname, MAXPATHLEN); 1444 | char* logpath = NULL; 1445 | eaname = argv[0]; 1446 | int xml = 0; 1447 | 1448 | goodfile[0] = 0; 1449 | logfile[0] = 0; 1450 | forkname[0] = 0; 1451 | 1452 | page_size = getpagesize(); 1453 | page_mask = page_size - 1; 1454 | 1455 | setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */ 1456 | 1457 | while ((ch = getopt_long(argc, argv, "b:c:d:ef:g:hil:m:no:p:qr:s:t:vw:xCD:F:G:I:LMN:OP:RS:T:W", NULL, NULL)) 1458 | != EOF) 1459 | switch (ch) { 1460 | case 'b': 1461 | simulatedopcount = getnum(optarg, &endp); 1462 | if (!quiet) 1463 | fprintf(stdout, "Will begin at operation %ld\n", 1464 | simulatedopcount); 1465 | if (simulatedopcount == 0) 1466 | usage(); 1467 | simulatedopcount -= 1; 1468 | break; 1469 | case 'c': 1470 | closeprob = getnum(optarg, &endp); 1471 | if (!quiet) 1472 | fprintf(stdout, "Chance of close/open is 1 in %d\n", closeprob); 1473 | if (closeprob <= 0) 1474 | usage(); 1475 | break; 1476 | case 'd': 1477 | duration = parsetime(optarg); 1478 | if(duration <= 0) 1479 | duration = 0; 1480 | printf("Running for %ld seconds\n", duration); 1481 | break; 1482 | case 'e': 1483 | ea = 1; 1484 | mapped_writes = 0; 1485 | mapped_reads = 0; 1486 | sizechecks = 0; 1487 | closeopen = 0; 1488 | maxoplen = 3802; 1489 | maxoplen &= ~(datasize - 1); // round down to multiple of datasize 1490 | maxfilelen = 3802; 1491 | maxfilelen &= ~(datasize - 1); // round down to multiple of datasize 1492 | printf("Writing into extended attribute\n"); 1493 | break; 1494 | case 'f': 1495 | if (strlcpy(forkname, optarg, sizeof(forkname)) >= sizeof(forkname)) 1496 | usage(); 1497 | break; 1498 | case 'g': 1499 | if (strlcpy(logfile, optarg, sizeof(logfile)) >= sizeof(logfile)) 1500 | usage(); 1501 | if (strlcat(logfile, "/", sizeof(logfile)) >= sizeof(logfile)) 1502 | usage(); 1503 | break; 1504 | case 'h': 1505 | usehole = 0; 1506 | break; 1507 | case 'i': 1508 | interactive = 1; 1509 | break; 1510 | case 'l': 1511 | logpath = optarg; 1512 | break; 1513 | case 'm': 1514 | monitorstart = getnum(optarg, &endp); 1515 | if (monitorstart < 0) 1516 | usage(); 1517 | if (!endp || *endp++ != ':') 1518 | usage(); 1519 | monitorend = getnum(endp, &endp); 1520 | if (monitorend < 0) 1521 | usage(); 1522 | if (monitorend == 0) 1523 | monitorend = -1; /* aka infinity */ 1524 | debug = 1; 1525 | case 'n': 1526 | sizechecks = 0; 1527 | break; 1528 | case 'o': 1529 | maxoplen = getnum(optarg, &endp); 1530 | if (maxoplen <= 0) 1531 | usage(); 1532 | break; 1533 | case 'p': 1534 | progressinterval = getnum(optarg, &endp); 1535 | if (progressinterval < 0) 1536 | usage(); 1537 | break; 1538 | case 'q': 1539 | quiet = 1; 1540 | break; 1541 | case 'r': 1542 | readbdy = getnum(optarg, &endp); 1543 | if (readbdy <= 0) 1544 | usage(); 1545 | break; 1546 | case 's': 1547 | style = getnum(optarg, &endp); 1548 | if (style < 0 || style > 1) 1549 | usage(); 1550 | break; 1551 | case 't': 1552 | truncbdy = getnum(optarg, &endp); 1553 | if (truncbdy <= 0) 1554 | usage(); 1555 | break; 1556 | case 'v': 1557 | debug = 1; 1558 | break; 1559 | case 'w': 1560 | writebdy = getnum(optarg, &endp); 1561 | if (writebdy <= 0) 1562 | usage(); 1563 | break; 1564 | case 'x': 1565 | xml = 1; 1566 | break; 1567 | case 'y': 1568 | sync_before_close = 1; 1569 | break; 1570 | case 'C': 1571 | gUseRandomNoCache = 1; 1572 | break; 1573 | case 'D': 1574 | debugstart = getnum(optarg, &endp); 1575 | if (debugstart < 1) 1576 | usage(); 1577 | break; 1578 | case 'F': 1579 | maxfilelen = getnum(optarg, &endp); 1580 | if (maxfilelen <= 0) 1581 | usage(); 1582 | break; 1583 | case 'I': 1584 | interactiveSince = getnum(optarg, &endp); 1585 | break; 1586 | case 'G': 1587 | logsize = getnum(optarg, &endp); 1588 | if (logsize < 0) 1589 | usage(); 1590 | break; 1591 | case 'L': 1592 | lite = 1; 1593 | break; 1594 | case 'M': 1595 | slow_motion = 1; 1596 | break; 1597 | case 'N': 1598 | numops = getnum(optarg, &endp); 1599 | if (numops < 0) 1600 | usage(); 1601 | break; 1602 | case 'O': 1603 | randomoplen = 0; 1604 | break; 1605 | case 'P': 1606 | if (strlcpy(goodfile, optarg, sizeof(goodfile)) >= sizeof(goodfile)) 1607 | usage(); 1608 | if (strlcat(goodfile, "/", sizeof(goodfile)) >= sizeof(goodfile)) 1609 | usage(); 1610 | if (strlcpy(logfile, optarg, sizeof(logfile)) >= sizeof(logfile)) 1611 | usage(); 1612 | if (strlcat(logfile, "/", sizeof(logfile)) >= sizeof(logfile)) 1613 | usage(); 1614 | break; 1615 | case 'R': 1616 | mapped_reads = 0; 1617 | break; 1618 | case 'S': 1619 | seed = getnum(optarg, &endp); 1620 | if (seed < 0) 1621 | usage(); 1622 | break; 1623 | case 'T': 1624 | datasize = getnum(optarg, &endp); 1625 | if ((datasize != 1) && (datasize != 2) && (datasize != 4)) 1626 | usage(); 1627 | break; 1628 | case 'W': 1629 | mapped_writes = 0; 1630 | if (!quiet) 1631 | fprintf(stdout, "mapped writes DISABLED\n"); 1632 | break; 1633 | 1634 | default: 1635 | usage(); 1636 | /* NOTREACHED */ 1637 | } 1638 | 1639 | /* for (i = optind; i < argc; i++) 1640 | fname = argv[i]; */ 1641 | 1642 | fname[0] = 0; 1643 | argc -= optind; 1644 | argv += optind; 1645 | if (argc != 1 && argc != 2) 1646 | usage(); 1647 | if (strlcpy(fname, argv[0], sizeof(fname)) >= sizeof(fname)) 1648 | usage(); 1649 | 1650 | if (argc == 2) { 1651 | for (msgbuf = argv[1]; *msgbuf; msgbuf++) 1652 | *msgbuf = ' '; 1653 | msgbuflen = msgbuf - argv[1]; 1654 | msgbuf = argv[1]; 1655 | } 1656 | 1657 | if (fname[0]) { 1658 | if (!quiet) { 1659 | printf("Using file %s\n", fname); 1660 | } 1661 | } else { 1662 | usage(); 1663 | } 1664 | 1665 | modsize = (datasize == 4) ? 0 : (datasize == 2) ? 1<<16 : 1<<8; 1666 | maxfilelen = (maxfilelen + datasize - 1) & ~(datasize - 1); // round up to multiple of datasize 1667 | maxoplen = (maxoplen + datasize - 1) & ~(datasize - 1); // round up to multiple of datasize 1668 | 1669 | signal(SIGHUP, cleanup); 1670 | signal(SIGINT, cleanup); 1671 | signal(SIGPIPE, cleanup); 1672 | signal(SIGALRM, cleanup); 1673 | signal(SIGTERM, cleanup); 1674 | signal(SIGXCPU, cleanup); 1675 | signal(SIGXFSZ, cleanup); 1676 | signal(SIGVTALRM, cleanup); 1677 | signal(SIGUSR1, cleanup); 1678 | signal(SIGUSR2, cleanup); 1679 | 1680 | // Open the log for writing 1681 | #ifdef XILOG 1682 | xilogref = XILogOpenLogExtended(logpath, "fsx", "com.apple.xintegration", NULL, xml, 0, NULL,"ResultOwner","com.apple.fsx",NULL); 1683 | if(xilogref == NULL) { 1684 | fprintf(stderr, "Couldn't create log for path: %s\n", logpath); 1685 | exit(-1); 1686 | } 1687 | 1688 | XILogBeginTestCase(xilogref,"Begin Tests", "Read/Write/MapRead/Truncate/MapWrite Tests"); 1689 | #endif 1690 | 1691 | /* 1692 | * create goodfile and logfile names from fname before potentially adding 1693 | * a fork name to fname 1694 | */ 1695 | if (strlcat(goodfile, fname, sizeof(goodfile)) >= sizeof(goodfile)) 1696 | usage(); 1697 | if (strlcat(goodfile, ".fsxgood", sizeof(goodfile)) >= sizeof(goodfile)) 1698 | usage(); 1699 | if (strlcat(logfile, fname, sizeof(logfile)) >= sizeof(logfile)) 1700 | usage(); 1701 | if (strlcat(logfile, ".fsxlog", sizeof(logfile)) >= sizeof(logfile)) 1702 | usage(); 1703 | /* 1704 | * add forkname to fname if forkname was supplied 1705 | */ 1706 | if (forkname[0] != 0) { 1707 | /* make sure fname exists if working with a named fork */ 1708 | fd = open(fname, O_RDWR|(lite ? 0 : O_CREAT), 0666); 1709 | if (fd < 0) { 1710 | prterr(fname); 1711 | exit(91); 1712 | } else { 1713 | /* don't need it open */ 1714 | close(fd); 1715 | } 1716 | if (strlcat(fname, _PATH_FORKSPECIFIER, sizeof(fname)) >= sizeof(fname)) 1717 | usage(); 1718 | if (strlcat(fname, forkname, sizeof(fname)) >= sizeof(fname)) 1719 | usage(); 1720 | } 1721 | 1722 | oplog = (struct log_entry *) malloc(logsize * sizeof(struct log_entry)); 1723 | if (!oplog) { 1724 | prt("unable to allocate %d entry log", logsize); 1725 | exit(99); 1726 | } 1727 | 1728 | if (seed == 0) 1729 | seed = (time(NULL) + getpid()) | 1; 1730 | initstate(seed, state, 256); 1731 | setstate(state); 1732 | fd = open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666); 1733 | if (fd < 0) { 1734 | prterr(fname); 1735 | exit(91); 1736 | } 1737 | fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666); 1738 | if (fsxgoodfd < 0) { 1739 | prterr(goodfile); 1740 | exit(92); 1741 | } 1742 | fsxlogf = fopen(logfile, "w"); 1743 | if (fsxlogf == NULL) { 1744 | prterr(logfile); 1745 | exit(93); 1746 | } 1747 | if (!quiet) { 1748 | prt("command line:"); 1749 | while (*oargv) 1750 | prt(" %s", *oargv++); 1751 | prt("\n"); 1752 | } 1753 | prt("Seed set to %d\n", seed); 1754 | if (lite) { 1755 | off_t ret; 1756 | file_size = maxfilelen = lseek(fd, (off_t)0, SEEK_END); 1757 | if (file_size == (off_t)-1) { 1758 | prterr(fname); 1759 | mwarn("WARNING: main: lseek eof"); 1760 | exit(94); 1761 | } 1762 | ret = lseek(fd, (off_t)0, SEEK_SET); 1763 | if (ret == (off_t)-1) { 1764 | prterr(fname); 1765 | mwarn("WARNING: main: lseek 0"); 1766 | exit(95); 1767 | } 1768 | maxfilelen &= ~(datasize - 1); // round down to multiple of datasize 1769 | } 1770 | good_buf = (char *) malloc(maxfilelen); 1771 | memset(good_buf, '\0', maxfilelen); 1772 | temp_buf = (char *) malloc(maxoplen); 1773 | memset(temp_buf, '\0', maxoplen); 1774 | if (lite) { /* zero entire existing file */ 1775 | ssize_t written; 1776 | 1777 | written = write(fd, good_buf, (size_t)maxfilelen); 1778 | if (written != maxfilelen) { 1779 | if (written == -1) { 1780 | prterr(fname); 1781 | mwarn("WARNING: main: error on write"); 1782 | } else 1783 | mwarn("WARNING: main: short write, 0x%x bytes instead of 0x%x\n", 1784 | (unsigned)written, maxfilelen); 1785 | exit(98); 1786 | } 1787 | } else 1788 | if (!ea) check_trunc_hack(); 1789 | 1790 | #ifdef XILOG 1791 | XIPing(0); 1792 | #endif /* XILOG */ 1793 | 1794 | if(duration > 0) // time based cycling 1795 | { 1796 | time_t currentTime = time(NULL); 1797 | struct tm* tmPtr = localtime(¤tTime); 1798 | tmPtr->tm_sec += duration; 1799 | time_t stopTime = mktime(tmPtr); 1800 | while(time(NULL) < stopTime) { 1801 | if (slow_motion) 1802 | sleep(2); /* wait for 1 second */ 1803 | test(); 1804 | #ifdef XILOG 1805 | if((testcalls % pinginterval) == 0) 1806 | XIPing(testcalls); 1807 | #endif 1808 | } 1809 | } 1810 | else 1811 | { 1812 | while (numops == -1 || numops--) { 1813 | if (interactiveSince == testcalls) { 1814 | interactive = 1; 1815 | debug = 1; 1816 | quiet = 0; 1817 | } 1818 | if (slow_motion) 1819 | sleep(2); /* wait for 1 second */ 1820 | test(); 1821 | #ifdef XILOG 1822 | if((testcalls % pinginterval) == 0) 1823 | XIPing(testcalls); 1824 | #endif 1825 | } 1826 | } 1827 | 1828 | if (sync_before_close && fsync(fd)) { 1829 | logdump(); 1830 | prterr("docloseopen: fsync"); 1831 | failure(182); 1832 | } 1833 | if (close(fd)) { 1834 | logdump(); 1835 | prterr("close"); 1836 | failure(99); 1837 | } 1838 | if (!quiet) 1839 | prt("All operations - %lu - completed A-OK!\n", testcalls); 1840 | 1841 | #ifdef XILOG 1842 | XILogEndTestCase(xilogref, kXILogTestPassOnErrorLevel); 1843 | XILogCloseLog(xilogref); 1844 | #endif 1845 | 1846 | exit(0); 1847 | return 0; 1848 | } 1849 | 1850 | --------------------------------------------------------------------------------