[Fstools-changes] [5] trunk/src

source_changes at macosforge.org source_changes at macosforge.org
Fri Feb 26 08:28:46 PST 2010


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.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+  <signature of Ty Coon>, 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 <cs at obdev.at>
+# 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 <root-dir1> <root-dir2> <number of processes> [<options>]
+
+The <root-dir1> and <root-dir2> 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. <number of
+processes> 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. <options>
+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 <cs at obdev.at>
+

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 <cs at obdev.at>
+ * 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 <cs at obdev.at>
+ * 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<BUF_SIZE;i++)
+		block[i] = rand() >> 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;i<CMPDIR_MAX_FILES;i++){
+		if(dir->files[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;i<CMPDIR_MAX_FILES;i++){
+		if(dir->files[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 <cs at obdev.at>
+ * 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 <sys/acl.h>
+
+//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 <cs at obdev.at>
+ * 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 <cs at obdev.at>
+ * 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 <sys/acl.h>
+
+#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 <filename>.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 <cs at obdev.at>
+ * 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<<startRemainder) - 1);
+	endMask = (1<<endRemainder) - 1;
+	if(value){
+		if(fillStart - 1 == fillEnd){
+			arr[fillEnd] |= startMask & endMask;
+		}else{
+			arr[fillStart - 1] |= startMask;
+			arr[fillEnd] |= endMask;
+		}
+	}else{
+		if(fillStart - 1 == fillEnd){
+			arr[fillEnd] &= ~(startMask & endMask);
+		}else{
+			arr[fillStart - 1] &= ~startMask;
+			arr[fillEnd] &= ~endMask;
+		}
+	}
+}
+
+/* ------------------------------------------------------------------------- */
+
+static inline btbool	bitarrBitIsSet(btu8 *arr, btsize bitIndex)
+{
+	return (arr[bitIndex/8] & (1<<(bitIndex % 8))) != 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+file_t	*fileNew(void)
+{
+file_t	*file;
+
+	file = calloc(1, sizeof(file_t));
+	file->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;i<len;i++){
+		if(bitarrBitIsSet(file->touchedBits, 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 <cs at obdev.at>
+ * 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 <cs at obdev.at>
+ * 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 <XILog/XILog.h>
+#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<len;i++){
+		*p++ = random_int(256);
+	}
+}
+
+static char	*charTable = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-";
+
+void	random_name(char *name, int len, int prefix)
+{
+	int		i,j;
+#define howmanyt 5
+	int rndnum=0;
+	int tstrlen=0;
+	char *dtypes[howmanyt];
+
+	dtypes[0] = ".app";
+	dtypes[1] = ".mp3";
+	dtypes[2] = ".mov";
+	dtypes[3] = ".rtf";
+	dtypes[4] = ".html";
+
+	/* add an one-digit prefix to avoid name duplication */
+	if (prefix >= 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;i<len;i++){
+		name[i] = charTable[random_int(strlen(charTable))];
+	}
+	name[i] = 0;
+
+	/* PFH - Now, let's add an extension */
+	rndnum = random_int(howmanyt);
+	tstrlen = strlen(dtypes[rndnum]);
+	for (j = 1; j <= tstrlen; j++) {
+		name[i-j] = dtypes[rndnum][tstrlen-j];
+	}
+}
+
+const char * random_root()
+{
+	return (random_int(2) ? root1 : root2);
+}
+
+void	random_path(char *path, int id, int running, const char *root)
+{
+char	rname[16];
+
+	random_name(rname, 8, 0);
+	sprintf(path, "%s/%02d-%03d-%s", root, id, running, rname);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --------------------- the test's main functionality --------------------- */
+/* ------------------------------------------------------------------------- */
+
+
+void perr(int e, char *s, ...) { // e is errno, and s is the string
+	int p;
+	va_list argp;
+	struct tm *newtime;
+	time_t aclock;
+	char msg[1024]; bzero(msg, 1024);
+	char msg2[1024]; bzero(msg2, 1024);
+
+	time( &aclock );                 /* Get time in seconds */
+	newtime = localtime( &aclock );  /* Convert time to struct */
+
+	if (e == 0)  // no error given
+		sprintf(msg, "%s %s", asctime(newtime), s);
+	else
+		sprintf(msg, "%s %s: %s", asctime(newtime), s, strerror(e));
+
+	// shoulda used asprintf, except for stripping \n's out
+	va_start(argp, s); // Let's reimplement printf!
+	for (p = 0; msg[p] != '\0'; p++) {
+		if(msg[p] == '\n')
+			continue;
+		if(msg[p] != '%') {
+			sprintf(msg2, "%s%c", msg2, msg[p]);
+			continue;
+		}
+		switch(msg[++p]) {
+			case 'c':
+				sprintf(msg2, "%s%c", msg2, va_arg(argp, int));
+				break;
+			case 'd':
+				sprintf(msg2, "%s%d", msg2, va_arg(argp, int));
+				break;
+			case 'o':
+				sprintf(msg2, "%s%o", msg2, va_arg(argp, int));
+				break;
+			case 's':
+				sprintf(msg2, "%s%s", msg2, va_arg(argp, char *));
+				break;
+			case 'x':
+				sprintf(msg2, "%s%x", msg2, va_arg(argp, int));
+				break;
+			case '%':
+				sprintf(msg2, "%s%%", msg2);
+				break;
+		}
+	}
+	va_end(argp);
+
+	printf("%s\n", msg2);
+
+#ifdef XILOG
+	XILogErr(msg2);	
+#endif /* XILOG */
+}
+
+
+
+static btbool	randomOpenOp(cmpfile_t *f, btbool w, int id, int running)
+{
+btbool	rval = 1;
+int		offset, len;
+void	*block;
+char	path[1024];
+
+	
+	switch(random_int(11)){
+	case 0:	/* read */
+	case 1:	/* read */
+		offset = random_int(30000) + random_gauss(10, 100000);
+		len = 1 + random_gauss(20000, 100000);
+		rval = cmpfileRead(f, offset, len);
+		break;
+	case 2:	/* write */
+	case 3:	/* 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 4:	/* truncate */
+		if(bugFtruncateSync)
+			fsync(f->fd);
+		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;i1<l1;i1++){
+
+	// Perform open file operations
+		w = random_int(3);
+		if(!fileIsWritable(f->refFile))
+			w = 0;
+		w = w != 0;
+		if(!cmpfileOpen(f, w, nocache))
+			goto errorOccured;
+		l = random_gauss(20, 5000);
+		for(i=0;i<l;i++){
+			if(!randomOpenOp(f, w, id, running))
+				goto errorOccured;
+		}
+		if(!cmpfileClose(f))
+			goto errorOccured;
+
+	// Perform closed file operations
+		if(random_int(2)){
+			l = random_gauss(20, 500);
+		}else{
+			l = random_int(5);
+		}
+		for(i=0;i<l;i++){
+			if(!randomClosedOp(f, id, running))
+				goto errorOccured;
+		}
+	}
+
+	hadErr = 0;
+errorOccured:
+	cmpfileFree(f, hadErr, 1);
+}
+
+
+static void     testOneUnlinkedFile(int id, int running)
+{
+char            path[1024];
+cmpfile_t       *f;
+int                     w, i, l, i1, l1;
+btbool          hadErr = 1;
+const char		*root = random_root();
+
+		if (noUnlinkOpenFiles)	/* Not supported */
+			return;
+        random_path(path, id, running, root);
+        f = cmpfileNew(path, root);
+        l1 = random_gauss(50,5000);
+
+        // Perform unlinked file operations
+        w = random_int(3);
+        if(!fileIsWritable(f->refFile))
+                w = 0;
+        w = w != 0;
+        if(!cmpfileOpen(f, w, nocache))
+                goto errorOccured;
+        if(!cmpfileUnlink(f))
+                goto errorOccured;
+        for(i1=0;i1<l1;i1++){
+                l = random_gauss(20, 5000);
+                for(i=0;i<l;i++){
+					if(!randomUnlinkOp(f, w, id, running)) 
+						goto errorOccured;
+                }
+        }
+
+        hadErr = 0;
+errorOccured:
+        cmpfileFree(f, hadErr, 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static btbool	randomDirOp(cmpdir_t *d, int id, int running)
+{
+btbool	rval = 1;
+char	path[1024];
+
+	switch(random_int(4)){
+	case 0:	/* rename */
+			random_path(path, id, running, random_root());
+			rval = cmpdirRename(d, path, WinVolume);
+		break;
+	case 1:	/* change files */
+		rval = cmpdirChangeFiles(d);
+		break;
+	case 2:	/* verify files */
+		rval = cmpdirVerifyFiles(d);
+		break;
+	case 3:	/* sleep */
+		if (sleepy) {
+			if(!random_int(8)){
+				usleep(1000000 * random_gauss(1, 200));
+		}
+			}
+	}
+	return rval;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void	testOneDirectory(int id, int running)
+{
+char		path[1024];
+cmpdir_t	*d;
+int			i, l;
+btbool		hadErr = 1;
+
+	random_path(path, id, running, random_root());
+	d = cmpdirNew(path);
+	if(d == NULL){
+		printf("Sleeping 1sec\n");
+		sleep(1);
+		return;
+	}
+	l = random_gauss(150, 5000);
+	for(i=0;i<l;i++){
+		if(!randomDirOp(d, id, running))
+			goto errorOccured;
+	}
+	hadErr = 0;
+errorOccured:
+	cmpdirFree(d);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void    testproc(int id, int isParent, int n)
+{
+	int             i = 0;
+
+	if (isParent)
+		parent_pid = getpid();
+	random_init(11 + id, 23, 234 + id, 78);
+
+	if ((gStopTime != 0) || (count != 0)) { // We are timing/counting this run
+		if (gStopTime != 0) 
+			gStopTime += (isParent ? 5 : 0); // parent quits 5sec after children
+		while((time(NULL) < gStopTime) || (count > 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 <root dir1> <root dir2> <number of processes> [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, "<number of processes> 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<argc;i++){
+		if(strcmp(argv[i], "fsync_before_ftruncate") == 0){
+			bugFtruncateSync = 1;
+		}else if(strcmp(argv[i], "no_rename_open_files") == 0){
+			noRenameOpenFiles = 1;
+		}else if(strcmp(argv[i], "no_unlink_open_files") == 0){
+			noUnlinkOpenFiles = 1;			
+		}else if(strcmp(argv[i], "no_test_dirs") == 0){
+			noTestDirs = 1;
+		}else if(strcmp(argv[i], "windows_volume") == 0){
+			/* 
+			 * If Leopard or greater then this flag is not 
+			 * required.
+			 */
+			WinVolume = 1;
+			noPerms = 1;
+		}else if(strcmp(argv[i], "windows98") == 0){
+			noUnlinkOpenFiles = 1;
+			noRenameOpenFiles = 1;
+			WinVolume = 1;
+			noPerms = 1;
+		}else if((strcmp(argv[i],"no_stats")==0)||strcmp(argv[i],"nostats")==0) {
+			noStats = 1;
+		}else if((strcmp(argv[i],"no_perms")==0)||strcmp(argv[i],"noperms")==0) {
+			noPerms = 1;
+		} else if(strcmp(argv[i], "nocache") == 0) {
+			nocache = 1;
+		} else if(strcmp(argv[i], "acl") == 0) {
+			acl = 1;
+		} else if(strcmp(argv[i], "nosoftlinks") == 0) {
+			softlinks = 0;
+		} else if(strcmp(argv[i], "nohardlinks") == 0) {
+			hardlinks = 0;
+		} else if(strcmp(argv[i], "-v") == 0) {
+			trace = 1;
+		} else if((strcmp(argv[i],"count")==0)||(strcmp(argv[i],"-c")==0)) {
+			if (argv[++i]) 
+				count = atoi(argv[i]);
+                } else if((strcmp(argv[i],"time")==0)||(strcmp(argv[i],"-t")==0)) {
+			if (argv[i+1]) {
+				gStopTime = parsetime(argv[++i]);
+				if (gStopTime == 0) {
+					printf("-t needs a proper time argument!\n");
+					exit(-1);
+				}
+				gStopTime += time(NULL);
+			} else {
+				printf("-t needs a time argument!\n");
+				exit(-1);
+			}
+		}else if(strcmp(argv[i], "sleep") == 0) {
+			sleepy = 1;
+		}
+#ifdef XILOG
+		else {
+			if(strcmp(argv[i], "-x") == 0) {
+				gXML = true;
+			}
+			else if(strcmp(argv[i], "-e") == 0) {
+				gEcho = true;
+			}
+			else if(strcmp(argv[i], "-l") == 0) {
+				gLogPath = argv[++i];
+			}
+#endif /* XILOG */
+			else {
+				if ((i == 4) && (isdigit(argv[4][0]))) { // for legacy pid
+					continue;
+				} else {
+					fprintf(stderr, "option ->%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<THREADS;i++){
+			pthread_create(&thr[i], NULL, thr_start, NULL);
+		}
+	}
+
+#ifdef XILOG
+	char argline[1024]; bzero(argline, 1024);
+	strcpy(argline, "Arguments: ");
+	int j;
+	for (j=1; j<argc; j++) {
+		sprintf(argline, "%s %s", argline, argv[j]);
+	}
+	gLogRef = XILogOpenLogExtended(gLogPath, "fstorture", "com.apple.xintegration", NULL, gXML,gEcho, NULL,"ResultOwner","com.apple.fstorture",NULL);
+	if(gLogRef == NULL) {
+		fprintf(stderr, "Couldn't create log for path: %s\n", gLogPath);
+		exit(1);
+	}
+	XILogEnableMultithreaded(gLogRef);
+	XILogBeginTestCase(gLogRef, argline, "Test random file operations");
+	XILogMsg("Test started [fstorture %s]", VERS);
+#endif /* XILOG */
+
+
+	printf("Test started   [fstorture %s]: ", VERS); fflush(NULL);
+	system("date");
+	if (bugFtruncateSync)
+		printf("Forcing fsync before ftruncate\n");
+	if (noRenameOpenFiles)
+		printf("Disabling rename of open files\n");
+	if (noTestDirs)
+		printf("Not using test directories\n");
+	if (WinVolume)
+		printf("Running test on a Windows Volume\n");
+	if (noStats)
+		printf("Disabling stats (and file permissions checks)\n");
+	if (noPerms)
+		printf("Disabling file permissions checks\n");
+	if (nocache)
+		printf("Setting fcntl(F_NOCACHE) after open\n");
+	if (acl)
+		printf("Running ACL busting\n");
+	if (softlinks==0)
+		printf("Disabling soft links\n");
+	if (hardlinks==0)
+		printf("Disabling hard links\n");
+	if (count != 0)
+		printf("Running for %d cycle%s\n", count, (count >= 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<n-1;i++){ // n is the number of processes (argv[3])
+		if(fork() == 0){        /* we are the child */
+			testproc(i, 0, n);
+			exit(0);
+		}
+	}
+	testproc(i, 1, n);            /* the last process is the parent */
+
+#ifdef XILOG
+	XILogEndTestCase(gLogRef, kXILogTestPassOnErrorLevel);
+	XILogCloseLog(gLogRef);
+#endif /* XILOG */
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void cleanup(int sig) {
+#ifdef XILOG
+	XILogEndTestCase(gLogRef, kXILogTestPassOnErrorLevel);
+	XILogCloseLog(gLogRef);
+#endif /* XILOG */
+	if (getpid() == parent_pid) {
+		if (sig)
+			printf("<- Got signal %d\n", sig);
+		printf("testcall cycles = %d\n", mycount);
+/* Test case is closed
+#ifdef XILOG
+		if (sig)
+			XILogMsg("signal %d\n", sig);
+		XILogMsg("testcall cycles = %d\n", mycount);
+#endif
+*/
+	}
+	exit(0);
+}

Added: trunk/src/fstorture/stdheaders.h
===================================================================
--- trunk/src/fstorture/stdheaders.h	                        (rev 0)
+++ trunk/src/fstorture/stdheaders.h	2010-02-26 16:28:43 UTC (rev 5)
@@ -0,0 +1,43 @@
+/*
+ * Name: stdheaders.h
+ * Project: CIFS Client Automatic Test
+ * Author: Christian Starkjohann <cs at obdev.at>
+ * 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 <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <membership.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef NeXT
+#	include <libc.h>
+#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 <cs at obdev.at>
+# 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 <directory-to-test>"
+	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 <cs at obdev.at>
+ * 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: <http://lists.macosforge.org/pipermail/fstools-changes/attachments/20100226/00efb2cb/attachment-0001.html>


More information about the Fstools-changes mailing list