[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