diff -urN oldtree/fs/Kconfig newtree/fs/Kconfig --- oldtree/fs/Kconfig 2006-01-28 16:36:00.000000000 +0000 +++ newtree/fs/Kconfig 2006-01-28 18:23:21.807816368 +0000 @@ -1288,6 +1288,16 @@ Say Y here if you want to try writing to UFS partitions. This is experimental, so you should back up your UFS partitions beforehand. +config UNION_FS + tristate "Union fs support" + depends on EXPERIMENTAL + help + Unionfs is a stackable unification file system, which can + appear to merge the contents of several directories (branches), + while keeping their physical content separate. + + see for details + endmenu menu "Network File Systems" diff -urN oldtree/fs/Kconfig.orig newtree/fs/Kconfig.orig --- oldtree/fs/Kconfig.orig 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/Kconfig.orig 2006-01-28 18:23:21.803816976 +0000 @@ -0,0 +1,1791 @@ +# +# File system configuration +# + +menu "File systems" + +config EXT2_FS + tristate "Second extended fs support" + help + Ext2 is a standard Linux file system for hard disks. + + To compile this file system support as a module, choose M here: the + module will be called ext2. Be aware however that the file system + of your root partition (the one containing the directory /) cannot + be compiled as a module, and so this could be dangerous. + + If unsure, say Y. + +config EXT2_FS_XATTR + bool "Ext2 extended attributes" + depends on EXT2_FS + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + for details). + + If unsure, say N. + +config EXT2_FS_POSIX_ACL + bool "Ext2 POSIX Access Control Lists" + depends on EXT2_FS_XATTR + select FS_POSIX_ACL + help + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N + +config EXT2_FS_SECURITY + bool "Ext2 Security Labels" + depends on EXT2_FS_XATTR + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the ext2 filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. + +config EXT2_FS_XIP + bool "Ext2 execute in place support" + depends on EXT2_FS + help + Execute in place can be used on memory-backed block devices. If you + enable this option, you can select to mount block devices which are + capable of this feature without using the page cache. + + If you do not use a block device that is capable of using this, + or if unsure, say N. + +config FS_XIP +# execute in place + bool + depends on EXT2_FS_XIP + default y + +config EXT3_FS + tristate "Ext3 journalling file system support" + help + This is the journaling version of the Second extended file system + (often called ext3), the de facto standard Linux file system + (method to organize files on a storage device) for hard disks. + + The journaling code included in this driver means you do not have + to run e2fsck (file system checker) on your file systems after a + crash. The journal keeps track of any changes that were being made + at the time the system crashed, and can ensure that your file system + is consistent without the need for a lengthy check. + + Other than adding the journal to the file system, the on-disk format + of ext3 is identical to ext2. It is possible to freely switch + between using the ext3 driver and the ext2 driver, as long as the + file system has been cleanly unmounted, or e2fsck is run on the file + system. + + To add a journal on an existing ext2 file system or change the + behavior of ext3 file systems, you can use the tune2fs utility ("man + tune2fs"). To modify attributes of files and directories on ext3 + file systems, use chattr ("man chattr"). You need to be using + e2fsprogs version 1.20 or later in order to create ext3 journals + (available at ). + + To compile this file system support as a module, choose M here: the + module will be called ext3. Be aware however that the file system + of your root partition (the one containing the directory /) cannot + be compiled as a module, and so this may be dangerous. + +config EXT3_FS_XATTR + bool "Ext3 extended attributes" + depends on EXT3_FS + default y + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + for details). + + If unsure, say N. + + You need this for POSIX ACL support on ext3. + +config EXT3_FS_POSIX_ACL + bool "Ext3 POSIX Access Control Lists" + depends on EXT3_FS_XATTR + select FS_POSIX_ACL + help + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N + +config EXT3_FS_SECURITY + bool "Ext3 Security Labels" + depends on EXT3_FS_XATTR + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the ext3 filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. + +config JBD +# CONFIG_JBD could be its own option (even modular), but until there are +# other users than ext3, we will simply make it be the same as CONFIG_EXT3_FS +# dep_tristate ' Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS + tristate + default EXT3_FS + help + This is a generic journaling layer for block devices. It is + currently used by the ext3 file system, but it could also be used to + add journal support to other file systems or block devices such as + RAID or LVM. + + If you are using the ext3 file system, you need to say Y here. If + you are not using ext3 then you will probably want to say N. + + To compile this device as a module, choose M here: the module will be + called jbd. If you are compiling ext3 into the kernel, you cannot + compile this code as a module. + +config JBD_DEBUG + bool "JBD (ext3) debugging support" + depends on JBD + help + If you are using the ext3 journaled file system (or potentially any + other file system/device using JBD), this option allows you to + enable debugging output while the system is running, in order to + help track down any problems you are having. By default the + debugging output will be turned off. + + If you select Y here, then you will be able to turn on debugging + with "echo N > /proc/sys/fs/jbd-debug", where N is a number between + 1 and 5, the higher the number, the more debugging output is + generated. To turn debugging off again, do + "echo 0 > /proc/sys/fs/jbd-debug". + +config FS_MBCACHE +# Meta block cache for Extended Attributes (ext2/ext3) + tristate + depends on EXT2_FS_XATTR || EXT3_FS_XATTR + default y if EXT2_FS=y || EXT3_FS=y + default m if EXT2_FS=m || EXT3_FS=m + +config REISERFS_FS + tristate "Reiserfs support" + help + Stores not just filenames but the files themselves in a balanced + tree. Uses journaling. + + Balanced trees are more efficient than traditional file system + architectural foundations. + + In general, ReiserFS is as fast as ext2, but is very efficient with + large directories and small files. Additional patches are needed + for NFS and quotas, please see for links. + + It is more easily extended to have features currently found in + database and keyword search systems than block allocation based file + systems are. The next version will be so extended, and will support + plugins consistent with our motto ``It takes more than a license to + make source code open.'' + + Read to learn more about reiserfs. + + Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com. + + If you like it, you can pay us to add new features to it that you + need, buy a support contract, or pay us to port it to another OS. + +config REISERFS_CHECK + bool "Enable reiserfs debug mode" + depends on REISERFS_FS + help + If you set this to Y, then ReiserFS will perform every check it can + possibly imagine of its internal consistency throughout its + operation. It will also go substantially slower. More than once we + have forgotten that this was on, and then gone despondent over the + latest benchmarks.:-) Use of this option allows our team to go all + out in checking for consistency when debugging without fear of its + effect on end users. If you are on the verge of sending in a bug + report, say Y and you might get a useful error message. Almost + everyone should say N. + +config REISERFS_PROC_INFO + bool "Stats in /proc/fs/reiserfs" + depends on REISERFS_FS + help + Create under /proc/fs/reiserfs a hierarchy of files, displaying + various ReiserFS statistics and internal data at the expense of + making your kernel or module slightly larger (+8 KB). This also + increases the amount of kernel memory required for each mount. + Almost everyone but ReiserFS developers and people fine-tuning + reiserfs or tracing problems should say N. + +config REISERFS_FS_XATTR + bool "ReiserFS extended attributes" + depends on REISERFS_FS + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + for details). + + If unsure, say N. + +config REISERFS_FS_POSIX_ACL + bool "ReiserFS POSIX Access Control Lists" + depends on REISERFS_FS_XATTR + select FS_POSIX_ACL + help + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N + +config REISERFS_FS_SECURITY + bool "ReiserFS Security Labels" + depends on REISERFS_FS_XATTR + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the ReiserFS filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. + +config JFS_FS + tristate "JFS filesystem support" + select NLS + help + This is a port of IBM's Journaled Filesystem . More information is + available in the file . + + If you do not intend to use the JFS filesystem, say N. + +config JFS_POSIX_ACL + bool "JFS POSIX Access Control Lists" + depends on JFS_FS + select FS_POSIX_ACL + help + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N + +config JFS_SECURITY + bool "JFS Security Labels" + depends on JFS_FS + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the jfs filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. + +config JFS_DEBUG + bool "JFS debugging" + depends on JFS_FS + help + If you are experiencing any problems with the JFS filesystem, say + Y here. This will result in additional debugging messages to be + written to the system log. Under normal circumstances, this + results in very little overhead. + +config JFS_STATISTICS + bool "JFS statistics" + depends on JFS_FS + help + Enabling this option will cause statistics from the JFS file system + to be made available to the user in the /proc/fs/jfs/ directory. + +config FS_POSIX_ACL +# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs) +# +# NOTE: you can implement Posix ACLs without these helpers (XFS does). +# Never use this symbol for ifdefs. +# + bool + default n + +source "fs/xfs/Kconfig" + +config MINIX_FS + tristate "Minix fs support" + help + Minix is a simple operating system used in many classes about OS's. + The minix file system (method to organize files on a hard disk + partition or a floppy disk) was the original file system for Linux, + but has been superseded by the second extended file system ext2fs. + You don't want to use the minix file system on your hard disk + because of certain built-in restrictions, but it is sometimes found + on older Linux floppy disks. This option will enlarge your kernel + by about 28 KB. If unsure, say N. + + To compile this file system support as a module, choose M here: the + module will be called minix. Note that the file system of your root + partition (the one containing the directory /) cannot be compiled as + a module. + +config ROMFS_FS + tristate "ROM file system support" + ---help--- + This is a very small read-only file system mainly intended for + initial ram disks of installation disks, but it could be used for + other read-only media as well. Read + for details. + + To compile this file system support as a module, choose M here: the + module will be called romfs. Note that the file system of your + root partition (the one containing the directory /) cannot be a + module. + + If you don't know whether you need it, then you don't need it: + answer N. + +config INOTIFY + bool "Inotify file change notification support" + default y + ---help--- + Say Y here to enable inotify support and the associated system + calls. Inotify is a file change notification system and a + replacement for dnotify. Inotify fixes numerous shortcomings in + dnotify and introduces several new features. It allows monitoring + of both files and directories via a single open fd. Other features + include multiple file events, one-shot support, and unmount + notification. + + For more information, see Documentation/filesystems/inotify.txt + + If unsure, say Y. + +config QUOTA + bool "Quota support" + help + If you say Y here, you will be able to set per user limits for disk + usage (also called disk quotas). Currently, it works for the + ext2, ext3, and reiserfs file system. ext3 also supports journalled + quotas for which you don't need to run quotacheck(8) after an unclean + shutdown. + For further details, read the Quota mini-HOWTO, available from + , or the documentation provided + with the quota tools. Probably the quota support is only useful for + multi user systems. If unsure, say N. + +config QFMT_V1 + tristate "Old quota format support" + depends on QUOTA + help + This quota format was (is) used by kernels earlier than 2.4.22. If + you have quota working and you don't want to convert to new quota + format say Y here. + +config QFMT_V2 + tristate "Quota format v2 support" + depends on QUOTA + help + This quota format allows using quotas with 32-bit UIDs/GIDs. If you + need this functionality say Y here. + +config QUOTACTL + bool + depends on XFS_QUOTA || QUOTA + default y + +config DNOTIFY + bool "Dnotify support" if EMBEDDED + default y + help + Dnotify is a directory-based per-fd file change notification system + that uses signals to communicate events to user-space. There exist + superior alternatives, but some applications may still rely on + dnotify. + + Because of this, if unsure, say Y. + +config AUTOFS_FS + tristate "Kernel automounter support" + help + The automounter is a tool to automatically mount remote file systems + on demand. This implementation is partially kernel-based to reduce + overhead in the already-mounted case; this is unlike the BSD + automounter (amd), which is a pure user space daemon. + + To use the automounter you need the user-space tools from the autofs + package; you can find the location in . + You also want to answer Y to "NFS file system support", below. + + If you want to use the newer version of the automounter with more + features, say N here and say Y to "Kernel automounter v4 support", + below. + + To compile this support as a module, choose M here: the module will be + called autofs. + + If you are not a part of a fairly large, distributed network, you + probably do not need an automounter, and can say N here. + +config AUTOFS4_FS + tristate "Kernel automounter version 4 support (also supports v3)" + help + The automounter is a tool to automatically mount remote file systems + on demand. This implementation is partially kernel-based to reduce + overhead in the already-mounted case; this is unlike the BSD + automounter (amd), which is a pure user space daemon. + + To use the automounter you need the user-space tools from + ; you also + want to answer Y to "NFS file system support", below. + + To compile this support as a module, choose M here: the module will be + called autofs4. You will need to add "alias autofs autofs4" to your + modules configuration file. + + If you are not a part of a fairly large, distributed network or + don't have a laptop which needs to dynamically reconfigure to the + local network, you probably do not need an automounter, and can say + N here. + +config FUSE_FS + tristate "Filesystem in Userspace support" + help + With FUSE it is possible to implement a fully functional filesystem + in a userspace program. + + There's also companion library: libfuse. This library along with + utilities is available from the FUSE homepage: + + + See for more information. + See for needed library/utility version. + + If you want to develop a userspace FS, or if you want to use + a filesystem based on FUSE, answer Y or M. + +menu "CD-ROM/DVD Filesystems" + +config ISO9660_FS + tristate "ISO 9660 CDROM file system support" + help + This is the standard file system used on CD-ROMs. It was previously + known as "High Sierra File System" and is called "hsfs" on other + Unix systems. The so-called Rock-Ridge extensions which allow for + long Unix filenames and symbolic links are also supported by this + driver. If you have a CD-ROM drive and want to do more with it than + just listen to audio CDs and watch its LEDs, say Y (and read + and the CD-ROM-HOWTO, + available from ), thereby + enlarging your kernel by about 27 KB; otherwise say N. + + To compile this file system support as a module, choose M here: the + module will be called isofs. + +config JOLIET + bool "Microsoft Joliet CDROM extensions" + depends on ISO9660_FS + select NLS + help + Joliet is a Microsoft extension for the ISO 9660 CD-ROM file system + which allows for long filenames in unicode format (unicode is the + new 16 bit character code, successor to ASCII, which encodes the + characters of almost all languages of the world; see + for more information). Say Y here if you + want to be able to read Joliet CD-ROMs under Linux. + +config ZISOFS + bool "Transparent decompression extension" + depends on ISO9660_FS + select ZLIB_INFLATE + help + This is a Linux-specific extension to RockRidge which lets you store + data in compressed form on a CD-ROM and have it transparently + decompressed when the CD-ROM is accessed. See + for the tools + necessary to create such a filesystem. Say Y here if you want to be + able to read such compressed CD-ROMs. + +config ZISOFS_FS +# for fs/nls/Config.in + tristate + depends on ZISOFS + default ISO9660_FS + +config UDF_FS + tristate "UDF file system support" + help + This is the new file system used on some CD-ROMs and DVDs. Say Y if + you intend to mount DVD discs or CDRW's written in packet mode, or + if written to by other UDF utilities, such as DirectCD. + Please read . + + To compile this file system support as a module, choose M here: the + module will be called udf. + + If unsure, say N. + +config UDF_NLS + bool + default y + depends on (UDF_FS=m && NLS) || (UDF_FS=y && NLS=y) + +endmenu + +menu "DOS/FAT/NT Filesystems" + +config FAT_FS + tristate + select NLS + help + If you want to use one of the FAT-based file systems (the MS-DOS and + VFAT (Windows 95) file systems), then you must say Y or M here + to include FAT support. You will then be able to mount partitions or + diskettes with FAT-based file systems and transparently access the + files on them, i.e. MSDOS files will look and behave just like all + other Unix files. + + This FAT support is not a file system in itself, it only provides + the foundation for the other file systems. You will have to say Y or + M to at least one of "MSDOS fs support" or "VFAT fs support" in + order to make use of it. + + Another way to read and write MSDOS floppies and hard drive + partitions from within Linux (but not transparently) is with the + mtools ("man mtools") program suite. You don't need to say Y here in + order to do that. + + If you need to move large files on floppies between a DOS and a + Linux box, say Y here, mount the floppy under Linux with an MSDOS + file system and use GNU tar's M option. GNU tar is a program + available for Unix and DOS ("man tar" or "info tar"). + + It is now also becoming possible to read and write compressed FAT + file systems; read for + details. + + The FAT support will enlarge your kernel by about 37 KB. If unsure, + say Y. + + To compile this as a module, choose M here: the module will be called + fat. Note that if you compile the FAT support as a module, you + cannot compile any of the FAT-based file systems into the kernel + -- they will have to be modules as well. + +config MSDOS_FS + tristate "MSDOS fs support" + select FAT_FS + help + This allows you to mount MSDOS partitions of your hard drive (unless + they are compressed; to access compressed MSDOS partitions under + Linux, you can either use the DOS emulator DOSEMU, described in the + DOSEMU-HOWTO, available from + , or try dmsdosfs in + . If you + intend to use dosemu with a non-compressed MSDOS partition, say Y + here) and MSDOS floppies. This means that file access becomes + transparent, i.e. the MSDOS files look and behave just like all + other Unix files. + + If you have Windows 95 or Windows NT installed on your MSDOS + partitions, you should use the VFAT file system (say Y to "VFAT fs + support" below), or you will not be able to see the long filenames + generated by Windows 95 / Windows NT. + + This option will enlarge your kernel by about 7 KB. If unsure, + answer Y. This will only work if you said Y to "DOS FAT fs support" + as well. To compile this as a module, choose M here: the module will + be called msdos. + +config VFAT_FS + tristate "VFAT (Windows-95) fs support" + select FAT_FS + help + This option provides support for normal Windows file systems with + long filenames. That includes non-compressed FAT-based file systems + used by Windows 95, Windows 98, Windows NT 4.0, and the Unix + programs from the mtools package. + + The VFAT support enlarges your kernel by about 10 KB and it only + works if you said Y to the "DOS FAT fs support" above. Please read + the file for details. If + unsure, say Y. + + To compile this as a module, choose M here: the module will be called + vfat. + +config FAT_DEFAULT_CODEPAGE + int "Default codepage for FAT" + depends on MSDOS_FS || VFAT_FS + default 437 + help + This option should be set to the codepage of your FAT filesystems. + It can be overridden with the "codepage" mount option. + See for more information. + +config FAT_DEFAULT_IOCHARSET + string "Default iocharset for FAT" + depends on VFAT_FS + default "iso8859-1" + help + Set this to the default input/output character set you'd + like FAT to use. It should probably match the character set + that most of your FAT filesystems use, and can be overridden + with the "iocharset" mount option for FAT filesystems. + Note that "utf8" is not recommended for FAT filesystems. + If unsure, you shouldn't set "utf8" here. + See for more information. + +config NTFS_FS + tristate "NTFS file system support" + select NLS + help + NTFS is the file system of Microsoft Windows NT, 2000, XP and 2003. + + Saying Y or M here enables read support. There is partial, but + safe, write support available. For write support you must also + say Y to "NTFS write support" below. + + There are also a number of user-space tools available, called + ntfsprogs. These include ntfsundelete and ntfsresize, that work + without NTFS support enabled in the kernel. + + This is a rewrite from scratch of Linux NTFS support and replaced + the old NTFS code starting with Linux 2.5.11. A backport to + the Linux 2.4 kernel series is separately available as a patch + from the project web site. + + For more information see + and . + + To compile this file system support as a module, choose M here: the + module will be called ntfs. + + If you are not using Windows NT, 2000, XP or 2003 in addition to + Linux on your computer it is safe to say N. + +config NTFS_DEBUG + bool "NTFS debugging support" + depends on NTFS_FS + help + If you are experiencing any problems with the NTFS file system, say + Y here. This will result in additional consistency checks to be + performed by the driver as well as additional debugging messages to + be written to the system log. Note that debugging messages are + disabled by default. To enable them, supply the option debug_msgs=1 + at the kernel command line when booting the kernel or as an option + to insmod when loading the ntfs module. Once the driver is active, + you can enable debugging messages by doing (as root): + echo 1 > /proc/sys/fs/ntfs-debug + Replacing the "1" with "0" would disable debug messages. + + If you leave debugging messages disabled, this results in little + overhead, but enabling debug messages results in very significant + slowdown of the system. + + When reporting bugs, please try to have available a full dump of + debugging messages while the misbehaviour was occurring. + +config NTFS_RW + bool "NTFS write support" + depends on NTFS_FS + help + This enables the partial, but safe, write support in the NTFS driver. + + The only supported operation is overwriting existing files, without + changing the file length. No file or directory creation, deletion or + renaming is possible. Note only non-resident files can be written to + so you may find that some very small files (<500 bytes or so) cannot + be written to. + + While we cannot guarantee that it will not damage any data, we have + so far not received a single report where the driver would have + damaged someones data so we assume it is perfectly safe to use. + + Note: While write support is safe in this version (a rewrite from + scratch of the NTFS support), it should be noted that the old NTFS + write support, included in Linux 2.5.10 and before (since 1997), + is not safe. + + This is currently useful with TopologiLinux. TopologiLinux is run + on top of any DOS/Microsoft Windows system without partitioning your + hard disk. Unlike other Linux distributions TopologiLinux does not + need its own partition. For more information see + + + It is perfectly safe to say N here. + +endmenu + +menu "Pseudo filesystems" + +config PROC_FS + bool "/proc file system support" + help + This is a virtual file system providing information about the status + of the system. "Virtual" means that it doesn't take up any space on + your hard disk: the files are created on the fly by the kernel when + you try to access them. Also, you cannot read the files with older + version of the program less: you need to use more or cat. + + It's totally cool; for example, "cat /proc/interrupts" gives + information about what the different IRQs are used for at the moment + (there is a small number of Interrupt ReQuest lines in your computer + that are used by the attached devices to gain the CPU's attention -- + often a source of trouble if two devices are mistakenly configured + to use the same IRQ). The program procinfo to display some + information about your system gathered from the /proc file system. + + Before you can use the /proc file system, it has to be mounted, + meaning it has to be given a location in the directory hierarchy. + That location should be /proc. A command such as "mount -t proc proc + /proc" or the equivalent line in /etc/fstab does the job. + + The /proc file system is explained in the file + and on the proc(5) manpage + ("man 5 proc"). + + This option will enlarge your kernel by about 67 KB. Several + programs depend on this, so everyone should say Y here. + +config PROC_KCORE + bool "/proc/kcore support" if !ARM + depends on PROC_FS && MMU + +config PROC_VMCORE + bool "/proc/vmcore support (EXPERIMENTAL)" + depends on PROC_FS && EMBEDDED && EXPERIMENTAL && CRASH_DUMP + help + Exports the dump image of crashed kernel in ELF format. + +config SYSFS + bool "sysfs file system support" if EMBEDDED + default y + help + The sysfs filesystem is a virtual filesystem that the kernel uses to + export internal kernel objects, their attributes, and their + relationships to one another. + + Users can use sysfs to ascertain useful information about the running + kernel, such as the devices the kernel has discovered on each bus and + which driver each is bound to. sysfs can also be used to tune devices + and other kernel subsystems. + + Some system agents rely on the information in sysfs to operate. + /sbin/hotplug uses device and object attributes in sysfs to assist in + delegating policy decisions, like persistantly naming devices. + + sysfs is currently used by the block subsystem to mount the root + partition. If sysfs is disabled you must specify the boot device on + the kernel boot command line via its major and minor numbers. For + example, "root=03:01" for /dev/hda1. + + Designers of embedded systems may wish to say N here to conserve space. + +config TMPFS + bool "Virtual memory file system support (former shm fs)" + help + Tmpfs is a file system which keeps all files in virtual memory. + + Everything in tmpfs is temporary in the sense that no files will be + created on your hard drive. The files live in memory and swap + space. If you unmount a tmpfs instance, everything stored therein is + lost. + + See for details. + +config HUGETLBFS + bool "HugeTLB file system support" + depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN + +config HUGETLB_PAGE + def_bool HUGETLBFS + +config RAMFS + bool + default y + ---help--- + Ramfs is a file system which keeps all files in RAM. It allows + read and write access. + + It is more of an programming example than a useable file system. If + you need a file system which lives in RAM with limit checking use + tmpfs. + + To compile this as a module, choose M here: the module will be called + ramfs. + +config RELAYFS_FS + tristate "Relayfs file system support" + ---help--- + Relayfs is a high-speed data relay filesystem designed to provide + an efficient mechanism for tools and facilities to relay large + amounts of data from kernel space to user space. + + To compile this code as a module, choose M here: the module will be + called relayfs. + + If unsure, say N. + +endmenu + +menu "Miscellaneous filesystems" + +config ADFS_FS + tristate "ADFS file system support (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + The Acorn Disc Filing System is the standard file system of the + RiscOS operating system which runs on Acorn's ARM-based Risc PC + systems and the Acorn Archimedes range of machines. If you say Y + here, Linux will be able to read from ADFS partitions on hard drives + and from ADFS-formatted floppy discs. If you also want to be able to + write to those devices, say Y to "ADFS write support" below. + + The ADFS partition should be the first partition (i.e., + /dev/[hs]d?1) on each of your drives. Please read the file + for further details. + + To compile this code as a module, choose M here: the module will be + called adfs. + + If unsure, say N. + +config ADFS_FS_RW + bool "ADFS write support (DANGEROUS)" + depends on ADFS_FS + help + If you say Y here, you will be able to write to ADFS partitions on + hard drives and ADFS-formatted floppy disks. This is experimental + codes, so if you're unsure, say N. + +config AFFS_FS + tristate "Amiga FFS file system support (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + The Fast File System (FFS) is the common file system used on hard + disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20). Say Y + if you want to be able to read and write files from and to an Amiga + FFS partition on your hard drive. Amiga floppies however cannot be + read with this driver due to an incompatibility of the floppy + controller used in an Amiga and the standard floppy controller in + PCs and workstations. Read + and . + + With this driver you can also mount disk files used by Bernd + Schmidt's Un*X Amiga Emulator + (). + If you want to do this, you will also need to say Y or M to "Loop + device support", above. + + To compile this file system support as a module, choose M here: the + module will be called affs. If unsure, say N. + +config HFS_FS + tristate "Apple Macintosh file system support (EXPERIMENTAL)" + depends on EXPERIMENTAL + select NLS + help + If you say Y here, you will be able to mount Macintosh-formatted + floppy disks and hard drive partitions with full read-write access. + Please read to learn about the available mount + options. + + To compile this file system support as a module, choose M here: the + module will be called hfs. + +config HFSPLUS_FS + tristate "Apple Extended HFS file system support" + select NLS + select NLS_UTF8 + help + If you say Y here, you will be able to mount extended format + Macintosh-formatted hard drive partitions with full read-write access. + + This file system is often called HFS+ and was introduced with + MacOS 8. It includes all Mac specific filesystem data such as + data forks and creator codes, but it also has several UNIX + style features such as file ownership and permissions. + +config BEFS_FS + tristate "BeOS file system (BeFS) support (read only) (EXPERIMENTAL)" + depends on EXPERIMENTAL + select NLS + help + The BeOS File System (BeFS) is the native file system of Be, Inc's + BeOS. Notable features include support for arbitrary attributes + on files and directories, and database-like indeces on selected + attributes. (Also note that this driver doesn't make those features + available at this time). It is a 64 bit filesystem, so it supports + extremly large volumes and files. + + If you use this filesystem, you should also say Y to at least one + of the NLS (native language support) options below. + + If you don't know what this is about, say N. + + To compile this as a module, choose M here: the module will be + called befs. + +config BEFS_DEBUG + bool "Debug BeFS" + depends on BEFS_FS + help + If you say Y here, you can use the 'debug' mount option to enable + debugging output from the driver. + +config BFS_FS + tristate "BFS file system support (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + Boot File System (BFS) is a file system used under SCO UnixWare to + allow the bootloader access to the kernel image and other important + files during the boot process. It is usually mounted under /stand + and corresponds to the slice marked as "STAND" in the UnixWare + partition. You should say Y if you want to read or write the files + on your /stand slice from within Linux. You then also need to say Y + to "UnixWare slices support", below. More information about the BFS + file system is contained in the file + . + + If you don't know what this is about, say N. + + To compile this as a module, choose M here: the module will be called + bfs. Note that the file system of your root partition (the one + containing the directory /) cannot be compiled as a module. + + + +config EFS_FS + tristate "EFS file system support (read only) (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + EFS is an older file system used for non-ISO9660 CD-ROMs and hard + disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer + uses the XFS file system for hard disk partitions however). + + This implementation only offers read-only access. If you don't know + what all this is about, it's safe to say N. For more information + about EFS see its home page at . + + To compile the EFS file system support as a module, choose M here: the + module will be called efs. + +config JFFS_FS + tristate "Journalling Flash File System (JFFS) support" + depends on MTD + help + JFFS is the Journaling Flash File System developed by Axis + Communications in Sweden, aimed at providing a crash/powerdown-safe + file system for disk-less embedded devices. Further information is + available at (). + +config JFFS_FS_VERBOSE + int "JFFS debugging verbosity (0 = quiet, 3 = noisy)" + depends on JFFS_FS + default "0" + help + Determines the verbosity level of the JFFS debugging messages. + +config JFFS_PROC_FS + bool "JFFS stats available in /proc filesystem" + depends on JFFS_FS && PROC_FS + help + Enabling this option will cause statistics from mounted JFFS file systems + to be made available to the user in the /proc/fs/jffs/ directory. + +config JFFS2_FS + tristate "Journalling Flash File System v2 (JFFS2) support" + select CRC32 + depends on MTD + help + JFFS2 is the second generation of the Journalling Flash File System + for use on diskless embedded devices. It provides improved wear + levelling, compression and support for hard links. You cannot use + this on normal block devices, only on 'MTD' devices. + + Further information on the design and implementation of JFFS2 is + available at . + +config JFFS2_FS_DEBUG + int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)" + depends on JFFS2_FS + default "0" + help + This controls the amount of debugging messages produced by the JFFS2 + code. Set it to zero for use in production systems. For evaluation, + testing and debugging, it's advisable to set it to one. This will + enable a few assertions and will print debugging messages at the + KERN_DEBUG loglevel, where they won't normally be visible. Level 2 + is unlikely to be useful - it enables extra debugging in certain + areas which at one point needed debugging, but when the bugs were + located and fixed, the detailed messages were relegated to level 2. + + If reporting bugs, please try to have available a full dump of the + messages at debug level 1 while the misbehaviour was occurring. + +config JFFS2_FS_WRITEBUFFER + bool "JFFS2 write-buffering support" + depends on JFFS2_FS + default y + help + This enables the write-buffering support in JFFS2. + + This functionality is required to support JFFS2 on the following + types of flash devices: + - NAND flash + - NOR flash with transparent ECC + - DataFlash + +config JFFS2_SUMMARY + bool "JFFS2 summary support (EXPERIMENTAL)" + depends on JFFS2_FS && EXPERIMENTAL + default n + help + This feature makes it possible to use summary information + for faster filesystem mount. + + The summary information can be inserted into a filesystem image + by the utility 'sumtool'. + + If unsure, say 'N'. + +config JFFS2_COMPRESSION_OPTIONS + bool "Advanced compression options for JFFS2" + depends on JFFS2_FS + default n + help + Enabling this option allows you to explicitly choose which + compression modules, if any, are enabled in JFFS2. Removing + compressors and mean you cannot read existing file systems, + and enabling experimental compressors can mean that you + write a file system which cannot be read by a standard kernel. + + If unsure, you should _definitely_ say 'N'. + +config JFFS2_ZLIB + bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS + select ZLIB_INFLATE + select ZLIB_DEFLATE + depends on JFFS2_FS + default y + help + Zlib is designed to be a free, general-purpose, legally unencumbered, + lossless data-compression library for use on virtually any computer + hardware and operating system. See for + further information. + + Say 'Y' if unsure. + +config JFFS2_RTIME + bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS + default y + help + Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. + +config JFFS2_RUBIN + bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS + default n + help + RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. + +choice + prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS + default JFFS2_CMODE_PRIORITY + depends on JFFS2_FS + help + You can set here the default compression mode of JFFS2 from + the available compression modes. Don't touch if unsure. + +config JFFS2_CMODE_NONE + bool "no compression" + help + Uses no compression. + +config JFFS2_CMODE_PRIORITY + bool "priority" + help + Tries the compressors in a predefinied order and chooses the first + successful one. + +config JFFS2_CMODE_SIZE + bool "size (EXPERIMENTAL)" + help + Tries all compressors and chooses the one which has the smallest + result. + +endchoice + +config CRAMFS + tristate "Compressed ROM file system support (cramfs)" + select ZLIB_INFLATE + help + Saying Y here includes support for CramFs (Compressed ROM File + System). CramFs is designed to be a simple, small, and compressed + file system for ROM based embedded systems. CramFs is read-only, + limited to 256MB file systems (with 16MB files), and doesn't support + 16/32 bits uid/gid, hard links and timestamps. + + See and + for further information. + + To compile this as a module, choose M here: the module will be called + cramfs. Note that the root file system (the one containing the + directory /) cannot be compiled as a module. + + If unsure, say N. + +config VXFS_FS + tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" + help + FreeVxFS is a file system driver that support the VERITAS VxFS(TM) + file system format. VERITAS VxFS(TM) is the standard file system + of SCO UnixWare (and possibly others) and optionally available + for Sunsoft Solaris, HP-UX and many other operating systems. + Currently only readonly access is supported. + + NOTE: the file system type as used by mount(1), mount(2) and + fstab(5) is 'vxfs' as it describes the file system format, not + the actual driver. + + To compile this as a module, choose M here: the module will be + called freevxfs. If unsure, say N. + + +config HPFS_FS + tristate "OS/2 HPFS file system support" + help + OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS + is the file system used for organizing files on OS/2 hard disk + partitions. Say Y if you want to be able to read files from and + write files to an OS/2 HPFS partition on your hard drive. OS/2 + floppies however are in regular MSDOS format, so you don't need this + option in order to be able to read them. Read + . + + To compile this file system support as a module, choose M here: the + module will be called hpfs. If unsure, say N. + + + +config QNX4FS_FS + tristate "QNX4 file system support (read only)" + help + This is the file system used by the real-time operating systems + QNX 4 and QNX 6 (the latter is also called QNX RTP). + Further information is available at . + Say Y if you intend to mount QNX hard disks or floppies. + Unless you say Y to "QNX4FS read-write support" below, you will + only be able to read these file systems. + + To compile this file system support as a module, choose M here: the + module will be called qnx4. + + If you don't know whether you need it, then you don't need it: + answer N. + +config QNX4FS_RW + bool "QNX4FS write support (DANGEROUS)" + depends on QNX4FS_FS && EXPERIMENTAL && BROKEN + help + Say Y if you want to test write support for QNX4 file systems. + + It's currently broken, so for now: + answer N. + + + +config SYSV_FS + tristate "System V/Xenix/V7/Coherent file system support" + help + SCO, Xenix and Coherent are commercial Unix systems for Intel + machines, and Version 7 was used on the DEC PDP-11. Saying Y + here would allow you to read from their floppies and hard disk + partitions. + + If you have floppies or hard disk partitions like that, it is likely + that they contain binaries from those other Unix systems; in order + to run these binaries, you will want to install linux-abi which is a + a set of kernel modules that lets you run SCO, Xenix, Wyse, + UnixWare, Dell Unix and System V programs under Linux. It is + available via FTP (user: ftp) from + ). + NOTE: that will work only for binaries from Intel-based systems; + PDP ones will have to wait until somebody ports Linux to -11 ;-) + + If you only intend to mount files from some other Unix over the + network using NFS, you don't need the System V file system support + (but you need NFS file system support obviously). + + Note that this option is generally not needed for floppies, since a + good portable way to transport files and directories between unixes + (and even other operating systems) is given by the tar program ("man + tar" or preferably "info tar"). Note also that this option has + nothing whatsoever to do with the option "System V IPC". Read about + the System V file system in + . + Saying Y here will enlarge your kernel by about 27 KB. + + To compile this as a module, choose M here: the module will be called + sysv. + + If you haven't heard about all of this before, it's safe to say N. + + + +config UFS_FS + tristate "UFS file system support (read only)" + help + BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD, + OpenBSD and NeXTstep) use a file system called UFS. Some System V + Unixes can create and mount hard disk partitions and diskettes using + this file system as well. Saying Y here will allow you to read from + these partitions; if you also want to write to them, say Y to the + experimental "UFS file system write support", below. Please read the + file for more information. + + The recently released UFS2 variant (used in FreeBSD 5.x) is + READ-ONLY supported. + + If you only intend to mount files from some other Unix over the + network using NFS, you don't need the UFS file system support (but + you need NFS file system support obviously). + + Note that this option is generally not needed for floppies, since a + good portable way to transport files and directories between unixes + (and even other operating systems) is given by the tar program ("man + tar" or preferably "info tar"). + + When accessing NeXTstep files, you may need to convert them from the + NeXT character set to the Latin1 character set; use the program + recode ("info recode") for this purpose. + + To compile the UFS file system support as a module, choose M here: the + module will be called ufs. + + If you haven't heard about all of this before, it's safe to say N. + +config UFS_FS_WRITE + bool "UFS file system write support (DANGEROUS)" + depends on UFS_FS && EXPERIMENTAL + help + Say Y here if you want to try writing to UFS partitions. This is + experimental, so you should back up your UFS partitions beforehand. + +endmenu + +menu "Network File Systems" + depends on NET + +config NFS_FS + tristate "NFS file system support" + depends on INET + select LOCKD + select SUNRPC + select NFS_ACL_SUPPORT if NFS_V3_ACL + help + If you are connected to some other (usually local) Unix computer + (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing + on that computer (the NFS server) using the Network File Sharing + protocol, say Y. "Mounting files" means that the client can access + the files with usual UNIX commands as if they were sitting on the + client's hard disk. For this to work, the server must run the + programs nfsd and mountd (but does not need to have NFS file system + support enabled in its kernel). NFS is explained in the Network + Administrator's Guide, available from + , on its man page: "man + nfs", and in the NFS-HOWTO. + + A superior but less widely used alternative to NFS is provided by + the Coda file system; see "Coda file system support" below. + + If you say Y here, you should have said Y to TCP/IP networking also. + This option would enlarge your kernel by about 27 KB. + + To compile this file system support as a module, choose M here: the + module will be called nfs. + + If you are configuring a diskless machine which will mount its root + file system over NFS at boot time, say Y here and to "Kernel + level IP autoconfiguration" above and to "Root file system on NFS" + below. You cannot compile this driver as a module in this case. + There are two packages designed for booting diskless machines over + the net: netboot, available from + , and Etherboot, + available from . + + If you don't know what all this is about, say N. + +config NFS_V3 + bool "Provide NFSv3 client support" + depends on NFS_FS + help + Say Y here if you want your NFS client to be able to speak version + 3 of the NFS protocol. + + If unsure, say Y. + +config NFS_V3_ACL + bool "Provide client support for the NFSv3 ACL protocol extension" + depends on NFS_V3 + help + Implement the NFSv3 ACL protocol extension for manipulating POSIX + Access Control Lists. The server should also be compiled with + the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option. + + If unsure, say N. + +config NFS_V4 + bool "Provide NFSv4 client support (EXPERIMENTAL)" + depends on NFS_FS && EXPERIMENTAL + select RPCSEC_GSS_KRB5 + help + Say Y here if you want your NFS client to be able to speak the newer + version 4 of the NFS protocol. + + Note: Requires auxiliary userspace daemons which may be found on + http://www.citi.umich.edu/projects/nfsv4/ + + If unsure, say N. + +config NFS_DIRECTIO + bool "Allow direct I/O on NFS files (EXPERIMENTAL)" + depends on NFS_FS && EXPERIMENTAL + help + This option enables applications to perform uncached I/O on files + in NFS file systems using the O_DIRECT open() flag. When O_DIRECT + is set for a file, its data is not cached in the system's page + cache. Data is moved to and from user-level application buffers + directly. Unlike local disk-based file systems, NFS O_DIRECT has + no alignment restrictions. + + Unless your program is designed to use O_DIRECT properly, you are + much better off allowing the NFS client to manage data caching for + you. Misusing O_DIRECT can cause poor server performance or network + storms. This kernel build option defaults OFF to avoid exposing + system administrators unwittingly to a potentially hazardous + feature. + + For more details on NFS O_DIRECT, see fs/nfs/direct.c. + + If unsure, say N. This reduces the size of the NFS client, and + causes open() to return EINVAL if a file residing in NFS is + opened with the O_DIRECT flag. + +config NFSD + tristate "NFS server support" + depends on INET + select LOCKD + select SUNRPC + select EXPORTFS + select NFS_ACL_SUPPORT if NFSD_V3_ACL || NFSD_V2_ACL + help + If you want your Linux box to act as an NFS *server*, so that other + computers on your local network which support NFS can access certain + directories on your box transparently, you have two options: you can + use the self-contained user space program nfsd, in which case you + should say N here, or you can say Y and use the kernel based NFS + server. The advantage of the kernel based solution is that it is + faster. + + In either case, you will need support software; the respective + locations are given in the file in the + NFS section. + + If you say Y here, you will get support for version 2 of the NFS + protocol (NFSv2). If you also want NFSv3, say Y to the next question + as well. + + Please read the NFS-HOWTO, available from + . + + To compile the NFS server support as a module, choose M here: the + module will be called nfsd. If unsure, say N. + +config NFSD_V2_ACL + bool + depends on NFSD + +config NFSD_V3 + bool "Provide NFSv3 server support" + depends on NFSD + help + If you would like to include the NFSv3 server as well as the NFSv2 + server, say Y here. If unsure, say Y. + +config NFSD_V3_ACL + bool "Provide server support for the NFSv3 ACL protocol extension" + depends on NFSD_V3 + select NFSD_V2_ACL + help + Implement the NFSv3 ACL protocol extension for manipulating POSIX + Access Control Lists on exported file systems. NFS clients should + be compiled with the NFSv3 ACL protocol extension; see the + CONFIG_NFS_V3_ACL option. If unsure, say N. + +config NFSD_V4 + bool "Provide NFSv4 server support (EXPERIMENTAL)" + depends on NFSD_V3 && EXPERIMENTAL + select NFSD_TCP + select CRYPTO_MD5 + select CRYPTO + select FS_POSIX_ACL + help + If you would like to include the NFSv4 server as well as the NFSv2 + and NFSv3 servers, say Y here. This feature is experimental, and + should only be used if you are interested in helping to test NFSv4. + If unsure, say N. + +config NFSD_TCP + bool "Provide NFS server over TCP support" + depends on NFSD + default y + help + If you want your NFS server to support TCP connections, say Y here. + TCP connections usually perform better than the default UDP when + the network is lossy or congested. If unsure, say Y. + +config ROOT_NFS + bool "Root file system on NFS" + depends on NFS_FS=y && IP_PNP + help + If you want your Linux box to mount its whole root file system (the + one containing the directory /) from some other computer over the + net via NFS (presumably because your box doesn't have a hard disk), + say Y. Read for details. It is + likely that in this case, you also want to say Y to "Kernel level IP + autoconfiguration" so that your box can discover its network address + at boot time. + + Most people say N here. + +config LOCKD + tristate + +config LOCKD_V4 + bool + depends on NFSD_V3 || NFS_V3 + default y + +config EXPORTFS + tristate + +config NFS_ACL_SUPPORT + tristate + select FS_POSIX_ACL + +config NFS_COMMON + bool + depends on NFSD || NFS_FS + default y + +config SUNRPC + tristate + +config SUNRPC_GSS + tristate + +config RPCSEC_GSS_KRB5 + tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)" + depends on SUNRPC && EXPERIMENTAL + select SUNRPC_GSS + select CRYPTO + select CRYPTO_MD5 + select CRYPTO_DES + help + Provides for secure RPC calls by means of a gss-api + mechanism based on Kerberos V5. This is required for + NFSv4. + + Note: Requires an auxiliary userspace daemon which may be found on + http://www.citi.umich.edu/projects/nfsv4/ + + If unsure, say N. + +config RPCSEC_GSS_SPKM3 + tristate "Secure RPC: SPKM3 mechanism (EXPERIMENTAL)" + depends on SUNRPC && EXPERIMENTAL + select SUNRPC_GSS + select CRYPTO + select CRYPTO_MD5 + select CRYPTO_DES + help + Provides for secure RPC calls by means of a gss-api + mechanism based on the SPKM3 public-key mechanism. + + Note: Requires an auxiliary userspace daemon which may be found on + http://www.citi.umich.edu/projects/nfsv4/ + + If unsure, say N. + +config SMB_FS + tristate "SMB file system support (to mount Windows shares etc.)" + depends on INET + select NLS + help + SMB (Server Message Block) is the protocol Windows for Workgroups + (WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share + files and printers over local networks. Saying Y here allows you to + mount their file systems (often called "shares" in this context) and + access them just like any other Unix directory. Currently, this + works only if the Windows machines use TCP/IP as the underlying + transport protocol, and not NetBEUI. For details, read + and the SMB-HOWTO, + available from . + + Note: if you just want your box to act as an SMB *server* and make + files and printing services available to Windows clients (which need + to have a TCP/IP stack), you don't need to say Y here; you can use + the program SAMBA (available from ) + for that. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at . + + To compile the SMB support as a module, choose M here: the module will + be called smbfs. Most people say N, however. + +config SMB_NLS_DEFAULT + bool "Use a default NLS" + depends on SMB_FS + help + Enabling this will make smbfs use nls translations by default. You + need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls + settings and you need to give the default nls for the SMB server as + CONFIG_SMB_NLS_REMOTE. + + The nls settings can be changed at mount time, if your smbmount + supports that, using the codepage and iocharset parameters. + + smbmount from samba 2.2.0 or later supports this. + +config SMB_NLS_REMOTE + string "Default Remote NLS Option" + depends on SMB_NLS_DEFAULT + default "cp437" + help + This setting allows you to specify a default value for which + codepage the server uses. If this field is left blank no + translations will be done by default. The local codepage/charset + default to CONFIG_NLS_DEFAULT. + + The nls settings can be changed at mount time, if your smbmount + supports that, using the codepage and iocharset parameters. + + smbmount from samba 2.2.0 or later supports this. + +config CIFS + tristate "CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)" + depends on INET + select NLS + help + This is the client VFS module for the Common Internet File System + (CIFS) protocol which is the successor to the Server Message Block + (SMB) protocol, the native file sharing mechanism for most early + PC operating systems. The CIFS protocol is fully supported by + file servers such as Windows 2000 (including Windows 2003, NT 4 + and Windows XP) as well by Samba (which provides excellent CIFS + server support for Linux and many other operating systems). Limited + support for Windows ME and similar servers is provided as well. + You must use the smbfs client filesystem to access older SMB servers + such as OS/2 and DOS. + + The intent of the cifs module is to provide an advanced + network file system client for mounting to CIFS compliant servers, + including support for dfs (hierarchical name space), secure per-user + session establishment, safe distributed caching (oplock), optional + packet signing, Unicode and other internationalization improvements, + and optional Winbind (nsswitch) integration. You do not need to enable + cifs if running only a (Samba) server. It is possible to enable both + smbfs and cifs (e.g. if you are using CIFS for accessing Windows 2003 + and Samba 3 servers, and smbfs for accessing old servers). If you need + to mount to Samba or Windows from this machine, say Y. + +config CIFS_STATS + bool "CIFS statistics" + depends on CIFS + help + Enabling this option will cause statistics for each server share + mounted by the cifs client to be displayed in /proc/fs/cifs/Stats + +config CIFS_STATS2 + bool "CIFS extended statistics" + depends on CIFS_STATS + help + Enabling this option will allow more detailed statistics on SMB + request timing to be displayed in /proc/fs/cifs/DebugData and also + allow optional logging of slow responses to dmesg (depending on the + value of /proc/fs/cifs/cifsFYI, see fs/cifs/README for more details). + These additional statistics may have a minor effect on performance + and memory utilization. + + Unless you are a developer or are doing network performance analysis + or tuning, say N. + +config CIFS_XATTR + bool "CIFS extended attributes" + depends on CIFS + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + for details). CIFS maps the name of + extended attributes beginning with the user namespace prefix + to SMB/CIFS EAs. EAs are stored on Windows servers without the + user namespace prefix, but their names are seen by Linux cifs clients + prefaced by the user namespace prefix. The system namespace + (used by some filesystems to store ACLs) is not supported at + this time. + + If unsure, say N. + +config CIFS_POSIX + bool "CIFS POSIX Extensions" + depends on CIFS_XATTR + help + Enabling this option will cause the cifs client to attempt to + negotiate a newer dialect with servers, such as Samba 3.0.5 + or later, that optionally can handle more POSIX like (rather + than Windows like) file behavior. It also enables + support for POSIX ACLs (getfacl and setfacl) to servers + (such as Samba 3.10 and later) which can negotiate + CIFS POSIX ACL support. If unsure, say N. + +config CIFS_EXPERIMENTAL + bool "CIFS Experimental Features (EXPERIMENTAL)" + depends on CIFS && EXPERIMENTAL + help + Enables cifs features under testing. These features are + experimental and currently include support for writepages + (multipage writebehind performance improvements) and directory + change notification ie fcntl(F_DNOTIFY) as well as some security + improvements. Some also depend on setting at runtime the + pseudo-file /proc/fs/cifs/Experimental (which is disabled by + default). See the file fs/cifs/README for more details. + + If unsure, say N. + +config CIFS_UPCALL + bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" + depends on CIFS_EXPERIMENTAL + select CONNECTOR + help + Enables an upcall mechanism for CIFS which will be used to contact + userspace helper utilities to provide SPNEGO packaged Kerberos + tickets which are needed to mount to certain secure servers + (for which more secure Kerberos authentication is required). If + unsure, say N. + +config NCP_FS + tristate "NCP file system support (to mount NetWare volumes)" + depends on IPX!=n || INET + help + NCP (NetWare Core Protocol) is a protocol that runs over IPX and is + used by Novell NetWare clients to talk to file servers. It is to + IPX what NFS is to TCP/IP, if that helps. Saying Y here allows you + to mount NetWare file server volumes and to access them just like + any other Unix directory. For details, please read the file + in the kernel source and + the IPX-HOWTO from . + + You do not have to say Y here if you want your Linux box to act as a + file *server* for Novell NetWare clients. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at . + + To compile this as a module, choose M here: the module will be called + ncpfs. Say N unless you are connected to a Novell network. + +source "fs/ncpfs/Kconfig" + +config CODA_FS + tristate "Coda file system support (advanced network fs)" + depends on INET + help + Coda is an advanced network file system, similar to NFS in that it + enables you to mount file systems of a remote server and access them + with regular Unix commands as if they were sitting on your hard + disk. Coda has several advantages over NFS: support for + disconnected operation (e.g. for laptops), read/write server + replication, security model for authentication and encryption, + persistent client caches and write back caching. + + If you say Y here, your Linux box will be able to act as a Coda + *client*. You will need user level code as well, both for the + client and server. Servers are currently user level, i.e. they need + no kernel support. Please read + and check out the Coda + home page . + + To compile the coda client support as a module, choose M here: the + module will be called coda. + +config CODA_FS_OLD_API + bool "Use 96-bit Coda file identifiers" + depends on CODA_FS + help + A new kernel-userspace API had to be introduced for Coda v6.0 + to support larger 128-bit file identifiers as needed by the + new realms implementation. + + However this new API is not backward compatible with older + clients. If you really need to run the old Coda userspace + cache manager then say Y. + + For most cases you probably want to say N. + +config AFS_FS +# for fs/nls/Config.in + tristate "Andrew File System support (AFS) (Experimental)" + depends on INET && EXPERIMENTAL + select RXRPC + help + If you say Y here, you will get an experimental Andrew File System + driver. It currently only supports unsecured read-only AFS access. + + See for more intormation. + + If unsure, say N. + +config RXRPC + tristate + +config 9P_FS + tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)" + depends on INET && EXPERIMENTAL + help + If you say Y here, you will get experimental support for + Plan 9 resource sharing via the 9P2000 protocol. + + See for more information. + + If unsure, say N. + +endmenu + +menu "Partition Types" + +source "fs/partitions/Kconfig" + +endmenu + +source "fs/nls/Kconfig" + +endmenu + diff -urN oldtree/fs/Makefile newtree/fs/Makefile --- oldtree/fs/Makefile 2006-01-28 16:36:00.000000000 +0000 +++ newtree/fs/Makefile 2006-01-28 18:23:21.821814240 +0000 @@ -101,3 +101,4 @@ obj-$(CONFIG_HOSTFS) += hostfs/ obj-$(CONFIG_HPPFS) += hppfs/ obj-$(CONFIG_DEBUG_FS) += debugfs/ +obj-$(CONFIG_UNION_FS) += unionfs/ diff -urN oldtree/fs/Makefile.orig newtree/fs/Makefile.orig --- oldtree/fs/Makefile.orig 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/Makefile.orig 2006-01-28 18:23:21.821814240 +0000 @@ -0,0 +1,103 @@ +# +# Makefile for the Linux filesystems. +# +# 14 Sep 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. +# + +obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \ + block_dev.o char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ + ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \ + attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \ + seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \ + ioprio.o pnode.o + +obj-$(CONFIG_INOTIFY) += inotify.o +obj-$(CONFIG_EPOLL) += eventpoll.o +obj-$(CONFIG_COMPAT) += compat.o + +nfsd-$(CONFIG_NFSD) := nfsctl.o +obj-y += $(nfsd-y) $(nfsd-m) + +obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o +obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o +obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o + +# binfmt_script is always there +obj-y += binfmt_script.o + +obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o +obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o +obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o +obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o + +obj-$(CONFIG_FS_MBCACHE) += mbcache.o +obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o +obj-$(CONFIG_NFS_COMMON) += nfs_common/ + +obj-$(CONFIG_QUOTA) += dquot.o +obj-$(CONFIG_QFMT_V1) += quota_v1.o +obj-$(CONFIG_QFMT_V2) += quota_v2.o +obj-$(CONFIG_QUOTACTL) += quota.o + +obj-$(CONFIG_DNOTIFY) += dnotify.o + +obj-$(CONFIG_PROC_FS) += proc/ +obj-y += partitions/ +obj-$(CONFIG_SYSFS) += sysfs/ +obj-y += devpts/ + +obj-$(CONFIG_PROFILING) += dcookies.o + +# Do not add any filesystems before this line +obj-$(CONFIG_REISERFS_FS) += reiserfs/ +obj-$(CONFIG_EXT3_FS) += ext3/ # Before ext2 so root fs can be ext3 +obj-$(CONFIG_JBD) += jbd/ +obj-$(CONFIG_EXT2_FS) += ext2/ +obj-$(CONFIG_CRAMFS) += cramfs/ +obj-$(CONFIG_RAMFS) += ramfs/ +obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ +obj-$(CONFIG_CODA_FS) += coda/ +obj-$(CONFIG_MINIX_FS) += minix/ +obj-$(CONFIG_FAT_FS) += fat/ +obj-$(CONFIG_MSDOS_FS) += msdos/ +obj-$(CONFIG_VFAT_FS) += vfat/ +obj-$(CONFIG_BFS_FS) += bfs/ +obj-$(CONFIG_ISO9660_FS) += isofs/ +obj-$(CONFIG_DEVFS_FS) += devfs/ +obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ +obj-$(CONFIG_HFS_FS) += hfs/ +obj-$(CONFIG_VXFS_FS) += freevxfs/ +obj-$(CONFIG_NFS_FS) += nfs/ +obj-$(CONFIG_EXPORTFS) += exportfs/ +obj-$(CONFIG_NFSD) += nfsd/ +obj-$(CONFIG_LOCKD) += lockd/ +obj-$(CONFIG_NLS) += nls/ +obj-$(CONFIG_SYSV_FS) += sysv/ +obj-$(CONFIG_SMB_FS) += smbfs/ +obj-$(CONFIG_CIFS) += cifs/ +obj-$(CONFIG_NCP_FS) += ncpfs/ +obj-$(CONFIG_HPFS_FS) += hpfs/ +obj-$(CONFIG_NTFS_FS) += ntfs/ +obj-$(CONFIG_UFS_FS) += ufs/ +obj-$(CONFIG_EFS_FS) += efs/ +obj-$(CONFIG_JFFS_FS) += jffs/ +obj-$(CONFIG_JFFS2_FS) += jffs2/ +obj-$(CONFIG_AFFS_FS) += affs/ +obj-$(CONFIG_ROMFS_FS) += romfs/ +obj-$(CONFIG_QNX4FS_FS) += qnx4/ +obj-$(CONFIG_AUTOFS_FS) += autofs/ +obj-$(CONFIG_AUTOFS4_FS) += autofs4/ +obj-$(CONFIG_ADFS_FS) += adfs/ +obj-$(CONFIG_FUSE_FS) += fuse/ +obj-$(CONFIG_UDF_FS) += udf/ +obj-$(CONFIG_RELAYFS_FS) += relayfs/ +obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ +obj-$(CONFIG_JFS_FS) += jfs/ +obj-$(CONFIG_XFS_FS) += xfs/ +obj-$(CONFIG_9P_FS) += 9p/ +obj-$(CONFIG_AFS_FS) += afs/ +obj-$(CONFIG_BEFS_FS) += befs/ +obj-$(CONFIG_HOSTFS) += hostfs/ +obj-$(CONFIG_HPPFS) += hppfs/ +obj-$(CONFIG_DEBUG_FS) += debugfs/ diff -urN oldtree/fs/unionfs/AUTHORS newtree/fs/unionfs/AUTHORS --- oldtree/fs/unionfs/AUTHORS 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/AUTHORS 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,155 @@ +PRIMARY AUTHORS AND MAJOR CONTRIBUTORS TO AM_UTILS: +The primary authors work at the Filesystems and Storage Lab at Stony Brook +University. They also currently maintain the package. + +* Erez Zadok +- Primary Investigator + +* Charles P. Wright +- Primary maintainer (12/2004-Present) +- Snapshotting support +- Initial development + +* Dave Quigley +- 2.6 Port +- Maintenance (1/2005-Present) + +* Arun Krishna Kumar +- Maintenance (6/2005-12/2005) + +* Mohammad Nayyer Zubair +- Initial development +- Regression Suite + +* Puja Gupta +- Initial development + +* Harikesavan Krishnan +- Initial development + +* Josef "Jeff" Sipek +- Maintenance (12/2005-Present) + +Other contributors: +* Sai Suman +January 10, 2005: NFS Export patch +January 10, 2005: Copyup bug fix. + +* Alex de Landgraaf +January 10, 2005: Fixes for gcc 2.9.5 + +* Anton Farygin +February 2, 2005: Fixes for non-privileged copyup. +March 2, 2005: vfs_readdir bug in dirhelper.c +March 2, 2005: Fix copyup on symlinks +March 2, 2005: Fix handling of failed whiteout lookup +August 15, 2005: Fix possible deadlock in incgen when memory allocaiton fails. + +* Jaspreet Singh +February 8, 2005: Use security functions for xattr copyup. +May 11, 2005: Fix for Xattr copyup on Selinux +May 12, 2005: Selinux requires valid i_mode before d_instantiate. + +* Fabian Franz +February 22, 2005: Hardlinks should have the same inode number. +February 22, 2005: Device copyup fix. +February 22, 2005: Identified d_delete problem over tmpfs +March 2, 2005: vfs_readdir bug in dirhelper.c + +* Terry Barnaby +March 3, 2005: Copy attributes on d_revalidate +March 2, 2005: Fix for readdir over NFS +March 16, 2005: Fix for unionfs_dir_llseek +April 20, 2005: Submitted opaque directory patch, wich the current code +is inspired by. + +* Lucas Correia Villa Real +March 7, 2005: Makefile uses MODDIR. + +* Eduard Bloch +March 7, 2005: Fix man page sections, improve Makefile + +* Fernando Freiregomez +March 7, 2005: Have snapmerge fix times on created files. + +* Markus F.X.J. Oberhumer +April 18, 2005: Fixes for compilation on AMD64 + +* Tomas Matejicek +May 10, 2005: I used his linuxrc as the basis for the Unionfs as a root +file system instructions. + +* Shaya Potter +July 19, 2005: Symbolic links should not be renamed to whiteout files, as +that confuses Unionfs later. +September 2, 2005: Fix copyup checking for mmap. +October 11, 2005: Deadlock fix. +October 20, 2005: Improved locking for branch manipulation +October 20, 2005: Fix for removing opaque directories. +November 18, 2005: NULL check in lookup_whiteout. + +* Jan Engelhardt +July 22, 2005: Support for realpath in unionctl. +August 1, 2005: Use vprintk instead of vsnprintf/printk combo. +August 9, 2005: Fix unionctl so that it doesn't truncate "/" to "". + +* Malcom Lashley +August 9, 2005: AMD64 compile fixes. + +* Eduard Bloch +August 9, 2005: Debian packaging files. + +* Klaus Knopper +August 22, 2005: Fix from lookup_one_len in unionfs_create. +September 23, 2005: Fix for unionfs_permission pertaining to +read only file systems + +* Junjiro Okajima +September 21, 2005: Fix for of by one error in KMALLOC. +September 26, 2005: Fix for d_revalidate. +September 28, 2005: rmdir fix. +October 13, 2005: rename fix (Bug #425). +October 19, 2005: NFS security hole fix. +November 5, 2005: Fix for race b/t lookup and new_dentry_private_data. +November 8, 2005: Fix error checking in lookup_backend. +December 27, 2005: Fixed create whiteout bug, forgotten dput() +December 27, 2005: Fixed unlink bug, forgotten dput()s +December 27, 2005: Fixed create bug, forgotten dput(), extra GET_PARENT +December 27, 2005: Fixed permission bug, creat/open truncates the running +executable +December 27, 2005: Properly copyup atime, mtime, and ctime. +December 28, 2005: Fixed missing DPUT()s in unionfs_lookup_backend +December 28, 2005: Fixed privileges-related bug in is_opaque_dir +December 29, 2005: Fixed missing/misplaced DPUT()sg DPUT() +January 20, 2006: Introduced per-branch nfsro flag (unionctl.c) +January 22, 2006: Fixed persistant inode code: link, rmdir, shrinking of +dcache, map validation +January 24, 2006: Fixed hidden inode not being iput() since ibstart and +ibend is not updated. + +* Robert Glowczynski +October 6, 2005: Fix for fsync over squashfs. + +* Charles Duffy +October 22, 2005: readdir.sh regression script + +* Alessio Curri +November 11, 2005: Fix for RPM spec file. + +* Martin Walter +November 16, 2005: Fix a thinko in NFS_SECURITY_HOLE. + +* Martin Kreiner +January 13, 2006: Introduced mount option nfsperms, and removed NFS_SECURITY_HOLE +January 20, 2006: Introduced per-branch nfsro flag, and removed nfsperms + +* Peeka J. Enberg +January 14, 2006: Removed the use of GFP_UNIONFS and replaced it with GFP_KERNEL + +* Amnon Aaronsohn +January 25, 2006: Fixed patch-kernel.sh error msg + +* And many more ... diff -urN oldtree/fs/unionfs/COPYING newtree/fs/unionfs/COPYING --- oldtree/fs/unionfs/COPYING 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/COPYING 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,373 @@ +This Unionfs-1.0 release is licensed under the terms of the GNU General +Public License (GPL). + +For information on commercial licensing through the SUNY Research +Foundation, contact Erez Zadok . + +Copyright (c) 2003-2006 Erez Zadok +Copyright (c) 2003-2006 Charles P. Wright +Copyright (c) 2005-2006 Josef Sipek +Copyright (c) 2005 Arun M. Krishnakumar +Copyright (c) 2005-2006 David P. Quigley +Copyright (c) 2003-2004 Mohammad Nayyer Zubair +Copyright (c) 2003 Puja Gupta +Copyright (c) 2003 Harikesavan Krishnan +Copyright (c) 2003-2006 Stony Brook University +Copyright (c) 2003-2006 The Research Foundation of State University of New York + +All rights reserved. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff -urN oldtree/fs/unionfs/ChangeLog newtree/fs/unionfs/ChangeLog --- oldtree/fs/unionfs/ChangeLog 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/ChangeLog 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,3418 @@ +2006-01-25 Josef "Jeff" Sipek + + * NEWS, Makefile, Makefile.kernel: Version 1.1.2 + +2006-01-25 Amnon Aaronsohn + + * patch-kernel.sh: Fixed patch-kernel.sh error msg + +2006-01-24 Junjiro Okajima + + * subr.c (create_whiteout_parent): Hidden inode is not iput() since + ibstart and ibend is not updated. + +2006-01-22 Junjiro Okajima + + * copyup.c (copyup_named_dentry, create_parents_named): Fixed + persistant inode code: link, rmdir, shrinking of dcache, map validation + + * main.c (copyup_xattrs): Fixed persistant inode code: link, rmdir, + shrinking of dcache, map validation + + * persistent_inode.c (__fread, __fread, verify_forwardmap, + verify_reversemap, init_imap_data, parse_imap_option, __get_uin, + __write_uin, get_uin, write_uin): Fixed persistant inode code: link, + rmdir, shrinking of dcache, map validation + + * unionfs.h: Fixed persistant inode code: link, rmdir, shrinking of + dcache, map validation + +2006-01-20 Martin Kreiner + + * BUGS, INSTALL, man/unionctl.8, man/unionfs.4: Documentation update + + * branchman.c (unionfs_ioctl_addbranch, unionfs_ioctl_rdwrbranch): + Per branch nfsro option + + * inode.c (inode_permission): Per branch nfsro option + + * main.c (parse_dirs_option, unionfs_parse_options): Per branch nfsro + option + + * super.c (unionfs_show_options): Per branch nfsro option + + * unionctl.c (__usage, parse_rw, parse_options, dump_branches, main): + Per branch nfsro option + + * unionfs.h: Per branch nfsro option + +2006-01-20 Josef "Jeff" Sipek + + * branchman.c (unionfs_ioctl_addbranch, unionfs_ioctl_delbranch): + Inode refcount debugging tool calls + + * copyup.c (create_parents_named):Inode refcount debugging tool calls + + * dentry.c (unionfs_d_revalidate, unionfs_d_iput):Inode refcount + debugging tool calls + + * inode.c (unionfs_link): Inode refcount debugging tool calls + + * main.c (unionfs_interpose, unionfs_reinterpose, unionfs_igrab, + unionfs_iput, unionfs_iget): Inode refcount debugging helper code; + Fixed init of atomic_t + + * subr.c (create_whiteout_parent, unionfs_refresh_hidden_dentry): + Inode refcount debugging tool calls + + * super.c (unionfs_clear_inode): Inode refcount debugging tool calls + + * unionfs.h: Definitions for IGET, IGRAB, and IPUT + + * match-iget.pl: Inode refcount debugging code output "matcher" + +2006-01-17 Josef "Jeff" Sipek + + * main.c, unionfs.h: Added #if'd kzalloc for kernels older than 2.6.14 + +2006-01-14 David P. Quigley + + * branchman.c: Replaced pairs of KMALLOC and memset calls to + KZALLOC calls. + + * commonfops.c: Replaced pairs of KMALLOC and memset calls to + KZALLOC calls. + + * copyup.c: Replaced pairs of KMALLOC and memset calls to + KZALLOC calls. + + * main.c: Replaced pairs of KMALLOC and memset calls to + KZALLOC calls. + + * persistent_inode.c: Replaced pairs of KMALLOC and memset calls to + KZALLOC calls. + + * super.c: Replaced pairs of KMALLOC and memset calls to + KZALLOC calls. + + +2006-01-14 Josef "Jeff" Sipek + + * unionfs.h: Fixed unionfs_kmalloc prototype + + * main.c (unionfs_kzalloc, unionfs_kmalloc): Use kzalloc, not + the non-existent kzmalloc + +2006-01-14 David P. Quigley + + * AUTHORS: added entry for Peeka J. Enberg + +2006-01-14 Peeka J. Enberg + + * ALL: Changed all use of GFP_UNIONFS to GFP_KERNEL + + * unionfs.h: Removed definition for GFP_UNIONFS + +2006-01-14 David P. Quigley + + * unionfs.h : Included defines for KZMALLOC and extern for + unionfs_kzalloc. NOTE: This change makes the minimum kernel + version for unionfs 2.6.14. + + * main.c (unionfs_kmalloc): Changed prototype to use the + actual type of GFP_KERNEL instead of int and removed a + (void *) since the kernel coding conventions say that this + is not necessary. + + * main.c (unionfs_kzalloc): New wrapper function to track + kzallocs when debugging. + +2006-01-13 Josef "Jeff" Sipek + + * BUGS, INSTALL: Removed all references to NFS_SECURITY_HOLE + +2006-01-13 Martin Kreiner + + * inode.c (inode_permission): Introduce nfsperms mount option and + remove NFS_SECURITY_HOLE + + * main.c (unionfs_dentry_info): Introduce nfsperms mount option and + remove NFS_SECURITY_HOLE + + * super.c (unionfs_show_options): Introduce nfsperms mount option and + remove NFS_SECURITY_HOLE + + * unionfs.h:Introduce nfsperms mount option and + remove NFS_SECURITY_HOLE + +2006-01-12 Josef "Jeff" Sipek + + * fist.h: Code moved to unionfs.h, unionfs_macros.h, and + unionfs_debugmacros.h + + * ALL, misc/*.c: Removed all references to fist.h + +2006-01-09 Josef "Jeff" Sipek + + * rename.c (__rename_all{,_unlink,_revert,_clobber}): Make functions + static + +2006-01-08 Josef "Jeff" Sipek + + * rename.c (unionfs_rename_all,lookup_whiteout): Split up the + nearly 300 line unionfs_rename_all function into several more + understandable "double underscore" functions; removed get_whname + it used __getname which allocates a whole page, updated + lookup_whiteout to use alloc_whname instead + + * lookup.c (unionfs_lookup_backend): Use this should be the last + alloc_whname patch + +2006-01-07 Josef "Jeff" Sipek + + * file.c: Use unlocked_ioctl iff the kernel is 2.6.11 or newer + (unionfs_main_fops) + + * dirfops.c: Use unlocked_ioctl iff the kernel is 2.6.11 or newer + (for unonfs_dir_fops) + + * commonfops.c (unionfs_ioctl): Use unlocked_ioctl iff the kernel + is 2.6.11 or newer, the prototype for unionfs_ioctl is also different + on 2.6.11 or newer + + * inode.c (inode_permission): If kernel is older than 2.6.10, use + vfs_permission otherwise generic_permission + +2006-01-03 David P. Quigley + + * ChangeLog : fixed two gramatical errors in the changelog. + +2006-01-03 David P. Quigley + + * unionfs.h: Added a define for the first valid inode number so we + aren't using magic numbers in the persistent inode code. + + * super.c: added a call to cleanup_imap_data to properly free + resources on unmount. + + * persistent_inode.c: (imap_parse_options): cleanedup code, + (init_imap_data): new function (cleanup_imap_data): new + function. + + * unionimap.c : cleaned up some brackets from single line if + statements. + +2006-01-03 Josef "Jeff" Sipek + + * unionfs.h: Renamed make_whname to alloc_whname, use strlcat instead + of strncat (the strcpy is safe since WHPFX will always be NULL + terminated), the NULL termination is dony by strlcat + + * inode.c (unionfs_create, unionfs_link, unionfs_symlink, + unionfs_mkdir, unionfs_mknod): Renamed make_whname to alloc_whname + + * rename.c (do_rename): Renamed make_whname to alloc_whname + + * subr.c (create_whiteout, create_whiteout_parent): Renamed + make_whname to alloc_whname + + * unlink.c (unionfs_unlink_whiteout): Renamed make_whname to + alloc_whname + +2006-01-03 Josef "Jeff" Sipek + + * branchman.c (unionfs_ioctl_branchcount, unionfs_ioctl_addbranch, + unionfs_ioctl_rdwrbranch, unionfs_ioctl_queryfile): Make sparse happy + + * commonfops.c (unionfs_ioctl): Make sparse happy + + * copyup.c (copyup_named_dentry): Make sparse happy + + * file.c (unionfs_read, unionfs_write): Make sparse happy + + * inode.c (unionfs_readlink, unionfs_follow_link): Make sparse happy + + * main.c (unionfs_read_super): Make sparse happy + + * persistent_inode.c (verify_forwardmap, verify_reversemap, get_uin, + get_lin): Make sparse happy + +2006-01-02 Josef "Jeff" Sipek + + * unionfs.h: added make_whname to replace scattered and duplicate + code that allocates memory, copies into it WHPFX and the rest of + the filename + + * inode.c (unionfs_create, unionfs_link, unionfs_symlink, + unionfs_mkdir, unionfs_mknod): Use make_whname instead of manually + allocating, and copying data + + * rename.c (do_rename): Use make_whname instead of manually + allocating, and copying data + + * subr.c (create_whiteout, create_whiteout_parent): Use make_whname + instead of manually allocating, and copying data + + * unlink.c (unionfs_unlink_whiteout): Use make_whname instead of + manually allocating, and copying data + +2006-01-02 Josef "Jeff" Sipek + + * ALL: Copyright year updated + + * man/*: Date updated + + * misc/split-views-2.4.26.patch: removed because 2.4 is not supported + +2006-01-01 Josef "Jeff" Sipek + + * rename.c (do_rename): use WHLEN+1 instead of 5 + +2005-12-30 Josef "Jeff" Sipek + + * rename.c (do_rename): Added two missing DPUT()s + + * subr.c (create_whiteout_parent): use LOOKUP_ONE_LEN instead of + lookup_one_len + +2005-12-29 David P. Quigley + + * commonfops.c, copyup.c, main.c, print.c, super.c: converted FISTBUG + commands to printk and BUG pairs. + * fist.h: removed definition for FISTBUG + +2005-12-29 Josef "Jeff" Sipek + + * lookup.c (unionfs_lookup_backend): Use WHLEN+1 instead of 5 + + * unionfs_debugmacros.h (__ftohf_index, __set_ftohf_index, __set_itohi_index, + __set_dbend, __set_dbstart, __set_dbopaque, __dtohd_index): BUG_ON with a more + complex condition is more optimal than "if(partial_condition) BUG_ON(...);" + +2005-12-29 Junjiro Okajima + + * lookup.c (unionfs_lookup_backend): DPUT() when done with the dentry + not before, added missing DPUT() + +2005-12-28 Charles P. Wright + + * AUTHORS: Some maintenance dates. + +2005-12-28 Josef "Jeff" Sipek + + * AUTHORS: updated to reflect the patches commited in the last two days + +2005-12-28 Junjiro Okajima + + * lookup.c (unionfs_lookup_backend): Fixed missing DPUT()s + +2005-12-28 Junjiro Okajima + + * lookup.c: change the process's privilege temporally when + creating/searching/deleting the whiteouts (in is_opaque_dir,) and + forgot DPUT() after failing is_opaque_dir() (in unionfs_lookup_backend) + +2005-12-27 Junjiro Okajima + + * subr.c (create_whiteout): create whiteout bug, forgotten dput() + +2005-12-27 Junjiro Okajima + + * unlink.c (unionfs_unlink_whiteout): unlink bug, forgotten dput()s + +2005-12-27 Junjiro Okajima + + * inode.c (unionfs_create): create bug, forgotten dput(), extra GET_PARENT + +2005-12-27 Josef "Jeff" Sipek + + * lookup.c (new_dentry_private_data): Use GFP_ATOMIC instead + of GFP_UNIONFS (which currently is same as GFP_KERNEL) to prevent + sleeping while atomic bug + +2005-12-27 Junjiro Okajima + + * inode.c (unionfs_permission): permission bug, creat/open truncates + the running executable + +2005-12-27 David P. Quigley + + * unionctl.c : Fixed check to see if a branch was already in the union and + fixed --before and --after logic. + + * regression/branchman.sh: BUG370 will not work anymore due to code to avoid + duplicate branches being added. Need to reevaluate if it should be kept + anymore. + +2005-12-27 David P. Quigley + + * *.[ch]: Went through every file and replaced ASSERT and ASSERT2 with + BUG_ON calls. The logic for BUG_ON is the opposite of ASSERT but I believe + they are all converted properly. + + * fist.h: Removed definitions for ASSERT and ASSERT2 + +2005-12-27 David P. Quigley + + * *.[ch]: Went through every file and removed PASSERT and PASSERT2 + statments. If there was an if that inclosed it then that was removed + also. + + * fist.h: Removed definitions for PASSERT and PASSERT2. + +2005-12-27 Junjiro Okajima + + * copyup.c (copyup_permissions): Properly copyup atime, mtime, and + ctime. + +2005-12-27 Josef "Jeff" Sipek + + * inode.c (unionfs_lookup): Bugfix for bug #451 is not valid, + change reverted + +2005-12-20 Josef "Jeff" Sipek + + * lookup.c (new_dentry_private_data): Use SLAB_ATOMIC instead + of SLAB_KERNEL (prevent sleeping while atomic bug) + +2005-11-30 Josef "Jeff" Sipek + + * main.c: Updated module info (now includes unionfs version + number) + +2005-11-29 Arun M. Krishnakumar + + * branchman.c: Added check for addition of branches with + overlapping paths. Fixes rest of Bug #374. + +2005-11-29 Arun M. Krishnakumar + + * unionctl.c: Fixed branch addition with just branch (and + neither mode nor before/after specified. + +2005-11-29 Charles P. Wright + + * Fix Coverity flagged errors. + +2005-11-29 Arun M. Krishnakumar + + * main.c : Corrected a boundary case, so that one cannot + use "/" as a branch if /ro is a branch. + +2005-11-28 Arun M. Krishnakumar + + * main.c : Ensure that the branches getting added during a + mount operation do not have overlapping branch paths. This + is part of Bug #374. + +2005-11-28 Arun M. Krishnakumar + + * inode.c: unionfs_lookup was not incrementing the reference + count of the dentry. this was causing the chmod bug. added + this, and fixed bug #451 + +2005-11-26 Arun M. Krishnakumar + + * unlink.c: Updated unionfs_unlink_whiteout to fix bug #434 + +2005-11-24 Charles P. Wright + + * print.c: Remove unused function. + + * Makefile: Don't duplicate source list. + +2005-11-23 Charles P. Wright + + * unionimap.c: Fix unchecked malloc. + + * usercommon.c: Fix double free. + +2005-11-20 Arun M. Krishnakumar + + * global : Changes made for "sparse" + +2005-11-18 Josef "Jeff" Sipek + + * rename.c (get_whname): Make constant's type clearer + +2005-11-18 Arun M. Krishnakumar + + * unionctl.c : Changes made for "sparse" + +2005-11-18 Josef "Jeff" Sipek + + * rename.c (get_whname): Add NULL termination. + +2005-11-18 Shaya Potter + + * rename.c (lookup_whiteout): Add NULL Check. + +2005-11-18 Charles P. Wright + + * Remove UNIONFS_XATTR define, because 2.6 has consistent prototypes. + +2005-11-16 Martin Walter + + * inode.c: Fix IS_NFS. + +2005-11-15 Charles P. Wright + + * main.c: Allow debug= to be passed to the Unionfs module. + +2005-11-11 Allessio Curri + + * rpm/unionfs.spec: Update RPM spec file to include unionimap. + +2005-11-09 Charles P. Wright + + * commonfops.c (unionfs_open): Slightly rework reader/writer locks. + +2005-10-24 Shaya Potter + + * Fix scope of readers/writer locks on branch configuration. + +2005-11-09 Charles P. Wright + + * unlink.c: Add comment w/ Junjiro's rmdir fix. + +2005-09-26 Junjiro Okajima + + * dentry.c (unionfs_d_revalidate): Don't copy attributes to nonexistent + inodes. + + * lookup.c (new_dentry_private_data): Fix a race b/t lookup and d_free. + +2005-11-08 Charles P. Wright + + * Makefile: use /lib/modules/`uname -r`/kernel/fs/unionfs/unionfs.ko + to be consistent with other file systems. + + * patch-kernel.sh: Add more double-patching checks. + + * Use WHPFX and WHLEN instead of ".wh." and 4. + + * dirhelper.c (delete_whiteouts): Remove useless partial lookup. + * unlink (unionfs_rmdir_all): Remove useless partial lookup. + + * subr.c (create_whiteout): Silently succeed if the whiteout already + exists. + * inode.c (unionfs_unlink_all): Fix some coding style. + +2005-11-07 David P. Quigley + + * unionctl.c (parse_options): Added a check in to see if a branch + already exists in the union and if it does the operation fails. + +2005-11-07 Charles P. Wright + + * dentry.c (dentry_revalidate): Remove extra d_deleted check. + * commonfops.c (unionfs_open): Undo add debug print of opened dentry. + + * commonfops.c (unionfs_open): Add debug print of opened dentry. + +2005-10-26 Charles P. Wright + + * inode.c (inode_permission): Fix typo in NFS_SECURITY_HOLE. + +2005-11-06 Josef "Jeff" Sipek + + * fist.h (lock_parent, unlock_dir): moved from now non-existent + missing_vfs_funcs.h + * inode.c (unionfs_create): use {,un}lock_rename instead of + double_{,un}lock + * rename.c (do_rename): use {,un}lock_rename instead of double_{,un}lock + * unlink.c (unionfs_unlink_whiteout): use {,un}lock_rename instead of + double_{,un}lock + * missing_vfs_funcs.h: removed + +2005-10-25 Charles P. Wright + + * Makefile: Increment version to 1.1.2pre. + * regression/readdir.sh: readdir regression script. + It doesn't reproduce the bug for us, but extra tests can't hurt. + + * dirfops.c (unionfs_readdir): Properly update uds_dirpos, + which fixes directory reading operations. + +2005-10-24 Charles P. Wright + + * compat.[ch]: Remove old files. + +2005-10-24 Shaya Potter + + * copyup.c (copyup_file): Don't fput errors. + * copyup.c, unionfs.h: Use loff_t for copyup size. + + * copyup.c (copyup_named_dentry): Code cleanup. + +2005-10-21 Charles P. Wright + + * AUTHORS: Update AUTHORS. + +2005-10-21 Charles Duffy + + * xattr.c: Use ssize_t for xattr functions. + +2005-10-20 Shaya Potter + + * dirhelper.c (check_empty): Respect opaqueness. + + * Replace lock_super around branch management operations with a + Unionfs read/write semaphore. This will allow branchput/branchget + to operate concurrently, but prevent them from racing against + branchman operations. + +2005-10-19 Charles P. Wright + + * inode.c (unionfs_permission): Don't call normal permission before + inode_permission (our modified version of permission), because it + just duplicates work. + + * commonfops.c (branchput_gen): Lock the super when we read putmaps. + + * inode.c (inode_permission): If NFS_SECURITY_HOLE is defined + treat -EACCESS as if we should fall back on inode_permission. + + * branchman.c (unionfs_ioctl_rdwrbranch): Make super/dentry + lock/unlock symmetric. + +2005-10-18 David P. Quigley + + * NEWS: Updates NEWS file for release + +2005-10-14 Arun M. Krishnakumar + + * rename.c : Used the create_whiteout_parent function to + create the whiteout in unionfs_rename_all. + * subr.c : Brought the create_whiteout_parent back. These + squash Bug #442. + +2005-10-13 Arun M. Krishnakumar + + * rename.c : Fixed rest of Bug #425. Applied the patch + sent in by Junjiro Okajima. + +2005-10-13 David P. Quigley + + * rmdir-all.sh: added test for bug 430. Not sure if + we are going to patch it yet but if we do the test + is there. + * regression/Makefile: added rmdircheckinode.c + * regression/progs/rmdircheckinode.c: program to check + if the inode numbers match after a failed rmdir. + +2005-10-13 Arun M. Krishnakumar + + * rename.c (unionfs_rename) : Fixed bug #425. The new_dentry + affects the unlink called by "mv" after the rename has failed. + It makes unlink return with -EISDIR. (partial fix) + +2005-10-11 Shaya Potter + + * dentry.c (unionfs_d_revalidate): Fix a deadlock. + +2005-10-06 Robert Glowczynski + + * file.c (unionfs_fsync): Fix check for NULL lower-level operation. + +2005-09-29 Patrik Weiskircher + + * Makefile.kernel: Remove reference to locks.c. + +2005-09-28 Junjiro Okajima + + * unlink.c (unionfs_rmdir_all): Always create whiteouts on directory + removal. + +2005-09-28 Charles P. Wright + + * commonfops.c (unionfs_file_revalidate): Properly update + generation when we combine copyup and reopening. + * Makefile: Remove some 2.4 cruft. + +2005-09-27 Charles P. Wright + + * branchman.c (unionfs_ioctl_incgen): Fix print indentation bug. + + * unionimap.c: AMD64 fix from Gentoo. + +2005-09-27 David P. Quigley + + * inode.c: Made change to use both inode_permissions and + permissions. + +2005-09-27 Charles P. Wright + + * INSTALL: Document MODDIR. + +2005-09-23 Klaus Knopper + + * inode.c: added inode_permissions to check for permissions + on a file even if its on an ROFS and used it in + unionfs_permissions + +2005-09-22 Josef "Jeff" Sipek + + * Makefile: remove 'tags' target dependency from 'all' + +2005-09-21 David P. Quigley + + * Makefile: forgot to remove locks.c from source list + +2005-09-21 Junjiro Okajima + + * inode.c: Fixed several off-by-one kmalloc bugs. + +2005-09-20 David P. Quigley + + * removed locking code from codebase since we no longer + handle locking (vfs will do it) + +2005-09-18 Josef "Jeff" Sipek + + * removed 2.4 code from fist.h, inode.c, lookup.c, + persistent_inode.c, rdstate.c + +2005-09-18 David P. Quigley + + * removed 2.4 code from copyup.c, dentry.c, dirfops.c + and file.c + +2005-09-18 Josef "Jeff" Sipek + + * removed 2.4 code from stale_inode.c, subr.c, unionfs.h, + unlink.c, xattr.c + +2005-09-17 Josef "Jeff" Sipek + + * removed 2.4 code from main.c, print.c, super.c, + xattr.c + +2005-09-17 David P. Quigley + + * removed 2.4 code from branchman.c, commonfops.c + +2005-09-16 Charles P. Wright + + * Makefile.kernel: Use EXTRA_CFLAGS. + + * Makefile: Use ${LD} instead of ld, for cross compilation. + +2005-09-15 David P. Quigley + + * Makefile: Updated to 1.1.0pre + * Makefile.kernel: Updated to 1.1.0pre + +2005-09-15 David P. Quigley + + * NEWS: Updated for release. + * Makefile: updated for release. + * Makefile.kernel: updated for release + +2005-09-12 David P. Quigley + + * locks.c: Removed locking code since its broken big define 0 around + it + * file.c: Removed locking references have the vfs handle it. + * unionfs.h: fixed bug with 2.4 compilation. + +2005-09-08 Charles P. Wright + + * main.c: Remove comment leftover from templates that doesn't make + sense in current context. + +2005-09-05 Charles P. Wright + + * commonfops.c: Remove lower fput debug printks. + +2005-09-02 Shaya Potter + + * file.c (unionfs_mmap): Fix flag checking for mmap. + +2005-09-01 Charles P. Wright + + * We shouldn't use d_delete, vfs_unlink already does it. The only + known remaining 2.6.13 issue is the unionfs_lock (flock.sh in the + regression suite). + + * inode.c,stale_inode.c: Support for 2.6.13's new follow_link + prototype. However, many of the regression tests fail for + unrelated reasons (or at least I think they are unrelated). + + * unionctl.c: Allow --FOO to go before the union specifier (e.g., + unionctl --list /mnt/unionfs now works). + * lookup.c: Don't partial lookup the root dentry. + + * copyup.c: Check for permission setting errors. + +2005-08-31 Charles P. Wright + + * lookup_one_len never returns NULL. + +2005-08-30 Charles P. Wright + + * inode.c (unionfs_permission): Simplified code. + + * inode.c (unionfs_link): Copy directory attrs to directory + (BUG391). Unfortunately, regression test doesn't quite catch the + bug because of a revalidate for the stat. + * commit: Don't complain about .sh file's indentation. + +2005-08-29 Charles P. Wright + + * INSTALL: tmpfs doesn't support fsync on directories + + * Makefile: Update release target for new directory structure. + + * patch-kernel.sh: Depend on Experimental, and move configuration + option to File Systems -> Miscellaneous file systems at the end, + not as the very first file system. Add UNIONFS_VERSION define. + Use tail -n +7 instead of tail +7. + + * file.c (unionfs_fsync): Don't use dtohd on unlocked dentries. + +2005-08-28 Charles P. Wright + + * inode.c (unionfs_link): Don't use unionfs_interpose with + INTERPOSE_LINK any more, because only one line of the whole + function was being used anyway. This fixes an inode refcount leak + in unionfs_link, so the regression suite now passes with the new + locking, without any leaks. + + * commonfops.c (unionfs_file_release): Update rdstate access time when + saving it in the inode (so that it won't be so quickly discarded). + +2005-08-26 Arun M. Krishnakumar + + * dirfops.c (unionfs_readdir) : removed the changes made + for the special way in which vfs_llseek was handles for + Reiser4, as Reiser4 introduced a patch which made it + behave properly. + +2005-08-26 Charles P. Wright + + * Passes regression tests. + + * Locking for create_parents. Regression tests from branchman to + open.sh PASS. + + * Basic inode operations pass sniff test with new locking (regression + tests not yet tried). + + * Dentries need locking, and there isn't much way around it.This + snapshot adds some untested locking, and you won't want to use it + yet. The basic principles are: + 1. As soon as a VFS operation that touches a dentry is entered, + the dentry should be locked. + 2. The lock ordering is: + Children before parents + Two children are tie broken with their address + There are several functions not done yet, most notably create_parents, + because it is going to require more thought (we walk up the parent + list and then back down it). This in part is why children need to go + before parents (also revalidate walks up the parent list). + +2005-08-25 David P. Quigley + + * xattr.c: unused label causing a warning and inturn an error. + +2005-08-25 Charles P. Wright + + * main.c (interpose,reinterpose): Interposition should lock the dentry. + + * file.c: CodingStyle, and we don't need to check ftopd before ftohf. + * file.c (unionfs_mmap): We were checking our file instead of the lower + -level file for having valid operations. + * dirfops.c,dirhelper.c: CodyingStyle + + * copyup.c: There is no need for _len at the end of functions, because + other versions don't exist any longer. + + * lookup.c (unionfs_lookup_backend): Lock the dentry private data + for the whole lookup routine. + * branchman.c: CodingStyle fixes. + * rdstate.c, super.c: Use KERN_ERR if we have unfreed objects. + +2005-08-25 Charles P. Wright + + * INSTALL: Fix losetup instructions. + +2005-08-24 Charles P. Wright + + * print.c: Avoid kmallocs. + * rdstate.c,dirfops.c: Code style cleanups. + +2005-08-24 Anton Farygin + + * dentry.c (d_revalidate): Lock inode when freeing lower level ones. + +2005-08-24 David P. Quigley + * unionfs.h: Updated forwardmap version and added a new data + structure bmapent.(Later on these should be unified into one header + rather than being in 2 header files). + * persistant_inode.c: Updated code to use bmapents now. + +2005-08-24 David P. Quigley + + * unionimap.c: Added code to ensure you dont add a filesystem with + the same fsid twice (no duplicate entries in the maps). + * unionimap.h: Added a new data structrue bmapent. + * The code in the kernel to read the maps hasent been changed so it + doesent work yet. Check back soon for that. + +2005-08-24 Charles P. Wright + + * inode.c (unionfs_create): Use proper permissions when recreating + a deleted file (BUG383). + +2005-08-23 Charles P. Wright + + * commonfops.c (copyup_deleted_file): Fix leak of name on subsequent + loop iterations. + + * commonfops.c (copyup_deleted_file): Cleanup of major loop. + + * unionfs.h (DPUT,KFREE): Don't try to free errors. + + * main.c (unionfs_reinterpose): Remove d_unhashed assertion. + * unionfs.h (d_deleted): Create an inline function to tell + if a directory is deleted (i.e., unhashed and not the root). + +2005-08-23 Charles P. Wright + + * main.c (unionfs_parse_options): More checking for copyupmode. + +2005-08-22 Charles P. Wright + + * unionfs.h (get_nlinks): More intelligent link counting. + + * inode.c (unionfs_create): Don't dput an IS_ERR. + + * unionfs.h: sbstart is always zero + * main.c (unionfs_read_super): check_branch does existence checking + + * unionfs_debugmacros.h: Fix stray printks. + + The following fixes are so that the regression suite runs without + any memory or dentry leaks: + * branchman.c (unionfs_ioctl_addbranch): Zero newly allocated + arrays. + * copyup.c (unionfs_create_named_dirs): Fix leak of path stack. + * main.c: Handle get_parent. + * lookup.c: Make the logic to put preceding negative dentries a + function. + * unlink.c (unionfs_unlink_all): Fix dentry reference count leak. + * inode.c (unionfs_link): Properly handle lock_ and unlock_dir. + * match-dget.pl: Handle DS and DD for set and unset records. + +2005-08-20 Charles P. Wright + + * INSTALL: sendfile conflicts w/ Unionfs. + +2005-08-19 Arun M. Krishnakumar + + * dirfops.c (unionfs_readdir) : changed the way the + return value of the repeated vfs_llseek (with origin + =1) is used. this is to allow readdir in Reiser4, + which returns -ENOENT (!!!) for the llseek in same + cases. this is for Bug #358 + +2005-08-18 Charles P. Wright + + * match-dget.pl: Insert both gets and puts into list of actions + for unreleased dentries. + + * match-dget.pl: Dget matching script. + * Use DGET, DPUT, DENTRY_OPEN, and LOOKUP_ONE_LEN to + record when we dget and dput dentries. + +2005-08-17 Charles P. Wright + + * match-malloc.pl: Return number of errors. + + * print.c (fist_print_generic_dentry): Print inode number. + + * copyup.c (unionfs_create_named_dirs): Fix dentry reference leak. + +2005-08-15 Charles P. Wright + + * print.c (fist_print_file): Divide into generic and Unionfs halves, + ASSERT if we are passed a lower-level file. + + * file.c (unionfs_lock): Handle write locks on r/o branches. + +2005-03-03 Anton Farygin + + * dentry.c (unionfs_d_revalidate): Fix possible double unlock. + + * branchman.c (unionfs_ioctl_incgen): Fix possible deadlock when + memory allocation fails. + +2005-08-12 Arun M. Krishnakumar + + * rename.c, commonfops.c : removed the + dget/dput functions sandwiching the vfs_unlink as + these raise the refcounts and cause the .nfsXYZ + files to get created after unlinks. This knocks + out Bug#364 for 2.6. + +2005-08-11 Charles P. Wright + + * main.c (unionfs_parse_dirs): Prevent recursive Unionfs mounts. + + * branchman.c: Plug a few memory leaks. + +2005-08-11 Arun M. Krishnakumar + + * dentry.c (unionfs_d_release) : fixed a case that would + cause a reference to the lower-level nfs inode to be + present. This is part of #364. + +2005-08-11 Charles P. Wright + + * unionctl.c: Support --mode ro branch or --mode branch ro + + * branchman.c: Only count putmaps that exist. + +2005-08-10 Charles P. Wright + + * man/unionctl.8: No need for warning about root directory anymore. + * commonfops.c: Kill branch deletion ioctl. + + * super.c: Magic MS_REMOUNT to remove a branch. + * unionctl.c: Use remount instead of ioctl to remove a branch. + * branchman.c (unionfs_ioctl_delbranch): Take the super, not an inode. + +2005-08-10 Charles P. Wright + + * dentry.c (unionfs_d_revalidate): All exit paths should go through + out. + + * main.c (unionfs_parse_options,unionfs_parse_dirs): Simplified + option parsing using strsep rather than direct pointer manipulation. + Organized the options into types to factor out common code. + +2005-08-09 Charles P. Wright + + * debian/*: Use official debian packaging files. + + * Some AMD64 fixes. + * vprintk wrapper for 2.4. + +2005-08-09 Jan Engelhardt + + * unionctl.c: Do not truncate "/" to "" when stripping the last "/" + from directories. + +2005-08-05 Charles P. Wright + + * main: Use FS_REVAL_DOT so that directories are always revalidated + during lookup. + + * Drop err=passup, as it is unmaintained. + +2005-08-05 Arun M. Krishnakumar + + * commonfops.c (unionfs_flush) : changed the dput to give + more symmetry and readability to the code. + +2005-08-04 Arun M. Krishnakumar + + * dentry.c (unionfs_d_revalidate) : return successfully if the + dentry is unhashed + * commonfops.c (unionfs_flush) : corrected the d_unhashed check + +2005-08-04 Charles P. Wright + + * branchman.c (QUERY): Don't copy FD_SET before ioctl. FD_ZERO the + set before the call. + + * branchman.c (newputmap): Subtract the count from old putmaps from + the brand new putmap's count. + + * branchman.c (unionfs_ioctl_delbranch): Use putmaps. + * lookup.c (new_dentry_private_data): Fix branch removal when + transitioning from > UNIONFS_INLINE_OBJECTS to == + UNIONFS_INLINE_OBJECTS. + +2005-08-03 David P. Quigley + + * unionfs.h,main.c,super.c,inode.c: removed all code + pertaining SETATTR_ALL since the feature is not necessary + and complicates things. + * man/unionfs.4: removed text pertaining to the setattr + mount option. + +2005-08-03 Charles P. Wright + + * unionfs.h (putmap): We need to keep track of the mapping between + branch numbers for older generation numbers and the current + generation so that we can properly branchput. + * branchman.c: Add functions to manipulate putmaps. + * commonfops.c: Use putmaps for revalidation and close. + +2005-08-03 Arun M. Krishnakumar + + * dentry.c (unionfs_d_release) : added a check to take care + of the case when the dentry coming into release is from a + failed lookup. This knocks bug #303 out. + +2005-08-03 Charles P. Wright + + * Remove older non-opaque directory mode. + +2005-08-01 Arun M. Krishnakumar + + * lookup.c (unionfs_lookup_backend): Skip those hidden + dentries that are NULL. + +2005-08-01 Jan Engelhardt + + * print.c (fist_dprint_internal): Use vprintk instead of + vsnprintf/printk combo. + +2005-08-01 Charles P. Wright + + * unionfs_debugmacros.h (branchget,branchput): + ASSERT if a branch's count goes negative. + * super.c (unionfs_put_super): ASSERT if the branch + counts are not zero on unmount. + * commonfops.c (unionfs_file_release): Don't put branches + that we didn't get. + * commonfops.c (unionfs_open): Don't get a branch until + we open it. + + * commonfops.c: Fix generation number increment. + +2005-07-26 David P. Quigley + + * main.c: cleaned up parse_options code for copyup, + copyupuid,copyupgid,copyupmode. + +2005-07-26 Charles P. Wright + + * unlink.c, main.c, rmdir.c, rename.c: Remove obsolete + and unmaintained DELETE_FIRST mode. + +2005-07-26 David P. Quigley + + * man/unionfs.4: Added default behavior into the options + section for entries that didnt already have it. + +2005-07-26 Charles P. Wright + + * main.c (unionfs_parse_options): Move directory parsing + out of parse options function, so we don't have as many 4+ level + indents. + +2005-07-25 Charles P. Wright + + * Makefile: Update version number to 1.0.14pre. + +2005-07-25 Charles P. Wright + + * man/unionimap.8: Minor editing. + +2005-07-24 David P. Quigley + + * man/unionimap.8 : finished the man page: added a verbose + description and examples. + +2005-07-22 David P. Quigley + + * man/unionimap.8 : added descriptions to options in the + option section. + +2005-07-22 Jan Engelhardt + + * unionctl.c: Use realpath so that relative pathnames are allowed + for mountpoints and branches. + +2005-07-22 Arun M. Krishnakumar + + * subr.c (create_whiteout_parent) : removed this function + as it is not called anymore (#258). + +2005-07-22 Charles P. Wright + + * Makefile: Update version to 1.0.13. + * Makefile: Include new regression tests in distribution. + * man/unionimap.8: An empty placeholder man page. + +2005-07-21 David P. Quigley + + * missing_vfs_funcs.h: Removed get_parent function since the 2.6 + kernel has a dget_parent function which is the appropriate one to use + also made note that the templates do not use either triple_up or triple_down + * unionfs.h: checked to see if we are in 2.6 and if so define get_parent to be + dget_parent. + * unionimap.c: fixed a typo in the usage example. + * man/unionfs.4: added an entry for imap + +2005-07-21 Arun M. Krishnakumar + + * copyup.c (unionfs_create_named_dirs) : corrected the + function to get rid of problems with the open-unlink + regression test. + +2005-07-20 Arun M. Krishnakumar + + * unlink.c (unionfs_rmdir_all) : added checks to ensure + that the delete_whiteouts is not called for files. this + is a fix for bug 323 + + * rename.c (unionfs_rename_all) : changed the whiteout + creation call to "create_whiteout" instead of the + "create_whiteout_parent". this must solve 332. + + * rename.c (unionfs_rename_whiteout) : change similar + to above to correct #336. + +2005-07-20 Charles P. Wright + + * file.c (unionfs_file_revalidate): Handle GFS and don't try + to reopen files that no longer exist. + * subr.c (unionfs_copyup_named_dentry_len): Add a bit of debugging. + * Fix comments that are past 80 characters and some other + minor style issues. + + * subr.c (unionfs_create_whiteout): Don't set the parent's + opaque field when creating a whiteout, set your own. + +2005-07-20 Charles P. Wright + + * Fix things so that we compile on 2.4 again, and use the + older form of ioctl for kernels less than 2.6.11. + + * ChangeLog: 80 character entries. + +2005-07-19 Charles P. Wright + + * unionctl.c: Check if we are trying to remove a branch while + this process is causing it to be busy and print an appropriate + error message. + + * man/unionctl.8: Minor edits. + +2005-07-19 Arun M. Krishnakumar + + * branchman.c (unionfs_ioctl_queryfile) : changed + function replacing lookup_one_len by partial lookups + (second commit) : changed O_NONBLOCK to O_RDONLY + +2005-07-19 Shaya Potter + + * unlink.c (unionfs_unlink_whiteout): Don't rename a symlink + to a whiteout, we need to unlink and create instead. + +2005-07-18 Arun M. Krishnakumar + + * unlink.c (unionfs_unlink_all) : checked if the dbopaque + value is set for the current dentry, as this will + indicate if there is a file to the right of the current + file (Fix BUG #319). + +2005-07-18 Charles P. Wright + + * commonfops.c: Use unlocked_ioctl when it is defined. + * branchman.c: Change prototypes to be more consistent with + unlocked_ioctl. + + * commit: Script for committing files + * Lindent: Linux indentation script. + * *.[ch]: Add emacs magic. + +2005-07-14 Arun M. Krishnakumar + + * lookup.c (unionfs_lookup_backend) : fixed bug #321 + (that is, removed the semicolon that was introduced + in the unionfs-042605-1324.tar.gz snapshot. + +2005-07-14 Arun M. Krishnakumar + + * copyup.c (unionfs_create_named_dirs) : corrected the usage of + the name and namelen arguments sent into the function. This + should take care of both bugs #299 and #322. + +2005-07-13 Arun M. Krishnakumar + + * branchman.c (unionfs_ioctl_queryfile) : added ioctl definition + that lists those branches where the specified file exists(#253). + * commonfops.c (unionfs_ioctl) : added the new ioctl. + * fist.h : added an include for the fd_set helper functions + * unionfs.h : added a structure unionfs_queryfile_args to + pass variables to the new structure. + * unionctl.c : added the user interface + * uniondbg.c : rearranged the includes to help compilation + +2005-07-08 Arun M. Krishnakumar + + * unionfs.h : added variables uii_totalopens and uii_writeopens to + help in keeping filehandles valid after unlinks until closes. + * fist.h : included random.h to help get random bytes for file names + * commonfops.c (unionfs_file_revalidate) : added functionality to copy + the lower-level file into a file with a randomly generated name + obtained by using the newly added function "get_random_name" in + commonfops.c + (unionfs_open, unionfs_flush) : updated the uii_totalopens and + uii_writeopens to be set and checked during the time of opening and + flushing the file. + * copyup.c (unionfs_copyup_dentry_len) : made this into a wrapper + function which now accepts the name of the file + (unionfs_copyup_named_dentry_len). + (unionfs_copyup_file) : similar wrapper to unionfs_copyup_named_file + as above. + (unionfs_create_dirs) : similar wrapper to unionfs_create_named_dirs + as above + (unionfs_copyup_named_file) : added function similar to + unionfs_copyup_file which takes the file name as argument as well. + * main.c (unionfs_reinterpose) : ensured that deleted dentries are not + reinterposed. + * dentry.c (unionfs_d_revalidate) : changed the check for deleted + dentries to use the d_unhashed function also. + +2005-07-07 David P. Quigley + * main.c: Ohh my god the inodes are persistent. Ohh and changed + interpose to use get_uin if we are using persistent inode maps. + +2005-07-07 David P. Quigley + * super.c: fixed problem with kernel version number in an ifdef + +2005-07-07 David P. Quigley + + * dirfops.c: removed some debugging printk statments. + * persistent_inode.c: finished debugging and cleanedup get_uin. + +2005-06-30 David P. Quigley + + * unionfs.h added extern decls for get_uin and get_lin + * persistent_inode.c: more work on the loading code and get_uin and + get_lin + * dirfops.c: changed to make use of the persistent inode code only + if maps are loaded. + +2005-06-28 David P. Quigley + + * persistent_inode.c: changed how files are loaded in should be + done still need to test + * unionfs.h: added a new variable into unionfs_superblock_info + * unionimap.c: changed called to mkfsid + * usercommon.c: changed fillfsid and mkfsid. No longer uses the inode + since it will always be 2 since we are using the root of the fs. + +2005-06-24 David P. Quigley + + * Makefile: added usercommon.c into the make targets + * usercommon.c: Moves find_union to here and fixed it up + * unionimap.c: uses mkfsid now if fsid comes back as 0 + * unionimap.h: added extern for mkfsid + * persistent_inode.c: fixed some bugs + * unionctl.c: removed find_union from here and updated calls to it. + +2005-06-23 Charles P. Wright + + * dentry.c (d_revalidate): We shouldn't re-lookup + non-connected dentries. + +2005-06-23 Arun M. Krishnakumar + + * Makefile: Include Makefile.kernel. + + * subr.c (create_whiteout, create_whiteout_parent): Set the dbopaque + value to the branch where the whiteout gets created. This is to solve + bug #294. + +2005-06-22 Arun M. Krishnakumar + + * commonfops.c (unionfs_open): If the highest-priority branch + is read-only return -EROFS for opens with O_WRITE. + +2005-06-21 David P. Quigley + + * persistent_inode.c: parse_imap_options and associated calls are + working. maps are loaded in properly. Still need to finish and test + calls to use the maps. + +2005-06-17 David P. Quigley + + * persistent_inode.c: it appears that parse_imap_options is working + and so is verify_forwardmap. verify_reversemap needs to be fixed. + +2005-06-17 David P. Quigley + + * persistent_inode.c: Fixed some bugs still not working properly + + * unionfs.h: added typedef for uuid_t. + + * doit.sh: added imap entry into script. + +2005-06-17 Charles P. Wright + + * INSTALL: If you have Fedora Core 4, then you need kernel-devel. + + * Makefile: Fix the Makefile so that it won't recompile every + object every time. + + * unionimap.c: Fix printf formats. + +2005-06-16 David P. Quigley + + * unionimap.c : Fixed a bug that prevented compiling on newer + gcc versions + +2005-06-16 David P. Quigley + + * unionimap.c : Tested and working we can now make and print valid + unionfs imap files. + +2005-06-16 David P. Quigley + + * unionimap.c : finished coding starting testing and debugging. + * unionimap.h : minor changes + +2005-06-15 David P. Quigley + + * unionimap.c : wrote some more code not tested yet + * unionimap.h : added a struct that is needed. + * Makefile: Cleanedup a conflict. + +2005-06-15 Charles P. Wright + + * fist.h,print.c,unionfs.h: Change NODEBUG to UNIONFS_NDEBUG to be + more inline with the rest of the kernel. + * print.c: Wrap in UNIONFS_NDEBUG, so there is no need for a separate + flag to not compile it. + + * unionctl.c: Add Unionfs version to help message + (not just unionctl version). + * unionimap.c: Add version to help message. + +2005-06-12 Charles P. Wright + + * main.c, match-malloc.pl: Handle KFREE(NULL). + * commonfops.c (unionfs_file_revalidate): NULL ftohf_ptr after freeing + it. + * commonfosp.c (unionfs_open): Allocate correctly sized ftohf_ptr. + +2005-06-10 David P. Quigley + + * unionimap.c: Beginning of a user mode program to create inode map + files. + * unionimap.h: Header for program. + * unionfs.h: added definitions for imap structs + * Makefile: added make targets for unionimap.c and .h + +2005-05-26 Charles P. Wright + + * persistent_inode.c: Comment out 64-bit division. + +2005-05-25 David P. Quigley + + * unionfs.h : added some variables to the unionfs_sb_info struct to + handle persistent inodes. + * persistent_inode.c : more work done on the parsing functions almost + done but not quite there yet. + * main.c : added entry in parse_options to handle persistent inodes. + +2005-05-24 Charles P. Wright + + * unlink.c (unionfs_unlink_whiteout): Missing dput in truncating fix. + + * unlink.c (unionfs_unlink_whiteout): Truncate whiteout after it + is created. + +2005-05-23 Charles P. Wright + + * Test commit. + + * inode.c (unionfs_create): Fix ASSERT that had a side-effect. + This fixes a dentry reference count bug if you compile with + -DNODEBUG. + +2005-05-19 Charles P. Wright + + * unlink.c: Empty a directory of its whiteouts before deleting it, + and refresh the hidden dentry on a failed rmdir. + + * unionfs.h: Always include ufi_file_i, so we can compile with zero + inline entries if we want. + + * Test commit. + + * Makefile: Define UNIONFS_VERSION to be the current version. + * main.c: Print the version of Unionfs, not main.c. + +2005-05-17 Charles P. Wright + + * lookup.c (unionfs_lookup_backend): Fix partial lookups for + three or more branches. + +2005-05-16 Charles P. Wright + + * lookup.c (unionfs_lookup_backend): Change UNIONFS_LOOKUP_PARTIAL + to UNIONFS_LOOKUP_REVAL_NEG, when a dentry magically turns positive + on us. + +2005-05-14 Charles P. Wright + + * lookup.c (new_dentry_private_data): Fix memset'ing logic. + * branchman.c (unionfs_ioctl_addbranch): Fix copying logic. + + * inode.c(unionfs_follow_link): Return 0 not the number of bytes + in follow_link. + + * Reduce Unionfs module size when NODEBUG is set by not compiling + print.c, and using a different set of macros that don't require + __FILE__, __FUNCTION__, and __LINE__, and don't do as much checking + because we've aleady turned ASSERT off. + + * Support for inline objects, so that we don't need more + than one allocation for inodes and only two for dentries (the dentry + itself and its private data). + + * Separate directory file operations from normal file operations. + +2005-05-13 Charles P. Wright + + * Makefile: Increment version number. + + * Makefile: Release 1.0.12 + +2005-05-13 Charles P. Wright + + * file.c: Disable generic_file_sendfile, because it causes nfsd + to Oops. + + * lookup.c (unionfs_lookup): Don't ASSERT dentry goodness along + the error path. + * dentry.c (unionfs_d_release): Handle dentries without dthod_ptrs. + +2005-05-11 Jaspreet Singh + + * main.c (unionfs_interpose): Move fist_copy_attr_all before + d_instantiate so Selinux can decide what type of inode it is. + +2005-05-13 David P. Quigley + + * Makefile : fixed spelling mistake + * persistent_inode.c : fixed typo for compilation + +2005-05-12 David P. Quigley + * persistent_inode.c : Stupid spelling mistake in the name + of the file. + +2005-05-12 David P. Quigley + + * persistant_inode.c : Functions needed to establish and maintain + a persistant inode scheme for unionfs. + * main.c : modified parse options for persistant inodes. Not done yet + +2005-05-11 Jaspreet Singh + + * copyup.c (unionfs_copyup_xattrs): Don't use XATTR_CREATE, + instead use 0 so that it is replaced or created as needed + (Selinux automatically creates attributes. + +2005-05-11 Charles P. Wright + + * print.c (fist_print_generic_dentry): ASSERT(d_count > 0) so + that we find dentries gone bad earlier rather than later. + + * inode.c (unionfs_mkdir): bend should not go past the opaque + directory, but stay there. + +2005-05-10 Charles P. Wright + + * INSTALL: Add root file system instructions based on Linux + Live's linuxrc. + +2005-05-08 Charles P. Wright + + * main.c,super.c,lookup.c: Use alloc_inode in 2.6, so that only + two allocations need to be made per inode instead of two. In + both 2.4 and 2.6 use a private kmem_cache for our dentry data, + so that we don't need to waste space by having kmalloc round up. + + * lookup.c (new_dentry_private_data): Merge initialization and + reinitialization code from lookup and read_super. Also don't + reallocate dentry private data if we already have enough space. + + * INSTALL: Add Jaspreet Singh's selinux instructions. + + * INSTALL: Add EXDEV on ro branch rename as a limitation. + + * inode.c: follow_link and put_link fix for 2.6. + + * lookup.c: Compile fix for 2.4. + + * rename.c: If a directory is moved on a read-only branch return EXDEV, + so that mv essentially does a cp -r (recursive copyup in the kernel + would be too ugly). + +2005-05-06 Charles P. Wright + + * lookup.c: Merge unionfs_lookup_backend and unionfs_partial_lookup, + partial lookups will now properly handle whiteouts. + + * print.c: Fix compile error when NODEBUG is defined. + + * lookup.c: Fix BUG 264. + * print.c: Separate generic inode printing from itohi printing. + Use const for print functions. + +2005-05-05 Charles P. Wright + + * Code style fixes. + +2005-04-27 David P. Quigley + + * inode.c changed ops vectors to C99 style initialization. + * file.c changed ops vectors to C99 style initialization. + * dentry.c changed ops vectors to C99 style initialization. + * super.c changed ops vectors to C99 style initialization. + * stale_inode.c changed ops vectors to C99 style initialization. + +2005-04-21 David P. Quigley + + * unionfs.h: added no check versions ot set_dtohd_index + and dtohd_index. + * dentry.c: changed a function call to dtohd_index_nocheck + +2005-04-26 Charles P. Wright + + * lookup.c (unionfs_lookup_backend): When a whiteout is encountered, + set opauqeness as we do with opaque directories, to prevent partial + lookup from seeing past the whiteout. + + * lookup.c: Separate file for lookup code. + * subr.c: Move unionfs_partial_lookup to lookup.c. + * inode.c: Move unionfs_lookup to lookup.c: + + * rename.c: Don't print lower-level dentries using a Unionfs + specific function. + + * print.c: Divide fist_print_dentry into one function for Unionfs + specific dentries, and then a generic function. Also ASSERT that + we are really printing a Unionfs dentry (so we don't dereference + bad private data). + + * Fix indentation comments. + +2005-04-25 Charles P. Wright + + * subr.c: Code style fixes. + +2005-04-22 Charles P. Wright + + * NEWS: Keep NEWS up to date. + +2005-04-21 Charles P. Wright + + * file.c (unionfs_filldir): Don't strncmp for .wh., if the + name's length is less than 4. Old cruft can make things + go horribly bad (BUG 254). + + * inode.c (unionfs_lookup_backend): Properly handle file + transitioning from a negative to a positive dentry. (BUG 215) + +2005-04-21 Charles P. Wright + + * file.c: Sendfile only exists on 2.6. + * main.c: Catch UNIONFS_REVAL_NEG specifically, still + need to understand/fix. + +2005-04-20 Charles P. Wright + + * subr.c (unionfs_partial_lookup) ,unionfs.h + (unionfs_dentry_info), inode.c(unionfs_lookup): + Correctly mark a directory as opaque and respect that + during partial lookups. + + * Exorcise struct typedefs and "fake" STATIC functions. + + * inode.c: Experimental support for opaque directories, + not all of the loose ends are tied up, so this snapshot + will have some associated oddities. + + * xattr.c: Use EOPNOTSUPP, not ENOTSUPP. + + * Makefile, unionfs.h: Separation of rename/unlink code. + * rename.c: Separate rename code from inode.c + * unlink.c: Separate unlink code from inode.c + +2005-04-20 Charles P. Wright + + * rdstate.c, unionfs.h: DOH, We were checking if + uii_rdversion <= MAXRDCOOKIE to decide whether or not + to wrap uii_cookie. + +2005-04-19 Fabian Franz + + * applied patch to file.c that uses generic_file_sendfile + to implement sendfile. + +2005-04-18 David P. Quigley + + * removed a stray printk + +2005-04-18 Markus F.X.J. Oberhumer + + * file.c, locks.c: Use #ifdef for 64-bit locking + commands, which are not defined on amd64. + +2005-04-18 David P. Quigley + + * copyup.c: Extended attributes now copyup properly. + This has only been tested in 2.6 but I see no reason + that it shouldent work in 2.4 + * copyup.c: unionfs_create_dirs is now nolonger bound + by MAX_DIRS_CREATE. We now use kmalloc to dynamically + allocate memory for it and "realloc" the memory when + needed. + +2005-04-18 Charles P. Wright + + * copyup.c: Use list_size as the argument to xattr_free, not the + MAX_LIST_SIZE. + + * file.c: ASSERT was asserting on the dentry, not the i_mode. + +2005-04-16 Charles P. Wright + + * file.c: Delay copyup of read-write files located on read-only + branches, until an operation will actually write to them (BUG 225). + + * INSTALL: Cleanup kernel instructions a bit. + +2005-04-13 David P. Quigley + + * inode.c: unionfs_mkdir now spoofes the uid and gid of the owner + of the whiteout file for the purpose of removing it. + +2005-04-11 David P. Quigley + * patch-kernel.sh : Script written to move unionfs into the kernel + source tree. The original script was submitted by Sven Geggus however + the script was cleaned up and modified for various reasons. Check the + file for more details. + * Makefile: PHONY added to the utils target to aid in building them + for the kernel. + * INSTALL: Directions added for building unionfs into a monolithic kernel. + +2005-04-11 David P. Quigley + + * copyup.c : changed comparison from > to >= to be compatable with 2.6.0 + * fist.h : same as above + * unionfs.h : same as above + * rdstate.c : same as above + * main.c : same as above + * inode.c : same as above + * super.c : same as above + * xattr.c : sme as above + +2005-03-24 David P. Quigley + + * unionfs.h : changed UNIONFS_SUPER_MAGIC. All fist based file systems + will have the first 2 bytes of the MAGIC number be f15f. + * super.c : statfs struct is now properly filled. + +2005-03-23 David P. Quigley + + * INSTALL: removed the warning about NFS exports + * Makefile: Increases release number. + * NEWS: Added release news for 1.0.11 + * unionfs.h: added a function rdstate2offset + * file.c: redid llseek and readdir implementation + * rdstate: redid find_rdstate + +2005-03-21 Charles P. Wright + + * Add big warnings that NFS exports won't work in 1.0.10. + +2005-03-17 Terry Barnaby + + * rdstate.c (find_rdstate): Factor out rdstate search. + * file.c (unionfs_dir_llseek): Use rdstate if it exists. + +2005-03-16 Terry Barnaby + + * Makefile: fix clean target + + * file.c (unionfs_dir_llseek): Fix mistaken use of origin + instead of offset. + +2005-03-16 Charles P. Wright + + * super.c (unionfs_statfs): Use shifting instead of division. + +2005-03-15 David P. Quigley + + * super.c (unionfs_statfs) : df now reports the proper numbers. + duplicate super blocks are not factored into the calculations and + all the block sizes are normalized to the first partition. + +2005-03-14 David P. Quigley + + * main.c (unionfs_read_super) : In 2.4 the kernel expects a valid + super block or null we were returning an error pointer and this + caused an Oops. This has been fixed. + +2005-03-10 Charles P. Wright + + * unionfs_getlk (unionfs_getlk): Add preprocessor define for + 2.6.11+, and add a missing case. + +2005-03-10 David P. Quigley + + * locks.c (unionfs_setlk): fixed a typo in the 2.6 function + +2005-03-10 Charles P. Wright + + * misc/snapmerge: Explain how to get two snapshots merged into one + snapshot. + + * file.c (unionfs_dir_llseek), locks.c (unionfs_setlk): Fix build + on 2.6. + +2005-03-09 David P. Quigley + + * file.c (unionfs_lock): function is completely rewritten to actually + work. + * locks.c (unionfs_setlk,unionfs_getlk): locks.c was added to house + locking functions so file.c doesent get overcrowded. unionfs_setlk + and unionfs_getlk were added and placed in this file with some + helper functions for 2.6 + +2005-03-08 Terry Barnaby + + * file.c (unionfs_dir_lseek): Allow seek to beginning/end of dirs. + +2005-03-07 Fernando Freiregomez + + * misc/snapmerge: Fix permissions/times after copying files. + +2005-03-07 Lucas Correia Villa Real + * Makefile: Use MODDIR instead of /lib/modules/`uname -r` + +2005-03-07 Eduard Bloch + * man/*: Fix man page sections + * Makefile: Add separate modules target, remove excessive uname -r's + so that kernel version can be overridden. + +2005-03-03 Anton Farygin + + * Makefile: Can now build utilities without building kernel module. + +2005-03-03 Terry Barnaby + + * dentry.c (unionfs_d_revalidate): Use fist_copy_attr_all to + make the cache appear more coherent. + +2005-03-02 Fabian Franz +2005-03-02 Anton Farygin + * dirhelper.c: Fix BUG 184: vfs_readdir is allowed to return positive + results. + +2005-03-02 Charles P. Wright + + * inode.c (unionfs_readdir): Remove buf.error which was unused. + +2005-03-02 Anton Farygin + + * Fix BUG 205: mv on symlinks + + * Fix BUG 203: Kernel oops on creat file with len of name > 252 + +2005-02-24 Charles P. Wright + + * RPM spec file included in release. Remove CVS directory from + debian directory in release. + + * Add fsid= to interactions, with pointer to exports(5). + +2005-02-22 Charles P. Wright + + * unionctl.c (find_union): Start off w/ a 1K buffer and double it + if the lines in /proc/mounts don't fit. Thanks to J. H. Wilson for + finding and patching this bug. + + * main.c (unionfs_interpose): Reorganize if statement. + + * rdstate.c (add_filldir_node,find_filldir_node): Don't print the + names in debug mode because they aren't '\0' terminated. + +2005-02-22 Fabian Franz + + * Applied patch to bug 193 Fixed the problem with + hardlinks not having the same inode number. + +2005-02-22 Charles P. Wright + + * dentry.c (unionfs_d_delete): d_delete should not be defined (or + call the lower d_delete). Thanks to Fabian Franz for identifying + this issue. + +2005-02-22 Fabian Franz + + * copyup.c (unionfs_copyup_dentry_len): Applied patch provided + for bug #196. A device was being decoded when it didnt have to be. + +2005-02-22 Charles P. Wright + + * README: Article URL. + +2005-02-18 David P. Quigley + + * dirhelper.c (create_dir_whs) : commiting chips change to make + sure it creates whiteouts properly. + +2005-02-17 Charles P. Wright + + * INSTALL: Squashfs is generally OK, but we do have flock problems. + + * file.c (unionfs_dir_llseek): Untested fix for BUG 187. + +2005-02-09 David P. Quigley + + * inode.c (unionfs_link): Fixed linking if the underlying file + system is read-only. The fix causes an issue with device being + busy on umount. * rdstate.c (find_filldir_node): Print statement + was referencing a bad pointer. + + +2005-02-08 Charles P. Wright + + * copyup.c (unionfs_copyup_xattrs): Use PASSERT, other compile fixes. + * xattr.c (xattr_alloc, xattr_free): Shouldn't be static. + * Go back to GFP_KERNEL, because GFP_NOFS causes problems with vserver. + +2005-02-08 Jaspreet Singh + + * copyup.c (unionfs_copyup_xattrs): Use security functions. + +2005-02-08 Charles P. Wright + + * copyup.c (unionfs_copyup_xattrs): Take the inode lock as is done in + setxattr. + * inode.c (unionfs_link): Reference counting on error paths/compile fix. + +2005-02-07 Charles P. Wright + + * inode.c (unionfs_link): On copyup path directory was not unlocked. + +2005-02-07 David P. Quigley + + * copyup.c (unionfs_xattr_copyup): Review of code, not yet tested. + + * inode.c (unionfs_link): Revert to Chip's version of + unionfs_link. + +2005-02-07 Charles P. Wright + + * Makefile: Allow module prefixes to be specified for + RPM_BUILD_ROOT + * rpm/unionfs.spec: Compiled, tested, and installed. + +2005-02-06 David P. Quigley + + * Makefile added a target for uninstall to accomodate rpm removal + +2005-02-02 Anton Farygin + + * copyup.c (unionfs_copyup_permissions): Use ATTR_FORCE to make + sure any user can change permissions. + * copyup.c (unionfs_create_dirs): Twiddle current->fsuid/fsgid + so that any user's copyup will behave properly. + +2005-02-02 Charles P. Wright + + * file.c (unionfs_mmap): Don't ASSERT that the lower mmap + operation is there, instead return ENODEV, as is done in + do_mmap_pgoff. NTFS (and others) don't support mmap, so + neither should we when stacked on top. + +2005-02-01 David P. Quigley + + * dirhelper.c : fixed 2.6 compilation. call to vfs_creat missing + last param in 2.6 + + * Makefile : namei.c is no longer needed so it was removed from + the make file. + +2005-01-28 Charles P. Wright + + * subr.c, dirhelper.c: Move mkdir/rmdir helpers into separate + file. + + * unionfs.h, fist.h: Remove unused/redundant definitions. + +2005-01-26 Charles P. Wright + + * rdstate.c, unionfs.h: Move finding and adding filldir nodes + into rdstate.c. This reduced the readdir code size, and should + also let us reuse the code for the subr.c functions. + * subr.c: Use an rdstate instead of a second readdir to remove + files in delete_whiteouts. + * namei.c: Removed vfs_unlink_nozombie. + +2005-01-19 Charles P. Wright + + * INSTALL: Add more CFLAGS options to make things smaller. + + * unionfs.h, file.c, rdstate.c: Change DIREOF from -1 to 2^31-1 to + fix readdir. + + * unionctl.c: Don't strip trailing slash for "/" when searching for + the Union. + + * Makefile: Include INSTALL. + +2005-01-14 Charles P. Wright + + * branchman.c (unionfs_ioctl_addbranch): Fix error path resource leak. + +2005-01-14 David P. Quigley + + * copyup.c (unionfs_copyup_permissions): Changed so it actually works now + instead of corrupting certian bits. + * copyup.c (unionfs_create_dirs): Function actually uses unionfs_copyup_permissions + for setting directory permissions instead of setting them explicitly. + +2005-01-14 Charles P. Wright + + * file.c (unionfs_dir_llseek): Allow llseek to the current + offset in the directory, but nowhere else. + * file.c (unionfs_readdir): Save the last offset, so we + can lseek to it (for pretend). + + * Remove all occurrences of GFP_KERNEL and replace with GFP_NOFS, + so our allocations can't cause file system calls. + +2005-01-13 Rakesh N. Iyer + + * file.c (unionfs_readdir): Fixed deadlock in rdstate search. + +2005-01-13 Charles P. Wright + + * Split README into INSTALL as well. + + * Makefile: Spit out a message saying to read install. + + * Don't build xattr functions w/o -DUNIONFS_XATTR + +2005-01-11 David P. Quigley + + * inode.c: Initial implementation of hardlinking a file on a read only branch. + Attributes are not copied properly yet. + +2005-01-10 Sai Suman + + * copyup.c: Fix usage of unionfs_copyup_permissions. + +2005-01-10 Charles P. Wright + + * super.c: 2.4 compile fixes + + * fist.h: Updated FISTBUG for gcc 2.9.5 + +2005-01-10 David P. Quigley + + * xattr.c: Format changes for size_t. + + * doit.sh: Call optional postdoit script + +2005-01-10 Charles P. Wright + + * AUTHORS file. + + * README updates. + + * Allow NFS exports on 2.6 (Sai Suman) + * Fixes to print format in xattr.c (Sai Suman) + + * debian/*: Debian packaging from Alex de Landgraaf. + + * Remove -Wno-unused-label for gcc 2.9.5 (alex@delandgraaf.com). + * Allow "EXTRACFLAGS=-DNODEBUG" in fistdev.mk to disable + the printing/ASSERT facility, cutting object size in half. + +2005-01-09 Charles P. Wright + + * unionfs.h: Warn when compiling on unsupported kernels. + * super.c: Compile fix for 2.6.8. + * Makefile: Include ChangeLog in the release. + +2005-01-07 Charles P. Wright + + * Prepare 1.0.6 release. + + * Fix 2.6 compile issues in new code. + + * rdstate.c: Move readdir state away from subr.c. + Use a kmem_cache for filldir nodes. + + * copyup.c: Move copyup functions away from subr.c + +2005-01-06 Charles P. Wright + + * file.c: Working NFS readdir. On close we store left-over + readdir state in the inode for up to 5 seconds. If a readdir + has a matching cookie, then we pull the state out of the inode + and use it. We also needed to use our own offsets, otherwise + the NFS client got confused. + + * subr.c: Remember the number of entries in our hash table for + each inode, and use that as the number for the next readdir. + + * Makefile: Fix dependencies on .h files. + + * print.c: Consistencify printing of files and superblocks + and shorten some overly verbose output that added no information, + but reduced the effective kernel log size. + + * fist.h: Make gcc check fist_dprint_internal formats. + + * file.c,unionfs.h: Separate readdir state into a separate structure. + + * file.c,unionfs.h,subr.c: Make readdir state use variable sized + hash tables based on number of pages in lower-level directories. + + * Makefile: Install unionfs.ko, not unionfs.o if it exists. + + * main.c: Remove MODULE_PARM because it is deprecated. + +2005-01-04 Charles P. Wright + + * file.c (unionfs_read): Fix "inifite" cat bug on 2.6 + + * Makefile: Auto-select 2.4 vs. 2.6 for build. + + * Unify 2.4 and 2.6 Makefiles + + * Fixes for printing file structures at debug level 18. + + * Fixes for 2.4 compilation. + +2004-12-30 Charles P. Wright + + * *.[ch]: Update year. + +2004-12-29 Charles P. Wright + + * inode.c: Embed rename.txt into comment. + +2004-12-29 Charles P. Wright + + * inode.c, unionfs.h: Changed directory copyup function back to + old prototype. + + * subr.c (unionfs_copyup_dentry_len): Handle directories, devices, + and symlinks. + +2004-12-27 Charles P. Wright + + * inode.c: Only request copyup of parent directories. + + * subr.c (unionfs_copyup_dentry_len): Handle directory copyup + (required for chmod). + + * main.c (unionfs_parse_options): Fix along error path. + +2004-12-06 Charles P. Wright + + * main.c (unionfs_interpose): Allow mount point crossing. + + * README, Makefile, inode.c: Turn off extended attributes, unless + the user specifically turns them back on by defining UNIONFS_XATTR. + This prevents us from getting various compile errors depending on + vendor-specific patches. + +2004-11-10 Charles P. Wright + + * Fix .cvsignore and release. + + * README: Added warning that anything less than 2.4.20 is unsupported. + + * namei.c: Removed inode_dir_notify calls when we are on less than + 2.4.20, because the symbol is not exported. + + * Fixed lots of bad casts from pointer to int in printks. + + * main.c (unionfs_parse_options): Fix for badly ordered variables. + + * main.c (unionfs_read_super): Remove double free along error path. + + * wrapfs.h (dtopd_lhs): Remove cast from LHS of assignments. + +2004-11-09 Erez Zadok + + * released unionfs-1.0.2. + + * README (site): fix typo. missing "`". + + * Makefile (clean): remove tarball. + + * README: updated. + +2004-11-09 Charles P. Wright + + * released unionfs-1.0.1. + + * Makefile: Include man pages in the release. + +2004-11-07 Erez Zadok + + * released unionfs-1.0. + + * announce-email.txt: revised announcement text. + +2004-09-23 Erez Zadok + + * announce-email.txt: draft announcement email. + + * README: revised. + +2004-09-15 Charles P. Wright + + * file.c: Don't allocate directory hash table for files. + + * inode.c (unionfs_setattr): Don't do partial lookup if setattr is not + set to all (should improve delete_whiteout). + + * Some grayout code (we don't discuss rename_first anymore, so it + actually doesn't matter). + +2004-08-24 Charles P. Wright + + * namei.c (vfs_create_nozombie): Whiteout creation needs a version + of vfs_create that won't down the i_zombie. + + * subr.c (create_dir_whs_filldir): Don't ASSERT that the whiteout + doesn't already exist, because we can have multiple files with + the same name in other branches. + +2004-08-23 Mohammad Nayyer Zubair + + * inode.c (unionfs_mkdir, unionfs_symlink, unionfs_mknod): lookup + whiteout in 'bstart' not 'bindex'. We always looked up on first branch + as bindex was set to 0 + +2004-08-20 Charles P. Wright + + * inode.c (unionfs_inode_revalidate): Walk up the tree to revalidate + inodes like we do for dentries. + + * inode.c, subr.c, unionfs.h: Use multilocks to protect against + unionfs_partial_lookup and revalidate operations racing against + each other. + + * unionfs.h: Implementation of "multilocks". + + * Makefile: install target + + * We don't change size, so no sca_*.[ch] files. + + * main.c (unionfs_hidden_dentry_index): This function is unused now + that Mohammad took it out, so I removed it. + + * Removed unnecessary files. + + * COPYING: SUNY we can't be blamed for anything notice; and the GPL. + +2004-08-19 Mohammad Nayyer Zubair + + * inode.c (unionfs_setattr): using dtohd_index() instead of + unionfs_hidden_dentry() because an intermediate hidden dentry + could be NULL and we dont want PASSERT to oops on us + +2004-08-19 Charles P. Wright + + * inode.c (unionfs_unlink_all): We shouldn't have negative dentries + unless they are the first one. + + * inode.c (unionfs_inode_revalidate): PASSERT(hidden_inode) instead + of Oopsing. + + * inode.c (unionfs_rename_all): Typo in the clobbering unlink. + + * inode.c (unionfs_rename_all): No debug printks. + + * unionfs.h (get_nlinks): Don't sum up non-directories. + + * subr.c (unionfs_refresh_hidden_dentry): Re-lookup a dentry, this + is needed on rename reverts because vfs_rename trashes the dentry + of the target. + + * inode.c (unionfs_rename_all): Working revert. + +2004-08-18 Charles P. Wright + + * inode.c (unionfs_rename_all): New rename that handles more cases, + revert code doesn't work yet. + +2004-08-18 Mohammad Nayyer Zubair + + * inode.c (rmdir_all): exit if error is not -EROFS and not -ENOTEMPTY + + * inode.c (rmdir_all): exit from function and dont create whiteout + if vfs_rmdir returns error other than -EROFS + + +2004-08-17 Charles P. Wright + + * inode.c (unionfs_unlink_all): Unlock the directory on error. + + * inode.c (unionfs_setattr): Lock on all attribute changes, not just + some. + + * inode.c (do_rename): Check renames based on index rather than + new_dentry which might not exist. + + * Makefile: debugging symbols are very useful for Oops tracing + + * unionfs.h (CUR_MAX_BRANCH): Removed CUR_MAX_BRANCH which was always + sbend + 1, and replaced with sbmax (that doesn't require a redundant + and possbly inconsistent field within the super-block). + + * unionfs.h (dtopd): Converted from a macro to an inline function + so that we can do more checking of the private data that we are + returning. + + * unionfs.h (dtohd_index) Added a udi_bcount field to the private data + so we would Oops rather than silently overflow array bounds. + + * dentry.c: Recursively revalidate the parent (the ASSERT that was + checking this was mis-written). It turns out that our parent was not + always valid. + + * file.c (unionfs_file_revalidate): Always reassign the read-ahead + values because the older file might have different values and llseek + will cause an assertion failure. + + * inode.c (unionfs_lookup_backend): Treat revalidated negative and + positive dentries differently. + +2004-08-16 Charles P. Wright + + * inode.c: Use an fd_set instead of an integer for tracking successful + renames. + + * branchman.c: Don't allow more than FD_SETSIZE (1024) branches. + + * unionctl.c: Specific message for exceeding FD_SETSIZE. + +2004-08-11 Charles P. Wright + + * inode.c: Return ENAMETOOLONG when looking up ".wh.*" + + * unionctl.c: Add ioctl. + + * branchman.c: Don't allow branches without MAY_READ + + * unionctl.c: Convert branch pathnames into index automatically. + + * unionctl.c: Match the longest prefix of our path inside of + /proc/mounts instead of the path itself. This is required so that + remove doesn't need to open the root of the union. + + * unionctl.c: Remove branch ioctl and list branch configuration. + +2004-08-10 Mohammad Nayyer Zubair + + * file.c: added CAP_SYS_ADMIN checks before calling unionfs ioctls + + * uniondbg.c: now contains debugging related ioctls + + * unionctl.c: now contains ioctls to add, remove and set branch + permissions moved here + + * uniondbg.c: ioctls to add, remove and set branch permissions + moved here + + * fist_ioctl.c: remaining ioctls stay here + + * subr.c: making sure copyupuid, copyupgid and copyupmode are all + specified when copyup option is set to mounter. + + * inode.c: implemented unionfs_rename_first() + +2004-08-09 Mohammad Nayyer Zubair + + * inode.c: more places where we should exit if get an error other than + -EROFS in unlink/rmdir and related functions. + + * subr.c: exit if get an error other than -EROFS when + creating/deleting whiteouts + + * inode.c: making sure that we create/mkdir/symlink/mknod to the + left only if the error returned is -EROFS, otherwise passup + + * subr.c: use notify_change instead of directly modifying the inode + fields. + + * subr.c: use notify_change instead of directly modifying the inode + fields. + + * main.c: added copyupuid, copyupgid and copyupmode mount options. + These options will specify the mode, uid and gid of copied-up files. + copyup option should be set to mounter. + + * subr.c: using the above mount time values for copied-up files. + + * unionfs.h added these values in the unionfs super block. + +2004-06-17 Charles P. Wright + + * file.c (unionfs_flush): Flush all branches (only makes a + difference for directories). + +2004-08-03 Mohammad Nayyer Zubair + + * super.c: Implemented unionfs_show_options. Can now view unionfs + mount time options in /proc/mounts + + * inode.c: using is_robranch_super instead of is_robranch in + create, mkdir, symlink, mknod operations, whenever we try to + remove whiteouts if they exist. + + * main.c: while parsing options using strcmp wherever we can, + removed all magic numbers, copyup options are now preserve, + currentuser, mounter + + * subr.c: when copying up the default mode should be original + owner (preserve) + +2004-08-02 Mohammad Nayyer Zubair + + * main.c: unionfs mount time flag changed from being an integer + flag to several text options that will together make up the flag. + +2004-05-17 Charles P. Wright + + * branchman.c: Fixed off by one error when adding more than 8 + branches. + +2004-05-10 Charles P. Wright + + * main.c (unionfs_read_super): Error check to prevent oops on bad + mount-time options. + +2004-04-21 Charles P. Wright + + * file.c: revalidate files when the are passed into our methods, + this allows copy-up of open files. Yeah snapshots. + + * dentry.c: Should not use d_hash and d_compare because Unionfs is + in charge of the namespace, not the lower-level file systems. + + * Unionfs now has split-view caches. If compiled with + -DSPLIT_VIEW_CACHES, then Unionfs supports duplicating the super + block structure and dynamically selecting the correct structure to + use when crossing into the unionfs mountpoint. Right now the + default behavior is that root has one view, and every other user + has another view. + + If the super block is not duplicated then everything works as + before. + +2004-04-20 Charles P. Wright + + * branchman.c: Super Duper works! An ioctl can let you create a + super block that is a copy of the original. When you stat the + mountpoint that super block is returned. Now to fix the reference + counting bugs associated with unmount. :) + +2004-04-19 Charles P. Wright + + * super.c (unionfs_select_super): return s_root for now + +2004-03-15 Charles P. Wright + + * dentry.c (unionfs_d_revalidate): Fix refcounts. + + * inode.c (unionfs_inode_revalidate): Fix reference counting. + + * inode revalidate "works" (e.g., no Oopses or other broken f/s + behavior), but has broken reference counting. + +2004-03-14 Charles P. Wright + + * main.c (unionfs_interpose): Changed neg_dent_flag to which was + true if we did *not* have a negative dentry to is_negative_dentry + which *is* true if we have a negative dentry. Fixed related + assert (which was ASSERT(1)). + + * inode.c (unionfs_lookup): Read through and simplified lookup by + removing duplicated code or nasty if/else statements when if + continue would work(to the tune of 20%). Clarified comments as + well. Now instead of being a 248 line monster it is a 199 line + monster. + + * UNIONFS-TODO: We still need to solve whiteouts (i.e., you can + sucessfully stat a whiteout in Unionfs). Note this is not + introduced by my changes. + +2004-03-12 Charles P. Wright + + * branchman.c (unionfs_ioctl_rdwrbranch): Read/write branch setting. + +2004-03-11 Charles P. Wright + + * branchman.c (unionfs_ioctl_addbranch): Refcount fix. + +2004-03-04 Charles P. Wright + + * inode.c (do_rename): Correctly check is_readonly. + + * fist.h (print_exit_pointer): Print out pointer using %p and + don't convert using PTR_ERR if it is not IS_ERR. + + * subr.c (unionfs_create_parent_dir): Return error as pointer + + * subr.c (create_whiteout): Check branch before creating whiteouts. + + * unionfs.h (VALID_MOUNT_FLAGS): Define valid mount flags in the + header, so main.c doesn't need to know all of them. + + * doit.sh (FLAG): Default mode should be UNLINK_ALL, not + UNLINK_WHITEOUT. + + * inode.c (unionfs_unlink): Unlink creates whiteout to the left. + +2004-03-03 Charles P. Wright + + * inode.c (unionfs_create): Creation on a robranch will + cause the file to be created to the left. + + * unionfs.h: More macros for checking if things are on read-only + branches. + + * xattr.c: Separate xattrs from inode.c. + + * ATTACH-TODO.txt: Unionfs doesn't attach. + + * README.attach: Unionfs doesn't attach. + + * mmap.c: Unionfs doesn't filter data. + + * vm_area.c: No data filtering. + +2004-03-02 Charles P. Wright + + * main.c: Updated parsing code so that dirs can be specified as + b0=rw,b1,b2=ro,b3. Defaults to rw. Need to actually integrate + the permission checking code elsewhere. + +2003-11-10 Harikesavan Pathangi Krishnan + + * file.c (unionfs_readdir): Changed code to fix the NFS related bug. + +2003-10-27 Harikesavan Pathangi Krishnan + + * subr.c (unionfs_copyup_dentry_len): This is a modified form of + unionfs_copyup_dentry() that takes in the length of file to be + copied up. The length is useful when the file size is changed in + the setattr. + +2003-10-01 Puja Gupta , Jay, Mohammad. + + * subr.c (unionfs_copyup_dentry): fixed copyup bug, update bstart, bend + on error on vfs_create. + +2003-09-27 Puja Gupta , Hari, Jay. + + * inode.c (unionfs_rename_all): fixed to call rename and create + whiteout for test_rename script. + +2003-09-26 Puja Gupta , Zubair, Hari. + + * subr.c (create_whiteout): removed unnecessary dput of hidden_dentry. + +2003-09-26 Puja Gupta , Hari + + * subr.c, inode.c, unionfs.h: Better function name and comments. + + * inode.c (unionfs_rename_all): changed to create whiteouts + properly on error conditions. + (unionfs_rename_whiteout): initilize parent dentry. + +2003-09-26 Harikesavan Pathangi Krishnan , Puja. + + * print.c (fist_print_dentry): added print for d_parent, aligned. + + * subr.c (create_whiteout_left_parent): Added function for + creating whiteout in a parent directory by a char * string. + (unionfs_create_parent_dir): initialize dtohd before checking and + changing the bstart and bend for new dentry. + (unionfs_copyup_dentry): removed extra dput, since fput internally + does that. + + * inode.c (unionfs_rename_whiteout): fixed to support copyup for EROFS. + +2003-09-24 Puja Gupta , Hari, Jay. + + * subr.c (unionfs_create_parent_dir): Fixed updating bstart for copyup. + +2003-09-23 Puja Gupta , Hari, Jay. + + * subr.c (unionfs_create_parent_dir): Updates bstart, bend, dputs + extra negative dentries. + +2003-09-23 Puja Gupta , Hari, Jay. + + * subr.c (unionfs_create_parent_dir): Dput the previous negative + dentry. + + * inode.c (unionfs_create, unionfs_mkdir, unionfs_mknod, unionfs_link) + (unionfs_symlink): Removed dgets and dputs to handle errors in + vfs functions. Now handled in unionfs_create_parent_dir. + (do_rename): removed dputs and dgets to balance with create_parent. + +2003-09-22 Harikesavan Pathangi Krishnan , Mohammad. + + * subr.c (unionfs_create_parent_dir): Fixed a bug related to + igrabbing lower inode. + +2003-09-22 Akshat Aranya + + * main.c (unionfs_parse_options): Fix some memory leaks in error + paths. + +2003-09-22 Charles P. Wright + + * main.c (unionfs_read_super): Fixed error path. + +2003-09-22 Erez Zadok + + * match-malloc.pl: document this script with a procedure telling + how to use malloc debugging. Use -DFIST_MALLOC_DEBUG from now on. + +2003-09-22 Puja Gupta + + * fist.h, main.c, subr.c: turned off MEMORY_DEBUG. + +2003-09-22 Puja Gupta + + * main.c (unionfs_read_super): Memory fix. + +2003-09-22 Puja Gupta + + * inode.c, dentry.c, super.c: Memory Leak Checks. + +2003-09-22 Erez Zadok + + * subr.c: add transcation counter to malloc/free debugging. + + * match-malloc.pl: perl script to parse log output from + KMALLOC/KFREE macros, and report leaks etc. + +2003-09-21 Mohammad Nayyer Zubair , Puja, Hari, Jay. + + * inode.c (unionfs_lookup): changed the dput location of hidden + whiteout dentry in the code. + +2003-09-22 Puja Gupta + + * subr.c (check_empty): added list_del. + + * inode.c (unionfs_lookup): kfree moved at out. + (unionfs_unlink_whiteout): added kfree. + +2003-09-21 Mohammad Nayyer Zubair , Puja, Hari, Jay + + * subr.c (create_parent_dir()): added support for left to right + copy up. Could be used in unionfs_link() + +2003-09-21 Puja Gupta , Jay, Hari, Mohammad. + + * subr.c (check_whiteout): check for error on kmalloc. + (check_empty): moved kfree after 'out' label. + + * main.c (unionfs_read_super): changed to dput superblock dentries on + error conditions. + + * file.c (unionfs_filldir): check for error on kmalloc. + +2003-09-21 Mohammad Nayyer Zubair , Puja, Hari, Jay. + + * inode.c (unionfs_link()): unlinking .wh.foo (if exists) + while creating link called foo + +2003-09-21 Puja Gupta , Hari, Jay, Mohammad. + + * inode.c (unionfs_mkdir, unionfs_mknod): dget hidden_dentry if not + calling create_parent_dir. + + * inode.c (unionfs_mkdir, unionfs_mknod): removed extra dget before + removing whiteout. + +2003-09-21 Mohammad Nayyer Zubair , Hari, Jay, Puja. + + * inode.c (unionfs_symlink()): removed extra dget() in symlink + +2003-09-21 Puja Gupta + + * inode.c, dentry.c, unionfs.h: variable declaration re-shuffled to + compile on local machine. + +2003-09-21 Mohammad Nayyer Zubair , Hari, Jay, Puja + + * subr.c (create_dir_whs()): removed extra dget on hidden dentry + + * file.c (unionfs_open()): calling branchput if get an error in + opening hidden dentry + +2003-09-21 Puja Gupta , Jay, Hari, Mohammad. + + * inode.c: removed extra bstart, and comments. + + * file.c (unionfs_readdir): Added a bindex++ to {un,re}-reverted code. + Works now!! ;-) + +2003-09-21 Mohammad Nayyer Zubair , Hari, Jay, Puja. + + * subr.c (create_whiteout_left()): synched reference counts for + hidden_dentry; added a dget for the hidden_dentry + +2003-09-21 Puja Gupta , Jay. + + * inode.c (unionfs_create): removed extra dget, dput for vfs_rename. + Removed extra dputs, d_drop on error. + +2003-09-21 Puja Gupta + + * subr.c (unionfs_create_parent_dir): removed extra dput on error + in lookup. + (create_whiteout_left): mode set to create whiteout. + (delete_whiteouts): removed dput on NULL hidden_dentry. + +2003-09-20 Mohammad Nayyer Zubair Puja, Jay + + * inode.c: removed all "dtohd_index(dentry, bindex) = NULL" references and any + extra dputs + + * subr.c: modified code in troublesome create_whiteout_left() function. + Removed extra dgets on the parent and dputting the hidden dentry + +2003-09-20 Puja Gupta + + * subr.c: added branchput for branchgets. + + * print.c (fist_checkinode): fixed the count print condition. + + * inode.c (unionfs_unlink_whiteout): changes to dget, notify_change. + match dget and dput. + +2003-09-20 Charles P. Wright + + * Makefile (tags): target for tags + + * inode.c (unionfs_unlink_whiteout): Refcount fix. + +2003-09-20 Puja Gupta + + * file.c (unionfs_readdir): reverting back to file.c before changes + related to readdir_called flag. Was going into an infinite loop due + to some condition. The current version works fine. + + * subr.c (create_dir_whs_filldir): replaced "return err" with + "goto out", which was causing an infinite loop. + (check_whiteout, delete_whiteouts): replaced 'ret' with err. + +2003-09-19 Puja Gupta + + * subr.c (create_dir_whs): added filldir_called flag. + +2003-09-19 Puja Gupta , Jay, Hari, Mohammad. + + * subr.c (check_empty): check if filldir is called or not. + +2003-09-19 Harikesavan Pathangi Krishnan , Jay, Chip, Puja, Mohammad + + * subr.c (check_empty): Added a flag field in the callback + structure that makes readdir call once again if all the contents + of the directory are not read. + +2003-09-19 Charles P. Wright + + * file.c (unionfs_release): free resources on file close. + + * file.c (unionfs_filldir): Print a warning on any duplicate, but + don't return -EIO. + + * subr.c (create_whiteout_left): fix a refcount leak + +2003-09-19 Mohammad Nayyer Zubair + + * file.c (unionfs_filldir()): fixed the rm -Rf (-EIO, ENOTEMTPY + error) cases. return -EIO ONLY when get a 'foo' and 'foo' exists + in the same directory, which would indicate corruption in the file + system. Before were returning -EIO ALSO if filldir gets a + '.wh.foo' and 'foo', latter being in the linked list already + +2003-09-17 Puja Gupta , Hari, Mohammed. + + * Makefile: Changing back to old file. + + * subr.c (create_whiteout_left): removed dput, hidden_dentry == NULL. + + * inode.c (do_rename): If error, make hidden_dentry NULL. + (unionfs_rename_all): copyup file on err = -EROFS. + + * unionfs.h: added copyup_dentry. + + * subr.c (unionfs_copyup_dentry): added this function, called from + setattr. + (unionfs_copyup_file): modified, calls copyup_dentry internally. Added + checks before kfree. + + * inode.c (unionfs_setattr): calls copyup when trying to setattr for a + RO branch. + + * fist.h (FISTBUG): imported from ncryptfs. + +2003-09-17 Harikesavan Pathangi Krishnan + + * inode.c: Fixed the bug related to creation of whiteouts on the + leftmost branch when a directory on that branch is rmdir'ed. + +2003-09-16 Charles P. Wright + + * subr.c: fixed indentation for readdir actors + + * inode.c (unionfs_rmdir): create_whiteout can just not do anything + + * unionfs.h (itohi, dtohd): Reference count check before returning + to user space. + +2003-09-16 Puja Gupta , Hari, Mohammad. + + * inode.c (unionfs_create): removed a dget, was giving a seg fault. + (unionfs_lookup): error check for lookup_one_len added. + (unionfs_rmdir_all): checking if rmdir failed on leftmost, and if it + had whiteouts, remove them, and call vfs_rmdir again, to create + whiteout. + +2003-09-16 Mohammad Nayyer Zubair Hari + + * main.c (unionfs_interpose()): removed unnecessary fist_prints() + +2003-09-16 Mohammad Nayyer Zubair Hari + + * print.c (fist_print_dentry() and fist_print_inode()): removed + the anding code when printing the mode of the inode. Was printing + a negative mode value. + +2003-09-15 Puja Gupta , Hari, Mohammed. + + * subr.c: fput for copied up file not required. + + * print.c: print level 9 changed to 8. Level 9 doesn't get printed. + + * unionfs.h (IS_COPYUP_ERR, IS_WRITE_FLAG): Added. + + * subr.c (unionfs_copyup_file): Checks added, replaced variables, fixed. + + * inode.c (unionfs_permission): One code for files and directories. + Error bypassed for -EROFS, but not for leftmost branch. + + * file.c (unionfs_open): Check added for RO partition, and call copyup. + +2003-09-15 Mohammad Nayyer Zubair Hari + + * inode.c (unionfs_mknod): done. removes whiteout if + present. format similar to unionfs_mkdir(). Tested. + +2003-09-14 Puja Gupta + + * inode.c (do_rename): Fixed parent directory for lookup of whiteout. + (unionfs_rename_whiteout): Added case for DELETE_WHITEOUT for rename. + (unionfs_rename): Check destination->inode before S_ISDIR. + +2003-09-14 Charles P. Wright + + * file.c (unionfs_filldir): Remove a duplicate from the list if + filldir fails. + + * dentry.c (unionfs_d_revalidate, unionfs_d_compare, unionfs_d_hash): + Turned into utility functions for printing to reduce volume of debug + output. + +2003-09-14 Puja Gupta + + * inode.c (unionfs_rename_all): fix for bindex counter. + (unionfs_rename_all): check if error not occured in bstart of + destination. + (unionfs_rename_all): whiteout is always create in the bstart of + source, not to go to left of it. + +2003-09-14 Charles P. Wright + + * Detect EIO on single directories by doing duplicate elimination + routine. + +2003-09-13 Puja Gupta , Jay. + + * inode.c: added dput for hidden_dentry, whiteout_dentry that + are not used after lookup. + + * subr.c: added dput for hidden_dentry, whiteout_dentry that + are not used after lookup. + +2003-09-13 Charles P. Wright + + * PASSERT is for pointers. ASSERT is for non-pointer conditions. + +2003-09-12 Charles P. Wright + + * main.c: Sanity checks on flag=. + + * subr.c (create_whiteout_left): Balanced a dput w/ a dget. + + * print.c: exit should be level 5, not 4. hidden_dentries/inodes + are level 9 instead of 8. + + * Changed ASSERT to Oops when the pointer is poisoned. + + * Changed ASSERT(foo != NULL) to ASSERT(foo) + + * Default flag is 0x0. + +2003-09-11 Puja Gupta , Hari, Zubair, Jay. + + * inode.c (unionfs_create, unionfs_symlink): whiteouts truncated + to zero and ctime updated. + + * unionfs.h: added flags COPYUP_OWNER, COPYUP_FS_MOUNTER, + redefined flags. + + * inode.c: unlock parent added. + + * file.c (unionfs_open): check for error and call copyup on EROFS. + + * inode.c (unionfs_unlink): changed the function like rmdir. Used + rename instead of unlink, create for whiteouts. + (unionfs_mkdir): restructured code. + + * unionfs.h (GLOBAL_ERR_PASSUP): removed DELETE_ERR_PASSUP. + GLOBAL_ERR_PASSUP indicates whether to pass error back or create + whiteouts/try again. + + * inode.c (unionfs_create, unionfs_symlink, unionfs_link): + restructured changed *_ERR_PASSUP to GLOBAL_ERR_PASSUP. + + * unionfs.h (GLOBAL_ERR_PASSUP): added, for all functions, + whether, on error, should passup or try to make up for error + encountered. + + * inode.c (unionfs_symlink): updating bstart, bend for symlink + create. Restructured the code. + +2003-09-11 Mohammad Nayyer Zubair + + * inode.c (unionfs_symlink): done. removes whiteout if + present. same format as in unionfs_create() + + * inode.c (unionfs_link): creating destination path in source's + branch instead of vice versa + + * inode.c (unionfs_rmdir_all): removed unneccessary d_drop() + call. unionfs_rmdir() calls it at the end + +2003-09-10 Charles P. Wright + + * inode.c (unionfs_rmdir): Split into several functions. + + * subr.c (delete_whiteouts): Delete all whiteouts in + a given directory in a given branch. + + * subr.c (check_empty): Check if a directory is empty. + +2003-09-10 Puja Gupta , Hari. + + * unionfs.h: unionfs_interpose now returns void. + + * subr.c (unionfs_partial_lookup): removed extra dput. + unionfs_reinterpose now returns void. + + * main.c (unionfs_reinterpose): is now a void function and igrab + was called twice for already existing hidden inode. Fixed. + + * file.c (single_branch_filldir): removed fist_dprint printed + extra newline character on commandline during readdir. + + * unionfs.h (COPYUP_CURRENT): removed multiple definition. + +2003-09-09 Puja Gupta + + * subr.c (unionfs_full_lookup): Removed this function, was similar + to unionfs_partial_lookup. + + * inode.c (unionfs_unlink): added if-else for three different + options for unlink, and also for error handling (passup or + whiteout). Replaced unionfs_full_lookup with + unionfs_partial_lookup (Both functions were same, just change in + name). Added dget, dput at appropriate places. + + * unionfs.h (DELETE_FIRST, DELETE_WHITEOUT, DELETE_ERR_PASSUP): + added, and removed all other unlink flags. + +2003-09-09 Mohammad Nayyer Zubair Hari + + * inode.c (unionfs_lookup): returning EIO for directory whiteout. + +2003-09-02 Mohammad Nayyer Zubair Hari + + * inode.c: mkdir and create revisted, restructured and tested + +2003-09-08 Charles P. Wright + + * file.c (unionfs_write): Fixed positioning code. + +2003-09-07 Puja Gupta + + * inode.c (unionfs_create): added dget, get_parent, double_lock + and error check for vfs_rename of whiteouts. Added d_drop for any + negative dentry at the end of function. + (unionfs_mkdir): added error check for vfs_unlink of whiteouts, + unionfs_interpose, create_dir_whs. Removed multiple unlock_dir. + + * subr.c (create_dir_whs_filldir, create_whiteout_left): + changed char name[PATH_MAX] to char *name. + + * inode.c (unionfs_create, unionfs_lookup, unionfs_unlink) + (unionfs_mkdir): changed char name[PATH_MAX] to char *name. + (unionfs_rmdir): removed unused name, wh_name. + +2003-09-06 Puja Gupta + + * inode.c (unionfs_create): reverted back to the loop for create + from bstart to zeroth branch. + +2003-09-02 Mohammad Nayyer Zubair + + * inode.c: file to file rename done. + + * major items left: dir to dir rename + + * minor items left: mknod, symlink + +2003-09-05 Charles P. Wright + + * file.c (unionfs_filldir, single_branch_filldir): Removed memory + leak for debug output in filldirs. + (unionfs_readdir): Return -failure from filldir (previously our + filldir had no error propagation). + + * ioctls via extended attributes works. + + * branchman.c (unionfs_ioctl_delbranch): Don't let people delete + the last remaining branch. It would be cooler if we could, but + probably not worth all the effort to make the root dentry behave + properly when there is nothing underneath it. + + * file.c: Removed branch management functions. + + * inode.c): xattr functions. + + * branchman.c: Branch management functions. + +2003-09-03 Charles P. Wright + + * super.c (unionfs_clear_inode): Fixed cleanup of stale inodes. + + * fist.h (ASSERT2): Macro to print out caller when we fail. + + * Changed ASSERT2's to ASSERT, since they weren't really being + used as an ASSERT2. + + * unionfs.h (itohi, dtohd): Converted to a function, added an + ASSERT2 to make sure we don't underflow the array. + +2003-09-02 Mohammad Nayyer Zubair + + * subr.c: removed the unnecessary vfs_rename() function call in + create_whiteout_left(). Doing vfs_create() directly. + + * inode.c: fixes in lookup(). Started on unionfs_rename(). + + +2003-09-01 Mohammad Nayyer Zubair + + * subr.c: added function int remove_whiteouts(dentry_t *dentry, + dentry_t *hidden_dentry, int bindex) + Called by unionfs_rmdir(). Does vfs_readdir() and then unlinks all + whiteouts entries in it. + +2003-09-01 Charles P. Wright + + * Updated CUR_MAX_BRANCH and MOUNT_FLAG. + + * dentry.c (unionfs_d_revalidate): Make negative dentries that + just turned negative stale. + + * inode.c (unionfs_inode_revalidate): Make negative inodes stale. + + * stale_inode.c: Functions to make a magic stale inode. + +2003-09-01 Mohammad Nayyer Zubair + + * inode.c: unionfs_mkdir() done and works as per updated design. + Creating whiteout entries for all entires to the right. Details on + this are in the updated function_description.html file + + * file.c: a separate filldir function for single branch directory. + Ignoring whiteout entries. + + * subr.c: added a function: int create_whs_right(dentry_t *dentry, + int cur_index) Does a vfs_readdir on all directories starting from + cur_index + 1 and creates whiteout entries in cur_index (called in + unionfs_mkdir()). Details on this are in the updated + function_description.html file + + preliminary cases are working as expected + + Left: rename, mknod, symlink. + +2003-09-01 Charles P. Wright + + * file.c: Add branch ioctl and trimmed unionfs_dir_fops. + + * fist.h: Structure for add branch ioctl. + + * fist_ioctl.c: Add branch and cleaner branchcount ioctl. + +2003-08-31 Charles P. Wright + + * dentry.c (unionfs_d_revalidate): Do revalidation of dentries, + we now can remove the leftmost branch and expose old contents. + +2003-08-27 Mohammad Nayyer Zubair + + * inode.c: unionfs_unlink() implemented as per new design specs + (ignoring intermiate directories for now) + + * subr.c: added create_whiteout_left(dentry, index) function: + creates a whiteout in index, on error it proceeds to the left. + + * file.c: in fill_dir() ignoring whiteout entries + + * Left: mkdir, mknod, symlink, rmdir, rename + +2003-08-27 Charles P. Wright + + * Branch removal sort of works. + +2003-08-27 Mohammad Nayyer Zubair + + * inode.c: unionfs_create() implemented as per new design specs. + If found a .wh.foo entry, vfs_rename it to foo. + + * inode.c: unionfs_lookup() implemented as per new design specs. + If found a whiteout entry, just stop lookup + + * inode.c: unionfs_link() implemented as per new design specs + + * inode.c: unionfs_setattr() implemented as per new design specs + + * inode.c: unionfs_permission() implemented as per new design specs. + + * file.c: calling unionfs_copyup_file() in unionfs_open() if open + with specified flags fails with the current underlying file + + * subr.c: fixes in unionfs_copyup_file() + + * unionfs.h: modified mount time flags + + * Still left (according to new specs): mkdir, symlink, mknod, + unlink, rmdir, rename hard. + +2003-08-26 Charles P. Wright + + * inode.c (unionfs_inode_revalidate): Refresh inode from lower level. + + * fist_ioctl.c: Increment super generation number. + + * file.c (unionfs_ioctl_incgen): Increment super generation number. + +2003-08-20 Charles P. Wright + + * file.c: Branch reference counters updated on open/close. Need + to figure out how do to update them when a unionfs directory + becomes the cwd of a process. + + * doit.sh: Source doitopts or doitopts.`uname -n` so different + developers can have different setups, w/o changing CVS. + + * unionfs.h: Added generation number to super block, inode, and dentries. + + * attach.c: Not used. + +2003-08-13 Mohammad Nayyer Zubair + + * subr.c: some fixes in unionfs_copyup_file() (untested yet) + + * file.c: calling unionfs_copyup_file() if write() fails on the + leftmost file. Failure could result because of read-only + permissions on the file so probably should do copy up only if + branch is mounted RO. + + * unionfs.h: modified definition for unionfs_copyup_file() + +2003-08-13 Mohammad Nayyer Zubair + + * subr.c: added function: unionfs_copyup_file(inode_t *dir, + dentry_t *dentry, int oldbindex, int newbindex) first does + recursive directory creation, then does vfs_create() and then + reads PAGE_SIZE bytes from old file to new file + + * subr.c, inode.c: moved useful functions: + unionfs_create_parent_dir() and unionfs_partial_lookup() to subr.c + from inode.c + + * unionfs.h: definition for unionfs_copyup_file + + * Makefile: added subr.o to the list of OBJS + +2003-08-13 Puja Gupta + + * unionfs.h: added definition for unionfs_create_whiteout. + +2003-08-12 Puja Gupta + + * inode.c: reverting back to old copy without changes to rename. + +2003-08-04 Puja Gupta + + * unionfs.h (UNLINK_WHITEOUT, UNLINK_ALL_FIRST, UNLINK_ERR): New flags + for handling various unlink options. + + * main.c (unionfs_parse_options): fixed check for getting mount flags. + + * inode.c (unionfs_unlink): added unlink for whiteout. If flag is set + for UNLINK_WHITEOUT, try to create whiteout in branches to left, create + recursive subdirectories. Also added check for various flags for + unlink_first or unlink_all, and how to handle error on unlink. + (unionfs_create_parent_dir): check in for loop fixed. + +2003-08-04 Mohammad Nayyer Zubair + + * file.c: readdir is working fine with the hashtable in the private + data of unionfs file. + diff -ru on gcc tarball is successful + + * inode.c: implemented option 2 of link(), recursively creating source + path in destination branch when branches are different + + * unionfs.h: added two mount time flags + LINK_EXDEV: just return -EXDEV when dentries are on different branches + LINK_RECURSIVE: recursively create source path in target branch + +2003-07-31 Mohammad Nayyer Zubair + + * file.c: readdir/filldir's linked list converted into a hashtable + of size HASHTABLE_SIZE Duplicate elimation is working. Still to + test the gcc tarball. + + * unionfs.h: converted dir_list list head to an array of list + heads of size HASHTABLE_SIZE + + +2003-07-30 Puja Gupta + + * unionfs.h: changed to new flag, CREATE_RW_ERR, UNLINK_WHITEOUT, + UNLINK_ERR. Function definition for unionfs_partial_lookup. + + * inode.c (unionfs_partial_lookup): added, called from + unlink. Looks up the remaining files that were not looked up in + unionfs_lookup. + (unionfs_unlink): code now transferred to unionfs_partial_lookup. + (unionfs_create): flag name is CREATE_RW_ERR. + + * inode.c (unionfs_create): changed to new flag values. + + * unionfs.h (IS_SET): changed flags to be exclusive. Also, changed + IS_SET to work on place value of bit. + +2003-07-27 Puja Gupta + + * file.c (unionfs_open): removed ftohd_index(file, bindex) = NULL. + unionfs_getdents_callback now has file_t *. + (unionfs_filldir, unionfs_readdir): changed the global list_head + for duplicate elimination to have a list_head in private data of + file. So, the list of name, namelen is stored in this new + list_head, and compared against this. + + * unionfs.h: added struct filldir_node to private data of file. + Thus, every file has unique and seperate list for readdir. + + * doit.sh: "flag=" instead of "flags=". + +2003-07-28 Mohammad Nayyer Zubair + + * inode.c: unionfs_link's option 1 done. Return -EXDEV if old and + new dentries are in different branches / starting option 2: if + different branches, creating destination path in the source branch + + * unionfs.h: added a simple function which returns the sum of all + the underlying inodes' nlink value + + * inode.c: calling the above function wherever nlinks value was + being set + +2003-07-24 Puja Gupta + + * unionfs.h: #defines for MOUNT_FLAG, CREATE_PASSUP, + CREATE_RW_ERR_PASSUP, CREATE_TRY_LEFT and IS_SET. + + * main.c (unionfs_parse_options): parse the mount time flag and + initialize it. + + * inode.c (unionfs_create): added handling of partial errors to + handle various cases: 1) Try to Left (default), 2) PassUp, 3) If + EPERM on RW branch, PassUp. + + * doit.sh: changed mount options to include "flag=". + +2003-07-24 Puja Gupta + + * inode.c (unionfs_setattr): added check for NULL hidden dentry. + (unionfs_inode_revalidate): added ASSERT2 for inode. + +2003-07-24 Mohammad Nayyer Zubair + + * file.c: in unionfs_open, now only opening leftmost file instead + of opening all of the hidden files. Opening all directories + though. + + * inode.c: setattr function done. Assigning 'correct' value to the + n_links variable in the unionfs inode. In inode_revalidate + function assigning 'correct' value to the n_links variable in the + unionfs inode. + + * main.c: just moved sum_nlinks variable to the beginning of the + interpose function. diff -ru on a randomly distributed + (recursive) gcc tarball is failing. Some duplicate files are + being listed. 'ls' on the directory containing above duplicate + files also lists the files twice. Files have same unionfs inode. + Checking out whats happening. + +2003-07-22 Mohammad Nayyer Zubair + + * main.c: in interpose() added lines which compute the sum of the + nlinks of the underlying inodes and assigns this sum to the + unionfs inode. + + * inode.c: in permission() added check for a null hidden inode + +2003-07-22 Puja Gupta + + * unionfs.h: init_file_array is now init_ftohf_ptr, + init_inode_array is now init_itohi_ptr, init_sb_array is now + init_stohs_ptr, added init_stohiddenmnt_ptr, init_dentry_info, + init_dentry_array is now init_dtohd_ptr. All this makes sure that + all allocated memory is initialized to zero before its being used. + + * super.c (unionfs_read_inode): init_inode_array is now init_itohi_ptr. + + * main.c (unionfs_parse_options): init_priv_inode is now + init_dentry_info. + (unionfs_parse_options): memset, init_stohs_ptr, init_stohiddenmnt_ptr + added for initialize memory allocated to NULL. + (unionfs_read_super): init_dtohd_ptr added to initialize to NULL. + + * inode.c (unionfs_lookup): init_dentry_array is now init_dtohd_ptr. + + * file.c (unionfs_open): added init_ftohf_ptr, setting underlying + file pointer to NULL. + +2003-07-21 Puja Gupta + + * inode.c (unionfs_create): get rid of the hidden dentry that lead + to an unsuccessful attempt to create. Update bstart, bend + accordingly. + (unionfs_create_parent_dir): added "count--" for proper pointer + position. Updated private data, bstart for the dentry and inode of + intermediate directories created. Also, updated bend for the + negative dentry returned from this function to create. + + * main.c (unionfs_interpose): removed comments and extra line + spaces. + +2003-07-20 Puja Gupta + + * unionfs.h (MAX_DIR_CREATE): added MAX_DIR_CREATE for the number of + directories allowed to be created in recursive subdir creation. + Should be dynamic. + + * inode.c (unionfs_create): changed to handle partial error by + recursively creating directory to left branches. + (unionfs_create_parent_dir): added this function, it creates + hidden directory path for a given parent inode and dentry in + specified branch. (Still to test) + +2003-07-15 Mohammad Nayyer Zubair + + * inode.c : Found a bug while mounting unionfs on + a randomly distributed (recursive) am-utils tarball on 5 branches. + Basically we were not memsetting the array of pointers to hidden + objects after kmallocing a CUR_MAX_BRANCH number of pointers for + dentry, inode, file and sb. They were assumed to be NULL in + lookup and hence were not explicitly set to NULL in the array when + requireed. + + * unionfs.h: Added macros which initialize hidden arrays to NULL + +2003-07-15 Puja Gupta + + * inode.c (unionfs_lookup): added few debug statements. + (unionfs_unlink): Since lookup for file had just the leftmost + entry, unlink now internally calls lookup for all remaining + branches. And the current policy for unlink is, unlink + all. (Tested). + + * unionfs.h: added definition for unionfs_reinterpose. + + * main.c (unionfs_reinterpose): This new function takes a dentry + with leftmost hidden inode interposed, and reinterposes the newly + lookedup hidden inodes in remaining branches. Called from + unionfs_unlink. + + * mount_tarball.sh, mount_tarball_random.sh: These scripts are now + moved to ../tools directory. + +2003-07-13 Puja Gupta + + * inode.c (unionfs_lookup): fixed initialization of negative dentry. + + * print.c (fist_print_inode), (fist_print_file),(fist_print_dentry), + (fist_print_sb): made more readable, pointers now printed with %p. + +2003-07-10 Puja Gupta + + * super.c (unionfs_statfs): check for duplicate superblock data being + added. + (unionfs_umount_begin): check for NULL hidden_sb, hidden_sb->s_op. + +2003-07-10 Mohammad Nayyer Zubair + + * print.c: fist_print_inode(): prints underlying inodes if any. + fist_print_dentry(): prints underlying dentries if any. + fist_print_files(): prints underlying files if any. + fist_print_superblock(): prints underlying sbs if any. + +2003-07-10 Mohammad Nayyer Zubair + + * print.c: improved the formatting of printing inode, dentry and + sb + + * main.c, inode.c removed unneccessary lines printing debugging + info in interpose() + +2003-07-13 Mohammad Nayyer Zubair + + * file.c inode.c: removed debugging info lines + + * created mount_tarball.sh. right now, distributes an equal + number of files/dirs among N branches tar-ing am-utils + through unionfs mount point gives same package buildall + through mount point gives same structure/files diff -urN oldtree/fs/unionfs/INSTALL newtree/fs/unionfs/INSTALL --- oldtree/fs/unionfs/INSTALL 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/INSTALL 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,182 @@ +To build Unionfs, there are two main components: + +- unionfs.ko: the kernel module in 2.6 + +- unionctl: a user utility which allows you to add and remove branches + +You should be able to just type "make" and Unionfs will build itself for the +running kernel. The Makefile will look for your running kernel sources in +/lib/modules/`uname -r`/build/include. + +If your kernel sources are located in a different directory, create a +"fistdev.mk" file along the lines of: +LINUXSRC=/path/to/my/kernel/sources/linux-2.6.xx +TOPINC=-I$(LINUXSRC)/include +MODDIR=/lib/modules/2.6.xx + +LINUXSRC points to the root of a Linux source tree. TOPINC should point to +that tree's include directory. Finally, the module will be copied to +$MODDIR/kernel/fs/unionfs.ko. + +You must set all three variables together, otherwise you can have problems +compiling, installing, or loading the module. + +You also need to have the headers for e2fsprogs installed, on Red Hat +derived systems (like Fedora Core), this means that you need to have +e2fsprogs-devel installed. + +There are two Makefile options related to extended attribute support, +which is turned off by default. You should define UNIONFS_XATTR to turn +it on. Vanilla kernels should work automatically, but if you (or your +vendor) has applied the ACL/EA patches you might need to define +FIST_SETXATTR_CONSTVOID to correct the setxattr operation's function +prototype. + +Using fistdev.mk, you can also turn off the debugging print system, +which adds to the modules code size significantly. Just add +"EXTRACFLAGS=-DUNIONFS_NDEBUG" to fistdev.mk. + +The doit.sh script included in the distribution will mount unionfs +with two branches (/branch0 and /branch1) by default. You can use it +as an example and edit to your tastes. + +To install unionfs run "make install". This copies unionfs.o into +/lib/modules/`uname -r`/kernel/fs/; copies the utilities into +/usr/local/sbin; and copies man pages into /usr/local/man; + +fistdev.mk summary: +UNIONFS_OPT_CFLAG By default -O2. If you want a different optimization + level change this variable. +UNIONFS_DEBUG_CFLAG By default -g. If you want to remove debug, set + this variable to nothing. This will result in a + smaller (but harder to debug) Unionfs. +EXTRACFLAGS Additional stuff to pass to the compiler, this + is useful when combined with the definitions below. + (e.g., EXTRACFLAGS=-DUNIONFS_NDEBUG to turn off + debugging). +LINUXSRC Where to find the kernel build directory. +TOPINC Where to find the kernel headers. +PREFIX Where to install Unionfs utilities. + By default /usr/local. +MODPREFIX What is the prefix to the root directory for modules, + by default this is unset. Your modules will end up + in /lib/modules/`uname -r`/kernel/fs. With + MODPREFIX=/foo they end up in + /foo/lib/modules/`uname -r`/kernel/fs. + +Define options summary: +UNIONFS_NDEBUG Turn off debugging facility (reduces code size). +UNIONFS_UNSUPPORTED Bypass kernel versions checks. +SUPPORT_BROKEN_SETUP Enable sendfile, which allows you to run losetup, but + if you try to write to a loop file, you will cause + an Oops. + +Known interactions with other kernel features/patches: +* If you get an error like this on Fedora Core 4: + make: *** /lib/modules/2.6.11-1.1369_FC4/build: No such file or directory. Stop. + Then you need to install the kernel-devel package. + +* If you get an error like this: + unionimap.h:9:23: uuid/uuid.h: No such file or directory + Followed, by more parse errors, then you need to make sure you have + e2fsprogs-devel installed (or your distribution's equivalent). + +* Some NFS servers return -EACCES instead of -EROFS when they are exported + read-only. This means that we can't legitimately determine when a user is + not allowed to access a file. To enable a hack so that NFS appears to work + correctly (but NFS ACLs will break), mount the nfs-branch with mode nfsro. + +* If you want to export Unionfs over NFS, then you need to add + extra information to /etc/exports. knfsd will not export Unionfs unless + you have an fsid option in /etc/exports. This is because Unionfs has no + real device. See man exports(5) for more information on fsid. + +* If you want to use Unionfs as your root file system you need to use + pivot_root. www.linux-live.org provides scripts for creating live CDs with + Unionfs as the root. The following commands are adapted from the linuxrc + from linux-live 5.0.16. You may want to look at the original script from + www.linux-live.org if you are having problems. SLAX (www.slax.org) is a + an actual live CD distribution based on these scripts. + + UNION=/union + MEMORY=/memory + MOUNTDIR=/mnt + CHANGES=$MEMORY/changes + + mkdir -p $UNION + + mkdir -p $MEMORY + mount -t tmpfs tmpfs $MEMORY + + mkdir -p $CHANGES + mount -t unionfs -o dirs=$CHANGES=rw unionfs $UNION + + # Here other things are added to the Union, by using unionctl. + + cd $UNION + mkdir -p initrd + pivot_root . initrd + exec chroot . /bin/bash + # You should never get here + +* If you want to use losetup, then you need to define -DSUPPORT_BROKEN_LOSETUP + You will be able to use it read-only, but when you try to use it read-write, + you will get an Oops. This should eventually be fixed when we have our + own address-space operations (so that we can support sendfile). + +* Selinux requires extended attributes (but has not been tested by us). + You should compile Unionfs with Extended Attribute support by adding + EXTRACFLAGS=-DUNIONFS_XATTR to fistdev.mk. After this, you can follow + the following instructions are from Jaspreet Singh: + + 1. Install strict/targetted selinux policy sources + 2. Open /etc/selinux//src/policy/fs_use + 3. Append "fs_use_xattr unionfs system_u:object_r:fs_t;" + 4. Compile, install, and reload the selinux policy + + "There were a couple of issues with Unionfs but they were minor." + +* tmpfs does not support fsyncing directories, so if you have a Union with + tmpfs as the leftmost branch, fsync returns EINVAL. + +Other known limitations: +* Unionfs does not provide cache coherency. What this means to you is that + if you directly modify the lower-level branches, then Unionfs will get + confused. You can tell Unionfs to throw out its cache and recreate all + of its objects (lazily), by running "uniondbg -g UNION". + + It is especially dangerous to create or remove whiteouts from underneath + Unionfs, as there are several places where it ASSERTs on invariants + that must be true (e.g., if the file exists, the whiteout should not and + vice versa). + +* Unionfs doesn't support sendfile. This often manifests itself as apache + serving zero length files. You can turn off sendfile n Apache with the + EnableSendfile httpd.conf directive (see + http://httpd.apache.org/docs/2.0/mod/core.html). This is also the reason + that losetup is unsupported, Unionfs needs its own address space operations + otherwise upper and lower-level files and pages get mixed and matched. + +* If you restart an NFS server, you will get ESTALE errors on the client + because Unionfs does not have persistent inode numbers. You should also + consider NFS over TCP, so lost packets don't cause readdir to get confused. + +* Renaming a directory on a read-only branch returns an EXDEV error. The "mv" + utility is designed to handle this error (at least GNU coreutils and busybox + will handle this correctly), so a user will not see anything. The only + issue will be applications that internally rename a directory, but do not + properly handle EXDEV (which is really a bug on the application's part). + +* The documentation needs to improve + +* The object code is much larger than it could be, but this can be solved by + enabling UNIONFS_NDEBUG and setting UNIONFS_DEBUG_CFLAG to the empty string. + +Integrating Unionfs into a 2.6 kernel source tree (2.4 is not supported): +1. First run patch-kernel.sh included with Unionfs. Its first argument is the + path to your kernel source tree. +2. Configure and compile your kernel as you normally would. Unionfs is at the + bottom of the the File systems -> Miscellaenous filesystems menu. +3. To install the Unionfs utilities (i.e., unionctl and uniondbg), run + "make utils install-utils" from the Unionfs source directory. +4. Boot into your new kernel, and enjoy Unionfs. diff -urN oldtree/fs/unionfs/Makefile newtree/fs/unionfs/Makefile --- oldtree/fs/unionfs/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/Makefile 2006-01-28 18:23:21.819814544 +0000 @@ -0,0 +1,11 @@ +UNIONFS_VERSION = 1.1.2 +EXTRA_CFLAGS+=-DUNIONFS_VERSION=\"${UNIONFS_VERSION}\" +# This will disable debugging support +# EXTRA_CFLAGS+=-DUNIONFS_NDEBUG + +obj-$(CONFIG_UNION_FS) += unionfs.o + +unionfs-objs := subr.o dentry.o file.o inode.o main.o super.o \ + stale_inode.o branchman.o xattr.o rdstate.o copyup.o \ + dirhelper.o rename.o unlink.o lookup.o persistent_inode.o \ + commonfops.o dirfops.o print.o diff -urN oldtree/fs/unionfs/NEWS newtree/fs/unionfs/NEWS --- oldtree/fs/unionfs/NEWS 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/NEWS 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,190 @@ +* Unionfs 1.1.2 +- Added inode refcounting debugging tool +- Fixed race between lookup and d_free +- Fixed double free/unchecked malloc +- Fixed permission bug, creat/open truncates the running executable +- Fixed many reference counting bugs +- Moved code from fist.h into unionfs*.h +- Removed unneeded UNIONFS_XATTR +- Removed ASSERTs in favor of BUG_ONs +- Removed FISTBUG +- Rename dentry locking changed to use 2.6 calls +- Replaced NFS_SECURITY_HOLE by nfsro branch option +- Cleaned up code to "pass" a Sparse run +- RPM spec file updated +- Miscellaneous cleanups + +* Unionfs 1.1.1 +- Directory reading is fixed +- Improved locking for branch manipulation operations +- Fix for removing an opaque directory +- Some cleanups and error handling fixes to the copyup code + +* Unionfs 1.1.0 +- Removed excess 2.4 code (Unionfs 1.1.0 is for 2.6 only) +- Removed file locking code, as the VFS does a better job of it. +- Fixed off by one errors when kmallocing names in inode.c. +- Fixed several deadlock bugs. +- Fixed several rename and rmdir bugs. +- Permissions checked on files that are on read-only file systems +- AMD64 fix for compiling on gentoo. +- Properly update generation when we combine copyup and reopening. +- Cleanedup Makefile to remove 2.4 clutter. +- Added documentation for the MODDIR option in the INSTALL file. + +* Unionfs 1.0.14 +Features: +- Dropped unmaintained setattr,diropaque,delete=first and mount flags +- Updated unionfs.4 to reflect default mount modes +- You can use the root of the Union to remove branches with unionctl +- Use official Debian packaging files. +- Linux 2.6.13 support. + +Bug fixes: +- Fixed several dentry refcount bugs introduced by new deletion framework. +- Fixed uninitialized fd_set in the query ioctl. +- Branch reference counting now works across insertion and removal of branches. + This prevents the branch counts from getting "confused". +- Handle "/" as a branch in unionctl. +- Removed static buffer for debug prints in favor of vprintk. +- NFS silly renames avoided during several cases. +- Attempting a write lock causes a copyup, so that the underying flock will + work. +- Cleaned up mount option parsing. +- Improved link counting for directories. + +* Unionfs 1.0.13 +- Unionfs now handles deleting an open file (and several other deletion fixes). + Thanks to the Knoppix people and Tomas Matejicek for finding these bugs. +- The NODEBUG flag has been renamed to UNIONFS_NDEBUG. +- Instead of allocating all of the lower-level pointers in dentries, inodes + and files, we have a fixed number of them preallocated and malloc only if + we exceed that number. +- Fixed a dentry reference count bug with UNIONFS_NDEBUG. +- Support for persistent inode numbers across mounts. +- Added a "which-branch" ioctl and corresponding --query to unionctl, so that + it is possible to find out where a file or directory is coming from. +- In 2.6.11 and onwards, don't take the BKL for ioctls. + +* Unionfs 1.0.12 +- Copy-up is delayed until a write operation occurs, so spurious copy-ups are + avoided. +- Improved copyup UID spoofing for mkdir +- Instructions and shell script for compiling Unionfs into a monolothic kernel. +- Added support for opaque directories, which mask the contents of + lower-priority directories. This makes recreating a removed directory an + O(1) operation instead of an O(n) operation, and also makes subsequent + operations faster. There were also several whiteout related fixes bundled + in here. +- Fixed bug with whiteouts on Reiserfs +- Fixed bug when a file transitioned from a negative dentry to a positive + dentry (i.e., if you add a branch that inserts a file you previously + looked up, but did not exist) +- Fixed return code for extended attribute functions +- amd64 compile fixes +- Extended attribute copy-up +- Unionfs returns EXDEV instead of copying up a directory on move, this + fixes a bug where Unionfs would "forget" the contents of a copied up + directory after unmount. +- Fix for following symlinks +- Improved print routines (separated generic from unionfs printing routines) +- INSTALL has some instructions for using Unionfs as a root file system and + also for using Unionfs with Selinux. +- Dentry private data uses a separate kmem_cache and inodes in 2.6 use their + own kmem_cache. This should improve performance a bit because there are + fewer individual memory allocations (and less wasted space). + +* Unionfs 1.0.11 +This release fixes NFS exporting which was broken in 1.0.10. +- f_pos and lseek's offsets are unified, so readdir works on NFS exported + unionfs mounts again. + +* Unionfs 1.0.10 +This release fixes several bugs over 1.0.9, but it will not correctly work if +you want to NFS export it. For that you need to use 1.0.9 on 2.4. In 1.0.11, +we will fix NFS exports correctly. + +- Don't d_delete entries that don't have positive refcounts (Fabian Franz) +- Hardlinks should point to the same inode (Fabian Franz) +- File locking works correctly. +- Improved directory llseeking. +- snapmerge preserves permissions/times after copying files +- Improved Makefile +- Unionfs_d_revalidate copies attributes so the cache appears more coherent. +- Directory reading bug fixed. +- symlink copyup fixed +- Don't oops when creating files longer than 252 characters +- Some readdir fixes. +- df produces correct size results + +* Unionfs 1.0.9 +- Fixed copyup permissions bugs (Anton Farygin) +- NTFS mmap will no longer cause Oops (but it won't do the mmap, as NTFS + doesn't support mmap). +- Moved directory reading helper routines into dirhelper.c from subr.c +- We no longer require hacked copies of vfs_create and vfs_unlink +- Moved finding and adding filldir_nodes into rdstate.c +- Added a sample RPM spec file, for those who want to package Unionfs + (Note, we are currently not distributing source or binary RPMS) +- Fixed unionfs_link to allow hard-linking of files with a source of a + readonly file system. +- Fixed apt-get on rw/ro branch configuration (related to unionfs_link) +- Modified regression/link.sh to reflect the changes in unionfs_link. It + now includes tests to make sure linking on a read only filesystem works. +- Fixed an issue where unionfs_dir_llseek would cause an Oops + +* Unionfs 1.0.8 +- Fixed bug with readdir (but oddly not ls) that prevented that last entry + from being shown. +- Include INSTALL file with information about installing Unionfs. +- Fix unionctl bug with "/" as the path to search for +- Fix to copyup permissions on directories +- Allow llseek to current directory position, but no others + +* Unionfs 1.0.7 +- Fixed locking for readdir state, this fixes a kernel Oops on preemptive + kernels, and deadlocks on SMP kernels. +- Prevent readdir from giving -ESTALE on last entry. +- Fixes for gcc 2.9.5 (Alex de Landegraaf) +- Debian package scripts (Alex de Landegraaf) +- NFS Export on 2.6 (Sai Suman) +- Copyup permissions fix (Sai Suman) +- Warn when compiling on unsupported kernels (<2.6.9 or <2.4.20) +- Improved hardlink support (but not quite there yet) + +* Unionfs 1.0.6 +A lot of code has changed in the 1.0.6 release, so it may not be as stable as +the 1.0.5 release. + +- Makefile fix over 1.0.5 for install target on 2.6 +- unionfs.h, fist.h Makefile dependency fixed +- Support for readdir over NFS +- Hash table sizes are now based on the size of the lower-level directory +- In 2.4 inode private data resides in the inode.u field, saving memory +- Use kmem caches for filldir nodes rather than wasting space with extra + large kmallocs, also move short names inline + +* Unionfs 1.0.5 +- Support for both 2.6 and 2.4 kernels + +* Unionfs 1.0.4 +- Copyup now correctly handles directories, devices, and symlinks. +- Extended attributes are now off by default because they cause too many + compile problems. +- The regression tests is now included in the release, but is not actually + installed. These tests are rather primitive, but do check some fundamental + Unionfs behavior on multiple branches. + +* Unionfs 1.0.3 +- Compile fixes for older (and newer) compilers than found on Redhat 9. +- Compile fixes for older kernels. +- Don't Oops when passed bad directories. + +* Unionfs 1.0.2 +- Minor README updates + +* Unionfs 1.0.1 +- Fix to release target which includes manual pages. + +* Unionfs 1.0 +- First public release diff -urN oldtree/fs/unionfs/README newtree/fs/unionfs/README --- oldtree/fs/unionfs/README 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/README 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,87 @@ +Copyright (c) 2003-2006 Erez Zadok +Copyright (c) 2003-2006 Charles P. Wright +Copyright (c) 2005-2006 Josef Sipek +Copyright (c) 2005 Arun M. Krishnakumar +Copyright (c) 2005-2006 David P. Quigley +Copyright (c) 2003-2004 Mohammad Nayyer Zubair +Copyright (c) 2003 Puja Gupta +Copyright (c) 2003 Harikesavan Krishnan +Copyright (c) 2003-2006 Stony Brook University +Copyright (c) 2003-2006 The Research Foundation of State University of New York + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +We're pleased to announce the first release of a unioning file system +for Linux, called Unionfs. To download software and documentation, +see + + http://www.fsl.cs.sunysb.edu/project-unionfs.html + +Unionfs is a stackable unification file system, which can appear to +merge the contents of several directories (branches), while keeping +their physical content separate. Unionfs is useful for unified source +tree management, merged contents of split CD-ROM, merged separate +software package directories, data grids, and more. Unionfs allows +any mix of read-only and read-write branches, as well as insertion and +deletion of branches anywhere in the fan-out. To maintain Unix +semantics, Unionfs handles elimination of duplicates, partial-error +conditions, and more. This release also includes additional +preliminary features that were specifically designed for security +applications, such as snapshotting and sandboxing. + +This Unionfs release has been tested with recent 2.4 and 2.6 kernels. +For the 2.4 kernels, the minimum requirement is 2.4.20. For 2.6 +kernels, the minimum requirement is 2.6.11. You also need to have the +development headers for e2fsprogs installed. + +Unionfs is released under the GPL (see the COPYING file in the +distribution for details). + +For more information on using Unionfs, download the tarball and see +the following man pages: + +- unionfs.4: Describes how to mount unionfs + +- unionctl.8: Describes how to control an already mounted Union + +For more information about Unionfs internals (which we think are +really cool :-), see the following technical report at the above Web +site: + + C. P. Wright, J. Dave, P. Gupta, H. Krishnan, E. Zadok, and M. Zubair + "Versatility and Unix Semantics in a Fan-Out Unification File System" + Technical Report FSL-04-01b, October 2004 + Computer Science Department, Stony Brook University + http://www.fsl.cs.sunysb.edu/docs/unionfs-tr/unionfs.pdf + +In addition, you can find an article in Linux Journal (December 2004 +issue) titled "Unionfs: Bringing File Systems Together." It is available +online at http://www.linuxjournal.com/article/7714. + +See the INSTALL file for instructions on building Unionfs, iteractions with +kernel features, and known bugs and limitations. + +To report bugs, please email them to the "fistgen@filesystems.org" +list (see www.filesystems.org), or submit them via Bugzilla to +https://bugzilla.filesystems.org/. But reports with fixes are most +welcome. + +Enjoy, +Erez and Charles (on behalf of the Unionfs team) + +############################################################################## +## For Emacs: +# Local variables: +# fill-column: 70 +# End: +############################################################################## diff -urN oldtree/fs/unionfs/branchman.c newtree/fs/unionfs/branchman.c --- oldtree/fs/unionfs/branchman.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/branchman.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: branchman.c,v 1.60 2006/01/21 02:58:11 jsipek Exp $ + */ + +#include "unionfs.h" + +static void fixputmaps(struct super_block *sb) +{ + struct unionfs_sb_info *spd; + struct putmap *cur; + int gen; + int i; + + print_entry_location(); + + spd = stopd(sb); + cur = spd->usi_putmaps[spd->usi_lastputmap - spd->usi_firstputmap]; + + for (gen = 0; gen < spd->usi_lastputmap - spd->usi_firstputmap; gen++) { + if (!spd->usi_putmaps[gen]) + continue; + for (i = 0; i <= spd->usi_putmaps[gen]->bend; i++) + spd->usi_putmaps[gen]->map[i] = + cur->map[spd->usi_putmaps[gen]->map[i]]; + } + + print_exit_location(); +} + +static int newputmap(struct super_block *sb) +{ + struct unionfs_sb_info *spd; + struct putmap *newmap; + int count = 0; + int i; + + print_entry_location(); + + spd = stopd(sb); + + i = sizeof(int) * (sbend(sb) + 1); + newmap = KMALLOC(sizeof(struct putmap) + i, GFP_KERNEL); + if (!newmap) { + print_exit_status(-ENOMEM); + return -ENOMEM; + } + + if (!spd->usi_firstputmap) { + spd->usi_firstputmap = 1; + spd->usi_lastputmap = 1; + + spd->usi_putmaps = KMALLOC(sizeof(struct putmap *), GFP_KERNEL); + if (!spd->usi_putmaps) { + KFREE(newmap); + print_exit_status(-ENOMEM); + return -ENOMEM; + } + } else { + struct putmap **newlist; + int newfirst = spd->usi_firstputmap; + + while (!spd->usi_putmaps[newfirst - spd->usi_firstputmap] && + newfirst <= spd->usi_lastputmap) { + newfirst++; + } + + newlist = + KMALLOC(sizeof(struct putmap *) * + (1 + spd->usi_lastputmap - newfirst), GFP_KERNEL); + if (!newlist) { + KFREE(newmap); + print_exit_status(-ENOMEM); + return -ENOMEM; + } + + for (i = newfirst; i <= spd->usi_lastputmap; i++) { + newlist[i - newfirst] = + spd->usi_putmaps[i - spd->usi_firstputmap]; + } + + KFREE(spd->usi_putmaps); + spd->usi_putmaps = newlist; + spd->usi_firstputmap = newfirst; + spd->usi_lastputmap++; + } + + newmap->bend = sbend(sb); + for (i = 0; i <= sbend(sb); i++) { + count += branch_count(sb, i); + newmap->map[i] = i; + } + for (i = spd->usi_firstputmap; i < spd->usi_lastputmap; i++) { + struct putmap *cur; + cur = spd->usi_putmaps[i - spd->usi_firstputmap]; + if (!cur) + continue; + count -= atomic_read(&cur->count); + } + atomic_set(&newmap->count, count); + spd->usi_putmaps[spd->usi_lastputmap - spd->usi_firstputmap] = newmap; + + print_exit_status(0); + return 0; +} + +int unionfs_ioctl_branchcount(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int err = 0; + int bstart, bend; + int i; + struct super_block *sb = file->f_dentry->d_sb; + + print_entry_location(); + + bstart = sbstart(sb); + bend = sbend(sb); + + err = bend + 1; + if (!arg) + goto out; + + for (i = bstart; i <= bend; i++) { + if (put_user(branch_count(sb, i), ((int __user *)arg) + i)) { + err = -EFAULT; + goto out; + } + } + + out: + print_exit_status(err); + return err; +} + +int unionfs_ioctl_incgen(struct file *file, unsigned int cmd, unsigned long arg) +{ + int err = 0; + struct super_block *sb; + + print_entry_location(); + + sb = file->f_dentry->d_sb; + + unionfs_write_lock(sb); + if ((err = newputmap(sb))) + goto out; + + atomic_inc(&stopd(sb)->usi_generation); + err = atomic_read(&stopd(sb)->usi_generation); + + atomic_set(&dtopd(sb->s_root)->udi_generation, err); + atomic_set(&itopd(sb->s_root->d_inode)->uii_generation, err); + + out: + unionfs_write_unlock(sb); + print_exit_status(err); + return err; +} + +int unionfs_ioctl_addbranch(struct inode *inode, unsigned int cmd, + unsigned long arg) +{ + int err; + struct unionfs_addbranch_args *addargs = NULL; + struct nameidata nd; + char *path = NULL; + int gen; + int i; + int count; + + int pobjects; + + struct vfsmount **new_hidden_mnt = NULL; + struct inode **new_uii_inode = NULL; + struct dentry **new_udi_dentry = NULL; + struct super_block **new_usi_sb = NULL; + int *new_branchperms = NULL; + atomic_t *new_counts = NULL; + + struct dentry *root = NULL; + struct dentry *hidden_root = NULL; + + print_entry_location(); + + err = -ENOMEM; + addargs = KMALLOC(sizeof(struct unionfs_addbranch_args), GFP_KERNEL); + if (!addargs) + goto out; + + err = -EFAULT; + if (copy_from_user + (addargs, (const void __user *)arg, + sizeof(struct unionfs_addbranch_args))) + goto out; + + err = -EINVAL; + if (addargs->ab_perms & ~(MAY_READ | MAY_WRITE | MAY_NFSRO)) + goto out; + if (!(addargs->ab_perms & MAY_READ)) + goto out; + + err = -E2BIG; + if (sbend(inode->i_sb) > FD_SETSIZE) + goto out; + + err = -ENOMEM; + if (!(path = getname((const char __user *)addargs->ab_path))) + goto out; + + err = path_lookup(path, LOOKUP_FOLLOW, &nd); + + RECORD_PATH_LOOKUP(&nd); + if (err) + goto out; + if ((err = check_branch(&nd))) { + path_release(&nd); + RECORD_PATH_RELEASE(&nd); + goto out; + } + + unionfs_write_lock(inode->i_sb); + lock_dentry(inode->i_sb->s_root); + + root = inode->i_sb->s_root; + for (i = dbstart(inode->i_sb->s_root); i <= dbend(inode->i_sb->s_root); + i++) { + hidden_root = dtohd_index(root, i); + if (is_branch_overlap(hidden_root, nd.dentry)) { + err = -EINVAL; + goto out; + } + } + + err = -EINVAL; + if (addargs->ab_branch < 0 + || (addargs->ab_branch > (sbend(inode->i_sb) + 1))) + goto out; + + if ((err = newputmap(inode->i_sb))) + goto out; + + stopd(inode->i_sb)->b_end++; + dtopd(inode->i_sb->s_root)->udi_bcount++; + set_dbend(inode->i_sb->s_root, dbend(inode->i_sb->s_root) + 1); + itopd(inode->i_sb->s_root->d_inode)->b_end++; + + atomic_inc(&stopd(inode->i_sb)->usi_generation); + gen = atomic_read(&stopd(inode->i_sb)->usi_generation); + + pobjects = (sbend(inode->i_sb) + 1) - UNIONFS_INLINE_OBJECTS; + if (pobjects > 0) { + /* Reallocate the dynamic structures. */ + new_hidden_mnt = + KZALLOC(sizeof(struct vfsmount *) * pobjects, GFP_KERNEL); + new_udi_dentry = + KZALLOC(sizeof(struct dentry *) * pobjects, GFP_KERNEL); + new_uii_inode = + KZALLOC(sizeof(struct inode *) * pobjects, GFP_KERNEL); + new_usi_sb = + KZALLOC(sizeof(struct super_block *) * pobjects, + GFP_KERNEL); + new_counts = KZALLOC(sizeof(atomic_t) * pobjects, GFP_KERNEL); + new_branchperms = KZALLOC(sizeof(int) * pobjects, GFP_KERNEL); + if (!new_hidden_mnt || !new_udi_dentry || !new_uii_inode + || !new_counts || !new_usi_sb || !new_branchperms) { + err = -ENOMEM; + goto out; + } + } + + /* Copy the in-place values to our new structure. */ + for (i = UNIONFS_INLINE_OBJECTS; i < addargs->ab_branch; i++) { + int j = i - UNIONFS_INLINE_OBJECTS; + + count = branch_count(inode->i_sb, i); + atomic_set(&(new_counts[j]), count); + + new_branchperms[j] = branchperms(inode->i_sb, i); + new_hidden_mnt[j] = stohiddenmnt_index(inode->i_sb, i); + + new_usi_sb[j] = stohs_index(inode->i_sb, i); + new_udi_dentry[j] = dtohd_index(inode->i_sb->s_root, i); + new_uii_inode[j] = itohi_index(inode->i_sb->s_root->d_inode, i); + } + + /* Shift the ends to the right (only handle reallocated bits). */ + for (i = sbend(inode->i_sb) - 1; i >= (int)addargs->ab_branch; i--) { + int j = i + 1; + int perms; + struct vfsmount *hm; + struct super_block *hs; + struct dentry *hd; + struct inode *hi; + int pmindex; + + count = branch_count(inode->i_sb, i); + perms = branchperms(inode->i_sb, i); + hm = stohiddenmnt_index(inode->i_sb, i); + hs = stohs_index(inode->i_sb, i); + hd = dtohd_index(inode->i_sb->s_root, i); + hi = itohi_index(inode->i_sb->s_root->d_inode, i); + + /* Update the newest putmap, so it is correct for later. */ + pmindex = stopd(inode->i_sb)->usi_lastputmap; + pmindex -= stopd(inode->i_sb)->usi_firstputmap; + stopd(inode->i_sb)->usi_putmaps[pmindex]->map[i] = j; + + if (j >= UNIONFS_INLINE_OBJECTS) { + j -= UNIONFS_INLINE_OBJECTS; + atomic_set(&(new_counts[j]), count); + new_branchperms[j] = perms; + new_hidden_mnt[j] = hm; + new_usi_sb[j] = hs; + new_udi_dentry[j] = hd; + new_uii_inode[j] = hi; + } else { + set_branch_count(inode->i_sb, j, count); + set_branchperms(inode->i_sb, j, perms); + set_stohiddenmnt_index(inode->i_sb, j, hm); + set_stohs_index(inode->i_sb, j, hs); + set_dtohd_index(inode->i_sb->s_root, j, hd); + set_itohi_index(inode->i_sb->s_root->d_inode, j, hi); + } + } + + /* Now we can free the old ones. */ + KFREE(dtopd(inode->i_sb->s_root)->udi_dentry_p); + KFREE(itopd(inode->i_sb->s_root->d_inode)->uii_inode_p); + KFREE(stopd(inode->i_sb)->usi_hidden_mnt_p); + KFREE(stopd(inode->i_sb)->usi_sb_p); + KFREE(stopd(inode->i_sb)->usi_sbcount_p); + KFREE(stopd(inode->i_sb)->usi_branchperms_p); + + /* Update the real pointers. */ + dtohd_ptr(inode->i_sb->s_root) = new_udi_dentry; + itohi_ptr(inode->i_sb->s_root->d_inode) = new_uii_inode; + stohiddenmnt_ptr(inode->i_sb) = new_hidden_mnt; + stohs_ptr(inode->i_sb) = new_usi_sb; + stopd(inode->i_sb)->usi_sbcount_p = new_counts; + stopd(inode->i_sb)->usi_branchperms_p = new_branchperms; + + /* Re-NULL the new ones so we don't try to free them. */ + new_hidden_mnt = NULL; + new_udi_dentry = NULL; + new_usi_sb = NULL; + new_uii_inode = NULL; + new_counts = NULL; + new_branchperms = NULL; + + /* Put the new dentry information into it's slot. */ + set_dtohd_index(inode->i_sb->s_root, addargs->ab_branch, nd.dentry); + set_itohi_index(inode->i_sb->s_root->d_inode, addargs->ab_branch, + IGRAB(nd.dentry->d_inode)); + set_branchperms(inode->i_sb, addargs->ab_branch, addargs->ab_perms); + set_branch_count(inode->i_sb, addargs->ab_branch, 0); + set_stohiddenmnt_index(inode->i_sb, addargs->ab_branch, nd.mnt); + set_stohs_index(inode->i_sb, addargs->ab_branch, nd.dentry->d_sb); + + atomic_set(&dtopd(inode->i_sb->s_root)->udi_generation, gen); + atomic_set(&itopd(inode->i_sb->s_root->d_inode)->uii_generation, gen); + + fixputmaps(inode->i_sb); + + out: + unlock_dentry(inode->i_sb->s_root); + unionfs_write_unlock(inode->i_sb); + + KFREE(new_hidden_mnt); + KFREE(new_udi_dentry); + KFREE(new_uii_inode); + KFREE(new_usi_sb); + KFREE(new_counts); + KFREE(new_branchperms); + KFREE(addargs); + if (path) + putname(path); + + print_exit_status(err); + + return err; +} + +/* This must be called with the super block already locked. */ +int unionfs_ioctl_delbranch(struct super_block *sb, unsigned long arg) +{ + struct dentry *hidden_dentry; + struct inode *hidden_inode; + struct vfsmount *hidden_mnt; + struct dentry *root_dentry; + struct inode *root_inode; + int err = 0; + int pmindex, i, gen; + + print_entry("branch = %lu ", arg); + lock_dentry(sb->s_root); + + err = -EBUSY; + if (sbmax(sb) == 1) + goto out; + err = -EINVAL; + if (arg < 0 || arg > stopd(sb)->b_end) + goto out; + err = -EBUSY; + if (branch_count(sb, arg)) + goto out; + + if ((err = newputmap(sb))) + goto out; + + pmindex = stopd(sb)->usi_lastputmap; + pmindex -= stopd(sb)->usi_firstputmap; + + atomic_inc(&stopd(sb)->usi_generation); + gen = atomic_read(&stopd(sb)->usi_generation); + + root_dentry = sb->s_root; + root_inode = sb->s_root->d_inode; + + hidden_dentry = dtohd_index(root_dentry, arg); + hidden_mnt = stohiddenmnt_index(sb, arg); + hidden_inode = itohi_index(root_inode, arg); + + DPUT(hidden_dentry); + IPUT(hidden_inode); + mntput(hidden_mnt); + + for (i = arg; i <= (sbend(sb) - 1); i++) { + set_branch_count(sb, i, branch_count(sb, i + 1)); + set_stohiddenmnt_index(sb, i, stohiddenmnt_index(sb, i + 1)); + set_stohs_index(sb, i, stohs_index(sb, i + 1)); + set_branchperms(sb, i, branchperms(sb, i + 1)); + set_dtohd_index(root_dentry, i, + dtohd_index(root_dentry, i + 1)); + set_itohi_index(root_inode, i, itohi_index(root_inode, i + 1)); + stopd(sb)->usi_putmaps[pmindex]->map[i + 1] = i; + } + + set_dtohd_index(root_dentry, sbend(sb), NULL); + set_itohi_index(root_inode, sbend(sb), NULL); + set_stohiddenmnt_index(sb, sbend(sb), NULL); + set_stohs_index(sb, sbend(sb), NULL); + + stopd(sb)->b_end--; + set_dbend(root_dentry, dbend(root_dentry) - 1); + dtopd(root_dentry)->udi_bcount--; + itopd(root_inode)->b_end--; + + atomic_set(&dtopd(root_dentry)->udi_generation, gen); + atomic_set(&itopd(root_inode)->uii_generation, gen); + + fixputmaps(sb); + + /* This doesn't open a file, so we might have to free the map here. */ + if (atomic_read(&stopd(sb)->usi_putmaps[pmindex]->count) == 0) { + KFREE(stopd(sb)->usi_putmaps[pmindex]); + stopd(sb)->usi_putmaps[pmindex] = NULL; + } + + out: + unlock_dentry(sb->s_root); + print_exit_status(err); + + return err; +} + +int unionfs_ioctl_rdwrbranch(struct inode *inode, unsigned int cmd, + unsigned long arg) +{ + int err; + struct unionfs_rdwrbranch_args *rdwrargs = NULL; + int gen; + + print_entry_location(); + + unionfs_write_lock(inode->i_sb); + lock_dentry(inode->i_sb->s_root); + + if ((err = newputmap(inode->i_sb))) + goto out; + + err = -ENOMEM; + rdwrargs = KMALLOC(sizeof(struct unionfs_rdwrbranch_args), GFP_KERNEL); + if (!rdwrargs) + goto out; + + err = -EFAULT; + if (copy_from_user + (rdwrargs, (const void __user *)arg, + sizeof(struct unionfs_rdwrbranch_args))) + goto out; + + err = -EINVAL; + if (rdwrargs->rwb_branch < 0 + || (rdwrargs->rwb_branch > (sbend(inode->i_sb) + 1))) + goto out; + if (rdwrargs->rwb_perms & ~(MAY_READ | MAY_WRITE | MAY_NFSRO)) + goto out; + if (!(rdwrargs->rwb_perms & MAY_READ)) + goto out; + + set_branchperms(inode->i_sb, rdwrargs->rwb_branch, rdwrargs->rwb_perms); + + atomic_inc(&stopd(inode->i_sb)->usi_generation); + gen = atomic_read(&stopd(inode->i_sb)->usi_generation); + atomic_set(&dtopd(inode->i_sb->s_root)->udi_generation, gen); + atomic_set(&itopd(inode->i_sb->s_root->d_inode)->uii_generation, gen); + + err = 0; + + out: + unlock_dentry(inode->i_sb->s_root); + unionfs_write_unlock(inode->i_sb); + KFREE(rdwrargs); + + print_exit_status(err); + + return err; +} + +int unionfs_ioctl_queryfile(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int err = 0; + fd_set branchlist; + + int bstart = 0, bend = 0, bindex = 0; + struct dentry *dentry, *hidden_dentry; + + print_entry_location(); + + dentry = file->f_dentry; + lock_dentry(dentry); + if ((err = unionfs_partial_lookup(dentry))) + goto out; + bstart = dbstart(dentry); + bend = dbend(dentry); + + FD_ZERO(&branchlist); + + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + if (hidden_dentry->d_inode) + FD_SET(bindex, &branchlist); + } + + err = copy_to_user((void __user *)arg, &branchlist, sizeof(fd_set)); + if (err) { + err = -EFAULT; + goto out; + } + + out: + unlock_dentry(dentry); + err = err < 0 ? err : bend; + print_exit_status(err); + return (err); +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/commonfops.c newtree/fs/unionfs/commonfops.c --- oldtree/fs/unionfs/commonfops.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/commonfops.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: commonfops.c,v 1.54 2006/01/15 00:15:57 dquigley Exp $ + */ + +#include "unionfs.h" + +/* We only need this function here, but it could get promoted to unionfs.h, if + * other things need a generation specific branch putting function. */ +static inline void branchput_gen(int generation, struct super_block *sb, + int index) +{ + struct putmap *putmap; + + if (generation == atomic_read(&stopd(sb)->usi_generation)) { + branchput(sb, index); + return; + } + + BUG_ON(stopd(sb)->usi_firstputmap > generation); + BUG_ON(stopd(sb)->usi_lastputmap < generation); + + putmap = + stopd(sb)->usi_putmaps[generation - stopd(sb)->usi_firstputmap]; + BUG_ON(index < 0); + BUG_ON(index > putmap->bend); + BUG_ON(putmap->map[index] < 0); + branchput(sb, putmap->map[index]); + if (atomic_dec_and_test(&putmap->count)) { + stopd(sb)->usi_putmaps[generation - stopd(sb)->usi_firstputmap] + = NULL; + fist_dprint(8, "Freeing putmap %d.\n", generation); + KFREE(putmap); + } +} + +static char *get_random_name(int size, unsigned char *name) +{ + int i; + int j; + unsigned char *tmpbuf = NULL; + + if (size <= WHLEN) + return NULL; + + if (!name) + name = KMALLOC(size + 1, GFP_KERNEL); + if (!name) { + name = ERR_PTR(-ENOMEM); + goto out; + } + strncpy(name, WHPFX, WHLEN); + + tmpbuf = KMALLOC(size, GFP_KERNEL); + if (!tmpbuf) { + KFREE(name); + name = ERR_PTR(-ENOMEM); + goto out; + } + + get_random_bytes((void *)tmpbuf, (size - 3) / 2); + + j = WHLEN; + i = 0; + while ((i < (size - 3) / 2) && (j < size)) { + /* get characters in the 0-9, A-F range */ + + name[j] = + (tmpbuf[i] % 16) < + 10 ? (tmpbuf[i] % 16) + '0' : (tmpbuf[i] % 16) + 'a'; + j++; + if (j == size) + break; + name[j] = + (tmpbuf[i] >> 4) < + 10 ? (tmpbuf[i] >> 4) + '0' : (tmpbuf[i] >> 4) + 'a'; + j++; + + i++; + } + + name[size] = '\0'; + + out: + KFREE(tmpbuf); + return (name); + +} + +static int copyup_deleted_file(struct file *file, struct dentry *dentry, + int bstart, int bindex) +{ + int attempts = 0; + int err; + int exists = 1; + char *name = NULL; + struct dentry *tmp_dentry = NULL; + struct dentry *hidden_dentry = NULL; + struct dentry *hidden_dir_dentry = NULL; + + print_entry_location(); + + /* Try five times to get a unique file name, fail after that. Five is + * simply a magic number, because we shouldn't try forever. */ + while (exists) { + /* The first call allocates, the subsequent ones reuse. */ + name = get_random_name(UNIONFS_TMPNAM_LEN, name); + err = -ENOMEM; + if (!name) + goto out; + + hidden_dentry = dtohd_index(dentry, bstart); + + tmp_dentry = LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + UNIONFS_TMPNAM_LEN); + err = PTR_ERR(tmp_dentry); + if (IS_ERR(tmp_dentry)) + goto out; + exists = tmp_dentry->d_inode ? 1 : 0; + DPUT(tmp_dentry); + + err = -EEXIST; + if (++attempts > 5) + goto out; + } + + err = copyup_named_file(dentry->d_parent->d_inode, file, name, bstart, + bindex, file->f_dentry->d_inode->i_size); + if (err) + goto out; + + /* bring it to the same state as an unlinked file */ + hidden_dentry = dtohd_index(dentry, dbstart(dentry)); + hidden_dir_dentry = lock_parent(hidden_dentry); + err = vfs_unlink(hidden_dir_dentry->d_inode, hidden_dentry); + unlock_dir(hidden_dir_dentry); + + out: + KFREE(name); + print_exit_status(err); + return err; +} + +int unionfs_file_revalidate(struct file *file, int willwrite) +{ + struct super_block *sb; + struct dentry *dentry; + int sbgen, fgen, dgen; + int bindex, bstart, bend; + struct file *hidden_file; + struct dentry *hidden_dentry; + + int err = 0; + + print_entry(" file = %p", file); + + dentry = file->f_dentry; + lock_dentry(dentry); + sb = dentry->d_sb; + unionfs_read_lock(sb); + if (!unionfs_d_revalidate(dentry, NULL) && !d_deleted(dentry)) { + err = -ESTALE; + goto out; + } + fist_print_dentry("file revalidate in", dentry); + + sbgen = atomic_read(&stopd(sb)->usi_generation); + dgen = atomic_read(&dtopd(dentry)->udi_generation); + fgen = atomic_read(&ftopd(file)->ufi_generation); + + BUG_ON(sbgen > dgen); + + /* There are two cases we are interested in. The first is if the + * generation is lower than the super-block. The second is if someone + * has copied up this file from underneath us, we also need to refresh + * things. */ + if (!d_deleted(dentry) && + ((sbgen > fgen) || (dbstart(dentry) != fbstart(file)))) { + /* First we throw out the existing files. */ + bstart = fbstart(file); + bend = fbend(file); + for (bindex = bstart; bindex <= bend; bindex++) { + if (ftohf_index(file, bindex)) { + branchput_gen(fgen, dentry->d_sb, bindex); + fput(ftohf_index(file, bindex)); + } + } + if (ftohf_ptr(file)) { + KFREE(ftohf_ptr(file)); + ftohf_ptr(file) = NULL; + } + + /* Now we reopen the file(s) as in unionfs_open. */ + bstart = fbstart(file) = dbstart(dentry); + bend = fbend(file) = dbend(dentry); + + if (sbmax(sb) > UNIONFS_INLINE_OBJECTS) { + int size = + sizeof(struct file *) * (sbmax(sb) - + UNIONFS_INLINE_OBJECTS); + ftohf_ptr(file) = KZALLOC(size, GFP_KERNEL); + if (!ftohf_ptr(file)) { + err = -ENOMEM; + goto out; + } + } + memset(ftohf_inline(file), 0, + sizeof(struct file *) * UNIONFS_INLINE_OBJECTS); + + if (S_ISDIR(dentry->d_inode->i_mode)) { + /* We need to open all the files. */ + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + + DGET(hidden_dentry); + mntget(stohiddenmnt_index(sb, bindex)); + branchget(sb, bindex); + + hidden_file = + DENTRY_OPEN(hidden_dentry, + stohiddenmnt_index(sb, bindex), + file->f_flags); + if (IS_ERR(hidden_file)) { + err = PTR_ERR(hidden_file); + goto out; + } else { + set_ftohf_index(file, bindex, + hidden_file); + } + } + } else { + /* We only open the highest priority branch. */ + hidden_dentry = dtohd(dentry); + if (willwrite && IS_WRITE_FLAG(file->f_flags) + && is_robranch(dentry)) { + for (bindex = bstart - 1; bindex >= 0; bindex--) { + + err = copyup_file(dentry-> + d_parent-> + d_inode, + file, + bstart, + bindex, + file-> + f_dentry-> + d_inode->i_size); + + if (!err) + break; + else + continue; + + } + atomic_set(&ftopd(file)->ufi_generation, + atomic_read(&itopd(dentry->d_inode)-> + uii_generation)); + goto out; + } + + DGET(hidden_dentry); + mntget(stohiddenmnt_index(sb, bstart)); + branchget(sb, bstart); + hidden_file = + DENTRY_OPEN(hidden_dentry, + stohiddenmnt_index(sb, bstart), + file->f_flags); + if (IS_ERR(hidden_file)) { + err = PTR_ERR(hidden_file); + goto out; + } + set_ftohf(file, hidden_file); + /* Fix up the position. */ + hidden_file->f_pos = file->f_pos; + + memcpy(&(hidden_file->f_ra), &(file->f_ra), + sizeof(struct file_ra_state)); + } + atomic_set(&ftopd(file)->ufi_generation, + atomic_read(&itopd(dentry->d_inode)-> + uii_generation)); + } + + /* Copyup on the first write to a file on a readonly branch. */ + if (willwrite && IS_WRITE_FLAG(file->f_flags) + && !IS_WRITE_FLAG(ftohf(file)->f_flags) && is_robranch(dentry)) { + fist_dprint(3, + "Doing delayed copyup of a read-write file on a read-only branch.\n"); + bstart = fbstart(file); + bend = fbend(file); + + BUG_ON(!S_ISREG(file->f_dentry->d_inode->i_mode)); + + for (bindex = bstart - 1; bindex >= 0; bindex--) { + if (!d_deleted(file->f_dentry)) { + err = + copyup_file(dentry->d_parent-> + d_inode, file, bstart, + bindex, + file->f_dentry-> + d_inode->i_size); + } else { + err = + copyup_deleted_file(file, dentry, bstart, + bindex); + } + + if (!err) + break; + else + continue; + + } + if (!err && (bstart > fbstart(file))) { + bend = fbend(file); + for (bindex = bstart; bindex <= bend; bindex++) { + if (ftohf_index(file, bindex)) { + branchput(dentry->d_sb, bindex); + fput(ftohf_index(file, bindex)); + set_ftohf_index(file, bindex, NULL); + } + } + fbend(file) = bend; + } + } + + out: + fist_print_dentry("file revalidate out", dentry); + unlock_dentry(dentry); + unionfs_read_unlock(dentry->d_sb); + print_exit_status(err); + return err; +} + +int unionfs_open(struct inode *inode, struct file *file) +{ + int err = 0; + int hidden_flags; + struct file *hidden_file = NULL; + struct dentry *hidden_dentry = NULL; + struct dentry *dentry = NULL; + int bindex = 0, bstart = 0, bend = 0; + int locked = 0; + + print_entry_location(); + + ftopd_lhs(file) = KZALLOC(sizeof(struct unionfs_file_info), GFP_KERNEL); + if (!ftopd(file)) { + err = -ENOMEM; + goto out; + } + fbstart(file) = -1; + fbend(file) = -1; + atomic_set(&ftopd(file)->ufi_generation, + atomic_read(&itopd(inode)->uii_generation)); + if (sbmax(inode->i_sb) > UNIONFS_INLINE_OBJECTS) { + int size = + sizeof(struct file *) * (sbmax(inode->i_sb) - + UNIONFS_INLINE_OBJECTS); + ftohf_ptr(file) = KZALLOC(size, GFP_KERNEL); + if (!ftohf_ptr(file)) { + err = -ENOMEM; + goto out; + } + } + memset(ftohf_inline(file), 0, + sizeof(struct file *) * UNIONFS_INLINE_OBJECTS); + + hidden_flags = file->f_flags; + + dentry = file->f_dentry; + fist_dprint(8, "dentry to open is %p\n", dentry); + lock_dentry(dentry); + unionfs_read_lock(inode->i_sb); + locked = 1; + + bstart = fbstart(file) = dbstart(dentry); + bend = fbend(file) = dbend(dentry); + + /* increment to show the kind of open, so that we can + * flush appropriately + */ + atomic_inc(&itopd(dentry->d_inode)->uii_totalopens); + + /* open all directories and make the unionfs file struct point to these hidden file structs */ + if (S_ISDIR(inode->i_mode)) { + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + + DGET(hidden_dentry); + mntget(stohiddenmnt_index(inode->i_sb, bindex)); + hidden_file = + DENTRY_OPEN(hidden_dentry, + stohiddenmnt_index(inode->i_sb, bindex), + hidden_flags); + if (IS_ERR(hidden_file)) { + err = PTR_ERR(hidden_file); + goto out; + } + + set_ftohf_index(file, bindex, hidden_file); + /* The branchget goes after the open, because otherwise + * we would miss the reference on release. */ + branchget(inode->i_sb, bindex); + } + } else { + /* open a file */ + hidden_dentry = dtohd(dentry); + + /* check for the permission for hidden file. If the error is COPYUP_ERR, + * copyup the file. + */ + if (hidden_dentry->d_inode && is_robranch(dentry)) { + /* if the open will change the file, copy it up otherwise defer it. */ + if (hidden_flags & O_TRUNC) { + int size = 0; + + err = -EROFS; + /* copyup the file */ + for (bindex = bstart - 1; bindex >= 0; bindex--) { + err = + copyup_file(dentry-> + d_parent-> + d_inode, file, + bstart, bindex, size); + if (!err) { + break; + } + } + goto out; + } else { + hidden_flags &= ~(OPEN_WRITE_FLAGS); + } + } + + DGET(hidden_dentry); + /* dentry_open will decrement mnt refcnt if err. + * otherwise fput() will do an mntput() for us upon file close. + */ + mntget(stohiddenmnt_index(inode->i_sb, bstart)); + hidden_file = DENTRY_OPEN(hidden_dentry, + stohiddenmnt_index(inode->i_sb, + bstart), + hidden_flags); + if (IS_ERR(hidden_file)) { + err = PTR_ERR(hidden_file); + goto out; + } else { + set_ftohf(file, hidden_file); + branchget(inode->i_sb, bstart); + } + } + + out: + /* freeing the allocated resources, and fput the opened files */ + if (err < 0 && ftopd(file)) { + if (!locked) + unionfs_read_lock(file->f_dentry->d_sb); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_file = ftohf_index(file, bindex); + if (hidden_file) { + branchput(file->f_dentry->d_sb, bindex); + /* fput calls dput for hidden_dentry */ + fput(hidden_file); + } + } + if (!locked) + unionfs_read_unlock(file->f_dentry->d_sb); + KFREE(ftohf_ptr(file)); + KFREE(ftopd(file)); + } + + fist_print_file("OUT: unionfs_open", file); + + if (locked) { + unlock_dentry(dentry); + unionfs_read_unlock(inode->i_sb); + } + print_exit_status(err); + return err; +} + +int unionfs_file_release(struct inode *inode, struct file *file) +{ + int err = 0; + struct file *hidden_file = NULL; + int bindex, bstart, bend; + int fgen; + + print_entry_location(); + + fist_checkinode(inode, "unionfs_release"); + + /* fput all the hidden files */ + fgen = atomic_read(&ftopd(file)->ufi_generation); + bstart = fbstart(file); + bend = fbend(file); + + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_file = ftohf_index(file, bindex); + + if (hidden_file) { + fput(hidden_file); + unionfs_read_lock(inode->i_sb); + branchput_gen(fgen, inode->i_sb, bindex); + unionfs_read_unlock(inode->i_sb); + } + } + KFREE(ftohf_ptr(file)); + + if (ftopd(file)->rdstate) { + ftopd(file)->rdstate->uds_access = jiffies; + fist_dprint(1, "Saving rdstate with cookie %u [%d.%lld]\n", + ftopd(file)->rdstate->uds_cookie, + ftopd(file)->rdstate->uds_bindex, + (long long)ftopd(file)->rdstate->uds_dirpos); + spin_lock(&itopd(inode)->uii_rdlock); + itopd(inode)->uii_rdcount++; + list_add_tail(&ftopd(file)->rdstate->uds_cache, + &itopd(inode)->uii_readdircache); + mark_inode_dirty(inode); + spin_unlock(&itopd(inode)->uii_rdlock); + ftopd(file)->rdstate = NULL; + } + KFREE(ftopd(file)); + + fist_checkinode(inode, "post unionfs_release"); + + print_exit_status(err); + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) +long unionfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +#else +int unionfs_ioctl(struct inode *unused, struct file *file, + unsigned int cmd, unsigned long arg) +#endif +{ + long err = 0; /* don't fail by default */ + struct file *hidden_file = NULL; + int val; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + + /* check if asked for local commands */ + switch (cmd) { + case FIST_IOCTL_GET_DEBUG_VALUE: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + val = fist_get_debug_value(); + err = put_user(val, (int __user *)arg); + break; + + case FIST_IOCTL_SET_DEBUG_VALUE: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + err = get_user(val, (int __user *)arg); + if (err) + break; + fist_dprint(6, "IOCTL SET: got arg %d\n", val); + if (val < 0 || val > 20) { + err = -EINVAL; + break; + } + fist_set_debug_value(val); + break; + + /* add non-debugging fist ioctl's here */ + + case UNIONFS_IOCTL_BRANCH_COUNT: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + err = unionfs_ioctl_branchcount(file, cmd, arg); + break; + + case UNIONFS_IOCTL_INCGEN: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + err = unionfs_ioctl_incgen(file, cmd, arg); + break; + + case UNIONFS_IOCTL_ADDBRANCH: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + err = + unionfs_ioctl_addbranch(file->f_dentry->d_inode, cmd, arg); + break; + + case UNIONFS_IOCTL_RDWRBRANCH: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + err = + unionfs_ioctl_rdwrbranch(file->f_dentry->d_inode, cmd, arg); + break; + + case UNIONFS_IOCTL_QUERYFILE: + /* XXX: This should take the file. */ + err = unionfs_ioctl_queryfile(file, cmd, arg); + break; + + default: + hidden_file = ftohf(file); + + err = security_file_ioctl(hidden_file, cmd, arg); + if (err) + goto out; + err = -ENOTTY; + if (!hidden_file || !hidden_file->f_op) + goto out; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) + if (hidden_file->f_op->unlocked_ioctl) { + err = + hidden_file->f_op->unlocked_ioctl(hidden_file, cmd, + arg); + } else +#endif + if (hidden_file->f_op->ioctl) { + lock_kernel(); + err = + hidden_file->f_op->ioctl(hidden_file->f_dentry-> + d_inode, hidden_file, cmd, + arg); + unlock_kernel(); + } + } /* end of outer switch statement */ + + out: + print_exit_status((int)err); + return err; +} + +int unionfs_flush(struct file *file) +{ + int err = 0; /* assume ok (see open.c:close_fp) */ + struct file *hidden_file = NULL; + int bindex, bstart, bend; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + if (!atomic_dec_and_test + (&itopd(file->f_dentry->d_inode)->uii_totalopens)) + goto out; + + lock_dentry(file->f_dentry); + + bstart = fbstart(file); + bend = fbend(file); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_file = ftohf_index(file, bindex); + + if (hidden_file && hidden_file->f_op + && hidden_file->f_op->flush) { + err = hidden_file->f_op->flush(hidden_file); + if (err) + goto out_lock; + /* This was earlier done in the unlink_all function in unlink.c */ + /* if there are no more references to the dentry, dput it */ + if (d_deleted(file->f_dentry)) { + DPUT(dtohd_index(file->f_dentry, bindex)); + set_dtohd_index(file->f_dentry, bindex, NULL); + } + } + + } + + out_lock: + unlock_dentry(file->f_dentry); + out: + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/copyup.c newtree/fs/unionfs/copyup.c --- oldtree/fs/unionfs/copyup.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/copyup.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,744 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York* + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: copyup.c,v 1.61 2006/01/22 19:46:50 jsipek Exp $ + */ + +#include "unionfs.h" + +/*Not Working Yet*/ +static int copyup_xattrs(struct dentry *old_hidden_dentry, + struct dentry *new_hidden_dentry) +{ + int err = 0; + ssize_t list_size = -1; + char *name_list = NULL; + char *attr_value = NULL; + char *name_list_orig = NULL; + + print_entry_location(); + + if (!old_hidden_dentry->d_inode->i_op->getxattr || + !old_hidden_dentry->d_inode->i_op->listxattr || + !new_hidden_dentry->d_inode->i_op->setxattr) { + err = -ENOTSUPP; + goto out; + } + + list_size = + old_hidden_dentry->d_inode->i_op->listxattr(old_hidden_dentry, NULL, + 0); + if (list_size <= 0) { + err = list_size; + goto out; + } + + name_list = xattr_alloc(list_size + 1, XATTR_LIST_MAX); + if (!name_list || IS_ERR(name_list)) { + err = PTR_ERR(name_list); + goto out; + } + list_size = + old_hidden_dentry->d_inode->i_op->listxattr(old_hidden_dentry, + name_list, list_size); + attr_value = xattr_alloc(XATTR_SIZE_MAX, XATTR_SIZE_MAX); + if (!attr_value || IS_ERR(attr_value)) { + err = PTR_ERR(name_list); + goto out; + } + name_list_orig = name_list; + while (*name_list) { + ssize_t size; + down(&old_hidden_dentry->d_inode->i_sem); + err = security_inode_getxattr(old_hidden_dentry, name_list); + if (err) + size = err; + else + size = + old_hidden_dentry->d_inode->i_op-> + getxattr(old_hidden_dentry, name_list, attr_value, + XATTR_SIZE_MAX); + up(&old_hidden_dentry->d_inode->i_sem); + if (size < 0) { + err = size; + goto out; + } + + if (size > XATTR_SIZE_MAX) { + err = -E2BIG; + goto out; + } + + down(&new_hidden_dentry->d_inode->i_sem); + + err = + security_inode_setxattr(old_hidden_dentry, name_list, + attr_value, size, 0); + + if (!err) { + err = + new_hidden_dentry->d_inode->i_op-> + setxattr(new_hidden_dentry, name_list, attr_value, + size, 0); + if (!err) + security_inode_post_setxattr(old_hidden_dentry, + name_list, + attr_value, size, + 0); + } + up(&new_hidden_dentry->d_inode->i_sem); + + if (err < 0) + goto out; + name_list += strlen(name_list) + 1; + } + out: + name_list = name_list_orig; + + if (name_list) + xattr_free(name_list, list_size + 1); + if (attr_value) + xattr_free(attr_value, XATTR_SIZE_MAX); + /* It is no big deal if this fails, we just roll with the punches. */ + if (err == -ENOTSUPP) + err = 0; + return err; +} + +/* Determine the mode based on the copyup flags, and the existing dentry. */ +static int copyup_permissions(struct super_block *sb, + struct dentry *old_hidden_dentry, + struct dentry *new_hidden_dentry) +{ + struct iattr newattrs; + int err; + + print_entry_location(); + + newattrs.ia_atime = old_hidden_dentry->d_inode->i_atime; + newattrs.ia_mtime = old_hidden_dentry->d_inode->i_mtime; + newattrs.ia_ctime = old_hidden_dentry->d_inode->i_ctime; + newattrs.ia_valid = ATTR_CTIME | ATTR_ATIME | ATTR_MTIME | + ATTR_ATIME_SET | ATTR_MTIME_SET; + if (IS_SET(sb, COPYUP_FS_MOUNTER)) { + /* f/s mounter */ + newattrs.ia_mode = stopd(sb)->copyupmode; + newattrs.ia_valid |= ATTR_FORCE | ATTR_MODE; + if (stopd(sb)->copyupuid != -1) { + newattrs.ia_uid = stopd(sb)->copyupuid; + newattrs.ia_valid |= ATTR_UID; + } + if (stopd(sb)->copyupgid != -1) { + newattrs.ia_gid = stopd(sb)->copyupgid; + newattrs.ia_valid |= ATTR_GID; + } + } else if (IS_SET(sb, COPYUP_CURRENT_USER)) { + /* current file permission */ + newattrs.ia_mode = ~current->fs->umask & S_IRWXUGO; + newattrs.ia_valid |= ATTR_FORCE | ATTR_MODE; + } else { + /* original mode of old file */ + newattrs.ia_mode = old_hidden_dentry->d_inode->i_mode; + newattrs.ia_gid = old_hidden_dentry->d_inode->i_gid; + newattrs.ia_uid = old_hidden_dentry->d_inode->i_uid; + newattrs.ia_valid |= + ATTR_FORCE | ATTR_GID | ATTR_UID | ATTR_MODE; + } + if (newattrs.ia_valid & ATTR_MODE) { + newattrs.ia_mode = + (newattrs.ia_mode & S_IALLUGO) | (old_hidden_dentry-> + d_inode-> + i_mode & ~S_IALLUGO); + } + + err = notify_change(new_hidden_dentry, &newattrs); + + print_exit_status(err); + return err; +} + +int copyup_dentry(struct inode *dir, struct dentry *dentry, + int bstart, int new_bindex, + struct file **copyup_file, loff_t len) +{ + return copyup_named_dentry(dir, dentry, bstart, new_bindex, + dentry->d_name.name, + dentry->d_name.len, copyup_file, len); +} + +int copyup_named_dentry(struct inode *dir, struct dentry *dentry, + int bstart, int new_bindex, const char *name, + int namelen, struct file **copyup_file, loff_t len) +{ + struct dentry *new_hidden_dentry; + struct dentry *old_hidden_dentry = NULL; + struct super_block *sb; + struct file *input_file = NULL; + struct file *output_file = NULL; + ssize_t read_bytes, write_bytes; + mm_segment_t old_fs; + int err = 0; + char *buf; + int old_bindex; + int got_branch_input = -1; + int got_branch_output = -1; + int old_bstart; + int old_bend; + int size = len; + struct dentry *new_hidden_parent_dentry = NULL; + mm_segment_t oldfs; + char *symbuf = NULL; + uid_t saved_uid = current->fsuid; + gid_t saved_gid = current->fsgid; + + print_entry_location(); + verify_locked(dentry); + fist_print_dentry("IN: copyup_named_dentry", dentry); + + old_bindex = bstart; + old_bstart = dbstart(dentry); + old_bend = dbend(dentry); + + BUG_ON(new_bindex < 0); + BUG_ON(new_bindex >= old_bindex); + + sb = dir->i_sb; + + unionfs_read_lock(sb); + + if ((err = is_robranch_super(sb, new_bindex))) + goto out; + + /* Create the directory structure above this dentry. */ + new_hidden_dentry = create_parents_named(dir, dentry, name, new_bindex); + if (IS_ERR(new_hidden_dentry)) { + err = PTR_ERR(new_hidden_dentry); + goto out; + } + + fist_print_generic_dentry("Copyup Object", new_hidden_dentry); + + /* Now we actually create the object. */ + old_hidden_dentry = dtohd_index(dentry, old_bindex); + DGET(old_hidden_dentry); + + /* For symlinks, we must read the link before we lock the directory. */ + if (S_ISLNK(old_hidden_dentry->d_inode->i_mode)) { + + symbuf = KMALLOC(PATH_MAX, GFP_KERNEL); + if (!symbuf) { + err = -ENOMEM; + goto copyup_readlink_err; + } + + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = + old_hidden_dentry->d_inode->i_op-> + readlink(old_hidden_dentry, (char __user *)symbuf, + PATH_MAX); + set_fs(oldfs); + if (err < 0) + goto copyup_readlink_err; + symbuf[err] = '\0'; + } + + /* Now we lock the parent, and create the object in the new branch. */ + new_hidden_parent_dentry = lock_parent(new_hidden_dentry); + current->fsuid = new_hidden_parent_dentry->d_inode->i_uid; + current->fsgid = new_hidden_parent_dentry->d_inode->i_gid; + if (S_ISDIR(old_hidden_dentry->d_inode->i_mode)) { + err = vfs_mkdir(new_hidden_parent_dentry->d_inode, + new_hidden_dentry, S_IRWXU); + } else if (S_ISLNK(old_hidden_dentry->d_inode->i_mode)) { + err = vfs_symlink(new_hidden_parent_dentry->d_inode, + new_hidden_dentry, symbuf, S_IRWXU); + } else if (S_ISBLK(old_hidden_dentry->d_inode->i_mode) + || S_ISCHR(old_hidden_dentry->d_inode->i_mode) + || S_ISFIFO(old_hidden_dentry->d_inode->i_mode) + || S_ISSOCK(old_hidden_dentry->d_inode->i_mode)) { + err = vfs_mknod(new_hidden_parent_dentry->d_inode, + new_hidden_dentry, + old_hidden_dentry->d_inode->i_mode, + old_hidden_dentry->d_inode->i_rdev); + } else if (S_ISREG(old_hidden_dentry->d_inode->i_mode)) { + err = vfs_create(new_hidden_parent_dentry->d_inode, + new_hidden_dentry, S_IRWXU, NULL); + } else { + char diemsg[100]; + snprintf(diemsg, sizeof(diemsg), "Unknown inode type %d\n", + old_hidden_dentry->d_inode->i_mode); + printk(KERN_ERR "%s\n", diemsg); + BUG(); + } + current->fsuid = saved_uid; + current->fsgid = saved_gid; + copyup_readlink_err: + KFREE(symbuf); + if (err) { + /* get rid of the hidden dentry and all its traces */ + DPUT(new_hidden_dentry); + set_dtohd_index(dentry, new_bindex, NULL); + set_dbstart(dentry, old_bstart); + set_dbend(dentry, old_bend); + goto out_dir; + } + + if (stopd(sb)->usi_persistent) { + err = write_uin(dentry->d_sb, dentry->d_inode->i_ino, + new_bindex, new_hidden_dentry->d_inode->i_ino); + if (err) + goto out_dir; + } + + /* We actually copyup the file here. */ + if (S_ISREG(old_hidden_dentry->d_inode->i_mode)) { + mntget(stohiddenmnt_index(sb, old_bindex)); + branchget(sb, old_bindex); + got_branch_input = old_bindex; + input_file = + DENTRY_OPEN(old_hidden_dentry, + stohiddenmnt_index(sb, old_bindex), O_RDONLY); + if (IS_ERR(input_file)) { + err = PTR_ERR(input_file); + goto out_dir; + } + if (!input_file->f_op || !input_file->f_op->read) { + err = -EINVAL; + goto out_dir; + } + + /* copy the new file */ + DGET(new_hidden_dentry); + mntget(stohiddenmnt_index(sb, new_bindex)); + branchget(sb, new_bindex); + got_branch_output = new_bindex; + output_file = + DENTRY_OPEN(new_hidden_dentry, + stohiddenmnt_index(sb, new_bindex), O_WRONLY); + if (IS_ERR(output_file)) { + err = PTR_ERR(output_file); + goto out_dir; + } + if (!output_file->f_op || !output_file->f_op->write) { + err = -EINVAL; + goto out_dir; + } + + /* allocating a buffer */ + buf = (char *)KMALLOC(PAGE_SIZE, GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto out_dir; + } + + /* now read PAGE_SIZE bytes from offset 0 in a loop */ + old_fs = get_fs(); + + input_file->f_pos = 0; + output_file->f_pos = 0; + + set_fs(KERNEL_DS); + do { + if (len >= PAGE_SIZE) + size = PAGE_SIZE; + else if ((len < PAGE_SIZE) && (len > 0)) + size = len; + + len -= PAGE_SIZE; + + read_bytes = + input_file->f_op->read(input_file, + (char __user *)buf, size, + &input_file->f_pos); + if (read_bytes <= 0) { + err = read_bytes; + break; + } + + write_bytes = + output_file->f_op->write(output_file, + (char __user *)buf, + read_bytes, + &output_file->f_pos); + if (write_bytes < 0 || (write_bytes < read_bytes)) { + err = -EIO; + break; + } + } while ((read_bytes > 0) && (len > 0)); + set_fs(old_fs); + KFREE(buf); + } + + /* Set permissions. */ + if ((err = + copyup_permissions(sb, old_hidden_dentry, new_hidden_dentry))) + goto out_dir; + /* Selinux uses extended attributes for permissions. */ + if ((err = copyup_xattrs(old_hidden_dentry, new_hidden_dentry))) + goto out_dir; + + /* do not allow files getting deleted to be reinterposed */ + if (!d_deleted(dentry)) + unionfs_reinterpose(dentry); + + out_dir: + if (new_hidden_parent_dentry) + unlock_dir(new_hidden_parent_dentry); + out: + if (input_file && !IS_ERR(input_file)) { + fput(input_file); + } else { + /* since input file was not opened, we need to explicitly + * dput the old_hidden_dentry + */ + DPUT(old_hidden_dentry); + } + + /* in any case, we have to branchput */ + if (got_branch_input >= 0) + branchput(sb, got_branch_input); + + if (output_file) { + if (copyup_file && !err) { + *copyup_file = output_file; + } else { + if (!err) { + fput(output_file); + } + branchput(sb, got_branch_output); + } + } + + unionfs_read_unlock(sb); + + fist_print_dentry("OUT: copyup_dentry", dentry); + fist_print_inode("OUT: copyup_dentry", dentry->d_inode); + + print_exit_status(err); + return err; +} + +/* This function creates a copy of a file represented by 'file' which currently + * resides in branch 'bstart' to branch 'new_bindex. The copy will be named + * "name". */ +int copyup_named_file(struct inode *dir, struct file *file, char *name, + int bstart, int new_bindex, loff_t len) +{ + int err = 0; + struct file *output_file = NULL; + + print_entry_location(); + + err = copyup_named_dentry(dir, file->f_dentry, bstart, + new_bindex, name, strlen(name), &output_file, + len); + if (!err) { + fbstart(file) = new_bindex; + set_ftohf_index(file, new_bindex, output_file); + } + + print_exit_status(err); + return err; +} + +/* This function creates a copy of a file represented by 'file' which currently + * resides in branch 'bstart' to branch 'new_bindex. + */ +int copyup_file(struct inode *dir, struct file *file, int bstart, + int new_bindex, loff_t len) +{ + int err = 0; + struct file *output_file = NULL; + + print_entry_location(); + + err = copyup_dentry(dir, file->f_dentry, bstart, new_bindex, + &output_file, len); + if (!err) { + fbstart(file) = new_bindex; + set_ftohf_index(file, new_bindex, output_file); + } + + print_exit_status(err); + return err; +} + +/* This function replicates the directory structure upto given dentry + * in the bindex branch. Can create directory structure recursively to the right + * also. + */ +struct dentry *create_parents(struct inode *dir, struct dentry *dentry, + int bindex) +{ + struct dentry *hidden_dentry; + + print_entry_location(); + hidden_dentry = + create_parents_named(dir, dentry, dentry->d_name.name, bindex); + print_exit_location(); + + return (hidden_dentry); +} + +/* This function replicates the directory structure upto given dentry + * in the bindex branch. */ +struct dentry *create_parents_named(struct inode *dir, struct dentry *dentry, + const char *name, int bindex) +{ + int err; + struct dentry *child_dentry; + struct dentry *parent_dentry; + struct dentry *hidden_parent_dentry = NULL; + struct dentry *hidden_dentry = NULL; + const char *childname; + unsigned int childnamelen; + + int old_kmalloc_size; + int kmalloc_size; + int num_dentry; + int count; + + int old_bstart; + int old_bend; + struct dentry **path = NULL; + struct dentry **tmp_path; + struct super_block *sb; + int persistent; + + print_entry_location(); + + verify_locked(dentry); + + /* There is no sense allocating any less than the minimum. */ + kmalloc_size = malloc_sizes[0].cs_size; + num_dentry = kmalloc_size / sizeof(struct dentry *); + + if ((err = is_robranch_super(dir->i_sb, bindex))) { + hidden_dentry = ERR_PTR(err); + goto out; + } + + fist_print_dentry("IN: create_parents_named", dentry); + fist_dprint(8, "name = %s\n", name); + + old_bstart = dbstart(dentry); + old_bend = dbend(dentry); + + hidden_dentry = ERR_PTR(-ENOMEM); + path = (struct dentry **)KZALLOC(kmalloc_size, GFP_KERNEL); + if (!path) + goto out; + + /* assume the negative dentry of unionfs as the parent dentry */ + parent_dentry = dentry; + + count = 0; + /* This loop finds the first parent that exists in the given branch. + * We start building the directory structure from there. At the end + * of the loop, the following should hold: + * child_dentry is the first nonexistent child + * parent_dentry is the first existent parent + * path[0] is the = deepest child + * path[count] is the first child to create + */ + do { + child_dentry = parent_dentry; + + /* find the parent directory dentry in unionfs */ + parent_dentry = child_dentry->d_parent; + lock_dentry(parent_dentry); + + /* find out the hidden_parent_dentry in the given branch */ + hidden_parent_dentry = dtohd_index(parent_dentry, bindex); + + /* store the child dentry */ + path[count++] = child_dentry; + if (count == num_dentry) { + old_kmalloc_size = kmalloc_size; + kmalloc_size *= 2; + num_dentry = kmalloc_size / sizeof(struct dentry *); + + tmp_path = + (struct dentry **)KZALLOC(kmalloc_size, GFP_KERNEL); + if (!tmp_path) { + hidden_dentry = ERR_PTR(-ENOMEM); + goto out; + } + memcpy(tmp_path, path, old_kmalloc_size); + KFREE(path); + path = tmp_path; + tmp_path = NULL; + } + + } while (!hidden_parent_dentry); + count--; + + sb = dentry->d_sb; + persistent = stopd(sb)->usi_persistent; + + /* This is basically while(child_dentry != dentry). This loop is + * horrible to follow and should be replaced with cleaner code. */ + while (1) { + // get hidden parent dir in the current branch + hidden_parent_dentry = dtohd_index(parent_dentry, bindex); + unlock_dentry(parent_dentry); + + // init the values to lookup + childname = child_dentry->d_name.name; + childnamelen = child_dentry->d_name.len; + + if (child_dentry != dentry) { + // lookup child in the underlying file system + hidden_dentry = + LOOKUP_ONE_LEN(childname, hidden_parent_dentry, + childnamelen); + if (IS_ERR(hidden_dentry)) + goto out; + } else { + int loop_start; + int loop_end; + int new_bstart = -1; + int new_bend = -1; + int i; + + /* is the name a whiteout of the childname ? */ + //lookup the whiteout child in the underlying file system + hidden_dentry = + LOOKUP_ONE_LEN(name, hidden_parent_dentry, + strlen(name)); + if (IS_ERR(hidden_dentry)) + goto out; + + /* Replace the current dentry (if any) with the new one. */ + DPUT(dtohd_index(dentry, bindex)); + set_dtohd_index(dentry, bindex, hidden_dentry); + + loop_start = + (old_bstart < bindex) ? old_bstart : bindex; + loop_end = (old_bend > bindex) ? old_bend : bindex; + + /* This loop sets the bstart and bend for the new + * dentry by traversing from left to right. + * It also dputs all negative dentries except + * bindex (the newly looked dentry + */ + for (i = loop_start; i <= loop_end; i++) { + if (!dtohd_index(dentry, i)) + continue; + + if (i == bindex) { + new_bend = i; + if (new_bstart < 0) + new_bstart = i; + continue; + } + + if (!dtohd_index(dentry, i)->d_inode) { + DPUT(dtohd_index(dentry, i)); + set_dtohd_index(dentry, i, NULL); + } else { + if (new_bstart < 0) + new_bstart = i; + new_bend = i; + } + } + + if (new_bstart < 0) + new_bstart = bindex; + if (new_bend < 0) + new_bend = bindex; + set_dbstart(dentry, new_bstart); + set_dbend(dentry, new_bend); + break; + } + + if (hidden_dentry->d_inode) { + /* since this already exists we dput to avoid + * multiple references on the same dentry */ + DPUT(hidden_dentry); + } else { + uid_t saved_uid = current->fsuid; + gid_t saved_gid = current->fsgid; + + /* its a negative dentry, create a new dir */ + hidden_parent_dentry = lock_parent(hidden_dentry); + current->fsuid = hidden_parent_dentry->d_inode->i_uid; + current->fsgid = hidden_parent_dentry->d_inode->i_gid; + err = vfs_mkdir(hidden_parent_dentry->d_inode, + hidden_dentry, S_IRWXUGO); + current->fsuid = saved_uid; + current->fsgid = saved_gid; + if (!err) + err = copyup_permissions + (dir->i_sb, child_dentry, hidden_dentry); + unlock_dir(hidden_parent_dentry); + if (err) { + DPUT(hidden_dentry); + hidden_dentry = ERR_PTR(err); + goto out; + } + if (persistent) { + err = write_uin + (sb, child_dentry->d_inode->i_ino, + bindex, hidden_dentry->d_inode->i_ino); + if (err) { + DPUT(hidden_dentry); + hidden_dentry = ERR_PTR(err); + goto out; + } + } + set_itohi_index(child_dentry->d_inode, bindex, + IGRAB(hidden_dentry->d_inode)); + if (ibstart(child_dentry->d_inode) > bindex) + ibstart(child_dentry->d_inode) = bindex; + if (ibend(child_dentry->d_inode) < bindex) + ibend(child_dentry->d_inode) = bindex; + + set_dtohd_index(child_dentry, bindex, hidden_dentry); + if (dbstart(child_dentry) > bindex) + set_dbstart(child_dentry, bindex); + if (dbend(child_dentry) < bindex) + set_dbend(child_dentry, bindex); + } + + parent_dentry = child_dentry; + child_dentry = path[--count]; + } + out: + KFREE(path); + fist_print_dentry("OUT: create_parents_named", dentry); + print_exit_pointer(hidden_dentry); + return hidden_dentry; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/dentry.c newtree/fs/unionfs/dentry.c --- oldtree/fs/unionfs/dentry.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/dentry.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: dentry.c,v 1.71 2006/01/21 01:33:04 jsipek Exp $ + */ + +#include "unionfs.h" + +/* declarations added for "sparse" */ +extern int unionfs_d_revalidate_wrap(struct dentry *dentry, + struct nameidata *nd); +extern void unionfs_d_release(struct dentry *dentry); +extern void unionfs_d_iput(struct dentry *dentry, struct inode *inode); + +/* + * THIS IS A BOOLEAN FUNCTION: returns 1 if valid, 0 otherwise. + */ +int unionfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + int err = 1; /* default is valid (1); invalid is 0. */ + int invalid = 0; + struct dentry *hidden_dentry; + int bindex, bstart, bend; + int sbgen, dgen; + int positive = 0; + int locked = 0; + int restart = 0; + + print_util_entry_location(); + + restart: + verify_locked(dentry); + + /* if the dentry is unhashed, do NOT revalidate */ + if (d_deleted(dentry)) { + fist_dprint(6, "unhashed dentry being revalidated: %*s\n", + dentry->d_name.len, dentry->d_name.name); + goto out; + } + + BUG_ON(dbstart(dentry) == -1); + if (dentry->d_inode) + positive = 1; + dgen = atomic_read(&dtopd(dentry)->udi_generation); + sbgen = atomic_read(&stopd(dentry->d_sb)->usi_generation); + /* If we are working on an unconnected dentry, then there is no + * revalidation to be done, because this file does not exist within the + * namespace, and Unionfs operates on the namespace, not data. + */ + if (sbgen != dgen) { + struct dentry *result; + int pdgen; + + unionfs_read_lock(dentry->d_sb); + locked = 1; + + /* The root entry should always be valid */ + BUG_ON(IS_ROOT(dentry)); + + /* We can't work correctly if our parent isn't valid. */ + pdgen = atomic_read(&dtopd(dentry->d_parent)->udi_generation); + if (!restart && (pdgen != sbgen)) { + unionfs_read_unlock(dentry->d_sb); + locked = 0; + /* We must be locked before our parent. */ + if (! + (dentry->d_parent->d_op-> + d_revalidate(dentry->d_parent, nd))) { + invalid = 1; + goto out; + } + restart = 1; + goto restart; + } + BUG_ON(pdgen != sbgen); + + /* Free the pointers for our inodes and this dentry. */ + bstart = dbstart(dentry); + bend = dbend(dentry); + if (bstart >= 0) { + struct dentry *hidden_dentry; + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = + dtohd_index_nocheck(dentry, bindex); + if (!hidden_dentry) + continue; + DPUT(hidden_dentry); + } + } + set_dbstart(dentry, -1); + set_dbend(dentry, -1); + + if (positive) { + down(&dentry->d_inode->i_sem); + bstart = ibstart(dentry->d_inode); + bend = ibend(dentry->d_inode); + if (bstart >= 0) { + struct inode *hidden_inode; + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_inode = + itohi_index(dentry->d_inode, + bindex); + if (!hidden_inode) + continue; + IPUT(hidden_inode); + } + } + KFREE(itohi_ptr(dentry->d_inode)); + itohi_ptr(dentry->d_inode) = NULL; + ibstart(dentry->d_inode) = -1; + ibend(dentry->d_inode) = -1; + up(&dentry->d_inode->i_sem); + } + + result = + unionfs_lookup_backend(dentry, + positive ? INTERPOSE_REVAL : + INTERPOSE_REVAL_NEG); + if (!result || IS_ERR(result)) { + err = 0; + goto out; + } + + if (positive && itopd(dentry->d_inode)->uii_stale) { + make_stale_inode(dentry->d_inode); + d_drop(dentry); + err = 0; + goto out; + } + goto out; + } + + /* The revalidation must occur across all branches */ + bstart = dbstart(dentry); + bend = dbend(dentry); + BUG_ON(bstart == -1); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry || !hidden_dentry->d_op + || !hidden_dentry->d_op->d_revalidate) + continue; + + err = hidden_dentry->d_op->d_revalidate(hidden_dentry, nd); + if (!err) + invalid = 1; + } + + if (!dentry->d_inode) + invalid = 1; + if (!invalid && dtohd(dentry) && dtohd(dentry)->d_inode) + fist_copy_attr_all(dentry->d_inode, dtohd(dentry)->d_inode); + + out: + if (locked) + unionfs_read_unlock(dentry->d_sb); + if (invalid) + err = 0; + fist_print_dentry("revalidate out", dentry); + print_util_exit_status(err); + return err; +} + +int unionfs_d_revalidate_wrap(struct dentry *dentry, struct nameidata *nd) +{ + int err; + + print_entry_location(); + lock_dentry(dentry); + + err = unionfs_d_revalidate(dentry, nd); + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +void unionfs_d_release(struct dentry *dentry) +{ + struct dentry *hidden_dentry; + int bindex, bstart, bend; + + print_entry_location(); + /* There is no reason to lock the dentry, because we have the only + * reference, but the printing functions verify that we have a lock + * on the dentry before calling dbstart, etc. */ + lock_dentry(dentry); + __fist_print_dentry("unionfs_d_release IN dentry", dentry, 0); + + /* this could be a negative dentry, so check first */ + if (!dtopd(dentry)) { + fist_dprint(6, "dentry without private data: %*s", + dentry->d_name.len, dentry->d_name.name); + goto out; + } else if (dbstart(dentry) < 0) { + /* this is due to a failed lookup */ + /* the failed lookup has a dtohd_ptr set to null, + but this is a better check */ + fist_dprint(6, "dentry without hidden dentries : %*s", + dentry->d_name.len, dentry->d_name.name); + goto out_free; + } + + /* Release all the hidden dentries */ + bstart = dbstart(dentry); + bend = dbend(dentry); + for (bindex = bstart; bindex <= bend; bindex++) { + if (!dtohd_ptr(dentry) && bindex > UNIONFS_INLINE_OBJECTS) + break; + hidden_dentry = dtohd_index(dentry, bindex); + DPUT(hidden_dentry); + set_dtohd_index(dentry, bindex, NULL); + } + /* free private data (unionfs_dentry_info) here */ + KFREE(dtohd_ptr(dentry)); + dtohd_ptr(dentry) = NULL; + out_free: + /* No need to unlock it, because it is disappeared. */ +#ifdef TRACKLOCK + printk("DESTROYLOCK:%p\n", dentry); +#endif + free_dentry_private_data(dtopd(dentry)); + dtopd_lhs(dentry) = NULL; /* just to be safe */ + out: + print_exit_location(); +} + +/* + * we don't really need unionfs_d_iput, because dentry_iput will call iput() if + * unionfs_d_iput is not defined. We left this implemented for ease of + * tracing/debugging. + */ +void unionfs_d_iput(struct dentry *dentry, struct inode *inode) +{ + print_entry_location(); + IPUT(inode); + print_exit_location(); +} + +struct dentry_operations unionfs_dops = { + .d_revalidate = unionfs_d_revalidate_wrap, + .d_release = unionfs_d_release, + .d_iput = unionfs_d_iput, +}; + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/dirfops.c newtree/fs/unionfs/dirfops.c --- oldtree/fs/unionfs/dirfops.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/dirfops.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: dirfops.c,v 1.20 2006/01/13 03:00:24 jsipek Exp $ + */ + +#include "unionfs.h" + +/* Make sure our rdstate is playing by the rules. */ +static void verify_rdstate_offset(struct unionfs_dir_state *rdstate) +{ + BUG_ON(rdstate->uds_offset >= DIREOF); + BUG_ON(rdstate->uds_cookie >= MAXRDCOOKIE); +} + +struct unionfs_getdents_callback { + struct unionfs_dir_state *rdstate; + void *dirent; + int entries_written; + int filldir_called; + int filldir_error; + filldir_t filldir; + struct super_block *sb; +}; + +/* copied from generic filldir in fs/readir.c */ +static int unionfs_filldir(void *dirent, const char *name, int namelen, + loff_t offset, ino_t ino, unsigned int d_type) +{ + struct unionfs_getdents_callback *buf = + (struct unionfs_getdents_callback *)dirent; + struct filldir_node *found = NULL; + int err = 0; + int is_wh_entry = 0; + + fist_dprint(9, "unionfs_filldir name=%*s\n", namelen, name); + + buf->filldir_called++; + + if ((namelen > WHLEN) && !strncmp(name, WHPFX, WHLEN)) { + name += WHLEN; + namelen -= WHLEN; + is_wh_entry = 1; + } + + found = find_filldir_node(buf->rdstate, name, namelen); + + if (found) + goto out; + + /* if 'name' isn't a whiteout filldir it. */ + if (!is_wh_entry) { + off_t pos = rdstate2offset(buf->rdstate); + ino_t unionfs_ino = ino; + + if (stopd(buf->sb)->usi_persistent) { + unionfs_ino = get_uin(buf->sb, buf->rdstate->uds_bindex, + ino, O_CREAT); + BUG_ON(unionfs_ino <= 0); + } + err = buf->filldir(buf->dirent, name, namelen, pos, + unionfs_ino, d_type); + buf->rdstate->uds_offset++; + verify_rdstate_offset(buf->rdstate); + } + /* If we did fill it, stuff it in our hash, otherwise return an error */ + if (err) { + buf->filldir_error = err; + goto out; + } + buf->entries_written++; + if ((err = add_filldir_node(buf->rdstate, name, namelen, + buf->rdstate->uds_bindex, is_wh_entry))) + buf->filldir_error = err; + + out: + return err; +} + +static int unionfs_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + int err = 0; + struct file *hidden_file = NULL; + struct inode *inode = NULL; + struct unionfs_getdents_callback buf; + struct unionfs_dir_state *uds; + int bend; + loff_t offset; + + print_entry("file = %p, pos = %llx", file, file->f_pos); + + fist_print_file("In unionfs_readdir()", file); + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + inode = file->f_dentry->d_inode; + fist_checkinode(inode, "unionfs_readdir"); + + uds = ftopd(file)->rdstate; + if (!uds) { + if (file->f_pos == DIREOF) { + goto out; + } else if (file->f_pos > 0) { + uds = find_rdstate(inode, file->f_pos); + if (!uds) { + err = -ESTALE; + goto out; + } + ftopd(file)->rdstate = uds; + } else { + init_rdstate(file); + uds = ftopd(file)->rdstate; + } + } + bend = fbend(file); + + while (uds->uds_bindex <= bend) { + hidden_file = ftohf_index(file, uds->uds_bindex); + if (!hidden_file) { + fist_dprint(7, + "Incremented bindex to %d of %d," + " because hidden file is NULL.\n", + uds->uds_bindex, bend); + uds->uds_bindex++; + uds->uds_dirpos = 0; + continue; + } + + /* prepare callback buffer */ + buf.filldir_called = 0; + buf.filldir_error = 0; + buf.entries_written = 0; + buf.dirent = dirent; + buf.filldir = filldir; + buf.rdstate = uds; + buf.sb = inode->i_sb; + + /* Read starting from where we last left off. */ + offset = vfs_llseek(hidden_file, uds->uds_dirpos, 0); + if (offset < 0) { + err = offset; + goto out; + } + fist_dprint(7, "calling readdir for %d.%lld (offset = %lld)\n", + uds->uds_bindex, uds->uds_dirpos, offset); + err = vfs_readdir(hidden_file, unionfs_filldir, (void *)&buf); + fist_dprint(7, + "readdir on %d.%lld = %d (entries written %d, filldir called %d)\n", + uds->uds_bindex, (long long)uds->uds_dirpos, err, + buf.entries_written, buf.filldir_called); + /* Save the position for when we continue. */ + + offset = vfs_llseek(hidden_file, 0, 1); + if (offset < 0) { + err = offset; + goto out; + } + uds->uds_dirpos = offset; + + /* Copy the atime. */ + fist_copy_attr_atime(inode, hidden_file->f_dentry->d_inode); + + if (err < 0) { + goto out; + } + + if (buf.filldir_error) { + break; + } + + if (!buf.entries_written) { + uds->uds_bindex++; + uds->uds_dirpos = 0; + } + } + + if (!buf.filldir_error && uds->uds_bindex >= bend) { + fist_dprint(3, + "Discarding rdstate because readdir is over (hashsize = %d)\n", + uds->uds_hashentries); + /* Save the number of hash entries for next time. */ + itopd(inode)->uii_hashsize = uds->uds_hashentries; + free_rdstate(uds); + ftopd(file)->rdstate = NULL; + file->f_pos = DIREOF; + } else { + file->f_pos = rdstate2offset(uds); + fist_dprint(3, "rdstate now has a cookie of %u (err = %d)\n", + uds->uds_cookie, err); + } + + out: + fist_checkinode(inode, "post unionfs_readdir"); + print_exit_status(err); + return err; +} + +/* This is not meant to be a generic repositioning function. If you do + * things that aren't supported, then we return EINVAL. + * + * What is allowed: + * (1) seeking to the same position that you are currently at + * This really has no effect, but returns where you are. + * (2) seeking to the end of the file, if you've read everything + * This really has no effect, but returns where you are. + * (3) seeking to the beginning of the file + * This throws out all state, and lets you begin again. + */ +static loff_t unionfs_dir_llseek(struct file *file, loff_t offset, int origin) +{ + struct unionfs_dir_state *rdstate; + loff_t err; + + print_entry(" file=%p, offset=0x%llx, origin = %d", file, offset, + origin); + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + rdstate = ftopd(file)->rdstate; + + /* We let users seek to their current position, but not anywhere else. */ + if (!offset) { + switch (origin) { + case SEEK_SET: + if (rdstate) { + free_rdstate(rdstate); + ftopd(file)->rdstate = NULL; + } + init_rdstate(file); + err = 0; + break; + case SEEK_CUR: + if (file->f_pos) { + if (file->f_pos == DIREOF) + err = DIREOF; + else + BUG_ON(file->f_pos != + rdstate2offset(rdstate)); + err = file->f_pos; + } else { + err = 0; + } + break; + case SEEK_END: + /* Unsupported, because we would break everything. */ + err = -EINVAL; + break; + } + } else { + switch (origin) { + case SEEK_SET: + if (rdstate) { + if (offset == rdstate2offset(rdstate)) { + err = offset; + } else if (file->f_pos == DIREOF) { + err = DIREOF; + } else { + err = -EINVAL; + } + } else { + if ((rdstate = + find_rdstate(file->f_dentry->d_inode, + offset))) { + ftopd(file)->rdstate = rdstate; + err = rdstate->uds_offset; + } else { + err = -EINVAL; + } + } + break; + case SEEK_CUR: + case SEEK_END: + /* Unsupported, because we would break everything. */ + err = -EINVAL; + break; + } + } + + out: + print_exit_status((int)err); + return err; +} + +/* Trimmed directory options, we shouldn't pass everything down since + * we don't want to operate on partial directories. + */ +struct file_operations unionfs_dir_fops = { + .llseek = unionfs_dir_llseek, + .read = generic_read_dir, + .readdir = unionfs_readdir, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) + .unlocked_ioctl = unionfs_ioctl, +#endif + .open = unionfs_open, + .release = unionfs_file_release, + .flush = unionfs_flush, +}; + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/dirhelper.c newtree/fs/unionfs/dirhelper.c --- oldtree/fs/unionfs/dirhelper.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/dirhelper.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: dirhelper.c,v 1.26 2006/01/14 19:56:01 dquigley Exp $ + */ + +#include "unionfs.h" + +/* Delete all of the whiteouts in a given directory for rmdir. */ +int delete_whiteouts(struct dentry *dentry, int bindex, + struct unionfs_dir_state *namelist) +{ + int err = 0; + struct dentry *hidden_dir_dentry = NULL; + struct dentry *hidden_dentry; + struct super_block *sb; + char *name = NULL; + + int i; + struct list_head *pos; + struct filldir_node *cursor; + + print_entry_location(); + + sb = dentry->d_sb; + + BUG_ON(!S_ISDIR(dentry->d_inode->i_mode)); + BUG_ON(bindex < dbstart(dentry)); + BUG_ON(bindex > dbend(dentry)); + + /* Find out hidden parent dentry */ + hidden_dir_dentry = dtohd_index(dentry, bindex); + BUG_ON(!S_ISDIR(hidden_dir_dentry->d_inode->i_mode)); + + name = (char *)__get_free_page(GFP_KERNEL); + if (!name) { + err = -ENOMEM; + goto out; + } + + for (i = 0; i < namelist->uds_size; i++) { + list_for_each(pos, &namelist->uds_list[i]) { + cursor = + list_entry(pos, struct filldir_node, file_list); + /* Only operate on whiteouts in this branch. */ + if (cursor->bindex != bindex) + continue; + if (!cursor->whiteout) + continue; + + strcpy(name, WHPFX); + strncpy(name + WHLEN, cursor->name, PAGE_SIZE - 4); + + hidden_dentry = + LOOKUP_ONE_LEN(name, hidden_dir_dentry, + cursor->namelen + WHLEN); + if (IS_ERR(hidden_dentry)) { + err = PTR_ERR(hidden_dentry); + goto out; + } + if (!hidden_dentry->d_inode) { + DPUT(hidden_dentry); + continue; + } + + down(&hidden_dir_dentry->d_inode->i_sem); + err = + vfs_unlink(hidden_dir_dentry->d_inode, + hidden_dentry); + up(&hidden_dir_dentry->d_inode->i_sem); + DPUT(hidden_dentry); + + if (err && !IS_COPYUP_ERR(err)) + goto out; + } + } + + out: + /* After all of the removals, we should copy the attributes once. */ + fist_copy_attr_times(dentry->d_inode, hidden_dir_dentry->d_inode); + dentry->d_inode->i_nlink = get_nlinks(dentry->d_inode); + + if (name) + free_page((unsigned long)name); + print_exit_status(err); + return err; +} + +#define RD_NONE 0 +#define RD_CHECK_EMPTY 1 +/* The callback structure for check_empty. */ +struct unionfs_rdutil_callback { + int err; + int filldir_called; + struct unionfs_dir_state *rdstate; + int mode; +}; + +/* This filldir function makes sure only whiteouts exist within a directory. */ +static int readdir_util_callback(void *dirent, const char *name, int namelen, + loff_t offset, ino_t ino, unsigned int d_type) +{ + int err = 0; + struct unionfs_rdutil_callback *buf = + (struct unionfs_rdutil_callback *)dirent; + int whiteout = 0; + struct filldir_node *found; + + print_entry_location(); + + buf->filldir_called = 1; + + if (name[0] == '.' + && (namelen == 1 || (name[1] == '.' && namelen == 2))) + goto out; + + if ((namelen > WHLEN) && !strncmp(name, WHPFX, WHLEN)) { + namelen -= WHLEN; + name += WHLEN; + whiteout = 1; + } + + found = find_filldir_node(buf->rdstate, name, namelen); + /* If it was found in the table there was a previous whiteout. */ + if (found) + goto out; + + /* If it wasn't found and isn't a whiteout, the directory isn't empty. */ + err = -ENOTEMPTY; + if ((buf->mode == RD_CHECK_EMPTY) && !whiteout) + goto out; + + err = add_filldir_node(buf->rdstate, name, namelen, + buf->rdstate->uds_bindex, whiteout); + + out: + buf->err = err; + print_exit_status(err); + return err; +} + +/* Is a directory logically empty? */ +int check_empty(struct dentry *dentry, struct unionfs_dir_state **namelist) +{ + int err = 0; + struct dentry *hidden_dentry = NULL; + struct super_block *sb; + struct file *hidden_file; + struct unionfs_rdutil_callback *buf = NULL; + int bindex, bstart, bend, bopaque; + + print_entry_location(); + + sb = dentry->d_sb; + + unionfs_read_lock(sb); + + BUG_ON(!S_ISDIR(dentry->d_inode->i_mode)); + + if ((err = unionfs_partial_lookup(dentry))) + goto out; + + bstart = dbstart(dentry); + bend = dbend(dentry); + bopaque = dbopaque(dentry); + if (0 <= bopaque && bopaque < bend) + bend = bopaque; + + buf = KMALLOC(sizeof(struct unionfs_rdutil_callback), GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto out; + } + buf->err = 0; + buf->mode = RD_CHECK_EMPTY; + buf->rdstate = alloc_rdstate(dentry->d_inode, bstart); + if (!buf->rdstate) { + err = -ENOMEM; + goto out; + } + + /* Process the hidden directories with rdutil_callback as a filldir. */ + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + if (!hidden_dentry->d_inode) + continue; + if (!S_ISDIR(hidden_dentry->d_inode->i_mode)) + continue; + + DGET(hidden_dentry); + mntget(stohiddenmnt_index(sb, bindex)); + branchget(sb, bindex); + hidden_file = + DENTRY_OPEN(hidden_dentry, stohiddenmnt_index(sb, bindex), + O_RDONLY); + if (IS_ERR(hidden_file)) { + err = PTR_ERR(hidden_file); + DPUT(hidden_dentry); + branchput(sb, bindex); + goto out; + } + + do { + buf->filldir_called = 0; + buf->rdstate->uds_bindex = bindex; + err = vfs_readdir(hidden_file, + readdir_util_callback, buf); + if (buf->err) + err = buf->err; + } while ((err >= 0) && buf->filldir_called); + + /* fput calls dput for hidden_dentry */ + fput(hidden_file); + branchput(sb, bindex); + + if (err < 0) + goto out; + } + + out: + if (buf) { + if (namelist && !err) + *namelist = buf->rdstate; + else if (buf->rdstate) + free_rdstate(buf->rdstate); + KFREE(buf); + } + + unionfs_read_unlock(sb); + + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/file.c newtree/fs/unionfs/file.c --- oldtree/fs/unionfs/file.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/file.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: file.c,v 1.135 2006/01/13 03:00:24 jsipek Exp $ + */ + +#include "unionfs.h" + +/* declarations for sparse */ +extern ssize_t unionfs_read(struct file *, char __user *, size_t, loff_t *); +extern ssize_t unionfs_write(struct file *, const char __user *, size_t, + loff_t *); + +/******************* + * File Operations * + *******************/ + +static loff_t unionfs_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t err; + struct file *hidden_file = NULL; + + print_entry_location(); + + fist_dprint(6, "unionfs_llseek: file=%p, offset=0x%llx, origin=%d\n", + file, offset, origin); + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + hidden_file = ftohf(file); + /* always set hidden position to this one */ + hidden_file->f_pos = file->f_pos; + + memcpy(&(hidden_file->f_ra), &(file->f_ra), + sizeof(struct file_ra_state)); + + if (hidden_file->f_op && hidden_file->f_op->llseek) + err = hidden_file->f_op->llseek(hidden_file, offset, origin); + else + err = generic_file_llseek(hidden_file, offset, origin); + + if (err < 0) + goto out; + if (err != file->f_pos) { + file->f_pos = err; + // ION maybe this? + // file->f_pos = hidden_file->f_pos; + + file->f_version++; + } + out: + print_exit_status((int)err); + return err; +} + +ssize_t unionfs_read(struct file * file, char __user * buf, size_t count, + loff_t * ppos) +{ + int err = -EINVAL; + struct file *hidden_file = NULL; + loff_t pos = *ppos; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + fist_print_file("entering read()", file); + + hidden_file = ftohf(file); + + if (!hidden_file->f_op || !hidden_file->f_op->read) + goto out; + + err = hidden_file->f_op->read(hidden_file, buf, count, &pos); + *ppos = pos; + if (err >= 0) { + /* atime should also be updated for reads of size zero or more */ + fist_copy_attr_atime(file->f_dentry->d_inode, + hidden_file->f_dentry->d_inode); + } + memcpy(&(file->f_ra), &(hidden_file->f_ra), + sizeof(struct file_ra_state)); + + out: + fist_print_file("leaving read()", file); + print_exit_status(err); + return err; +} + +#if defined(SUPPORT_BROKEN_LOSETUP) +static ssize_t unionfs_sendfile(struct file *file, loff_t * ppos, + size_t count, read_actor_t actor, void *target) +{ + ssize_t err; + struct file *hidden_file = NULL; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + hidden_file = ftohf(file); + + err = -EINVAL; + if (!hidden_file->f_op || !hidden_file->f_op->sendfile) + goto out; + + err = hidden_file->f_op->sendfile(hidden_file, ppos, count, actor, + target); + + out: + print_exit_status(err); + return err; +} +#endif + +/* this unionfs_write() does not modify data pages! */ +ssize_t unionfs_write(struct file * file, const char __user * buf, size_t count, + loff_t * ppos) +{ + int err = -EINVAL; + struct file *hidden_file = NULL; + struct inode *inode; + struct inode *hidden_inode; + loff_t pos = *ppos; + int bstart, bend; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + + inode = file->f_dentry->d_inode; + + bstart = fbstart(file); + bend = fbend(file); + + BUG_ON(bstart == -1); + + hidden_file = ftohf(file); + hidden_inode = hidden_file->f_dentry->d_inode; + + if (!hidden_file->f_op || !hidden_file->f_op->write) + goto out; + + /* adjust for append -- seek to the end of the file */ + if (file->f_flags & O_APPEND) + pos = inode->i_size; + + err = hidden_file->f_op->write(hidden_file, buf, count, &pos); + + /* + * copy ctime and mtime from lower layer attributes + * atime is unchanged for both layers + */ + if (err >= 0) + fist_copy_attr_times(inode, hidden_inode); + + *ppos = pos; + + /* update this inode's size */ + if (pos > inode->i_size) + inode->i_size = pos; + + out: + print_exit_status(err); + return err; +} + +static int unionfs_file_readdir(struct file *file, void *dirent, + filldir_t filldir) +{ + int err = -ENOTDIR; + print_entry_location(); + print_exit_status(err); + return err; +} + +static unsigned int unionfs_poll(struct file *file, poll_table * wait) +{ + unsigned int mask = DEFAULT_POLLMASK; + struct file *hidden_file = NULL; + + print_entry_location(); + + if (unionfs_file_revalidate(file, 0)) { + /* We should pretend an error happend. */ + mask = POLLERR | POLLIN | POLLOUT; + goto out; + } + + hidden_file = ftohf(file); + + if (!hidden_file->f_op || !hidden_file->f_op->poll) + goto out; + + mask = hidden_file->f_op->poll(hidden_file, wait); + + out: + print_exit_status(mask); + return mask; +} + +/* FIST-LITE special version of mmap */ +static int unionfs_mmap(struct file *file, struct vm_area_struct *vma) +{ + int err = 0; + struct file *hidden_file = NULL; + int willwrite; + + print_entry_location(); + + /* This might could be deferred to mmap's writepage. */ + willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags); + if ((err = unionfs_file_revalidate(file, willwrite))) + goto out; + + hidden_file = ftohf(file); + + err = -ENODEV; + if (!hidden_file->f_op || !hidden_file->f_op->mmap) + goto out; + + vma->vm_file = hidden_file; + err = hidden_file->f_op->mmap(hidden_file, vma); + get_file(hidden_file); /* make sure it doesn't get freed on us */ + fput(file); /* no need to keep extra ref on ours */ + + out: + print_exit_status(err); + return err; +} + +static int unionfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + int err; + struct file *hidden_file = NULL; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + + hidden_file = ftohf(file); + + err = -EINVAL; + if (!hidden_file->f_op || !hidden_file->f_op->fsync) + goto out; + + down(&hidden_file->f_dentry->d_inode->i_sem); + err = hidden_file->f_op->fsync(hidden_file, hidden_file->f_dentry, + datasync); + up(&hidden_file->f_dentry->d_inode->i_sem); + + out: + print_exit_status(err); + return err; +} + +static int unionfs_fasync(int fd, struct file *file, int flag) +{ + int err = 0; + struct file *hidden_file = NULL; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + + hidden_file = ftohf(file); + + if (hidden_file->f_op && hidden_file->f_op->fasync) + err = hidden_file->f_op->fasync(fd, hidden_file, flag); + + out: + print_exit_status(err); + return err; +} + +struct file_operations unionfs_main_fops = { + .llseek = unionfs_llseek, + .read = unionfs_read, + .write = unionfs_write, + .readdir = unionfs_file_readdir, + .poll = unionfs_poll, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) + .unlocked_ioctl = unionfs_ioctl, +#endif + .mmap = unionfs_mmap, + .open = unionfs_open, + .flush = unionfs_flush, + .release = unionfs_file_release, + .fsync = unionfs_fsync, + .fasync = unionfs_fasync, +#if defined(SUPPORT_BROKEN_LOSETUP) + .sendfile = unionfs_sendfile, +#endif +}; + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/inode.c newtree/fs/unionfs/inode.c --- oldtree/fs/unionfs/inode.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/inode.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,1029 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: inode.c,v 1.260 2006/01/21 02:58:11 jsipek Exp $ + */ + +#include "unionfs.h" + +/* declarations added for "sparse" */ +extern struct dentry *unionfs_lookup(struct inode *, struct dentry *, + struct nameidata *); +extern int unionfs_readlink(struct dentry *dentry, char __user * buf, + int bufsiz); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) +extern void unionfs_put_link(struct dentry *dentry, struct nameidata *nd); +#else +extern void unionfs_put_link(struct dentry *dentry, struct nameidata *nd, + void *cookie); +#endif + +static int unionfs_create(struct inode *parent, struct dentry *dentry, + int mode, struct nameidata *nd) +{ + int err = 0; + struct dentry *hidden_dentry = NULL; + struct dentry *whiteout_dentry = NULL; + struct dentry *new_hidden_dentry; + struct dentry *hidden_parent_dentry = NULL; + int bindex = 0, bstart; + char *name = NULL; + + print_entry_location(); + lock_dentry(dentry); + fist_print_dentry("IN unionfs_create", dentry); + + /* We start out in the leftmost branch. */ + bstart = dbstart(dentry); + hidden_dentry = dtohd(dentry); + + /* check if whiteout exists in this branch, i.e. lookup .wh.foo first */ + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + whiteout_dentry = + LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + whiteout_dentry = NULL; + goto out; + } + + if (whiteout_dentry->d_inode) { + /* .wh.foo has been found. */ + /* First truncate it and then rename it to foo (hence having + * the same overall effect as a normal create. + * + * XXX: This is not strictly correct. If we have unlinked the + * file and it still has a reference count, then we should + * actually unlink the whiteout so that user's data isn't + * hosed over. + */ + struct dentry *hidden_dir_dentry; + struct iattr newattrs; + + down(&whiteout_dentry->d_inode->i_sem); + newattrs.ia_valid = ATTR_CTIME | ATTR_MODE; + newattrs.ia_mode = mode; + if (whiteout_dentry->d_inode->i_size != 0) { + newattrs.ia_valid |= ATTR_SIZE; + newattrs.ia_size = 0; + } + err = notify_change(whiteout_dentry, &newattrs); + up(&whiteout_dentry->d_inode->i_sem); + + new_hidden_dentry = dtohd(dentry); + DGET(new_hidden_dentry); + + hidden_dir_dentry = GET_PARENT(whiteout_dentry); + lock_rename(hidden_dir_dentry, hidden_dir_dentry); + + if (!(err = is_robranch_super(dentry->d_sb, bstart))) { + err = + vfs_rename(hidden_dir_dentry->d_inode, + whiteout_dentry, + hidden_dir_dentry->d_inode, + new_hidden_dentry); + } + if (!err) { + fist_copy_attr_timesizes(parent, + new_hidden_dentry->d_parent-> + d_inode); + parent->i_nlink = get_nlinks(parent); + } + + unlock_rename(hidden_dir_dentry, hidden_dir_dentry); + DPUT(hidden_dir_dentry); + + DPUT(new_hidden_dentry); + + if (err) { + /* exit if the error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + goto out; + /* We were not able to create the file in this branch, + * so, we try to create it in one branch to left + */ + bstart--; + } else { + /* reset the unionfs dentry to point to the .wh.foo entry. */ + + /* Discard any old reference. */ + DPUT(dtohd(dentry)); + + /* Trade one reference to another. */ + set_dtohd_index(dentry, bstart, whiteout_dentry); + whiteout_dentry = NULL; + + err = unionfs_interpose(dentry, parent->i_sb, 0); + goto out; + } + } + + for (bindex = bstart; bindex >= 0; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + /* if hidden_dentry is NULL, create the entire + * dentry directory structure in branch 'bindex'. + * hidden_dentry will NOT be null when bindex == bstart + * because lookup passed as a negative unionfs dentry + * pointing to a lone negative underlying dentry */ + hidden_dentry = create_parents(parent, dentry, bindex); + if (!hidden_dentry || IS_ERR(hidden_dentry)) { + if (IS_ERR(hidden_dentry)) + err = PTR_ERR(hidden_dentry); + continue; + } + } + + fist_checkinode(parent, "unionfs_create"); + + hidden_parent_dentry = lock_parent(hidden_dentry); + if (IS_ERR(hidden_parent_dentry)) { + err = PTR_ERR(hidden_parent_dentry); + goto out; + } + /* We shouldn't create things in a read-only branch. */ + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + //DQ: vfs_create has a different prototype in 2.6 + err = vfs_create(hidden_parent_dentry->d_inode, + hidden_dentry, mode, nd); + } + if (err || !hidden_dentry->d_inode) { + unlock_dir(hidden_parent_dentry); + + /* break out of for loop if the error wasn't -EROFS */ + if (!IS_COPYUP_ERR(err)) + break; + } else { + err = unionfs_interpose(dentry, parent->i_sb, 0); + if (!err) { + fist_copy_attr_timesizes(parent, + hidden_parent_dentry-> + d_inode); + /* update number of links on parent directory */ + parent->i_nlink = get_nlinks(parent); + } + unlock_dir(hidden_parent_dentry); + break; + } + } + + out: + DPUT(whiteout_dentry); + KFREE(name); + + fist_print_dentry("OUT unionfs_create :", dentry); + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +struct dentry *unionfs_lookup(struct inode *parent, struct dentry *dentry, + struct nameidata *nd) +{ + /* The locking is done by unionfs_lookup_backend. */ + return unionfs_lookup_backend(dentry, INTERPOSE_LOOKUP); +} + +static int unionfs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry) +{ + int err = 0; + struct dentry *hidden_old_dentry = NULL; + struct dentry *hidden_new_dentry = NULL; + struct dentry *hidden_dir_dentry = NULL; + struct dentry *whiteout_dentry; + char *name = NULL; + + print_entry_location(); + double_lock_dentry(new_dentry, old_dentry); + + hidden_new_dentry = dtohd(new_dentry); + + /* check if whiteout exists in the branch of new dentry, i.e. lookup + * .wh.foo first. If present, delete it */ + name = alloc_whname(new_dentry->d_name.name, new_dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + whiteout_dentry = + LOOKUP_ONE_LEN(name, hidden_new_dentry->d_parent, + new_dentry->d_name.len + WHLEN); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + goto out; + } + + if (!whiteout_dentry->d_inode) { + DPUT(whiteout_dentry); + whiteout_dentry = NULL; + } else { + /* found a .wh.foo entry, unlink it and then call vfs_link() */ + hidden_dir_dentry = lock_parent(whiteout_dentry); + if (! + (err = + is_robranch_super(new_dentry->d_sb, + dbstart(new_dentry)))) { + err = + vfs_unlink(hidden_dir_dentry->d_inode, + whiteout_dentry); + } + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + dir->i_nlink = get_nlinks(dir); + unlock_dir(hidden_dir_dentry); + hidden_dir_dentry = NULL; + DPUT(whiteout_dentry); + if (err) + goto out; + } + + if (dbstart(old_dentry) != dbstart(new_dentry)) { + hidden_new_dentry = + create_parents(dir, new_dentry, dbstart(old_dentry)); + err = PTR_ERR(hidden_new_dentry); + if (IS_COPYUP_ERR(err)) + goto docopyup; + if (!hidden_new_dentry || IS_ERR(hidden_new_dentry)) + goto out; + } + hidden_new_dentry = dtohd(new_dentry); + hidden_old_dentry = dtohd(old_dentry); + + BUG_ON(dbstart(old_dentry) != dbstart(new_dentry)); + hidden_dir_dentry = lock_parent(hidden_new_dentry); + if (!(err = is_robranch(old_dentry))) + err = + vfs_link(hidden_old_dentry, hidden_dir_dentry->d_inode, + hidden_new_dentry); + unlock_dir(hidden_dir_dentry); + + docopyup: + if (IS_COPYUP_ERR(err)) { + int old_bstart = dbstart(old_dentry); + int bindex; + + for (bindex = old_bstart - 1; bindex >= 0; bindex--) { + err = + copyup_dentry(old_dentry->d_parent-> + d_inode, old_dentry, + old_bstart, bindex, NULL, + old_dentry->d_inode->i_size); + if (!err) { + hidden_new_dentry = + create_parents(dir, new_dentry, bindex); + hidden_old_dentry = dtohd(old_dentry); + hidden_dir_dentry = + lock_parent(hidden_new_dentry); + /* do vfs_link */ + err = + vfs_link(hidden_old_dentry, + hidden_dir_dentry->d_inode, + hidden_new_dentry); + unlock_dir(hidden_dir_dentry); + goto check_link; + } + } + goto out; + } + check_link: + if (err || !hidden_new_dentry->d_inode) + goto out; + + /* Its a hard link, so use the same inode */ + new_dentry->d_inode = IGRAB(old_dentry->d_inode); + d_instantiate(new_dentry, new_dentry->d_inode); + fist_copy_attr_all(dir, hidden_new_dentry->d_parent->d_inode); + /* propagate number of hard-links */ + old_dentry->d_inode->i_nlink = get_nlinks(old_dentry->d_inode); + + out: + if (!new_dentry->d_inode) + d_drop(new_dentry); + + KFREE(name); + + unlock_dentry(new_dentry); + unlock_dentry(old_dentry); + + print_exit_status(err); + return err; +} + +static int unionfs_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) +{ + int err = 0; + struct dentry *hidden_dentry = NULL; + struct dentry *whiteout_dentry = NULL; + struct dentry *hidden_dir_dentry = NULL; + umode_t mode; + int bindex = 0, bstart; + char *name = NULL; + + print_entry_location(); + lock_dentry(dentry); + fist_print_dentry("IN unionfs_symlink", dentry); + + /* We start out in the leftmost branch. */ + bstart = dbstart(dentry); + + hidden_dentry = dtohd(dentry); + + /* check if whiteout exists in this branch, i.e. lookup .wh.foo first. If present, delete it */ + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + whiteout_dentry = + LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + goto out; + } + + if (!whiteout_dentry->d_inode) { + DPUT(whiteout_dentry); + whiteout_dentry = NULL; + } else { + /* found a .wh.foo entry, unlink it and then call vfs_symlink() */ + hidden_dir_dentry = lock_parent(whiteout_dentry); + + fist_print_generic_dentry("HDD", hidden_dir_dentry); + fist_print_generic_dentry("WD", whiteout_dentry); + + if (!(err = is_robranch_super(dentry->d_sb, bstart))) { + err = + vfs_unlink(hidden_dir_dentry->d_inode, + whiteout_dentry); + } + DPUT(whiteout_dentry); + + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + /* propagate number of hard-links */ + dir->i_nlink = get_nlinks(dir); + + unlock_dir(hidden_dir_dentry); + + if (err) { + /* exit if the error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + goto out; + /* should now try to create symlink in the another branch */ + bstart--; + } + } + + /* deleted whiteout if it was present, now do a normal vfs_symlink() with + possible recursive directory creation */ + for (bindex = bstart; bindex >= 0; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + /* if hidden_dentry is NULL, create the entire + * dentry directory structure in branch 'bindex'. hidden_dentry will NOT be null when + * bindex == bstart because lookup passed as a negative unionfs dentry pointing to a + * lone negative underlying dentry */ + hidden_dentry = create_parents(dir, dentry, bindex); + if (!hidden_dentry || IS_ERR(hidden_dentry)) { + if (IS_ERR(hidden_dentry)) { + err = PTR_ERR(hidden_dentry); + } + fist_dprint(8, + "hidden dentry NULL (or error) for bindex = %d\n", + bindex); + continue; + } + } + + hidden_dir_dentry = lock_parent(hidden_dentry); + + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + mode = S_IALLUGO; + err = + vfs_symlink(hidden_dir_dentry->d_inode, + hidden_dentry, symname, mode); + } + unlock_dir(hidden_dir_dentry); + + if (err || !hidden_dentry->d_inode) { + /* break out of for loop if error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + break; + } else { + err = unionfs_interpose(dentry, dir->i_sb, 0); + if (!err) { + fist_copy_attr_timesizes(dir, + hidden_dir_dentry-> + d_inode); + /* update number of links on parent directory */ + dir->i_nlink = get_nlinks(dir); + } + break; + } + } + + out: + if (!dentry->d_inode) + d_drop(dentry); + + KFREE(name); + fist_print_dentry("OUT unionfs_symlink :", dentry); + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +static int unionfs_mkdir(struct inode *parent, struct dentry *dentry, int mode) +{ + int err = 0; + struct dentry *hidden_dentry = NULL, *whiteout_dentry = NULL; + struct dentry *hidden_parent_dentry = NULL; + int bindex = 0, bstart; + char *name = NULL; + int whiteout_unlinked = 0; + uid_t saved_uid = current->fsuid; + gid_t saved_gid = current->fsgid; + + print_entry_location(); + lock_dentry(dentry); + fist_print_dentry("IN unionfs_mkdir", dentry); + bstart = dbstart(dentry); + + hidden_dentry = dtohd(dentry); + + // check if whiteout exists in this branch, i.e. lookup .wh.foo first + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + whiteout_dentry = + LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + goto out; + } + + if (!whiteout_dentry->d_inode) { + DPUT(whiteout_dentry); + whiteout_dentry = NULL; + } else { + hidden_parent_dentry = lock_parent(whiteout_dentry); + + /* Set the uid and gid to trick the fs into allowing us to create + * the file */ + current->fsuid = hidden_parent_dentry->d_inode->i_uid; + current->fsgid = hidden_parent_dentry->d_inode->i_gid; + //found a.wh.foo entry, remove it then do vfs_mkdir + if (!(err = is_robranch_super(dentry->d_sb, bstart))) { + err = + vfs_unlink(hidden_parent_dentry->d_inode, + whiteout_dentry); + } + DPUT(whiteout_dentry); + + current->fsuid = saved_uid; + current->fsgid = saved_gid; + + unlock_dir(hidden_parent_dentry); + + if (err) { + /* exit if the error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + goto out; + bstart--; + } else { + whiteout_unlinked = 1; + } + } + + for (bindex = bstart; bindex >= 0; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + hidden_dentry = create_parents(parent, dentry, bindex); + if (!hidden_dentry || IS_ERR(hidden_dentry)) { + fist_dprint(8, + "hidden dentry NULL for bindex = %d\n", + bindex); + continue; + } + } + + hidden_parent_dentry = lock_parent(hidden_dentry); + if (IS_ERR(hidden_parent_dentry)) { + err = PTR_ERR(hidden_parent_dentry); + goto out; + } + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + err = + vfs_mkdir(hidden_parent_dentry->d_inode, + hidden_dentry, mode); + } + unlock_dir(hidden_parent_dentry); + + /* XXX this could potentially return a negative hidden_dentry! */ + if (err || !hidden_dentry->d_inode) { + /* break out of for loop if error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + break; + } else { + int i; + int bend = dbend(dentry); + for (i = bindex + 1; i < bend; i++) { + if (dtohd_index(dentry, i)) { + DPUT(dtohd_index(dentry, i)); + set_dtohd_index(dentry, i, NULL); + } + } + bend = bindex; + set_dbend(dentry, bend); + + err = unionfs_interpose(dentry, parent->i_sb, 0); + if (!err) { + fist_copy_attr_timesizes(parent, + hidden_parent_dentry-> + d_inode); + /* update number of links on parent directory */ + parent->i_nlink = get_nlinks(parent); + } + whiteout_dentry = LOOKUP_ONE_LEN(UNIONFS_DIR_OPAQUE, + hidden_dentry, + sizeof + (UNIONFS_DIR_OPAQUE) - + 1); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + goto out; + } + down(&hidden_dentry->d_inode->i_sem); + err = vfs_create(hidden_dentry->d_inode, + whiteout_dentry, 0600, NULL); + up(&hidden_dentry->d_inode->i_sem); + DPUT(whiteout_dentry); + + if (err) { + fist_dprint(8, + "mkdir: error creating directory override entry: %d\n", + err); + goto out; + } + break; + } + } + + out: + if (!dentry->d_inode) + d_drop(dentry); + + KFREE(name); + + fist_print_dentry("OUT unionfs_mkdir :", dentry); + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +static int unionfs_mknod(struct inode *dir, struct dentry *dentry, int mode, + dev_t dev) +{ + int err = 0; + struct dentry *hidden_dentry = NULL, *whiteout_dentry = NULL; + struct dentry *hidden_parent_dentry = NULL; + int bindex = 0, bstart; + char *name = NULL; + int whiteout_unlinked = 0; + + print_entry_location(); + lock_dentry(dentry); + fist_print_dentry("IN unionfs_mknod", dentry); + bstart = dbstart(dentry); + + hidden_dentry = dtohd(dentry); + + // check if whiteout exists in this branch, i.e. lookup .wh.foo first + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + whiteout_dentry = + LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + goto out; + } + + if (!whiteout_dentry->d_inode) { + DPUT(whiteout_dentry); + whiteout_dentry = NULL; + } else { + /* found .wh.foo, unlink it */ + hidden_parent_dentry = lock_parent(whiteout_dentry); + + //found a.wh.foo entry, remove it then do vfs_mkdir + if (!(err = is_robranch_super(dentry->d_sb, bstart))) + err = vfs_unlink(hidden_parent_dentry->d_inode, + whiteout_dentry); + DPUT(whiteout_dentry); + + unlock_dir(hidden_parent_dentry); + + if (err) { + if (!IS_COPYUP_ERR(err)) + goto out; + + bstart--; + } else { + whiteout_unlinked = 1; + } + } + + for (bindex = bstart; bindex >= 0; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + hidden_dentry = create_parents(dir, dentry, bindex); + if (!hidden_dentry || IS_ERR(hidden_dentry)) { + fist_dprint(8, + "hidden dentry NULL for bindex = %d\n", + bindex); + continue; + } + } + + hidden_parent_dentry = lock_parent(hidden_dentry); + if (IS_ERR(hidden_parent_dentry)) { + err = PTR_ERR(hidden_parent_dentry); + goto out; + } + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + err = vfs_mknod(hidden_parent_dentry->d_inode, + hidden_dentry, mode, dev); + } + /* XXX this could potentially return a negative hidden_dentry! */ + if (err || !hidden_dentry->d_inode) { + unlock_dir(hidden_parent_dentry); + /* break out of for, if error was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + break; + } else { + err = unionfs_interpose(dentry, dir->i_sb, 0); + if (!err) { + fist_copy_attr_timesizes(dir, + hidden_parent_dentry-> + d_inode); + /* update number of links on parent directory */ + dir->i_nlink = get_nlinks(dir); + } + unlock_dir(hidden_parent_dentry); + + break; + } + } + + out: + if (!dentry->d_inode) + d_drop(dentry); + + if (name) { + KFREE(name); + } + + fist_print_dentry("OUT unionfs_mknod :", dentry); + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +int unionfs_readlink(struct dentry *dentry, char __user * buf, int bufsiz) +{ + int err; + struct dentry *hidden_dentry; + + print_entry_location(); + lock_dentry(dentry); + hidden_dentry = dtohd(dentry); + fist_print_dentry("unionfs_readlink IN", dentry); + + if (!hidden_dentry->d_inode->i_op || + !hidden_dentry->d_inode->i_op->readlink) { + err = -EINVAL; + goto out; + } + + err = hidden_dentry->d_inode->i_op->readlink(hidden_dentry, + buf, bufsiz); + if (err > 0) + fist_copy_attr_atime(dentry->d_inode, hidden_dentry->d_inode); + + out: + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* We don't lock the dentry here, because readlink does the heavy lifting. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) +static int unionfs_follow_link(struct dentry *dentry, struct nameidata *nd) +#else +static void *unionfs_follow_link(struct dentry *dentry, struct nameidata *nd) +#endif +{ + char *buf; + int len = PAGE_SIZE, err; + mm_segment_t old_fs; + + print_entry_location(); + + /* This is freed by the put_link method assuming a successful call. */ + buf = (char *)KMALLOC(len, GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto out; + } + + /* read the symlink, and then we will follow it */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len); + set_fs(old_fs); + if (err < 0) { + KFREE(buf); + buf = NULL; + goto out; + } + buf[err] = 0; + nd_set_link(nd, buf); + err = 0; + + out: + print_exit_status(err); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) + return err; +#else + return ERR_PTR(err); +#endif +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) +void unionfs_put_link(struct dentry *dentry, struct nameidata *nd) +#else +void unionfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) +#endif +{ + char *link; + print_entry_location(); + link = nd_get_link(nd); + KFREE(link); + print_exit_location(); +} + +/* Basically copied from the kernel vfs permission(), but we've changed + * the following: (1) the IS_RDONLY check is skipped, and (2) if you set + * the mount option `nfsperms=insceure', we assume that -EACCES means that + * the export is read-only and we should check standard Unix permissions. + * This means that NFS ACL checks (or other advanced permission features) + * are bypassed. + */ +static int inode_permission(struct inode *inode, int mask, struct nameidata *nd, + int bindex) +{ + int retval, submask; + + if (mask & MAY_WRITE) { + /* The first branch is allowed to be really readonly. */ + if (bindex == 0) { + umode_t mode = inode->i_mode; + if (IS_RDONLY(inode) && (S_ISREG(mode) || S_ISDIR(mode) + || S_ISLNK(mode))) + return -EROFS; + } + /* + * Nobody gets write access to an immutable file. + */ + if (IS_IMMUTABLE(inode)) + return -EACCES; + } + + /* Ordinary permission routines do not understand MAY_APPEND. */ + submask = mask & ~MAY_APPEND; + if (inode->i_op && inode->i_op->permission) { + retval = inode->i_op->permission(inode, submask, nd); + if ((retval == -EACCES) && (submask & MAY_WRITE) && + (!strcmp("nfs", (inode)->i_sb->s_type->name)) && + (branchperms(nd->mnt->mnt_sb, bindex) & MAY_NFSRO)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + retval = vfs_permission(inode, submask); +#else + retval = generic_permission(inode, submask, NULL); +#endif + } + } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + retval = vfs_permission(inode, submask); +#else + retval = generic_permission(inode, submask, NULL); +#endif + } + if (retval) + return retval; + + return security_inode_permission(inode, mask, nd); +} + +static int unionfs_permission(struct inode *inode, int mask, + struct nameidata *nd) +{ + struct inode *hidden_inode = NULL; + int err = 0; + int bindex, bstart, bend; + int is_file = 0; + + print_entry_location(); + + bstart = ibstart(inode); + bend = ibend(inode); + + fist_print_inode("IN unionfs_permission", inode); + + /* set if check is for file */ + if (!S_ISDIR(inode->i_mode)) + is_file = 1; + + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_inode = itohi_index(inode, bindex); + if (!hidden_inode) + continue; + + /* check the condition for D-F-D underlying files/directories, + * we dont have to check for files, if we are checking for + * directories. + */ + if (!S_ISDIR(hidden_inode->i_mode) && (!is_file)) + continue; + /* We use our own special version of permission, such that + * only the first branch returns -EROFS. */ + err = inode_permission(hidden_inode, mask, nd, bindex); + /* The permissions are an intersection of the overall directory + * permissions, so we fail if one fails. */ + if (err) + goto out; + /* only the leftmost file matters. */ + if (is_file) { + if (mask & MAY_WRITE) { + err = get_write_access(hidden_inode); + if (err) + goto out; + put_write_access(hidden_inode); + } + break; + } + } + + out: + print_exit_status(err); + return err; +} + +static int unionfs_setattr(struct dentry *dentry, struct iattr *ia) +{ + int err = 0; + struct dentry *hidden_dentry; + struct inode *inode = NULL; + struct inode *hidden_inode = NULL; + int bstart, bend, bindex; + int i; + int copyup = 0; + + print_entry_location(); + lock_dentry(dentry); + bstart = dbstart(dentry); + bend = dbend(dentry); + inode = dentry->d_inode; + + for (bindex = bstart; (bindex <= bend) || (bindex == bstart); bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + BUG_ON(hidden_dentry->d_inode == NULL); + + /* If the file is on a read only branch */ + if (is_robranch_super(dentry->d_sb, bindex) + || IS_RDONLY(hidden_dentry->d_inode)) { + if (copyup || (bindex != bstart)) + continue; + /* Only if its the leftmost file, copyup the file */ + for (i = bstart - 1; i >= 0; i--) { + size_t size = dentry->d_inode->i_size; + if (ia->ia_valid & ATTR_SIZE) + size = ia->ia_size; + err = copyup_dentry(dentry->d_parent->d_inode, + dentry, bstart, i, NULL, + size); + + if (!err) { + copyup = 1; + hidden_dentry = dtohd(dentry); + break; + } + /* if error is in the leftmost f/s, pass it up */ + if (i == 0) + goto out; + } + + } + err = notify_change(hidden_dentry, ia); + if (err) + goto out; + break; + } + + /* get the size from the first hidden inode */ + hidden_inode = itohi(dentry->d_inode); + fist_checkinode(inode, "unionfs_setattr"); + fist_copy_attr_all(inode, hidden_inode); + + out: + unlock_dentry(dentry); + fist_checkinode(inode, "post unionfs_setattr"); + print_exit_status(err); + return err; +} + +struct inode_operations unionfs_symlink_iops = { + .readlink = unionfs_readlink, + .permission = unionfs_permission, + .follow_link = unionfs_follow_link, + .setattr = unionfs_setattr, + .put_link = unionfs_put_link, +}; + +struct inode_operations unionfs_dir_iops = { + .create = unionfs_create, + .lookup = unionfs_lookup, + .link = unionfs_link, + .unlink = unionfs_unlink, + .symlink = unionfs_symlink, + .mkdir = unionfs_mkdir, + .rmdir = unionfs_rmdir, + .mknod = unionfs_mknod, + .rename = unionfs_rename, + .permission = unionfs_permission, + .setattr = unionfs_setattr, + .setxattr = unionfs_setxattr, + .getxattr = unionfs_getxattr, + .removexattr = unionfs_removexattr, + .listxattr = unionfs_listxattr, +}; + +struct inode_operations unionfs_main_iops = { + .permission = unionfs_permission, + .setattr = unionfs_setattr, + .setxattr = unionfs_setxattr, + .getxattr = unionfs_getxattr, + .removexattr = unionfs_removexattr, + .listxattr = unionfs_listxattr, +}; + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/lookup.c newtree/fs/unionfs/lookup.c --- oldtree/fs/unionfs/lookup.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/lookup.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: lookup.c,v 1.41 2006/01/13 03:00:24 jsipek Exp $ + */ + +#include "unionfs.h" + +static int is_opaque_dir(struct dentry *dentry, int bindex); +static int is_validname(const char *name); + +struct dentry *unionfs_lookup_backend(struct dentry *dentry, int lookupmode) +{ + int err = 0; + struct dentry *hidden_dentry = NULL; + struct dentry *wh_hidden_dentry = NULL; + struct dentry *hidden_dir_dentry = NULL; + struct dentry *parent_dentry = NULL; + int bindex, bstart, bend, bopaque; + int dentry_count = 0; /* Number of positive dentries. */ + int first_dentry_offset = -1; + struct dentry *first_hidden_dentry = NULL; + int locked_parent = 0; + int locked_child = 0; + + int opaque; + char *whname = NULL; + const char *name; + int namelen; + + print_entry("mode = %d", lookupmode); + + /* We should already have a lock on this dentry in the case of a + * partial lookup, or a revalidation. Otherwise it is returned from + * new_dentry_private_data already locked. */ + if (lookupmode == INTERPOSE_PARTIAL || lookupmode == INTERPOSE_REVAL + || lookupmode == INTERPOSE_REVAL_NEG) { + verify_locked(dentry); + } else { + BUG_ON(dtopd_nocheck(dentry) != NULL); + locked_child = 1; + } + if (lookupmode != INTERPOSE_PARTIAL) + if ((err = new_dentry_private_data(dentry))) + goto out; + /* must initialize dentry operations */ + dentry->d_op = &unionfs_dops; + + parent_dentry = GET_PARENT(dentry); + /* We never partial lookup the root directory. */ + if (parent_dentry != dentry) { + lock_dentry(parent_dentry); + locked_parent = 1; + } else { + DPUT(parent_dentry); + parent_dentry = NULL; + goto out; + } + + fist_print_dentry("IN unionfs_lookup (parent)", parent_dentry); + fist_print_dentry("IN unionfs_lookup (child)", dentry); + + name = dentry->d_name.name; + namelen = dentry->d_name.len; + + /* No dentries should get created for possible whiteout names. */ + if (!is_validname(name)) { + err = -EPERM; + goto out_free; + } + + /* Now start the actual lookup procedure. */ + bstart = dbstart(parent_dentry); + bend = dbend(parent_dentry); + bopaque = dbopaque(parent_dentry); + BUG_ON(bstart < 0); + + /* It would be ideal if we could convert partial lookups to only have + * to do this work when they really need to. It could probably improve + * performance quite a bit, and maybe simplify the rest of the code. */ + if (lookupmode == INTERPOSE_PARTIAL) { + bstart++; + if ((bopaque != -1) && (bopaque < bend)) + bend = bopaque; + } + + fist_dprint(8, "bstart = %d, bend = %d\n", bstart, bend); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (lookupmode == INTERPOSE_PARTIAL && hidden_dentry) + continue; + BUG_ON(hidden_dentry != NULL); + + hidden_dir_dentry = dtohd_index(parent_dentry, bindex); + + /* if the parent hidden dentry does not exist skip this */ + if (!(hidden_dir_dentry && hidden_dir_dentry->d_inode)) + continue; + + /* also skip it if the parent isn't a directory. */ + if (!S_ISDIR(hidden_dir_dentry->d_inode->i_mode)) + continue; + + /* Reuse the whiteout name because its value doesn't change. */ + if (!whname) { + whname = alloc_whname(name, namelen); + if (IS_ERR(whname)) { + err = PTR_ERR(whname); + goto out_free; + } + } + + /* check if whiteout exists in this branch: lookup .wh.foo */ + wh_hidden_dentry = LOOKUP_ONE_LEN(whname, hidden_dir_dentry, + namelen + WHLEN); + if (IS_ERR(wh_hidden_dentry)) { + DPUT(first_hidden_dentry); + err = PTR_ERR(wh_hidden_dentry); + goto out_free; + } + + if (wh_hidden_dentry->d_inode) { + /* We found a whiteout so lets give up. */ + fist_dprint(8, "whiteout found in %d\n", bindex); + if (S_ISREG(wh_hidden_dentry->d_inode->i_mode)) { + set_dbend(dentry, bindex); + set_dbopaque(dentry, bindex); + DPUT(wh_hidden_dentry); + break; + } + err = -EIO; + printk(KERN_NOTICE "EIO: Invalid whiteout entry type" + " %d.\n", wh_hidden_dentry->d_inode->i_mode); + DPUT(wh_hidden_dentry); + DPUT(first_hidden_dentry); + goto out_free; + } + + DPUT(wh_hidden_dentry); + wh_hidden_dentry = NULL; + + /* Now do regular lookup; lookup foo */ + hidden_dentry = LOOKUP_ONE_LEN(name, hidden_dir_dentry, + namelen); + fist_print_generic_dentry("hidden result", hidden_dentry); + if (IS_ERR(hidden_dentry)) { + DPUT(first_hidden_dentry); + err = PTR_ERR(hidden_dentry); + goto out_free; + } + + /* Store the first negative dentry specially, because if they + * are all negative we need this for future creates. */ + if (!hidden_dentry->d_inode) { + if (!first_hidden_dentry && (dbstart(dentry) == -1)) { + first_hidden_dentry = hidden_dentry; + first_dentry_offset = bindex; + } else { + DPUT(hidden_dentry); + } + continue; + } + + /* number of positive dentries */ + dentry_count++; + + /* store underlying dentry */ + if (dbstart(dentry) == -1) + set_dbstart(dentry, bindex); + set_dtohd_index(dentry, bindex, hidden_dentry); + set_dbend(dentry, bindex); + + /* update parent directory's atime with the bindex */ + fist_copy_attr_atime(parent_dentry->d_inode, + hidden_dir_dentry->d_inode); + + /* We terminate file lookups here. */ + if (!S_ISDIR(hidden_dentry->d_inode->i_mode)) { + if (lookupmode == INTERPOSE_PARTIAL) + continue; + if (dentry_count == 1) + goto out_positive; + /* This can only happen with mixed D-*-F-* */ + BUG_ON(!S_ISDIR(dtohd(dentry)->d_inode->i_mode)); + continue; + } + + opaque = is_opaque_dir(dentry, bindex); + if (opaque < 0) { + DPUT(first_hidden_dentry); + err = opaque; + goto out_free; + } + if (opaque) { + set_dbend(dentry, bindex); + set_dbopaque(dentry, bindex); + break; + } + } + + if (dentry_count) + goto out_positive; + else + goto out_negative; + + out_negative: + if (lookupmode == INTERPOSE_PARTIAL) + goto out; + + /* If we've only got negative dentries, then use the leftmost one. */ + if (lookupmode == INTERPOSE_REVAL) { + if (dentry->d_inode) { + itopd(dentry->d_inode)->uii_stale = 1; + } + goto out; + } + /* This should only happen if we found a whiteout. */ + if (first_dentry_offset == -1) { + first_hidden_dentry = LOOKUP_ONE_LEN(name, hidden_dir_dentry, + namelen); + first_dentry_offset = bindex; + if (IS_ERR(first_hidden_dentry)) { + err = PTR_ERR(first_hidden_dentry); + goto out; + } + } + set_dtohd_index(dentry, first_dentry_offset, first_hidden_dentry); + set_dbstart(dentry, first_dentry_offset); + set_dbend(dentry, first_dentry_offset); + + if (lookupmode == INTERPOSE_REVAL_NEG) + BUG_ON(dentry->d_inode != NULL); + else + d_add(dentry, NULL); + goto out; + +/* This part of the code is for positive dentries. */ + out_positive: + BUG_ON(dentry_count <= 0); + + /* If we're holding onto the first negative dentry throw it out. */ + DPUT(first_hidden_dentry); + + /* Partial lookups need to reinterpose, or throw away older negs. */ + if (lookupmode == INTERPOSE_PARTIAL) { + if (dentry->d_inode) { + unionfs_reinterpose(dentry); + goto out; + } + + /* This somehow turned positive, so it is as if we had a + * negative revalidation. */ + lookupmode = INTERPOSE_REVAL_NEG; + + update_bstart(dentry); + bstart = dbstart(dentry); + bend = dbend(dentry); + } + + err = unionfs_interpose(dentry, dentry->d_sb, lookupmode); + if (err) + goto out_drop; + + fist_checkinode(dentry->d_inode, "unionfs_lookup OUT: child"); + fist_checkinode(parent_dentry->d_inode, "unionfs_lookup OUT: dir"); + goto out; + + out_drop: + d_drop(dentry); + + out_free: + /* should dput all the underlying dentries on error condition */ + bstart = dbstart(dentry); + if (bstart >= 0) { + bend = dbend(dentry); + for (bindex = bstart; bindex <= bend; bindex++) + DPUT(dtohd_index(dentry, bindex)); + } + KFREE(dtohd_ptr(dentry)); + dtohd_ptr(dentry) = NULL; + set_dbstart(dentry, -1); + set_dbend(dentry, -1); + + out: + if (!err && dtopd(dentry)) { + BUG_ON(dbend(dentry) > dtopd(dentry)->udi_bcount); + BUG_ON(dbend(dentry) > sbmax(dentry->d_sb)); + BUG_ON(dbstart(dentry) < 0); + } + KFREE(whname); + fist_print_dentry("OUT unionfs_lookup (parent)", parent_dentry); + fist_print_dentry("OUT unionfs_lookup (child)", dentry); + if (locked_parent) + unlock_dentry(parent_dentry); + DPUT(parent_dentry); + if (locked_child) + unlock_dentry(dentry); + print_exit_status(err); + return ERR_PTR(err); +} + +/* This is a utility function that fills in a unionfs dentry.*/ +int unionfs_partial_lookup(struct dentry *dentry) +{ + struct dentry *tmp; + + tmp = unionfs_lookup_backend(dentry, INTERPOSE_PARTIAL); + + return PTR_ERR(tmp); +} + +/* The rest of these are utility functions for lookup. */ +static int is_opaque_dir(struct dentry *dentry, int bindex) +{ + int err = 0; + struct dentry *hidden_dentry; + struct dentry *wh_hidden_dentry; + struct inode *hidden_inode; + uid_t saved_uid = current->fsuid; + gid_t saved_gid = current->fsgid; + + print_entry_location(); + + hidden_dentry = dtohd_index(dentry, bindex); + hidden_inode = hidden_dentry->d_inode; + + BUG_ON(!S_ISDIR(hidden_inode->i_mode)); + + current->fsuid = hidden_inode->i_uid; + current->fsgid = hidden_inode->i_gid; + wh_hidden_dentry = LOOKUP_ONE_LEN(UNIONFS_DIR_OPAQUE, hidden_dentry, + sizeof(UNIONFS_DIR_OPAQUE) - 1); + current->fsuid = saved_uid; + current->fsgid = saved_gid; + if (IS_ERR(wh_hidden_dentry)) { + err = PTR_ERR(wh_hidden_dentry); + fist_dprint(1, "LOOKUP_ONE_LEN returned: %d\n", err); + goto out; + } + if (wh_hidden_dentry->d_inode) + err = 1; + DPUT(wh_hidden_dentry); + out: + print_exit_status(err); + return err; +} + +static int is_validname(const char *name) +{ + if (!strncmp(name, WHPFX, WHLEN)) + return 0; + if (!strncmp(name, UNIONFS_DIR_OPAQUE_NAME, + sizeof(UNIONFS_DIR_OPAQUE_NAME) - 1)) + return 0; + return 1; +} + +/* The dentry cache is just so we have properly sized dentries. */ +static kmem_cache_t *unionfs_dentry_cachep; +int init_dentry_cache(void) +{ + unionfs_dentry_cachep = + kmem_cache_create("unionfs_dentry", + sizeof(struct unionfs_dentry_info), 0, + SLAB_RECLAIM_ACCOUNT, NULL, NULL); + + if (!unionfs_dentry_cachep) + return -ENOMEM; + return 0; +} + +void destroy_dentry_cache(void) +{ + if (!unionfs_dentry_cachep) + return; + if (kmem_cache_destroy(unionfs_dentry_cachep)) + printk(KERN_ERR + "unionfs_dentry_cache: not all structures were freed\n"); + return; +} + +void free_dentry_private_data(struct unionfs_dentry_info *udi) +{ + if (!udi) + return; + kmem_cache_free(unionfs_dentry_cachep, udi); +} + +int new_dentry_private_data(struct dentry *dentry) +{ + int newsize; + int oldsize = 0; + + spin_lock(&dentry->d_lock); + if (!dtopd_nocheck(dentry)) { + dtopd_lhs(dentry) = (struct unionfs_dentry_info *) + kmem_cache_alloc(unionfs_dentry_cachep, SLAB_ATOMIC); + if (!dtopd_nocheck(dentry)) + goto out; + init_MUTEX_LOCKED(&dtopd_nocheck(dentry)->udi_sem); +#ifdef TRACKLOCK + printk("INITLOCK:%p\n", dentry); +#endif + dtohd_ptr(dentry) = NULL; + } else { + if (dtopd(dentry)->udi_bcount > UNIONFS_INLINE_OBJECTS) + oldsize = sizeof(struct dentry *) * + (dtopd(dentry)->udi_bcount - + UNIONFS_INLINE_OBJECTS); + } + + dtopd_nocheck(dentry)->udi_bstart = -1; + dtopd_nocheck(dentry)->udi_bend = -1; + dtopd_nocheck(dentry)->udi_bopaque = -1; + dtopd_nocheck(dentry)->udi_bcount = sbmax(dentry->d_sb); + atomic_set(&dtopd_nocheck(dentry)->udi_generation, + atomic_read(&stopd(dentry->d_sb)->usi_generation)); + newsize = (sbmax(dentry->d_sb) - UNIONFS_INLINE_OBJECTS) + * sizeof(struct dentry *); + if (newsize < 0) + newsize = 0; + + /* Don't reallocate when we already have enough space. */ + /* It would be ideal if we could actually use the slab macros to + * determine what our object sizes is, but those are not exported. + */ + if (oldsize) { + int minsize = malloc_sizes[0].cs_size; + + if (!newsize || ((oldsize < newsize) && (newsize > minsize))) { + KFREE(dtohd_ptr(dentry)); + dtohd_ptr(dentry) = NULL; + } + } + + if (!dtohd_ptr(dentry) && newsize) { + dtohd_ptr(dentry) = KMALLOC(newsize, GFP_ATOMIC); + if (!dtohd_ptr(dentry)) + goto out; + } + memset(dtohd_inline(dentry), 0, + UNIONFS_INLINE_OBJECTS * sizeof(struct dentry *)); + if (newsize) { + if (oldsize > newsize) + memset(dtohd_ptr(dentry), 0, oldsize); + else + memset(dtohd_ptr(dentry), 0, newsize); + } + + spin_unlock(&dentry->d_lock); + return 0; + + out: + free_dentry_private_data(dtopd_nocheck(dentry)); + dtopd_lhs(dentry) = NULL; + spin_unlock(&dentry->d_lock); + return -ENOMEM; +} + +void update_bstart(struct dentry *dentry) +{ + int bindex; + int bstart = dbstart(dentry); + int bend = dbend(dentry); + struct dentry *hidden_dentry; + + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + if (hidden_dentry->d_inode) { + set_dbstart(dentry, bindex); + break; + } + DPUT(hidden_dentry); + set_dtohd_index(dentry, bindex, NULL); + } +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/main.c newtree/fs/unionfs/main.c --- oldtree/fs/unionfs/main.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/main.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,1078 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: main.c,v 1.152 2006/01/22 19:46:50 jsipek Exp $ + */ + +#include "unionfs.h" +#include +#include + +/* declarations added for "sparse" */ +extern void unionfs_kill_block_super(struct super_block *sb); + +/* sb we pass is unionfs's super_block */ +int unionfs_interpose(struct dentry *dentry, struct super_block *sb, int flag) +{ + struct inode *hidden_inode; + struct dentry *hidden_dentry; + int err = 0; + struct inode *inode; + int is_negative_dentry = 1; + int bindex, bstart, bend; + + print_entry("flag = %d", flag); + + verify_locked(dentry); + + fist_print_dentry("In unionfs_interpose", dentry); + + bstart = dbstart(dentry); + bend = dbend(dentry); + + /* Make sure that we didn't get a negative dentry. */ + for (bindex = bstart; bindex <= bend; bindex++) { + if (dtohd_index(dentry, bindex) && + dtohd_index(dentry, bindex)->d_inode) { + is_negative_dentry = 0; + break; + } + } + BUG_ON(is_negative_dentry); + + /* We allocate our new inode below, by calling iget. + * iget will call our read_inode which will initialize some + * of the new inode's fields + */ + + /* On revalidate we've already got our own inode and just need + * to fix it up. */ + if (flag == INTERPOSE_REVAL) { + inode = dentry->d_inode; + itopd(inode)->b_start = -1; + itopd(inode)->b_end = -1; + atomic_set(&itopd(inode)->uii_generation, + atomic_read(&stopd(sb)->usi_generation)); + + if (sbmax(sb) > UNIONFS_INLINE_OBJECTS) { + int size = + (sbmax(sb) - + UNIONFS_INLINE_OBJECTS) * sizeof(struct inode *); + itohi_ptr(inode) = KZALLOC(size, GFP_KERNEL); + if (!itohi_ptr(inode)) { + err = -ENOMEM; + goto out; + } + } + memset(itohi_inline(inode), 0, + UNIONFS_INLINE_OBJECTS * sizeof(struct inode *)); + } else { + ino_t ino; + /* get unique inode number for unionfs */ + if (stopd(sb)->usi_persistent) + ino = + get_uin(sb, bindex, + dtohd_index(dentry, bindex)->d_inode->i_ino, + O_CREAT); + else + ino = iunique(sb, UNIONFS_ROOT_INO); + + inode = IGET(sb, ino); + if (!inode) { + err = -EACCES; /* should be impossible??? */ + goto out; + } + } + + down(&inode->i_sem); + if (atomic_read(&inode->i_count) > 1) + goto skip; + + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + set_itohi_index(inode, bindex, NULL); + continue; + } + /* Initialize the hidden inode to the new hidden inode. */ + if (!hidden_dentry->d_inode) + continue; + set_itohi_index(inode, bindex, IGRAB(hidden_dentry->d_inode)); + } + + ibstart(inode) = dbstart(dentry); + ibend(inode) = dbend(dentry); + + /* Use attributes from the first branch. */ + hidden_inode = itohi(inode); + + /* Use different set of inode ops for symlinks & directories */ + if (S_ISLNK(hidden_inode->i_mode)) + inode->i_op = &unionfs_symlink_iops; + else if (S_ISDIR(hidden_inode->i_mode)) + inode->i_op = &unionfs_dir_iops; + + /* Use different set of file ops for directories */ + if (S_ISDIR(hidden_inode->i_mode)) + inode->i_fop = &unionfs_dir_fops; + + /* properly initialize special inodes */ + if (S_ISBLK(hidden_inode->i_mode) || S_ISCHR(hidden_inode->i_mode) || + S_ISFIFO(hidden_inode->i_mode) || S_ISSOCK(hidden_inode->i_mode)) + init_special_inode(inode, hidden_inode->i_mode, + hidden_inode->i_rdev); + + /* Fix our inode's address operations to that of the lower inode (Unionfs is FiST-Lite) */ + if (inode->i_mapping->a_ops != hidden_inode->i_mapping->a_ops) { + fist_dprint(7, "fixing inode 0x%p a_ops (0x%p -> 0x%p)\n", + inode, inode->i_mapping->a_ops, + hidden_inode->i_mapping->a_ops); + inode->i_mapping->a_ops = hidden_inode->i_mapping->a_ops; + } + + /* all well, copy inode attributes */ + fist_copy_attr_all(inode, hidden_inode); + + skip: + /* only (our) lookup wants to do a d_add */ + switch (flag) { + case INTERPOSE_DEFAULT: + case INTERPOSE_REVAL_NEG: + d_instantiate(dentry, inode); + break; + case INTERPOSE_LOOKUP: + err = PTR_ERR(d_splice_alias(inode, dentry)); + break; + case INTERPOSE_REVAL: + /* Do nothing. */ + break; + default: + printk(KERN_ERR "Invalid interpose flag passed!"); + BUG(); + } + + fist_print_dentry("Leaving unionfs_interpose", dentry); + fist_print_inode("Leaving unionfs_interpose", inode); + up(&inode->i_sem); + + out: + print_exit_status(err); + return err; +} + +void unionfs_reinterpose(struct dentry *dentry) +{ + struct dentry *hidden_dentry; + struct inode *inode; + int bindex, bstart, bend; + + print_entry_location(); + verify_locked(dentry); + fist_print_dentry("IN: unionfs_reinterpose: ", dentry); + + /* This is pre-allocated inode */ + inode = dentry->d_inode; + + bstart = dbstart(dentry); + bend = dbend(dentry); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + + if (!hidden_dentry->d_inode) + continue; + if (itohi_index(inode, bindex)) + continue; + set_itohi_index(inode, bindex, IGRAB(hidden_dentry->d_inode)); + } + ibstart(inode) = dbstart(dentry); + ibend(inode) = dbend(dentry); + + fist_print_dentry("OUT: unionfs_reinterpose: ", dentry); + fist_print_inode("OUT: unionfs_reinterpose: ", inode); + + print_exit_location(); +} + +int check_branch(struct nameidata *nd) +{ + if (!strcmp(nd->dentry->d_sb->s_type->name, "unionfs")) + return -EINVAL; + if (!nd->dentry->d_inode) + return -ENOENT; + if (!S_ISDIR(nd->dentry->d_inode->i_mode)) + return -ENOTDIR; + return 0; +} + +/* checks if two hidden_dentries have overlapping branches */ +int is_branch_overlap(struct dentry *dent1, struct dentry *dent2) +{ + struct dentry *dent = NULL; + + dent = dent1; + while ((dent != dent2) && (dent->d_parent != dent)) { + dent = dent->d_parent; + } + if (dent == dent2) { + return 1; + } + + dent = dent2; + while ((dent != dent1) && (dent->d_parent != dent)) { + dent = dent->d_parent; + } + if (dent == dent1) { + return 1; + } + + return 0; +} + +static int parse_dirs_option(struct super_block *sb, struct unionfs_dentry_info + *hidden_root_info, char *options) +{ + struct nameidata nd; + char *name; + int pobjects = 0; + int err = 0; + int branches = 1; + int bindex = 0; + int i = 0; + int j = 0; + + struct dentry *dent1 = NULL; + struct dentry *dent2 = NULL; + + if (options[0] == '\0') { + printk(KERN_WARNING "unionfs: no branches specified\n"); + err = -EINVAL; + goto out; + } + + /* Each colon means we have a separator, this is really just a rough + * guess, since strsep will handle empty fields for us. */ + for (i = 0; options[i]; i++) { + if (options[i] == ':') + branches++; + } + + /* allocate space for underlying pointers to hidden dentry */ + if (branches > UNIONFS_INLINE_OBJECTS) + pobjects = branches - UNIONFS_INLINE_OBJECTS; + + if (pobjects) { + err = -ENOMEM; + + hidden_root_info->udi_dentry_p = + KZALLOC(sizeof(struct dentry *) * pobjects, GFP_KERNEL); + if (!hidden_root_info->udi_dentry_p) + goto out; + + stohs_ptr(sb) = + KZALLOC(sizeof(struct super_block *) * + pobjects, GFP_KERNEL); + if (!stohs_ptr(sb)) + goto out; + + stopd(sb)->usi_sbcount_p = + KMALLOC(sizeof(atomic_t) * pobjects, GFP_KERNEL); + if (!stopd(sb)->usi_sbcount_p) + goto out; + + stopd(sb)->usi_branchperms_p = + KMALLOC(sizeof(int) * pobjects, GFP_KERNEL); + if (!stopd(sb)->usi_branchperms_p) + goto out; + + stohiddenmnt_ptr(sb) = + KMALLOC(sizeof(struct vfsmount *) * pobjects, GFP_KERNEL); + if (!stohiddenmnt_ptr(sb)) + goto out; + + /* We're done with allocating memory. */ + err = 0; + } + + /* now parsing the string b1:b2=rw:b3=ro:b4 */ + branches = 0; + while ((name = strsep(&options, ":")) != NULL) { + int perms; + int l; + + if (!*name) + continue; + + branches++; + + /* strip off =rw or =ro if it is specified. */ + l = strlen(name); + if (!strcmp(name + l - 3, "=ro")) { + perms = MAY_READ; + name[l - 3] = '\0'; + } else if (!strcmp(name + l - 6, "=nfsro")) { + perms = MAY_READ | MAY_NFSRO; + name[l - 6] = '\0'; + } else if (!strcmp(name + l - 3, "=rw")) { + perms = MAY_READ | MAY_WRITE; + name[l - 3] = '\0'; + } else { + perms = MAY_READ | MAY_WRITE; + } + + fist_dprint(4, "unionfs: using directory: %s (%c%c%c)\n", + name, perms & MAY_READ ? 'r' : '-', + perms & MAY_WRITE ? 'w' : '-', + perms & MAY_NFSRO ? 'n' : '-'); + + err = path_lookup(name, LOOKUP_FOLLOW, &nd); + RECORD_PATH_LOOKUP(&nd); + if (err) { + printk(KERN_WARNING "unionfs: error accessing " + "hidden directory '%s' (error %d)\n", name, err); + goto out; + } + + if ((err = check_branch(&nd))) { + printk(KERN_WARNING "unionfs: hidden directory " + "'%s' is not a valid branch\n", name); + path_release(&nd); + RECORD_PATH_RELEASE(&nd); + goto out; + } + + if (bindex < UNIONFS_INLINE_OBJECTS) + hidden_root_info->udi_dentry_i[bindex] = nd.dentry; + else + hidden_root_info->udi_dentry_p[bindex - + UNIONFS_INLINE_OBJECTS] + = nd.dentry; + + set_stohiddenmnt_index(sb, bindex, nd.mnt); + set_branchperms(sb, bindex, perms); + set_branch_count(sb, bindex, 0); + + if (hidden_root_info->udi_bstart < 0) + hidden_root_info->udi_bstart = bindex; + hidden_root_info->udi_bend = bindex; + bindex++; + } + + if (branches == 0) { + printk(KERN_WARNING "unionfs: no branches specified\n"); + err = -EINVAL; + goto out; + } + + BUG_ON(branches != (hidden_root_info->udi_bend + 1)); + + /* ensure that no overlaps exist in the branches */ + for (i = 0; i < branches; i++) { + for (j = i + 1; j < branches; j++) { + if (i < UNIONFS_INLINE_OBJECTS) + dent1 = hidden_root_info->udi_dentry_i[i]; + else + dent1 = + hidden_root_info->udi_dentry_p[i - + UNIONFS_INLINE_OBJECTS]; + + if (j < UNIONFS_INLINE_OBJECTS) + dent2 = hidden_root_info->udi_dentry_i[j]; + else + dent2 = + hidden_root_info->udi_dentry_p[j - + UNIONFS_INLINE_OBJECTS]; + + if (is_branch_overlap(dent1, dent2)) { + goto out_overlap; + } + } + } + + out_overlap: + + if (i != branches) { + printk(KERN_WARNING "unionfs: branches %d and %d overlap\n", i, + j); + err = -EINVAL; + goto out; + } + + out: + return err; +} + +/* + * Parse mount options. See the manual page for usage instructions. + * + * Returns the dentry object of the lower-level (hidden) directory; + * We want to mount our stackable file system on top of that hidden directory. + * + * Sets default debugging level to N, if any. + */ +static struct unionfs_dentry_info *unionfs_parse_options(struct super_block *sb, + char *options) +{ + struct unionfs_dentry_info *hidden_root_info; + char *optname; + int err = 0; + int bindex; + int dirsfound = 0; + int imapfound = 0; + int mounter_f = 0, copyupuid_f = 0, copyupgid_f = 0, copyupmode_f = 0; + print_entry_location(); + + /* allocate private data area */ + err = -ENOMEM; + hidden_root_info = + KZALLOC(sizeof(struct unionfs_dentry_info), GFP_KERNEL); + if (!hidden_root_info) + goto out_error; + hidden_root_info->udi_bstart = -1; + hidden_root_info->udi_bend = -1; + hidden_root_info->udi_bopaque = -1; + + while ((optname = strsep(&options, ",")) != NULL) { + char *optarg; + char *endptr; + int intval; + + if (!*optname) { + continue; + } + + optarg = strchr(optname, '='); + if (optarg) { + *optarg++ = '\0'; + } + + /* All of our options take an argument now. Insert ones that + * don't, above this check. */ + if (!optarg) { + printk("unionfs: %s requires an argument.\n", optname); + err = -EINVAL; + goto out_error; + } + + if (!strcmp("dirs", optname)) { + if (++dirsfound > 1) { + printk(KERN_WARNING + "unionfs: multiple dirs specified\n"); + err = -EINVAL; + goto out_error; + } + err = parse_dirs_option(sb, hidden_root_info, optarg); + if (err) + goto out_error; + continue; + } + if (!strcmp("imap", optname)) { + if (++imapfound > 1) { + printk(KERN_WARNING + "unionfs: multiple imap specified\n"); + err = -EINVAL; + goto out_error; + } + err = parse_imap_option(sb, hidden_root_info, optarg); + if (err) + goto out_error; + continue; + } + if (!strcmp("delete", optname)) { + if (!strcmp("all", optarg)) { + /* default */ + } else if (!strcmp("whiteout", optarg)) { + MOUNT_FLAG(sb) |= DELETE_WHITEOUT; + } else { + printk(KERN_WARNING + "unionfs: invalid delete option '%s'\n", + optarg); + err = -EINVAL; + goto out_error; + } + continue; + } + if (!strcmp("copyup", optname)) { + if (!strcmp("preserve", optarg)) { + /* default */ + } else if (!strcmp("currentuser", optarg)) { + MOUNT_FLAG(sb) |= COPYUP_CURRENT_USER; + } else if (!strcmp("mounter", optarg)) { + MOUNT_FLAG(sb) |= COPYUP_FS_MOUNTER; + mounter_f = 1; + } else { + printk(KERN_WARNING + "unionfs: could not parse copyup option value '%s'\n", + optarg); + err = -EINVAL; + goto out_error; + } + continue; + } + + /* All of these options require an integer argument. */ + intval = simple_strtoul(optarg, &endptr, 0); + if (*endptr) { + printk(KERN_WARNING + "unionfs: invalid %s option '%s'\n", + optname, optarg); + err = -EINVAL; + goto out_error; + } + + if (!strcmp("debug", optname)) { + fist_set_debug_value(intval); + continue; + } + if (!strcmp("copyupuid", optname)) { + stopd(sb)->copyupuid = intval; + copyupuid_f = 1; + continue; + } + if (!strcmp("copyupgid", optname)) { + stopd(sb)->copyupgid = intval; + copyupgid_f = 1; + continue; + } + if (!strcmp("copyupmode", optname)) { + if (intval & ~0777) { + err = -EINVAL; + printk(KERN_WARNING + "unionfs: copyupmode invalid '%o' (note: you need to preface octal values with 0.\n", + intval); + goto out_error; + } + stopd(sb)->copyupmode = intval; + copyupmode_f = 1; + continue; + } + + err = -EINVAL; + printk(KERN_WARNING + "unionfs: unrecognized option '%s'\n", optname); + goto out_error; + } + if (dirsfound != 1) { + printk(KERN_WARNING "unionfs: dirs option required\n"); + err = -EINVAL; + goto out_error; + } + if (mounter_f && !(copyupuid_f && copyupgid_f && copyupmode_f)) { + printk(KERN_WARNING + "unionfs: " + "copyup=mounter all copyup options must be set\n"); + + err = -EINVAL; + goto out_error; + } + if ((copyupuid_f || copyupgid_f || copyupmode_f) && !mounter_f) { + printk(KERN_WARNING + "unionfs: " + "copyup!=mounter and a copyup option is set\n"); + err = -EINVAL; + goto out_error; + } + goto out; + + out_error: + for (bindex = hidden_root_info->udi_bstart; + bindex >= 0 && bindex <= hidden_root_info->udi_bend; bindex++) { + struct dentry *d; + if (bindex < UNIONFS_INLINE_OBJECTS) + d = hidden_root_info->udi_dentry_i[bindex]; + else + d = hidden_root_info->udi_dentry_p[bindex - + UNIONFS_INLINE_OBJECTS]; + DPUT(d); + if (stohiddenmnt_index(sb, bindex)) + mntput(stohiddenmnt_index(sb, bindex)); + } + KFREE(hidden_root_info->udi_dentry_p); + KFREE(hidden_root_info); + + KFREE(stohiddenmnt_ptr(sb)); + stohiddenmnt_ptr(sb) = NULL; + KFREE(stopd(sb)->usi_sbcount_p); + stopd(sb)->usi_sbcount_p = NULL; + KFREE(stopd(sb)->usi_branchperms_p); + stopd(sb)->usi_branchperms_p = NULL; + KFREE(stohs_ptr(sb)); + stohs_ptr(sb) = NULL; + + hidden_root_info = ERR_PTR(err); + out: + print_exit_location(); + return hidden_root_info; +} + +#ifdef FIST_MALLOC_DEBUG +/* for malloc debugging */ +atomic_t unionfs_malloc_counter = ATOMIC_INIT(0); +atomic_t unionfs_mallocs_outstanding = ATOMIC_INIT(0); +atomic_t unionfs_dget_counter = ATOMIC_INIT(0); +atomic_t unionfs_dgets_outstanding = ATOMIC_INIT(0); +atomic_t unionfs_iget_counter = ATOMIC_INIT(0); +atomic_t unionfs_igets_outstanding = ATOMIC_INIT(0); + +void *unionfs_kzalloc(size_t size, gfp_t flags, int line, const char *file) +{ + void *ptr = kzalloc(size, flags); + if (ptr) { + atomic_inc(&unionfs_malloc_counter); + atomic_inc(&unionfs_mallocs_outstanding); + printk("KZA:%d:%d:%p:%d:%s\n", + atomic_read(&unionfs_malloc_counter), + atomic_read(&unionfs_mallocs_outstanding), ptr, line, + file); + } + return ptr; +} +void *unionfs_kmalloc(size_t size, gfp_t flags, int line, const char *file) +{ + void *ptr = kmalloc(size, flags); + if (ptr) { + atomic_inc(&unionfs_malloc_counter); + atomic_inc(&unionfs_mallocs_outstanding); + printk("KM:%d:%d:%p:%d:%s\n", + atomic_read(&unionfs_malloc_counter), + atomic_read(&unionfs_mallocs_outstanding), ptr, line, + file); + } + return ptr; +} + +void unionfs_kfree(void *ptr, int line, const char *file) +{ + atomic_inc(&unionfs_malloc_counter); + if (ptr) { + BUG_ON(IS_ERR(ptr)); + atomic_dec(&unionfs_mallocs_outstanding); + } + printk("KF:%d:%d:%p:%d:%s\n", atomic_read(&unionfs_malloc_counter), + atomic_read(&unionfs_mallocs_outstanding), ptr, line, file); + kfree(ptr); +} + +void record_set(struct dentry *upper, int index, struct dentry *ptr, + struct dentry *old, int line, const char *file) +{ + atomic_inc(&unionfs_dget_counter); + printk("DD:%d:%d:%d:%p:%d:%s %p, %d\n", + atomic_read(&unionfs_dget_counter), + atomic_read(&unionfs_dgets_outstanding), + old ? atomic_read(&old->d_count) : 0, old, line, file, upper, + index); + atomic_inc(&unionfs_dget_counter); + printk("DS:%d:%d:%d:%p:%d:%s %p, %d\n", + atomic_read(&unionfs_dget_counter), + atomic_read(&unionfs_dgets_outstanding), + ptr ? atomic_read(&ptr->d_count) : 0, ptr, line, file, upper, + index); +} + +void record_path_lookup(struct nameidata *nd, int line, const char *file) +{ + struct dentry *ptr = nd->dentry; + if (ptr) { + atomic_inc(&unionfs_dget_counter); + atomic_inc(&unionfs_dgets_outstanding); + printk("DL:%d:%d:%d:%p:%d:%s\n", + atomic_read(&unionfs_dget_counter), + atomic_read(&unionfs_dgets_outstanding), + atomic_read(&ptr->d_count), ptr, line, file); + } +} + +void record_path_release(struct nameidata *nd, int line, const char *file) +{ + struct dentry *ptr = nd->dentry; + + atomic_inc(&unionfs_dget_counter); + if (ptr) + atomic_dec(&unionfs_dgets_outstanding); + printk("DP:%d:%d:%d:%p:%d:%s\n", atomic_read(&unionfs_dget_counter), + atomic_read(&unionfs_dgets_outstanding), + ptr ? atomic_read(&ptr->d_count) : 0, ptr, line, file); +} + +struct file *unionfs_dentry_open(struct dentry *ptr, struct vfsmount *mnt, + int flags, int line, const char *file) +{ + atomic_inc(&unionfs_dget_counter); + if (ptr) + atomic_dec(&unionfs_dgets_outstanding); + printk("DO:%d:%d:%d:%p:%d:%s\n", atomic_read(&unionfs_dget_counter), + atomic_read(&unionfs_dgets_outstanding), + ptr ? atomic_read(&ptr->d_count) : 0, ptr, line, file); + return dentry_open(ptr, mnt, flags); +} + +struct dentry *unionfs_dget(struct dentry *ptr, int line, const char *file) +{ + ptr = dget(ptr); + if (ptr) { + atomic_inc(&unionfs_dget_counter); + atomic_inc(&unionfs_dgets_outstanding); + printk("DG:%d:%d:%d:%p:%d:%s\n", + atomic_read(&unionfs_dget_counter), + atomic_read(&unionfs_dgets_outstanding), + atomic_read(&ptr->d_count), ptr, line, file); + } + return ptr; +} + +struct dentry *unionfs_dget_parent(struct dentry *child, int line, + const char *file) +{ + struct dentry *ptr; + + ptr = dget_parent(child); + atomic_inc(&unionfs_dget_counter); + atomic_inc(&unionfs_dgets_outstanding); + printk("DG:%d:%d:%d:%p:%d:%s\n", + atomic_read(&unionfs_dget_counter), + atomic_read(&unionfs_dgets_outstanding), + atomic_read(&ptr->d_count), ptr, line, file); + + return ptr; +} + +struct dentry *unionfs_lookup_one_len(const char *name, struct dentry *parent, + int len, int line, const char *file) +{ + struct dentry *ptr = lookup_one_len(name, parent, len); + if (ptr && !IS_ERR(ptr)) { + atomic_inc(&unionfs_dget_counter); + atomic_inc(&unionfs_dgets_outstanding); + printk("DL:%d:%d:%d:%p:%d:%s\n", + atomic_read(&unionfs_dget_counter), + atomic_read(&unionfs_dgets_outstanding), + atomic_read(&ptr->d_count), ptr, line, file); + } + return ptr; +} + +void unionfs_dput(struct dentry *ptr, int line, const char *file) +{ + atomic_inc(&unionfs_dget_counter); + if (ptr) { + BUG_ON(IS_ERR(ptr)); + atomic_dec(&unionfs_dgets_outstanding); + } + printk("DP:%d:%d:%d:%p:%d:%s\n", atomic_read(&unionfs_dget_counter), + atomic_read(&unionfs_dgets_outstanding), + ptr ? atomic_read(&ptr->d_count) : 0, ptr, line, file); + dput(ptr); +} + +struct inode *unionfs_igrab(struct inode *inode, int line, char *file) +{ + atomic_inc(&unionfs_iget_counter); + if (inode) + atomic_inc(&unionfs_igets_outstanding); + printk("IR:%d:%d:%d:%p:%d:%s\n", atomic_read(&unionfs_iget_counter), + atomic_read(&unionfs_igets_outstanding), + inode ? atomic_read(&inode->i_count) : 0, inode, line, file); + return igrab(inode); +} + +void unionfs_iput(struct inode *inode, int line, char *file) +{ + atomic_inc(&unionfs_iget_counter); + if (inode) + atomic_dec(&unionfs_igets_outstanding); + printk("IP:%d:%d:%d:%p:%d:%s\n", atomic_read(&unionfs_iget_counter), + atomic_read(&unionfs_igets_outstanding), + inode ? atomic_read(&inode->i_count) : 0, inode, line, file); + iput(inode); +} + +struct inode *unionfs_iget(struct super_block *sb, unsigned long ino, int line, + char *file) +{ + struct inode *inode = iget(sb, ino); + atomic_inc(&unionfs_iget_counter); + if (inode) + atomic_inc(&unionfs_igets_outstanding); + printk("IG:%d:%d:%d:%p:%d:%s\n", atomic_read(&unionfs_iget_counter), + atomic_read(&unionfs_igets_outstanding), + inode ? atomic_read(&inode->i_count) : 0, inode, line, file); + return inode; +} + +#endif /* FIST_MALLOC_DEBUG */ + +static int +unionfs_read_super(struct super_block *sb, void *raw_data, int silent) +{ + int err = 0; + + struct unionfs_dentry_info *hidden_root_info = NULL; + int bindex, bstart, bend; + unsigned long long maxbytes; + + print_entry_location(); + + if (!raw_data) { + printk(KERN_WARNING + "unionfs_read_super: missing data argument\n"); + err = -EINVAL; + goto out; + } + + /* + * Allocate superblock private data + */ + stopd_lhs(sb) = KZALLOC(sizeof(struct unionfs_sb_info), GFP_KERNEL); + if (!stopd(sb)) { + printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__); + err = -ENOMEM; + goto out; + } + stopd(sb)->b_end = -1; + atomic_set(&stopd(sb)->usi_generation, 1); + init_rwsem(&stopd(sb)->usi_rwsem); + + hidden_root_info = unionfs_parse_options(sb, raw_data); + if (IS_ERR(hidden_root_info)) { + printk(KERN_WARNING + "unionfs_read_super: error while parsing options (err = %ld)\n", + PTR_ERR(hidden_root_info)); + err = PTR_ERR(hidden_root_info); + hidden_root_info = NULL; + goto out_free; + } + if (hidden_root_info->udi_bstart == -1) { + err = -ENOENT; + goto out_free; + } + + /* set the hidden superblock field of upper superblock */ + bstart = hidden_root_info->udi_bstart; + BUG_ON(bstart != 0); + sbend(sb) = bend = hidden_root_info->udi_bend; + for (bindex = bstart; bindex <= bend; bindex++) { + struct dentry *d; + + if (bindex < UNIONFS_INLINE_OBJECTS) + d = hidden_root_info->udi_dentry_i[bindex]; + else + d = hidden_root_info->udi_dentry_p[bindex - + UNIONFS_INLINE_OBJECTS]; + + set_stohs_index(sb, bindex, d->d_sb); + } + + /* Unionfs: Max Bytes is the maximum bytes from among all the branches */ + maxbytes = -1; + for (bindex = bstart; bindex <= bend; bindex++) + if (maxbytes < stohs_index(sb, bindex)->s_maxbytes) + maxbytes = stohs_index(sb, bindex)->s_maxbytes; + sb->s_maxbytes = maxbytes; + + sb->s_op = &unionfs_sops; + sb->s_export_op = &unionfs_export_ops; + + /* + * we can't use d_alloc_root if we want to use + * our own interpose function unchanged, + * so we simply replicate *most* of the code in d_alloc_root here + */ + sb->s_root = d_alloc(NULL, &(const struct qstr) { + .hash = 0,.name = "/",.len = 1}); + if (IS_ERR(sb->s_root)) { + printk(KERN_WARNING "unionfs_read_super: d_alloc failed\n"); + err = PTR_ERR(sb->s_root); + goto out_dput; + } + + sb->s_root->d_op = &unionfs_dops; + sb->s_root->d_sb = sb; + sb->s_root->d_parent = sb->s_root; + + /* link the upper and lower dentries */ + dtopd_lhs(sb->s_root) = NULL; + if ((err = new_dentry_private_data(sb->s_root))) + goto out_freedpd; + + /* Set the hidden dentries for s_root */ + for (bindex = bstart; bindex <= bend; bindex++) { + struct dentry *d; + + if (bindex < UNIONFS_INLINE_OBJECTS) + d = hidden_root_info->udi_dentry_i[bindex]; + else + d = hidden_root_info->udi_dentry_p[bindex - + UNIONFS_INLINE_OBJECTS]; + + set_dtohd_index(sb->s_root, bindex, d); + } + set_dbstart(sb->s_root, bstart); + set_dbend(sb->s_root, bend); + + /* Set the generation number to one, since this is for the mount. */ + atomic_set(&dtopd(sb->s_root)->udi_generation, 1); + + /* call interpose to create the upper level inode */ + if ((err = unionfs_interpose(sb->s_root, sb, 0))) + goto out_freedpd; + unlock_dentry(sb->s_root); + goto out; + + out_freedpd: + if (dtopd(sb->s_root)) { + KFREE(dtohd_ptr(sb->s_root)); + free_dentry_private_data(dtopd(sb->s_root)); + } + DPUT(sb->s_root); + out_dput: + if (hidden_root_info && !IS_ERR(hidden_root_info)) { + for (bindex = hidden_root_info->udi_bstart; + bindex <= hidden_root_info->udi_bend; bindex++) { + struct dentry *d; + + if (bindex < UNIONFS_INLINE_OBJECTS) + d = hidden_root_info->udi_dentry_i[bindex]; + else if (!hidden_root_info->udi_dentry_p) + break; + else + d = hidden_root_info->udi_dentry_p[bindex - + UNIONFS_INLINE_OBJECTS]; + + if (d) + DPUT(d); + + if (stopd(sb) && stohiddenmnt_index(sb, bindex)) + mntput(stohiddenmnt_index(sb, bindex)); + } + KFREE(hidden_root_info->udi_dentry_p); + KFREE(hidden_root_info); + hidden_root_info = NULL; + } + out_free: + KFREE(stohiddenmnt_ptr(sb)); + KFREE(stopd(sb)->usi_sbcount_p); + KFREE(stopd(sb)->usi_branchperms_p); + KFREE(stohs_ptr(sb)); + KFREE(stopd(sb)); + stopd_lhs(sb) = NULL; + out: + if (hidden_root_info && !IS_ERR(hidden_root_info)) { + KFREE(hidden_root_info->udi_dentry_p); + KFREE(hidden_root_info); + } + print_exit_status(err); + return err; +} + +static struct super_block *unionfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *raw_data) +{ + return get_sb_nodev(fs_type, flags, raw_data, unionfs_read_super); +} + +void unionfs_kill_block_super(struct super_block *sb) +{ + generic_shutdown_super(sb); +} + +/* Compat..it is simpler to have it here, than to duplicate the code in + unionfs_kzalloc and KZALLOC non-debug macro */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) +void *kzalloc(size_t size, gfp_t flags) +{ + void *ret = kmalloc(size, flags); + if (ret) + memset(ret, 0, size); + return ret; +} +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) */ + +static struct file_system_type unionfs_fs_type = { + .owner = THIS_MODULE, + .name = "unionfs", + .get_sb = unionfs_get_sb, + .kill_sb = unionfs_kill_block_super, + .fs_flags = FS_REVAL_DOT, +}; + +static int init_debug = 0; +module_param_named(debug, init_debug, int, 0444); +MODULE_PARM_DESC(debug, "Initial Unionfs debug value."); + +static int __init init_unionfs_fs(void) +{ + int err; + printk("Registering unionfs " UNIONFS_VERSION "\n"); + + fist_set_debug_value(init_debug); + +#ifdef FIST_MALLOC_DEBUG + atomic_set(&unionfs_malloc_counter, 0); + atomic_set(&unionfs_mallocs_outstanding, 0); +#endif /* FIST_MALLOC_DEBUG */ + + if ((err = init_filldir_cache())) + goto out; + if ((err = init_inode_cache())) + goto out; + if ((err = init_dentry_cache())) + goto out; + err = register_filesystem(&unionfs_fs_type); + out: + if (err) { + destroy_filldir_cache(); + destroy_inode_cache(); + destroy_dentry_cache(); + } + return err; +} +static void __exit exit_unionfs_fs(void) +{ + destroy_filldir_cache(); + destroy_inode_cache(); + destroy_dentry_cache(); + unregister_filesystem(&unionfs_fs_type); + printk("Completed unionfs module unload.\n"); +} + +MODULE_AUTHOR + ("Filesystems and Storage Lab, Stony Brook University (http://www.fsl.cs.sunysb.edu/)"); +MODULE_DESCRIPTION("Unionfs " UNIONFS_VERSION + " (http://unionfs.filesystems.org/)"); +MODULE_LICENSE("GPL"); + +module_init(init_unionfs_fs); +module_exit(exit_unionfs_fs); +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/persistent_inode.c newtree/fs/unionfs/persistent_inode.c --- oldtree/fs/unionfs/persistent_inode.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/persistent_inode.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,633 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: persistent_inode.c,v 1.27 2006/01/22 19:46:50 jsipek Exp $ + */ + +#include "unionfs.h" + +static ssize_t __fread(struct file *filp, void *buf, size_t size, loff_t * pos) +{ + int err; + mm_segment_t oldfs; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + if (filp->f_op->read) + err = filp->f_op->read(filp, (char __user *)buf, size, pos); + else + err = do_sync_read(filp, (char __user *)buf, size, pos); + set_fs(oldfs); + return err; +} + +static ssize_t __fwrite(struct file *filp, void *buf, size_t size, loff_t * pos) +{ + int err; + mm_segment_t oldfs; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + if (filp->f_op->write) + err = + filp->f_op->write(filp, (const char __user *)buf, size, + pos); + else + err = do_sync_write(filp, (const char __user *)buf, size, pos); + set_fs(oldfs); + return err; +} + +/* + * verify_forwardmap(super_block *sb) + * sb: pointer to a superblock containing the forwardmap. + * returns: 0 on success EINVAL or ENOMEM on failure; + */ +static int verify_forwardmap(struct super_block *sb) +{ + int err = 0, bytesread = 0, bindex = 0, mallocsize = 0, i = 0; + loff_t readpos = 0; + struct file *forwardmap = NULL; + struct fmaphdr header; + struct unionfs_sb_info *spd = NULL; + print_entry_location(); + + spd = stopd(sb); + BUG_ON(!spd); + + forwardmap = spd->usi_forwardmap; + if (!forwardmap) { + err = -EINVAL; + goto out; + } + bytesread = __fread(forwardmap, &header, sizeof(struct fmaphdr), + &readpos); + if (bytesread < sizeof(struct fmaphdr)) { + err = -EINVAL; + goto out; + } + if (header.magic != FORWARDMAP_MAGIC + || header.version != FORWARDMAP_VERSION) { + err = -EINVAL; + goto out; + } + spd->usi_bmap = + KMALLOC(sizeof(struct bmapent) * header.usedbranches, GFP_KERNEL); + //spd->usi_num_bmapents = header.usedbranches; + if (!spd->usi_bmap) { + err = -ENOMEM; + goto out; + } + while (bindex < header.usedbranches) { + bytesread = __fread(forwardmap, &stopd(sb)->usi_bmap[bindex], + sizeof(struct bmapent), &readpos); + if (bytesread < sizeof(struct bmapent)) { + err = -EINVAL; + goto out_err; + } + bindex++; + } + mallocsize = sizeof(int) * header.usedbranches; + spd->usi_fsnum_table = KMALLOC(mallocsize, GFP_KERNEL); + if (!spd->usi_fsnum_table) { + err = -ENOMEM; + goto out_err; + } + for (i = 0; i < header.usedbranches; i++) { + spd->usi_fsnum_table[i] = -1; + } + goto out; + out_err: + if (spd->usi_bmap) + KFREE(spd->usi_bmap); + if (spd->usi_fsnum_table) + KFREE(spd->usi_fsnum_table); + out: + print_exit_status(err); + return err; +} + +/* + * verify_reversemap(struct super_block sb, int rmapindex) + * + * sb: The unionfs superblock containing all of the current imap info + * rmapindex: the index in the usi_reversemaps array that we wish to + * verify + * + * Assumes the reverse maps less than rmapindex are valid. + * + * returns: 0 if the opperation succeds + * -EINVAL if the map file does not belong to the forward map + * + */ +static int verify_reversemap(struct super_block *sb, int rmapindex, + struct unionfs_dentry_info *hidden_root_info) +{ + int err = 0, i = 0, bindex = 0, found = 0, bytesread; + loff_t readpos = 0; + struct file *forwardmap, *reversemap; + struct fmaphdr fheader; + struct rmaphdr rheader; + struct kstatfs st; + struct unionfs_sb_info *spd = NULL; + + print_entry_location(); + + spd = stopd(sb); + BUG_ON(!spd); + + forwardmap = spd->usi_forwardmap; + if (!forwardmap) { + err = -EINVAL; + goto out; + } + reversemap = spd->usi_reversemaps[rmapindex]; + if (!reversemap) { + err = -EINVAL; + goto out; + } + bytesread = __fread(forwardmap, &fheader, sizeof(struct fmaphdr), + &readpos); + if (bytesread < sizeof(struct fmaphdr)) { + err = -EINVAL; + goto out; + } + readpos = 0; + bytesread = __fread(reversemap, &rheader, sizeof(struct rmaphdr), + &readpos); + if (bytesread < sizeof(struct rmaphdr)) { + err = -EINVAL; + goto out; + } + if (rheader.magic != REVERSEMAP_MAGIC + || rheader.version != REVERSEMAP_VERSION) { + err = -EINVAL; + goto out; + } + if (memcmp(fheader.uuid, rheader.fwduuid, sizeof(fheader.uuid))) { + err = -EINVAL; + goto out; + } + + /* XXX: Ok so here we take the new map and read the fsid from it. Then + * we go through all the branches in the union and see which ones it + * matches with*/ + for (i = 0; i < spd->usi_num_bmapents && !found; i++) { + if (memcmp + (rheader.revuuid, spd->usi_bmap[i].uuid, + sizeof(rheader.revuuid))) + continue; + + found = 1; + for (bindex = 0; bindex <= hidden_root_info->udi_bend; bindex++) { + struct dentry *d; + fsid_t fsid; + dev_t dev; + memset(&st, 0, sizeof(struct kstatfs)); + + if (bindex < UNIONFS_INLINE_OBJECTS) + d = hidden_root_info->udi_dentry_i[bindex]; + else + d = hidden_root_info->udi_dentry_p[bindex - + UNIONFS_INLINE_OBJECTS]; + + err = d->d_sb->s_op->statfs(d->d_sb, &st); + if (err) + goto out; + + if (st.f_fsid.val[0] || st.f_fsid.val[1]) { + fsid = st.f_fsid; + } else { + + dev = d->d_sb->s_dev; + fsid.val[0] = MAJOR(dev); + fsid.val[1] = MINOR(dev); + } + + if (memcmp(&fsid, &rheader.fsid, sizeof(fsid))) + continue; + + if (spd->usi_fsnum_table[i] == -1) + spd->usi_fsnum_table[i] = bindex; + if (spd->usi_bnum_table[bindex] == -1) + spd->usi_bnum_table[bindex] = i; + if (spd->usi_map_table[bindex]) { + printk(KERN_WARNING + "Two reverse maps share fsid %u%u!\n", + rheader.fsid.val[0], + rheader.fsid.val[1]); + err = -EINVAL; + goto out; + } else { + spd->usi_map_table[bindex] = reversemap; + } + } + } + if (!found) { + printk(KERN_WARNING + "Could not match the reversemap uuid with an entry in the forwardmap table\n"); + err = -EINVAL; + } + out: + print_exit_status(err); + return err; +} + +int init_imap_data(struct super_block *sb, + struct unionfs_dentry_info *hidden_root_info) +{ + int i, err = 0, mallocsize = 0; + struct unionfs_sb_info *spd; + + print_entry_location(); + + spd = stopd(sb); + + spd->usi_forwardmap = NULL; + spd->usi_reversemaps = NULL; + spd->usi_fsnum_table = NULL; + spd->usi_bnum_table = NULL; + + mallocsize = sizeof(struct file *) * (hidden_root_info->udi_bend + 1); + spd->usi_reversemaps = KZALLOC(mallocsize, GFP_KERNEL); + if (!spd->usi_reversemaps) { + err = -ENOMEM; + goto out_error; + } + + spd->usi_map_table = KZALLOC(mallocsize, GFP_KERNEL); + if (!spd->usi_map_table) { + err = -ENOMEM; + goto out_error; + } + + mallocsize = sizeof(int) * (hidden_root_info->udi_bend + 1); + spd->usi_bnum_table = KMALLOC(mallocsize, GFP_KERNEL); + if (!spd->usi_bnum_table) { + err = -ENOMEM; + goto out_error; + } + + for (i = 0; i <= hidden_root_info->udi_bend; i++) { + spd->usi_bnum_table[i] = -1; + } + + if (!err) + goto out; + out_error: + + if (spd->usi_reversemaps) { + KFREE(spd->usi_reversemaps); + spd->usi_reversemaps = NULL; + } + + if (spd->usi_map_table) { + KFREE(spd->usi_map_table); + spd->usi_map_table = NULL; + } + + if (spd->usi_bnum_table) { + KFREE(spd->usi_bnum_table); + spd->usi_bnum_table = NULL; + + } + + out: + print_exit_status(err); + return err; + +} + +void cleanup_imap_data(struct super_block *sb) +{ + int count = 0; + struct unionfs_sb_info *spd; + + print_entry_location(); + + spd = stopd(sb); + + spd->usi_persistent = 0; + count = spd->usi_num_bmapents; + while (count - 1 >= 0) { + if (spd->usi_reversemaps[count - 1]) { + filp_close(spd->usi_reversemaps[count - 1], NULL); + spd->usi_reversemaps[count - 1] = NULL; + } + count--; + } + if (spd->usi_reversemaps) { + KFREE(spd->usi_reversemaps); + spd->usi_reversemaps = NULL; + } + + if (spd->usi_map_table) { + KFREE(spd->usi_map_table); + spd->usi_map_table = NULL; + } + + if (spd->usi_bnum_table) { + KFREE(spd->usi_bnum_table); + spd->usi_bnum_table = NULL; + } + if (spd->usi_forwardmap) { + filp_close(spd->usi_forwardmap, NULL); + spd->usi_forwardmap = NULL; + } + print_exit_location(); +} + +int parse_imap_option(struct super_block *sb, + struct unionfs_dentry_info *hidden_root_info, + char *options) +{ + int count = 0, err = 0; + char *name; + struct unionfs_sb_info *spd = NULL; + + print_entry_location(); + spd = stopd(sb); + BUG_ON(!spd); + + err = init_imap_data(sb, hidden_root_info); + if (err) + goto out_error; + while ((name = strsep(&options, ":")) != NULL) { + if (!*name) + continue; + if (!spd->usi_forwardmap) { + spd->usi_forwardmap = filp_open(name, O_RDWR, 0); + if (IS_ERR(spd->usi_forwardmap)) { + err = PTR_ERR(spd->usi_forwardmap); + spd->usi_forwardmap = NULL; + goto out_error; + } + } else { + spd->usi_reversemaps[count] = + filp_open(name, O_RDWR, 0); + if (IS_ERR(spd->usi_reversemaps[count])) { + err = PTR_ERR(spd->usi_reversemaps[count]); + spd->usi_reversemaps[count] = NULL; + goto out_error; + + } + count++; + } + } + if (count <= 0) { + printk(KERN_WARNING "unionfs: no reverse maps specified.\n"); + err = -EINVAL; + } + if (err) + goto out_error; + + /* Initialize the super block's next_avail field */ + /* Dave, you can't use 64-bit division here because the i386 doesn't + * support it natively. Instead you need to punt if the size is + * greater than unsigned long, and then cast it down. Then you should + * be able to assign to this value, without having these problems. */ + + if (spd->usi_forwardmap->f_dentry->d_inode->i_size > ULONG_MAX) { + err = -EFBIG; + goto out_error; + } + spd->usi_next_avail = + ((unsigned long)(spd->usi_forwardmap->f_dentry->d_inode-> + i_size - (sizeof(struct fmaphdr) + + sizeof(struct bmapent[256]))) + / sizeof(struct fmapent)); + + if (spd->usi_next_avail < FIRST_VALID_INODE) + spd->usi_next_avail = FIRST_VALID_INODE; + + spd->usi_num_bmapents = count; + err = verify_forwardmap(sb); + if (err) + goto out_error; + while (count > 0) { + err = verify_reversemap(sb, --count, hidden_root_info); + if (err) + goto out_error; + } + spd->usi_persistent = 1; + + goto out; + + out_error: + spd->usi_num_bmapents = count; + printk("Before cleanup_imap_data\n"); + cleanup_imap_data(sb); + printk("After cleanup_imap_data\n"); + + out: + print_exit_status(err); + return err; +} + + /* + * get @ino from @hidden_ino. + */ +static int __get_uin(struct unionfs_sb_info *sbi, ino_t hidden_ino, int bindex, + ino_t * ino) +{ + int err; + struct file *rev; + loff_t pos; + ssize_t sz; + uint64_t ino64; + const int elmnt = sizeof(ino64); + + rev = sbi->usi_map_table[bindex]; + pos = sizeof(struct rmaphdr) + elmnt * hidden_ino; + *ino = 0; + err = 0; + if (pos + elmnt > rev->f_dentry->d_inode->i_size) + goto out; + + sz = __fread(rev, &ino64, elmnt, &pos); + err = sz; + if (err < 0) + goto out; + err = 0; + *ino = -1; + if (sz != elmnt || ino64 > *ino) + err = -EIO; + *ino = ino64; + out: + print_exit_status(err); + return err; +} + +/* + * put unionfs @ino for @hidden_ino on @bindex. + */ +static int __write_uin(struct unionfs_sb_info *sbi, ino_t ino, int bindex, + ino_t hidden_ino) +{ + struct file *fwd, *rev; + struct fmapent ent; + loff_t pos; + ssize_t sz; + int err; + uint64_t ino64; + const int fwdhdr = sizeof(struct fmaphdr) + sizeof(struct bmapent[256]); + const int fwd_elmnt = sizeof(ent); + const int rev_elmnt = sizeof(ino64); + + err = -ENOSPC; + if (ino < FIRST_VALID_INODE) + goto out; + + fwd = sbi->usi_forwardmap; + ent.fsnum = sbi->usi_bnum_table[bindex]; + ent.inode = ino; + pos = fwdhdr + fwd_elmnt * hidden_ino; + sz = __fwrite(fwd, &ent, fwd_elmnt, &pos); + err = sz; + if (err < 0) + goto out; + err = -EIO; + if (sz != fwd_elmnt) + goto out; + + rev = sbi->usi_map_table[bindex]; + pos = sizeof(struct rmaphdr) + rev_elmnt * hidden_ino; + ino64 = ino; + sz = __fwrite(rev, &ino64, rev_elmnt, &pos); + err = sz; + if (err < 0) + goto out; + err = 0; + if (sz != rev_elmnt) + err = -EIO; + out: + print_exit_status(err); + return err; +} + +/* + * get_uin(struct super_block *sb, uint8_t branchnum, ino_t inode_number, int flag) + * fsnum: branch to reference when getting the inode number + * inode_number: lower level inode number use to reference the proper inode. + * flag: if set to O_CREAT it will creat the entry if it doesent exist + * otherwise it will return the existing one. + * returns: the unionfs inode number either created or retrieved based on + * the information. + */ +ino_t get_uin(struct super_block * sb, uint8_t branchnum, ino_t inode_number, + int flag) +{ + ino_t ino, err = 0; + struct unionfs_sb_info *spd; + + print_entry_location(); + + spd = stopd(sb); + BUG_ON(!spd); + + /* Find appropriate reverse map and then read from the required position */ + /* get it from the array. */ + err = __get_uin(spd, inode_number, branchnum, &ino); + if (err || ino) + goto out; + + err = -EIO; + if (!(flag & O_CREAT)) + goto out; + + /* If we haven't found an entry and we have the O_CREAT flag set we want to + * create a new entry write it out to the file and return its index + */ + ino = spd->usi_next_avail++; + down(&sb->s_lock); + err = __write_uin(spd, ino, branchnum, inode_number); + if (err) + spd->usi_next_avail--; + up(&sb->s_lock); + out: + print_exit_status((int)err); + if (!err) + err = ino; + return err; +} + +int write_uin(struct super_block *sb, ino_t ino, int bindex, ino_t hidden_ino) +{ + int err; + + print_entry_location(); + err = __write_uin(stopd(sb), ino, bindex, hidden_ino); + print_exit_status(err); + return err; +} + +/* + * get_lin(ino_t inode_number) + * inode_number : inode number for the unionfs inode + * returns: the lower level inode# and branch# + */ +/* entry should use a poiner on the stack. should be staticly allocated one + * level up*/ +int get_lin(struct super_block *sb, ino_t inode_number, struct fmapent *entry) +{ + struct file *forwardmap; + loff_t seek_size; + mm_segment_t oldfs; + int err = 0, bytesread = 0; + + print_entry_location(); + + if (!entry) { + entry = ERR_PTR(-ENOMEM); + goto out; + } + forwardmap = stopd(sb)->usi_forwardmap; + seek_size = + sizeof(struct fmaphdr) + sizeof(struct bmapent[256]) + + (sizeof(struct fmapent) * inode_number); + oldfs = get_fs(); + set_fs(KERNEL_DS); + bytesread = + forwardmap->f_op->read(forwardmap, (char __user *)entry, + sizeof(struct fmapent), &seek_size); + set_fs(oldfs); + if (bytesread != sizeof(struct fmapent)) { + entry = ERR_PTR(-EINVAL); + goto out; + } + + out: + print_exit_location(); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/print.c newtree/fs/unionfs/print.c --- oldtree/fs/unionfs/print.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/print.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: print.c,v 1.74 2006/01/13 03:00:24 jsipek Exp $ + */ + +/* Print debugging functions */ + +#ifndef UNIONFS_NDEBUG + +#include "unionfs.h" + +static int fist_debug_var = 0; + +/* get value of debugging variable */ +int fist_get_debug_value(void) +{ + return fist_debug_var; +} + +/* set debug level variable and return the previous value */ +int fist_set_debug_value(int val) +{ + int prev = fist_debug_var; + + fist_debug_var = val; + fist_dprint(1, "unionfs: setting debug level to %d\n", val); + return prev; +} + +/* + * Utilities used by both client and server + * Standard levels: + * 0) no debugging + * 1) hard failures + * 2) soft failures + * 3) current test software + * 4) main procedure entry points + * 5) main procedure exit points + * 6) utility procedure entry points + * 7) utility procedure exit points + * 8) obscure procedure entry points + * 9) obscure procedure exit points + * 10) random stuff + * 11) all <= 1 + * 12) all <= 2 + * 13) all <= 3 + * ... + */ + +void fist_dprint_internal(const char *file, const char *function, int line, + int level, char *str, ...) +{ + va_list ap; + int var = fist_get_debug_value(); + + if (level >= 10 || level < 0) { + printk(KERN_ERR "fist_dprint_internal: Invalid level passed" + "from %s:%s:%d\n", file, function, line); + } + + if (var == level || (var > 10 && (var - 10) >= level)) { + va_start(ap, str); + vprintk(str, ap); + va_end(ap); + } + return; +} + +static int num_indents = 0; +static char indent_buf[80] = + " "; +char *add_indent(void) +{ + indent_buf[num_indents] = ' '; + num_indents++; + if (num_indents > 79) + num_indents = 79; + indent_buf[num_indents] = '\0'; + return indent_buf; +} + +char *del_indent(void) +{ + if (num_indents <= 0) + return ""; + indent_buf[num_indents] = ' '; + num_indents--; + indent_buf[num_indents] = '\0'; + return indent_buf; +} + +static void fist_print_generic_inode3(const char *str, const char *str2, + const struct inode *inode) +{ + if (!inode) { + printk("PI:%s%s: NULL INODE PASSED!\n", str, str2); + return; + } + if (IS_ERR(inode)) { + printk("PI:%s%s: ERROR INODE PASSED: %ld\n", str, str2, + PTR_ERR(inode)); + return; + } + fist_dprint(8, "PI:%s%s: %s=%lu\n", str, str2, "i_ino", inode->i_ino); + fist_dprint(8, "PI:%s%s: %s=%u\n", str, str2, "i_count", + atomic_read(&inode->i_count)); + fist_dprint(8, "PI:%s%s: %s=%u\n", str, str2, "i_nlink", + inode->i_nlink); + fist_dprint(8, "PI:%s%s: %s=%o\n", str, str2, "i_mode", inode->i_mode); + fist_dprint(8, "PI:%s%s: %s=%llu\n", str, str2, "i_size", + inode->i_size); + fist_dprint(8, "PI:%s%s: %s=%p\n", str, str2, "i_op", inode->i_op); + fist_dprint(8, "PI:%s%s: %s=%p (%s)\n", str, str2, "i_sb", + inode->i_sb, (inode->i_sb ? sbt(inode->i_sb) : "NullTypeSB") + ); +} + +void fist_print_generic_inode(const char *str, const struct inode *inode) +{ + fist_print_generic_inode3(str, "", inode); +} + +void fist_print_inode(const char *str, const struct inode *inode) +{ + int bindex; + + if (!inode) { + printk("PI:%s: NULL INODE PASSED!\n", str); + return; + } + if (IS_ERR(inode)) { + printk("PI:%s: ERROR INODE PASSED: %ld\n", str, PTR_ERR(inode)); + return; + } + + if (strcmp("unionfs", sbt(inode->i_sb))) { + char msg[100]; + snprintf(msg, sizeof(msg), "Invalid inode passed to" + "fist_print_inode: %s\n", sbt(inode->i_sb)); + printk(KERN_ERR "%s\n", msg); + BUG(); + } + + fist_print_generic_inode(str, inode); + + if (!itopd(inode)) + return; + fist_dprint(8, "PI:%s: ibstart=%d, ibend=%d\n", str, + ibstart(inode), ibend(inode)); + + if (ibstart(inode) == -1) + return; + + for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) { + struct inode *hidden_inode = itohi_index(inode, bindex); + char newstr[10]; + if (!hidden_inode) { + fist_dprint(8, "PI:%s: HI#%d: NULL\n", str, bindex); + continue; + } + sprintf(newstr, ": HI%d", bindex); + fist_print_generic_inode3(str, newstr, hidden_inode); + } +} + +static void fist_print_generic_file3(const char *str, const char *str2, + const struct file *file) +{ + fist_dprint(8, "PF:%s%s: %s=0x%p\n", str, str2, "f_dentry", + file->f_dentry); + fist_dprint(8, "PF:%s%s: name=%s\n", str, str2, + file->f_dentry->d_name.name); + if (file->f_dentry->d_inode) { + fist_dprint(8, "PF:%s%s: %s=%lu\n", str, str2, + "f_dentry->d_inode->i_ino", + file->f_dentry->d_inode->i_ino); + fist_dprint(8, "PF:%s%s: %s=%o\n", str, str2, + "f_dentry->d_inode->i_mode", + file->f_dentry->d_inode->i_mode); + } + fist_dprint(8, "PF:%s%s: %s=0x%p\n", str, str2, "f_op", file->f_op); + fist_dprint(8, "PF:%s%s: %s=0x%x\n", str, str2, "f_mode", file->f_mode); + fist_dprint(8, "PF:%s%s: %s=0x%llu\n", str, str2, "f_pos", file->f_pos); + fist_dprint(8, "PF:%s%s: %s=%u\n", str, str2, "f_count", + atomic_read(&file->f_count)); + fist_dprint(8, "PF:%s%s: %s=0x%x\n", str, str2, "f_flags", + file->f_flags); + fist_dprint(8, "PF:%s%s: %s=%lu\n", str, str2, "f_version", + file->f_version); +} + +static void fist_print_generic_file(const char *str, const struct file *file) +{ + fist_print_generic_file3(str, "", file); +} + +void fist_print_file(const char *str, const struct file *file) +{ + struct file *hidden_file; + + if (!file) { + fist_dprint(8, "PF:%s: NULL FILE PASSED!\n", str); + return; + } + + if (strcmp("unionfs", sbt(file->f_dentry->d_sb))) { + char msg[100]; + snprintf(msg, sizeof(msg), "Invalid file passed to" + "fist_print_file: %s\n", sbt(file->f_dentry->d_sb)); + printk(KERN_ERR "%s\n", msg); + BUG(); + + } + + fist_print_generic_file(str, file); + + if (ftopd(file)) { + int bindex; + + fist_dprint(8, "PF:%s: fbstart=%d, fbend=%d\n", str, + fbstart(file), fbend(file)); + + for (bindex = fbstart(file); bindex <= fbend(file); bindex++) { + char newstr[10]; + hidden_file = ftohf_index(file, bindex); + if (!hidden_file) { + fist_dprint(8, "PF:%s: HF#%d is NULL\n", str, + bindex); + continue; + } + sprintf(newstr, ": HF%d", bindex); + fist_print_generic_file3(str, newstr, hidden_file); + } + } +} + +static char mode_to_type(mode_t mode) +{ + if (S_ISDIR(mode)) + return 'd'; + if (S_ISLNK(mode)) + return 'l'; + if (S_ISCHR(mode)) + return 'c'; + if (S_ISBLK(mode)) + return 'b'; + if (S_ISREG(mode)) + return 'f'; + return '?'; +} + +void __fist_print_dentry(const char *str, const struct dentry *dentry, + int check) +{ + if (!dentry) { + fist_dprint(8, "PD:%s: NULL DENTRY PASSED!\n", str); + return; + } + if (IS_ERR(dentry)) { + fist_dprint(8, "PD:%s: ERROR DENTRY (%ld)!\n", str, + PTR_ERR(dentry)); + return; + } + + if (strcmp("unionfs", sbt(dentry->d_sb))) { + char msg[100]; + snprintf(msg, sizeof(msg), "Invalid dentry passed to" + "fist_print_dentry: %s\n", sbt(dentry->d_sb)); + printk(KERN_ERR "%s\n", msg); + BUG(); + + } + + __fist_print_generic_dentry(str, "", dentry, check); + + if (!dtopd(dentry)) + return; + fist_dprint(8, "PD:%s: dbstart=%d, dbend=%d, dbopaque=%d\n", + str, dbstart(dentry), dbend(dentry), dbopaque(dentry)); + if (dbstart(dentry) != -1) { + int bindex; + char newstr[10]; + struct dentry *hidden_dentry; + + for (bindex = dbstart(dentry); bindex <= dbend(dentry); + bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + fist_dprint(8, "PD:%s: HD#%d: NULL\n", str, + bindex); + continue; + } + sprintf(newstr, ": HD%d", bindex); + fist_print_generic_dentry3(str, newstr, hidden_dentry); + } + } +} +void fist_print_dentry(const char *str, const struct dentry *dentry) +{ + __fist_print_dentry(str, dentry, 1); +} + +void __fist_print_generic_dentry(const char *str, const char *str2, const + struct dentry *dentry, int check) +{ + if (!dentry) { + fist_dprint(8, "PD:%s%s: NULL DENTRY PASSED!\n", str, str2); + return; + } + if (IS_ERR(dentry)) { + fist_dprint(8, "PD:%s%s: ERROR DENTRY (%ld)!\n", str, str2, + PTR_ERR(dentry)); + return; + } + + fist_dprint(8, "PD:%s%s: dentry = %p\n", str, str2, dentry); + fist_dprint(8, "PD:%s%s: %s=%d\n", str, str2, "d_count", + atomic_read(&dentry->d_count)); + fist_dprint(8, "PD:%s%s: %s=%x\n", str, str2, "d_flags", + (int)dentry->d_flags); + fist_dprint(8, "PD:%s%s: %s=\"%s\" (len = %d)\n", str, str2, + "d_name.name", dentry->d_name.name, dentry->d_name.len); + fist_dprint(8, "PD:%s%s: %s=%p (%s)\n", str, str2, "d_sb", dentry->d_sb, + sbt(dentry->d_sb)); + fist_dprint(8, "PD:%s%s: %s=%p\n", str, str2, "d_inode", + dentry->d_inode); + if (dentry->d_inode) { + fist_dprint(8, "PD:%s%s: %s=%ld (%s)\n", str, str2, + "d_inode->i_ino", dentry->d_inode->i_ino, + sbt(dentry->d_inode->i_sb)); + fist_dprint(8, "PD:%s%s: dentry->d_inode->i_mode: %c%o\n", str, + str2, mode_to_type(dentry->d_inode->i_mode), + dentry->d_inode->i_mode); + } + fist_dprint(8, "PD:%s%s: %s=%p (%s)\n", str, str2, "d_parent", + dentry->d_parent, + (dentry->d_parent ? sbt(dentry->d_parent->d_sb) : "nil")); + fist_dprint(8, "PD:%s%s: %s=\"%s\"\n", str, str2, + "d_parent->d_name.name", dentry->d_parent->d_name.name); + fist_dprint(8, "PD:%s%s: %s=%d\n", str, str2, "d_parent->d_count", + atomic_read(&dentry->d_parent->d_count)); + fist_dprint(8, "PD:%s%s: %s=%p\n", str, str2, "d_op", dentry->d_op); + fist_dprint(8, "PD:%s%s: %s=%p\n", str, str2, "d_fsdata", + dentry->d_fsdata); + fist_dprint(8, "PD:%s%s: %s=%d\n", str, str2, "hlist_unhashed(d_hash)", + hlist_unhashed(&((struct dentry *)dentry)->d_hash)); + /* After we have printed it, we can assert something about it. */ + if (check) + BUG_ON(atomic_read(&dentry->d_count) <= 0); +} + +void fist_print_generic_dentry(const char *str, const struct dentry *dentry) +{ + __fist_print_generic_dentry(str, "", dentry, 1); +} +void fist_print_generic_dentry3(const char *str, const char *str2, + const struct dentry *dentry) +{ + __fist_print_generic_dentry(str, str2, dentry, 1); +} + +void fist_checkinode(const struct inode *inode, const char *msg) +{ + if (!inode) { + printk(KERN_WARNING "fist_checkinode - inode is NULL! (%s)\n", + msg); + return; + } + if (!itopd(inode)) { + fist_dprint(8, "fist_checkinode(%ld) - no private data (%s)\n", + inode->i_ino, msg); + return; + } + if ((itopd(inode)->b_start < 0) || !itohi(inode)) { + fist_dprint(8, + "fist_checkinode(%ld) - underlying is NULL! (%s)\n", + inode->i_ino, msg); + return; + } + if (!inode->i_sb) { + fist_dprint(8, + "fist_checkinode(%ld) - inode->i_sb is NULL! (%s)\n", + inode->i_ino, msg); + return; + } + fist_dprint(8, "inode->i_sb->s_type %p\n", inode->i_sb->s_type); + if (!inode->i_sb->s_type) { + fist_dprint(8, + "fist_checkinode(%ld) - inode->i_sb->s_type is NULL! (%s)\n", + inode->i_ino, msg); + return; + } + fist_dprint(6, + "CI: %s: inode->i_count = %d, hidden_inode->i_count = %d, inode = %lu, sb = %s, hidden_sb = %s\n", + msg, atomic_read(&inode->i_count), + itopd(inode)->b_start >= + 0 ? atomic_read(&itohi(inode)->i_count) : -1, inode->i_ino, + inode->i_sb->s_type->name, + itopd(inode)->b_start >= + 0 ? itohi(inode)->i_sb->s_type->name : "(none)"); +} + +void fist_print_sb(const char *str, const struct super_block *sb) +{ + struct super_block *hidden_superblock; + + if (!sb) { + fist_dprint(8, "PSB:%s: NULL SB PASSED!\n", str); + return; + } + + fist_dprint(8, "PSB:%s: %s=%u\n", str, "s_blocksize", + (int)sb->s_blocksize); + fist_dprint(8, "PSB:%s: %s=%u\n", str, "s_blocksize_bits", + (int)sb->s_blocksize_bits); + fist_dprint(8, "PSB:%s: %s=0x%x\n", str, "s_flags", (int)sb->s_flags); + fist_dprint(8, "PSB:%s: %s=0x%x\n", str, "s_magic", (int)sb->s_magic); + fist_dprint(8, "PSB:%s: %s=%llu\n", str, "s_maxbytes", sb->s_maxbytes); + fist_dprint(8, "PSB:%s: %s=%d\n", str, "s_count", (int)sb->s_count); + fist_dprint(8, "PSB:%s: %s=%d\n", str, "s_active", + (int)atomic_read(&sb->s_active)); + if (stopd(sb)) + fist_dprint(8, "sbstart=%d, sbend=%d\n", sbstart(sb), + sbend(sb)); + fist_dprint(8, "\n"); + + if (stopd(sb)) { + int bindex; + for (bindex = sbstart(sb); bindex <= sbend(sb); bindex++) { + hidden_superblock = stohs_index(sb, bindex); + if (!hidden_superblock) { + fist_dprint(8, "PSB:%s: HS#%d is NULL", str, + bindex); + continue; + } + + fist_dprint(8, "PSB:%s: HS#%d: %s=%u\n", str, bindex, + "s_blocksize", + (int)hidden_superblock->s_blocksize); + fist_dprint(8, "PSB:%s: HS#%d: %s=%u\n", str, bindex, + "s_blocksize_bits", + (int)hidden_superblock->s_blocksize_bits); + fist_dprint(8, "PSB:%s: HS#%d: %s=0x%x\n", str, bindex, + "s_flags", (int)hidden_superblock->s_flags); + fist_dprint(8, "PSB:%s: HS#%d: %s=0x%x\n", str, bindex, + "s_magic", (int)hidden_superblock->s_magic); + fist_dprint(8, "PSB:%s: HS#%d: %s=%llu\n", str, bindex, + "s_maxbytes", + hidden_superblock->s_maxbytes); + fist_dprint(8, "PSB:%s: HS#%d: %s=%d\n", str, bindex, + "s_count", (int)hidden_superblock->s_count); + fist_dprint(8, "PSB:%s: HS#%d: %s=%d\n", str, bindex, + "s_active", + (int)atomic_read(&hidden_superblock-> + s_active)); + } + } +} + +#endif +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/rdstate.c newtree/fs/unionfs/rdstate.c --- oldtree/fs/unionfs/rdstate.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/rdstate.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: rdstate.c,v 1.31 2006/01/14 19:56:01 dquigley Exp $ + */ + +#include "unionfs.h" + +/* This file contains the routines for maintaining readdir state. */ +/* There are two structures here, rdstate which is a hash table + * of the second structure which is a filldir_node. */ + +/* This is a kmem_cache_t for filldir nodes, because we allocate a lot of them + * and they shouldn't waste memory. If the node has a small name (as defined + * by the dentry structure), then we use an inline name to preserve kmalloc + * space. */ +static kmem_cache_t *unionfs_filldir_cachep; +int init_filldir_cache(void) +{ + unionfs_filldir_cachep = + kmem_cache_create("unionfs_filldir", sizeof(struct filldir_node), 0, + SLAB_RECLAIM_ACCOUNT, NULL, NULL); + + if (!unionfs_filldir_cachep) { + return -ENOMEM; + } + return 0; +} + +void destroy_filldir_cache(void) +{ + if (!unionfs_filldir_cachep) + return; + if (kmem_cache_destroy(unionfs_filldir_cachep)) { + printk(KERN_ERR + "unionfs_filldir_cache: not all structures were freed\n"); + } + return; +} + +/* This is a tuning parameter that tells us roughly how big to make the + * hash table in directory entries per page. This isn't perfect, but + * at least we get a hash table size that shouldn't be too overloaded. + * The following averages are based on my home directory. + * 14.44693 Overall + * 12.29 Single Page Directories + * 117.93 Multi-page directories + */ +#define DENTPAGE 4096 +#define DENTPERONEPAGE 12 +#define DENTPERPAGE 118 +#define MINHASHSIZE 1 +static int guesstimate_hash_size(struct inode *inode) +{ + struct inode *hidden_inode; + int bindex; + int hashsize = MINHASHSIZE; + + if (itopd(inode)->uii_hashsize > 0) + return itopd(inode)->uii_hashsize; + + for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) { + if (!(hidden_inode = itohi_index(inode, bindex))) + continue; + + if (hidden_inode->i_size == DENTPAGE) { + hashsize += DENTPERONEPAGE; + } else { + hashsize += + (hidden_inode->i_size / DENTPAGE) * DENTPERPAGE; + } + } + + return hashsize; +} + +int init_rdstate(struct file *file) +{ + BUG_ON(sizeof(loff_t) != (sizeof(unsigned int) + sizeof(unsigned int))); + BUG_ON(ftopd(file)->rdstate != NULL); + + ftopd(file)->rdstate = + alloc_rdstate(file->f_dentry->d_inode, fbstart(file)); + if (!ftopd(file)->rdstate) + return -ENOMEM; + return 0; +} + +struct unionfs_dir_state *find_rdstate(struct inode *inode, loff_t fpos) +{ + struct unionfs_dir_state *rdstate = NULL; + struct list_head *pos; + + print_entry("f_pos: %lld", fpos); + spin_lock(&itopd(inode)->uii_rdlock); + list_for_each(pos, &itopd(inode)->uii_readdircache) { + struct unionfs_dir_state *r = + list_entry(pos, struct unionfs_dir_state, uds_cache); + if (fpos == rdstate2offset(r)) { + itopd(inode)->uii_rdcount--; + list_del(&r->uds_cache); + rdstate = r; + break; + } + } + spin_unlock(&itopd(inode)->uii_rdlock); + print_exit_pointer(rdstate); + return rdstate; +} + +struct unionfs_dir_state *alloc_rdstate(struct inode *inode, int bindex) +{ + int i = 0; + int hashsize; + int mallocsize = sizeof(struct unionfs_dir_state); + struct unionfs_dir_state *rdstate; + + hashsize = guesstimate_hash_size(inode); + mallocsize += hashsize * sizeof(struct list_head); + /* Round it up to the next highest power of two. */ + mallocsize--; + mallocsize |= mallocsize >> 1; + mallocsize |= mallocsize >> 2; + mallocsize |= mallocsize >> 4; + mallocsize |= mallocsize >> 8; + mallocsize |= mallocsize >> 16; + mallocsize++; + + /* This should give us about 500 entries anyway. */ + if (mallocsize > PAGE_SIZE) + mallocsize = PAGE_SIZE; + + hashsize = + (mallocsize - + sizeof(struct unionfs_dir_state)) / sizeof(struct list_head); + + rdstate = KMALLOC(mallocsize, GFP_KERNEL); + if (!rdstate) + return NULL; + + spin_lock(&itopd(inode)->uii_rdlock); + if (itopd(inode)->uii_cookie >= (MAXRDCOOKIE - 1)) + itopd(inode)->uii_cookie = 1; + else + itopd(inode)->uii_cookie++; + + rdstate->uds_cookie = itopd(inode)->uii_cookie; + spin_unlock(&itopd(inode)->uii_rdlock); + rdstate->uds_offset = 1; + rdstate->uds_access = jiffies; + rdstate->uds_bindex = bindex; + rdstate->uds_dirpos = 0; + rdstate->uds_hashentries = 0; + rdstate->uds_size = hashsize; + for (i = 0; i < rdstate->uds_size; i++) + INIT_LIST_HEAD(&rdstate->uds_list[i]); + + return rdstate; +} + +static void free_filldir_node(struct filldir_node *node) +{ + if (node->namelen >= DNAME_INLINE_LEN_MIN) + KFREE(node->name); + kmem_cache_free(unionfs_filldir_cachep, node); +} + +void free_rdstate(struct unionfs_dir_state *state) +{ + struct filldir_node *tmp; + int i; + + for (i = 0; i < state->uds_size; i++) { + struct list_head *head = &(state->uds_list[i]); + struct list_head *pos, *n; + + /* traverse the list and deallocate space */ + list_for_each_safe(pos, n, head) { + tmp = list_entry(pos, struct filldir_node, file_list); + list_del(&tmp->file_list); + free_filldir_node(tmp); + } + } + + KFREE(state); +} + +struct filldir_node *find_filldir_node(struct unionfs_dir_state *rdstate, + const char *name, int namelen) +{ + int index; + unsigned int hash; + struct list_head *head; + struct list_head *pos; + struct filldir_node *cursor = NULL; + int found = 0; + + /* If we print entry, we end up with spurious data. */ + /* print_entry("name = %*s", namelen, name); */ + print_entry_location(); + + BUG_ON(namelen <= 0); + + hash = full_name_hash(name, namelen); + index = hash % rdstate->uds_size; + + head = &(rdstate->uds_list[index]); + list_for_each(pos, head) { + cursor = list_entry(pos, struct filldir_node, file_list); + + if (cursor->namelen == namelen && cursor->hash == hash + && !strncmp(cursor->name, name, namelen)) { + /* a duplicate exists, and hence no need to create entry to the list */ + found = 1; + /* if the duplicate is in this branch, then the file system is corrupted. */ + if (cursor->bindex == rdstate->uds_bindex) { + //buf->error = err = -EIO; + fist_dprint(8, + "Possible I/O error unionfs_filldir: a file is duplicated in the same branch %d: %s\n", + rdstate->uds_bindex, cursor->name); + } + break; + } + } + + if (!found) { + cursor = NULL; + } + print_exit_pointer(cursor); + return cursor; +} + +inline struct filldir_node *alloc_filldir_node(const char *name, int namelen, + unsigned int hash, int bindex) +{ + struct filldir_node *newnode; + + newnode = + (struct filldir_node *)kmem_cache_alloc(unionfs_filldir_cachep, + SLAB_KERNEL); + if (!newnode) + goto out; + + out: + return newnode; +} + +int add_filldir_node(struct unionfs_dir_state *rdstate, const char *name, + int namelen, int bindex, int whiteout) +{ + struct filldir_node *new; + unsigned int hash; + int index; + int err = 0; + struct list_head *head; + + /* We can't print this because we end up Oopsing. */ + /* print_entry("name = %*s", namelen, name); */ + print_entry_location(); + + BUG_ON(namelen <= 0); + + hash = full_name_hash(name, namelen); + index = hash % rdstate->uds_size; + head = &(rdstate->uds_list[index]); + + new = alloc_filldir_node(name, namelen, hash, bindex); + if (!new) { + err = -ENOMEM; + goto out; + } + + INIT_LIST_HEAD(&new->file_list); + new->namelen = namelen; + new->hash = hash; + new->bindex = bindex; + new->whiteout = whiteout; + + if (namelen < DNAME_INLINE_LEN_MIN) { + new->name = new->iname; + } else { + new->name = (char *)KMALLOC(namelen + 1, GFP_KERNEL); + if (!new->name) { + kmem_cache_free(unionfs_filldir_cachep, new); + new = NULL; + goto out; + } + } + + memcpy(new->name, name, namelen); + new->name[namelen] = '\0'; + + rdstate->uds_hashentries++; + + list_add(&(new->file_list), head); + out: + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/rename.c newtree/fs/unionfs/rename.c --- oldtree/fs/unionfs/rename.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/rename.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,843 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: rename.c,v 1.38 2006/01/14 19:56:01 dquigley Exp $ + */ + +#include "unionfs.h" + +static int do_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + int bindex) +{ + int err = 0; + struct dentry *hidden_old_dentry; + struct dentry *hidden_new_dentry; + struct dentry *hidden_old_dir_dentry; + struct dentry *hidden_new_dir_dentry; + struct dentry *hidden_wh_dentry; + struct dentry *hidden_wh_dir_dentry; + char *wh_name = NULL; + + print_entry(" bindex=%d", bindex); + + fist_print_dentry("IN: do_rename, old_dentry", old_dentry); + fist_print_dentry("IN: do_rename, new_dentry", new_dentry); + fist_dprint(7, "do_rename for bindex = %d\n", bindex); + + hidden_new_dentry = dtohd_index(new_dentry, bindex); + hidden_old_dentry = dtohd_index(old_dentry, bindex); + + if (!hidden_new_dentry) { + hidden_new_dentry = + create_parents(new_dentry->d_parent->d_inode, new_dentry, + bindex); + if (IS_ERR(hidden_new_dentry)) { + fist_dprint(7, + "error creating directory tree for rename, bindex = %d\n", + bindex); + err = PTR_ERR(hidden_new_dentry); + goto out; + } + } + + wh_name = alloc_whname(new_dentry->d_name.name, new_dentry->d_name.len); + if (IS_ERR(wh_name)) { + err = PTR_ERR(wh_name); + goto out; + } + + hidden_wh_dentry = + LOOKUP_ONE_LEN(wh_name, hidden_new_dentry->d_parent, + new_dentry->d_name.len + WHLEN); + if (IS_ERR(hidden_wh_dentry)) { + err = PTR_ERR(hidden_wh_dentry); + goto out; + } + + if (hidden_wh_dentry->d_inode) { + /* get rid of the whiteout that is existing */ + if (hidden_new_dentry->d_inode) { + printk(KERN_WARNING + "Both a whiteout and a dentry exist when doing a rename!\n"); + err = -EIO; + + DPUT(hidden_wh_dentry); + goto out; + } + + hidden_wh_dir_dentry = lock_parent(hidden_wh_dentry); + if (!(err = is_robranch_super(old_dentry->d_sb, bindex))) { + err = + vfs_unlink(hidden_wh_dir_dentry->d_inode, + hidden_wh_dentry); + } + DPUT(hidden_wh_dentry); + unlock_dir(hidden_wh_dir_dentry); + if (err) + goto out; + } else + DPUT(hidden_wh_dentry); + + DGET(hidden_old_dentry); + hidden_old_dir_dentry = GET_PARENT(hidden_old_dentry); + hidden_new_dir_dentry = GET_PARENT(hidden_new_dentry); + + lock_rename(hidden_old_dir_dentry, hidden_new_dir_dentry); + + if (!(err = is_robranch_super(old_dentry->d_sb, bindex))) { + fist_print_dentry("NEWBEF", new_dentry); + fist_print_dentry("OLDBEF", old_dentry); + err = + vfs_rename(hidden_old_dir_dentry->d_inode, + hidden_old_dentry, + hidden_new_dir_dentry->d_inode, + hidden_new_dentry); + fist_print_dentry("NEWAFT", new_dentry); + fist_print_dentry("OLDAFT", old_dentry); + } + + unlock_rename(hidden_old_dir_dentry, hidden_new_dir_dentry); + + DPUT(hidden_old_dir_dentry); + DPUT(hidden_new_dir_dentry); + DPUT(hidden_old_dentry); + + out: + if (!err) { + /* Fixup the newdentry. */ + if (bindex < dbstart(new_dentry)) + set_dbstart(new_dentry, bindex); + else if (bindex > dbend(new_dentry)) + set_dbend(new_dentry, bindex); + } + + KFREE(wh_name); + + fist_print_dentry("OUT: do_rename, old_dentry", old_dentry); + fist_print_dentry("OUT: do_rename, new_dentry", new_dentry); + + print_exit_status(err); + return err; +} + +static int unionfs_rename_whiteout(struct inode *old_dir, + struct dentry *old_dentry, + struct inode *new_dir, + struct dentry *new_dentry) +{ + int err = 0; + int bindex; + int old_bstart, old_bend; + int new_bstart, new_bend; + int do_copyup = -1; + struct dentry *parent_dentry = NULL; + int local_err = 0; + int eio = 0; + int revert = 0; + + print_entry_location(); + + old_bstart = dbstart(old_dentry); + old_bend = dbend(old_dentry); + parent_dentry = old_dentry->d_parent; + + new_bstart = dbstart(new_dentry); + new_bend = dbend(new_dentry); + + /* Rename source to destination. */ + err = do_rename(old_dir, old_dentry, new_dir, new_dentry, old_bstart); + if (err) { + if (!IS_COPYUP_ERR(err)) { + goto out; + } + do_copyup = old_bstart - 1; + } else { + revert = 1; + } + + /* Unlink all instances of destination that exist to the left of + * bstart of source. On error, revert back, goto out. + */ + for (bindex = old_bstart - 1; bindex >= new_bstart; bindex--) { + struct dentry *unlink_dentry; + struct dentry *unlink_dir_dentry; + + unlink_dentry = dtohd_index(new_dentry, bindex); + if (!unlink_dentry) { + continue; + } + + unlink_dir_dentry = lock_parent(unlink_dentry); + if (!(err = is_robranch_super(old_dir->i_sb, bindex))) { + err = + vfs_unlink(unlink_dir_dentry->d_inode, + unlink_dentry); + } + + fist_copy_attr_times(new_dentry->d_parent->d_inode, + unlink_dir_dentry->d_inode); + /* propagate number of hard-links */ + new_dentry->d_parent->d_inode->i_nlink = + get_nlinks(new_dentry->d_parent->d_inode); + + unlock_dir(unlink_dir_dentry); + if (!err) { + if (bindex != new_bstart) { + DPUT(unlink_dentry); + set_dtohd_index(new_dentry, bindex, NULL); + } + } else if (IS_COPYUP_ERR(err)) { + do_copyup = bindex - 1; + } else if (revert) { + goto revert; + } + } + + if (do_copyup != -1) { + for (bindex = do_copyup; bindex >= 0; bindex--) { + /* copyup the file into some left directory, so that you can rename it */ + err = + copyup_dentry(old_dentry->d_parent->d_inode, + old_dentry, old_bstart, bindex, NULL, + old_dentry->d_inode->i_size); + if (!err) { + parent_dentry = old_dentry->d_parent; + err = + do_rename(old_dir, old_dentry, new_dir, + new_dentry, bindex); + } + } + } + + /* Create whiteout for source, only if: + * (1) There is more than one underlying instance of source. + * (2) We did a copy_up + */ + if ((old_bstart != old_bend) || (do_copyup != -1)) { + int start = (do_copyup == -1) ? old_bstart : do_copyup; + /* we want to create a whiteout for name in this parent dentry */ + local_err = create_whiteout(old_dentry, start); + if (local_err) { + /* We can't fix anything now, so we cop-out and use -EIO. */ + printk + ("<0>We can't create a whiteout for the source in rename!\n"); + err = -EIO; + goto out; + } + } + + out: + + print_exit_status(err); + return err; + + revert: + /* Do revert here. */ + local_err = unionfs_refresh_hidden_dentry(new_dentry, old_bstart); + if (local_err) { + printk(KERN_WARNING + "Revert failed in rename: the new refresh failed.\n"); + eio = -EIO; + } + + local_err = unionfs_refresh_hidden_dentry(old_dentry, old_bstart); + if (local_err) { + printk(KERN_WARNING + "Revert failed in rename: the old refresh failed.\n"); + eio = -EIO; + goto revert_out; + } + + if (!dtohd_index(new_dentry, bindex) + || !dtohd_index(new_dentry, bindex)->d_inode) { + printk(KERN_WARNING + "Revert failed in rename: the object disappeared from under us!\n"); + eio = -EIO; + goto revert_out; + } + + if (dtohd_index(old_dentry, bindex) + && dtohd_index(old_dentry, bindex)->d_inode) { + printk(KERN_WARNING + "Revert failed in rename: the object was created underneath us!\n"); + eio = -EIO; + goto revert_out; + } + + local_err = + do_rename(new_dir, new_dentry, old_dir, old_dentry, old_bstart); + + /* If we can't fix it, then we cop-out with -EIO. */ + if (local_err) { + printk(KERN_WARNING "Revert failed in rename!\n"); + eio = -EIO; + } + + local_err = unionfs_refresh_hidden_dentry(new_dentry, bindex); + if (local_err) + eio = -EIO; + local_err = unionfs_refresh_hidden_dentry(old_dentry, bindex); + if (local_err) + eio = -EIO; + + revert_out: + if (eio) + err = eio; + print_exit_status(err); + return err; +} + +/* + * Unfortunately, we cannot simply call things like dbstart() in different + * places of the rename code because we move things around. So, we use this + * structure to pass the necessary information around to all the places that + * need it. + */ +struct rename_info { + int do_copyup; + int do_whiteout; + int rename_ok; + + int old_bstart; + int old_bend; + int new_bstart; + int new_bend; + + int isdir; /* Is the source a directory? */ + int clobber; /* Are we clobbering the destination? */ +}; + +/* + * Rename all occurences of source except for the leftmost destination + */ +static int __rename_all(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + fd_set * success_mask, struct rename_info *info) +{ + int bindex; + + int err = 0; + + print_entry_location(); + + /* Loop through all the branches from right to left and rename all + * instances of source to destination, except the leftmost destination + */ + for (bindex = info->old_bend; bindex >= info->old_bstart; bindex--) { + /* We don't rename if there is no source. */ + if (dtohd_index(old_dentry, bindex) == NULL) + continue; + + /* we rename the bstart of destination only at the last of + * all operations, so that we don't lose it on error + */ + if (info->clobber && (bindex == info->new_bstart)) + continue; + + /* We shouldn't have a handle on this if there is no inode. */ + err = + do_rename(old_dir, old_dentry, new_dir, new_dentry, bindex); + if (!err) { + /* For reverting. */ + FD_SET(bindex, success_mask); + /* So we know not to copyup on failures the right */ + info->rename_ok = bindex; + } else if (IS_COPYUP_ERR(err)) { + if (info->isdir) { + err = -EXDEV; + break; + } + + /* we need a whiteout... */ + info->do_whiteout = bindex - 1; + + if (bindex == info->old_bstart) + /* ...and a copyup */ + info->do_copyup = bindex - 1; + + err = 0; /* reset error */ + } else + break; /* error is set by do_rename */ + } + + print_exit_status(err); + return err; +} + +/* + * Unlink all destinations (if they exist) to the left of the left-most + * source + */ +static int __rename_all_unlink(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + struct rename_info *info) +{ + int bindex; + + struct dentry *unlink_dentry; + struct dentry *unlink_dir_dentry; + + int err = 0; + + print_entry_location(); + + for (bindex = info->old_bstart - 1; bindex > info->new_bstart; bindex--) { + unlink_dentry = dtohd_index(new_dentry, bindex); + if (!unlink_dentry) + continue; + + /* lock, unlink if possible, copyup times, unlock */ + unlink_dir_dentry = lock_parent(unlink_dentry); + if (!(err = is_robranch_super(old_dir->i_sb, bindex))) + err = + vfs_unlink(unlink_dir_dentry->d_inode, + unlink_dentry); + + fist_copy_attr_times(new_dentry->d_parent->d_inode, + unlink_dir_dentry->d_inode); + new_dentry->d_parent->d_inode->i_nlink = + get_nlinks(new_dentry->d_parent->d_inode); + + unlock_dir(unlink_dir_dentry); + + if (!err) { + if (bindex != info->new_bstart) { + DPUT(unlink_dentry); + set_dtohd_index(new_dentry, bindex, NULL); + } + } else if (IS_COPYUP_ERR(err)) { + if (info->isdir) { + err = -EXDEV; + break; + } + info->do_copyup = bindex - 1; + + err = 0; /* reset error */ + } else + break; /* err is set by is_ro_branch_super or vfs_unlink */ + } + + print_exit_status(err); + return err; +} + +/* + * Try to revert everything we have done in __rename_all and __rename_all_unlink + */ +static int __rename_all_revert(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + fd_set * success_mask, struct rename_info *info) +{ + int bindex; + + int err; + int eio = 0; + + print_entry_location(); + + for (bindex = info->old_bstart; bindex <= info->old_bend; bindex++) { + if (!FD_ISSET(bindex, success_mask)) + continue; + + err = unionfs_refresh_hidden_dentry(new_dentry, bindex); + if (err) { + printk(KERN_WARNING "Revert failed in rename: " + "the new refresh failed.\n"); + eio = -EIO; + } + + err = unionfs_refresh_hidden_dentry(old_dentry, bindex); + if (err) { + printk(KERN_WARNING "Revert failed in rename: " + "the old refresh failed.\n"); + eio = -EIO; + continue; + } + + if (!dtohd_index(new_dentry, bindex) + || !dtohd_index(new_dentry, bindex)->d_inode) { + printk(KERN_WARNING "Revert failed in rename: " + "the object disappeared from under us!\n"); + eio = -EIO; + continue; + } + + if (dtohd_index(old_dentry, bindex) + && dtohd_index(old_dentry, bindex)->d_inode) { + printk(KERN_WARNING "Revert failed in rename: " + "the object was created underneath us!\n"); + eio = -EIO; + continue; + } + + err = + do_rename(new_dir, new_dentry, old_dir, old_dentry, bindex); + /* If we can't fix it, then we cop-out with -EIO. */ + if (err) { + printk(KERN_WARNING "Revert failed in rename!\n"); + eio = -EIO; + } + + err = unionfs_refresh_hidden_dentry(new_dentry, bindex); + if (err) + eio = -EIO; + err = unionfs_refresh_hidden_dentry(old_dentry, bindex); + if (err) + eio = -EIO; + } + + print_exit_status(eio); + return eio; +} + +/* + * Finish off the rename, by either over writing the last destination or + * unlinking the last destination to the left of us + */ +static int __rename_all_clobber(struct inode *old_dir, + struct dentry *old_dentry, + struct inode *new_dir, + struct dentry *new_dentry, + struct rename_info *info) +{ + int err = 0; + + print_entry_location(); + + if (dtohd_index(old_dentry, info->new_bstart)) { + /* rename the last source, knowing we're overwriting something */ + err = + do_rename(old_dir, old_dentry, new_dir, new_dentry, + info->new_bstart); + if (IS_COPYUP_ERR(err)) { + if (info->isdir) { + err = -EXDEV; + goto out; + } + if (info->rename_ok > info->new_bstart) { + if ((info->do_copyup == -1) + || (info->new_bstart - 1 < info->do_copyup)) + info->do_copyup = info->new_bstart - 1; + } + if ((info->do_whiteout == -1) + || (info->new_bstart - 1 < info->do_whiteout)) { + info->do_whiteout = info->new_bstart - 1; + } + err = 0; // reset error + } + } else if (info->new_bstart < info->old_bstart) { + /* the newly renamed file would get hidden, let's unlink the + * file to the left of it */ + struct dentry *unlink_dentry; + struct dentry *unlink_dir_dentry; + + unlink_dentry = dtohd_index(new_dentry, info->new_bstart); + + unlink_dir_dentry = lock_parent(unlink_dentry); + if (!(err = is_robranch_super(old_dir->i_sb, info->new_bstart))) + err = vfs_unlink(unlink_dir_dentry->d_inode, + unlink_dentry); + + fist_copy_attr_times(new_dentry->d_parent->d_inode, + unlink_dir_dentry->d_inode); + new_dentry->d_parent->d_inode->i_nlink = + get_nlinks(new_dentry->d_parent->d_inode); + + unlock_dir(unlink_dir_dentry); + + if (IS_COPYUP_ERR(err)) { + if (info->isdir) { + err = -EXDEV; + goto out; + } + if ((info->do_copyup == -1) + || (info->new_bstart - 1 < info->do_copyup)) + info->do_copyup = info->new_bstart - 1; + + err = 0; // reset error + } + } + + out: + print_exit_status(err); + return err; +} + +/* + * The function is nasty, nasty, nasty, but so is rename. :( + */ +static int unionfs_rename_all(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct dentry *parent_dentry = NULL; + int err = 0; + int eio; + + /* These variables control error handling. */ + fd_set success_mask; + char *name = NULL; + + /* unfortunately, we have to resort to this, because dbstart/dbend would + return different things in different place of the rename code */ + struct rename_info info; + + info.rename_ok = FD_SETSIZE; /* The last rename that is ok. */ + info.do_copyup = -1; /* Where we should start copyup. */ + info.do_whiteout = -1; /* Where we should start whiteouts of the source. */ + + print_entry_location(); + + parent_dentry = old_dentry->d_parent; + name = KMALLOC(old_dentry->d_name.len + 1, GFP_KERNEL); + if (!name) { + err = -ENOMEM; + goto out; + } + strncpy(name, old_dentry->d_name.name, old_dentry->d_name.len + 1); + + info.new_bstart = dbstart(new_dentry); + info.new_bend = dbend(new_dentry); + + info.old_bstart = dbstart(old_dentry); + info.old_bend = dbend(old_dentry); + + BUG_ON(info.new_bstart < 0); + BUG_ON(info.old_bstart < 0); + + /* The failure mask only can deal with FD_SETSIZE entries. */ + BUG_ON(info.old_bend > FD_SETSIZE); + BUG_ON(info.new_bend > FD_SETSIZE); + FD_ZERO(&success_mask); + + /* Life is simpler if the dentry doesn't exist. */ + info.clobber = + (dtohd_index(new_dentry, info.new_bstart)->d_inode) ? 1 : 0; + info.isdir = S_ISDIR(old_dentry->d_inode->i_mode); + + /* rename everything we can */ + err = + __rename_all(old_dir, old_dentry, new_dir, new_dentry, + &success_mask, &info); + if (err) + goto revert; + + /* unlink destinations even further left */ + err = + __rename_all_unlink(old_dir, old_dentry, new_dir, new_dentry, + &info); + if (err) + goto revert; + + if (info.clobber) { + /* Now we need to handle the leftmost of the destination. */ + err = + __rename_all_clobber(old_dir, old_dentry, new_dir, + new_dentry, &info); + if (err) + goto revert; + } + + /* Create a whiteout for the source. */ + if (info.do_whiteout != -1) { + BUG_ON(info.do_whiteout < 0); + /* create a lookup in the old_dentry's actual parent */ + lock_dentry(parent_dentry); + err = + create_whiteout_parent(parent_dentry, name, + info.do_whiteout); + unlock_dentry(parent_dentry); + if (err) { + /* We can't fix anything now, so we -EIO. */ + printk(KERN_WARNING "We can't create a whiteout for the" + "source in rename!\n"); + err = -EIO; + goto out; + } + } + + /* Copy up if necessary */ + if (info.do_copyup != -1) { + int bindex; + + /* We can't copyup a directory, because it may involve huge + * numbers of children, etc. Doing that in the kernel would + * be bad, so instead we let the userspace recurse and ask us + * to copy up each file separately + */ + if (S_ISDIR(old_dentry->d_inode->i_mode)) { + err = -EXDEV; + goto out; + } + + for (bindex = info.do_copyup; bindex >= 0; bindex--) { + err = + copyup_dentry(old_dentry->d_parent->d_inode, + old_dentry, info.old_bstart, bindex, + NULL, old_dentry->d_inode->i_size); + if (!err) + err = + do_rename(old_dir, old_dentry, new_dir, + new_dentry, bindex); + } + } + + /* We are at the point where reverting doesn't happen. */ + goto out; + + revert: + /* something bad happened, try to revert */ + eio = + __rename_all_revert(old_dir, old_dentry, new_dir, new_dentry, + &success_mask, &info); + if (eio) + err = eio; + + out: + KFREE(name); + print_exit_status(err); + return err; +} + +static struct dentry *lookup_whiteout(struct dentry *dentry) +{ + char *whname; + int bindex = -1, bstart = -1, bend = -1; + struct dentry *parent, *hidden_parent, *wh_dentry; + + whname = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(whname)) + return (void *)whname; + + parent = GET_PARENT(dentry); + lock_dentry(parent); + bstart = dbstart(parent); + bend = dbend(parent); + wh_dentry = ERR_PTR(-ENOENT); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_parent = dtohd_index(parent, bindex); + if (!hidden_parent) + continue; + wh_dentry = + LOOKUP_ONE_LEN(whname, hidden_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(wh_dentry)) + continue; + if (wh_dentry->d_inode) + break; + DPUT(wh_dentry); + wh_dentry = ERR_PTR(-ENOENT); + } + unlock_dentry(parent); + DPUT(parent); + KFREE(whname); + return wh_dentry; +} + +int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + int err = 0; + struct dentry *wh_dentry; + + print_entry_location(); + + double_lock_dentry(old_dentry, new_dentry); + + fist_checkinode(old_dir, "unionfs_rename-old_dir"); + fist_checkinode(new_dir, "unionfs_rename-new_dir"); + fist_print_dentry("IN: unionfs_rename, old_dentry", old_dentry); + fist_print_dentry("IN: unionfs_rename, new_dentry", new_dentry); + + err = unionfs_partial_lookup(old_dentry); + if (err) + goto out; + err = unionfs_partial_lookup(new_dentry); + if (err) + goto out; + + /* + * if new_dentry is already hidden because of whiteout, + * simply override it even if the whiteouted dir is not empty. + */ + wh_dentry = lookup_whiteout(new_dentry); + if (!IS_ERR(wh_dentry)) + DPUT(wh_dentry); + else if (new_dentry->d_inode) { + if (S_ISDIR(old_dentry->d_inode->i_mode) != + S_ISDIR(new_dentry->d_inode->i_mode)) { + err = + S_ISDIR(old_dentry->d_inode-> + i_mode) ? -ENOTDIR : -EISDIR; + goto out; + } + + if (S_ISDIR(old_dentry->d_inode->i_mode)) { + /* check if this unionfs directory is empty or not */ + err = check_empty(new_dentry, NULL); + if (err) + goto out; + /* Handle the case where we are overwriting directories + * that are not really empty because of whiteout or + * non-whiteout entries. + */ + } + } + + if (IS_SET(old_dir->i_sb, DELETE_WHITEOUT)) { + /* create whiteout */ + err = unionfs_rename_whiteout(old_dir, old_dentry, new_dir, + new_dentry); + } else { + /* delete all. */ + err = unionfs_rename_all(old_dir, old_dentry, new_dir, + new_dentry); + } + + out: + fist_checkinode(new_dir, "post unionfs_rename-new_dir"); + fist_print_dentry("OUT: unionfs_rename, old_dentry", old_dentry); + + if (err) { + /* clear the new_dentry stuff created */ + d_drop(new_dentry); + } else + fist_print_dentry("OUT: unionfs_rename, new_dentry", + new_dentry); + + unlock_dentry(new_dentry); + unlock_dentry(old_dentry); + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/stale_inode.c newtree/fs/unionfs/stale_inode.c --- oldtree/fs/unionfs/stale_inode.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/stale_inode.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,142 @@ +/* + * Adpated from linux/fs/bad_inode.c + * + * Copyright (C) 1997, Stephen Tweedie + * + * Provide stub functions for "stale" inodes, a bit friendlier than the + * -EIO that bad_inode.c does. + */ +/* + * $Id: stale_inode.c,v 1.12 2005/11/20 23:03:34 arunmk Exp $ + */ + +#include +#include + +#include +#include +#include + +static struct address_space_operations unionfs_stale_aops; + +/* declarations for "sparse */ +extern struct inode_operations stale_inode_ops; + +/* + * The follow_link operation is special: it must behave as a no-op + * so that a stale root inode can at least be unmounted. To do this + * we must dput() the base and return the dentry with a dget(). + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) +static int stale_follow_link(struct dentry *dent, struct nameidata *nd) +#else +static void *stale_follow_link(struct dentry *dent, struct nameidata *nd) +#endif +{ + int err = vfs_follow_link(nd, ERR_PTR(-ESTALE)); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) + return err; +#else + return ERR_PTR(err); +#endif +} + +static int return_ESTALE(void) +{ + return -ESTALE; +} + +#define ESTALE_ERROR ((void *) (return_ESTALE)) + +static struct file_operations stale_file_ops = { + .llseek = ESTALE_ERROR, + .read = ESTALE_ERROR, + .write = ESTALE_ERROR, + .readdir = ESTALE_ERROR, + .poll = ESTALE_ERROR, + .ioctl = ESTALE_ERROR, + .mmap = ESTALE_ERROR, + .open = ESTALE_ERROR, + .flush = ESTALE_ERROR, + .release = ESTALE_ERROR, + .fsync = ESTALE_ERROR, + .fasync = ESTALE_ERROR, + .lock = ESTALE_ERROR, +}; + +struct inode_operations stale_inode_ops = { + .create = ESTALE_ERROR, + .lookup = ESTALE_ERROR, + .link = ESTALE_ERROR, + .unlink = ESTALE_ERROR, + .symlink = ESTALE_ERROR, + .mkdir = ESTALE_ERROR, + .rmdir = ESTALE_ERROR, + .mknod = ESTALE_ERROR, + .rename = ESTALE_ERROR, + .readlink = ESTALE_ERROR, + .follow_link = stale_follow_link, + .truncate = ESTALE_ERROR, + .permission = ESTALE_ERROR, +}; + +/* + * When a filesystem is unable to read an inode due to an I/O error in + * its read_inode() function, it can call make_stale_inode() to return a + * set of stubs which will return ESTALE errors as required. + * + * We only need to do limited initialisation: all other fields are + * preinitialised to zero automatically. + */ + +/** + * make_stale_inode - mark an inode stale due to an I/O error + * @inode: Inode to mark stale + * + * When an inode cannot be read due to a media or remote network + * failure this function makes the inode "stale" and causes I/O operations + * on it to fail from this point on. + */ + +void make_stale_inode(struct inode *inode) +{ + inode->i_mode = S_IFREG; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_op = &stale_inode_ops; + inode->i_fop = &stale_file_ops; + inode->i_mapping->a_ops = &unionfs_stale_aops; +} + +/* + * This tests whether an inode has been flagged as stale. The test uses + * &stale_inode_ops to cover the case of invalidated inodes as well as + * those created by make_stale_inode() above. + */ + +/** + * is_stale_inode - is an inode errored + * @inode: inode to test + * + * Returns true if the inode in question has been marked as stale. + */ + +int is_stale_inode(struct inode *inode) +{ + return (inode->i_op == &stale_inode_ops); +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/subr.c newtree/fs/unionfs/subr.c --- oldtree/fs/unionfs/subr.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/subr.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: subr.c,v 1.133 2006/01/24 23:57:41 jsipek Exp $ + */ + +#include "unionfs.h" + +/* Pass an unionfs dentry and an index. It will try to create a whiteout + * for the filename in dentry, and will try in branch 'index'. On error, + * it will proceed to a branch to the left. + */ +int create_whiteout(struct dentry *dentry, int start) +{ + int bstart, bend, bindex; + struct dentry *hidden_dir_dentry; + struct dentry *hidden_dentry; + struct dentry *hidden_wh_dentry; + char *name = NULL; + int err = -EINVAL; + + print_entry("start = %d", start); + + verify_locked(dentry); + + fist_print_dentry("IN create_whiteout", dentry); + bstart = dbstart(dentry); + bend = dbend(dentry); + + /* create dentry's whiteout equivalent */ + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + for (bindex = start; bindex >= 0; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + + if (!hidden_dentry) { + /* if hidden dentry is not present, create the entire + * hidden dentry directory structure and go ahead. + * Since we want to just create whiteout, we only want + * the parent dentry, and hence get rid of this dentry. + */ + hidden_dentry = create_parents(dentry->d_inode, + dentry, bindex); + if (!hidden_dentry || IS_ERR(hidden_dentry)) { + fist_dprint(8, + "hidden dentry NULL for bindex = %d\n", + bindex); + continue; + } + } + hidden_wh_dentry = + LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(hidden_wh_dentry)) + continue; + + /* The whiteout already exists. This used to be impossible, but + * now is possible because of opaqueness. */ + if (hidden_wh_dentry->d_inode) { + DPUT(hidden_wh_dentry); + err = 0; + goto out; + } + + hidden_dir_dentry = lock_parent(hidden_wh_dentry); + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + err = + vfs_create(hidden_dir_dentry->d_inode, + hidden_wh_dentry, + ~current->fs->umask & S_IRWXUGO, NULL); + + } + unlock_dir(hidden_dir_dentry); + DPUT(hidden_wh_dentry); + + if (!err) + break; + + if (!IS_COPYUP_ERR(err)) + break; + } + + /* set dbopaque so that lookup will not proceed after this branch */ + if (!err) + set_dbopaque(dentry, bindex); + + fist_print_dentry("OUT create_whiteout", dentry); + out: + KFREE(name); + print_exit_status(err); + return err; +} + +/* Create a whiteout for filename in parent at 'start' branch */ +/* the parent dentry has to be valid with the hidden parent also being +valid */ +/* dbopaque has to be set by the caller */ +int create_whiteout_parent(struct dentry *parent_dentry, const char *filename, + int start) +{ + int bindex; + int old_bstart, old_bend; + struct dentry *hidden_dir_dentry; + struct dentry *hidden_grand_parent_dentry; + struct dentry *hidden_parent_dentry; + struct dentry *hidden_wh_dentry; + char *name = NULL; + int err = -EINVAL; + + print_entry_location(); + + verify_locked(parent_dentry); + + old_bstart = dbstart(parent_dentry); + old_bend = dbend(parent_dentry); + + fist_print_dentry("IN create_whiteout_parent", parent_dentry); + + /* create dentry's whiteout equivalent */ + name = alloc_whname(filename, strlen(filename)); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + for (bindex = start; bindex >= 0; bindex--) { + hidden_parent_dentry = dtohd_index(parent_dentry, bindex); + + if (!hidden_parent_dentry) { + /* create the recursive directory structure and return + * the negative dentry for the parent where we want to + * create whiteout. */ + BUG_ON(parent_dentry->d_inode == NULL); + hidden_parent_dentry = + create_parents(parent_dentry->d_parent->d_inode, + parent_dentry, bindex); + if (!hidden_parent_dentry + || IS_ERR(hidden_parent_dentry)) { + fist_dprint(8, + "hidden dentry NULL for bindex = %d\n", + bindex); + continue; + } + + /* create directory of the hidden parent, + * if it is negative. + * This is where whiteout is created + */ + hidden_grand_parent_dentry = + lock_parent(hidden_parent_dentry); + + /* We shouldn't create things in a read-only branch. */ + if (! + (err = + is_robranch_super(parent_dentry->d_sb, bindex))) + err = + vfs_mkdir(hidden_grand_parent_dentry-> + d_inode, hidden_parent_dentry, + S_IRWXU); + + unlock_dir(hidden_grand_parent_dentry); + if (err || !hidden_parent_dentry->d_inode) { + DPUT(hidden_parent_dentry); + if (!IS_COPYUP_ERR(err)) + break; + else + continue; + } + set_itohi_index(parent_dentry->d_inode, bindex, + IGRAB(hidden_parent_dentry->d_inode)); + if (bindex < ibstart(parent_dentry->d_inode)) + ibstart(parent_dentry->d_inode) = bindex; + else if (bindex > ibend(parent_dentry->d_inode)) + ibend(parent_dentry->d_inode) = bindex; + } + + /* lookup for the whiteout dentry that we want to create */ + hidden_wh_dentry = + LOOKUP_ONE_LEN(name, hidden_parent_dentry, + strlen(filename) + WHLEN); + if (!hidden_wh_dentry || IS_ERR(hidden_wh_dentry)) + continue; + BUG_ON(hidden_wh_dentry->d_inode); + + /* hidden_dir_dentry and hidden_parent_dentry + * are going to be the same */ + hidden_dir_dentry = lock_parent(hidden_wh_dentry); + + /* We shouldn't create things in a read-only branch. */ + if (!(err = is_robranch_super(parent_dentry->d_sb, bindex))) { + err = + vfs_create(hidden_dir_dentry->d_inode, + hidden_wh_dentry, + ~current->fs->umask & S_IRWXUGO, NULL); + } + + unlock_dir(hidden_dir_dentry); + DPUT(hidden_wh_dentry); + + if (!err || !IS_COPYUP_ERR(err)) + break; + } + + out: + fist_print_dentry("OUT create_whiteout_parent", parent_dentry); + KFREE(name); + print_exit_status(err); + return err; +} + +/* This is a helper function for rename, which ends up with hosed over dentries + * when it needs to revert. */ +int unionfs_refresh_hidden_dentry(struct dentry *dentry, int bindex) +{ + struct dentry *hidden_dentry; + struct dentry *hidden_parent; + int err = 0; + + print_entry(" bindex = %d", bindex); + + verify_locked(dentry); + lock_dentry(dentry->d_parent); + hidden_parent = dtohd_index(dentry->d_parent, bindex); + unlock_dentry(dentry->d_parent); + + BUG_ON(!S_ISDIR(hidden_parent->d_inode->i_mode)); + + hidden_dentry = + LOOKUP_ONE_LEN(dentry->d_name.name, hidden_parent, + dentry->d_name.len); + if (IS_ERR(hidden_dentry)) { + err = PTR_ERR(hidden_dentry); + goto out; + } + + if (dtohd_index(dentry, bindex)) + DPUT(dtohd_index(dentry, bindex)); + if (itohi_index(dentry->d_inode, bindex)) { + IPUT(itohi_index(dentry->d_inode, bindex)); + set_itohi_index(dentry->d_inode, bindex, NULL); + } + if (!hidden_dentry->d_inode) { + DPUT(hidden_dentry); + set_dtohd_index(dentry, bindex, NULL); + } else { + set_dtohd_index(dentry, bindex, hidden_dentry); + set_itohi_index(dentry->d_inode, bindex, + IGRAB(hidden_dentry->d_inode)); + } + + out: + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/super.c newtree/fs/unionfs/super.c --- oldtree/fs/unionfs/super.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/super.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2003-2005 Erez Zadok + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: super.c,v 1.85 2006/01/21 02:58:11 jsipek Exp $ + */ + +#include "unionfs.h" + +/* The inode cache is used with alloc_inode for both our inode info and the + * vfs inode. */ +static kmem_cache_t *unionfs_inode_cachep; + +static void unionfs_read_inode(struct inode *inode) +{ + static struct address_space_operations unionfs_empty_aops; + + print_entry_location(); + + if (!itopd(inode)) { + printk(KERN_ERR + "No kernel memory when allocating inode private data!\n"); + BUG(); + } + + memset(itopd(inode), 0, sizeof(struct unionfs_inode_info)); + itopd(inode)->b_start = -1; + itopd(inode)->b_end = -1; + atomic_set(&itopd(inode)->uii_generation, + atomic_read(&stopd(inode->i_sb)->usi_generation)); + itopd(inode)->uii_rdlock = SPIN_LOCK_UNLOCKED; + itopd(inode)->uii_rdcount = 1; + itopd(inode)->uii_hashsize = -1; + INIT_LIST_HEAD(&itopd(inode)->uii_readdircache); + + if (sbmax(inode->i_sb) > UNIONFS_INLINE_OBJECTS) { + int size = + (sbmax(inode->i_sb) - + UNIONFS_INLINE_OBJECTS) * sizeof(struct inode *); + itohi_ptr(inode) = KZALLOC(size, GFP_KERNEL); + if (!itohi_ptr(inode)) { + printk(KERN_ERR + "No kernel memory when allocating lower-pointer array!\n"); + BUG(); + } + } + memset(itohi_inline(inode), 0, + UNIONFS_INLINE_OBJECTS * sizeof(struct inode *)); + + inode->i_version++; + inode->i_op = &unionfs_main_iops; + inode->i_fop = &unionfs_main_fops; + /* I don't think ->a_ops is ever allowed to be NULL */ + inode->i_mapping->a_ops = &unionfs_empty_aops; + fist_dprint(7, "setting inode 0x%p a_ops to empty (0x%p)\n", + inode, inode->i_mapping->a_ops); + + print_exit_location(); +} + +static void unionfs_put_inode(struct inode *inode) +{ + print_entry_location(); + fist_dprint(8, "%s i_count = %d, i_nlink = %d\n", __FUNCTION__, + atomic_read(&inode->i_count), inode->i_nlink); + /* + * This is really funky stuff: + * Basically, if i_count == 1, iput will then decrement it and this inode will be destroyed. + * It is currently holding a reference to the hidden inode. + * Therefore, it needs to release that reference by calling iput on the hidden inode. + * iput() _will_ do it for us (by calling our clear_inode), but _only_ if i_nlink == 0. + * The problem is, NFS keeps i_nlink == 1 for silly_rename'd files. + * So we must for our i_nlink to 0 here to trick iput() into calling our clear_inode. + */ + if (atomic_read(&inode->i_count) == 1) + inode->i_nlink = 0; + print_exit_location(); +} + +/* + * we now define delete_inode, because there are two VFS paths that may + * destroy an inode: one of them calls clear inode before doing everything + * else that's needed, and the other is fine. This way we truncate the inode + * size (and its pages) and then clear our own inode, which will do an iput + * on our and the lower inode. + */ +static void unionfs_delete_inode(struct inode *inode) +{ + print_entry_location(); + + fist_checkinode(inode, "unionfs_delete_inode IN"); + inode->i_size = 0; /* every f/s seems to do that */ + clear_inode(inode); + + print_exit_location(); +} + +/* final actions when unmounting a file system */ +static void unionfs_put_super(struct super_block *sb) +{ + int bindex, bstart, bend; + struct unionfs_sb_info *spd; + + print_entry_location(); + + if ((spd = stopd(sb))) { + /* XXX: Free persistent inode stuff. */ + cleanup_imap_data(sb); + + bstart = sbstart(sb); + bend = sbend(sb); + for (bindex = bstart; bindex <= bend; bindex++) + mntput(stohiddenmnt_index(sb, bindex)); + + /* Make sure we have no leaks of branchget/branchput. */ + for (bindex = bstart; bindex <= bend; bindex++) + BUG_ON(branch_count(sb, bindex) != 0); + + KFREE(stohs_ptr(sb)); + KFREE(stohiddenmnt_ptr(sb)); + KFREE(spd->usi_sbcount_p); + KFREE(spd->usi_branchperms_p); + KFREE(spd->usi_putmaps); + KFREE(spd); + stopd_lhs(sb) = NULL; + } + fist_dprint(6, "unionfs: released super\n"); + + print_exit_location(); +} + +static int unionfs_statfs(struct super_block *sb, struct kstatfs *buf) +{ + int err = 0; + struct super_block *hidden_sb; + struct kstatfs rsb; + int bindex, bindex1, bstart, bend; + + print_entry_location(); + memset(buf, 0, sizeof(struct kstatfs)); + buf->f_type = UNIONFS_SUPER_MAGIC; + + buf->f_frsize = 0; + buf->f_namelen = 0; + + bstart = sbstart(sb); + bend = sbend(sb); + + for (bindex = bstart; bindex <= bend; bindex++) { + int dup = 0; + + hidden_sb = stohs_index(sb, bindex); + /* Ignore duplicate super blocks. */ + for (bindex1 = bstart; bindex1 < bindex; bindex1++) { + if (hidden_sb == stohs_index(sb, bindex1)) { + dup = 1; + break; + } + } + if (dup) { + continue; + } + + err = vfs_statfs(hidden_sb, &rsb); + fist_dprint(8, + "adding values for bindex:%d bsize:%d blocks:%d bfree:%d bavail:%d\n", + bindex, (int)rsb.f_bsize, (int)rsb.f_blocks, + (int)rsb.f_bfree, (int)rsb.f_bavail); + + if (!buf->f_frsize) + buf->f_frsize = rsb.f_frsize; + if (!buf->f_namelen) { + buf->f_namelen = rsb.f_namelen; + } else { + if (buf->f_namelen > rsb.f_namelen) + buf->f_namelen = rsb.f_namelen; + } + if (!buf->f_bsize) { + buf->f_bsize = rsb.f_bsize; + } else { + if (buf->f_bsize < rsb.f_bsize) { + int shifter = 0; + while (buf->f_bsize < rsb.f_bsize) { + shifter++; + rsb.f_bsize >>= 1; + } + rsb.f_blocks <<= shifter; + rsb.f_bfree <<= shifter; + rsb.f_bavail <<= shifter; + } else { + int shifter = 0; + while (buf->f_bsize > rsb.f_bsize) { + shifter++; + rsb.f_bsize <<= 1; + } + rsb.f_blocks >>= shifter; + rsb.f_bfree >>= shifter; + rsb.f_bavail >>= shifter; + } + } + buf->f_blocks += rsb.f_blocks; + buf->f_bfree += rsb.f_bfree; + buf->f_bavail += rsb.f_bavail; + buf->f_files += rsb.f_files; + buf->f_ffree += rsb.f_ffree; + } + buf->f_namelen -= WHLEN; + + memset(&buf->f_fsid, 0, sizeof(__kernel_fsid_t)); + memset(&buf->f_spare, 0, sizeof(buf->f_spare)); + print_exit_status(err); + return err; +} + +static int do_binary_remount(struct super_block *sb, int *flags, char *data) +{ + unsigned long *uldata = (unsigned long *)data; + int err; + + uldata++; + + switch (*uldata) { + case UNIONFS_IOCTL_DELBRANCH: + err = unionfs_ioctl_delbranch(sb, *(uldata + 1)); + break; + default: + err = -ENOTTY; + } + + return err; +} + +/* We don't support a standard text remount, but we do have a magic remount + * for unionctl. The idea is that you can remove a branch without opening + * the union. Eventually it would be nice to support a full-on remount, so + * that you can have all of the directories change at once, but that would + * require some pretty complicated matching code. */ +static int unionfs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + if (data && *((unsigned long *)data) == UNIONFS_REMOUNT_MAGIC) + return do_binary_remount(sb, flags, data); + return -ENOSYS; +} + +/* + * Called by iput() when the inode reference count reached zero + * and the inode is not hashed anywhere. Used to clear anything + * that needs to be, before the inode is completely destroyed and put + * on the inode free list. + */ +static void unionfs_clear_inode(struct inode *inode) +{ + int bindex, bstart, bend; + struct inode *hidden_inode; + struct list_head *pos, *n; + struct unionfs_dir_state *rdstate; + + print_entry_location(); + + fist_checkinode(inode, "unionfs_clear_inode IN"); + + list_for_each_safe(pos, n, &itopd(inode)->uii_readdircache) { + rdstate = list_entry(pos, struct unionfs_dir_state, uds_cache); + list_del(&rdstate->uds_cache); + free_rdstate(rdstate); + } + + /* Decrement a reference to a hidden_inode, which was incremented + * by our read_inode when it was created initially. */ + bstart = ibstart(inode); + bend = ibend(inode); + if (bstart >= 0) { + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_inode = itohi_index(inode, bindex); + if (!hidden_inode) + continue; + IPUT(hidden_inode); + } + } + // XXX: why this assertion fails? + // because it doesn't like us + // BUG_ON((inode->i_state & I_DIRTY) != 0); + KFREE(itohi_ptr(inode)); + itohi_ptr(inode) = NULL; + + print_exit_location(); +} + +static struct inode *unionfs_alloc_inode(struct super_block *sb) +{ + struct unionfs_inode_container *c; + + print_entry_location(); + + c = (struct unionfs_inode_container *) + kmem_cache_alloc(unionfs_inode_cachep, SLAB_KERNEL); + if (!c) { + print_exit_pointer(NULL); + return NULL; + } + + memset(&c->info, 0, sizeof(c->info)); + + c->vfs_inode.i_version = 1; + print_exit_pointer(&c->vfs_inode); + return &c->vfs_inode; +} + +static void unionfs_destroy_inode(struct inode *inode) +{ + print_entry("inode = %p", inode); + kmem_cache_free(unionfs_inode_cachep, itopd(inode)); + print_exit_location(); +} + +static void init_once(void *v, kmem_cache_t * cachep, unsigned long flags) +{ + struct unionfs_inode_container *c = (struct unionfs_inode_container *)v; + + print_entry_location(); + + if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) + inode_init_once(&c->vfs_inode); + + print_exit_location(); +} + +int init_inode_cache(void) +{ + int err = 0; + + print_entry_location(); + + unionfs_inode_cachep = + kmem_cache_create("unionfs_inode_cache", + sizeof(struct unionfs_inode_container), 0, + SLAB_RECLAIM_ACCOUNT, init_once, NULL); + if (!unionfs_inode_cachep) + err = -ENOMEM; + print_exit_status(err); + return err; +} + +void destroy_inode_cache(void) +{ + print_entry_location(); + if (!unionfs_inode_cachep) + goto out; + if (kmem_cache_destroy(unionfs_inode_cachep)) + printk(KERN_ERR + "unionfs_inode_cache: not all structures were freed\n"); + out: + print_exit_location(); + return; +} + +/* Called when we have a dirty inode, right here we only throw out + * parts of our readdir list that are too old. + */ +static int unionfs_write_inode(struct inode *inode, int sync) +{ + struct list_head *pos, *n; + struct unionfs_dir_state *rdstate; + + print_entry_location(); + + spin_lock(&itopd(inode)->uii_rdlock); + list_for_each_safe(pos, n, &itopd(inode)->uii_readdircache) { + rdstate = list_entry(pos, struct unionfs_dir_state, uds_cache); + /* We keep this list in LRU order. */ + if ((rdstate->uds_access + RDCACHE_JIFFIES) > jiffies) + break; + itopd(inode)->uii_rdcount--; + list_del(&rdstate->uds_cache); + free_rdstate(rdstate); + } + spin_unlock(&itopd(inode)->uii_rdlock); + + print_exit_location(); + return 0; +} + +/* + * Called in do_umount() if the MNT_FORCE flag was used and this + * function is defined. See comment in linux/fs/super.c:do_umount(). + * Used only in nfs, to kill any pending RPC tasks, so that subsequent + * code can actually succeed and won't leave tasks that need handling. + * + * PS. I wonder if this is somehow useful to undo damage that was + * left in the kernel after a user level file server (such as amd) + * dies. + */ +static void unionfs_umount_begin(struct super_block *sb) +{ + struct super_block *hidden_sb; + int bindex, bstart, bend; + + print_entry_location(); + + bstart = sbstart(sb); + bend = sbend(sb); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_sb = stohs_index(sb, bindex); + if (hidden_sb && hidden_sb->s_op && + hidden_sb->s_op->umount_begin) + hidden_sb->s_op->umount_begin(hidden_sb); + } + print_exit_location(); +} + +static int unionfs_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct super_block *sb = mnt->mnt_sb; + int ret = 0; + unsigned long tmp = 0; + char *hidden_path; + int bindex, bstart, bend; + int perms; + + lock_dentry(sb->s_root); + + tmp = __get_free_page(GFP_KERNEL); + if (!tmp) { + ret = -ENOMEM; + goto out; + } + + bindex = bstart = sbstart(sb); + bend = sbend(sb); + + seq_printf(m, ",dirs="); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_path = + d_path(dtohd_index(sb->s_root, bindex), + stohiddenmnt_index(sb, bindex), (char *)tmp, + PAGE_SIZE); + perms = branchperms(sb, bindex); + seq_printf(m, "%s=%s", hidden_path, + perms & MAY_WRITE ? "rw" : + perms & MAY_NFSRO ? "nfsro" : "ro"); + if (bindex != bend) { + seq_printf(m, ":"); + } + } + + seq_printf(m, ",debug=%d", fist_get_debug_value()); + + if (IS_SET(sb, DELETE_WHITEOUT)) + seq_printf(m, ",delete=whiteout"); + else + seq_printf(m, ",delete=all"); + + if (IS_SET(sb, COPYUP_CURRENT_USER)) + seq_printf(m, ",copyup=currentuser"); + else if (IS_SET(sb, COPYUP_FS_MOUNTER)) + seq_printf(m, ",copyup=mounter"); + else + seq_printf(m, ",copyup=preserve"); + + out: + if (tmp) + free_page(tmp); + unlock_dentry(sb->s_root); + return ret; +} + +/** + * The entry given by dentry here is always a directory. + * We can't just do dentry->d_parent, because it may + * not be there, since this dentry could have been + * created by calling d_alloc_anon. + */ +static struct dentry *unionfs_get_parent(struct dentry *dentry) +{ + + struct dentry *ret; + struct inode *childinode; + childinode = dentry->d_inode; + ret = d_find_alias(childinode); + return ret; +} + +struct export_operations unionfs_export_ops = { + .get_parent = unionfs_get_parent +}; + +struct super_operations unionfs_sops = { + .read_inode = unionfs_read_inode, + .put_inode = unionfs_put_inode, + .delete_inode = unionfs_delete_inode, + .put_super = unionfs_put_super, + .statfs = unionfs_statfs, + .remount_fs = unionfs_remount_fs, + .clear_inode = unionfs_clear_inode, + .umount_begin = unionfs_umount_begin, + .show_options = unionfs_show_options, + .write_inode = unionfs_write_inode, + .alloc_inode = unionfs_alloc_inode, + .destroy_inode = unionfs_destroy_inode, +#ifdef SPLIT_VIEW_CACHES + .select_super = unionfs_select_super, +#endif +}; + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/unionctl.c newtree/fs/unionfs/unionctl.c --- oldtree/fs/unionfs/unionctl.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/unionctl.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: unionctl.c,v 1.40 2006/01/21 02:58:11 jsipek Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "unionfs.h" + +#define MAY_READ 4 +#define MAY_WRITE 2 + +extern int find_union(const char *path, char **options, char **actual_path, + int uniononly); +static char **branches; +static int *branchperms; +static const char *progname; + +void __attribute__ ((__noreturn__)) __usage(int line); + +#define usage() __usage(__LINE__) + +void __attribute__ ((__noreturn__)) __usage(int line) +{ +#ifdef DEBUG + fprintf(stderr, "Line: %d\n", line); +#endif + fprintf(stderr, + "unionctl version: $Id: unionctl.c,v 1.40 2006/01/21 02:58:11 jsipek Exp $\n"); + fprintf(stderr, "Distributed with Unionfs " UNIONFS_VERSION "\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "unionctl UNION ACTION [arguments]\n"); + fprintf(stderr, + "ACTION can be --add, --remove, --mode, --list, or --query.\nFurther arguments depend on ACTION.\n"); + fprintf(stderr, + "\tunionctl UNION --add [ --before BRANCH | --after BRANCH ] [ --mode (rw|ro|nfsro) ] DIRECTORY\n"); + fprintf(stderr, "\tunionctl UNION --remove BRANCH\n"); + fprintf(stderr, "\tunionctl UNION --mode BRANCH (rw|ro|nfsro)\n"); + fprintf(stderr, "\tunionctl UNION --list\n"); + fprintf(stderr, "\tunionctl FILENAME --query\n"); + fprintf(stderr, + "The unionctl man page has a more detailed description of its usage.\n"); + exit(EXIT_FAILURE); +} + +static inline int parse_rw(char *p) +{ + if (strcmp(p, "ro") == 0) + return MAY_READ; + else if (strcmp(p, "nfsro") == 0) + return MAY_READ | MAY_NFSRO; + else if (strcmp(p, "rw") == 0) + return MAY_READ | MAY_WRITE; + else + return 0; +} + +static char **parse_options(char *options) +{ + char **ret = NULL; + int i = 0; + + char *p; + char *q; + char *r; + char *s, *t, *u; + + p = options; + do { + q = strchr(p, ','); + if (q) { + *q++ = '\0'; + } + if (!strncmp(p, "dirs=", strlen("dirs="))) { + r = p + strlen("dirs="); + do { + s = strchr(r, ':'); + if (s) { + *s++ = '\0'; + } + + i++; + ret = realloc(ret, sizeof(char *) * (i + 1)); + if (!ret) { + perror("realloc()"); + exit(EXIT_FAILURE); + } + branchperms = + realloc(branchperms, sizeof(int) * i); + if (!branchperms) { + perror("realloc()"); + exit(EXIT_FAILURE); + } + + t = strchr(r, '='); + u = t + 1; + if (!t || !u || !*u) + goto err; + *t = 0; + branchperms[i - 1] = parse_rw(u); + if (!branchperms[i - 1]) { + err: + fprintf(stderr, "cannot parse '%s'\n", + r); + exit(EXIT_FAILURE); + } + ret[i - 1] = strdup(r); + ret[i] = NULL; + + r = s; + } + while (r); + } + p = q; + } + while (p); + + branches = ret; + return ret; +} + +static int get_branch(char *path) +{ + char *end; + int ret; + + ret = strtol(path, &end, 0); + if (!*end) { + return ret; + } + + ret = strlen(path); + if ((ret > 1) && (path[ret - 1] == '/')) { + path[ret - 1] = '\0'; + } + + ret = 0; + while (branches[ret]) { + if (!strcmp(branches[ret], path)) { + return ret; + } + ret++; + } + + return -1; +} + +static void dump_branches(const char *prefix) +{ + int i = 0; + + while (branches[i]) { + char r, w, n; + r = (branchperms[i] & MAY_READ) ? 'r' : '-'; + w = (branchperms[i] & MAY_WRITE) ? 'w' : '-'; + n = (branchperms[i] & MAY_NFSRO) ? 'n' : '-'; + printf("%s%s (%c%c%c)\n", prefix, branches[i], r, w, n); + i++; + } +} + +#define ADD 1 +#define REMOVE 2 +#define MODE 3 +#define LIST 4 +#define QUERY 5 + +int main(int argc, char *argv[]) +{ + struct unionfs_addbranch_args addargs; + struct unionfs_rdwrbranch_args rdwrargs; + unsigned long remountdata[3]; + fd_set branchlist; + struct stat st; + + int fd = -1; + int ret, i; + + char *path, resolv_path[PATH_MAX], resolv_bp[PATH_MAX]; + char *options = NULL, *actual_path = NULL; + int action; + + char *branchpath; + int branchnum; + int unionpos = 1; + int modepos = 2; + + progname = argv[0]; + + /* check that minimum number of args were specified */ + if (argc < 3) + usage(); + + if (argv[1][0] == '-' && argv[1][1] == '-') { + modepos = 1; + unionpos = 2; + } else { + modepos = 2; + unionpos = 1; + } + + if (realpath(argv[unionpos], resolv_path) == NULL) { + perror("realpath()"); + exit(EXIT_FAILURE); + } + path = resolv_path; + if (strcmp(path, "/") && (path[strlen(path) - 1] == '/')) { + path[strlen(path) - 1] = '\0'; + } + + if (!strcmp(argv[modepos], "--add")) { + action = ADD; + } else if (!strcmp(argv[modepos], "--remove")) { + action = REMOVE; + } else if (!strcmp(argv[modepos], "--mode")) { + action = MODE; + } else if (!strcmp(argv[modepos], "--list")) { + action = LIST; + } else if (!strcmp(argv[modepos], "--query")) { + action = QUERY; + } else { + usage(); + } + + if (stat(path, &st) == -1) { + fprintf(stderr, "stat(%s): %s\n", path, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (find_union(path, &options, &actual_path, 1) < 0) { + fprintf(stderr, "%s is not a valid union.\n", path); + exit(EXIT_FAILURE); + } + branches = parse_options(options); + if (!branches) { + fprintf(stderr, "Could not parse options from /proc/mounts!\n"); + exit(EXIT_FAILURE); + } + + /* open file on which ioctl will operate (that is actually any file in the union) */ + if (action != REMOVE) { + fd = open(path, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "open(%s): %s\n", path, + strerror(errno)); + exit(EXIT_FAILURE); + } + } + + /* Parse the action's options into something usable, and do it. */ + switch (action) { + case ADD: + if (argc < 4) + usage(); + + /* Default values if the user leaves them unspecified. */ + branchnum = -1; + addargs.ab_perms = MAY_READ | MAY_WRITE; + branchpath = NULL; + for (i = 3; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == '-') { + if (!strcmp(argv[i], "--before")) { + i++; + if (i == argc) { + fprintf(stderr, + "%s requires an argument!\n", + argv[i - 1]); + usage(); + } + + branchnum = get_branch(argv[i]); + if (branchnum == -1) { + fprintf(stderr, + "%s is not a valid branch.\nThe current branch configuration is:\n", + argv[i]); + dump_branches("\t"); + } + } else if (!strcmp(argv[i], "--after")) { + i++; + if (i == argc) { + fprintf(stderr, + "%s requires an argument!\n", + argv[i - 1]); + usage(); + } + + branchnum = get_branch(argv[i]); + if (branchnum == -1) { + fprintf(stderr, + "%s is not a valid branch.\nThe current branch configuration is:\n", + argv[i]); + dump_branches("\t"); + } + branchnum++; + } else if (!strcmp(argv[i], "--mode")) { + i++; + if (i == argc) { + fprintf(stderr, + "%s requires an argument!\n", + argv[i - 1]); + usage(); + } + + addargs.ab_perms = parse_rw(argv[i]); + if (!addargs.ab_perms) { + fprintf(stderr, + "Valid modes are ro, nfsro and rw you specified: \"%s\"\n", + argv[i]); + usage(); + } + } else { + fprintf(stderr, "Unknown option: %s\n", + argv[i]); + usage(); + } + } else { + int branchchk = -1; + /* The options must go before the path */ + if ((i + 1) != argc) { + fprintf(stderr, + "The path of the branch to add must go after all options.\n"); + usage(); + } + branchchk = get_branch(argv[i]); + if (branchchk != -1) { + fprintf(stderr, + "%s already exists in the Union.\n", + argv[i]); + usage(); + } + if (branchnum == -1) + branchnum = 0; + branchpath = argv[i]; + } + } + if (!branchpath) { + fprintf(stderr, + "You must specify the path to add into the union!\n"); + usage(); + } + + if (realpath(branchpath, resolv_bp) == NULL) { + perror("realpath()"); + exit(EXIT_FAILURE); + } + + addargs.ab_branch = branchnum; + addargs.ab_path = resolv_bp; + + errno = 0; + ret = ioctl(fd, UNIONFS_IOCTL_ADDBRANCH, &addargs); + if (ret < 0) { + switch (errno) { + case E2BIG: + fprintf(stderr, + "Unionfs supports only %d branches.\n", + FD_SETSIZE); + break; + } + fprintf(stderr, "Failed to add %s into %s: %s", + branchpath, path, strerror(errno)); + exit(EXIT_FAILURE); + } + break; + case MODE: + if (argc != 5) { + usage(); + } + + branchnum = 3; + rdwrargs.rwb_perms = parse_rw(argv[4]); + if (!rdwrargs.rwb_perms) { + branchnum = 4; + rdwrargs.rwb_perms = parse_rw(argv[3]); + if (!rdwrargs.rwb_perms) { + usage(); + exit(EXIT_FAILURE); + } + } + + if (realpath(argv[branchnum], resolv_bp) == NULL) { + perror("realpath()"); + exit(EXIT_FAILURE); + } + branchpath = resolv_bp; + + /* Set a branches writeable status. */ + rdwrargs.rwb_branch = get_branch(branchpath); + if (rdwrargs.rwb_branch == -1) { + fprintf(stderr, + "%s is not a valid branch.\nThe current branch configuration is:\n", + branchpath); + dump_branches("\t"); + exit(EXIT_FAILURE); + } + + ret = ioctl(fd, UNIONFS_IOCTL_RDWRBRANCH, &rdwrargs); + if (ret < 0) { + fprintf(stderr, + "Failed to set permissions for %s in %s: %s", + branchpath, path, strerror(errno)); + exit(EXIT_FAILURE); + } + + goto out; + break; + case REMOVE: + if (argc != 4) + usage(); + + if (realpath(argv[3], resolv_bp) == NULL) { + perror("realpath()"); + exit(EXIT_FAILURE); + } + branchpath = resolv_bp; + + branchnum = get_branch(branchpath); + if (branchnum == -1) { + fprintf(stderr, + "%s is not a valid branch.\nThe current branch configuration is:\n", + branchpath); + dump_branches("\t"); + exit(EXIT_FAILURE); + } + + errno = 0; + remountdata[0] = UNIONFS_REMOUNT_MAGIC; + remountdata[1] = UNIONFS_IOCTL_DELBRANCH; + remountdata[2] = branchnum; + ret = + mount("unionfs", actual_path, "unionfs", + MS_REMOUNT | MS_MGC_VAL, remountdata); + if (ret < 0) { + fprintf(stderr, "Failed to remove %s from %s: %s", + branchpath, path, strerror(errno)); + exit(EXIT_FAILURE); + } + break; + case LIST: + dump_branches("\t"); + break; + + case QUERY: + if (argc != 3) { + usage(); + } + + if ((fd = open(argv[unionpos], O_RDONLY)) < 0) { + fprintf(stderr, + "Unable to open file %s : %s", + argv[unionpos], strerror(errno)); + exit(EXIT_FAILURE); + } + + ret = ioctl(fd, UNIONFS_IOCTL_QUERYFILE, &branchlist); + if (ret < 0) { + fprintf(stderr, + "Unable to retrieve list of branches for file %s : %s\n", + argv[unionpos], strerror(errno)); + exit(EXIT_FAILURE); + } + + for (i = 0; i <= ret; i++) { + char r, w, n; + r = (branchperms[i] & MAY_READ) ? 'r' : '-'; + w = (branchperms[i] & MAY_WRITE) ? 'w' : '-'; + n = (branchperms[i] & MAY_NFSRO) ? 'n' : '-'; + + if (FD_ISSET(i, &branchlist)) + printf("%s\t%s (%c%c%c)\n", argv[unionpos], + branches[i], r, w, n); + } + break; + } + + out: + if (fd != -1) + close(fd); + exit(EXIT_SUCCESS); +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/uniondbg.c newtree/fs/unionfs/uniondbg.c --- oldtree/fs/unionfs/uniondbg.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/uniondbg.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: uniondbg.c,v 1.16 2006/01/13 03:00:24 jsipek Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "unionfs.h" + +#define MAY_READ 4 +#define MAY_WRITE 2 + +static int opt_d = 0; +static int opt_c = 0; +static int opt_g = 0; +static int optcount; +static const char *progname; + +void usage(void) +{ + fprintf(stderr, "Usage:\n" + "%s -d file [val]\n\tto set/get debugging values\n" + "%s -c file\n\tto print out branch reference counts (in kernel debug output)\n" + "%s -g file\n\tto increment the super block generation count\n" + "%s -s file\n\tto duplicate the super block\n", progname, + progname, progname, progname); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int fd, ret, val = 0; + int i; + + progname = argv[0]; + + /* check that minimum number of args were specified */ + if (argc < 3) + usage(); + + if (strcmp(argv[1], "-d") == 0) { + if (argc > 4) + usage(); + opt_d++; + optcount++; + } + if (strcmp(argv[1], "-c") == 0) { + if (argc > 3) + usage(); + opt_c++; + optcount++; + } + if (strcmp(argv[1], "-g") == 0) { + if (argc > 3) + usage(); + opt_g++; + optcount++; + } + + /* check that at least one option was used */ + if (!optcount) + usage(); + + /* open file on which ioctl will operate */ + fd = open(argv[2], O_RDONLY); + if (fd < 0) { + perror(argv[2]); + exit(1); + } + + /* if specified 3rd arg, want to set debug level */ + if (opt_d) { + if (argc == 4) { + val = atoi(argv[3]); + ret = ioctl(fd, FIST_IOCTL_SET_DEBUG_VALUE, &val); + if (ret < 0) { + perror("ioctl set"); + exit(1); + } + } else { + ret = ioctl(fd, FIST_IOCTL_GET_DEBUG_VALUE, &val); + if (ret < 0) { + perror("ioctl get"); + exit(1); + } + printf("debug ioctl returned value %d\n", val); + } + goto out; + } + + /* branch refcounts */ + if (opt_c) { + int *counts; + ret = ioctl(fd, UNIONFS_IOCTL_BRANCH_COUNT, NULL); + if (ret < 0) { + perror("ioctl branchcount (a)"); + exit(1); + } + counts = malloc(ret * sizeof(int)); + if (!counts) { + perror("malloc"); + exit(1); + } + ret = ioctl(fd, UNIONFS_IOCTL_BRANCH_COUNT, counts); + if (ret < 0) { + perror("ioctl branchcount (b)"); + exit(1); + } + printf("%d total branches.\n", ret); + for (i = 0; i < ret; i++) { + printf("%d: %d\n", i, counts[i]); + } + free(counts); + goto out; + } + + /* Update generation number. */ + if (opt_g) { + ret = ioctl(fd, UNIONFS_IOCTL_INCGEN, NULL); + if (ret < 0) { + perror("ioctl incgen"); + exit(1); + } + printf("New generation %d\n", ret); + goto out; + } + + out: + close(fd); + exit(0); +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/unionfs.h newtree/fs/unionfs/unionfs.h --- oldtree/fs/unionfs/unionfs.h 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/unionfs.h 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,872 @@ +#ifndef __UNIONFS_H_ +#define __UNIONFS_H_ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#if (!defined(UNIONFS_UNSUPPORTED)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) +#warning You are compiling Unionfs on an unsupported kernel version. +#warning To compile Unionfs, you will need to define UNIONFS_UNSUPPORTED. +#warning Try adding: EXTRACFLAGS=-DUNIONFS_UNSUPPORTED to fistdev.mk +#endif + +#include +#define wq_write_lock_irqsave(lock,flags) spin_lock_irqsave(lock,flags) +#define wq_write_unlock(lock) spin_unlock(lock) +#define wq_write_lock_irq(lock) spin_lock_irq(lock) +#define wq_write_unlock_irqrestore(lock,flags) spin_unlock_irqrestore(lock,flags) + +/* number of characters while generating unique temporary file names */ +#define UNIONFS_TMPNAM_LEN 12 + +/* fist file systems superblock magic */ +#define UNIONFS_SUPER_MAGIC 0xf15f083d + +/* unionfs root inode number */ +#define UNIONFS_ROOT_INO 1 + +/* Mount time flags */ +#define MOUNT_FLAG(sb) (stopd(sb)->usi_mount_flag) + +/*UUID typedef needed later*/ +typedef uint8_t uuid_t[16]; + +/* Operations vectors defined in specific files. */ +extern struct file_operations unionfs_main_fops; +extern struct file_operations unionfs_dir_fops; +extern struct inode_operations unionfs_main_iops; +extern struct inode_operations unionfs_dir_iops; +extern struct inode_operations unionfs_symlink_iops; +extern struct super_operations unionfs_sops; +extern struct dentry_operations unionfs_dops; +extern struct export_operations unionfs_export_ops; + +/* How many dentries, inodes, and other things should be stuck directly int our + * unionfs structures without an intervening KMALLOC? */ +#ifndef UNIONFS_INLINE_OBJECTS +#define UNIONFS_INLINE_OBJECTS 1 +#endif + +/* How long should an entry be allowed to persist */ +#define RDCACHE_JIFFIES 5*HZ +/* unionfs inode data in memory */ +struct unionfs_inode_info { + int b_start; + int b_end; + atomic_t uii_generation; + int uii_stale; + /* Stuff for readdir over NFS. */ + spinlock_t uii_rdlock; + struct list_head uii_readdircache; + int uii_rdcount; + int uii_hashsize; + int uii_cookie; + /* The hidden inodes */ + struct inode *uii_inode_i[UNIONFS_INLINE_OBJECTS]; + struct inode **uii_inode_p; + /* to keep track of reads/writes for unlinks before closes */ + atomic_t uii_totalopens; +}; + +struct unionfs_inode_container { + struct unionfs_inode_info info; + struct inode vfs_inode; +}; + +/* unionfs dentry data in memory */ +struct unionfs_dentry_info { + /* The semaphore is used to lock the dentry as soon as we get into a + * unionfs function from the VFS. Our lock ordering is that children + * go before their parents. */ + struct semaphore udi_sem; + int udi_bstart; + int udi_bend; + int udi_bopaque; + int udi_bcount; + atomic_t udi_generation; + struct dentry *udi_dentry_i[UNIONFS_INLINE_OBJECTS]; + struct dentry **udi_dentry_p; +}; + +/* A putmap is used so that older files can still do branchput correctly. */ +struct putmap { + atomic_t count; + int bend; + int map[0]; +}; + +/* unionfs super-block data in memory */ +struct unionfs_sb_info { + int b_end; + + uid_t copyupuid; + gid_t copyupgid; + umode_t copyupmode; + + atomic_t usi_generation; + unsigned long usi_mount_flag; + struct rw_semaphore usi_rwsem; + + int usi_persistent; + + /* These are the pointers to our various objects. */ + struct super_block *usi_sb_i[UNIONFS_INLINE_OBJECTS]; + atomic_t usi_sbcount_i[UNIONFS_INLINE_OBJECTS]; + struct vfsmount *usi_hidden_mnt_i[UNIONFS_INLINE_OBJECTS]; + int usi_branchperms_i[UNIONFS_INLINE_OBJECTS]; + + struct super_block **usi_sb_p; + atomic_t *usi_sbcount_p; + struct vfsmount **usi_hidden_mnt_p; + int *usi_branchperms_p; + + /* These map branch numbers for old generation numbers to the new bindex, + * so that branchput will behave properly. */ + int usi_firstputmap; + int usi_lastputmap; + struct putmap **usi_putmaps; + + /* These will need a lock. */ + uint64_t usi_next_avail; + uint8_t usi_num_bmapents; + struct bmapent *usi_bmap; + struct file *usi_forwardmap; + struct file **usi_reversemaps; + struct file **usi_map_table; + int *usi_fsnum_table; //This is a table of fsnums to branches. + int *usi_bnum_table; //This is a table of branches to fsnums. +}; + +/* + * structure for making the linked list of entries by readdir on left branch + * to compare with entries on right branch + */ +struct filldir_node { + struct list_head file_list; // list for directory entries + char *name; // name entry + int hash; // name hash + int namelen; // name len since name is not 0 terminated + int bindex; // we can check for duplicate whiteouts and files in the same branch in order to return -EIO. + int whiteout; // is this a whiteout entry? + char iname[DNAME_INLINE_LEN_MIN]; // Inline name, so we don't need to separately kmalloc small ones +}; + +/* Cache creation/deletion routines. */ +void destroy_filldir_cache(void); +int init_filldir_cache(void); +int init_inode_cache(void); +void destroy_inode_cache(void); +int init_dentry_cache(void); +void destroy_dentry_cache(void); + +/* Initialize and free readdir-specific state. */ +int init_rdstate(struct file *file); +struct unionfs_dir_state *alloc_rdstate(struct inode *inode, int bindex); +struct unionfs_dir_state *find_rdstate(struct inode *inode, loff_t fpos); +void free_rdstate(struct unionfs_dir_state *state); +int add_filldir_node(struct unionfs_dir_state *rdstate, const char *name, + int namelen, int bindex, int whiteout); +struct filldir_node *find_filldir_node(struct unionfs_dir_state *rdstate, + const char *name, int namelen); + +/* Directory hash table. */ +struct unionfs_dir_state { + unsigned int uds_cookie; /* The cookie, which is based off of uii_rdversion */ + unsigned int uds_offset; /* The entry we have returned. */ + int uds_bindex; + loff_t uds_dirpos; /* The offset within the lower level directory. */ + int uds_size; /* How big is the hash table? */ + int uds_hashentries; /* How many entries have been inserted? */ + unsigned long uds_access; + /* This cache list is used when the inode keeps us around. */ + struct list_head uds_cache; + struct list_head uds_list[0]; +}; + +/* Compat stuff.. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) + +# ifdef __CHECKER__ +# define __bitwise__ __attribute__((bitwise)) +# else +# define __bitwise__ +# endif + +typedef unsigned __bitwise__ gfp_t; +void *kzalloc(size_t size, gfp_t flags); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) */ + +#ifdef FIST_MALLOC_DEBUG + +extern void *unionfs_kzalloc(size_t size, gfp_t flags, int line, + const char *file); +extern void *unionfs_kmalloc(size_t size, gfp_t flags, int line, + const char *file); +extern void unionfs_kfree(void *ptr, int line, const char *file); + +extern struct dentry *unionfs_dget_parent(struct dentry *child, int line, + const char *file); +extern struct dentry *unionfs_dget(struct dentry *ptr, int line, + const char *file); +extern void unionfs_dput(struct dentry *ptr, int line, const char *file); +extern struct inode *unionfs_igrab(struct inode *inode, int line, char *file); +extern void unionfs_iput(struct inode *inode, int line, char *file); +extern struct inode *unionfs_iget(struct super_block *sb, unsigned long ino, + int line, char *file); +extern struct dentry *unionfs_lookup_one_len(const char *name, + struct dentry *parent, int len, + int line, const char *file); +void record_path_lookup(struct nameidata *nd, int line, const char *file); +void record_path_release(struct nameidata *nd, int line, const char *file); +struct file *unionfs_dentry_open(struct dentry *ptr, struct vfsmount *mnt, + int flags, int line, const char *file); +void record_set(struct dentry *upper, int index, struct dentry *ptr, + struct dentry *old, int line, const char *file); + +#define KZALLOC(size,flags) unionfs_kzalloc((size),(flags),__LINE__,__FILE__) +#define KMALLOC(size,flags) unionfs_kmalloc((size),(flags),__LINE__,__FILE__) +#define KFREE(ptr) unionfs_kfree((ptr),__LINE__,__FILE__) +#define DGET(d) unionfs_dget((d),__LINE__,__FILE__) +#define DPUT(d) unionfs_dput((d),__LINE__,__FILE__) +# define IPUT(a) unionfs_iput((a),__LINE__,__FILE__) +# define IGET(a,b) unionfs_iget((a),(b),__LINE__,__FILE__) +# define IGRAB(a) unionfs_igrab((a),__LINE__,__FILE__) +#define LOOKUP_ONE_LEN(name,parent,len) unionfs_lookup_one_len((name),(parent),(len),__LINE__,__FILE__) +# define RECORD_PATH_LOOKUP(nd) record_path_lookup((nd),__LINE__,__FILE__) +# define RECORD_PATH_RELEASE(nd) record_path_release((nd),__LINE__,__FILE__) +/* This has the effect of reducing the reference count sooner or later, + * if the file is closed. If it isn't then the mount will be busy and + * you can't unmount. + */ +# define DENTRY_OPEN(d,m,f) unionfs_dentry_open((d),(m),(f),__LINE__,__FILE__) +# define GET_PARENT(dentry) unionfs_dget_parent((dentry),__LINE__,__FILE__) +#else /* not FIST_MALLOC_DEBUG */ +# define KZALLOC(a,b) kzalloc((a),(b)) +# define KMALLOC(a,b) kmalloc((a),(b)) +# define KFREE(a) kfree((a)) +# define DPUT(a) dput((a)) +# define DGET(a) dget((a)) +# define IPUT(a) iput((a)) +# define IGET(a,b) iget((a),(b)) +# define IGRAB(a) igrab((a)) +# define LOOKUP_ONE_LEN(a,b,c) lookup_one_len((a),(b),(c)) +# define RECORD_PATH_LOOKUP(a) +# define RECORD_PATH_RELEASE(a) +# define DENTRY_OPEN(d,m,f) dentry_open((d),(m),(f)) +# define GET_PARENT(d) dget_parent(d) +#endif /* not FIST_MALLOC_DEBUG */ + +/* We can only use 32-bits of offset for rdstate --- blech! */ +#define DIREOF (0xfffff) +#define RDOFFBITS 20 /* This is the number of bits in DIREOF. */ +#define MAXRDCOOKIE (0xfff) +/* Turn an rdstate into an offset. */ +static inline off_t rdstate2offset(struct unionfs_dir_state *buf) +{ + off_t tmp; + tmp = + ((buf->uds_cookie & MAXRDCOOKIE) << RDOFFBITS) | (buf-> + uds_offset & + DIREOF); + return tmp; +} + +/* file private data. */ +struct unionfs_file_info { + int b_start; + int b_end; + atomic_t ufi_generation; + + struct unionfs_dir_state *rdstate; + struct file *ufi_file_i[UNIONFS_INLINE_OBJECTS]; + struct file **ufi_file_p; +}; + +/* File to private Data */ +#define ftopd(file) ((struct unionfs_file_info *)((file)->private_data)) +#define ftopd_lhs(file) ((file)->private_data) +#define ftohf_ptr(file) (ftopd(file)->ufi_file_p) +#define ftohf_inline(file) (ftopd(file)->ufi_file_i) +#define fbstart(file) (ftopd(file)->b_start) +#define fbend(file) (ftopd(file)->b_end) + +/* Inode to private data */ +static inline struct unionfs_inode_info *itopd(const struct inode *inode) +{ + return + &(container_of(inode, struct unionfs_inode_container, vfs_inode)-> + info); +} + +#define itohi_ptr(ino) (itopd(ino)->uii_inode_p) +#define itohi_inline(ino) (itopd(ino)->uii_inode_i) +#define ibstart(ino) (itopd(ino)->b_start) +#define ibend(ino) (itopd(ino)->b_end) + +/* Superblock to private data */ +#define stopd(super) ((struct unionfs_sb_info *)(super)->s_fs_info) +#define stopd_lhs(super) ((super)->s_fs_info) +#define sbstart(sb) 0 +#define sbend(sb) stopd(sb)->b_end +#define sbmax(sb) (stopd(sb)->b_end + 1) +#define stohs_ptr(super) (stopd(super)->usi_sb_p) +#define stohs_inline(super) (stopd(super)->usi_sb_i) +#define stohiddenmnt_ptr(super) (stopd(super)->usi_hidden_mnt_p) +#define stohiddenmnt_inline(super) (stopd(super)->usi_hidden_mnt_i) + +#define unionfs_read_lock(sb) down_read(&stopd(sb)->usi_rwsem) +#define unionfs_read_unlock(sb) up_read(&stopd(sb)->usi_rwsem) +#define unionfs_write_lock(sb) down_write(&stopd(sb)->usi_rwsem) +#define unionfs_write_unlock(sb) up_write(&stopd(sb)->usi_rwsem) + +/* The UNIONFS_NDEBUG versions are defines, the debug versions are inline + * functions with extra checks. */ +#ifdef UNIONFS_NDEBUG +#include "unionfs_macros.h" +#else +#include "unionfs_debugmacros.h" +#endif + +/* The double lock function needs to go after the debugmacros, so that + * dtopd is defined. */ +static inline void double_lock_dentry(struct dentry *d1, struct dentry *d2) +{ + if (d2 < d1) { + struct dentry *tmp = d1; + d1 = d2; + d2 = tmp; + } + lock_dentry(d1); + lock_dentry(d2); +} + +extern int new_dentry_private_data(struct dentry *dentry); +void free_dentry_private_data(struct unionfs_dentry_info *udi); +void update_bstart(struct dentry *dentry); +#define sbt(sb) ((sb)->s_type->name) + +/* + * EXTERNALS: + */ +/* replicates the directory structure upto given dentry in given branch */ +extern struct dentry *create_parents(struct inode *dir, struct dentry *dentry, + int bindex); +struct dentry *create_parents_named(struct inode *dir, struct dentry *dentry, + const char *name, int bindex); + +/* check if two branches overlap */ +extern int is_branch_overlap(struct dentry *dent1, struct dentry *dent2); + +/* partial lookup */ +extern int unionfs_partial_lookup(struct dentry *dentry); + +/* Pass an unionfs dentry and an index and it will try to create a whiteout in branch 'index'. + On error, it will proceed to a branch to the left */ +extern int create_whiteout(struct dentry *dentry, int start); +extern int create_whiteout_parent(struct dentry *parent_dentry, + const char *filename, int start); +/* copies a file from dbstart to newbindex branch */ +extern int copyup_file(struct inode *dir, struct file *file, int bstart, + int newbindex, loff_t size); +extern int copyup_named_file(struct inode *dir, struct file *file, + char *name, int bstart, int new_bindex, + loff_t len); + +/* copies a dentry from dbstart to newbindex branch */ +extern int copyup_dentry(struct inode *dir, struct dentry *dentry, int bstart, + int new_bindex, struct file **copyup_file, loff_t len); +extern int copyup_named_dentry(struct inode *dir, struct dentry *dentry, + int bstart, int new_bindex, const char *name, + int namelen, struct file **copyup_file, + loff_t len); + +extern int remove_whiteouts(struct dentry *dentry, struct dentry *hidden_dentry, + int bindex); + +/* Is this directory empty: 0 if it is empty, -ENOTEMPTY if not. */ +extern int check_empty(struct dentry *dentry, + struct unionfs_dir_state **namelist); +/* Delete whiteouts from this directory in branch bindex. */ +extern int delete_whiteouts(struct dentry *dentry, int bindex, + struct unionfs_dir_state *namelist); + +/* Re-lookup a hidden dentry. */ +extern int unionfs_refresh_hidden_dentry(struct dentry *dentry, int bindex); + +extern void unionfs_reinterpose(struct dentry *this_dentry); +extern struct super_block *unionfs_duplicate_super(struct super_block *sb); + +/* Locking functions. */ +extern int unionfs_setlk(struct file *file, int cmd, struct file_lock *fl); +extern int unionfs_getlk(struct file *file, struct file_lock *fl); + +/* Common file operations. */ +extern int unionfs_file_revalidate(struct file *file, int willwrite); +extern int unionfs_open(struct inode *inode, struct file *file); +extern int unionfs_file_release(struct inode *inode, struct file *file); +extern int unionfs_flush(struct file *file); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) +extern long unionfs_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); +#else +extern int unionfs_ioctl(struct inode *unused, struct file *file, + unsigned int cmd, unsigned long arg); +#endif + +/* Inode operations */ +extern int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry); +int unionfs_unlink(struct inode *dir, struct dentry *dentry); +int unionfs_rmdir(struct inode *dir, struct dentry *dentry); + +int unionfs_d_revalidate(struct dentry *dentry, struct nameidata *nd); + +/* The values for unionfs_interpose's flag. */ +#define INTERPOSE_DEFAULT 0 +#define INTERPOSE_LOOKUP 1 +#define INTERPOSE_REVAL 2 +#define INTERPOSE_REVAL_NEG 3 +#define INTERPOSE_PARTIAL 4 + +extern int unionfs_interpose(struct dentry *this_dentry, struct super_block *sb, + int flag); + +/* Branch management ioctls. */ +int unionfs_ioctl_branchcount(struct file *file, unsigned int cmd, + unsigned long arg); +int unionfs_ioctl_incgen(struct file *file, unsigned int cmd, + unsigned long arg); +int unionfs_ioctl_addbranch(struct inode *inode, unsigned int cmd, + unsigned long arg); +int unionfs_ioctl_delbranch(struct super_block *sb, unsigned long arg); +int unionfs_ioctl_rdwrbranch(struct inode *inode, unsigned int cmd, + unsigned long arg); +int unionfs_ioctl_queryfile(struct file *file, unsigned int cmd, + unsigned long arg); + +/* Verify that a branch is valid. */ +int check_branch(struct nameidata *nd); + +/* Extended attribute functions. */ +extern void *xattr_alloc(size_t size, size_t limit); +extern void xattr_free(void *ptr, size_t size); + +extern ssize_t unionfs_getxattr(struct dentry *dentry, const char *name, + void *value, size_t size); +extern int unionfs_removexattr(struct dentry *dentry, const char *name); +extern ssize_t unionfs_listxattr(struct dentry *dentry, char *list, + size_t size); + +int unionfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags); + +#define copy_inode_size(dst, src) \ + dst->i_size = src->i_size; \ + dst->i_blocks = src->i_blocks; + +/* The root directory is unhashed, but isn't deleted. */ +static inline int d_deleted(struct dentry *d) +{ + return d_unhashed(d) && (d != d->d_sb->s_root); +} + +/* returns the sum of the n_link values of all the underlying inodes of the passed inode */ +static inline int get_nlinks(struct inode *inode) +{ + int sum_nlinks = 0; + int dirs = 0; + int bindex; + struct inode *hidden_inode; + + if (!S_ISDIR(inode->i_mode)) + return itohi(inode)->i_nlink; + + for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) { + hidden_inode = itohi_index(inode, bindex); + if (!hidden_inode || !S_ISDIR(hidden_inode->i_mode)) + continue; + BUG_ON(hidden_inode->i_nlink < 0); + + /* A deleted directory. */ + if (hidden_inode->i_nlink == 0) + continue; + dirs++; + /* A broken directory (e.g., squashfs). */ + if (hidden_inode->i_nlink == 1) + sum_nlinks += 2; + else + sum_nlinks += (hidden_inode->i_nlink - 2); + } + + if (!dirs) + return 0; + return sum_nlinks + 2; +} + +static inline void fist_copy_attr_atime(struct inode *dest, + const struct inode *src) +{ + dest->i_atime = src->i_atime; +} +static inline void fist_copy_attr_times(struct inode *dest, + const struct inode *src) +{ + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; +} +static inline void fist_copy_attr_timesizes(struct inode *dest, + const struct inode *src) +{ + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + copy_inode_size(dest, src); +} +static inline void fist_copy_attr_all(struct inode *dest, + const struct inode *src) +{ + + print_entry_location(); + dest->i_mode = src->i_mode; + /* we do not need to copy if the file is a deleted file */ + if (dest->i_nlink > 0) + dest->i_nlink = get_nlinks(dest); + dest->i_uid = src->i_uid; + dest->i_gid = src->i_gid; + dest->i_rdev = src->i_rdev; + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + dest->i_blksize = src->i_blksize; + dest->i_blkbits = src->i_blkbits; + copy_inode_size(dest, src); + + //DQ: This was a change I noticed in the templates. In 2.6 they removedi_attr_flags. + //Which makes me think they rolled it into flags. + dest->i_flags = src->i_flags; + + print_exit_location(); +} + +struct dentry *unionfs_lookup_backend(struct dentry *dentry, int lookupmode); +int is_stale_inode(struct inode *inode); +void make_stale_inode(struct inode *inode); + +#define IS_SET(sb, check_flag) (check_flag & MOUNT_FLAG(sb)) + +/* unionfs_permission, check if we should bypass error to facilitate copyup */ +#define IS_COPYUP_ERR(err) (err == -EROFS) + +/* unionfs_open, check if we need to copyup the file */ +#define OPEN_WRITE_FLAGS (O_WRONLY | O_RDWR | O_APPEND) +#define IS_WRITE_FLAG(flag) (flag & (OPEN_WRITE_FLAGS)) + +static inline int branchperms(struct super_block *sb, int index) +{ + int perms; + + BUG_ON(index < 0); + + if (index < UNIONFS_INLINE_OBJECTS) + perms = stopd(sb)->usi_branchperms_i[index]; + else + perms = + stopd(sb)->usi_branchperms_p[index - + UNIONFS_INLINE_OBJECTS]; + + return perms; +} +static inline int set_branchperms(struct super_block *sb, int index, int perms) +{ + BUG_ON(index < 0); + + if (index < UNIONFS_INLINE_OBJECTS) + stopd(sb)->usi_branchperms_i[index] = perms; + else + stopd(sb)->usi_branchperms_p[index - UNIONFS_INLINE_OBJECTS] = + perms; + + return perms; +} + +/* Is this file on a read-only branch? */ +static inline int __is_robranch_super(struct super_block *sb, int index, + char *file, const char *function, + int line) +{ + int err = 0; + + print_util_entry_location(); + + if (!(branchperms(sb, index) & MAY_WRITE)) { + err = -EROFS; + } + + print_util_exit_status(err); + return err; +} + +/* Is this file on a read-only branch? */ +static inline int __is_robranch_index(struct dentry *dentry, int index, + char *file, const char *function, + int line) +{ + int err = 0; + int perms; + + print_util_entry_location(); + + BUG_ON(index < 0); + + if (index < UNIONFS_INLINE_OBJECTS) + perms = stopd(dentry->d_sb)->usi_branchperms_i[index]; + else + perms = + stopd(dentry->d_sb)->usi_branchperms_p[index - + UNIONFS_INLINE_OBJECTS]; + + if (!(perms & MAY_WRITE)) { + err = -EROFS; + } else if (IS_RDONLY(dtohd_index(dentry, index)->d_inode)) { + err = -EROFS; + } + + print_util_exit_status(err); + + return err; +} +static inline int __is_robranch(struct dentry *dentry, char *file, + const char *function, int line) +{ + int index; + int err; + + print_util_entry_location(); + + index = dtopd(dentry)->udi_bstart; + BUG_ON(index < 0); + + err = __is_robranch_index(dentry, index, file, function, line); + + print_util_exit_status(err); + + return err; +} + +#define is_robranch(d) __is_robranch(d, __FILE__, __FUNCTION__, __LINE__) +#define is_robranch_super(s, n) __is_robranch_super(s, n, __FILE__, __FUNCTION__, __LINE__) + +/* What do we use for whiteouts. */ +#define WHPFX ".wh." +#define WHLEN 4 +/* If a directory contains this file, then it is opaque. We start with the + * .wh. flag so that it is blocked by loomkup. + */ +#define UNIONFS_DIR_OPAQUE_NAME "__dir_opaque" +#define UNIONFS_DIR_OPAQUE WHPFX UNIONFS_DIR_OPAQUE_NAME + +/* construct whiteout filename */ +static inline char *alloc_whname(const char *name, int len) +{ + char *buf; + + buf = KMALLOC(len + WHLEN + 1, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + strcpy(buf, WHPFX); + strlcat(buf, name, len + WHLEN + 1); + + return buf; +} + +/* +* Defines,structs,and functions for persistant used by kenrel and user +*/ +#define MAX_MAPS 256 +#define UUID_LEN 16 +#define FORWARDMAP_MAGIC 0x4b1cb38f +#define REVERSEMAP_MAGIC 0Xfcafad71 +#define FORWARDMAP_VERSION 0x02 +#define REVERSEMAP_VERSION 0x01 +#define FIRST_VALID_INODE 3 +struct fmaphdr { + uint32_t magic; + uint32_t version; + uint8_t usedbranches; + uint8_t uuid[UUID_LEN]; +}; + +struct rmaphdr { + uint32_t magic; + uint32_t version; + uint8_t fwduuid[UUID_LEN]; + uint8_t revuuid[UUID_LEN]; + fsid_t fsid; +}; +struct bmapent { + fsid_t fsid; + uint8_t uuid[UUID_LEN]; +}; +struct fmapent { + uint8_t fsnum; + uint64_t inode; +}; + +/* Persistant Inode functions */ +extern ino_t get_uin(struct super_block *sb, uint8_t branchnum, + ino_t inode_number, int flag); +extern int write_uin(struct super_block *sb, ino_t ino, int bindex, + ino_t hidden_ino); +extern int get_lin(struct super_block *sb, ino_t inode_number, + struct fmapent *entry); +extern int parse_imap_option(struct super_block *sb, + struct unionfs_dentry_info *hidden_root_info, + char *options); +extern void cleanup_imap_data(struct super_block *sb); + +/* Definitions for various ways to handle errors. + Each flag's value is its bit position */ + +/* 1 = delete whiteout, 0 = check for DELETE_FIRST */ +#define DELETE_WHITEOUT 4 + +/* 1 = use current user's permissions, 0 = use original owner's permissions */ +#define COPYUP_CURRENT_USER 8 + +/* 1 = f/s mounter permission, 0 = check for COPYUP_OWNER */ +#define COPYUP_FS_MOUNTER 16 + +#define VALID_MOUNT_FLAGS (DELETE_WHITEOUT | COPYUP_OWNER | COPYUP_FS_MOUNTER) + +/* + * MACROS: + */ + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif /* not SEEK_SET */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif /* not SEEK_CUR */ + +#ifndef SEEK_END +#define SEEK_END 2 +#endif /* not SEEK_END */ + +#ifndef DEFAULT_POLLMASK +#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) +#endif + +/* + * EXTERNALS: + */ + +/* JS: These two functions are here because it is kind of daft to copy and paste the + * contents of the two functions to 32+ places in unionfs + */ +static inline struct dentry *lock_parent(struct dentry *dentry) +{ + struct dentry *dir = DGET(dentry->d_parent); + + down(&dir->d_inode->i_sem); + return dir; +} + +static inline void unlock_dir(struct dentry *dir) +{ + up(&dir->d_inode->i_sem); + DPUT(dir); +} + +#endif /* __KERNEL__ */ + +/* + * DEFINITIONS FOR USER AND KERNEL CODE: + * (Note: ioctl numbers 1--9 are reserved for fistgen, the rest + * are auto-generated automatically based on the user's .fist file.) + */ +# define FIST_IOCTL_GET_DEBUG_VALUE _IOR(0x15, 1, int) +# define FIST_IOCTL_SET_DEBUG_VALUE _IOW(0x15, 2, int) +# define UNIONFS_IOCTL_BRANCH_COUNT _IOR(0x15, 10, int) +# define UNIONFS_IOCTL_INCGEN _IOR(0x15, 11, int) +# define UNIONFS_IOCTL_ADDBRANCH _IOW(0x15, 12, int) +# define UNIONFS_IOCTL_DELBRANCH _IOW(0x15, 13, int) +# define UNIONFS_IOCTL_RDWRBRANCH _IOW(0x15, 14, int) +# define UNIONFS_IOCTL_QUERYFILE _IOR(0x15, 15, int) + +/* We don't support normal remount, but unionctl uses it. */ +# define UNIONFS_REMOUNT_MAGIC 0x4a5a4380 + +/* should be at least LAST_USED_UNIONFS_PERMISSION<<1 */ +#define MAY_NFSRO 16 + +struct unionfs_addbranch_args { + unsigned int ab_branch; + char *ab_path; + unsigned int ab_perms; +}; + +struct unionfs_rdwrbranch_args { + unsigned int rwb_branch; + unsigned int rwb_perms; +}; + +#endif /* not __UNIONFS_H_ */ +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/unionfs.mod.c newtree/fs/unionfs/unionfs.mod.c --- oldtree/fs/unionfs/unionfs.mod.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/unionfs.mod.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,121 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +#undef unix +struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = __stringify(KBUILD_MODNAME), + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif +}; + +static const struct modversion_info ____versions[] +__attribute_used__ +__attribute__((section("__versions"))) = { + { 0xd32c915c, "struct_module" }, + { 0xe95696e7, "vfs_create" }, + { 0xcf1fe90f, "d_path" }, + { 0x96c05b2d, "kmem_cache_destroy" }, + { 0x12da5bb2, "__kmalloc" }, + { 0x97b206d8, "security_ops" }, + { 0x2b1778ee, "get_sb_nodev" }, + { 0x2f1b5cbf, "generic_file_llseek" }, + { 0x5a27c0c5, "__mark_inode_dirty" }, + { 0xd6ee688f, "vmalloc" }, + { 0xfc2543a8, "vfs_readdir" }, + { 0x89b301d4, "param_get_int" }, + { 0xbeb16aff, "vfs_link" }, + { 0x79aa04a2, "get_random_bytes" }, + { 0x74cc238d, "current_kernel_time" }, + { 0x23310184, "malloc_sizes" }, + { 0xf03a211d, "vfs_llseek" }, + { 0x20000329, "simple_strtoul" }, + { 0xc88c7ada, "_spin_lock" }, + { 0xffe7d2c3, "dput" }, + { 0x4364c43c, "seq_printf" }, + { 0xa03d6a57, "__get_user_4" }, + { 0x25c3b783, "filp_close" }, + { 0x74ccc6a6, "vfs_follow_link" }, + { 0x6c3e2634, "d_find_alias" }, + { 0xc659a6d6, "rwsem_down_write_failed" }, + { 0xf4900a8d, "dentry_open" }, + { 0xb4d1020c, "vfs_mknod" }, + { 0x85df9b6c, "strsep" }, + { 0xd414c791, "generic_read_dir" }, + { 0x2fd1d81c, "vfree" }, + { 0x98bd6f46, "param_set_int" }, + { 0xd31e37a1, "igrab" }, + { 0x201be703, "vfs_symlink" }, + { 0x1d26aa98, "sprintf" }, + { 0x7d11c268, "jiffies" }, + { 0xd533bec7, "__might_sleep" }, + { 0x500e0f7e, "vfs_rmdir" }, + { 0xce378d15, "unlock_rename" }, + { 0xdd0a2ba2, "strlcat" }, + { 0x7c60d66e, "getname" }, + { 0x1b7d4074, "printk" }, + { 0x9f42c98d, "d_rehash" }, + { 0x8cba25c9, "rwsem_wake" }, + { 0x2f287f0d, "copy_to_user" }, + { 0x2cd3086, "__down_failed_trylock" }, + { 0xaec4759f, "vprintk" }, + { 0x177db3cd, "kmem_cache_free" }, + { 0x24db2f29, "lock_rename" }, + { 0x7f215d1a, "dcache_lock" }, + { 0x542ac514, "path_release" }, + { 0x608c9ae, "fput" }, + { 0x69900829, "_spin_unlock" }, + { 0x118f01ea, "putname" }, + { 0xa3eda7a8, "inode_init_once" }, + { 0x7dceceac, "capable" }, + { 0x2328ae0f, "kmem_cache_alloc" }, + { 0xb2fd5ceb, "__put_user_4" }, + { 0x8dfcfaa5, "path_lookup" }, + { 0x2edfde60, "mntput_no_expire" }, + { 0x840e938a, "d_alloc" }, + { 0x107d6ba3, "__get_free_pages" }, + { 0xe5317bae, "do_sync_read" }, + { 0xdd004bdc, "unlock_new_inode" }, + { 0x95105d4, "vfs_statfs" }, + { 0x5950c7ce, "vfs_mkdir" }, + { 0xe51cdc5d, "vfs_unlink" }, + { 0x17bce82f, "kmem_cache_create" }, + { 0xedb27b70, "register_filesystem" }, + { 0x9941ccb8, "free_pages" }, + { 0x1d10cdb2, "kzalloc" }, + { 0x93892132, "iput" }, + { 0x37a0cba, "kfree" }, + { 0xcf67c9b0, "iunique" }, + { 0xf9ae11e9, "generic_permission" }, + { 0x8f3c76ae, "do_sync_write" }, + { 0x351ccbe8, "d_splice_alias" }, + { 0x60a4461c, "__up_wakeup" }, + { 0xcb956da, "unregister_filesystem" }, + { 0xf2e89af8, "init_special_inode" }, + { 0x25da070, "snprintf" }, + { 0xc5ebe7a1, "lookup_one_len" }, + { 0x96b27088, "__down_failed" }, + { 0xc65dd31d, "vfs_rename" }, + { 0xd6c963c, "copy_from_user" }, + { 0x38e011c9, "notify_change" }, + { 0xae57a38d, "clear_inode" }, + { 0x9f5b043, "d_instantiate" }, + { 0x1f0b2def, "get_write_access" }, + { 0x8e87c4af, "rwsem_down_read_failed" }, + { 0x75ee388e, "iget_locked" }, + { 0x8b95db40, "filp_open" }, + { 0xd5b562b8, "generic_shutdown_super" }, +}; + +static const char __module_depends[] +__attribute_used__ +__attribute__((section(".modinfo"))) = +"depends="; + + +MODULE_INFO(srcversion, "5074BD7EEE83F0525B15952"); diff -urN oldtree/fs/unionfs/unionfs_debugmacros.h newtree/fs/unionfs/unionfs_debugmacros.h --- oldtree/fs/unionfs/unionfs_debugmacros.h 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/unionfs_debugmacros.h 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: unionfs_debugmacros.h,v 1.15 2006/01/13 03:00:24 jsipek Exp $ + */ + +#ifndef __UNIONFS_H_ +#error This file should only be included from unionfs.h! +#endif + +/* File to hidden file */ + +static inline struct file *__ftohf_index(const struct file *f, int index, + const char *file, const char *function, + int line) +{ + struct file *hidden_file; + if (index < UNIONFS_INLINE_OBJECTS) + hidden_file = ftopd(f)->ufi_file_i[index]; + else + hidden_file = + ftopd(f)->ufi_file_p[index - UNIONFS_INLINE_OBJECTS]; + + BUG_ON(hidden_file && (atomic_read(&hidden_file->f_count) <= 0)); + + return hidden_file; +} +static inline struct file *__ftohf(const struct file *f, const char *file, + const char *function, int line) +{ + int branch; + BUG_ON(ftopd(f)->b_start < 0); + branch = fbstart(f); + return __ftohf_index(f, branch, file, function, line); +} +static inline struct file *__set_ftohf_index(struct file *f, int index, + struct file *val, const char *file, + const char *function, int line) +{ + BUG_ON(index < 0); + BUG_ON(val && (atomic_read(&val->f_count) <= 0)); + + if (index < UNIONFS_INLINE_OBJECTS) + ftopd(f)->ufi_file_i[index] = val; + else + ftopd(f)->ufi_file_p[index - UNIONFS_INLINE_OBJECTS] = val; + return val; +} +static inline struct file *__set_ftohf(struct file *f, struct file *val, + const char *file, const char *function, + int line) +{ + int branch; + BUG_ON(ftopd(f)->b_start < 0); + branch = fbstart(f); + return __set_ftohf_index(f, branch, val, file, function, line); +} + +#define ftohf(file) __ftohf(file, __FILE__, __FUNCTION__, __LINE__) +#define set_ftohf(file, val) __set_ftohf(file, val, __FILE__, __FUNCTION__, __LINE__) +#define ftohf_index(file, index) __ftohf_index(file, index, __FILE__, __FUNCTION__, __LINE__) +#define set_ftohf_index(file, index, val) __set_ftohf_index(file, index, val, __FILE__, __FUNCTION__, __LINE__) + +/* Inode to hidden inode. */ + +static inline struct inode *__itohi_index(const struct inode *ino, int index, + const char *file, + const char *function, int line) +{ + struct inode *hidden_inode; + BUG_ON(index < 0); + if (index < UNIONFS_INLINE_OBJECTS) + hidden_inode = itopd(ino)->uii_inode_i[index]; + else + hidden_inode = + itopd(ino)->uii_inode_p[index - UNIONFS_INLINE_OBJECTS]; + if (hidden_inode) + BUG_ON((atomic_read(&hidden_inode->i_count)) <= 0); + return hidden_inode; +} +static inline struct inode *__itohi(const struct inode *ino, const char *file, + const char *function, int line) +{ + int index; + BUG_ON(itopd(ino)->b_start < 0); + index = itopd(ino)->b_start; + return __itohi_index(ino, index, file, function, line); +} +static inline struct inode *__set_itohi_index(struct inode *ino, int index, + struct inode *val, + const char *file, + const char *function, int line) +{ + BUG_ON(index < 0); + BUG_ON(val && (atomic_read(&val->i_count) <= 0)); + + if (index < UNIONFS_INLINE_OBJECTS) + itopd(ino)->uii_inode_i[index] = val; + else + itopd(ino)->uii_inode_p[index - UNIONFS_INLINE_OBJECTS] = val; + return val; +} + +#define itohi(ino) __itohi(ino, __FILE__, __FUNCTION__, __LINE__) +#define itohi_index(ino, index) __itohi_index(ino, index, __FILE__, __FUNCTION__, __LINE__) +#define set_itohi_index(ino, index, val) __set_itohi_index(ino, index, val, __FILE__, __FUNCTION__, __LINE__); + +/* Superblock to hidden superblock */ +static inline struct super_block *__stohs_index(const struct super_block *f, + int index, const char *file, + const char *function, int line) +{ + struct super_block *hidden_sb; + if (index < UNIONFS_INLINE_OBJECTS) + hidden_sb = stopd(f)->usi_sb_i[index]; + else + hidden_sb = stopd(f)->usi_sb_p[index - UNIONFS_INLINE_OBJECTS]; + return hidden_sb; +} +static inline struct super_block *__stohs(const struct super_block *sb, + const char *file, + const char *function, int line) +{ + int branch; + BUG_ON(sbstart(sb) != 0); + branch = sbstart(sb); + return __stohs_index(sb, branch, file, function, line); +} +static inline struct super_block *__set_stohs_index(struct super_block *sb, + int index, + struct super_block *val, + const char *file, + const char *function, + int line) +{ + if (index < UNIONFS_INLINE_OBJECTS) + stopd(sb)->usi_sb_i[index] = val; + else + stopd(sb)->usi_sb_p[index - UNIONFS_INLINE_OBJECTS] = val; + return val; +} + +#define stohs(file) __stohs(file, __FILE__, __FUNCTION__, __LINE__) +#define stohs_index(file, index) __stohs_index(file, index, __FILE__, __FUNCTION__, __LINE__) +#define set_stohs_index(file, index, val) __set_stohs_index(file, index, val, __FILE__, __FUNCTION__, __LINE__) + +/* Superblock to hidden vfsmount */ +static inline struct vfsmount *stohiddenmnt_index(struct super_block *sb, + int index) +{ + BUG_ON(index < 0); + if (index < UNIONFS_INLINE_OBJECTS) + return stopd(sb)->usi_hidden_mnt_i[index]; + else + return stopd(sb)->usi_hidden_mnt_p[index - + UNIONFS_INLINE_OBJECTS]; +} + +static inline void set_stohiddenmnt_index(struct super_block *sb, int index, + struct vfsmount *mnt) +{ + BUG_ON(index < 0); + if (index < UNIONFS_INLINE_OBJECTS) + stopd(sb)->usi_hidden_mnt_i[index] = mnt; + else + stopd(sb)->usi_hidden_mnt_p[index - UNIONFS_INLINE_OBJECTS] = + mnt; +} + +/* Get and put branches on the superblock. */ +static inline void set_branch_count(struct super_block *sb, int index, + int count) +{ + BUG_ON(index < 0); + if (index < UNIONFS_INLINE_OBJECTS) + atomic_set(&stopd(sb)->usi_sbcount_i[index], count); + else + atomic_set(&stopd(sb)-> + usi_sbcount_p[index - UNIONFS_INLINE_OBJECTS], + count); +} +static inline int branch_count(struct super_block *sb, int index) +{ + int count; + BUG_ON(index < 0); + if (index < UNIONFS_INLINE_OBJECTS) + count = atomic_read(&stopd(sb)->usi_sbcount_i[index]); + else + count = + atomic_read(&stopd(sb)-> + usi_sbcount_p[index - UNIONFS_INLINE_OBJECTS]); + return count; +} +static inline void branchget(struct super_block *sb, int index) +{ + BUG_ON(index < 0); + if (index < UNIONFS_INLINE_OBJECTS) { + atomic_inc(&stopd(sb)->usi_sbcount_i[index]); + BUG_ON(atomic_read(&stopd(sb)->usi_sbcount_i[index]) < 0); + } else { + atomic_inc(&stopd(sb)-> + usi_sbcount_p[index - UNIONFS_INLINE_OBJECTS]); + BUG_ON(atomic_read(&stopd(sb)-> + usi_sbcount_p[index - + UNIONFS_INLINE_OBJECTS]) < 0); + } +} +static inline void branchput(struct super_block *sb, int index) +{ + BUG_ON(index < 0); + if (index < UNIONFS_INLINE_OBJECTS) { + atomic_dec(&stopd(sb)->usi_sbcount_i[index]); + BUG_ON(atomic_read(&stopd(sb)->usi_sbcount_i[index]) < 0); + } else { + atomic_dec(&stopd(sb)-> + usi_sbcount_p[index - UNIONFS_INLINE_OBJECTS]); + BUG_ON(atomic_read(&stopd(sb)-> + usi_sbcount_p[index - + UNIONFS_INLINE_OBJECTS]) < 0); + } +} + +/* Dentry to Hidden Dentry */ +static inline struct unionfs_dentry_info *__dtopd(const struct dentry *dent, + int check, const char *file, + const char *function, + int line) +{ + struct unionfs_dentry_info *ret; + + ret = (struct unionfs_dentry_info *)(dent)->d_fsdata; + /* We are really only interested in catching poison here. */ + if (ret) { + if (check) { + if ((ret->udi_bend > ret->udi_bcount) + || (ret->udi_bend > sbmax(dent->d_sb))) { + printk(KERN_EMERG + "udi_bend = %d, udi_count = %d, sbmax = %d\n", + ret->udi_bend, ret->udi_bcount, + sbmax(dent->d_sb)); + } + BUG_ON(ret->udi_bend > ret->udi_bcount); + BUG_ON(ret->udi_bend > sbmax(dent->d_sb)); + } + } + + return ret; +} + +#define dtopd(dent) __dtopd(dent, 1, __FILE__, __FUNCTION__, __LINE__) +#define dtopd_nocheck(dent) ((struct unionfs_dentry_info *)(dent)->d_fsdata) +#define dtopd_lhs(dent) ((dent)->d_fsdata) + +/* Macros for locking a dentry. */ +static inline void lock_dentry(struct dentry *d) +{ +#ifdef TRACKLOCK + printk("LOCK:%p\n", d); +#endif + down(&dtopd(d)->udi_sem); +} +static inline void unlock_dentry(struct dentry *d) +{ +#ifdef TRACKLOCK + printk("UNLOCK:%p\n", d); +#endif + up(&dtopd(d)->udi_sem); +} + +#define verify_locked2(dentry) __verify_locked((dentry), (file), (function), (line)) +#define verify_locked(dentry) __verify_locked((dentry), __FILE__, __FUNCTION__, __LINE__) +static inline void __verify_locked(const struct dentry *d, const char *file, + const char *function, int line) +{ +#ifdef TRACKLOCK + printk("MUST BE LOCKED:%p\n", d); +#endif + BUG_ON(down_trylock(&dtopd(d)->udi_sem) == 0); +} + +#define dbend(dentry) __dbend(dentry, __FILE__, __FUNCTION__, __LINE__) +static inline int __dbend(const struct dentry *dentry, const char *file, + const char *function, int line) +{ + verify_locked2(dentry); + return dtopd(dentry)->udi_bend; +} + +#define set_dbend(dentry, val) __set_dbend(dentry, val, __FILE__, __FUNCTION__, __LINE__) +static inline int __set_dbend(const struct dentry *dentry, int val, + const char *file, const char *function, int line) +{ + verify_locked2(dentry); + + BUG_ON((val < 0) && (val != -1)); + BUG_ON(val > __dtopd(dentry, 0, file, function, line)->udi_bcount); + BUG_ON(val > sbmax(dentry->d_sb)); + + dtopd(dentry)->udi_bend = val; + return __dtopd(dentry, 1, file, function, line)->udi_bend; +} + +#define dbstart(dentry) __dbstart(dentry, __FILE__, __FUNCTION__, __LINE__) +static inline int __dbstart(const struct dentry *dentry, const char *file, + const char *function, int line) +{ + verify_locked2(dentry); + return dtopd(dentry)->udi_bstart; +} + +#define set_dbstart(dentry, val) __set_dbstart(dentry, val, __FILE__, __FUNCTION__, __LINE__) +static inline int __set_dbstart(const struct dentry *dentry, int val, + const char *file, const char *function, + int line) +{ + verify_locked2(dentry); + + BUG_ON((val < 0) && (val != -1)); + BUG_ON(val > __dtopd(dentry, 0, file, function, line)->udi_bcount); + BUG_ON(val > sbmax(dentry->d_sb)); + + __dtopd(dentry, 0, file, function, line)->udi_bstart = val; + return __dtopd(dentry, 1, file, function, line)->udi_bstart; +} + +#define dbopaque(dentry) __dbopaque(dentry, __FILE__, __FUNCTION__, __LINE__) +static inline int __dbopaque(const struct dentry *dentry, const char *file, + const char *function, int line) +{ + verify_locked2(dentry); + return dtopd(dentry)->udi_bopaque; +} + +#define set_dbopaque(dentry, val) __set_dbopaque(dentry, val, __FILE__, __FUNCTION__, __LINE__) +static inline int __set_dbopaque(const struct dentry *dentry, int val, + const char *file, const char *function, + int line) +{ + verify_locked2(dentry); + + BUG_ON((val < 0) && (val != -1)); + BUG_ON(val > __dtopd(dentry, 0, file, function, line)->udi_bcount); + BUG_ON(val > sbmax(dentry->d_sb)); + BUG_ON(val > dbend(dentry)); + + __dtopd(dentry, 0, file, function, line)->udi_bopaque = val; + return __dtopd(dentry, 1, file, function, line)->udi_bopaque; +} + +/* Dentry to hidden dentry functions */ +#define dtohd_index(dent, index) __dtohd_index(dent, index, __FILE__, __FUNCTION__, __LINE__,1) +#define dtohd_index_nocheck(dent, index) __dtohd_index(dent, index, __FILE__, __FUNCTION__, __LINE__,0) +/* This pointer should not be generally used except for maintainence functions. */ +#define dtohd_ptr(dent) (dtopd_nocheck(dent)->udi_dentry_p) +#define dtohd_inline(dent) (dtopd_nocheck(dent)->udi_dentry_i) +static inline struct dentry *__dtohd_index(const struct dentry *dent, int index, + const char *file, + const char *function, int line, + int docheck) +{ + struct dentry *d; + + verify_locked2(dent); + BUG_ON(index < 0); + if (docheck) { + if (index > sbend(dent->d_sb)) { + printk + ("Dentry index out of super bounds: index=%d, sbend=%d\n", + index, sbend(dent->d_sb)); + BUG_ON(index > sbend(dent->d_sb)); + } + if (index > dtopd(dent)->udi_bcount) { + printk + ("Dentry index out of array bounds: index=%d, count=%d\n", + index, dtopd(dent)->udi_bcount); + printk("Generation of dentry: %d\n", + atomic_read(&dtopd(dent)->udi_generation)); + printk("Generation of sb: %d\n", + atomic_read(&stopd(dent->d_sb)->usi_generation)); + BUG_ON(index > dtopd(dent)->udi_bcount); + } + } + if (index < UNIONFS_INLINE_OBJECTS) + d = dtopd(dent)->udi_dentry_i[index]; + else + d = dtopd(dent)->udi_dentry_p[index - UNIONFS_INLINE_OBJECTS]; + + BUG_ON(d && (atomic_read(&d->d_count) <= 0)); + + return d; +} + +#define dtohd(dent) __dtohd(dent, __FILE__, __FUNCTION__, __LINE__) +static inline struct dentry *__dtohd(const struct dentry *dent, + const char *file, const char *function, + int line) +{ + struct dentry *d; + int index; + + verify_locked2(dent); + BUG_ON(dbstart(dent) < 0); + index = dbstart(dent); + d = __dtohd_index(dent, index, file, function, line, 1); + + return d; +} + +// Dentry to Hidden Dentry based on index +#define set_dtohd_index(dent, index, val) __set_dtohd_index(dent, index, val, __FILE__, __FUNCTION__, __LINE__, 1) +#define set_dtohd_index_nocheck(dent, index, val) __set_dtohd_index(dent, index, val, __FILE__, __FUNCTION__, __LINE__, 0) +static inline struct dentry *__set_dtohd_index(struct dentry *dent, int index, + struct dentry *val, + const char *file, + const char *function, int line, + int docheck) +{ +#ifdef FIST_MALLOC_DEBUG + struct dentry *old; +#endif + + verify_locked2(dent); + BUG_ON(index < 0); + if (docheck) { + if (index > sbend(dent->d_sb)) { + printk + ("Dentry index out of super bounds: index=%d, sbend=%d\n", + index, sbend(dent->d_sb)); + BUG_ON(index > sbend(dent->d_sb)); + } + if (index > dtopd(dent)->udi_bcount) { + printk + ("Dentry index out of array bounds: index=%d, count=%d\n", + index, dtopd(dent)->udi_bcount); + printk("Generation of dentry: %d\n", + atomic_read(&dtopd(dent)->udi_generation)); + printk("Generation of sb: %d\n", + atomic_read(&stopd(dent->d_sb)->usi_generation)); + BUG_ON(index > dtopd(dent)->udi_bcount); + } + } +#ifdef FIST_MALLOC_DEBUG + if (index < UNIONFS_INLINE_OBJECTS) + old = dtopd(dent)->udi_dentry_i[index]; + else + old = dtopd(dent)->udi_dentry_p[index - UNIONFS_INLINE_OBJECTS]; + record_set(dent, index, val, old, line, file); +#endif + if (index < UNIONFS_INLINE_OBJECTS) + dtopd(dent)->udi_dentry_i[index] = val; + else + dtopd(dent)->udi_dentry_p[index - UNIONFS_INLINE_OBJECTS] = val; + + return val; +} + +extern int fist_get_debug_value(void); +extern int fist_set_debug_value(int val); +extern void fist_dprint_internal(const char *file, const char *function, + int line, int level, char *str, ...) + __attribute__ ((format(__printf__, 5, 6))); + +extern void fist_print_dentry(const char *, const struct dentry *); +extern void __fist_print_dentry(const char *, const struct dentry *, int); +extern void fist_print_generic_dentry(const char *, const struct dentry *); +extern void fist_print_generic_dentry3(const char *, const char *, + const struct dentry *); +extern void __fist_print_generic_dentry(const char *, const char *, const + struct dentry *, int); +extern void fist_print_inode(const char *, const struct inode *); +extern void fist_print_generic_inode(const char *, const struct inode *); +extern void fist_print_file(const char *, const struct file *); +extern void fist_checkinode(const struct inode *, const char *); +extern void fist_print_sb(const char *str, const struct super_block *); + +extern char *add_indent(void); +extern char *del_indent(void); + +#define fist_dprint(level, str, args...) fist_dprint_internal(__FILE__, __FUNCTION__, __LINE__, level, KERN_DEBUG str, ## args) +#define print_entry(format, args...) fist_dprint(4, "%sIN: %s %s:%d " format "\n", add_indent(), __FUNCTION__, __FILE__, __LINE__, ##args) +#define print_entry_location() fist_dprint(4, "%sIN: %s %s:%d\n", add_indent(), __FUNCTION__, __FILE__, __LINE__) +#define print_exit_location() fist_dprint(5, "%s OUT: %s %s:%d\n", del_indent(), __FUNCTION__, __FILE__, __LINE__) +#define print_exit_status(status) fist_dprint(5, "%s OUT: %s %s:%d, STATUS: %d\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, status) +#define print_exit_pointer(status) \ +do { \ + if (IS_ERR(status)) \ + fist_dprint(5, "%s OUT: %s %s:%d, RESULT: %ld\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, PTR_ERR(status)); \ + else \ + fist_dprint(5, "%s OUT: %s %s:%d, RESULT: 0x%p\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, status); \ +} while (0) + +#define print_util_entry(format, args...) fist_dprint(6, "%sIN: %s %s:%d" format "\n", add_indent(), __FUNCTION__, __FILE__, __LINE__, ##args) +#define print_util_entry_location() fist_dprint(6, "%sIN: %s %s:%d\n", add_indent(), __FUNCTION__, __FILE__, __LINE__) +#define print_util_exit_location() fist_dprint(7, "%s OUT: %s %s:%d\n", del_indent(), __FUNCTION__, __FILE__, __LINE__) +#define print_util_exit_status(status) fist_dprint(7, "%s OUT: %s %s:%d, STATUS: %d\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, status) +#define print_util_exit_pointer(status) \ +do { \ + if (IS_ERR(status)) \ + fist_dprint(7, "%s OUT: %s %s:%d, RESULT: %ld\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, PTR_ERR(status)); \ + else \ + fist_dprint(5, "%s OUT: %s %s:%d, RESULT: 0x%x\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, PTR_ERR(status)); \ +} while (0) + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/unionfs_macros.h newtree/fs/unionfs/unionfs_macros.h --- oldtree/fs/unionfs/unionfs_macros.h 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/unionfs_macros.h 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: unionfs_macros.h,v 1.9 2006/01/13 03:00:24 jsipek Exp $ + */ + +#ifndef __UNIONFS_H_ +#error This file should only be included from unionfs.h! +#endif + +/* File to hidden file. */ +#define ftohf(f) (fbstart(f) < UNIONFS_INLINE_OBJECTS ? ftopd(f)->ufi_file_i[fbstart(f)] : ftopd(f)->ufi_file_p[fbstart(f) - UNIONFS_INLINE_OBJECTS]) +#define ftohf_index(f, index) (index < UNIONFS_INLINE_OBJECTS ? ftopd(f)->ufi_file_i[index] : ftopd(f)->ufi_file_p[index - UNIONFS_INLINE_OBJECTS]) + +#define set_ftohf_index(f, index, val) \ +do { \ + struct file *f2 = f;\ + if (index < UNIONFS_INLINE_OBJECTS) \ + ftopd(f2)->ufi_file_i[index] = val; \ + else \ + ftopd(f2)->ufi_file_p[index - UNIONFS_INLINE_OBJECTS] = val; \ +} while (0); +#define set_ftohf(f, val) \ +do { \ + struct file *f2 = f;\ + int index = fbstart(f2); \ + if (index < UNIONFS_INLINE_OBJECTS) \ + ftopd(f2)->ufi_file_i[index] = val; \ + else \ + ftopd(f2)->ufi_file_p[index - UNIONFS_INLINE_OBJECTS] = val; \ +} while (0); + +/* Inode to hidden inode. */ +#define itohi(i) (ibstart(i) < UNIONFS_INLINE_OBJECTS ? itopd(i)->uii_inode_i[ibstart(i)] : itopd(i)->uii_inode_p[ibstart(i) - UNIONFS_INLINE_OBJECTS]) +#define itohi_index(i, index) (index < UNIONFS_INLINE_OBJECTS ? itopd(i)->uii_inode_i[index] : itopd(i)->uii_inode_p[index - UNIONFS_INLINE_OBJECTS]) + +#define set_itohi_index(i, index, val) \ +do { \ + struct inode *i2 = i;\ + if (index < UNIONFS_INLINE_OBJECTS) \ + itopd(i2)->uii_inode_i[index] = val; \ + else \ + itopd(i2)->uii_inode_p[index - UNIONFS_INLINE_OBJECTS] = val; \ +} while (0); +#define set_itohi(i, val) \ +do { \ + struct inode *i2 = i;\ + int index = ibstart(i2); \ + if (index < UNIONFS_INLINE_OBJECTS) \ + itopd(i2)->uii_inode_i[index] = val; \ + else \ + itopd(i2)->uii_inode_p[index - UNIONFS_INLINE_OBJECTS] = val; \ +} while (0); + +/* Superblock to hidden superblock. */ +#define stohs(o) (sbstart(o) < UNIONFS_INLINE_OBJECTS ? stopd(o)->usi_sb_i[sbstart(o)] : stopd(o)->usi_sb_p[sbstart(o) - UNIONFS_INLINE_OBJECTS]) +#define stohs_index(o, index) (index < UNIONFS_INLINE_OBJECTS ? stopd(o)->usi_sb_i[index] : stopd(o)->usi_sb_p[index - UNIONFS_INLINE_OBJECTS]) + +#define set_stohs_index(o, index, val) \ +do { \ + struct super_block *s2 = o;\ + if (index < UNIONFS_INLINE_OBJECTS) \ + stopd(s2)->usi_sb_i[index] = val; \ + else \ + stopd(s2)->usi_sb_p[index - UNIONFS_INLINE_OBJECTS] = val; \ +} while (0); +#define set_stohs(o, val) \ +do { \ + struct super_block *s2 = o;\ + int index = sbstart(s2); \ + if (index < UNIONFS_INLINE_OBJECTS) \ + stopd(s2)->usi_sb_i[index] = val; \ + else \ + stopd(s2)->usi_sb_p[index - UNIONFS_INLINE_OBJECTS] = val; \ +} while (0); + +/* Super to hidden mount. */ +#define stohiddenmnt_index(o, index) (index < UNIONFS_INLINE_OBJECTS ? stopd(o)->usi_hidden_mnt_i[index] : stopd(o)->usi_hidden_mnt_p[index - UNIONFS_INLINE_OBJECTS]) + +#define set_stohiddenmnt_index(o, index, val) \ +do { \ + struct super_block *s2 = o;\ + if (index < UNIONFS_INLINE_OBJECTS) \ + stopd(s2)->usi_hidden_mnt_i[index] = val; \ + else \ + stopd(s2)->usi_hidden_mnt_p[index - UNIONFS_INLINE_OBJECTS] = val; \ +} while (0); + +/* Branch count macros. */ +#define branch_count(o, index) \ +(index < UNIONFS_INLINE_OBJECTS ? \ +atomic_read(&stopd(o)->usi_sbcount_i[index]) : \ +atomic_read(&stopd(o)->usi_sbcount_p[index - UNIONFS_INLINE_OBJECTS])) + +#define set_branch_count(o, index, val) \ +do { \ + if (index < UNIONFS_INLINE_OBJECTS) \ + atomic_set(&stopd(o)->usi_sbcount_i[index], val); \ + else \ + atomic_set(&stopd(o)->usi_sbcount_p[index - UNIONFS_INLINE_OBJECTS], val); \ +} while (0); +#define branchget(o, index) \ +do { \ + if (index < UNIONFS_INLINE_OBJECTS) \ + atomic_inc(&stopd(o)->usi_sbcount_i[index]); \ + else \ + atomic_inc(&stopd(o)->usi_sbcount_p[index - UNIONFS_INLINE_OBJECTS]); \ +} while (0); +#define branchput(o, index) \ +do { \ + if (index < UNIONFS_INLINE_OBJECTS) \ + atomic_dec(&stopd(o)->usi_sbcount_i[index]); \ + else \ + atomic_dec(&stopd(o)->usi_sbcount_p[index - UNIONFS_INLINE_OBJECTS]); \ +} while (0); + +/* Dentry macros */ +#define dtopd(dent) ((struct unionfs_dentry_info *)(dent)->d_fsdata) +#define dtopd_lhs(dent) ((dent)->d_fsdata) +#define dtopd_nocheck(dent) dtopd(dent) +#define dbstart(dent) (dtopd(dent)->udi_bstart) +#define set_dbstart(dent, val) do { dtopd(dent)->udi_bstart = val; } while(0) +#define dbend(dent) (dtopd(dent)->udi_bend) +#define set_dbend(dent, val) do { dtopd(dent)->udi_bend = val; } while(0) +#define dbopaque(dent) (dtopd(dent)->udi_bopaque) +#define set_dbopaque(dent, val) do { dtopd(dent)->udi_bopaque = val; } while (0) + +#define set_dtohd_index(dent, index, val) \ +do { \ + struct dentry *d2 = dent; \ + if (index < UNIONFS_INLINE_OBJECTS) \ + dtopd(d2)->udi_dentry_i[index] = val; \ + else \ + dtopd(d2)->udi_dentry_p[index - UNIONFS_INLINE_OBJECTS] = val; \ +} while (0); + +static inline struct dentry *dtohd_index(const struct dentry *dent, int index) +{ + struct dentry *d; + if (index < UNIONFS_INLINE_OBJECTS) + d = dtopd(dent)->udi_dentry_i[index]; + else + d = dtopd(dent)->udi_dentry_p[index - UNIONFS_INLINE_OBJECTS]; + return d; +} + +static inline struct dentry *dtohd(const struct dentry *dent) +{ + struct dentry *d; + int index; + index = dbstart(dent); + if (index < UNIONFS_INLINE_OBJECTS) + d = dtopd(dent)->udi_dentry_i[index]; + else + d = dtopd(dent)->udi_dentry_p[index - UNIONFS_INLINE_OBJECTS]; + return d; +} + +#define set_dtohd_index_nocheck(dent, index, val) set_dtohd_index(dent, index, val) +#define dtohd_index_nocheck(dent, index) dtohd_index(dent, index) + +#define dtohd_ptr(dent) (dtopd_nocheck(dent)->udi_dentry_p) +#define dtohd_inline(dent) (dtopd_nocheck(dent)->udi_dentry_i) + +/* Macros for locking a dentry. */ +#define lock_dentry(d) down(&dtopd(d)->udi_sem) +#define unlock_dentry(d) up(&dtopd(d)->udi_sem) +#define verify_locked(d) + +/* All of these should be noops. */ +static inline int fist_get_debug_value(void) +{ + return 0; +} +static inline int fist_set_debug_value(int val) +{ + return -ENOTSUPP; +} + +#define fist_print_dentry(msg, o) +#define __fist_print_dentry(msg, o, i) +#define fist_print_generic_dentry(msg, o) +#define fist_print_generic_dentry3(msg, o) +#define __fist_print_generic_dentry(msg, o, i) +#define fist_print_inode(msg, o) +#define fist_print_generic_inode(msg, o) +#define fist_print_file(msg, o) +#define fist_checkinode(o, msg) +#define fist_print_sb(msg, o) + +#define fist_dprint(args...) +#define print_entry(args...) +#define print_entry_location() +#define print_exit_location() +#define print_exit_status(status) +#define print_exit_pointer(status) +#define print_util_entry(args...) +#define print_util_entry_location() +#define print_util_exit_location() +#define print_util_exit_status(status) +#define print_util_exit_pointer(status) + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/unionimap.c newtree/fs/unionfs/unionimap.c --- oldtree/fs/unionfs/unionimap.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/unionimap.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: unionimap.c,v 1.21 2006/01/03 19:09:12 dquigley Exp $ + */ + +#include "unionimap.h" + +/** + * print_usage() + * Function used to print out usage information + * when an error is encountered + */ +void print_usage() +{ + fprintf(stderr, + "unionimap version: $Id: unionimap.c,v 1.21 2006/01/03 19:09:12 dquigley Exp $\n"); + fprintf(stderr, "Distributed with Unionfs " UNIONFS_VERSION "\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Usage: unionimap [-c] [-a ARG:] filename path\n"); + fprintf(stderr, " flag -c: create forward map with name filename\n"); + fprintf(stderr, + " flag -a ARG: create reverse map with name filename and path and add it to forwardmap ARG\n"); + fprintf(stderr, + " flag -d: if set once will dump the header of the map if twice it will also dump the contents\n"); + fprintf(stderr, " flag -h: prints this message then quits\n"); + fprintf(stderr, + " please note that -c -a and -d are mutually exclusive\n"); +} + +/** + * create_forwardmap(char *filename) + * verifies that the forward map is valid. + * + */ +int create_forwardmap(char *filename) +{ + int byteswritten = 0, err = 0; + int fwrdmap = 0; + struct fmaphdr header; + void *table = NULL; + uuid_t uuid; + + fwrdmap = open(filename, O_WRONLY | O_CREAT, S_IRWXU); + if (fwrdmap < 0) { + err = -EINVAL; + goto out; + } + memset(&header, 0, sizeof(struct fmaphdr)); + header.version = FORWARDMAP_VERSION; + header.magic = FORWARDMAP_MAGIC; + header.usedbranches = 0; + uuid_generate(uuid); + memcpy(&header.uuid, &uuid, UUID_LEN); + byteswritten = write(fwrdmap, (void *)&header, sizeof(struct fmaphdr)); + if (byteswritten < sizeof(struct fmaphdr)) { + perror("Failed Writting header: "); + err = -EIO; + goto out; + } + table = malloc(sizeof(struct bmapent[256])); + if (!table) { + err = -ENOMEM; + goto out; + } + memset(table, 0, sizeof(struct bmapent[256])); + byteswritten = write(fwrdmap, table, sizeof(struct bmapent[256])); + if (byteswritten < sizeof(struct bmapent[256])) { + perror("Failed writting table: "); + err = -EIO; + goto out; + } + out: + if (fwrdmap) + close(fwrdmap); + if (table) + free(table); + + return err; +} +int open_forwardmap(struct fmaphdr *header, char *forwardmap) +{ + int fwrdmap = 0, bytesread = 0, err = 0; + fwrdmap = open(forwardmap, O_RDWR); + if (fwrdmap < 0) { + perror("Open on Forwardmap Failed: "); + err = errno; + goto out_error; + } + bytesread = read(fwrdmap, (void *)header, sizeof(struct fmaphdr)); + if (bytesread < 0 || bytesread < sizeof(struct fmaphdr)) { + err = -EINVAL; + goto out_error; + } + if (header->magic != FORWARDMAP_MAGIC + || header->version != FORWARDMAP_VERSION) { + err = -EINVAL; + goto out_error; + } + if (header->usedbranches == 255) { + fprintf(stderr, + "Forwardmap already contains maximum number of reverse maps"); + err = -EINVAL; + goto out_error; + } + err = fwrdmap; + goto out; + out_error: + if (fwrdmap) + close(fwrdmap); + out: + return err; +} +int check_if_entry_exists(int fwrdmap, struct statfs stat, char *path) +{ + int err = 0, bytesread = 0, i; + struct fmaphdr header; + struct bmapent btable[256]; + fsid_t fsid; + + if (fwrdmap < 0) { + err = -EINVAL; + goto out; + } + err = lseek(fwrdmap, 0L, SEEK_SET); + if (err) { + goto out; + } + bytesread = read(fwrdmap, (void *)&header, sizeof(struct fmaphdr)); + if (bytesread != sizeof(struct fmaphdr)) { + err = -EIO; + goto out; + } + bytesread = read(fwrdmap, (void *)&btable, sizeof(struct bmapent[256])); + if (bytesread != sizeof(struct bmapent[256])) { + err = -EIO; + goto out; + } + if (((unsigned int *)&stat.f_fsid)[0] + || ((unsigned int *)&stat.f_fsid)[1]) { + fsid = stat.f_fsid; + } else { + err = mkfsid(path, &fsid); + if (err) { + goto out; + } + } + for (i = 0; i < header.usedbranches; i++) { + if (!memcmp(&fsid, &btable[i].fsid, sizeof(fsid_t))) { + err = 1; + break; + } + } + out: + return err; +} +int create_reversemap(char *filename, char *path, char *forwardmap) +{ + int byteswritten = 0, err = 0, seekres = 0; + off_t offset = 0; + int fwrdmap = 0, revmap = 0; + struct fmaphdr fwdheader; + struct rmaphdr revheader; + struct statfs stat; + struct bmapent ent; + uuid_t uuid; + + fwrdmap = open_forwardmap(&fwdheader, forwardmap); + if (fwrdmap < 0) { + err = fwrdmap; + goto out; + } + memset(&stat, 0, sizeof(struct statfs)); + err = statfs(path, &stat); + if (err) { + perror("statfs failed on path: "); + goto out; + } + err = check_if_entry_exists(fwrdmap, stat, path); + if (err) { + if (err > 0) { + err = -EINVAL; + fprintf(stderr, + "Specified fs already exists in the forward map\n"); + } + goto out; + } + revmap = open(filename, O_WRONLY | O_CREAT, S_IRWXU); + if (!revmap) { + err = -EINVAL; + perror("Open on Reversemap failed: "); + goto out; + } + revheader.version = REVERSEMAP_VERSION; + revheader.magic = REVERSEMAP_MAGIC; + uuid_generate(uuid); + memcpy(&revheader.revuuid, &uuid, UUID_LEN); + memcpy(&revheader.fwduuid, &fwdheader.uuid, UUID_LEN); + + if (((unsigned int *)&stat.f_fsid)[0] + || ((unsigned int *)&stat.f_fsid)[1]) { + revheader.fsid = stat.f_fsid; + } else { + err = mkfsid(path, &revheader.fsid); + if (err) { + goto out; + } + + } + byteswritten = write(revmap, &revheader, sizeof(struct rmaphdr)); + if (byteswritten < sizeof(struct rmaphdr)) { + err = -EIO; + perror("Reversemap Write failed: "); + goto out; + } + + offset = + sizeof(struct fmaphdr) + + (fwdheader.usedbranches * sizeof(struct bmapent)); + seekres = lseek(fwrdmap, offset, SEEK_SET); + if (!(seekres == offset)) { + err = -EIO; + perror("Couldent seek to offset in uuid table: "); + } + errno = 0; + memcpy(&ent.uuid, &uuid, UUID_LEN); + memcpy(&ent.fsid, &revheader.fsid, sizeof(fsid_t)); + byteswritten = write(fwrdmap, &ent, sizeof(struct bmapent)); + if (byteswritten < sizeof(struct bmapent)) { + perror("Forwardmap Write failed to write uuid to table: "); + err = -EIO; + goto out; + } + fwdheader.usedbranches++; + offset = (int)&(((struct fmaphdr *)(0))->usedbranches); + seekres = lseek(fwrdmap, offset, SEEK_SET); + if (!(seekres == offset)) { + perror("Couldent seek to usedbranch offset: "); + err = -EIO; + goto out; + } + byteswritten = write(fwrdmap, &fwdheader.usedbranches, sizeof(uint8_t)); + if (byteswritten < sizeof(uint8_t)) { + perror("Forwardmap Write failed to update usedbranches: "); + err = -EIO; + goto out; + } + + out: + if (fwrdmap) { + close(fwrdmap); + } + if (revmap) { + close(revmap); + } + return err; +} +int print_forwardmap(int file, int debug_level) +{ + int err = 0, bytesread = 0, i; + struct fmaphdr header; + struct bmapent btable[256]; + char *uuid_unparsed; + struct fmapent entry; + + if (file < 0 || debug_level <= 0) { + err = -EINVAL; + goto out; + } + err = lseek(file, 0L, SEEK_SET); + if (err) { + goto out; + } + bytesread = read(file, (void *)&header, sizeof(struct fmaphdr)); + if (bytesread != sizeof(struct fmaphdr)) { + err = -EIO; + goto out; + } + uuid_unparsed = (char *)malloc(37); + if (!uuid_unparsed) { + err = -EIO; + goto out; + } + memset(uuid_unparsed, 0, 37); + fprintf(stdout, "Unionfs Forwardmap:\n"); + fprintf(stdout, "Magic: %x\n", header.magic); + fprintf(stdout, "Version: %d\n", header.version); + fprintf(stdout, "Used Branches: %d\n", header.usedbranches); + uuid_unparse(header.uuid, uuid_unparsed); + fprintf(stdout, "UUID: %s\n", uuid_unparsed); + bytesread = read(file, (void *)&btable, sizeof(struct bmapent[256])); + if (bytesread != sizeof(struct bmapent[256])) { + err = -EIO; + goto out; + } + for (i = 0; i < header.usedbranches; i++) { + fprintf(stdout, "Branch at index : %d\n", i); + fprintf(stdout, "fsid: %04x%04x\n", + ((unsigned int *)&btable[i].fsid)[0], + ((unsigned int *)&btable[i].fsid)[1]); + uuid_unparse(btable[i].uuid, uuid_unparsed); + fprintf(stdout, "uuid: %s\n", uuid_unparsed); + } + if (debug_level > 1) { + unsigned long inode = 1; + fprintf(stdout, "%-11s %-8s %-22s\n", "Unionfs", "FS Num", + "Lower-Level"); + while (read(file, (void *)&entry, sizeof(struct fmapent))) { + fprintf(stdout, "%-11lu %-8d %-22llu\n", inode++, + entry.fsnum, + (long long unsigned int)entry.inode); + } + } + out: + return err; + +} +int print_reversemap(int file, int debug_level) +{ + + int err = 0, bytesread = 0; + struct rmaphdr header; + char *uuid_unparsed = NULL; + uint64_t inode; + + if (file < 0 || debug_level <= 0) { + err = -EINVAL; + goto out; + } + err = lseek(file, 0L, SEEK_SET); + if (err) { + goto out; + } + bytesread = read(file, (void *)&header, sizeof(struct rmaphdr)); + if (bytesread != sizeof(struct rmaphdr)) { + err = -EIO; + goto out; + } + uuid_unparsed = (char *)malloc(37); + if (!uuid_unparsed) { + err = -ENOMEM; + goto out; + } + memset(uuid_unparsed, 0, 37); + fprintf(stdout, "Unionfs Reversemap:\n"); + fprintf(stdout, "Magic: %x\n", header.magic); + fprintf(stdout, "Version: %d\n", header.version); + uuid_unparse(header.fwduuid, uuid_unparsed); + fprintf(stdout, "Forward UUID: %s\n", uuid_unparsed); + uuid_unparse(header.revuuid, uuid_unparsed); + fprintf(stdout, "Reverse UUID: %s\n", uuid_unparsed); + fprintf(stdout, "fsid: %04x%04x\n", ((unsigned int *)&header.fsid)[0], + ((unsigned int *)&header.fsid)[1]); + if (debug_level > 1) { + fprintf(stdout, "%-11s %-22s\n", "Lower", "Unionfs"); + while (read(file, (void *)&inode, sizeof(uint64_t))) { + unsigned long lowerlevel = 0; + if (inode) { + fprintf(stdout, "%-11lu %-22llu\n", + lowerlevel++, + (long long unsigned int)inode); + } + } + } + out: + if (uuid_unparsed) { + free(uuid_unparsed); + } + return err; +} +int dump_map(char *filename, int debug_level) +{ + int err = 0, bytesread = 0, file = 0; + uint32_t magic; + + file = open(filename, O_RDONLY); + if (file < 0) { + err = -EINVAL; + goto out; + } + bytesread = read(file, (void *)&magic, sizeof(uint32_t)); + if (bytesread < sizeof(uint32_t)) { + err = -EINVAL; + goto out; + } + if (magic == FORWARDMAP_MAGIC) { + err = print_forwardmap(file, debug_level); + } else if (magic == REVERSEMAP_MAGIC) { + err = print_reversemap(file, debug_level); + } else { + err = -EINVAL; + } + out: + if (file) { + close(file); + } + + return err; +} + +int main(int argc, char **argv) +{ + int c = 0; //Temp varliable to hold our character for the switch + int cflag = 0, aflag = 0, dflag = 0; + int err = 0; + char *avalue = NULL; + if (argc < 2) { + print_usage(); + err = -EINVAL; + goto out; + } + while ((c = getopt(argc, argv, "a:cd")) != -1) { + switch (c) { + case 'c': + cflag = c; + break; + case 'a': + aflag = 1; + avalue = strdup(optarg); + if (!avalue) { + perror("strdup"); + exit(1); + } + break; + case 'd': + dflag++; + break; + case '?': + if (isprint(optopt)) + fprintf(stderr, "Unknown option `-%c'.\n", + optopt); + else + fprintf(stderr, + "Unknown option character `\\x%x'.\n", + optopt); + print_usage(); + err = -EINVAL; + goto out; + break; + default: + print_usage(); + err = -EINVAL; + goto out; + break; + } + } + if (optind == argc) { + print_usage(); + err = -EINVAL; + goto out; + } + if (!(cflag ^ aflag ^ dflag)) { + print_usage(); + err = -EINVAL; + goto out; + } + if (cflag) { + err = create_forwardmap(argv[optind]); + if (err) { + unlink(argv[optind]); + } + goto out; + } else if (aflag) { + if (optind + 1 > argc) { + print_usage(); + err = -EINVAL; + goto out; + } + + err = create_reversemap(argv[optind], argv[optind + 1], avalue); + if (err) { + unlink(argv[optind]); + goto out; + } + + } else if (dflag) { + err = dump_map(argv[optind], dflag); + if (err) { + goto out; + } + } + out: + free(avalue); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/unionimap.h newtree/fs/unionfs/unionimap.h --- oldtree/fs/unionfs/unionimap.h 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/unionimap.h 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: unionimap.h,v 1.11 2006/01/03 01:15:56 jsipek Exp $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * Defines,structs,and functions for persistent inodes used by kernel and user + */ +#define MAX_MAPS 256 +#define UUID_LEN 16 +#define FORWARDMAP_MAGIC 0x4b1cb38f +#define REVERSEMAP_MAGIC 0Xfcafad71 +#define FORWARDMAP_VERSION 0x02 +#define REVERSEMAP_VERSION 0x01 + +typedef u_int8_t uint8_t; +typedef u_int32_t uint32_t; +typedef u_int64_t uint64_t; + +struct fmaphdr { + uint32_t magic; + uint32_t version; + uint8_t usedbranches; + uint8_t uuid[UUID_LEN]; +}; +struct bmapent { + fsid_t fsid; + uint8_t uuid[UUID_LEN]; +}; + +struct rmaphdr { + uint32_t magic; + uint32_t version; + uint8_t fwduuid[UUID_LEN]; + uint8_t revuuid[UUID_LEN]; + fsid_t fsid; +}; + +struct bpair { + fsid_t fsid; + uint8_t fsnum; +}; + +struct fmapent { + uint8_t fsnum; + uint64_t inode; +}; + +extern int mkfsid(char *path, fsid_t * fsid); +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/unlink.c newtree/fs/unionfs/unlink.c --- oldtree/fs/unionfs/unlink.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/unlink.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: unlink.c,v 1.37 2006/01/13 03:00:24 jsipek Exp $ + */ + +#include "unionfs.h" + +static int unionfs_unlink_all(struct inode *dir, struct dentry *dentry) +{ + struct dentry *hidden_dentry; + struct dentry *hidden_dir_dentry; + int bstart, bend, bindex; + int err = 0; + int global_err = 0; + + print_entry_location(); + + if ((err = unionfs_partial_lookup(dentry))) + goto out; + + bstart = dbstart(dentry); + bend = dbend(dentry); + + for (bindex = bend; bindex >= bstart; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + + hidden_dir_dentry = lock_parent(hidden_dentry); + + /* avoid destroying the hidden inode if the file is in use */ + DGET(hidden_dentry); + if (!(err = is_robranch_super(dentry->d_sb, bindex))) + err = vfs_unlink(hidden_dir_dentry->d_inode, + hidden_dentry); + DPUT(hidden_dentry); + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + unlock_dir(hidden_dir_dentry); + + if (err) { + /* passup the last error we got */ + if (!IS_COPYUP_ERR(err)) + goto out; + global_err = err; + } + } + + /* check if encountered error in the above loop */ + if (global_err) { + /* If we failed in the leftmost branch, then err will be set + * and we should move one over to create the whiteout. + * Otherwise, we should try in the leftmost branch. */ + if (err) { + if (dbstart(dentry) == 0) { + goto out; + } + err = create_whiteout(dentry, dbstart(dentry) - 1); + } else { + err = create_whiteout(dentry, dbstart(dentry)); + } + } else if (dbopaque(dentry) != -1) { + /* There is a hidden lower-priority file with the same name. */ + err = create_whiteout(dentry, dbopaque(dentry)); + } + out: + /* propagate number of hard-links */ + if (dentry->d_inode->i_nlink != 0) { + dentry->d_inode->i_nlink = get_nlinks(dentry->d_inode); + if (!err && global_err) + dentry->d_inode->i_nlink--; + } + /* We don't want to leave negative leftover dentries for revalidate. */ + if (!err && (global_err || dbopaque(dentry) != -1)) + update_bstart(dentry); + + print_exit_status(err); + return err; +} + +static int unionfs_unlink_whiteout(struct inode *dir, struct dentry *dentry) +{ + int err = 0; + struct dentry *hidden_old_dentry; + struct dentry *hidden_wh_dentry = NULL; + struct dentry *hidden_old_dir_dentry, *hidden_new_dir_dentry; + char *name = NULL; + struct iattr newattrs; + + print_entry_location(); + fist_print_dentry("IN unionfs_unlink_whiteout: ", dentry); + + /* create whiteout, get the leftmost underlying dentry and rename it */ + hidden_old_dentry = dtohd(dentry); + + /* lookup .wh.foo first, MUST NOT EXIST */ + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + hidden_wh_dentry = + LOOKUP_ONE_LEN(name, hidden_old_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(hidden_wh_dentry)) { + err = PTR_ERR(hidden_wh_dentry); + goto out; + } + BUG_ON(hidden_wh_dentry->d_inode != NULL); + + DGET(hidden_old_dentry); + + hidden_old_dir_dentry = GET_PARENT(hidden_old_dentry); + hidden_new_dir_dentry = GET_PARENT(hidden_wh_dentry); + lock_rename(hidden_old_dir_dentry, hidden_new_dir_dentry); + + if (!(err = is_robranch(dentry))) { + if (S_ISREG(hidden_old_dentry->d_inode->i_mode)) { + err = vfs_rename(hidden_old_dir_dentry->d_inode, + hidden_old_dentry, + hidden_new_dir_dentry->d_inode, + hidden_wh_dentry); + } else { + err = vfs_unlink(hidden_old_dir_dentry->d_inode, + hidden_old_dentry); + if (!err) + err = vfs_create(hidden_new_dir_dentry->d_inode, + hidden_wh_dentry, 0666, NULL); + } + } + + unlock_rename(hidden_old_dir_dentry, hidden_new_dir_dentry); + DPUT(hidden_old_dir_dentry); + DPUT(hidden_new_dir_dentry); + DPUT(hidden_old_dentry); + DPUT(hidden_wh_dentry); + + if (!err) { + hidden_wh_dentry = LOOKUP_ONE_LEN(name, + hidden_old_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(hidden_wh_dentry)) { + err = PTR_ERR(hidden_wh_dentry); + goto out; + } + down(&hidden_wh_dentry->d_inode->i_sem); + newattrs.ia_valid = ATTR_CTIME; + if (hidden_wh_dentry->d_inode->i_size != 0) { + newattrs.ia_valid |= ATTR_SIZE; + /* do not truncate if the i_nlink >= 2 */ + if (hidden_wh_dentry->d_inode->i_nlink < 2) { + newattrs.ia_size = 0; + } else { + newattrs.ia_size = + hidden_wh_dentry->d_inode->i_size; + hidden_wh_dentry->d_inode->i_nlink--; + } + + } + /* We discard this error, because the entry is whited out + * even if we fail here. */ + notify_change(hidden_wh_dentry, &newattrs); + up(&hidden_wh_dentry->d_inode->i_sem); + DPUT(hidden_wh_dentry); + } + + if (err) { + if (dbstart(dentry) == 0) + goto out; + /* exit if the error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + goto out; + err = create_whiteout(dentry, dbstart(dentry) - 1); + } else { + fist_copy_attr_all(dir, hidden_new_dir_dentry->d_inode); + } + + out: + KFREE(name); + print_exit_status(err); + return err; +} + +int unionfs_unlink(struct inode *dir, struct dentry *dentry) +{ + int err = 0; + + print_entry_location(); + lock_dentry(dentry); + fist_print_dentry("IN unionfs_unlink", dentry); + + if (IS_SET(dir->i_sb, DELETE_WHITEOUT)) + err = unionfs_unlink_whiteout(dir, dentry); + else + err = unionfs_unlink_all(dir, dentry); + + /* call d_drop so the system "forgets" about us */ + if (!err) + d_drop(dentry); + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +static int unionfs_rmdir_first(struct inode *dir, struct dentry *dentry, + struct unionfs_dir_state *namelist) +{ + int err; + struct dentry *hidden_dentry; + struct dentry *hidden_dir_dentry = NULL; + + print_entry_location(); + fist_print_dentry("IN unionfs_rmdir_first: ", dentry); + + /* Here we need to remove whiteout entries. */ + err = delete_whiteouts(dentry, dbstart(dentry), namelist); + if (err) { + goto out; + } + + hidden_dentry = dtohd(dentry); + + hidden_dir_dentry = lock_parent(hidden_dentry); + + /* avoid destroying the hidden inode if the file is in use */ + DGET(hidden_dentry); + if (!(err = is_robranch(dentry))) { + err = vfs_rmdir(hidden_dir_dentry->d_inode, hidden_dentry); + } + DPUT(hidden_dentry); + + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + /* propagate number of hard-links */ + dentry->d_inode->i_nlink = get_nlinks(dentry->d_inode); + + out: + if (hidden_dir_dentry) { + unlock_dir(hidden_dir_dentry); + } + fist_print_dentry("OUT unionfs_rmdir_first: ", dentry); + print_exit_status(err); + return err; +} + +static int unionfs_rmdir_all(struct inode *dir, struct dentry *dentry, + struct unionfs_dir_state *namelist) +{ + struct dentry *hidden_dentry; + struct dentry *hidden_dir_dentry; + int bstart, bend, bindex; + int err = 0; + int global_err = 0; + + print_entry_location(); + fist_print_dentry("IN unionfs_rmdir_all: ", dentry); + + bstart = dbstart(dentry); + bend = dbend(dentry); + + for (bindex = bend; bindex >= bstart; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + + hidden_dir_dentry = lock_parent(hidden_dentry); + if (S_ISDIR(hidden_dentry->d_inode->i_mode)) { + delete_whiteouts(dentry, bindex, namelist); + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + err = + vfs_rmdir(hidden_dir_dentry->d_inode, + hidden_dentry); + } + } else { + err = -EISDIR; + } + + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + unlock_dir(hidden_dir_dentry); + if (err) { + int local_err = + unionfs_refresh_hidden_dentry(dentry, bindex); + if (local_err) { + err = local_err; + goto out; + } + + if (!IS_COPYUP_ERR(err) && err != -ENOTEMPTY + && err != -EISDIR) + goto out; + + global_err = err; + } + } + + /* check if encountered error in the above loop */ + if (global_err) { + /* If we failed in the leftmost branch, then err will be set and we should + * move one over to create the whiteout. Otherwise, we should try in the + * leftmost branch. + */ + if (err) { + if (dbstart(dentry) == 0) { + goto out; + } + err = create_whiteout(dentry, dbstart(dentry) - 1); + } else { + err = create_whiteout(dentry, dbstart(dentry)); + } + } else { + err = create_whiteout(dentry, dbstart(dentry)); + } + + out: + /* propagate number of hard-links */ + dentry->d_inode->i_nlink = get_nlinks(dentry->d_inode); + + fist_print_dentry("OUT unionfs_rmdir_all: ", dentry); + print_exit_status(err); + return err; +} + +int unionfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + int err = 0; + struct unionfs_dir_state *namelist = NULL; + + print_entry_location(); + lock_dentry(dentry); + fist_print_dentry("IN unionfs_rmdir: ", dentry); + + /* check if this unionfs directory is empty or not */ + err = check_empty(dentry, &namelist); + if (err) { +#if 0 + /* vfs_rmdir(our caller) unhashed the dentry. This will recover + * the Unionfs inode number for the directory itself, but the + * children are already lost. It seems that tmpfs manages its + * way around this by upping the refcount on everything. + * + * Even if we do this, we still lose the inode numbers of the + * children. The best way to fix this is to fix the VFS (or + * use persistent inode maps). */ + if (d_unhashed(dentry)) + d_rehash(dentry); +#endif + goto out; + } + + if (IS_SET(dir->i_sb, DELETE_WHITEOUT)) { + /* Delete the first directory. */ + err = unionfs_rmdir_first(dir, dentry, namelist); + /* create whiteout */ + if (!err) { + err = create_whiteout(dentry, dbstart(dentry)); + } else { + int new_err; + + if (dbstart(dentry) == 0) + goto out; + + /* exit if the error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + goto out; + + new_err = create_whiteout(dentry, dbstart(dentry) - 1); + if (new_err != -EEXIST) + err = new_err; + } + } else { + /* delete all. */ + err = unionfs_rmdir_all(dir, dentry, namelist); + } + + out: + /* call d_drop so the system "forgets" about us */ + if (!err) + d_drop(dentry); + + if (namelist) + free_rdstate(namelist); + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/usercommon.c newtree/fs/unionfs/usercommon.c --- oldtree/fs/unionfs/usercommon.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/usercommon.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: usercommon.c,v 1.8 2006/01/03 01:15:56 jsipek Exp $ + */ +/* + * Copyright (c) 2003-2005 Erez Zadok + * Copyright (c) 2003-2005 Charles P. Wright + * Copyright (c) 2003-2005 Mohammad Nayyer Zubair + * Copyright (c) 2003-2005 Puja Gupta + * Copyright (c) 2003-2005 Harikesavan Krishnan + * Copyright (c) 2003-2005 Stony Brook University + * Copyright (c) 2003-2005 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * This function will take a patch and check it against /proc/mounts to + * find its mount point. If uniononly is set then it will make sure its + * a unionf mount point. This function assumes the both options and actual_path + * are valid and not null; + */ +int find_union(const char *path, char **options, char **actual_path, + int uniononly) +{ + FILE *f = NULL; + char *s = NULL; + char *s2 = NULL; + char *p; + char *q; + int candidate = 0; + int mallocsize = 1024; /* Just a reasonable starting value. */ + + retry: + if (*options) { + free(*options); + *options = NULL; + } + + if (*actual_path) { + free(*actual_path); + *actual_path = NULL; + } + if (f) { + fclose(f); + f = NULL; + } + s2 = realloc(s, mallocsize); + if (!s2) { + fprintf(stderr, "realloc(%d): %s\n", mallocsize, + strerror(errno)); + goto out; + } + s = s2; + + f = fopen("/proc/mounts", "r"); + if (!f) { + fprintf(stderr, "fopen(/proc/mounts): %s\n", strerror(errno)); + goto out; + } + while (fgets(s, mallocsize, f)) { + int testcan; + + /* If we don't have enough information, we should remalloc it. */ + if (strlen(s) == (mallocsize - 1)) { + mallocsize *= 2; + goto retry; + } + + p = strchr(s, ' '); + if (!p) + continue; + p++; + + q = strchr(p, ' '); + if (!q) + continue; + *q++ = '\0'; + + testcan = strlen(p); + if (testcan <= candidate) { + continue; + } + + if (!strncmp(path, p, testcan)) { + if (*actual_path) { + free(*actual_path); + } + *actual_path = strdup(p); + if (!*actual_path) { + fprintf(stderr, "strdup: %s\n", + strerror(errno)); + goto out; + } + p = strchr(q, ' '); + if (!p) + continue; + *p++ = '\0'; + if (uniononly) { + if (strcmp(q, "unionfs")) { + candidate = 0; + continue; + } + } + candidate = testcan; + + q = strrchr(p, ' '); + if (!q) + continue; + *q = '\0'; + q = strrchr(p, ' '); + if (!q) + continue; + *q = '\0'; + + if (*options) { + free(*options); + } + *options = strdup(p); + if (!*options) { + fprintf(stderr, "strdup: %s\n", + strerror(errno)); + goto out; + } + } + } + + out: + if (s) + free(s); + if (f) + fclose(f); + + if (*options) { + return 0; + } + + errno = -ENOENT; + return -1; +} + +/** + * Takes the device and creates an fsid from it by placing major in the first + * int and minor in the second. + */ +void fillfsid(dev_t dev, fsid_t * fsid) +{ + ((unsigned int *)fsid)[0] = major(dev); + ((unsigned int *)fsid)[1] = minor(dev); +} + +int mkfsid(char *path, fsid_t * fsid) +{ + int err = 0; + char *actual_path = NULL; + char *options = NULL; + struct stat stat_struct; + + memset(&stat_struct, 0, sizeof(struct stat)); + + err = find_union(path, &options, &actual_path, 0); + if (err) { + printf("find_union failed:\n"); + goto out; + } + err = stat(actual_path, &stat_struct); + if (err) { + perror("Couldent stat path: "); + goto out; + } + + fillfsid(stat_struct.st_dev, fsid); + + out: + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/fs/unionfs/xattr.c newtree/fs/unionfs/xattr.c --- oldtree/fs/unionfs/xattr.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/fs/unionfs/xattr.c 2006-01-25 21:58:11.000000000 +0000 @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: xattr.c,v 1.29 2006/01/13 03:00:24 jsipek Exp $ + */ + +#include "unionfs.h" + +/* This is lifted from fs/xattr.c */ +void *xattr_alloc(size_t size, size_t limit) +{ + void *ptr; + + if (size > limit) + return ERR_PTR(-E2BIG); + + if (!size) /* size request, no buffer is needed */ + return NULL; + else if (size <= PAGE_SIZE) + ptr = KMALLOC((unsigned long)size, GFP_KERNEL); + else + ptr = vmalloc((unsigned long)size); + if (!ptr) + return ERR_PTR(-ENOMEM); + return ptr; +} + +void xattr_free(void *ptr, size_t size) +{ + if (!size) /* size request, no buffer was needed */ + return; + else if (size <= PAGE_SIZE) + KFREE(ptr); + else + vfree(ptr); +} + +/* BKL held by caller. + * dentry->d_inode->i_sem down + * ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); + */ +ssize_t unionfs_getxattr(struct dentry *dentry, const char *name, void *value, + size_t size) +{ + struct dentry *hidden_dentry = NULL; + int err = -EOPNOTSUPP; + /* Define these anyway so we don't need as much ifdef'ed code. */ + char *encoded_name = NULL; + char *encoded_value = NULL; + + print_entry_location(); + + lock_dentry(dentry); + + hidden_dentry = dtohd(dentry); + + fist_dprint(8, "getxattr: name=\"%s\", value %lu bytes\n", name, + (unsigned long)size); + + if (hidden_dentry->d_inode->i_op->getxattr) { + encoded_name = (char *)name; + + encoded_value = (char *)value; + + down(&hidden_dentry->d_inode->i_sem); + /* lock_kernel() already done by caller. */ + err = + hidden_dentry->d_inode->i_op->getxattr(hidden_dentry, + encoded_name, + encoded_value, size); + /* unlock_kernel() will be done by caller. */ + up(&hidden_dentry->d_inode->i_sem); + + } + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* BKL held by caller. + * dentry->d_inode->i_sem down + */ +int +unionfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags) +{ + struct dentry *hidden_dentry = NULL; + int err = -EOPNOTSUPP; + + print_entry_location(); + + lock_dentry(dentry); + hidden_dentry = dtohd(dentry); + + fist_dprint(8, "setxattr: name=\"%s\", value %lu bytes, flags=%x\n", + name, (unsigned long)size, flags); + + if (hidden_dentry->d_inode->i_op->setxattr) { + down(&hidden_dentry->d_inode->i_sem); + /* lock_kernel() already done by caller. */ + err = hidden_dentry->d_inode->i_op-> + setxattr(hidden_dentry, name, value, size, flags); + /* unlock_kernel() will be done by caller. */ + up(&hidden_dentry->d_inode->i_sem); + } + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* BKL held by caller. + * dentry->d_inode->i_sem down + */ +int unionfs_removexattr(struct dentry *dentry, const char *name) +{ + struct dentry *hidden_dentry = NULL; + int err = -EOPNOTSUPP; + char *encoded_name; + print_entry_location(); + + lock_dentry(dentry); + hidden_dentry = dtohd(dentry); + + fist_dprint(8, "removexattr: name=\"%s\"\n", name); + + if (hidden_dentry->d_inode->i_op->removexattr) { + encoded_name = (char *)name; + + down(&hidden_dentry->d_inode->i_sem); + /* lock_kernel() already done by caller. */ + err = + hidden_dentry->d_inode->i_op->removexattr(hidden_dentry, + encoded_name); + /* unlock_kernel() will be done by caller. */ + up(&hidden_dentry->d_inode->i_sem); + } + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* BKL held by caller. + * dentry->d_inode->i_sem down + */ +ssize_t unionfs_listxattr(struct dentry * dentry, char *list, size_t size) +{ + struct dentry *hidden_dentry = NULL; + int err = -EOPNOTSUPP; + char *encoded_list = NULL; + + print_entry_location(); + lock_dentry(dentry); + + hidden_dentry = dtohd(dentry); + + if (hidden_dentry->d_inode->i_op->listxattr) { + encoded_list = list; + down(&hidden_dentry->d_inode->i_sem); + /* lock_kernel() already done by caller. */ + err = + hidden_dentry->d_inode->i_op->listxattr(hidden_dentry, + encoded_list, size); + /* unlock_kernel() will be done by caller. */ + up(&hidden_dentry->d_inode->i_sem); + } + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ diff -urN oldtree/scripts/basic/.docproc.cmd newtree/scripts/basic/.docproc.cmd --- oldtree/scripts/basic/.docproc.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/basic/.docproc.cmd 2006-01-28 18:23:29.596632288 +0000 @@ -0,0 +1,67 @@ +cmd_scripts/basic/docproc := gcc -Wp,-MD,scripts/basic/.docproc.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/docproc scripts/basic/docproc.c + +deps_scripts/basic/docproc := \ + scripts/basic/docproc.c \ + /usr/include/stdio.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/types.h \ + /usr/include/bits/typesizes.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/stdlib.h \ + /usr/include/sys/types.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/ctype.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/limits.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/syslimits.h \ + /usr/include/limits.h \ + /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h \ + /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h \ + /usr/include/sys/wait.h \ + /usr/include/signal.h \ + /usr/include/bits/signum.h \ + /usr/include/bits/siginfo.h \ + /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h \ + /usr/include/asm/sigcontext.h \ + /usr/include/linux/compiler.h \ + /usr/include/bits/sigstack.h \ + /usr/include/bits/sigthread.h \ + /usr/include/sys/resource.h \ + /usr/include/bits/resource.h \ + /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h \ + +scripts/basic/docproc: $(deps_scripts/basic/docproc) + +$(deps_scripts/basic/docproc): diff -urN oldtree/scripts/basic/.fixdep.cmd newtree/scripts/basic/.fixdep.cmd --- oldtree/scripts/basic/.fixdep.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/basic/.fixdep.cmd 2006-01-28 18:23:29.137702056 +0000 @@ -0,0 +1,76 @@ +cmd_scripts/basic/fixdep := gcc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c + +deps_scripts/basic/fixdep := \ + scripts/basic/fixdep.c \ + $(wildcard include/config/his/driver.h) \ + $(wildcard include/config/my/option.h) \ + $(wildcard include/config/.h) \ + $(wildcard include/config/foo.h) \ + $(wildcard include/config/boom.h) \ + /usr/include/sys/types.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/sys/stat.h \ + /usr/include/bits/stat.h \ + /usr/include/sys/mman.h \ + /usr/include/bits/mman.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/limits.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/syslimits.h \ + /usr/include/limits.h \ + /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h \ + /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h \ + /usr/include/ctype.h \ + /usr/include/arpa/inet.h \ + /usr/include/netinet/in.h \ + /usr/include/stdint.h \ + /usr/include/sys/socket.h \ + /usr/include/sys/uio.h \ + /usr/include/bits/uio.h \ + /usr/include/bits/socket.h \ + /usr/include/bits/sockaddr.h \ + /usr/include/asm/socket.h \ + /usr/include/asm/sockios.h \ + /usr/include/bits/in.h \ + /usr/include/bits/byteswap.h \ + +scripts/basic/fixdep: $(deps_scripts/basic/fixdep) + +$(deps_scripts/basic/fixdep): diff -urN oldtree/scripts/basic/.split-include.cmd newtree/scripts/basic/.split-include.cmd --- oldtree/scripts/basic/.split-include.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/basic/.split-include.cmd 2006-01-28 18:23:29.337671656 +0000 @@ -0,0 +1,57 @@ +cmd_scripts/basic/split-include := gcc -Wp,-MD,scripts/basic/.split-include.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/split-include scripts/basic/split-include.c + +deps_scripts/basic/split-include := \ + scripts/basic/split-include.c \ + $(wildcard include/config/.h) \ + /usr/include/sys/stat.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/bits/stat.h \ + /usr/include/sys/types.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/ctype.h \ + /usr/include/errno.h \ + /usr/include/bits/errno.h \ + /usr/include/linux/errno.h \ + /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + +scripts/basic/split-include: $(deps_scripts/basic/split-include) + +$(deps_scripts/basic/split-include): Files oldtree/scripts/basic/docproc and newtree/scripts/basic/docproc differ Files oldtree/scripts/basic/fixdep and newtree/scripts/basic/fixdep differ Files oldtree/scripts/basic/split-include and newtree/scripts/basic/split-include differ diff -urN oldtree/scripts/kconfig/.conf.o.cmd newtree/scripts/kconfig/.conf.o.cmd --- oldtree/scripts/kconfig/.conf.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/kconfig/.conf.o.cmd 2006-01-28 18:23:29.886588208 +0000 @@ -0,0 +1,56 @@ +cmd_scripts/kconfig/conf.o := gcc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -c -o scripts/kconfig/conf.o scripts/kconfig/conf.c + +deps_scripts/kconfig/conf.o := \ + scripts/kconfig/conf.c \ + $(wildcard include/config/allconfig.h) \ + /usr/include/ctype.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/stdlib.h \ + /usr/include/sys/types.h \ + /usr/include/time.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/sys/stat.h \ + /usr/include/bits/stat.h \ + scripts/kconfig/lkc.h \ + scripts/kconfig/expr.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + /usr/include/libintl.h \ + /usr/include/locale.h \ + /usr/include/bits/locale.h \ + scripts/kconfig/lkc_proto.h \ + +scripts/kconfig/conf.o: $(deps_scripts/kconfig/conf.o) + +$(deps_scripts/kconfig/conf.o): diff -urN oldtree/scripts/kconfig/.kxgettext.o.cmd newtree/scripts/kconfig/.kxgettext.o.cmd --- oldtree/scripts/kconfig/.kxgettext.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/kconfig/.kxgettext.o.cmd 2006-01-28 18:23:30.024567232 +0000 @@ -0,0 +1,48 @@ +cmd_scripts/kconfig/kxgettext.o := gcc -Wp,-MD,scripts/kconfig/.kxgettext.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -c -o scripts/kconfig/kxgettext.o scripts/kconfig/kxgettext.c + +deps_scripts/kconfig/kxgettext.o := \ + scripts/kconfig/kxgettext.c \ + /usr/include/stdlib.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/sys/types.h \ + /usr/include/bits/types.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + scripts/kconfig/lkc.h \ + scripts/kconfig/expr.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + /usr/include/libintl.h \ + /usr/include/locale.h \ + /usr/include/bits/locale.h \ + scripts/kconfig/lkc_proto.h \ + +scripts/kconfig/kxgettext.o: $(deps_scripts/kconfig/kxgettext.o) + +$(deps_scripts/kconfig/kxgettext.o): diff -urN oldtree/scripts/kconfig/.mconf.cmd newtree/scripts/kconfig/.mconf.cmd --- oldtree/scripts/kconfig/.mconf.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/kconfig/.mconf.cmd 2006-01-28 18:23:32.058258064 +0000 @@ -0,0 +1 @@ +cmd_scripts/kconfig/mconf := gcc -o scripts/kconfig/mconf scripts/kconfig/mconf.o scripts/kconfig/zconf.tab.o diff -urN oldtree/scripts/kconfig/.mconf.o.cmd newtree/scripts/kconfig/.mconf.o.cmd --- oldtree/scripts/kconfig/.mconf.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/kconfig/.mconf.o.cmd 2006-01-28 18:23:30.443503544 +0000 @@ -0,0 +1,92 @@ +cmd_scripts/kconfig/mconf.o := gcc -Wp,-MD,scripts/kconfig/.mconf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -c -o scripts/kconfig/mconf.o scripts/kconfig/mconf.c + +deps_scripts/kconfig/mconf.o := \ + scripts/kconfig/mconf.c \ + $(wildcard include/config/mode.h) \ + $(wildcard include/config/.h) \ + /usr/include/sys/ioctl.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/ioctls.h \ + /usr/include/asm/ioctls.h \ + /usr/include/asm/ioctl.h \ + /usr/include/bits/ioctl-types.h \ + /usr/include/sys/ttydefaults.h \ + /usr/include/sys/wait.h \ + /usr/include/signal.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/bits/signum.h \ + /usr/include/time.h \ + /usr/include/bits/siginfo.h \ + /usr/include/bits/sigaction.h \ + /usr/include/bits/sigcontext.h \ + /usr/include/asm/sigcontext.h \ + /usr/include/linux/compiler.h \ + /usr/include/bits/sigstack.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/bits/sigthread.h \ + /usr/include/sys/resource.h \ + /usr/include/bits/resource.h \ + /usr/include/bits/time.h \ + /usr/include/bits/waitflags.h \ + /usr/include/bits/waitstatus.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/ctype.h \ + /usr/include/errno.h \ + /usr/include/bits/errno.h \ + /usr/include/linux/errno.h \ + /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/sys/types.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/sys/sysmacros.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/limits.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/syslimits.h \ + /usr/include/limits.h \ + /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h \ + /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/termios.h \ + /usr/include/bits/termios.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/locale.h \ + /usr/include/bits/locale.h \ + scripts/kconfig/lkc.h \ + scripts/kconfig/expr.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + /usr/include/libintl.h \ + scripts/kconfig/lkc_proto.h \ + +scripts/kconfig/mconf.o: $(deps_scripts/kconfig/mconf.o) + +$(deps_scripts/kconfig/mconf.o): diff -urN oldtree/scripts/kconfig/.zconf.tab.o.cmd newtree/scripts/kconfig/.zconf.tab.o.cmd --- oldtree/scripts/kconfig/.zconf.tab.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/kconfig/.zconf.tab.o.cmd 2006-01-28 18:23:32.012265056 +0000 @@ -0,0 +1,80 @@ +cmd_scripts/kconfig/zconf.tab.o := gcc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.c + +deps_scripts/kconfig/zconf.tab.o := \ + scripts/kconfig/zconf.tab.c \ + /usr/include/ctype.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/stdlib.h \ + /usr/include/sys/types.h \ + /usr/include/time.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + scripts/kconfig/lkc.h \ + scripts/kconfig/expr.h \ + /usr/include/libintl.h \ + /usr/include/locale.h \ + /usr/include/bits/locale.h \ + scripts/kconfig/lkc_proto.h \ + scripts/kconfig/zconf.hash.c \ + scripts/kconfig/lex.zconf.c \ + /usr/include/errno.h \ + /usr/include/bits/errno.h \ + /usr/include/linux/errno.h \ + /usr/include/asm/errno.h \ + /usr/include/asm-generic/errno.h \ + /usr/include/asm-generic/errno-base.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/limits.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/syslimits.h \ + /usr/include/limits.h \ + /usr/include/bits/posix1_lim.h \ + /usr/include/bits/local_lim.h \ + /usr/include/linux/limits.h \ + /usr/include/bits/posix2_lim.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + scripts/kconfig/util.c \ + scripts/kconfig/confdata.c \ + $(wildcard include/config/.h) \ + $(wildcard include/config/notimestamp.h) \ + /usr/include/sys/stat.h \ + /usr/include/bits/stat.h \ + scripts/kconfig/expr.c \ + scripts/kconfig/symbol.c \ + /usr/include/regex.h \ + /usr/include/sys/utsname.h \ + /usr/include/bits/utsname.h \ + scripts/kconfig/menu.c \ + +scripts/kconfig/zconf.tab.o: $(deps_scripts/kconfig/zconf.tab.o) + +$(deps_scripts/kconfig/zconf.tab.o): Files oldtree/scripts/kconfig/conf.o and newtree/scripts/kconfig/conf.o differ Files oldtree/scripts/kconfig/kxgettext.o and newtree/scripts/kconfig/kxgettext.o differ diff -urN oldtree/scripts/kconfig/lex.zconf.c newtree/scripts/kconfig/lex.zconf.c --- oldtree/scripts/kconfig/lex.zconf.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/kconfig/lex.zconf.c 2006-01-28 18:23:30.456501568 +0000 @@ -0,0 +1,2317 @@ + +#line 3 "scripts/kconfig/lex.zconf.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 31 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE zconfrestart(zconfin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int zconfleng; + +extern FILE *zconfin, *zconfout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up zconftext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up zconftext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef unsigned int yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via zconfrestart()), so that the user can continue scanning by + * just pointing zconfin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when zconftext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int zconfleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow zconfwrap()'s to do buffer switches + * instead of setting up a fresh zconfin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void zconfrestart (FILE *input_file ); +void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size ); +void zconf_delete_buffer (YY_BUFFER_STATE b ); +void zconf_flush_buffer (YY_BUFFER_STATE b ); +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ); +void zconfpop_buffer_state (void ); + +static void zconfensure_buffer_stack (void ); +static void zconf_load_buffer_state (void ); +static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len ); + +void *zconfalloc (yy_size_t ); +void *zconfrealloc (void *,yy_size_t ); +void zconffree (void * ); + +#define yy_new_buffer zconf_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + zconfensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + zconfensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define zconfwrap() 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0; + +typedef int yy_state_type; + +extern int zconflineno; + +int zconflineno = 1; + +extern char *zconftext; +#define yytext_ptr zconftext +static yyconst flex_int16_t yy_nxt[][17] = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }, + + { + 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12 + }, + + { + 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12 + }, + + { + 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 18, 16, 16, 16 + }, + + { + 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 18, 16, 16, 16 + + }, + + { + 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19 + }, + + { + 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19 + }, + + { + 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, + 22, 22, 22, 22, 22, 25, 22 + }, + + { + 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, + 22, 22, 22, 22, 22, 25, 22 + }, + + { + 11, 26, 26, 27, 28, 29, 30, 31, 29, 32, + 33, 34, 35, 35, 36, 37, 38 + + }, + + { + 11, 26, 26, 27, 28, 29, 30, 31, 29, 32, + 33, 34, 35, 35, 36, 37, 38 + }, + + { + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11 + }, + + { + 11, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12 + }, + + { + 11, -13, 39, 40, -13, -13, 41, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13 + }, + + { + 11, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14 + + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16 + }, + + { + 11, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17 + }, + + { + 11, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, 44, -18, -18, -18 + }, + + { + 11, 45, 45, -19, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45 + + }, + + { + 11, -20, 46, 47, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20 + }, + + { + 11, 48, -21, -21, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48 + }, + + { + 11, 49, 49, 50, 49, -22, 49, 49, -22, 49, + 49, 49, 49, 49, 49, -22, 49 + }, + + { + 11, -23, -23, -23, -23, -23, -23, -23, -23, -23, + -23, -23, -23, -23, -23, -23, -23 + }, + + { + 11, -24, -24, -24, -24, -24, -24, -24, -24, -24, + -24, -24, -24, -24, -24, -24, -24 + + }, + + { + 11, 51, 51, 52, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51 + }, + + { + 11, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26 + }, + + { + 11, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27 + }, + + { + 11, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, 53, -28, -28 + }, + + { + 11, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29 + + }, + + { + 11, 54, 54, -30, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54 + }, + + { + 11, -31, -31, -31, -31, -31, -31, 55, -31, -31, + -31, -31, -31, -31, -31, -31, -31 + }, + + { + 11, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32 + }, + + { + 11, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33 + }, + + { + 11, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, 56, 57, 57, -34, -34, -34 + + }, + + { + 11, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, 57, 57, 57, -35, -35, -35 + }, + + { + 11, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36 + }, + + { + 11, -37, -37, 58, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37 + }, + + { + 11, -38, -38, -38, -38, -38, -38, -38, -38, -38, + -38, -38, -38, -38, -38, -38, 59 + }, + + { + 11, -39, 39, 40, -39, -39, 41, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39 + + }, + + { + 11, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40 + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43 + }, + + { + 11, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, 44, -44, -44, -44 + + }, + + { + 11, 45, 45, -45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45 + }, + + { + 11, -46, 46, 47, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46 + }, + + { + 11, 48, -47, -47, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48 + }, + + { + 11, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48 + }, + + { + 11, 49, 49, 50, 49, -49, 49, 49, -49, 49, + 49, 49, 49, 49, 49, -49, 49 + + }, + + { + 11, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50 + }, + + { + 11, -51, -51, 52, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51 + }, + + { + 11, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52 + }, + + { + 11, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53 + }, + + { + 11, 54, 54, -54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54 + + }, + + { + 11, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55 + }, + + { + 11, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, 60, 57, 57, -56, -56, -56 + }, + + { + 11, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, 57, 57, 57, -57, -57, -57 + }, + + { + 11, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58 + }, + + { + 11, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59 + + }, + + { + 11, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, 57, 57, 57, -60, -60, -60 + }, + + } ; + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up zconftext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + zconfleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 33 +#define YY_END_OF_BUFFER 34 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[61] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 34, 5, 4, 2, 3, 7, 8, 6, 32, 29, + 31, 24, 28, 27, 26, 22, 17, 13, 16, 20, + 22, 11, 12, 19, 19, 14, 22, 22, 4, 2, + 3, 3, 1, 6, 32, 29, 31, 30, 24, 23, + 26, 25, 15, 20, 9, 19, 19, 21, 10, 18 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 6, 1, 1, 7, 8, 9, + 10, 1, 1, 1, 11, 12, 12, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, + 14, 1, 1, 1, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 1, 15, 1, 1, 13, 1, 13, 13, 13, 13, + + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 1, 16, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +extern int zconf_flex_debug; +int zconf_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *zconftext; + +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#define START_STRSIZE 16 + +static struct { + struct file *file; + int lineno; +} current_pos; + +static char *text; +static int text_size, text_asize; + +struct buffer { + struct buffer *parent; + YY_BUFFER_STATE state; +}; + +struct buffer *current_buf; + +static int last_ts, first_ts; + +static void zconf_endhelp(void); +static void zconf_endfile(void); + +void new_string(void) +{ + text = malloc(START_STRSIZE); + text_asize = START_STRSIZE; + text_size = 0; + *text = 0; +} + +void append_string(const char *str, int size) +{ + int new_size = text_size + size + 1; + if (new_size > text_asize) { + new_size += START_STRSIZE - 1; + new_size &= -START_STRSIZE; + text = realloc(text, new_size); + text_asize = new_size; + } + memcpy(text + text_size, str, size); + text_size += size; + text[text_size] = 0; +} + +void alloc_string(const char *str, int size) +{ + text = malloc(size + 1); + memcpy(text, str, size); + text[size] = 0; +} + +#define INITIAL 0 +#define COMMAND 1 +#define HELP 2 +#define STRING 3 +#define PARAM 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int zconfwrap (void ); +#else +extern int zconfwrap (void ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( zconftext, zconfleng, 1, zconfout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + errno=0; \ + while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(zconfin); \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int zconflex (void); + +#define YY_DECL int zconflex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after zconftext and zconfleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + + int str = 0; + int ts, i; + + if ( (yy_init) ) + { + (yy_init) = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! zconfin ) + zconfin = stdin; + + if ( ! zconfout ) + zconfout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + zconfensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + zconf_create_buffer(zconfin,YY_BUF_SIZE ); + } + + zconf_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of zconftext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 ) + ++yy_cp; + + yy_current_state = -yy_current_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ +case 1: +/* rule 1 can match eol */ +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +{ + current_file->lineno++; + return T_EOL; +} + YY_BREAK +case 3: +YY_RULE_SETUP + + YY_BREAK +case 4: +YY_RULE_SETUP +{ + BEGIN(COMMAND); +} + YY_BREAK +case 5: +YY_RULE_SETUP +{ + unput(zconftext[0]); + BEGIN(COMMAND); +} + YY_BREAK + +case 6: +YY_RULE_SETUP +{ + struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); + BEGIN(PARAM); + current_pos.file = current_file; + current_pos.lineno = current_file->lineno; + if (id && id->flags & TF_COMMAND) { + zconflval.id = id; + return id->token; + } + alloc_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD; + } + YY_BREAK +case 7: +YY_RULE_SETUP + + YY_BREAK +case 8: +/* rule 8 can match eol */ +YY_RULE_SETUP +{ + BEGIN(INITIAL); + current_file->lineno++; + return T_EOL; + } + YY_BREAK + +case 9: +YY_RULE_SETUP +return T_AND; + YY_BREAK +case 10: +YY_RULE_SETUP +return T_OR; + YY_BREAK +case 11: +YY_RULE_SETUP +return T_OPEN_PAREN; + YY_BREAK +case 12: +YY_RULE_SETUP +return T_CLOSE_PAREN; + YY_BREAK +case 13: +YY_RULE_SETUP +return T_NOT; + YY_BREAK +case 14: +YY_RULE_SETUP +return T_EQUAL; + YY_BREAK +case 15: +YY_RULE_SETUP +return T_UNEQUAL; + YY_BREAK +case 16: +YY_RULE_SETUP +{ + str = zconftext[0]; + new_string(); + BEGIN(STRING); + } + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +BEGIN(INITIAL); current_file->lineno++; return T_EOL; + YY_BREAK +case 18: +YY_RULE_SETUP +/* ignore */ + YY_BREAK +case 19: +YY_RULE_SETUP +{ + struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); + if (id && id->flags & TF_PARAM) { + zconflval.id = id; + return id->token; + } + alloc_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD; + } + YY_BREAK +case 20: +YY_RULE_SETUP +/* comment */ + YY_BREAK +case 21: +/* rule 21 can match eol */ +YY_RULE_SETUP +current_file->lineno++; + YY_BREAK +case 22: +YY_RULE_SETUP + + YY_BREAK +case YY_STATE_EOF(PARAM): +{ + BEGIN(INITIAL); + } + YY_BREAK + +case 23: +/* rule 23 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + append_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD_QUOTE; + } + YY_BREAK +case 24: +YY_RULE_SETUP +{ + append_string(zconftext, zconfleng); + } + YY_BREAK +case 25: +/* rule 25 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + append_string(zconftext + 1, zconfleng - 1); + zconflval.string = text; + return T_WORD_QUOTE; + } + YY_BREAK +case 26: +YY_RULE_SETUP +{ + append_string(zconftext + 1, zconfleng - 1); + } + YY_BREAK +case 27: +YY_RULE_SETUP +{ + if (str == zconftext[0]) { + BEGIN(PARAM); + zconflval.string = text; + return T_WORD_QUOTE; + } else + append_string(zconftext, 1); + } + YY_BREAK +case 28: +/* rule 28 can match eol */ +YY_RULE_SETUP +{ + printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); + current_file->lineno++; + BEGIN(INITIAL); + return T_EOL; + } + YY_BREAK +case YY_STATE_EOF(STRING): +{ + BEGIN(INITIAL); + } + YY_BREAK + +case 29: +YY_RULE_SETUP +{ + ts = 0; + for (i = 0; i < zconfleng; i++) { + if (zconftext[i] == '\t') + ts = (ts & ~7) + 8; + else + ts++; + } + last_ts = ts; + if (first_ts) { + if (ts < first_ts) { + zconf_endhelp(); + return T_HELPTEXT; + } + ts -= first_ts; + while (ts > 8) { + append_string(" ", 8); + ts -= 8; + } + append_string(" ", ts); + } + } + YY_BREAK +case 30: +/* rule 30 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + current_file->lineno++; + zconf_endhelp(); + return T_HELPTEXT; + } + YY_BREAK +case 31: +/* rule 31 can match eol */ +YY_RULE_SETUP +{ + current_file->lineno++; + append_string("\n", 1); + } + YY_BREAK +case 32: +YY_RULE_SETUP +{ + append_string(zconftext, zconfleng); + if (!first_ts) + first_ts = last_ts; + } + YY_BREAK +case YY_STATE_EOF(HELP): +{ + zconf_endhelp(); + return T_HELPTEXT; + } + YY_BREAK + +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMAND): +{ + if (current_file) { + zconf_endfile(); + return T_EOL; + } + fclose(zconfin); + yyterminate(); +} + YY_BREAK +case 33: +YY_RULE_SETUP +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed zconfin at a new source and called + * zconflex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( zconfwrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * zconftext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of zconflex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + zconfrestart(zconfin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + + yy_current_state = yy_nxt[yy_current_state][1]; + yy_is_jam = (yy_current_state <= 0); + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp ) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up zconftext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + zconfrestart(zconfin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( zconfwrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve zconftext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void zconfrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + zconfensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + zconf_create_buffer(zconfin,YY_BUF_SIZE ); + } + + zconf_init_buffer(YY_CURRENT_BUFFER,input_file ); + zconf_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * zconfpop_buffer_state(); + * zconfpush_buffer_state(new_buffer); + */ + zconfensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + zconf_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (zconfwrap()) processing, but the only time this flag + * is looked at is after zconfwrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void zconf_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + zconf_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with zconf_create_buffer() + * + */ + void zconf_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + zconffree((void *) b->yy_ch_buf ); + + zconffree((void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a zconfrestart() or at EOF. + */ + static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + zconf_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then zconf_init_buffer was _probably_ + * called from zconfrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void zconf_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + zconf_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + zconfensure_buffer_stack(); + + /* This block is copied from zconf_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from zconf_switch_to_buffer. */ + zconf_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void zconfpop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + zconf_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + zconf_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void zconfensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + zconf_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to zconflex() will + * scan from a @e copy of @a str. + * @param yy_str a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * zconf_scan_bytes() instead. + */ +YY_BUFFER_STATE zconf_scan_string (yyconst char * yy_str ) +{ + + return zconf_scan_bytes(yy_str,strlen(yy_str) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_bytes (yyconst char * bytes, int len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) zconfalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = zconf_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up zconftext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + zconftext[zconfleng] = (yy_hold_char); \ + (yy_c_buf_p) = zconftext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + zconfleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int zconfget_lineno (void) +{ + + return zconflineno; +} + +/** Get the input stream. + * + */ +FILE *zconfget_in (void) +{ + return zconfin; +} + +/** Get the output stream. + * + */ +FILE *zconfget_out (void) +{ + return zconfout; +} + +/** Get the length of the current token. + * + */ +int zconfget_leng (void) +{ + return zconfleng; +} + +/** Get the current token. + * + */ + +char *zconfget_text (void) +{ + return zconftext; +} + +/** Set the current line number. + * @param line_number + * + */ +void zconfset_lineno (int line_number ) +{ + + zconflineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see zconf_switch_to_buffer + */ +void zconfset_in (FILE * in_str ) +{ + zconfin = in_str ; +} + +void zconfset_out (FILE * out_str ) +{ + zconfout = out_str ; +} + +int zconfget_debug (void) +{ + return zconf_flex_debug; +} + +void zconfset_debug (int bdebug ) +{ + zconf_flex_debug = bdebug ; +} + +/* zconflex_destroy is for both reentrant and non-reentrant scanners. */ +int zconflex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + zconf_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + zconfpop_buffer_state(); + } + + /* Destroy the stack itself. */ + zconffree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *zconfalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *zconfrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void zconffree (void * ptr ) +{ + free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef yytext_ptr +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +void zconf_starthelp(void) +{ + new_string(); + last_ts = first_ts = 0; + BEGIN(HELP); +} + +static void zconf_endhelp(void) +{ + zconflval.string = text; + BEGIN(INITIAL); +} + +/* + * Try to open specified file with following names: + * ./name + * $(srctree)/name + * The latter is used when srctree is separate from objtree + * when compiling the kernel. + * Return NULL if file is not found. + */ +FILE *zconf_fopen(const char *name) +{ + char *env, fullname[PATH_MAX+1]; + FILE *f; + + f = fopen(name, "r"); + if (!f && name[0] != '/') { + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + f = fopen(fullname, "r"); + } + } + return f; +} + +void zconf_initscan(const char *name) +{ + zconfin = zconf_fopen(name); + if (!zconfin) { + printf("can't find file %s\n", name); + exit(1); + } + + current_buf = malloc(sizeof(*current_buf)); + memset(current_buf, 0, sizeof(*current_buf)); + + current_file = file_lookup(name); + current_file->lineno = 1; + current_file->flags = FILE_BUSY; +} + +void zconf_nextfile(const char *name) +{ + struct file *file = file_lookup(name); + struct buffer *buf = malloc(sizeof(*buf)); + memset(buf, 0, sizeof(*buf)); + + current_buf->state = YY_CURRENT_BUFFER; + zconfin = zconf_fopen(name); + if (!zconfin) { + printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name); + exit(1); + } + zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE)); + buf->parent = current_buf; + current_buf = buf; + + if (file->flags & FILE_BUSY) { + printf("recursive scan (%s)?\n", name); + exit(1); + } + if (file->flags & FILE_SCANNED) { + printf("file %s already scanned?\n", name); + exit(1); + } + file->flags |= FILE_BUSY; + file->lineno = 1; + file->parent = current_file; + current_file = file; +} + +static void zconf_endfile(void) +{ + struct buffer *parent; + + current_file->flags |= FILE_SCANNED; + current_file->flags &= ~FILE_BUSY; + current_file = current_file->parent; + + parent = current_buf->parent; + if (parent) { + fclose(zconfin); + zconf_delete_buffer(YY_CURRENT_BUFFER); + zconf_switch_to_buffer(parent->state); + } + free(current_buf); + current_buf = parent; +} + +int zconf_lineno(void) +{ + return current_pos.lineno; +} + +char *zconf_curname(void) +{ + return current_pos.file ? current_pos.file->name : ""; +} + Files oldtree/scripts/kconfig/mconf and newtree/scripts/kconfig/mconf differ Files oldtree/scripts/kconfig/mconf.o and newtree/scripts/kconfig/mconf.o differ diff -urN oldtree/scripts/kconfig/zconf.hash.c newtree/scripts/kconfig/zconf.hash.c --- oldtree/scripts/kconfig/zconf.hash.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/kconfig/zconf.hash.c 2006-01-28 18:23:30.460500960 +0000 @@ -0,0 +1,231 @@ +/* ANSI-C code produced by gperf version 3.0.1 */ +/* Command-line: gperf */ +/* Computed positions: -k'1,3' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +struct kconf_id; +/* maximum key range = 45, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +kconf_id_hash (register const char *str, register unsigned int len) +{ + static unsigned char asso_values[] = + { + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 25, 10, 15, + 0, 0, 5, 47, 0, 0, 47, 47, 0, 10, + 0, 20, 20, 20, 5, 0, 0, 20, 47, 47, + 20, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47 + }; + register int hval = len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[2]]; + /*FALLTHROUGH*/ + case 2: + case 1: + hval += asso_values[(unsigned char)str[0]]; + break; + } + return hval; +} + +struct kconf_id_strings_t + { + char kconf_id_strings_str2[sizeof("if")]; + char kconf_id_strings_str3[sizeof("int")]; + char kconf_id_strings_str4[sizeof("help")]; + char kconf_id_strings_str5[sizeof("endif")]; + char kconf_id_strings_str6[sizeof("select")]; + char kconf_id_strings_str7[sizeof("endmenu")]; + char kconf_id_strings_str8[sizeof("tristate")]; + char kconf_id_strings_str9[sizeof("endchoice")]; + char kconf_id_strings_str10[sizeof("range")]; + char kconf_id_strings_str11[sizeof("string")]; + char kconf_id_strings_str12[sizeof("default")]; + char kconf_id_strings_str13[sizeof("def_bool")]; + char kconf_id_strings_str14[sizeof("menu")]; + char kconf_id_strings_str16[sizeof("def_boolean")]; + char kconf_id_strings_str17[sizeof("def_tristate")]; + char kconf_id_strings_str18[sizeof("mainmenu")]; + char kconf_id_strings_str20[sizeof("menuconfig")]; + char kconf_id_strings_str21[sizeof("config")]; + char kconf_id_strings_str22[sizeof("on")]; + char kconf_id_strings_str23[sizeof("hex")]; + char kconf_id_strings_str26[sizeof("source")]; + char kconf_id_strings_str27[sizeof("depends")]; + char kconf_id_strings_str28[sizeof("optional")]; + char kconf_id_strings_str31[sizeof("enable")]; + char kconf_id_strings_str32[sizeof("comment")]; + char kconf_id_strings_str33[sizeof("requires")]; + char kconf_id_strings_str34[sizeof("bool")]; + char kconf_id_strings_str37[sizeof("boolean")]; + char kconf_id_strings_str41[sizeof("choice")]; + char kconf_id_strings_str46[sizeof("prompt")]; + }; +static struct kconf_id_strings_t kconf_id_strings_contents = + { + "if", + "int", + "help", + "endif", + "select", + "endmenu", + "tristate", + "endchoice", + "range", + "string", + "default", + "def_bool", + "menu", + "def_boolean", + "def_tristate", + "mainmenu", + "menuconfig", + "config", + "on", + "hex", + "source", + "depends", + "optional", + "enable", + "comment", + "requires", + "bool", + "boolean", + "choice", + "prompt" + }; +#define kconf_id_strings ((const char *) &kconf_id_strings_contents) +#ifdef __GNUC__ +__inline +#endif +struct kconf_id * +kconf_id_lookup (register const char *str, register unsigned int len) +{ + enum + { + TOTAL_KEYWORDS = 30, + MIN_WORD_LENGTH = 2, + MAX_WORD_LENGTH = 12, + MIN_HASH_VALUE = 2, + MAX_HASH_VALUE = 46 + }; + + static struct kconf_id wordlist[] = + { + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str4, T_HELP, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_SELECT, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_RANGE, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_TYPE, TF_COMMAND, S_STRING}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_MENU, TF_COMMAND}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_MAINMENU, TF_COMMAND}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20, T_MENUCONFIG, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_CONFIG, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ON, TF_PARAM}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_HEX}, + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SOURCE, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_DEPENDS, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPTIONAL, TF_COMMAND}, + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_REQUIRES, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {-1}, {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_CHOICE, TF_COMMAND}, + {-1}, {-1}, {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_PROMPT, TF_COMMAND} + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = kconf_id_hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register int o = wordlist[key].name; + if (o >= 0) + { + register const char *s = o + kconf_id_strings; + + if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') + return &wordlist[key]; + } + } + } + return 0; +} + diff -urN oldtree/scripts/kconfig/zconf.tab.c newtree/scripts/kconfig/zconf.tab.c --- oldtree/scripts/kconfig/zconf.tab.c 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/kconfig/zconf.tab.c 2006-01-28 18:23:30.452502176 +0000 @@ -0,0 +1,2173 @@ +/* A Bison parser, made by GNU Bison 2.0. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + + 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, 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Written by Richard Stallman by simplifying the original so called + ``semantic'' parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse zconfparse +#define yylex zconflex +#define yyerror zconferror +#define yylval zconflval +#define yychar zconfchar +#define yydebug zconfdebug +#define yynerrs zconfnerrs + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + T_MAINMENU = 258, + T_MENU = 259, + T_ENDMENU = 260, + T_SOURCE = 261, + T_CHOICE = 262, + T_ENDCHOICE = 263, + T_COMMENT = 264, + T_CONFIG = 265, + T_MENUCONFIG = 266, + T_HELP = 267, + T_HELPTEXT = 268, + T_IF = 269, + T_ENDIF = 270, + T_DEPENDS = 271, + T_REQUIRES = 272, + T_OPTIONAL = 273, + T_PROMPT = 274, + T_TYPE = 275, + T_DEFAULT = 276, + T_SELECT = 277, + T_RANGE = 278, + T_ON = 279, + T_WORD = 280, + T_WORD_QUOTE = 281, + T_UNEQUAL = 282, + T_CLOSE_PAREN = 283, + T_OPEN_PAREN = 284, + T_EOL = 285, + T_OR = 286, + T_AND = 287, + T_EQUAL = 288, + T_NOT = 289 + }; +#endif +#define T_MAINMENU 258 +#define T_MENU 259 +#define T_ENDMENU 260 +#define T_SOURCE 261 +#define T_CHOICE 262 +#define T_ENDCHOICE 263 +#define T_COMMENT 264 +#define T_CONFIG 265 +#define T_MENUCONFIG 266 +#define T_HELP 267 +#define T_HELPTEXT 268 +#define T_IF 269 +#define T_ENDIF 270 +#define T_DEPENDS 271 +#define T_REQUIRES 272 +#define T_OPTIONAL 273 +#define T_PROMPT 274 +#define T_TYPE 275 +#define T_DEFAULT 276 +#define T_SELECT 277 +#define T_RANGE 278 +#define T_ON 279 +#define T_WORD 280 +#define T_WORD_QUOTE 281 +#define T_UNEQUAL 282 +#define T_CLOSE_PAREN 283 +#define T_OPEN_PAREN 284 +#define T_EOL 285 +#define T_OR 286 +#define T_AND 287 +#define T_EQUAL 288 +#define T_NOT 289 + + + + +/* Copy the first part of user declarations. */ + + +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#include "zconf.hash.c" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[257]; + +static struct menu *current_menu, *current_entry; + +#define YYDEBUG 0 +#if YYDEBUG +#define YYERROR_VERBOSE +#endif + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) + +typedef union YYSTYPE { + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + struct kconf_id *id; +} YYSTYPE; +/* Line 190 of yacc.c. */ + +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 213 of yacc.c. */ + + +#if ! defined (yyoverflow) || YYERROR_VERBOSE + +# ifndef YYFREE +# define YYFREE free +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# endif + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# else +# define YYSTACK_ALLOC alloca +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# endif +#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short int yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined (__GNUC__) && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined (__STDC__) || defined (__cplusplus) + typedef signed char yysigned_char; +#else + typedef short int yysigned_char; +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 3 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 264 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 35 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 42 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 104 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 175 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 289 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const unsigned char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const unsigned short int yyprhs[] = +{ + 0, 0, 3, 5, 6, 9, 12, 15, 20, 23, + 28, 33, 37, 39, 41, 43, 45, 47, 49, 51, + 53, 55, 57, 59, 61, 63, 67, 70, 74, 77, + 81, 84, 85, 88, 91, 94, 97, 100, 104, 109, + 114, 119, 125, 128, 131, 133, 137, 138, 141, 144, + 147, 150, 153, 158, 162, 165, 170, 171, 174, 178, + 180, 184, 185, 188, 191, 194, 198, 201, 203, 207, + 208, 211, 214, 217, 221, 225, 228, 231, 234, 235, + 238, 241, 244, 249, 253, 257, 258, 261, 263, 265, + 268, 271, 274, 276, 279, 280, 283, 285, 289, 293, + 297, 300, 304, 308, 310 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yysigned_char yyrhs[] = +{ + 36, 0, -1, 37, -1, -1, 37, 39, -1, 37, + 50, -1, 37, 61, -1, 37, 3, 71, 73, -1, + 37, 72, -1, 37, 25, 1, 30, -1, 37, 38, + 1, 30, -1, 37, 1, 30, -1, 16, -1, 19, + -1, 20, -1, 22, -1, 18, -1, 23, -1, 21, + -1, 30, -1, 56, -1, 65, -1, 42, -1, 44, + -1, 63, -1, 25, 1, 30, -1, 1, 30, -1, + 10, 25, 30, -1, 41, 45, -1, 11, 25, 30, + -1, 43, 45, -1, -1, 45, 46, -1, 45, 69, + -1, 45, 67, -1, 45, 40, -1, 45, 30, -1, + 20, 70, 30, -1, 19, 71, 74, 30, -1, 21, + 75, 74, 30, -1, 22, 25, 74, 30, -1, 23, + 76, 76, 74, 30, -1, 7, 30, -1, 47, 51, + -1, 72, -1, 48, 53, 49, -1, -1, 51, 52, + -1, 51, 69, -1, 51, 67, -1, 51, 30, -1, + 51, 40, -1, 19, 71, 74, 30, -1, 20, 70, + 30, -1, 18, 30, -1, 21, 25, 74, 30, -1, + -1, 53, 39, -1, 14, 75, 73, -1, 72, -1, + 54, 57, 55, -1, -1, 57, 39, -1, 57, 61, + -1, 57, 50, -1, 4, 71, 30, -1, 58, 68, + -1, 72, -1, 59, 62, 60, -1, -1, 62, 39, + -1, 62, 61, -1, 62, 50, -1, 6, 71, 30, + -1, 9, 71, 30, -1, 64, 68, -1, 12, 30, + -1, 66, 13, -1, -1, 68, 69, -1, 68, 30, + -1, 68, 40, -1, 16, 24, 75, 30, -1, 16, + 75, 30, -1, 17, 75, 30, -1, -1, 71, 74, + -1, 25, -1, 26, -1, 5, 30, -1, 8, 30, + -1, 15, 30, -1, 30, -1, 73, 30, -1, -1, + 14, 75, -1, 76, -1, 76, 33, 76, -1, 76, + 27, 76, -1, 29, 75, 28, -1, 34, 75, -1, + 75, 31, 75, -1, 75, 32, 75, -1, 25, -1, + 26, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const unsigned short int yyrline[] = +{ + 0, 103, 103, 105, 107, 108, 109, 110, 111, 112, + 113, 117, 121, 121, 121, 121, 121, 121, 121, 125, + 126, 127, 128, 129, 130, 134, 135, 141, 149, 155, + 163, 173, 175, 176, 177, 178, 179, 182, 190, 196, + 206, 212, 220, 229, 234, 242, 245, 247, 248, 249, + 250, 251, 254, 260, 271, 277, 287, 289, 294, 302, + 310, 313, 315, 316, 317, 322, 329, 334, 342, 345, + 347, 348, 349, 352, 360, 367, 374, 380, 387, 389, + 390, 391, 394, 399, 404, 412, 414, 419, 420, 423, + 424, 425, 429, 430, 433, 434, 437, 438, 439, 440, + 441, 442, 443, 446, 447 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE +/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", + "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", + "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", + "T_REQUIRES", "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", + "T_SELECT", "T_RANGE", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", + "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL", + "T_NOT", "$accept", "input", "stmt_list", "option_name", "common_stmt", + "option_error", "config_entry_start", "config_stmt", + "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", + "config_option", "choice", "choice_entry", "choice_end", "choice_stmt", + "choice_option_list", "choice_option", "choice_block", "if_entry", + "if_end", "if_stmt", "if_block", "menu", "menu_entry", "menu_end", + "menu_stmt", "menu_block", "source_stmt", "comment", "comment_stmt", + "help_start", "help", "depends_list", "depends", "prompt_stmt_opt", + "prompt", "end", "nl", "if_expr", "expr", "symbol", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const unsigned short int yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const unsigned char yyr1[] = +{ + 0, 35, 36, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 38, 38, 38, 38, 38, 38, 38, 39, + 39, 39, 39, 39, 39, 40, 40, 41, 42, 43, + 44, 45, 45, 45, 45, 45, 45, 46, 46, 46, + 46, 46, 47, 48, 49, 50, 51, 51, 51, 51, + 51, 51, 52, 52, 52, 52, 53, 53, 54, 55, + 56, 57, 57, 57, 57, 58, 59, 60, 61, 62, + 62, 62, 62, 63, 64, 65, 66, 67, 68, 68, + 68, 68, 69, 69, 69, 70, 70, 71, 71, 72, + 72, 72, 73, 73, 74, 74, 75, 75, 75, 75, + 75, 75, 75, 76, 76 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const unsigned char yyr2[] = +{ + 0, 2, 1, 0, 2, 2, 2, 4, 2, 4, + 4, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 2, 3, 2, 3, + 2, 0, 2, 2, 2, 2, 2, 3, 4, 4, + 4, 5, 2, 2, 1, 3, 0, 2, 2, 2, + 2, 2, 4, 3, 2, 4, 0, 2, 3, 1, + 3, 0, 2, 2, 2, 3, 2, 1, 3, 0, + 2, 2, 2, 3, 3, 2, 2, 2, 0, 2, + 2, 2, 4, 3, 3, 0, 2, 1, 1, 2, + 2, 2, 1, 2, 0, 2, 1, 3, 3, 3, + 2, 3, 3, 1, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const unsigned char yydefact[] = +{ + 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12, 16, 13, 14, + 18, 15, 17, 0, 19, 0, 4, 31, 22, 31, + 23, 46, 56, 5, 61, 20, 78, 69, 6, 24, + 78, 21, 8, 11, 87, 88, 0, 0, 89, 0, + 42, 90, 0, 0, 0, 103, 104, 0, 0, 0, + 96, 91, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 92, 7, 65, 73, 74, 27, 29, 0, + 100, 0, 0, 58, 0, 0, 9, 10, 0, 0, + 0, 0, 0, 85, 0, 0, 0, 0, 36, 35, + 32, 0, 34, 33, 0, 0, 85, 0, 50, 51, + 47, 49, 48, 57, 45, 44, 62, 64, 60, 63, + 59, 80, 81, 79, 70, 72, 68, 71, 67, 93, + 99, 101, 102, 98, 97, 26, 76, 0, 0, 0, + 94, 0, 94, 94, 94, 0, 0, 77, 54, 94, + 0, 94, 0, 83, 84, 0, 0, 37, 86, 0, + 0, 94, 25, 0, 53, 0, 82, 95, 38, 39, + 40, 0, 52, 55, 41 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const short int yydefgoto[] = +{ + -1, 1, 2, 25, 26, 99, 27, 28, 29, 30, + 64, 100, 31, 32, 114, 33, 66, 110, 67, 34, + 118, 35, 68, 36, 37, 126, 38, 70, 39, 40, + 41, 101, 102, 69, 103, 141, 142, 42, 73, 156, + 59, 60 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -78 +static const short int yypact[] = +{ + -78, 2, 159, -78, -21, 0, 0, -12, 0, 1, + 4, 0, 27, 38, 60, 58, -78, -78, -78, -78, + -78, -78, -78, 100, -78, 104, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, 86, 113, -78, 114, + -78, -78, 125, 127, 128, -78, -78, 60, 60, 210, + 65, -78, 141, 142, 39, 103, 182, 200, 6, 66, + 6, 131, -78, 146, -78, -78, -78, -78, -78, 196, + -78, 60, 60, 146, 40, 40, -78, -78, 155, 156, + -2, 60, 0, 0, 60, 105, 40, 194, -78, -78, + -78, 206, -78, -78, 183, 0, 0, 195, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, 197, -78, -78, -78, -78, -78, 60, 213, 216, + 212, 203, 212, 190, 212, 40, 208, -78, -78, 212, + 222, 212, 219, -78, -78, 60, 223, -78, -78, 224, + 225, 212, -78, 226, -78, 227, -78, 47, -78, -78, + -78, 228, -78, -78, -78 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const short int yypgoto[] = +{ + -78, -78, -78, -78, 164, -36, -78, -78, -78, -78, + 230, -78, -78, -78, -78, 29, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, 59, -78, -78, -78, + -78, -78, 198, 220, 24, 157, -5, 169, 202, 74, + -53, -77 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -76 +static const short int yytable[] = +{ + 46, 47, 3, 49, 79, 80, 52, 133, 134, 43, + 6, 7, 8, 9, 10, 11, 12, 13, 48, 145, + 14, 15, 137, 55, 56, 44, 45, 57, 131, 132, + 109, 50, 58, 122, 51, 122, 24, 138, 139, -28, + 88, 143, -28, -28, -28, -28, -28, -28, -28, -28, + -28, 89, 53, -28, -28, 90, 91, -28, 92, 93, + 94, 95, 96, 54, 97, 55, 56, 88, 161, 98, + -66, -66, -66, -66, -66, -66, -66, -66, 81, 82, + -66, -66, 90, 91, 152, 55, 56, 140, 61, 57, + 112, 97, 84, 123, 58, 123, 121, 117, 85, 125, + 149, 62, 167, -30, 88, 63, -30, -30, -30, -30, + -30, -30, -30, -30, -30, 89, 72, -30, -30, 90, + 91, -30, 92, 93, 94, 95, 96, 119, 97, 127, + 144, -75, 88, 98, -75, -75, -75, -75, -75, -75, + -75, -75, -75, 74, 75, -75, -75, 90, 91, -75, + -75, -75, -75, -75, -75, 76, 97, 77, 78, -2, + 4, 121, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 86, 87, 14, 15, 16, 129, 17, 18, 19, + 20, 21, 22, 88, 23, 135, 136, -43, -43, 24, + -43, -43, -43, -43, 89, 146, -43, -43, 90, 91, + 104, 105, 106, 107, 155, 7, 8, 97, 10, 11, + 12, 13, 108, 148, 14, 15, 158, 159, 160, 147, + 151, 81, 82, 163, 130, 165, 155, 81, 82, 82, + 24, 113, 116, 157, 124, 171, 115, 120, 162, 128, + 72, 81, 82, 153, 81, 82, 154, 81, 82, 166, + 81, 82, 164, 168, 169, 170, 172, 173, 174, 65, + 71, 83, 0, 150, 111 +}; + +static const short int yycheck[] = +{ + 5, 6, 0, 8, 57, 58, 11, 84, 85, 30, + 4, 5, 6, 7, 8, 9, 10, 11, 30, 96, + 14, 15, 24, 25, 26, 25, 26, 29, 81, 82, + 66, 30, 34, 69, 30, 71, 30, 90, 91, 0, + 1, 94, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 25, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 25, 25, 25, 26, 1, 145, 30, + 4, 5, 6, 7, 8, 9, 10, 11, 31, 32, + 14, 15, 16, 17, 137, 25, 26, 92, 30, 29, + 66, 25, 27, 69, 34, 71, 30, 68, 33, 70, + 105, 1, 155, 0, 1, 1, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 30, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 68, 25, 70, + 25, 0, 1, 30, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 30, 30, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 30, 25, 30, 30, 0, + 1, 30, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 30, 30, 14, 15, 16, 30, 18, 19, 20, + 21, 22, 23, 1, 25, 30, 30, 5, 6, 30, + 8, 9, 10, 11, 12, 1, 14, 15, 16, 17, + 18, 19, 20, 21, 14, 5, 6, 25, 8, 9, + 10, 11, 30, 30, 14, 15, 142, 143, 144, 13, + 25, 31, 32, 149, 28, 151, 14, 31, 32, 32, + 30, 67, 68, 30, 70, 161, 67, 68, 30, 70, + 30, 31, 32, 30, 31, 32, 30, 31, 32, 30, + 31, 32, 30, 30, 30, 30, 30, 30, 30, 29, + 40, 59, -1, 106, 66 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const unsigned char yystos[] = +{ + 0, 36, 37, 0, 1, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 16, 18, 19, 20, + 21, 22, 23, 25, 30, 38, 39, 41, 42, 43, + 44, 47, 48, 50, 54, 56, 58, 59, 61, 63, + 64, 65, 72, 30, 25, 26, 71, 71, 30, 71, + 30, 30, 71, 25, 25, 25, 26, 29, 34, 75, + 76, 30, 1, 1, 45, 45, 51, 53, 57, 68, + 62, 68, 30, 73, 30, 30, 30, 30, 30, 75, + 75, 31, 32, 73, 27, 33, 30, 30, 1, 12, + 16, 17, 19, 20, 21, 22, 23, 25, 30, 40, + 46, 66, 67, 69, 18, 19, 20, 21, 30, 40, + 52, 67, 69, 39, 49, 72, 39, 50, 55, 61, + 72, 30, 40, 69, 39, 50, 60, 61, 72, 30, + 28, 75, 75, 76, 76, 30, 30, 24, 75, 75, + 71, 70, 71, 75, 25, 76, 1, 13, 30, 71, + 70, 25, 75, 30, 30, 14, 74, 30, 74, 74, + 74, 76, 30, 74, 30, 74, 30, 75, 30, 30, + 30, 74, 30, 30, 30 +}; + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up");\ + YYERROR; \ + } \ +while (0) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (0) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yysymprint (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_stack_print (short int *bottom, short int *top) +#else +static void +yy_stack_print (bottom, top) + short int *bottom; + short int *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (/* Nothing. */; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_reduce_print (int yyrule) +#else +static void +yy_reduce_print (yyrule) + int yyrule; +#endif +{ + int yyi; + unsigned int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", + yyrule - 1, yylno); + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) + YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); + YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +#endif /* !YYERROR_VERBOSE */ + + + +#if YYDEBUG +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) +#else +static void +yysymprint (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + switch (yytype) + { + default: + break; + } + YYFPRINTF (yyoutput, ")"); +} + +#endif /* ! YYDEBUG */ +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + case 48: /* choice_entry */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 54: /* if_entry */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 59: /* menu_entry */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM); +# else +int yyparse (); +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM) +# else +int yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short int yyssa[YYINITDEPTH]; + short int *yyss = yyssa; + register short int *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + + + +#define YYPOPSTACK (yyvsp--, yyssp--) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + + yyvsp[0] = yylval; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short int *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyoverflowlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + short int *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a look-ahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to look-ahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; + + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 8: + + { zconf_error("unexpected end statement"); ;} + break; + + case 9: + + { zconf_error("unknown statement \"%s\"", (yyvsp[-2].string)); ;} + break; + + case 10: + + { + zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[-2].id)->name); +;} + break; + + case 11: + + { zconf_error("invalid statement"); ;} + break; + + case 25: + + { zconf_error("unknown option \"%s\"", (yyvsp[-2].string)); ;} + break; + + case 26: + + { zconf_error("invalid option"); ;} + break; + + case 27: + + { + struct symbol *sym = sym_lookup((yyvsp[-1].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string)); +;} + break; + + case 28: + + { + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 29: + + { + struct symbol *sym = sym_lookup((yyvsp[-1].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string)); +;} + break; + + case 30: + + { + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 37: + + { + menu_set_type((yyvsp[-2].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[-2].id)->stype); +;} + break; + + case 38: + + { + menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 39: + + { + menu_add_expr(P_DEFAULT, (yyvsp[-2].expr), (yyvsp[-1].expr)); + if ((yyvsp[-3].id)->stype != S_UNKNOWN) + menu_set_type((yyvsp[-3].id)->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[-3].id)->stype); +;} + break; + + case 40: + + { + menu_add_symbol(P_SELECT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr)); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 41: + + { + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[-3].symbol), (yyvsp[-2].symbol)), (yyvsp[-1].expr)); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 42: + + { + struct symbol *sym = sym_lookup(NULL, 0); + sym->flags |= SYMBOL_CHOICE; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 43: + + { + (yyval.menu) = menu_add_menu(); +;} + break; + + case 44: + + { + if (zconf_endtoken((yyvsp[0].id), T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +;} + break; + + case 52: + + { + menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 53: + + { + if ((yyvsp[-2].id)->stype == S_BOOLEAN || (yyvsp[-2].id)->stype == S_TRISTATE) { + menu_set_type((yyvsp[-2].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[-2].id)->stype); + } else + YYERROR; +;} + break; + + case 54: + + { + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 55: + + { + if ((yyvsp[-3].id)->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr)); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +;} + break; + + case 58: + + { + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep((yyvsp[-1].expr)); + (yyval.menu) = menu_add_menu(); +;} + break; + + case 59: + + { + if (zconf_endtoken((yyvsp[0].id), T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +;} + break; + + case 65: + + { + menu_add_entry(NULL); + menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 66: + + { + (yyval.menu) = menu_add_menu(); +;} + break; + + case 67: + + { + if (zconf_endtoken((yyvsp[0].id), T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +;} + break; + + case 73: + + { + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string)); + zconf_nextfile((yyvsp[-1].string)); +;} + break; + + case 74: + + { + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, (yyvsp[-1].string), NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 75: + + { + menu_end_entry(); +;} + break; + + case 76: + + { + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +;} + break; + + case 77: + + { + current_entry->sym->help = (yyvsp[0].string); +;} + break; + + case 82: + + { + menu_add_dep((yyvsp[-1].expr)); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 83: + + { + menu_add_dep((yyvsp[-1].expr)); + printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 84: + + { + menu_add_dep((yyvsp[-1].expr)); + printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 86: + + { + menu_add_prompt(P_PROMPT, (yyvsp[-1].string), (yyvsp[0].expr)); +;} + break; + + case 89: + + { (yyval.id) = (yyvsp[-1].id); ;} + break; + + case 90: + + { (yyval.id) = (yyvsp[-1].id); ;} + break; + + case 91: + + { (yyval.id) = (yyvsp[-1].id); ;} + break; + + case 94: + + { (yyval.expr) = NULL; ;} + break; + + case 95: + + { (yyval.expr) = (yyvsp[0].expr); ;} + break; + + case 96: + + { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); ;} + break; + + case 97: + + { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;} + break; + + case 98: + + { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;} + break; + + case 99: + + { (yyval.expr) = (yyvsp[-1].expr); ;} + break; + + case 100: + + { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); ;} + break; + + case 101: + + { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), (yyvsp[0].expr)); ;} + break; + + case 102: + + { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), (yyvsp[0].expr)); ;} + break; + + case 103: + + { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); free((yyvsp[0].string)); ;} + break; + + case 104: + + { (yyval.symbol) = sym_lookup((yyvsp[0].string), 1); free((yyvsp[0].string)); ;} + break; + + + } + +/* Line 1037 of yacc.c. */ + + + yyvsp -= yylen; + yyssp -= yylen; + + + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (YYPACT_NINF < yyn && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + int yytype = YYTRANSLATE (yychar); + const char* yyprefix; + char *yymsg; + int yyx; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 0; + + yyprefix = ", expecting "; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); + yycount += 1; + if (yycount == 5) + { + yysize = 0; + break; + } + } + yysize += (sizeof ("syntax error, unexpected ") + + yystrlen (yytname[yytype])); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); + yyp = yystpcpy (yyp, yytname[yytype]); + + if (yycount < 5) + { + yyprefix = ", expecting "; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + yyp = yystpcpy (yyp, yyprefix); + yyp = yystpcpy (yyp, yytname[yyx]); + yyprefix = " or "; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("syntax error; also virtual memory exhausted"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror ("syntax error"); + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* If at end of input, pop the error token, + then the rest of the stack, then return failure. */ + if (yychar == YYEOF) + for (;;) + { + + YYPOPSTACK; + if (yyssp == yyss) + YYABORT; + yydestruct ("Error: popping", + yystos[*yyssp], yyvsp); + } + } + else + { + yydestruct ("Error: discarding", yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + +#ifdef __GNUC__ + /* Pacify GCC when the user code never invokes YYERROR and the label + yyerrorlab therefore never appears in user code. */ + if (0) + goto yyerrorlab; +#endif + +yyvsp -= yylen; + yyssp -= yylen; + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", yystos[yystate], yyvsp); + YYPOPSTACK; + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yydestruct ("Error: discarding lookahead", + yytoken, &yylval); + yychar = YYEMPTY; + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*----------------------------------------------. +| yyoverflowlab -- parser overflow comes here. | +`----------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} + + + + + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + menu_init(); + modules_sym = sym_lookup("MODULES", 0); + rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + +#if YYDEBUG + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; +#endif + zconfparse(); + if (zconfnerrs) + exit(1); + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + sym_check_deps(sym); + } + + sym_change_count = 1; +} + +const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + } + return ""; +} + +static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ +#if YYDEBUG + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +#endif +} + +void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "choice\n"); + else + fprintf(out, "config %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (sym->help) { + int len = strlen(sym->help); + while (sym->help[--len] == '\n') + sym->help[len] = 0; + fprintf(out, " help\n%s\n", sym->help); + } + fputc('\n', out); +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + fputs("\n", out); + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "lex.zconf.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" + + Files oldtree/scripts/kconfig/zconf.tab.o and newtree/scripts/kconfig/zconf.tab.o differ diff -urN oldtree/scripts/lxdialog/.checklist.o.cmd newtree/scripts/lxdialog/.checklist.o.cmd --- oldtree/scripts/lxdialog/.checklist.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/lxdialog/.checklist.o.cmd 2006-01-28 18:23:32.340215200 +0000 @@ -0,0 +1,54 @@ +cmd_scripts/lxdialog/checklist.o := gcc -Wp,-MD,scripts/lxdialog/.checklist.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE -DCURSES_LOC="" -c -o scripts/lxdialog/checklist.o scripts/lxdialog/checklist.c + +deps_scripts/lxdialog/checklist.o := \ + scripts/lxdialog/checklist.c \ + scripts/lxdialog/dialog.h \ + /usr/include/sys/types.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/ctype.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/ncurses.h \ + /usr/include/ncurses_dll.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/unctrl.h \ + /usr/include/curses.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + +scripts/lxdialog/checklist.o: $(deps_scripts/lxdialog/checklist.o) + +$(deps_scripts/lxdialog/checklist.o): diff -urN oldtree/scripts/lxdialog/.inputbox.o.cmd newtree/scripts/lxdialog/.inputbox.o.cmd --- oldtree/scripts/lxdialog/.inputbox.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/lxdialog/.inputbox.o.cmd 2006-01-28 18:23:32.486193008 +0000 @@ -0,0 +1,54 @@ +cmd_scripts/lxdialog/inputbox.o := gcc -Wp,-MD,scripts/lxdialog/.inputbox.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE -DCURSES_LOC="" -c -o scripts/lxdialog/inputbox.o scripts/lxdialog/inputbox.c + +deps_scripts/lxdialog/inputbox.o := \ + scripts/lxdialog/inputbox.c \ + scripts/lxdialog/dialog.h \ + /usr/include/sys/types.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/ctype.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/ncurses.h \ + /usr/include/ncurses_dll.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/unctrl.h \ + /usr/include/curses.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + +scripts/lxdialog/inputbox.o: $(deps_scripts/lxdialog/inputbox.o) + +$(deps_scripts/lxdialog/inputbox.o): diff -urN oldtree/scripts/lxdialog/.lxdialog.cmd newtree/scripts/lxdialog/.lxdialog.cmd --- oldtree/scripts/lxdialog/.lxdialog.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/lxdialog/.lxdialog.cmd 2006-01-28 18:23:33.573027784 +0000 @@ -0,0 +1 @@ +cmd_scripts/lxdialog/lxdialog := gcc -o scripts/lxdialog/lxdialog scripts/lxdialog/checklist.o scripts/lxdialog/menubox.o scripts/lxdialog/textbox.o scripts/lxdialog/yesno.o scripts/lxdialog/inputbox.o scripts/lxdialog/util.o scripts/lxdialog/lxdialog.o scripts/lxdialog/msgbox.o -lncurses diff -urN oldtree/scripts/lxdialog/.lxdialog.o.cmd newtree/scripts/lxdialog/.lxdialog.o.cmd --- oldtree/scripts/lxdialog/.lxdialog.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/lxdialog/.lxdialog.o.cmd 2006-01-28 18:23:32.642169296 +0000 @@ -0,0 +1,56 @@ +cmd_scripts/lxdialog/lxdialog.o := gcc -Wp,-MD,scripts/lxdialog/.lxdialog.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE -DCURSES_LOC="" -c -o scripts/lxdialog/lxdialog.o scripts/lxdialog/lxdialog.c + +deps_scripts/lxdialog/lxdialog.o := \ + scripts/lxdialog/lxdialog.c \ + scripts/lxdialog/dialog.h \ + /usr/include/sys/types.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/ctype.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/ncurses.h \ + /usr/include/ncurses_dll.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/unctrl.h \ + /usr/include/curses.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + /usr/include/locale.h \ + /usr/include/bits/locale.h \ + +scripts/lxdialog/lxdialog.o: $(deps_scripts/lxdialog/lxdialog.o) + +$(deps_scripts/lxdialog/lxdialog.o): diff -urN oldtree/scripts/lxdialog/.menubox.o.cmd newtree/scripts/lxdialog/.menubox.o.cmd --- oldtree/scripts/lxdialog/.menubox.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/lxdialog/.menubox.o.cmd 2006-01-28 18:23:32.891131448 +0000 @@ -0,0 +1,54 @@ +cmd_scripts/lxdialog/menubox.o := gcc -Wp,-MD,scripts/lxdialog/.menubox.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE -DCURSES_LOC="" -c -o scripts/lxdialog/menubox.o scripts/lxdialog/menubox.c + +deps_scripts/lxdialog/menubox.o := \ + scripts/lxdialog/menubox.c \ + scripts/lxdialog/dialog.h \ + /usr/include/sys/types.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/ctype.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/ncurses.h \ + /usr/include/ncurses_dll.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/unctrl.h \ + /usr/include/curses.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + +scripts/lxdialog/menubox.o: $(deps_scripts/lxdialog/menubox.o) + +$(deps_scripts/lxdialog/menubox.o): diff -urN oldtree/scripts/lxdialog/.msgbox.o.cmd newtree/scripts/lxdialog/.msgbox.o.cmd --- oldtree/scripts/lxdialog/.msgbox.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/lxdialog/.msgbox.o.cmd 2006-01-28 18:23:32.992116096 +0000 @@ -0,0 +1,54 @@ +cmd_scripts/lxdialog/msgbox.o := gcc -Wp,-MD,scripts/lxdialog/.msgbox.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE -DCURSES_LOC="" -c -o scripts/lxdialog/msgbox.o scripts/lxdialog/msgbox.c + +deps_scripts/lxdialog/msgbox.o := \ + scripts/lxdialog/msgbox.c \ + scripts/lxdialog/dialog.h \ + /usr/include/sys/types.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/ctype.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/ncurses.h \ + /usr/include/ncurses_dll.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/unctrl.h \ + /usr/include/curses.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + +scripts/lxdialog/msgbox.o: $(deps_scripts/lxdialog/msgbox.o) + +$(deps_scripts/lxdialog/msgbox.o): diff -urN oldtree/scripts/lxdialog/.textbox.o.cmd newtree/scripts/lxdialog/.textbox.o.cmd --- oldtree/scripts/lxdialog/.textbox.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/lxdialog/.textbox.o.cmd 2006-01-28 18:23:33.234079312 +0000 @@ -0,0 +1,54 @@ +cmd_scripts/lxdialog/textbox.o := gcc -Wp,-MD,scripts/lxdialog/.textbox.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE -DCURSES_LOC="" -c -o scripts/lxdialog/textbox.o scripts/lxdialog/textbox.c + +deps_scripts/lxdialog/textbox.o := \ + scripts/lxdialog/textbox.c \ + scripts/lxdialog/dialog.h \ + /usr/include/sys/types.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/ctype.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/ncurses.h \ + /usr/include/ncurses_dll.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/unctrl.h \ + /usr/include/curses.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + +scripts/lxdialog/textbox.o: $(deps_scripts/lxdialog/textbox.o) + +$(deps_scripts/lxdialog/textbox.o): diff -urN oldtree/scripts/lxdialog/.util.o.cmd newtree/scripts/lxdialog/.util.o.cmd --- oldtree/scripts/lxdialog/.util.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/lxdialog/.util.o.cmd 2006-01-28 18:23:33.414051952 +0000 @@ -0,0 +1,55 @@ +cmd_scripts/lxdialog/util.o := gcc -Wp,-MD,scripts/lxdialog/.util.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE -DCURSES_LOC="" -c -o scripts/lxdialog/util.o scripts/lxdialog/util.c + +deps_scripts/lxdialog/util.o := \ + scripts/lxdialog/util.c \ + scripts/lxdialog/dialog.h \ + /usr/include/sys/types.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/ctype.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/ncurses.h \ + /usr/include/ncurses_dll.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/unctrl.h \ + /usr/include/curses.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + scripts/lxdialog/colors.h \ + +scripts/lxdialog/util.o: $(deps_scripts/lxdialog/util.o) + +$(deps_scripts/lxdialog/util.o): diff -urN oldtree/scripts/lxdialog/.yesno.o.cmd newtree/scripts/lxdialog/.yesno.o.cmd --- oldtree/scripts/lxdialog/.yesno.o.cmd 1970-01-01 00:00:00.000000000 +0000 +++ newtree/scripts/lxdialog/.yesno.o.cmd 2006-01-28 18:23:33.523035384 +0000 @@ -0,0 +1,54 @@ +cmd_scripts/lxdialog/yesno.o := gcc -Wp,-MD,scripts/lxdialog/.yesno.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE -DCURSES_LOC="" -c -o scripts/lxdialog/yesno.o scripts/lxdialog/yesno.c + +deps_scripts/lxdialog/yesno.o := \ + scripts/lxdialog/yesno.c \ + scripts/lxdialog/dialog.h \ + /usr/include/sys/types.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stddef.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/fcntl.h \ + /usr/include/bits/fcntl.h \ + /usr/include/unistd.h \ + /usr/include/bits/posix_opt.h \ + /usr/include/bits/confname.h \ + /usr/include/getopt.h \ + /usr/include/ctype.h \ + /usr/include/stdlib.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + /usr/include/ncurses.h \ + /usr/include/ncurses_dll.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/include/unctrl.h \ + /usr/include/curses.h \ + /usr/lib/gcc/i686-pc-linux-gnu/4.0.3-20060119/include/stdbool.h \ + +scripts/lxdialog/yesno.o: $(deps_scripts/lxdialog/yesno.o) + +$(deps_scripts/lxdialog/yesno.o): Files oldtree/scripts/lxdialog/checklist.o and newtree/scripts/lxdialog/checklist.o differ Files oldtree/scripts/lxdialog/inputbox.o and newtree/scripts/lxdialog/inputbox.o differ Files oldtree/scripts/lxdialog/lxdialog and newtree/scripts/lxdialog/lxdialog differ Files oldtree/scripts/lxdialog/lxdialog.o and newtree/scripts/lxdialog/lxdialog.o differ Files oldtree/scripts/lxdialog/menubox.o and newtree/scripts/lxdialog/menubox.o differ Files oldtree/scripts/lxdialog/msgbox.o and newtree/scripts/lxdialog/msgbox.o differ Files oldtree/scripts/lxdialog/textbox.o and newtree/scripts/lxdialog/textbox.o differ Files oldtree/scripts/lxdialog/util.o and newtree/scripts/lxdialog/util.o differ Files oldtree/scripts/lxdialog/yesno.o and newtree/scripts/lxdialog/yesno.o differ