From source_changes at macosforge.org Fri Feb 26 08:28:46 2010 From: source_changes at macosforge.org (source_changes at macosforge.org) Date: Fri, 26 Feb 2010 08:28:46 -0800 (PST) Subject: [Fstools-changes] [5] trunk/src Message-ID: <20100226162847.6F24441C3FF7@beta.macosforge.org> Revision: 5 http://trac.macosforge.org/projects/fstools/changeset/5 Author: jpeach at apple.com Date: 2010-02-26 08:28:43 -0800 (Fri, 26 Feb 2010) Log Message: ----------- Add latest fstorture snapshot. Added Paths: ----------- trunk/src/fstorture/ trunk/src/fstorture/CHANGELOG trunk/src/fstorture/LICENSE trunk/src/fstorture/Makefile trunk/src/fstorture/README trunk/src/fstorture/basictypes.h trunk/src/fstorture/cmpdir.c trunk/src/fstorture/cmpdir.h trunk/src/fstorture/cmpfile.c trunk/src/fstorture/cmpfile.h trunk/src/fstorture/fileemu.c trunk/src/fstorture/fileemu.h trunk/src/fstorture/fstorture.c trunk/src/fstorture/stdheaders.h trunk/src/fstorture/testPerformance trunk/src/fstorture/util.h Added: trunk/src/fstorture/CHANGELOG =================================================================== --- trunk/src/fstorture/CHANGELOG (rev 0) +++ trunk/src/fstorture/CHANGELOG 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,21 @@ +2.1 [01/16/06] +* George Colley: Added "windows_volume"/"windows98" & "no_unlink_open_files" flags +* Log file handling bug fixes + +2.0 [11/30/05] +Added XILog functionality; cleaned up error handling +Added lots of options +Removed "Kill this PID on error" argument (but we're still backwards-compatible) +Added XIPing + +1.7 [11/17/05] +Check volume capabilities for soft/hard links and ACLs + +1.6 [11/07/05] +soft/hard links added + +1.5 [10/27/05] +Unlinked files support + +1.4 [10/13/05] +ACL support added Added: trunk/src/fstorture/LICENSE =================================================================== --- trunk/src/fstorture/LICENSE (rev 0) +++ trunk/src/fstorture/LICENSE 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. \ No newline at end of file Added: trunk/src/fstorture/Makefile =================================================================== --- trunk/src/fstorture/Makefile (rev 0) +++ trunk/src/fstorture/Makefile 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,72 @@ +# Name: Makefile +# Project: CIFS Client Automatic Test +# Author: Christian Starkjohann +# Creation Date: 1998-04-20 +# Tabsize: 4 +# Copyright: (c) 1998 by Christian Starkjohann. This program is distributed +# under the terms of the Gnu General Public License (GPL). +# +# Copyright ? 2009 Apple Inc. +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only. This +# program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details. A copy of the GNU General Public License +# version 2 is included along with this program. +# + +# +# The testsoftware is currently not ported to all platforms Sharity +# runs on. It is a naive quick hack to find bugs quickly. Please modify +# the CFLAGS and LIBS lines appropriately for your platform. +# + +# USE XILOG +#CFLAGS= -Wall -g -O0 -DXILOG -F/AppleInternal/Library/Frameworks +ARCHES= -arch ppc -arch i386 -arch x86_64 +CFLAGS= $(ARCHES) -Wall -O3 -DXILOG -F/AppleInternal/Library/Frameworks +LDFLAGS= -framework XILog + +# DON'T USE XILOG +#CFLAGS= -Wall -O3 -fomit-frame-pointer + +# For Linux add: +# LIBS = -lm + +OBJ = fileemu.o cmpfile.o cmpdir.o fstorture.o + +XNAME = fstorture + +all: $(XNAME) + +Project = $(XNAME) + +#include $(MAKEFILEPATH)/CoreOS/ReleaseControl/Common.make + + +.c.o: + $(CC) $(CFLAGS) -c $*.c -o $*.o + +clean:: + rm -f $(OBJ) $(XNAME) + +$(XNAME):$(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) + + + + +# More stuff + + +XintInstall = $(DSTROOT)/$(HOME)/TestSuite/Tools/$(XNAME) + +install:: $(XintInstall)/$(XNAME) + +$(XintInstall)/$(XNAME):$(XNAME) + $(CP) $(SRCROOT)/$(XNAME) $(SYMROOT) + $(STRIP) $(SRCROOT)/$(XNAME) + $(MKDIR) $(XintInstall) + $(MV) $(SRCROOT)/$(XNAME) $(XintInstall) + Added: trunk/src/fstorture/README =================================================================== --- trunk/src/fstorture/README (rev 0) +++ trunk/src/fstorture/README 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,191 @@ +This is the README file for fstorture, a test program written to find bugs +in Sharity. This test program performs random operations on the filesystem +and verifies the results. + +WARNING: This program may crash your machine! See section "Known Problems" +for details! + + +What is fstorture? +================== +fstorture performs the following filesystem operations in a reasonable (but +still random) order with reasonable parameters and verifies the results: + - creat() + - mkdir() + - open() + - close() + - read() + - write() + - truncate() + - ftruncate() + - chmod() + - stat() + - rename() + - unlink() +This is done in parallel from a given number of processes. +fstorture is not user friendly and not distributed in binary versions, +because it is intended for developers. If no problems are found, nothing +will be printed. If you want to know the details of the test procedure, +please look into the source code. + +In addition to fstorture, this package contains the shell script +"testPerformance". This script performs some trivial performance tests on a +given directory (which is assumed to be located on a remote server). It +takes the path to the directory as a parameter and prints out the +performance statistics. + + +Commandline parameters +====================== +The usage of fstorture is: + + fstorture [] + +The and are the directories where the +filesystem test will be performed. There are two root directories +to better test cross-directory renames. The root directories must +exist and must be empty before fstorture is started. is the number of parallel running processes that will +be used for the test. Each process operates on only one file or +subdirectory at a time. You should choose this number appropriate +for your system. Higher numbers mean more testing but can put a +heavy load on the operating system. Good numbers are in the range +of 5 to 100, depending on the load your kernel can take. +are options that modify the way certain tests are performed or that +switch off certain tests. It may be necessary to use these options +to compensate for operating system bugs, different ideas of how +things should work or different semantics. + +Available options: +------------------ +* fsync_before_ftruncate + It seems as if the truncate functionality were implemented totally + independent of the rest of the filesystem functions on some + operating systems. For instance, it may happen that a truncate + operation "overtakes" a write operation. The sequence + write(offset=1000, length=1000) + truncate(500) + may in fact be executed as + truncate(500) + write(offset=1000, length=1000) + which results in a completely different file, of course. To work + around this operating system bug, you can define + "fsync_before_ftruncate". If this parameter is passed to fstorture, + it executes an fsync() before every truncate() or ftruncate(). + +* no_rename_open_files + Unix semantics allow to rename files while they are still open. + Reads and writes will go to the same file even after renaming. + Older versions of Sharity do not provide this behaviour and reads + and writes to the old file will fail. If you test an older version + of Sharity, add this option. + +* no_test_dirs + fstorture also creates, renames and destroys directories during + the test. The directories are populated with open files, even during + renames. This is a hard test for the filing system and there are + operating systems that introduce structural errors on the hard + drive if this test is performed (on the hard drive, of course). If + you don't want to perform the directory test, add this option. + + +Setting up a Test +================= +Before you start testing, you should be aware of several facts. You are +testing the entire filesystem between the application and the disk. In the +case of Sharity this consists of the system call library, the nfs client +in the kernel, the Sharity daemon, the CIFS/SMB-server software and the +filesystem on the kernel. If an error occures, it may be in any of these +components. + +Before you start testing Sharity, please make sure the other +components work appropriately. First you should try fstorture on the local +filesystem. There you can verify whether your OS has bugs. If you find one, +you can disable the specific test or aspect of the test. + +If that works, try it on an NFS mounted directory. This tests the local +filesystem code, the NFS client in the kernel and the NFS server. If no +problems occure, you can switch over to Sharity. Always start with a low +number of parallel processes until you become more confident. + + +Known Problems +============== +Here is a list of known problems in clients, servers and Sharity: + +NEXTSTEP, OPENSTEP/Mach operating system: +----------------------------------------- +Never try fstorture with the directory test enabled on NEXTSTEP! It will +destroy parts of the filesystem structure and you will have to perform +a manual disk check (which resulted in a kernel panic when I did it....). + +The NFS client code is buggy. You will always read incorrect file sizes with +any NFS server. After some minutes or even seconds of test with any NFS +server, the system will freeze. + +Linux operating system: +----------------------- +No known bugs. If you are low on real memory (RAM), the kernel +might get into trouble being inable to get real memory. The system +may freeze in this case. + +Windows NT server: +------------------ +NT does not always give correct file sizes. In fact, the file size is almost +always wrong if the file has been written to recently. NT probably does +writeback caching and returns the size of the file on disk instead of the +logical size determined by the cache. Sharity tries to work around this +problem, but it might fail sometimes. NT does not always send OPLOCK breaks +when it should. This made older versions of Sharity fail on some rename +operations. Newer versions of Sharity don't rely on OPLOCKs for renames, +but the bug might still be a problem if some clients access the same file +concurrently. + +Windows 95 server: +------------------ +The CIFS/SMB server code in Win 95 is, well, very buggy. There are the same +bugs as with Win NT and others related to write protection semantics. +Sharity can not always work around these problems, although it tries +everything that is possible. It is, for instance, impossible to have a file +open for write that is write protected. If this is required from the +Unix side, the file is simply un-writeprotected transparently. The file will +then stat with wrong write protection status, of course. The workaround +for the "wrong filesize" bug also does not work as good as for NT because +Win 95 does not support oplocks. + +Sharity: +-------- +Sharity has two possible options for the file lookup strategy (see the +manual, section "configuration file" for details). One provides real +Unix-like semantics (the "database" option) and the other does not allow +renaming open files (the "pseudoInode" option). If you test Sharity with +the "pseudoInode" option, you should use the options no_rename_open_files +and no_test_dirs. On Solaris you will see errors even with these options due +to a bug in the writeback cache implementation of the Solaris NFS client. + + +Note for Developers +=================== +This program is not supported software, it is also not a reference for +good programming style, but it's a real quick hack. It has limited +complexity and should do it's job quite well. It's not intended to be +easily portable, although it probably is due to the low number of system +calls needed. I have tested it on NEXTSTEP, OPENSTEP/Mach and Linux, others +probably need some porting. fstorture is probably not bug-free, although +I have gone through all of the code several times. + +General Disclaimer +================== +Be prepared for the worst! The sentence "This software may +damage your machine or kill your hamster", usually inserted as default +disclaimer, has to be taken seriously with fstorture! It's built to trigger +problems in the filesystem! For the exact wording of the disclaimer please +consult the GNU General Public License. + + +--- +Contact information: +e-mail: office at obdev.at +www: http://www.obdev.at/ +Author: Christian Starkjohann + Added: trunk/src/fstorture/basictypes.h =================================================================== --- trunk/src/fstorture/basictypes.h (rev 0) +++ trunk/src/fstorture/basictypes.h 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,46 @@ +/* + * Name: basictypes.h + * Project: CIFS Client Automatic Test + * Author: Christian Starkjohann + * Creation Date: 1998-04-20 + * Tabsize: 4 + * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed + * under the terms of the Gnu General Public License (GPL). + * + * Copyright ? 2009 Apple Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only. This + * program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details. A copy of the GNU General Public License + * version 2 is included along with this program. + */ + +#ifndef __BASICTYPES_H_INCLUDED__ +#define __BASICTYPES_H_INCLUDED__ + +/* +General Description: +This header defines an abstraction for the primitive C datatypes. It is not +necessary to have this in the simple test program, but I became used to +the bt* names... +*/ + +#define bti8 char +#define bti16 short +#define bti32 int +#define bti64 long long +#define btu8 unsigned char +#define btu16 unsigned short +#define btu32 unsigned +#define btu64 unsigned long long +#define btoffset btu32 /* offset in files (currently 32 bit) */ +#define btuni unsigned short /* unicode character */ +#define btbool char + +#define btsize int /* for data block sizes */ +#define btint int /* fast integer, min 32 bit long */ + + +#endif /* __BASICTYPES_H_INCLUDED__ */ Added: trunk/src/fstorture/cmpdir.c =================================================================== --- trunk/src/fstorture/cmpdir.c (rev 0) +++ trunk/src/fstorture/cmpdir.c 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,216 @@ +/* + * Name: cmpdir.c + * Project: CIFS Client Automatic Test + * Author: Christian Starkjohann + * Creation Date: 1998-04-28 + * Tabsize: 4 + * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed + * under the terms of the Gnu General Public License (GPL). + * + * Copyright ? 2009 Apple Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only. This + * program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details. A copy of the GNU General Public License + * version 2 is included along with this program. + */ + +#include "stdheaders.h" +#include "cmpdir.h" +#include "util.h" + +extern int trace; +char *acl_perm_dir_n[] = { "list", "add_file", "search", "delete", "add_subdirectory", "delete_child", "readattr", "writeattr", "readextattr", "writeextattr", "readsecurity", "writesecurity", "chown" }; +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 }; +char errstr[1024]; + +/* ------------------------------------------------------------------------- */ + +const int BUF_SIZE=32768; + +static unsigned char *blockWithPattern(int pattern, unsigned char block[BUF_SIZE]) +{ +int i; + srand(pattern); /* make reproducible random sequence */ + for(i=0;i> 8; + return block; +} + +static btbool verifyFile(cmpdir_t *dir, int i) +{ +int fileLen; +unsigned char block[BUF_SIZE], buffer[BUF_SIZE]; + + if(lseek(dir->files[i].fd, 0, SEEK_SET) == -1){ + perr(errno, "error seeking (read) in file %s in dir %s", dir->files[i].name, dir->name); + return 0; + } + fileLen = read(dir->files[i].fd, buffer, BUF_SIZE); + if(fileLen < 0){ + perr(errno, "error reading file %s in dir %s", dir->files[i].name, dir->name); + return 0; + } + if(fileLen != BUF_SIZE){ + perr(errno, "read size error reading file %s in dir %s: %d", dir->files[i].name, dir->name, fileLen); + return 0; + } + blockWithPattern(dir->files[i].filePattern, block); + if(memcmp(block, buffer, BUF_SIZE) != 0){ + perr(errno, "verify error in file %s in dir %s filepattern:%d", dir->files[i].name, dir->name, dir->files[i].filePattern); + return 0; + } + return 1; +} + +/* ------------------------------------------------------------------------- */ + +cmpdir_t *cmpdirNew(char *path) +{ +cmpdir_t *dir = calloc(1, sizeof(cmpdir_t)); + + if(trace) + printf("creating directory %s\n", path); + dir->name = malloc(strlen(path) + 1); + strcpy(dir->name, path); + if(mkdir(path, 0700) != 0){ + perr(errno, "error making dir %s", path); + free(dir->name); + free(dir); + return NULL; + } + return dir; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpdirFree(cmpdir_t *dir) +{ +int i; +btbool rval = 1; +char path[1024]; + + if(trace) + printf("destroying directory %s\n", dir->name); + for(i=0;ifiles[i].name[0] != 0){ + if(!verifyFile(dir, i)) + rval = 0; + if(close(dir->files[i].fd)){ + perr(errno, "error closing file %s in dir %s", dir->files[i].name, dir->name); + rval = 0; + } + sprintf(path, "%s/%s", dir->name, dir->files[i].name); + if(unlink(path)){ + perr(errno, "error unlinking file %s", path); + rval = 0; + } + dir->files[i].fd = 0; + dir->files[i].name[0] = 0; + } + } + if(rmdir(dir->name)){ + perr(errno, "error removing dir %s", dir->name); + rval = 0; + } + if(dir->name != NULL) + free(dir->name); + free(dir); + return rval; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpdirRename(cmpdir_t *dir, char *newPath, int WinVolume) +{ +int ii; + + if(trace) + printf("renaming directory %s to %s\n", dir->name, newPath); + if(rename(dir->name, newPath) < 0) { + /* + * Remember that Windows will not let you rename a directory, if + * there is an open file in the directory. So if we get an EACCES + * error, and there are any open files in the directory just ignore + * the error. + */ + if (WinVolume && (errno == EACCES)) { + for (ii = 0; ii < CMPDIR_MAX_FILES; ii++) + if (dir->files[ii].fd) + return 1; + } + perr(errno, "error renaming dir %s to %s", dir->name, newPath); + return 0; + } + free(dir->name); + dir->name = malloc(strlen(newPath) + 1); + strcpy(dir->name, newPath); + return 1; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpdirChangeFiles(cmpdir_t *dir) +{ +btbool rval = 1; +int i, len; +char path[1024]; +unsigned char block[BUF_SIZE]; + + if(trace) + printf("changing file in %s\n", dir->name); + i = random_int(CMPDIR_MAX_FILES); + if(dir->files[i].name[0]){ /* file exists */ + if(!verifyFile(dir, i)) + rval = 0; + if(close(dir->files[i].fd)){ + perr(errno, "error closing file %s in dir %s", dir->files[i].name, dir->name); + rval = 0; + } + sprintf(path, "%s/%s", dir->name, dir->files[i].name); + if(unlink(path)){ + perr(errno, "error unlinking file %s", path); + rval = 0; + } + dir->files[i].fd = 0; + dir->files[i].name[0] = 0; + }else{ /* file does not exist */ + random_name(dir->files[i].name, 8, i); + dir->files[i].filePattern = random_int(65536); + sprintf(path, "%s/%s", dir->name, dir->files[i].name); + if((dir->files[i].fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0){ + perr(errno, "error creating file %s in dir %s", dir->files[i].name, dir->name); + rval = 0; + dir->files[i].fd = 0; + dir->files[i].name[0] = 0; + }else{ + if((len = write(dir->files[i].fd, blockWithPattern(dir->files[i].filePattern, block), BUF_SIZE)) != BUF_SIZE){ + perr(errno, "error writing file %s, wlen = %d", path, len); + rval = 0; + } + } + } + return rval; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpdirVerifyFiles(cmpdir_t *dir) +{ +btbool rval = 1; +int i; + + if(trace) + printf("verifying all in %s\n", dir->name); + for(i=0;ifiles[i].name[0]){ /* file exists */ + if(!verifyFile(dir, i)) + rval = 0; + } + } + return rval; +} + +/* ------------------------------------------------------------------------- */ Added: trunk/src/fstorture/cmpdir.h =================================================================== --- trunk/src/fstorture/cmpdir.h (rev 0) +++ trunk/src/fstorture/cmpdir.h 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,54 @@ +/* + * Name: cmpdir.h + * Project: CIFS Client Automatic Test + * Author: Christian Starkjohann + * Creation Date: 1998-04-28 + * Tabsize: 4 + * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed + * under the terms of the Gnu General Public License (GPL). + * + * Copyright ? 2009 Apple Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only. This + * program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details. A copy of the GNU General Public License + * version 2 is included along with this program. + */ + +/* ------------------------------------------------------------------------- */ + +#include "basictypes.h" +#include + +//char *acl_perm_dir_n[] = { "list", "add_file", "search", "delete", "add_subdirectory", "delete_child", "readattr", "writeattr", "readextattr", "writeextattr", "readsecurity", "writesecurity", "chown" }; +//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 }; + +//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 }; +//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" }; + + + +#define CMPDIR_MAX_FILES 10 + + + +typedef struct cmpdir{ + char *name; + struct{ + char name[16]; + int fd; + int filePattern; + } files[CMPDIR_MAX_FILES]; +}cmpdir_t; + +/* ------------------------------------------------------------------------- */ + +cmpdir_t *cmpdirNew(char *path); +btbool cmpdirFree(cmpdir_t *dir); +btbool cmpdirRename(cmpdir_t *dir, char *newPath, int WinVolume); +btbool cmpdirChangeFiles(cmpdir_t *dir); +btbool cmpdirVerifyFiles(cmpdir_t *dir); + +/* ------------------------------------------------------------------------- */ Added: trunk/src/fstorture/cmpfile.c =================================================================== --- trunk/src/fstorture/cmpfile.c (rev 0) +++ trunk/src/fstorture/cmpfile.c 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,469 @@ +/* + * Name: cmpfile.c + * Project: CIFS Client Automatic Test + * Author: Christian Starkjohann + * Creation Date: 1998-04-20 + * Tabsize: 4 + * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed + * under the terms of the Gnu General Public License (GPL). + * + * Copyright ? 2009 Apple Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only. This + * program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details. A copy of the GNU General Public License + * version 2 is included along with this program. + */ + +#include "stdheaders.h" +#include "cmpfile.h" +#include "fileemu.h" +#include "util.h" + +extern int trace; +char *acl_perm_t_file_n[] = { "read", "write", "execute", "delete", "append", "readattr", "writeattr", "readextattr", "writeextattr", "readsecurity", "writesecurity", "chown" }; +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 }; +extern uuid_t *uuid; +extern pthread_t thr[THREADS]; +extern pthread_mutex_t mutex_start; +extern pthread_cond_t cond_start; +char filename_shared[1024]; +int howmany = 0; +int acl_err = 1; + + +/* ------------------------------------------------------------------------- */ + +cmpfile_t *cmpfileNew(char *path, const char *root) +{ +cmpfile_t *cmpfile = calloc(1, sizeof(cmpfile_t)); + + if(trace) + printf("creating file %s\n", path); + cmpfile->refFile = fileNew(); + cmpfile->fd = creat(path, 0600); + if(cmpfile->fd < 0){ + perr(errno, "error creating file %s", path); + } + if(close(cmpfile->fd) < 0){ + perr(errno, "error closing file %s", path); + } + cmpfile->name = malloc(strlen(path) + 1); + strcpy(cmpfile->name, path); + cmpfile->isOpen = 0; + cmpfile->root = root; + return cmpfile; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpfileLink(cmpfile_t *cmpfile, char *linkName, int hard) +{ + if (!strcasecmp(cmpfile->name, linkName)) { +// printf("CASE MATCHES: %s %s\n", cmpfile->name, linkName); + return 1; + } + + if (trace) + printf("%s linking file %s to %s\n", hard ? "hard" : "soft", cmpfile->name, linkName); + + if (hard) { // Hard link request + if (link(cmpfile->name, linkName) < 0) { + perr(errno, "error hard linking file %s to %s", cmpfile->name, linkName); + return 0; + } + } else { // Soft link request + if (symlink(cmpfile->name, linkName) < 0) { + perr(errno, "error soft linking file %s to %s", cmpfile->name, linkName); + return 0; + } + } + unlink(linkName); + return 1; +} + + +/* ------------------------------------------------------------------------- */ + +btbool cmpfileRename(cmpfile_t *cmpfile, char *newName) +{ + filename_shared[0] = '\0'; + if (trace) + printf("Renaming file %s to %s\n", cmpfile->name, newName); + if(rename(cmpfile->name, newName) < 0){ + perr(errno, "error renaming file %s to %s", cmpfile->name, newName); + return 0; + } + free(cmpfile->name); + cmpfile->name = malloc(strlen(newName) + 1); + strcpy(cmpfile->name, newName); + return 1; +} + +/* ------------------------------------------------------------------------- */ + +void cmpfileFree(cmpfile_t *cmpfile, btbool hadErr, btbool unlinkme) +{ +char errName[1024]; + + if(trace) + printf("destroying file %s\n", cmpfile->name); + if(cmpfile->isOpen){ + if(close(cmpfile->fd) < 0){ + perr(errno, "error closing file %s", cmpfile->name); + } + cmpfile->isOpen = 0; + } + if(hadErr){ + sprintf(errName, "%s.error", cmpfile->name); + if(rename(cmpfile->name, errName) < 0){ + perr(errno, "error renaming file %s to %s", cmpfile->name, errName); + } + }else if (unlinkme) { + if(unlink(cmpfile->name) < 0){ + perr(errno, "error unlinking file %s", cmpfile->name); + } + } + fileFree(cmpfile->refFile); + cmpfile->refFile = NULL; + free(cmpfile->name); + cmpfile->name = NULL; + free(cmpfile); +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpfileOpen(cmpfile_t *cmpfile, btbool writable, btbool nocache) +{ + if(trace) + printf("opening file %s %s\n", cmpfile->name, writable ? "writable" : ""); + if(!fileOpen(cmpfile->refFile, writable)) + return 0; + cmpfile->fd = open(cmpfile->name, writable ? O_RDWR : O_RDONLY, 0); + if(cmpfile->fd < 0){ + perr(errno, "error opening file %s %s", cmpfile->name, writable ? "RDWR" : "RDONLY"); + fileClose(cmpfile->refFile); + return 0; + } + + if (nocache) + fcntl(cmpfile->fd, F_NOCACHE, 1); + cmpfile->isOpen = 1; + return 1; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpfileClose(cmpfile_t *cmpfile) +{ + if(trace) + printf("closing file %s\n", cmpfile->name); + fileClose(cmpfile->refFile); + if(close(cmpfile->fd) < 0){ + perr(errno, "error closing file %s", cmpfile->name); + } + cmpfile->isOpen = 0; + return 1; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpfileWrite(cmpfile_t *cmpfile, int offset, int len, void *data) +{ +int wlen; + + if(trace) + printf("writing file %s offset=%d, len=%d\n", cmpfile->name, offset, len); + fileWrite(cmpfile->refFile, offset, len, data); + if(lseek(cmpfile->fd, offset, SEEK_SET) == -1){ + perr(errno, "error seeking (write) in file %s", cmpfile->name); + return 0; + } + wlen = write(cmpfile->fd, data, len); + if(wlen != len){ + perr(errno, "error writing file %s, wlen = %d", cmpfile->name, wlen); + return 0; + } + return 1; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpfileRead(cmpfile_t *cmpfile, int offset, int len) +{ +char *fileBuf; +int refLen, fileLen; +btbool rval = 1; + + if(trace) + printf("reading file %s offset=%d, len=%d\n", cmpfile->name, offset, len); + fileBuf = malloc(len); + refLen = fileReadSize(cmpfile->refFile, offset, len); + if(lseek(cmpfile->fd, offset, SEEK_SET) == -1){ + perr(errno, "error seeking (read) in file %s", cmpfile->name); + rval = 0; + }else{ + fileLen = read(cmpfile->fd, fileBuf, len); + if(fileLen < 0){ + perr(errno, "error reading file %s", cmpfile->name); + rval = 0; + }else{ + if(refLen != fileLen){ + perr(0, "read size error reading file %s: %d instead of %d", cmpfile->name, fileLen, refLen); + rval = 0; + }else{ + if(!fileCompareRead(cmpfile->refFile, offset, refLen, fileBuf)){ + perr(0, "read error file %s: content error offset=%d len=%d size=%d", cmpfile->name, offset, len, fileSize(cmpfile->refFile)); + rval = 0; + } + } + } + } + free(fileBuf); + return rval; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpfileTruncate(cmpfile_t *cmpfile, int len) +{ +int rval; + + fileTruncate(cmpfile->refFile, len); + if(cmpfile->isOpen){ + if(trace) + printf("ftruncating file %s to %d\n", cmpfile->name, len); + rval = ftruncate(cmpfile->fd, len); + }else{ + if(trace) + printf("truncating file %s to %d\n", cmpfile->name, len); + rval = truncate(cmpfile->name, len); + } + if(rval < 0){ + perr(errno, "error (f)truncating file %s", cmpfile->name); + return 0; + } + return 1; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpfileSetMode(cmpfile_t *cmpfile, btbool writable) +{ +int rval = 0; + if(trace) + printf("setting mode of file %s to %s\n", cmpfile->name, writable ? "writable" : "not writable"); + fileSetMode(cmpfile->refFile, writable); + if (cmpfile->isOpen) { + rval = fchmod(cmpfile->fd, writable ? 0600 : 0400); + } else { + rval = chmod(cmpfile->name, writable ? 0600 : 0400); + } + if(rval < 0){ + perr(errno, "error chmoding file %s", cmpfile->name); + return 0; + } + return 1; +} + +/* ------------------------------------------------------------------------- */ + +void *thr_start() { // here, we just wait for work == when howmany != 0 + while (1) { + pthread_cond_wait(&cond_start, &mutex_start); + pthread_mutex_unlock(&mutex_start); + while (howmany > 0) { + acl_err = cmpfileAcls_do(); + howmany--; + usleep(100); + } + } + return(0); +} + +btbool cmpfileAcls(cmpfile_t *cmpfile) +{ + howmany = random_int(200); // how many iterations of acl bustin' we should do + if (trace) { + printf("acl busting: %i times\n", howmany); + } + strcpy(filename_shared, cmpfile->name); + pthread_cond_broadcast(&cond_start); + while (howmany > 0) { + if (acl_err == 0) { + return 0; + } + usleep(1); + } + return 1; +} +btbool cmpfileAcls_do() +{ // don't forget: sudo /usr/sbin/fsaclctl -p / -e + acl_t acl; + acl_entry_t ace; + acl_permset_t perms; + + if (trace) + printf("%p: acl'ing file %s\n", pthread_self(), filename_shared); + + if (NULL == (acl = acl_init(32))) { + perr(errno, "acl_init()"); + return 0; + } + + if (0 != acl_create_entry(&acl, &ace)) { + perr(errno, "acl_create_entry()"); + return 0; + } + + /* allow or deny */ + if (0 != acl_set_tag_type(ace, (random_int(2) == 1) ? ACL_EXTENDED_ALLOW : ACL_EXTENDED_DENY)) { + perr(errno, "acl_set_tag_type()"); + return 0; + } + + /* associate this with our uuid */ + if (0 != acl_set_qualifier(ace, uuid)) { + perr(errno, "acl_set_qualifier()"); + return 0; + } + + if (0 != acl_get_permset(ace, &perms)) { + perr(errno, "acl_get_permset()"); + return 0; + } + + switch(random_int(3)) { + case 0: /* ADD */ + if (0 != acl_add_perm(perms, acl_perm_t_file_r[random_int(12)])) { + perr(errno, "acl_add_perm()"); + return 0; + } + break; + case 1: /* DELETE */ + if (0 != acl_delete_perm(perms, acl_perm_t_file_r[random_int(12)])) { + perr(errno, "acl_delete_perms()"); + return 0; + } + break; + case 2: /* CLEAR */ + if (0 != acl_clear_perms(perms)) { + perr(errno, "acl_clear_perms()"); + return 0; + } + break; + } + + if (0 != acl_set_permset(ace, perms)) { + perr(errno, "acl_set_permset()"); + return 0; + } + + if (filename_shared[0] != '\0') { + if (0 != acl_set_file(filename_shared, ACL_TYPE_EXTENDED, acl)) { + perr(errno, "acl_set_file()"); + printf("f:%s\n", filename_shared); + return 0; + } + } + + acl_free(acl); + + return 1; +} + + + +// This is unused and was the first quick attempt +int cmpfileAcls2(cmpfile_t *cmpfile) +{ // don't forget: sudo /usr/sbin/fsaclctl -p / -e + char dothis[100]; + sprintf(dothis, "www"); + + switch(random_int(3)) { + case 0: /* ADD */ + sprintf(dothis, "%s %s %s", dothis, + (random_int(2) == 1) ? "allow" : "deny", + acl_perm_t_file_n[random_int(12)]); + + strcpy(cmpfile->acl, dothis); + sprintf(dothis, "exec chmod +a \"%s\" %s", cmpfile->acl, cmpfile->name); + break; + + case 1: /* REMOVE */ + if (cmpfile->acl[0] != '\0') { + sprintf(dothis, "exec chmod -a \"%s\" %s", cmpfile->acl, cmpfile->name); + cmpfile->acl[0] = '\0'; + } else { dothis[0] = '\0'; } + break; + + case 2: /* CHANGE */ + if (cmpfile->acl[0] != 'z') { + sprintf(dothis, "%s %s %s", dothis, + (random_int(2) == 1) ? "allow" : "deny", + acl_perm_t_file_n[random_int(12)]); + strcpy(cmpfile->acl, dothis); + sprintf(dothis, "exec chmod =a# 0 \"%s\" %s", cmpfile->acl, cmpfile->name); + } else { dothis[0] = '\0'; } + break; + } + + if (dothis[0] != '\0') { + // printf("dothis=%s\n", dothis); + system(dothis); + } + + return 1; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpfileStat(cmpfile_t *cmpfile, int noPerms) +{ + btbool isW; + int refSize; + struct stat buf; + int sret = 0; + + if(trace) + printf("stating file %s\n", cmpfile->name); + isW = fileIsWritable(cmpfile->refFile); + refSize = fileSize(cmpfile->refFile); + if (cmpfile->isOpen) { + sret = fstat(cmpfile->fd, &buf); + } else { + sret = stat(cmpfile->name, &buf); + } + if(sret < 0){ + perr(errno, "error stating file %s\n", cmpfile->name); + return 0; + }else{ + if(buf.st_size != refSize){ + perr(0, "file %s %sstats with wrong size (%d instead of %d)\n", cmpfile->name, cmpfile->isOpen ? "f" : "",(int)buf.st_size, refSize); + return 0; + } + if(((buf.st_mode & 0200) != 0) != isW){ + if (!noPerms) { + perr(0, "file %s %sstats with wrong write protection status (0%o)\n", cmpfile->name, cmpfile->isOpen ? "f" : "", buf.st_mode); + return 0; + } + } + } + return 1; +} + +/* ------------------------------------------------------------------------- */ + +btbool cmpfileUnlink(cmpfile_t *cmpfile) { + int rval = 0; + if (trace) + printf("Unlinking %s\n", cmpfile->name); + rval = unlink(cmpfile->name); + if (rval < 0) { + perr(errno, "error unlinking file %s\n", cmpfile->name); + return 0; + } + return 1; +} Added: trunk/src/fstorture/cmpfile.h =================================================================== --- trunk/src/fstorture/cmpfile.h (rev 0) +++ trunk/src/fstorture/cmpfile.h 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,100 @@ +/* + * Name: cmpfile.h + * Project: CIFS Client Automatic Test + * Author: Christian Starkjohann + * Creation Date: 1998-04-20 + * Tabsize: 4 + * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed + * under the terms of the Gnu General Public License (GPL). + * + * Copyright ? 2009 Apple Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only. This + * program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details. A copy of the GNU General Public License + * version 2 is included along with this program. + */ + +/* +General Description: +This class defines a "comparing file". The file class defined herein +implements the usual file operations. All these operations are performed +on a stored reference file (file_t object, type defined by fileemu.h) _and_ +on a real file in the filesystem. The results are compared when possible +and errors are reported. The only return value is whether the operation +succeeded without errors (both files returned the same results). The return +value is 1 on success, 0 on failure. +*/ + +/* ------------------------------------------------------------------------- */ + +#include "basictypes.h" +#include + +#define THREADS 5 + +//char *acl_perm_t_file_n[] = { "read", "write", "execute", "delete", "append", "readattr", "writeattr", "readextattr", "writeextattr", "readsecurity", "writesecurity", "chown" }; +//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 }; + +//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 }; + + +typedef struct cmpfile{ + struct file *refFile; + int fd; + char *name; + const char *root; + char acl[100]; + btbool isOpen; +}cmpfile_t; + +/* ------------------------------------------------------------------------- */ + +cmpfile_t *cmpfileNew(char *path, const char *root); +/* Creates a new object. This method also creates the embedded reference + * file object and creates the file on disk. + */ +void cmpfileFree(cmpfile_t *cmpfile, btbool hadErr, btbool unlinkme); +/* Frees the object and the embedded reference file. The file on disk is + * unlinked if 'hadErr' is 0 or renamed to .error if 'hadErr' is 1. + */ + +btbool cmpfileLink(cmpfile_t *cmpfile, char *linkName, int hard); + +btbool cmpfileRename(cmpfile_t *cmpfile, char *newName); +/* Renames the file on disk and stores the new name for further named + * references to the file. + */ +btbool cmpfileOpen(cmpfile_t *cmpfile, btbool writable, btbool nocache); +/* Opens the file read/write, if 'writable' is 1, read only if 'writable' + * is 0. + */ +btbool cmpfileClose(cmpfile_t *cmpfile); +/* Closes the file. + */ +btbool cmpfileWrite(cmpfile_t *cmpfile, int offset, int len, void *data); +/* Writes the given data block to the file. The file must be open for write. + */ +btbool cmpfileRead(cmpfile_t *cmpfile, int offset, int len); +/* Reads the data block at the given position from the file and verifies the + * result. + */ +btbool cmpfileTruncate(cmpfile_t *cmpfile, int len); +/* Sets the file size to the given size. + */ +btbool cmpfileSetMode(cmpfile_t *cmpfile, btbool writable); +/* Changes the write protection mode of the file. + */ + +btbool cmpfileAcls_do(); +btbool cmpfileAcls(cmpfile_t *cmpfile); + +btbool cmpfileStat(cmpfile_t *cmpfile, int noPerms); +/* Compares write protection status and size of the "real" file and the + * reference file. + */ +btbool cmpfileUnlink(cmpfile_t *cmpfile); + +/* ------------------------------------------------------------------------- */ Added: trunk/src/fstorture/fileemu.c =================================================================== --- trunk/src/fstorture/fileemu.c (rev 0) +++ trunk/src/fstorture/fileemu.c 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,236 @@ +/* + * Name: fileemu.c + * Project: CIFS Client Automatic Test + * Author: Christian Starkjohann + * Creation Date: 1998-04-20 + * Tabsize: 4 + * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed + * under the terms of the Gnu General Public License (GPL). + * + * Copyright ? 2009 Apple Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only. This + * program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details. A copy of the GNU General Public License + * version 2 is included along with this program. + */ + +#include "stdheaders.h" +#include "fileemu.h" + +/* ------------------------------------------------------------------------- */ + +static void reallocTouched(file_t *file) +{ +int size = file->allocSize / 8 + 1; + + file->touchedBits = realloc(file->touchedBits, size); + memset(file->touchedBits + file->touchedSize, 0, size - file->touchedSize); + file->touchedSize = size; +} + +/* ------------------------------------------------------------------------- */ + +static void bitarrSetRange(btu8 *arr, btsize startBitIndex, btsize numBits, btbool value) +{ +btsize fillStart, startRemainder, fillEnd, endRemainder; +btu8 startMask, endMask; + + fillStart = startBitIndex / 8 + 1; + startRemainder = startBitIndex % 8; + fillEnd = (startBitIndex + numBits) / 8; + endRemainder = (startBitIndex + numBits) % 8; + if(fillEnd > fillStart) + memset(arr + fillStart, value ? 0xff : 0, fillEnd - fillStart); + startMask = ~((1<isOpen = 0; + file->isWritable = 1; + file->allocSize = 32768; + file->data = calloc(1, file->allocSize); + file->size = 0; + reallocTouched(file); + return file; +} + +/* ------------------------------------------------------------------------- */ + +void fileFree(file_t *file) +{ + free(file->data); + if(file->touchedBits != NULL) + free(file->touchedBits); + free(file); +} + +/* ------------------------------------------------------------------------- */ + +btbool fileOpen(file_t *file, btbool writable) +{ + if(writable && !file->isWritable) + return 0; + file->isOpen = 1; + return 1; +} + +/* ------------------------------------------------------------------------- */ + +void fileClose(file_t *file) +{ + file->isOpen = 0; +} + +/* ------------------------------------------------------------------------- */ + +void fileWrite(file_t *file, int offset, int len, void *data) +{ +int maxlen = offset + len, newSize; + + if(!file->isOpen){ + fprintf(stderr, "fileemu: write to closed file\n"); + return; + } + if(maxlen > file->allocSize){ + newSize = file->allocSize; + while(maxlen > newSize) + newSize *= 2; + file->data = realloc(file->data, newSize); + memset(file->data + file->allocSize, 0, newSize - file->allocSize); + file->allocSize = newSize; + reallocTouched(file); + } + memcpy(file->data + offset, data, len); + bitarrSetRange(file->touchedBits, offset, len, 1); + if(file->size < maxlen) + file->size = maxlen; +} + +/* ------------------------------------------------------------------------- */ + +int fileReadSize(file_t *file, int offset, int len) +{ +int maxlen = offset + len; + + if(!file->isOpen){ + fprintf(stderr, "fileemu: read from closed file\n"); + return 0; + } + if(maxlen > file->size){ + len = file->size - offset; + } + if(len <= 0){ + return 0; + } + return len; +} + +/* ------------------------------------------------------------------------- */ + +int fileRead(file_t *file, int offset, int len, void *dest) +{ + len = fileReadSize(file, offset, len); + memcpy(dest, file->data + offset, len); + return len; +} + +/* ------------------------------------------------------------------------- */ + +btbool fileCompareRead(file_t *file, int offset, int len, void *data) +{ +int i; +char *refData = data; +int errors = 0, firstErrorIndex=0, lastErrorIndex=0; +int originalOffset = offset; + + if(fileReadSize(file, offset, len) != len){ + fprintf(stderr, "file compare failed due to size error\n"); + return 0; + } + for(i=0;itouchedBits, offset)){ /* is touched */ + if(file->data[offset] != refData[i]){ + if(errors == 0) + firstErrorIndex = offset; + lastErrorIndex = offset; + if(errors < 20) + fprintf(stderr, "data in file[%d] is 0x%02x instead of 0x%02x\n", offset, (btu8)refData[i], (btu8)file->data[offset]); + errors++; + } + } + offset++; + } + if(errors != 0){ + fprintf(stderr, "fileCompareRead: %d errors in data block: first=%d last=%d, blockstart=%d, blocklen=%d\n", errors, firstErrorIndex, lastErrorIndex, originalOffset, len); + } + return errors == 0; +} + +/* ------------------------------------------------------------------------- */ + +void fileTruncate(file_t *file, int len) +{ +int maxlen = len, newSize; + + if(maxlen > file->allocSize){ + newSize = file->allocSize; + while(maxlen > newSize) + newSize *= 2; + file->data = realloc(file->data, newSize); + memset(file->data + file->allocSize, 0, newSize - file->allocSize); + file->allocSize = newSize; + reallocTouched(file); + } + if(maxlen < file->size){ /* file shrinks */ + bitarrSetRange(file->touchedBits, maxlen, file->size - maxlen, 0); + } + file->size = maxlen; +} + +/* ------------------------------------------------------------------------- */ + +void fileSetMode(file_t *file, btbool writable) +{ + file->isWritable = writable; +} + +/* ------------------------------------------------------------------------- */ + +btbool fileIsWritable(file_t *file) +{ + return file->isWritable; +} + +/* ------------------------------------------------------------------------- */ Added: trunk/src/fstorture/fileemu.h =================================================================== --- trunk/src/fstorture/fileemu.h (rev 0) +++ trunk/src/fstorture/fileemu.h 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,92 @@ +/* + * Name: fileemu.h + * Project: CIFS Client Automatic Test + * Author: Christian Starkjohann + * Creation Date: 1998-04-20 + * Tabsize: 4 + * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed + * under the terms of the Gnu General Public License (GPL). + * + * Copyright ? 2009 Apple Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only. This + * program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details. A copy of the GNU General Public License + * version 2 is included along with this program. + */ + +/* +General Description: +The file class defined in this module emulates the behaviour of files on +disk media. It is used as a reference when the results of file operations +must be verified. +*/ + +/* ------------------------------------------------------------------------- */ + +#include "basictypes.h" + +typedef struct file{ + btbool isOpen; + btbool isWritable; + btu8 *touchedBits; + int touchedSize; + char *data; + int allocSize; + int size; +}file_t; + +/* ------------------------------------------------------------------------- */ + +file_t *fileNew(void); +/* Creates a new file_t object + */ +void fileFree(file_t *file); +/* Frees an existing file_t object + */ +btbool fileOpen(file_t *file, btbool writable); +/* Sets a file_t object into the "opened" state. The flag "writable" defines + * whether writes to the file will be possible. + */ +void fileClose(file_t *file); +/* Sets the file_t object into the closed state. + */ +void fileWrite(file_t *file, int offset, int len, void *data); +/* Writes to the file_t object. The data written to the file is stored in + * memory and the range of already written-to bytes is also stored. + */ +int fileReadSize(file_t *file, int offset, int len); +/* Returns the number of bytes that would be read from the file_t object + * if a read with the parameters 'offset' and 'len' would be performed. + */ +int fileRead(file_t *file, int offset, int len, void *dest); +/* Reads data from the file. This method is currently not used. + */ +btbool fileCompareRead(file_t *file, int offset, int len, void *data); +/* This method verifies whether the data read from the "real" file is correct. + * It takes into account that only those parts of the block should be verified + * that have already been written to. Unwritten parts that are not entire + * filesystem blocks or pages may contain old data of previous contents. + * The function returns 1, if no compare error occured. + */ +void fileTruncate(file_t *file, int len); +/* Sets the file size to the given value and invalidates all data behind the + * end of file. + */ +void fileSetMode(file_t *file, btbool writable); +/* Changes the write protection mode of the file. The write protection is only + * checked by fileOpen(). Whether writes are possible depends on the open mode + * used. + */ +btbool fileIsWritable(file_t *file); +/* Returns the write protection status of the file. + */ + +static inline int fileSize(file_t *file) +{ + return file->size; +} + +/* ------------------------------------------------------------------------- */ Added: trunk/src/fstorture/fstorture.c =================================================================== --- trunk/src/fstorture/fstorture.c (rev 0) +++ trunk/src/fstorture/fstorture.c 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,1064 @@ +/* + * Name: fstorture.c + * Project: CIFS Client Automatic Test + * Author: Christian Starkjohann + * Creation Date: 1998-04-20 + * Tabsize: 4 + * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed + * under the terms of the Gnu General Public License (GPL). + * + * Copyright ? 2009 Apple Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only. This + * program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details. A copy of the GNU General Public License + * version 2 is included along with this program. + */ + +#include "stdheaders.h" +#include "cmpfile.h" +#include "cmpdir.h" +#include "fileemu.h" +#include "util.h" +#ifdef XILOG +#include +#endif /* XILOG */ + +#define VERS "2.1-pfh" + +// Global variables +uuid_t *uuid=NULL; +pthread_t thr[THREADS]; +extern void *thr_start(); +pthread_mutex_t mutex_start; +pthread_cond_t cond_start; + +/* ------------------------------------------------------------------------- */ +/* ------------------------ commandline parameters ------------------------- */ +/* ------------------------------------------------------------------------- */ +static btbool bugFtruncateReadonly = 0; +static btbool bugFtruncateSync = 0; +static btbool noRenameOpenFiles = 0; +static btbool noUnlinkOpenFiles = 0; +static btbool noTestDirs = 0; +static btbool WinVolume = 0; +static btbool noStats = 0; +static btbool noPerms = 0; +static btbool softlinks = 1; +static btbool hardlinks = 1; +static btbool sleepy = 0; +static btbool acl = 0; +static btbool nocache = 0; +static char *root1; /* directories where to perform test */ +static char *root2; +static int count = 0; // how many to do +static int mycount = 0; // how many we've done so far +static int gStopTime = 0; +pid_t parent_pid = 0; +int trace = 0; + +#ifdef XILOG +static XILogRef gLogRef; +char* gLogPath; +Boolean gXML = false; +Boolean gEcho = false; +#endif //XILOG + +int parsetime(char *t) { + int i = 0; + int secs = 0; + char b[128]; bzero(b, 128); + + for (i=0; i < strlen(t); i++) { + switch (t[i]) { + case 's': + secs += atoi(b); + bzero(b, 128); + break; + case 'm': + secs += atoi(b) * 60; + bzero(b, 128); + break; + case 'h': + secs += atoi(b) * 60 * 60; + bzero(b, 128); + break; + case 'd': + secs += atoi(b) * 60 * 60 * 24; + bzero(b, 128); + break; + case 'w': + secs += atoi(b) * 60 * 60 * 24 * 7; + bzero(b, 128); + break; + case 'y': + secs += atoi(b) * 60 * 60 * 24 * 365; + bzero(b, 128); + break; + default: + sprintf(b, "%s%c", b, t[i]); + } + } + if (secs == 0) // maybe they just gave us a number? + secs = atoi(t); + return(secs); +} + +/* ------------------------------------------------------------------------- */ +/* ------------------- random number generator for tests ------------------- */ +/* ------------------------------------------------------------------------- */ + +struct random_status{ + int i; + real_t u[97]; + real_t c; +}; + +struct random_status random_status; + +/* ------------------------------------------------------------------------- */ + +real_t random_get(void) /* 3.56 microseconds execution-time on 486/66 */ +{ +real_t r; + + r = random_status.u[random_status.i] + - random_status.u[(random_status.i + 33) % 97]; + if(r < 0) + r += 1; + random_status.u[random_status.i--] = r; + if(random_status.i < 0) + random_status.i = 96; + random_status.c = random_status.c - 7654321./16777216.; + if(random_status.c < 0) + random_status.c += 16777213./16777216.; + r -= random_status.c; + if(r < 0) + r += 1; + return r; +} + +/* ------------------------------------------------------------------------- */ + +void random_init(int na1, int na2, int na3, int nb1) +{ +int i, j, mat; +real_t s, t; + + random_status.i = 96; + for(j = 0; j < 97; j++){ + s = 0; + t = 0.5; + for(i = 0; i < 24; i++){ + mat = (((na1 * na2) % 179) * na3) % 179; + na1 = na2; + na2 = na3; + na3 = mat; + nb1 = (53 * nb1 + 1) % 169; + if((nb1 * mat % 64) >= 32) + s += t; + t /= 2; + + } + random_status.u[j] = s; + } + random_status.c = 362436./16777216.; +} + +/* ------------------------------------------------------------------------- */ + +int random_int(int exclusive_range) +{ +int r = (int)(random_get() * exclusive_range); + + if(r < 0 || r >= exclusive_range){ + printf("random number %d illegal\n", r); + exit(1); + } + return r; +} + +/* ------------------------------------------------------------------------- */ + +/* This is not a real gaussian random number generator. Don't use it for + * something where the probability distribution really counts! It is + * shaped after what is mathematically easy and what the application + * demands. + */ +real_t random_gauss(real_t stdval, real_t maxRange) +{ +real_t val, x, f, m, a, b, h; + + a = 10; b = 2; + m = M_PI/2 - 1 + a + a/b; /* mean value of distribution */ + f = stdval / m; + for(;;){ + x = random_get(); + h = sqrt(1 - x*x); + if(h == 0) + continue; + val = a * pow(x, 1/b) + 1/h - 1; + val *= f; + if(val < maxRange) + return val; + } +} + +void random_block(void *block, int len) +{ +int i; +btu8 *p = block; + + for(i=0;i= 10 || prefix < 0) { + perr(0, "CMPDIR_MAX_FILES and prefix must be no larger than 10"); +#if XILOG + XILogEndTestCase(gLogRef, kXILogTestPassOnErrorLevel); + XILogCloseLog(gLogRef); +#endif /* XILOG */ + exit(1); + } + name[0] = '0' + prefix; + + for(i=1;ifd); + if(!random_int(10)){ /* do much less truncates than rest */ + if(!bugFtruncateReadonly || (w && fileIsWritable(f->refFile))){ + rval = cmpfileTruncate(f, random_int(50000)); + } + } + break; + case 5: /* chmod */ + rval = cmpfileSetMode(f, random_int(3) != 0); + break; + case 6: /* stat */ + if (!noStats) { // if the noStats flag ISN'T set + rval = cmpfileStat(f, noPerms); + } + break; + case 7: /* sleep */ + if (sleepy) { + if(!random_int(4)){ + usleep(1000000 * random_gauss(1, 200)); + } + } + break; + case 8: /* rename */ + if(!noRenameOpenFiles) { + random_path(path, id, running, (WinVolume) ? f->root : random_root()); + rval = cmpfileRename(f, path); + } + break; + case 9: /* acls */ + if (acl) { + if(!random_int(5)) { // do less ACL busting + rval = cmpfileAcls(f); + } + } + break; + case 10: /* link */ + if (!random_int(2)) { + if (softlinks) { + random_path(path, id, running, random_root()); + rval = cmpfileLink(f, path, 0); // Soft link + } + } else { + if (hardlinks) { + random_path(path, id, running, random_root()); + rval = cmpfileLink(f, path, 1); // Hard link + } + } + break; + } + return rval; +} + +/* ------------------------------------------------------------------------- */ + +static btbool randomClosedOp(cmpfile_t *f, int id, int running) +{ +btbool rval = 1; +char path[1024]; +const char *root; + + switch(random_int(7)){ + case 0: /* truncate */ + if(!random_int(10)){ /* do much less truncates than rest */ + if(fileIsWritable(f->refFile)){ + rval = cmpfileTruncate(f, random_int(50000)); + } + } + break; + case 1: /* chmod */ + rval = cmpfileSetMode(f, random_int(3) != 0); + break; + case 2: /* stat */ + if (!noStats) { // if the noStats flag ISN'T set + rval = cmpfileStat(f, noPerms); + } + break; + case 3: /* sleep */ + if (sleepy) { + if(!random_int(4)){ + usleep(1000000 * random_gauss(1, 200)); + } + } + break; + case 4: /* rename */ + root = random_root(); + random_path(path, id, running, root); + rval = cmpfileRename(f, path); + if (rval) /* Rename sucessed so reset the root */ + f->root = root; + break; + case 5: /* acls */ + if(!random_int(5)){ // do less ACL busting than the rest + if (acl) + rval = cmpfileAcls(f); + } + break; + case 6: /* link */ + if (!random_int(2)) { + if (softlinks) { + random_path(path, id, running, random_root()); + rval = cmpfileLink(f, path, 0); // Soft link + } + } else { + if (hardlinks) { + random_path(path, id, running, random_root()); + rval = cmpfileLink(f, path, 1); // Hard link + } + } + break; + } + return rval; +} + +/* ------------------------------------------------------------------------- */ + +static btbool randomUnlinkOp(cmpfile_t *f, btbool w, int id, int running) +{ +btbool rval = 1; +int offset, len; +void *block; + + + switch(random_int(5)){ + case 0: /* read */ + offset = random_int(30000) + random_gauss(10, 100000); + len = 1 + random_gauss(20000, 100000); + rval = cmpfileRead(f, offset, len); + break; + case 1: /* write */ + if(w){ + offset = random_int(30000) + random_gauss(10, 100000); + len = 1 + random_gauss(30000, 500000); + block = malloc(len); + random_block(block, len); + rval = cmpfileWrite(f, offset, len, block); + free(block); + } + break; + + case 2: /* ftruncate */ + if(bugFtruncateSync) + fsync(f->fd); + if(!bugFtruncateReadonly || (w && fileIsWritable(f->refFile))){ + rval = cmpfileTruncate(f, random_int(50000)); + } + break; + case 3: /* fchmod */ + rval = cmpfileSetMode(f, random_int(3) != 0); + break; + case 4: /* fstat */ + if (!noStats) { // if the noStats flag ISN'T set + rval = cmpfileStat(f, noPerms); + } + break; + } + return rval; +} + +/* ------------------------------------------------------------------------- */ + + +static void testOneFile(int id, int running) +{ +char path[1024]; +cmpfile_t *f; +int w, i, l, i1, l1; +btbool hadErr = 1; +const char *root = random_root(); + + random_path(path, id, running, root); + f = cmpfileNew(path, root); + l1 = random_gauss(50,5000); + for(i1=0;i1refFile)) + w = 0; + w = w != 0; + if(!cmpfileOpen(f, w, nocache)) + goto errorOccured; + l = random_gauss(20, 5000); + for(i=0;irefFile)) + w = 0; + w = w != 0; + if(!cmpfileOpen(f, w, nocache)) + goto errorOccured; + if(!cmpfileUnlink(f)) + goto errorOccured; + for(i1=0;i1 0)) { // whichever is LONGER is run + if(noTestDirs || random_int(7)) { + testOneFile(id, i); + testOneUnlinkedFile(id, i); + } else + testOneDirectory(id, i); + i++; + count -= n; + mycount += n; +#ifdef XILOG + if (isParent) + if ((i*n % 100) == 0) + XIPing(i); +#endif /* XILOG */ + } + + } else { // Just run indefinitely + for(i=0;;i++){ +#ifdef XILOG + if (isParent) + if ((i*n % 100) == 0) + XIPing(mycount); +#endif /* XILOG */ + if(noTestDirs || random_int(7)){ + testOneFile(id, i); + testOneUnlinkedFile(id, i); + }else{ + testOneDirectory(id, i); + } + mycount += n; + } + + } + if (isParent) { + printf("Test completed [fstorture %s]: ", VERS); fflush(NULL); + system("date"); + } +} + + +/* ------------------------------------------------------------------------- */ +void usage(char *argv) { + fprintf(stderr, "fstorture %s\n", VERS); + fprintf(stderr, "usage: %s [options]\n", argv); + fprintf(stderr, "available options are:\n"); + fprintf(stderr, " fsync_before_ftruncate\n"); + fprintf(stderr, " no_rename_open_files\n"); + fprintf(stderr, " no_unlink_open_files\n"); + fprintf(stderr, " no_test_dirs\n"); + fprintf(stderr, " no_stats\n"); + fprintf(stderr, " no_perms\n"); + fprintf(stderr, " windows_volume\n"); + fprintf(stderr, " windows98\n"); + fprintf(stderr, " nocache Adds fcntl(F_NOCACHE) after open\n"); + fprintf(stderr, " acl Performs ACL busting\n"); + fprintf(stderr, " nosoftlinks Disables soft-links\n"); + fprintf(stderr, " nohardlinks Disables hard-links\n"); + fprintf(stderr, " sleep Adds sleep between operations\n"); + fprintf(stderr, " -v Increases verbosity\n"); + fprintf(stderr, " -c 100 Each process will run this many tests\n"); + fprintf(stderr, " -t 5h35m18s Runs for 5hours 35min 18sec\n"); + fprintf(stderr, " NOTE: Both count & time may be given; whichever takes longer is used\n"); + fprintf(stderr, " NOTE: If you specify 4 processes instead of 1, -c 100 will take 4x as long\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + int n, i; + struct stat sbuf; + struct volcapbuf { + u_long buffer_size; + vol_capabilities_attr_t caps; + }; + struct attrlist alist; + struct volcapbuf buf; + struct statfs st; + int dirs = 0; + + if(argc < 4) + usage(argv[0]); + root1 = argv[1]; + root2 = argv[2]; + if(stat(root1, &sbuf) != 0){ + fprintf(stderr, "root1 = %s does not exist\n", root1); + exit(1); + } + if(stat(root2, &sbuf) != 0){ + fprintf(stderr, "root2 = %s does not exist\n", root2); + exit(1); + } + if(!isdigit(argv[3][0])){ + fprintf(stderr, " must be a number, not %s!\n", argv[3]); + usage(argv[0]); + } + n = atoi(argv[3]); // number of processes to spawn + bugFtruncateReadonly = 1; /* always on, documentation bug */ + for(i=4;i%s<- not known\n", argv[i]); + exit(1); + } + } +#ifdef XILOG + } +#endif /* XILOG */ + } + + + // Check if root1 and root2 are empty directories + DIR* dirp; + struct dirent *dp; + dirs = 0; + dirp = opendir(root1); + while ((dp = readdir(dirp)) != NULL) + dirs++; + (void)closedir(dirp); + if (dirs != 2) + printf("--> WARNING: %s should be an EMPTY DIRECTORY <-- \n", root1); + + dirs = 0; + dirp = opendir(root2); + while ((dp = readdir(dirp)) != NULL) + dirs++; + (void)closedir(dirp); + if (dirs != 2) + printf("--> WARNING: %s should be an EMPTY DIRECTORY <--\n", root2); + + + // Check if soft/hard links & ACLs are supported + alist.bitmapcount = 5; + alist.reserved = 0; + alist.commonattr = 0; + alist.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES; + alist.dirattr = 0; + alist.fileattr = 0; + alist.forkattr = 0; + + if (statfs(root1, &st) < 0) { + perr(errno, "statfs"); + exit(-1); + } + if (getattrlist(st.f_mntonname, &alist, &buf, sizeof buf, 0) < 0) { + perr(errno, "getattrlist"); + exit(-1); + } + printf("Capabilities of %s (on %s): softlinks?", root1, st.f_mntonname); + if (buf.caps.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_SYMBOLICLINKS) { + printf("Y"); + } else { + printf("N"); + softlinks = 0; + } + + printf(" hardlinks?"); + if (buf.caps.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_HARDLINKS) { + printf("Y"); + } else { + printf("N"); + hardlinks = 0; + } + printf(" ACLs?"); + if(buf.caps.capabilities[VOL_CAPABILITIES_INTERFACES]&VOL_CAP_INT_EXTENDED_SECURITY){ + printf("Y"); + } else { + printf("N"); + acl = 0; + } + printf("\n"); + + if (statfs(root1, &st) < 0) { + perr(errno, "statfs"); + exit(-1); + } + if (getattrlist(st.f_mntonname, &alist, &buf, sizeof buf, 0) < 0) { + perr(errno, "getattrlist"); + exit(-1); + } + printf("Capabilities of %s (on %s): softlinks?", root2, st.f_mntonname); + if (buf.caps.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_SYMBOLICLINKS) { + printf("Y"); + } else { + printf("N"); + softlinks = 0; + } + printf(" hardlinks?"); + + if (buf.caps.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_HARDLINKS) { + printf("Y"); + } else { + printf("N"); + hardlinks = 0; + } + printf(" ACLs?"); + if(buf.caps.capabilities[VOL_CAPABILITIES_INTERFACES]&VOL_CAP_INT_EXTENDED_SECURITY){ + printf("Y"); + } else { + printf("N"); + acl = 0; + } + printf("\n"); + + + + if (acl) { + // Now, put user "www"'s UUID into the global variable "uuid" + char *u = "www"; + struct passwd *tpass = NULL; + //uuid_t *uuid=NULL; // this was defined globally + if (NULL == (uuid = (uuid_t *)calloc(1,sizeof(uuid_t)))) + perr(errno, "unable to allocate a uuid"); + tpass = getpwnam(u); + if (tpass) { + if (0 != mbr_uid_to_uuid(tpass->pw_uid, *uuid)) { + perr(errno, "mbr_uid_to_uuid(): Unable to translate"); + } + } + + // Next, make our threads + pthread_mutex_init(&mutex_start, NULL); + pthread_cond_init (&cond_start, NULL); + + for (i=0;i= 2 ) ? "s" : ""); + if (gStopTime != 0) + printf("Running for %d seconds\n", gStopTime - (int)time(NULL)); + if (sleepy) + printf("Throwing in random sleeps\n"); + + signal(SIGHUP, cleanup); + signal(SIGINT, cleanup); + signal(SIGPIPE, cleanup); + signal(SIGALRM, cleanup); + signal(SIGTERM, cleanup); + signal(SIGXCPU, cleanup); + signal(SIGXFSZ, cleanup); + signal(SIGVTALRM,cleanup); + signal(SIGUSR1, cleanup); + signal(SIGUSR2, cleanup); + +#ifdef XILOG + XIPing(0); +#endif /* XILOG */ + + for(i=0;i + * Creation Date: 1998-04-20 + * Tabsize: 4 + * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed + * under the terms of the Gnu General Public License (GPL). + * + * Copyright ? 2009 Apple Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only. This + * program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details. A copy of the GNU General Public License + * version 2 is included along with this program. + */ + +/* +General Description: +This header includes all system headers that are needed. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NeXT +# include +#endif Added: trunk/src/fstorture/testPerformance =================================================================== --- trunk/src/fstorture/testPerformance (rev 0) +++ trunk/src/fstorture/testPerformance 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,124 @@ +#!/bin/sh +# Name: testPerformance +# Project: CIFS Client +# Author: Christian Starkjohann +# Creation Date: 1998-05-16 +# Tabsize: 4 +# Copyright: (c) 1998 by Christian Starkjohann. This program is distributed +# under the terms of the Gnu General Public License (GPL). +# +# Copyright ? 2009 Apple Inc. +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only. This +# program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details. A copy of the GNU General Public License +# version 2 is included along with this program. +# +# General Description: +# This script runs some performance tests within a given directory of the +# file system. + +mypath=`pwd` + +PATH=$PATH:/etc:/usr/ucb # extend search path + +srvdir="$1" + +testLarge=/bin/true +testMany=/bin/true + +if [ -z "$srvdir" ]; then + echo "You need to specify a destination directory" + echo "Usage: $0 " + exit 1 +fi + +if [ -r "$srvdir" ]; then + deletesrv=no +else + if mkdir "$srvdir"; then + true + else + echo "error creating test directory" + exit 1 + fi + deletesrv=yes +fi + +tmpdir="/tmp/testperf-`whoami`-$$" + +many="$tmpdir/many" +large="$tmpdir/large" + +mkdir "$tmpdir" +mkdir "$many" + +if $testLarge; then + echo "Setting up large file with 64MB " + echo 123456789012345678901234567890123456789012345678901234567890123 >$large + dd if=$large bs=64 count=1023 >>$large # file should now be 64k + dd if=$large bs=65536 count=1023 >>$large # file should now be 64MB +fi + +if $testMany; then + echo -n "Setting up directory with 2000 files " + for i in 0 1; do + for j in 0 1 2 3 4 5 6 7 8 9; do + for k in 0 1 2 3 4 5 6 7 8 9; do + for l in 0 1 2 3 4 5 6 7 8 9; do + echo "this is file $i$j$k$l" >$many/file-$i$j$k$l.txt + done + echo -n '.' + done + done + done +fi + +echo + +if $testLarge; then + echo "----------------------------------------------------------------------" + echo "First test: copy large file to server" + time cp $large $srvdir + + echo "----------------------------------------------------------------------" + echo "Second test: copy large file from server" + rm $large + time cp $srvdir/large $large + rm $srvdir/large +fi + +if /$testMany; then + echo "----------------------------------------------------------------------" + echo "Copy 2000 files to server" + time cp -r $many $srvdir + + echo "----------------------------------------------------------------------" + echo "Copy 2000 files from server" + rm -r $many + time cp -r $srvdir/many $many + + echo "----------------------------------------------------------------------" + echo "Disk usage of large directory" + time du $srvdir/many + + echo "----------------------------------------------------------------------" + echo "Listing of large directory" + time ls -al $srvdir/many >/dev/null + + echo "----------------------------------------------------------------------" + echo "Deleting 2000 files on server" + time rm -r $srvdir/many +fi + +echo "----------------------------------------------------------------------" +echo "cleaning up" + +rm -rf "$tmpdir" +if [ $deletesrv '=' yes ]; then + rmdir $srvdir +fi + +echo "ready." Property changes on: trunk/src/fstorture/testPerformance ___________________________________________________________________ Added: svn:executable + * Added: trunk/src/fstorture/util.h =================================================================== --- trunk/src/fstorture/util.h (rev 0) +++ trunk/src/fstorture/util.h 2010-02-26 16:28:43 UTC (rev 5) @@ -0,0 +1,38 @@ +/* + * Name: util.h + * Project: CIFS Client Automatic Test + * Author: Christian Starkjohann + * Creation Date: 1998-04-28 + * Tabsize: 4 + * Copyright: (c) 1998 by Christian Starkjohann. This program is distributed + * under the terms of the Gnu General Public License (GPL). + * + * Copyright ? 2009 Apple Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only. This + * program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details. A copy of the GNU General Public License + * version 2 is included along with this program. + */ + +#include "basictypes.h" + +/* ------------------------------------------------------------------------- */ + +typedef double real_t; /* real numbers are double */ + +void random_init(int na1, int na2, int na3, int nb1); +real_t random_get(void); +int random_int(int exclusive_range); +real_t random_gauss(real_t stdval, real_t maxRange); +void random_block(void *block, int len); +void random_name(char *name, int len, int prefix); +const char * random_root(); +void random_path(char *path, int id, int running, const char *root); + +void perr(int e, char *s, ...); +void cleanup(int sig); +/* ------------------------------------------------------------------------- */ + -------------- next part -------------- An HTML attachment was scrubbed... URL: